summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/media/Makefile2
-rw-r--r--Documentation/DocBook/media/dvb/audio.xml113
-rw-r--r--Documentation/DocBook/media/dvb/ca.xml353
-rw-r--r--Documentation/DocBook/media/dvb/demux.xml230
-rw-r--r--Documentation/DocBook/media/dvb/dvbapi.xml2
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml65
-rw-r--r--Documentation/DocBook/media/dvb/frontend.xml70
-rw-r--r--Documentation/DocBook/media/dvb/kdapi.xml2
-rw-r--r--Documentation/DocBook/media/dvb/net.xml127
-rw-r--r--Documentation/DocBook/media/dvb/video.xml333
-rw-r--r--Documentation/DocBook/media/v4l/biblio.xml12
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml16
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml453
-rw-r--r--Documentation/DocBook/media/v4l/dev-rds.xml2
-rw-r--r--Documentation/DocBook/media/v4l/dev-subdev.xml20
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml3
-rw-r--r--Documentation/DocBook/media/v4l/selection-api.xml22
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml14
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-selection.xml9
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-qbuf.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml8
-rw-r--r--Documentation/DocBook/media_api.tmpl9
-rw-r--r--Documentation/dvb/README.dvb-usb2
-rw-r--r--Documentation/feature-removal-schedule.txt9
-rw-r--r--Documentation/ioctl/ioctl-number.txt5
-rw-r--r--MAINTAINERS28
-rw-r--r--arch/arm/mach-imx/clk-imx27.c4
-rw-r--r--arch/arm/mach-imx/devices-imx27.h4
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c49
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c30
-rw-r--r--arch/arm/plat-mxc/devices/Kconfig6
-rw-r--r--arch/arm/plat-mxc/devices/Makefile1
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx27-coda.c37
-rw-r--r--arch/arm/plat-mxc/include/mach/devices-common.h8
-rw-r--r--drivers/gpio/gpio-bt8xx.c2
-rw-r--r--drivers/media/Kconfig53
-rw-r--r--drivers/media/Makefile7
-rw-r--r--drivers/media/common/Kconfig12
-rw-r--r--drivers/media/common/Makefile7
-rw-r--r--drivers/media/common/b2c2/Kconfig28
-rw-r--r--drivers/media/common/b2c2/Makefile8
-rw-r--r--drivers/media/common/b2c2/flexcop-common.h (renamed from drivers/media/dvb/b2c2/flexcop-common.h)0
-rw-r--r--drivers/media/common/b2c2/flexcop-eeprom.c (renamed from drivers/media/dvb/b2c2/flexcop-eeprom.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop-fe-tuner.c (renamed from drivers/media/dvb/b2c2/flexcop-fe-tuner.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop-hw-filter.c (renamed from drivers/media/dvb/b2c2/flexcop-hw-filter.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop-i2c.c (renamed from drivers/media/dvb/b2c2/flexcop-i2c.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop-misc.c (renamed from drivers/media/dvb/b2c2/flexcop-misc.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop-reg.h (renamed from drivers/media/dvb/b2c2/flexcop-reg.h)0
-rw-r--r--drivers/media/common/b2c2/flexcop-sram.c (renamed from drivers/media/dvb/b2c2/flexcop-sram.c)0
-rw-r--r--drivers/media/common/b2c2/flexcop.c325
-rw-r--r--drivers/media/common/b2c2/flexcop.h (renamed from drivers/media/dvb/b2c2/flexcop.h)0
-rw-r--r--drivers/media/common/b2c2/flexcop_ibi_value_be.h (renamed from drivers/media/dvb/b2c2/flexcop_ibi_value_be.h)0
-rw-r--r--drivers/media/common/b2c2/flexcop_ibi_value_le.h (renamed from drivers/media/dvb/b2c2/flexcop_ibi_value_le.h)0
-rw-r--r--drivers/media/common/saa7146/Kconfig9
-rw-r--r--drivers/media/common/saa7146/Makefile5
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c592
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c664
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c (renamed from drivers/media/common/saa7146_hlp.c)0
-rw-r--r--drivers/media/common/saa7146/saa7146_i2c.c (renamed from drivers/media/common/saa7146_i2c.c)0
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c (renamed from drivers/media/common/saa7146_vbi.c)0
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c (renamed from drivers/media/common/saa7146_video.c)0
-rw-r--r--drivers/media/common/saa7146_core.c600
-rw-r--r--drivers/media/common/saa7146_fops.c641
-rw-r--r--drivers/media/common/siano/Kconfig17
-rw-r--r--drivers/media/common/siano/Makefile7
-rw-r--r--drivers/media/common/siano/sms-cards.c (renamed from drivers/media/dvb/siano/sms-cards.c)0
-rw-r--r--drivers/media/common/siano/sms-cards.h (renamed from drivers/media/dvb/siano/sms-cards.h)0
-rw-r--r--drivers/media/common/siano/smscoreapi.c (renamed from drivers/media/dvb/siano/smscoreapi.c)0
-rw-r--r--drivers/media/common/siano/smscoreapi.h (renamed from drivers/media/dvb/siano/smscoreapi.h)0
-rw-r--r--drivers/media/common/siano/smsdvb.c (renamed from drivers/media/dvb/siano/smsdvb.c)0
-rw-r--r--drivers/media/common/siano/smsendian.c (renamed from drivers/media/dvb/siano/smsendian.c)0
-rw-r--r--drivers/media/common/siano/smsendian.h (renamed from drivers/media/dvb/siano/smsendian.h)0
-rw-r--r--drivers/media/common/siano/smsir.c (renamed from drivers/media/dvb/siano/smsir.c)0
-rw-r--r--drivers/media/common/siano/smsir.h (renamed from drivers/media/dvb/siano/smsir.h)0
-rw-r--r--drivers/media/common/tuners/Kconfig243
-rw-r--r--drivers/media/common/tuners/Makefile37
-rw-r--r--drivers/media/common/tuners/qt1010.c480
-rw-r--r--drivers/media/common/tuners/tda18212.c326
-rw-r--r--drivers/media/common/tuners/tda18218.c342
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c1510
-rw-r--r--drivers/media/common/tuners/xc4000.c1758
-rw-r--r--drivers/media/common/tuners/xc5000.c1265
-rw-r--r--drivers/media/dvb-core/Kconfig29
-rw-r--r--drivers/media/dvb-core/Makefile (renamed from drivers/media/dvb/dvb-core/Makefile)0
-rw-r--r--drivers/media/dvb-core/demux.h (renamed from drivers/media/dvb/dvb-core/demux.h)0
-rw-r--r--drivers/media/dvb-core/dmxdev.c1275
-rw-r--r--drivers/media/dvb-core/dmxdev.h (renamed from drivers/media/dvb/dvb-core/dmxdev.h)0
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h (renamed from drivers/media/dvb/dvb-usb/dvb-usb-ids.h)0
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c (renamed from drivers/media/dvb/dvb-core/dvb_ca_en50221.c)0
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.h (renamed from drivers/media/dvb/dvb-core/dvb_ca_en50221.h)0
-rw-r--r--drivers/media/dvb-core/dvb_demux.c1318
-rw-r--r--drivers/media/dvb-core/dvb_demux.h (renamed from drivers/media/dvb/dvb-core/dvb_demux.h)0
-rw-r--r--drivers/media/dvb-core/dvb_filter.c (renamed from drivers/media/dvb/dvb-core/dvb_filter.c)0
-rw-r--r--drivers/media/dvb-core/dvb_filter.h (renamed from drivers/media/dvb/dvb-core/dvb_filter.h)0
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c2591
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h427
-rw-r--r--drivers/media/dvb-core/dvb_math.c (renamed from drivers/media/dvb/dvb-core/dvb_math.c)0
-rw-r--r--drivers/media/dvb-core/dvb_math.h (renamed from drivers/media/dvb/dvb-core/dvb_math.h)0
-rw-r--r--drivers/media/dvb-core/dvb_net.c (renamed from drivers/media/dvb/dvb-core/dvb_net.c)0
-rw-r--r--drivers/media/dvb-core/dvb_net.h (renamed from drivers/media/dvb/dvb-core/dvb_net.h)0
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.c (renamed from drivers/media/dvb/dvb-core/dvb_ringbuffer.c)0
-rw-r--r--drivers/media/dvb-core/dvb_ringbuffer.h (renamed from drivers/media/dvb/dvb-core/dvb_ringbuffer.h)0
-rw-r--r--drivers/media/dvb-core/dvbdev.c (renamed from drivers/media/dvb/dvb-core/dvbdev.c)0
-rw-r--r--drivers/media/dvb-core/dvbdev.h146
-rw-r--r--drivers/media/dvb-frontends/Kconfig741
-rw-r--r--drivers/media/dvb-frontends/Makefile105
-rw-r--r--drivers/media/dvb-frontends/a8293.c (renamed from drivers/media/dvb/frontends/a8293.c)0
-rw-r--r--drivers/media/dvb-frontends/a8293.h (renamed from drivers/media/dvb/frontends/a8293.h)0
-rw-r--r--drivers/media/dvb-frontends/af9013.c (renamed from drivers/media/dvb/frontends/af9013.c)0
-rw-r--r--drivers/media/dvb-frontends/af9013.h (renamed from drivers/media/dvb/frontends/af9013.h)0
-rw-r--r--drivers/media/dvb-frontends/af9013_priv.h (renamed from drivers/media/dvb/frontends/af9013_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/af9033.c (renamed from drivers/media/dvb/frontends/af9033.c)0
-rw-r--r--drivers/media/dvb-frontends/af9033.h (renamed from drivers/media/dvb/frontends/af9033.h)0
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h (renamed from drivers/media/dvb/frontends/af9033_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/atbm8830.c508
-rw-r--r--drivers/media/dvb-frontends/atbm8830.h (renamed from drivers/media/dvb/frontends/atbm8830.h)0
-rw-r--r--drivers/media/dvb-frontends/atbm8830_priv.h (renamed from drivers/media/dvb/frontends/atbm8830_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/au8522.h (renamed from drivers/media/dvb/frontends/au8522.h)0
-rw-r--r--drivers/media/dvb-frontends/au8522_common.c277
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c839
-rw-r--r--drivers/media/dvb-frontends/au8522_dig.c828
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h446
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c (renamed from drivers/media/dvb/frontends/bcm3510.c)0
-rw-r--r--drivers/media/dvb-frontends/bcm3510.h (renamed from drivers/media/dvb/frontends/bcm3510.h)0
-rw-r--r--drivers/media/dvb-frontends/bcm3510_priv.h (renamed from drivers/media/dvb/frontends/bcm3510_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/bsbe1-d01a.h (renamed from drivers/media/dvb/frontends/bsbe1-d01a.h)0
-rw-r--r--drivers/media/dvb-frontends/bsbe1.h (renamed from drivers/media/dvb/frontends/bsbe1.h)0
-rw-r--r--drivers/media/dvb-frontends/bsru6.h (renamed from drivers/media/dvb/frontends/bsru6.h)0
-rw-r--r--drivers/media/dvb-frontends/cx22700.c (renamed from drivers/media/dvb/frontends/cx22700.c)0
-rw-r--r--drivers/media/dvb-frontends/cx22700.h (renamed from drivers/media/dvb/frontends/cx22700.h)0
-rw-r--r--drivers/media/dvb-frontends/cx22702.c (renamed from drivers/media/dvb/frontends/cx22702.c)0
-rw-r--r--drivers/media/dvb-frontends/cx22702.h (renamed from drivers/media/dvb/frontends/cx22702.h)0
-rw-r--r--drivers/media/dvb-frontends/cx24110.c (renamed from drivers/media/dvb/frontends/cx24110.c)0
-rw-r--r--drivers/media/dvb-frontends/cx24110.h (renamed from drivers/media/dvb/frontends/cx24110.h)0
-rw-r--r--drivers/media/dvb-frontends/cx24113.c (renamed from drivers/media/dvb/frontends/cx24113.c)0
-rw-r--r--drivers/media/dvb-frontends/cx24113.h (renamed from drivers/media/dvb/frontends/cx24113.h)0
-rw-r--r--drivers/media/dvb-frontends/cx24116.c (renamed from drivers/media/dvb/frontends/cx24116.c)0
-rw-r--r--drivers/media/dvb-frontends/cx24116.h (renamed from drivers/media/dvb/frontends/cx24116.h)0
-rw-r--r--drivers/media/dvb-frontends/cx24123.c (renamed from drivers/media/dvb/frontends/cx24123.c)0
-rw-r--r--drivers/media/dvb-frontends/cx24123.h (renamed from drivers/media/dvb/frontends/cx24123.h)0
-rw-r--r--drivers/media/dvb-frontends/cxd2820r.h (renamed from drivers/media/dvb/frontends/cxd2820r.h)0
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_c.c (renamed from drivers/media/dvb/frontends/cxd2820r_c.c)0
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c (renamed from drivers/media/dvb/frontends/cxd2820r_core.c)0
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h (renamed from drivers/media/dvb/frontends/cxd2820r_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t.c452
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t2.c (renamed from drivers/media/dvb/frontends/cxd2820r_t2.c)0
-rw-r--r--drivers/media/dvb-frontends/dib0070.c (renamed from drivers/media/dvb/frontends/dib0070.c)0
-rw-r--r--drivers/media/dvb-frontends/dib0070.h (renamed from drivers/media/dvb/frontends/dib0070.h)0
-rw-r--r--drivers/media/dvb-frontends/dib0090.c (renamed from drivers/media/dvb/frontends/dib0090.c)0
-rw-r--r--drivers/media/dvb-frontends/dib0090.h (renamed from drivers/media/dvb/frontends/dib0090.h)0
-rw-r--r--drivers/media/dvb-frontends/dib3000.h (renamed from drivers/media/dvb/frontends/dib3000.h)0
-rw-r--r--drivers/media/dvb-frontends/dib3000mb.c (renamed from drivers/media/dvb/frontends/dib3000mb.c)0
-rw-r--r--drivers/media/dvb-frontends/dib3000mb_priv.h (renamed from drivers/media/dvb/frontends/dib3000mb_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.c (renamed from drivers/media/dvb/frontends/dib3000mc.c)0
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.h (renamed from drivers/media/dvb/frontends/dib3000mc.h)0
-rw-r--r--drivers/media/dvb-frontends/dib7000m.c (renamed from drivers/media/dvb/frontends/dib7000m.c)0
-rw-r--r--drivers/media/dvb-frontends/dib7000m.h (renamed from drivers/media/dvb/frontends/dib7000m.h)0
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c (renamed from drivers/media/dvb/frontends/dib7000p.c)0
-rw-r--r--drivers/media/dvb-frontends/dib7000p.h (renamed from drivers/media/dvb/frontends/dib7000p.h)0
-rw-r--r--drivers/media/dvb-frontends/dib8000.c (renamed from drivers/media/dvb/frontends/dib8000.c)0
-rw-r--r--drivers/media/dvb-frontends/dib8000.h (renamed from drivers/media/dvb/frontends/dib8000.h)0
-rw-r--r--drivers/media/dvb-frontends/dib9000.c (renamed from drivers/media/dvb/frontends/dib9000.c)0
-rw-r--r--drivers/media/dvb-frontends/dib9000.h (renamed from drivers/media/dvb/frontends/dib9000.h)0
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.c (renamed from drivers/media/dvb/frontends/dibx000_common.c)0
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.h (renamed from drivers/media/dvb/frontends/dibx000_common.h)0
-rw-r--r--drivers/media/dvb-frontends/drxd.h (renamed from drivers/media/dvb/frontends/drxd.h)0
-rw-r--r--drivers/media/dvb-frontends/drxd_firm.c (renamed from drivers/media/dvb/frontends/drxd_firm.c)0
-rw-r--r--drivers/media/dvb-frontends/drxd_firm.h (renamed from drivers/media/dvb/frontends/drxd_firm.h)0
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c (renamed from drivers/media/dvb/frontends/drxd_hard.c)0
-rw-r--r--drivers/media/dvb-frontends/drxd_map_firm.h (renamed from drivers/media/dvb/frontends/drxd_map_firm.h)0
-rw-r--r--drivers/media/dvb-frontends/drxk.h (renamed from drivers/media/dvb/frontends/drxk.h)0
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c (renamed from drivers/media/dvb/frontends/drxk_hard.c)0
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.h (renamed from drivers/media/dvb/frontends/drxk_hard.h)0
-rw-r--r--drivers/media/dvb-frontends/drxk_map.h (renamed from drivers/media/dvb/frontends/drxk_map.h)0
-rw-r--r--drivers/media/dvb-frontends/ds3000.c (renamed from drivers/media/dvb/frontends/ds3000.c)0
-rw-r--r--drivers/media/dvb-frontends/ds3000.h (renamed from drivers/media/dvb/frontends/ds3000.h)0
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.c820
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.h57
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.c (renamed from drivers/media/dvb/frontends/dvb_dummy_fe.c)0
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.h (renamed from drivers/media/dvb/frontends/dvb_dummy_fe.h)0
-rw-r--r--drivers/media/dvb-frontends/ec100.c (renamed from drivers/media/dvb/frontends/ec100.c)0
-rw-r--r--drivers/media/dvb-frontends/ec100.h (renamed from drivers/media/dvb/frontends/ec100.h)0
-rw-r--r--drivers/media/dvb-frontends/ec100_priv.h (renamed from drivers/media/dvb/frontends/ec100_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/eds1547.h (renamed from drivers/media/dvb/frontends/eds1547.h)0
-rw-r--r--drivers/media/dvb-frontends/hd29l2.c (renamed from drivers/media/dvb/frontends/hd29l2.c)0
-rw-r--r--drivers/media/dvb-frontends/hd29l2.h (renamed from drivers/media/dvb/frontends/hd29l2.h)0
-rw-r--r--drivers/media/dvb-frontends/hd29l2_priv.h (renamed from drivers/media/dvb/frontends/hd29l2_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/isl6405.c (renamed from drivers/media/dvb/frontends/isl6405.c)0
-rw-r--r--drivers/media/dvb-frontends/isl6405.h (renamed from drivers/media/dvb/frontends/isl6405.h)0
-rw-r--r--drivers/media/dvb-frontends/isl6421.c (renamed from drivers/media/dvb/frontends/isl6421.c)0
-rw-r--r--drivers/media/dvb-frontends/isl6421.h (renamed from drivers/media/dvb/frontends/isl6421.h)0
-rw-r--r--drivers/media/dvb-frontends/isl6423.c (renamed from drivers/media/dvb/frontends/isl6423.c)0
-rw-r--r--drivers/media/dvb-frontends/isl6423.h (renamed from drivers/media/dvb/frontends/isl6423.h)0
-rw-r--r--drivers/media/dvb-frontends/it913x-fe-priv.h (renamed from drivers/media/dvb/frontends/it913x-fe-priv.h)0
-rw-r--r--drivers/media/dvb-frontends/it913x-fe.c1045
-rw-r--r--drivers/media/dvb-frontends/it913x-fe.h (renamed from drivers/media/dvb/frontends/it913x-fe.h)0
-rw-r--r--drivers/media/dvb-frontends/itd1000.c (renamed from drivers/media/dvb/frontends/itd1000.c)0
-rw-r--r--drivers/media/dvb-frontends/itd1000.h (renamed from drivers/media/dvb/frontends/itd1000.h)0
-rw-r--r--drivers/media/dvb-frontends/itd1000_priv.h (renamed from drivers/media/dvb/frontends/itd1000_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/ix2505v.c (renamed from drivers/media/dvb/frontends/ix2505v.c)0
-rw-r--r--drivers/media/dvb-frontends/ix2505v.h (renamed from drivers/media/dvb/frontends/ix2505v.h)0
-rw-r--r--drivers/media/dvb-frontends/l64781.c (renamed from drivers/media/dvb/frontends/l64781.c)0
-rw-r--r--drivers/media/dvb-frontends/l64781.h (renamed from drivers/media/dvb/frontends/l64781.h)0
-rw-r--r--drivers/media/dvb-frontends/lg2160.c (renamed from drivers/media/dvb/frontends/lg2160.c)0
-rw-r--r--drivers/media/dvb-frontends/lg2160.h (renamed from drivers/media/dvb/frontends/lg2160.h)0
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.c (renamed from drivers/media/dvb/frontends/lgdt3305.c)0
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.h (renamed from drivers/media/dvb/frontends/lgdt3305.h)0
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c (renamed from drivers/media/dvb/frontends/lgdt330x.c)0
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.h (renamed from drivers/media/dvb/frontends/lgdt330x.h)0
-rw-r--r--drivers/media/dvb-frontends/lgdt330x_priv.h (renamed from drivers/media/dvb/frontends/lgdt330x_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.c453
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.h (renamed from drivers/media/dvb/frontends/lgs8gl5.h)0
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.c1075
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.h (renamed from drivers/media/dvb/frontends/lgs8gxx.h)0
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx_priv.h (renamed from drivers/media/dvb/frontends/lgs8gxx_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/lnbh24.h (renamed from drivers/media/dvb/frontends/lnbh24.h)0
-rw-r--r--drivers/media/dvb-frontends/lnbp21.c (renamed from drivers/media/dvb/frontends/lnbp21.c)0
-rw-r--r--drivers/media/dvb-frontends/lnbp21.h (renamed from drivers/media/dvb/frontends/lnbp21.h)0
-rw-r--r--drivers/media/dvb-frontends/lnbp22.c (renamed from drivers/media/dvb/frontends/lnbp22.c)0
-rw-r--r--drivers/media/dvb-frontends/lnbp22.h (renamed from drivers/media/dvb/frontends/lnbp22.h)0
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c919
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.h (renamed from drivers/media/dvb/frontends/m88rs2000.h)0
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c (renamed from drivers/media/dvb/frontends/mb86a16.c)0
-rw-r--r--drivers/media/dvb-frontends/mb86a16.h (renamed from drivers/media/dvb/frontends/mb86a16.h)0
-rw-r--r--drivers/media/dvb-frontends/mb86a16_priv.h (renamed from drivers/media/dvb/frontends/mb86a16_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c (renamed from drivers/media/dvb/frontends/mb86a20s.c)0
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h (renamed from drivers/media/dvb/frontends/mb86a20s.h)0
-rw-r--r--drivers/media/dvb-frontends/mt312.c (renamed from drivers/media/dvb/frontends/mt312.c)0
-rw-r--r--drivers/media/dvb-frontends/mt312.h (renamed from drivers/media/dvb/frontends/mt312.h)0
-rw-r--r--drivers/media/dvb-frontends/mt312_priv.h (renamed from drivers/media/dvb/frontends/mt312_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/mt352.c (renamed from drivers/media/dvb/frontends/mt352.c)0
-rw-r--r--drivers/media/dvb-frontends/mt352.h (renamed from drivers/media/dvb/frontends/mt352.h)0
-rw-r--r--drivers/media/dvb-frontends/mt352_priv.h (renamed from drivers/media/dvb/frontends/mt352_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/nxt200x.c1242
-rw-r--r--drivers/media/dvb-frontends/nxt200x.h (renamed from drivers/media/dvb/frontends/nxt200x.h)0
-rw-r--r--drivers/media/dvb-frontends/nxt6000.c (renamed from drivers/media/dvb/frontends/nxt6000.c)0
-rw-r--r--drivers/media/dvb-frontends/nxt6000.h (renamed from drivers/media/dvb/frontends/nxt6000.h)0
-rw-r--r--drivers/media/dvb-frontends/nxt6000_priv.h (renamed from drivers/media/dvb/frontends/nxt6000_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/or51132.c (renamed from drivers/media/dvb/frontends/or51132.c)0
-rw-r--r--drivers/media/dvb-frontends/or51132.h (renamed from drivers/media/dvb/frontends/or51132.h)0
-rw-r--r--drivers/media/dvb-frontends/or51211.c (renamed from drivers/media/dvb/frontends/or51211.c)0
-rw-r--r--drivers/media/dvb-frontends/or51211.h (renamed from drivers/media/dvb/frontends/or51211.h)0
-rw-r--r--drivers/media/dvb-frontends/rtl2830.c757
-rw-r--r--drivers/media/dvb-frontends/rtl2830.h (renamed from drivers/media/dvb/frontends/rtl2830.h)0
-rw-r--r--drivers/media/dvb-frontends/rtl2830_priv.h (renamed from drivers/media/dvb/frontends/rtl2830_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c (renamed from drivers/media/dvb/frontends/rtl2832.c)0
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h (renamed from drivers/media/dvb/frontends/rtl2832.h)0
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h (renamed from drivers/media/dvb/frontends/rtl2832_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/s5h1409.c (renamed from drivers/media/dvb/frontends/s5h1409.c)0
-rw-r--r--drivers/media/dvb-frontends/s5h1409.h (renamed from drivers/media/dvb/frontends/s5h1409.h)0
-rw-r--r--drivers/media/dvb-frontends/s5h1411.c (renamed from drivers/media/dvb/frontends/s5h1411.c)0
-rw-r--r--drivers/media/dvb-frontends/s5h1411.h (renamed from drivers/media/dvb/frontends/s5h1411.h)0
-rw-r--r--drivers/media/dvb-frontends/s5h1420.c (renamed from drivers/media/dvb/frontends/s5h1420.c)0
-rw-r--r--drivers/media/dvb-frontends/s5h1420.h (renamed from drivers/media/dvb/frontends/s5h1420.h)0
-rw-r--r--drivers/media/dvb-frontends/s5h1420_priv.h (renamed from drivers/media/dvb/frontends/s5h1420_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/s5h1432.c (renamed from drivers/media/dvb/frontends/s5h1432.c)0
-rw-r--r--drivers/media/dvb-frontends/s5h1432.h (renamed from drivers/media/dvb/frontends/s5h1432.h)0
-rw-r--r--drivers/media/dvb-frontends/s921.c (renamed from drivers/media/dvb/frontends/s921.c)0
-rw-r--r--drivers/media/dvb-frontends/s921.h (renamed from drivers/media/dvb/frontends/s921.h)0
-rw-r--r--drivers/media/dvb-frontends/si21xx.c (renamed from drivers/media/dvb/frontends/si21xx.c)0
-rw-r--r--drivers/media/dvb-frontends/si21xx.h (renamed from drivers/media/dvb/frontends/si21xx.h)0
-rw-r--r--drivers/media/dvb-frontends/sp8870.c (renamed from drivers/media/dvb/frontends/sp8870.c)0
-rw-r--r--drivers/media/dvb-frontends/sp8870.h (renamed from drivers/media/dvb/frontends/sp8870.h)0
-rw-r--r--drivers/media/dvb-frontends/sp887x.c (renamed from drivers/media/dvb/frontends/sp887x.c)0
-rw-r--r--drivers/media/dvb-frontends/sp887x.h (renamed from drivers/media/dvb/frontends/sp887x.h)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_algo.c (renamed from drivers/media/dvb/frontends/stb0899_algo.c)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_cfg.h (renamed from drivers/media/dvb/frontends/stb0899_cfg.h)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c (renamed from drivers/media/dvb/frontends/stb0899_drv.c)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.h (renamed from drivers/media/dvb/frontends/stb0899_drv.h)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_priv.h (renamed from drivers/media/dvb/frontends/stb0899_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/stb0899_reg.h (renamed from drivers/media/dvb/frontends/stb0899_reg.h)0
-rw-r--r--drivers/media/dvb-frontends/stb6000.c (renamed from drivers/media/dvb/frontends/stb6000.c)0
-rw-r--r--drivers/media/dvb-frontends/stb6000.h (renamed from drivers/media/dvb/frontends/stb6000.h)0
-rw-r--r--drivers/media/dvb-frontends/stb6100.c (renamed from drivers/media/dvb/frontends/stb6100.c)0
-rw-r--r--drivers/media/dvb-frontends/stb6100.h (renamed from drivers/media/dvb/frontends/stb6100.h)0
-rw-r--r--drivers/media/dvb-frontends/stb6100_cfg.h (renamed from drivers/media/dvb/frontends/stb6100_cfg.h)0
-rw-r--r--drivers/media/dvb-frontends/stb6100_proc.h (renamed from drivers/media/dvb/frontends/stb6100_proc.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0288.c (renamed from drivers/media/dvb/frontends/stv0288.c)0
-rw-r--r--drivers/media/dvb-frontends/stv0288.h (renamed from drivers/media/dvb/frontends/stv0288.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0297.c (renamed from drivers/media/dvb/frontends/stv0297.c)0
-rw-r--r--drivers/media/dvb-frontends/stv0297.h (renamed from drivers/media/dvb/frontends/stv0297.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0299.c (renamed from drivers/media/dvb/frontends/stv0299.c)0
-rw-r--r--drivers/media/dvb-frontends/stv0299.h (renamed from drivers/media/dvb/frontends/stv0299.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0367.c (renamed from drivers/media/dvb/frontends/stv0367.c)0
-rw-r--r--drivers/media/dvb-frontends/stv0367.h (renamed from drivers/media/dvb/frontends/stv0367.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0367_priv.h (renamed from drivers/media/dvb/frontends/stv0367_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0367_regs.h (renamed from drivers/media/dvb/frontends/stv0367_regs.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0900.h (renamed from drivers/media/dvb/frontends/stv0900.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c (renamed from drivers/media/dvb/frontends/stv0900_core.c)0
-rw-r--r--drivers/media/dvb-frontends/stv0900_init.h (renamed from drivers/media/dvb/frontends/stv0900_init.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0900_priv.h (renamed from drivers/media/dvb/frontends/stv0900_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0900_reg.h (renamed from drivers/media/dvb/frontends/stv0900_reg.h)0
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c (renamed from drivers/media/dvb/frontends/stv0900_sw.c)0
-rw-r--r--drivers/media/dvb-frontends/stv090x.c (renamed from drivers/media/dvb/frontends/stv090x.c)0
-rw-r--r--drivers/media/dvb-frontends/stv090x.h (renamed from drivers/media/dvb/frontends/stv090x.h)0
-rw-r--r--drivers/media/dvb-frontends/stv090x_priv.h (renamed from drivers/media/dvb/frontends/stv090x_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/stv090x_reg.h (renamed from drivers/media/dvb/frontends/stv090x_reg.h)0
-rw-r--r--drivers/media/dvb-frontends/stv6110.c (renamed from drivers/media/dvb/frontends/stv6110.c)0
-rw-r--r--drivers/media/dvb-frontends/stv6110.h (renamed from drivers/media/dvb/frontends/stv6110.h)0
-rw-r--r--drivers/media/dvb-frontends/stv6110x.c (renamed from drivers/media/dvb/frontends/stv6110x.c)0
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h (renamed from drivers/media/dvb/frontends/stv6110x.h)0
-rw-r--r--drivers/media/dvb-frontends/stv6110x_priv.h (renamed from drivers/media/dvb/frontends/stv6110x_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/stv6110x_reg.h (renamed from drivers/media/dvb/frontends/stv6110x_reg.h)0
-rw-r--r--drivers/media/dvb-frontends/tda10021.c (renamed from drivers/media/dvb/frontends/tda10021.c)0
-rw-r--r--drivers/media/dvb-frontends/tda10023.c (renamed from drivers/media/dvb/frontends/tda10023.c)0
-rw-r--r--drivers/media/dvb-frontends/tda1002x.h (renamed from drivers/media/dvb/frontends/tda1002x.h)0
-rw-r--r--drivers/media/dvb-frontends/tda10048.c (renamed from drivers/media/dvb/frontends/tda10048.c)0
-rw-r--r--drivers/media/dvb-frontends/tda10048.h (renamed from drivers/media/dvb/frontends/tda10048.h)0
-rw-r--r--drivers/media/dvb-frontends/tda1004x.c (renamed from drivers/media/dvb/frontends/tda1004x.c)0
-rw-r--r--drivers/media/dvb-frontends/tda1004x.h (renamed from drivers/media/dvb/frontends/tda1004x.h)0
-rw-r--r--drivers/media/dvb-frontends/tda10071.c (renamed from drivers/media/dvb/frontends/tda10071.c)0
-rw-r--r--drivers/media/dvb-frontends/tda10071.h (renamed from drivers/media/dvb/frontends/tda10071.h)0
-rw-r--r--drivers/media/dvb-frontends/tda10071_priv.h (renamed from drivers/media/dvb/frontends/tda10071_priv.h)0
-rw-r--r--drivers/media/dvb-frontends/tda10086.c (renamed from drivers/media/dvb/frontends/tda10086.c)0
-rw-r--r--drivers/media/dvb-frontends/tda10086.h (renamed from drivers/media/dvb/frontends/tda10086.h)0
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.c (renamed from drivers/media/dvb/frontends/tda18271c2dd.c)0
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.h (renamed from drivers/media/dvb/frontends/tda18271c2dd.h)0
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd_maps.h (renamed from drivers/media/dvb/frontends/tda18271c2dd_maps.h)0
-rw-r--r--drivers/media/dvb-frontends/tda665x.c (renamed from drivers/media/dvb/frontends/tda665x.c)0
-rw-r--r--drivers/media/dvb-frontends/tda665x.h (renamed from drivers/media/dvb/frontends/tda665x.h)0
-rw-r--r--drivers/media/dvb-frontends/tda8083.c (renamed from drivers/media/dvb/frontends/tda8083.c)0
-rw-r--r--drivers/media/dvb-frontends/tda8083.h (renamed from drivers/media/dvb/frontends/tda8083.h)0
-rw-r--r--drivers/media/dvb-frontends/tda8261.c (renamed from drivers/media/dvb/frontends/tda8261.c)0
-rw-r--r--drivers/media/dvb-frontends/tda8261.h (renamed from drivers/media/dvb/frontends/tda8261.h)0
-rw-r--r--drivers/media/dvb-frontends/tda8261_cfg.h (renamed from drivers/media/dvb/frontends/tda8261_cfg.h)0
-rw-r--r--drivers/media/dvb-frontends/tda826x.c (renamed from drivers/media/dvb/frontends/tda826x.c)0
-rw-r--r--drivers/media/dvb-frontends/tda826x.h (renamed from drivers/media/dvb/frontends/tda826x.h)0
-rw-r--r--drivers/media/dvb-frontends/tdhd1.h (renamed from drivers/media/dvb/frontends/tdhd1.h)0
-rw-r--r--drivers/media/dvb-frontends/tua6100.c (renamed from drivers/media/dvb/frontends/tua6100.c)0
-rw-r--r--drivers/media/dvb-frontends/tua6100.h (renamed from drivers/media/dvb/frontends/tua6100.h)0
-rw-r--r--drivers/media/dvb-frontends/ves1820.c (renamed from drivers/media/dvb/frontends/ves1820.c)0
-rw-r--r--drivers/media/dvb-frontends/ves1820.h (renamed from drivers/media/dvb/frontends/ves1820.h)0
-rw-r--r--drivers/media/dvb-frontends/ves1x93.c (renamed from drivers/media/dvb/frontends/ves1x93.c)0
-rw-r--r--drivers/media/dvb-frontends/ves1x93.h (renamed from drivers/media/dvb/frontends/ves1x93.h)0
-rw-r--r--drivers/media/dvb-frontends/z0194a.h (renamed from drivers/media/dvb/frontends/z0194a.h)0
-rw-r--r--drivers/media/dvb-frontends/zl10036.c (renamed from drivers/media/dvb/frontends/zl10036.c)0
-rw-r--r--drivers/media/dvb-frontends/zl10036.h (renamed from drivers/media/dvb/frontends/zl10036.h)0
-rw-r--r--drivers/media/dvb-frontends/zl10039.c (renamed from drivers/media/dvb/frontends/zl10039.c)0
-rw-r--r--drivers/media/dvb-frontends/zl10039.h (renamed from drivers/media/dvb/frontends/zl10039.h)0
-rw-r--r--drivers/media/dvb-frontends/zl10353.c (renamed from drivers/media/dvb/frontends/zl10353.c)0
-rw-r--r--drivers/media/dvb-frontends/zl10353.h (renamed from drivers/media/dvb/frontends/zl10353.h)0
-rw-r--r--drivers/media/dvb-frontends/zl10353_priv.h (renamed from drivers/media/dvb/frontends/zl10353_priv.h)0
-rw-r--r--drivers/media/dvb/Kconfig91
-rw-r--r--drivers/media/dvb/Makefile21
-rw-r--r--drivers/media/dvb/b2c2/Kconfig45
-rw-r--r--drivers/media/dvb/b2c2/Makefile16
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c590
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c324
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig22
-rw-r--r--drivers/media/dvb/bt8xx/Makefile6
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c725
-rw-r--r--drivers/media/dvb/ddbridge/Kconfig18
-rw-r--r--drivers/media/dvb/ddbridge/Makefile14
-rw-r--r--drivers/media/dvb/dm1105/Kconfig20
-rw-r--r--drivers/media/dvb/dm1105/Makefile3
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c1277
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c1309
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c2563
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h423
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h172
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig440
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile121
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c1952
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h132
-rw-r--r--drivers/media/dvb/dvb-usb/af9035.c1242
-rw-r--r--drivers/media/dvb/dvb-usb/af9035.h113
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c1406
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.h332
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c252
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.h39
-rw-r--r--drivers/media/dvb/dvb-usb/az6007.c955
-rw-r--r--drivers/media/dvb/dvb-usb/ce6230.c324
-rw-r--r--drivers/media/dvb/dvb-usb/ce6230.h69
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c845
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c289
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h485
-rw-r--r--drivers/media/dvb/dvb-usb/ec168.c435
-rw-r--r--drivers/media/dvb/dvb-usb/ec168.h73
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c217
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.h15
-rw-r--r--drivers/media/dvb/dvb-usb/it913x.c931
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c1407
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf-tuner.c525
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf.c1835
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf.h158
-rw-r--r--drivers/media/dvb/dvb-usb/pctv452e.c1064
-rw-r--r--drivers/media/dvb/dvb-usb/rtl28xxu.c1428
-rw-r--r--drivers/media/dvb/dvb-usb/rtl28xxu.h264
-rw-r--r--drivers/media/dvb/firewire/Makefile6
-rw-r--r--drivers/media/dvb/frontends/Kconfig756
-rw-r--r--drivers/media/dvb/frontends/Makefile105
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c508
-rw-r--r--drivers/media/dvb/frontends/au8522_common.c259
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c842
-rw-r--r--drivers/media/dvb/frontends/au8522_dig.c826
-rw-r--r--drivers/media/dvb/frontends/au8522_priv.h423
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t.c453
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c794
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h56
-rw-r--r--drivers/media/dvb/frontends/it913x-fe.c1045
-rw-r--r--drivers/media/dvb/frontends/lgs8gl5.c453
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c1075
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.c919
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c1240
-rw-r--r--drivers/media/dvb/frontends/rtl2830.c757
-rw-r--r--drivers/media/dvb/mantis/Kconfig38
-rw-r--r--drivers/media/dvb/mantis/Makefile28
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c307
-rw-r--r--drivers/media/dvb/mantis/mantis_core.c235
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c299
-rw-r--r--drivers/media/dvb/ngene/Kconfig13
-rw-r--r--drivers/media/dvb/ngene/Makefile14
-rw-r--r--drivers/media/dvb/ngene/ngene-cards.c560
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c1713
-rw-r--r--drivers/media/dvb/pluto2/Makefile3
-rw-r--r--drivers/media/dvb/pt1/Makefile5
-rw-r--r--drivers/media/dvb/siano/Kconfig34
-rw-r--r--drivers/media/dvb/siano/Makefile11
-rw-r--r--drivers/media/dvb/ttpci/Kconfig159
-rw-r--r--drivers/media/dvb/ttpci/Makefile21
-rw-r--r--drivers/media/dvb/ttpci/budget.c811
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig18
-rw-r--r--drivers/media/dvb/ttusb-budget/Makefile3
-rw-r--r--drivers/media/dvb/ttusb-dec/Makefile3
-rw-r--r--drivers/media/firewire/Kconfig (renamed from drivers/media/dvb/firewire/Kconfig)0
-rw-r--r--drivers/media/firewire/Makefile6
-rw-r--r--drivers/media/firewire/firedtv-avc.c (renamed from drivers/media/dvb/firewire/firedtv-avc.c)0
-rw-r--r--drivers/media/firewire/firedtv-ci.c (renamed from drivers/media/dvb/firewire/firedtv-ci.c)0
-rw-r--r--drivers/media/firewire/firedtv-dvb.c (renamed from drivers/media/dvb/firewire/firedtv-dvb.c)0
-rw-r--r--drivers/media/firewire/firedtv-fe.c (renamed from drivers/media/dvb/firewire/firedtv-fe.c)0
-rw-r--r--drivers/media/firewire/firedtv-fw.c (renamed from drivers/media/dvb/firewire/firedtv-fw.c)0
-rw-r--r--drivers/media/firewire/firedtv-rc.c (renamed from drivers/media/dvb/firewire/firedtv-rc.c)0
-rw-r--r--drivers/media/firewire/firedtv.h (renamed from drivers/media/dvb/firewire/firedtv.h)0
-rw-r--r--drivers/media/i2c/Kconfig561
-rw-r--r--drivers/media/i2c/Makefile64
-rw-r--r--drivers/media/i2c/adp1653.c487
-rw-r--r--drivers/media/i2c/adv7170.c (renamed from drivers/media/video/adv7170.c)0
-rw-r--r--drivers/media/i2c/adv7175.c (renamed from drivers/media/video/adv7175.c)0
-rw-r--r--drivers/media/i2c/adv7180.c (renamed from drivers/media/video/adv7180.c)0
-rw-r--r--drivers/media/i2c/adv7183.c (renamed from drivers/media/video/adv7183.c)0
-rw-r--r--drivers/media/i2c/adv7183_regs.h (renamed from drivers/media/video/adv7183_regs.h)0
-rw-r--r--drivers/media/i2c/adv7343.c (renamed from drivers/media/video/adv7343.c)0
-rw-r--r--drivers/media/i2c/adv7343_regs.h (renamed from drivers/media/video/adv7343_regs.h)0
-rw-r--r--drivers/media/i2c/adv7393.c (renamed from drivers/media/video/adv7393.c)0
-rw-r--r--drivers/media/i2c/adv7393_regs.h (renamed from drivers/media/video/adv7393_regs.h)0
-rw-r--r--drivers/media/i2c/ak881x.c (renamed from drivers/media/video/ak881x.c)0
-rw-r--r--drivers/media/i2c/aptina-pll.c (renamed from drivers/media/video/aptina-pll.c)0
-rw-r--r--drivers/media/i2c/aptina-pll.h (renamed from drivers/media/video/aptina-pll.h)0
-rw-r--r--drivers/media/i2c/as3645a.c888
-rw-r--r--drivers/media/i2c/bt819.c (renamed from drivers/media/video/bt819.c)0
-rw-r--r--drivers/media/i2c/bt856.c (renamed from drivers/media/video/bt856.c)0
-rw-r--r--drivers/media/i2c/bt866.c (renamed from drivers/media/video/bt866.c)0
-rw-r--r--drivers/media/i2c/btcx-risc.c (renamed from drivers/media/video/btcx-risc.c)0
-rw-r--r--drivers/media/i2c/btcx-risc.h (renamed from drivers/media/video/btcx-risc.h)0
-rw-r--r--drivers/media/i2c/cs5345.c (renamed from drivers/media/video/cs5345.c)0
-rw-r--r--drivers/media/i2c/cs53l32a.c (renamed from drivers/media/video/cs53l32a.c)0
-rw-r--r--drivers/media/i2c/cx2341x.c (renamed from drivers/media/video/cx2341x.c)0
-rw-r--r--drivers/media/i2c/cx25840/Kconfig (renamed from drivers/media/video/cx25840/Kconfig)0
-rw-r--r--drivers/media/i2c/cx25840/Makefile6
-rw-r--r--drivers/media/i2c/cx25840/cx25840-audio.c (renamed from drivers/media/video/cx25840/cx25840-audio.c)0
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c (renamed from drivers/media/video/cx25840/cx25840-core.c)0
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.h (renamed from drivers/media/video/cx25840/cx25840-core.h)0
-rw-r--r--drivers/media/i2c/cx25840/cx25840-firmware.c175
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c (renamed from drivers/media/video/cx25840/cx25840-ir.c)0
-rw-r--r--drivers/media/i2c/cx25840/cx25840-vbi.c (renamed from drivers/media/video/cx25840/cx25840-vbi.c)0
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c (renamed from drivers/media/video/ir-kbd-i2c.c)0
-rw-r--r--drivers/media/i2c/ks0127.c (renamed from drivers/media/video/ks0127.c)0
-rw-r--r--drivers/media/i2c/ks0127.h (renamed from drivers/media/video/ks0127.h)0
-rw-r--r--drivers/media/i2c/m52790.c (renamed from drivers/media/video/m52790.c)0
-rw-r--r--drivers/media/i2c/m5mols/Kconfig (renamed from drivers/media/video/m5mols/Kconfig)0
-rw-r--r--drivers/media/i2c/m5mols/Makefile (renamed from drivers/media/video/m5mols/Makefile)0
-rw-r--r--drivers/media/i2c/m5mols/m5mols.h (renamed from drivers/media/video/m5mols/m5mols.h)0
-rw-r--r--drivers/media/i2c/m5mols/m5mols_capture.c (renamed from drivers/media/video/m5mols/m5mols_capture.c)0
-rw-r--r--drivers/media/i2c/m5mols/m5mols_controls.c (renamed from drivers/media/video/m5mols/m5mols_controls.c)0
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c (renamed from drivers/media/video/m5mols/m5mols_core.c)0
-rw-r--r--drivers/media/i2c/m5mols/m5mols_reg.h (renamed from drivers/media/video/m5mols/m5mols_reg.h)0
-rw-r--r--drivers/media/i2c/msp3400-driver.c (renamed from drivers/media/video/msp3400-driver.c)0
-rw-r--r--drivers/media/i2c/msp3400-driver.h (renamed from drivers/media/video/msp3400-driver.h)0
-rw-r--r--drivers/media/i2c/msp3400-kthreads.c (renamed from drivers/media/video/msp3400-kthreads.c)0
-rw-r--r--drivers/media/i2c/mt9m032.c (renamed from drivers/media/video/mt9m032.c)0
-rw-r--r--drivers/media/i2c/mt9p031.c (renamed from drivers/media/video/mt9p031.c)0
-rw-r--r--drivers/media/i2c/mt9t001.c (renamed from drivers/media/video/mt9t001.c)0
-rw-r--r--drivers/media/i2c/mt9v011.c (renamed from drivers/media/video/mt9v011.c)0
-rw-r--r--drivers/media/i2c/mt9v032.c (renamed from drivers/media/video/mt9v032.c)0
-rw-r--r--drivers/media/i2c/noon010pc30.c (renamed from drivers/media/video/noon010pc30.c)0
-rw-r--r--drivers/media/i2c/ov7670.c (renamed from drivers/media/video/ov7670.c)0
-rw-r--r--drivers/media/i2c/s5k6aa.c1667
-rw-r--r--drivers/media/i2c/saa6588.c (renamed from drivers/media/video/saa6588.c)0
-rw-r--r--drivers/media/i2c/saa7110.c (renamed from drivers/media/video/saa7110.c)0
-rw-r--r--drivers/media/i2c/saa7115.c (renamed from drivers/media/video/saa7115.c)0
-rw-r--r--drivers/media/i2c/saa711x_regs.h (renamed from drivers/media/video/saa711x_regs.h)0
-rw-r--r--drivers/media/i2c/saa7127.c852
-rw-r--r--drivers/media/i2c/saa717x.c (renamed from drivers/media/video/saa717x.c)0
-rw-r--r--drivers/media/i2c/saa7185.c (renamed from drivers/media/video/saa7185.c)0
-rw-r--r--drivers/media/i2c/saa7191.c (renamed from drivers/media/video/saa7191.c)0
-rw-r--r--drivers/media/i2c/saa7191.h (renamed from drivers/media/video/saa7191.h)0
-rw-r--r--drivers/media/i2c/smiapp-pll.c418
-rw-r--r--drivers/media/i2c/smiapp-pll.h103
-rw-r--r--drivers/media/i2c/smiapp/Kconfig (renamed from drivers/media/video/smiapp/Kconfig)0
-rw-r--r--drivers/media/i2c/smiapp/Makefile5
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c2895
-rw-r--r--drivers/media/i2c/smiapp/smiapp-limits.c132
-rw-r--r--drivers/media/i2c/smiapp/smiapp-limits.h128
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.c306
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.h83
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg-defs.h503
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg.h122
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.c273
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.h (renamed from drivers/media/video/smiapp/smiapp-regs.h)0
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h252
-rw-r--r--drivers/media/i2c/soc_camera/Kconfig89
-rw-r--r--drivers/media/i2c/soc_camera/Makefile14
-rw-r--r--drivers/media/i2c/soc_camera/imx074.c495
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c757
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c1046
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c857
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c1142
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c919
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c1122
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c1088
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c1069
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c1137
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c763
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.h (renamed from drivers/media/video/ov9640.h)0
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c1020
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c1431
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c973
-rw-r--r--drivers/media/i2c/sr030pc30.c (renamed from drivers/media/video/sr030pc30.c)0
-rw-r--r--drivers/media/i2c/tcm825x.c937
-rw-r--r--drivers/media/i2c/tcm825x.h200
-rw-r--r--drivers/media/i2c/tda7432.c (renamed from drivers/media/video/tda7432.c)0
-rw-r--r--drivers/media/i2c/tda9840.c (renamed from drivers/media/video/tda9840.c)0
-rw-r--r--drivers/media/i2c/tea6415c.c (renamed from drivers/media/video/tea6415c.c)0
-rw-r--r--drivers/media/i2c/tea6415c.h (renamed from drivers/media/video/tea6415c.h)0
-rw-r--r--drivers/media/i2c/tea6420.c (renamed from drivers/media/video/tea6420.c)0
-rw-r--r--drivers/media/i2c/tea6420.h (renamed from drivers/media/video/tea6420.h)0
-rw-r--r--drivers/media/i2c/ths7303.c (renamed from drivers/media/video/ths7303.c)0
-rw-r--r--drivers/media/i2c/tlv320aic23b.c (renamed from drivers/media/video/tlv320aic23b.c)0
-rw-r--r--drivers/media/i2c/tvaudio.c (renamed from drivers/media/video/tvaudio.c)0
-rw-r--r--drivers/media/i2c/tveeprom.c (renamed from drivers/media/video/tveeprom.c)0
-rw-r--r--drivers/media/i2c/tvp514x.c1166
-rw-r--r--drivers/media/i2c/tvp514x_regs.h287
-rw-r--r--drivers/media/i2c/tvp5150.c (renamed from drivers/media/video/tvp5150.c)0
-rw-r--r--drivers/media/i2c/tvp5150_reg.h (renamed from drivers/media/video/tvp5150_reg.h)0
-rw-r--r--drivers/media/i2c/tvp7002.c (renamed from drivers/media/video/tvp7002.c)0
-rw-r--r--drivers/media/i2c/tvp7002_reg.h (renamed from drivers/media/video/tvp7002_reg.h)0
-rw-r--r--drivers/media/i2c/upd64031a.c (renamed from drivers/media/video/upd64031a.c)0
-rw-r--r--drivers/media/i2c/upd64083.c (renamed from drivers/media/video/upd64083.c)0
-rw-r--r--drivers/media/i2c/vp27smpx.c (renamed from drivers/media/video/vp27smpx.c)0
-rw-r--r--drivers/media/i2c/vpx3220.c (renamed from drivers/media/video/vpx3220.c)0
-rw-r--r--drivers/media/i2c/vs6624.c (renamed from drivers/media/video/vs6624.c)0
-rw-r--r--drivers/media/i2c/vs6624_regs.h (renamed from drivers/media/video/vs6624_regs.h)0
-rw-r--r--drivers/media/i2c/wm8739.c (renamed from drivers/media/video/wm8739.c)0
-rw-r--r--drivers/media/i2c/wm8775.c (renamed from drivers/media/video/wm8775.c)0
-rw-r--r--drivers/media/media-device.c4
-rw-r--r--drivers/media/mmc/Kconfig2
-rw-r--r--drivers/media/mmc/Makefile1
-rw-r--r--drivers/media/mmc/siano/Kconfig10
-rw-r--r--drivers/media/mmc/siano/Makefile6
-rw-r--r--drivers/media/mmc/siano/smssdio.c (renamed from drivers/media/dvb/siano/smssdio.c)0
-rw-r--r--drivers/media/parport/Kconfig52
-rw-r--r--drivers/media/parport/Makefile4
-rw-r--r--drivers/media/parport/bw-qcam.c (renamed from drivers/media/video/bw-qcam.c)0
-rw-r--r--drivers/media/parport/c-qcam.c (renamed from drivers/media/video/c-qcam.c)0
-rw-r--r--drivers/media/parport/pms.c (renamed from drivers/media/video/pms.c)0
-rw-r--r--drivers/media/parport/w9966.c (renamed from drivers/media/video/w9966.c)0
-rw-r--r--drivers/media/pci/Kconfig47
-rw-r--r--drivers/media/pci/Makefile26
-rw-r--r--drivers/media/pci/b2c2/Kconfig15
-rw-r--r--drivers/media/pci/b2c2/Makefile9
-rw-r--r--drivers/media/pci/b2c2/flexcop-dma.c (renamed from drivers/media/dvb/b2c2/flexcop-dma.c)0
-rw-r--r--drivers/media/pci/b2c2/flexcop-pci.c (renamed from drivers/media/dvb/b2c2/flexcop-pci.c)0
-rw-r--r--drivers/media/pci/bt8xx/Kconfig43
-rw-r--r--drivers/media/pci/bt8xx/Makefile11
-rw-r--r--drivers/media/pci/bt8xx/bt848.h (renamed from drivers/media/video/bt8xx/bt848.h)0
-rw-r--r--drivers/media/pci/bt8xx/bt878.c (renamed from drivers/media/dvb/bt8xx/bt878.c)0
-rw-r--r--drivers/media/pci/bt8xx/bt878.h (renamed from drivers/media/dvb/bt8xx/bt878.h)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-audio-hook.c (renamed from drivers/media/video/bt8xx/bttv-audio-hook.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-audio-hook.h (renamed from drivers/media/video/bt8xx/bttv-audio-hook.h)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c (renamed from drivers/media/video/bt8xx/bttv-cards.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c (renamed from drivers/media/video/bt8xx/bttv-driver.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-gpio.c (renamed from drivers/media/video/bt8xx/bttv-gpio.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-i2c.c (renamed from drivers/media/video/bt8xx/bttv-i2c.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-if.c (renamed from drivers/media/video/bt8xx/bttv-if.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-input.c (renamed from drivers/media/video/bt8xx/bttv-input.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-risc.c (renamed from drivers/media/video/bt8xx/bttv-risc.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-vbi.c (renamed from drivers/media/video/bt8xx/bttv-vbi.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv.h (renamed from drivers/media/video/bt8xx/bttv.h)0
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h (renamed from drivers/media/video/bt8xx/bttvp.h)0
-rw-r--r--drivers/media/pci/bt8xx/dst.c (renamed from drivers/media/dvb/bt8xx/dst.c)0
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c726
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.h (renamed from drivers/media/dvb/bt8xx/dst_ca.h)0
-rw-r--r--drivers/media/pci/bt8xx/dst_common.h (renamed from drivers/media/dvb/bt8xx/dst_common.h)0
-rw-r--r--drivers/media/pci/bt8xx/dst_priv.h (renamed from drivers/media/dvb/bt8xx/dst_priv.h)0
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.c (renamed from drivers/media/dvb/bt8xx/dvb-bt8xx.c)0
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.h (renamed from drivers/media/dvb/bt8xx/dvb-bt8xx.h)0
-rw-r--r--drivers/media/pci/cx18/Kconfig35
-rw-r--r--drivers/media/pci/cx18/Makefile13
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c (renamed from drivers/media/video/cx18/cx18-alsa-main.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-mixer.c (renamed from drivers/media/video/cx18/cx18-alsa-mixer.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-mixer.h (renamed from drivers/media/video/cx18/cx18-alsa-mixer.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-pcm.c (renamed from drivers/media/video/cx18/cx18-alsa-pcm.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-pcm.h (renamed from drivers/media/video/cx18/cx18-alsa-pcm.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-alsa.h (renamed from drivers/media/video/cx18/cx18-alsa.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-audio.c (renamed from drivers/media/video/cx18/cx18-audio.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-audio.h (renamed from drivers/media/video/cx18/cx18-audio.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-av-audio.c (renamed from drivers/media/video/cx18/cx18-av-audio.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c (renamed from drivers/media/video/cx18/cx18-av-core.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.h (renamed from drivers/media/video/cx18/cx18-av-core.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-av-firmware.c225
-rw-r--r--drivers/media/pci/cx18/cx18-av-vbi.c (renamed from drivers/media/video/cx18/cx18-av-vbi.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-cards.c (renamed from drivers/media/video/cx18/cx18-cards.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-cards.h (renamed from drivers/media/video/cx18/cx18-cards.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-controls.c (renamed from drivers/media/video/cx18/cx18-controls.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-controls.h (renamed from drivers/media/video/cx18/cx18-controls.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c1360
-rw-r--r--drivers/media/pci/cx18/cx18-driver.h (renamed from drivers/media/video/cx18/cx18-driver.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-dvb.c609
-rw-r--r--drivers/media/pci/cx18/cx18-dvb.h (renamed from drivers/media/video/cx18/cx18-dvb.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.c (renamed from drivers/media/video/cx18/cx18-fileops.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.h (renamed from drivers/media/video/cx18/cx18-fileops.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-firmware.c459
-rw-r--r--drivers/media/pci/cx18/cx18-firmware.h (renamed from drivers/media/video/cx18/cx18-firmware.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-gpio.c (renamed from drivers/media/video/cx18/cx18-gpio.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-gpio.h (renamed from drivers/media/video/cx18/cx18-gpio.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-i2c.c (renamed from drivers/media/video/cx18/cx18-i2c.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-i2c.h (renamed from drivers/media/video/cx18/cx18-i2c.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-io.c (renamed from drivers/media/video/cx18/cx18-io.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-io.h (renamed from drivers/media/video/cx18/cx18-io.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c (renamed from drivers/media/video/cx18/cx18-ioctl.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.h (renamed from drivers/media/video/cx18/cx18-ioctl.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-irq.c (renamed from drivers/media/video/cx18/cx18-irq.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-irq.h (renamed from drivers/media/video/cx18/cx18-irq.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-mailbox.c (renamed from drivers/media/video/cx18/cx18-mailbox.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-mailbox.h (renamed from drivers/media/video/cx18/cx18-mailbox.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-queue.c (renamed from drivers/media/video/cx18/cx18-queue.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-queue.h (renamed from drivers/media/video/cx18/cx18-queue.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-scb.c (renamed from drivers/media/video/cx18/cx18-scb.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-scb.h (renamed from drivers/media/video/cx18/cx18-scb.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c (renamed from drivers/media/video/cx18/cx18-streams.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-streams.h (renamed from drivers/media/video/cx18/cx18-streams.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-vbi.c (renamed from drivers/media/video/cx18/cx18-vbi.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-vbi.h (renamed from drivers/media/video/cx18/cx18-vbi.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-version.h (renamed from drivers/media/video/cx18/cx18-version.h)0
-rw-r--r--drivers/media/pci/cx18/cx18-video.c (renamed from drivers/media/video/cx18/cx18-video.c)0
-rw-r--r--drivers/media/pci/cx18/cx18-video.h (renamed from drivers/media/video/cx18/cx18-video.h)0
-rw-r--r--drivers/media/pci/cx18/cx23418.h (renamed from drivers/media/video/cx18/cx23418.h)0
-rw-r--r--drivers/media/pci/cx23885/Kconfig46
-rw-r--r--drivers/media/pci/cx23885/Makefile15
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c (renamed from drivers/media/video/cx23885/altera-ci.c)0
-rw-r--r--drivers/media/pci/cx23885/altera-ci.h (renamed from drivers/media/video/cx23885/altera-ci.h)0
-rw-r--r--drivers/media/pci/cx23885/cimax2.c (renamed from drivers/media/video/cx23885/cimax2.c)0
-rw-r--r--drivers/media/pci/cx23885/cimax2.h (renamed from drivers/media/video/cx23885/cimax2.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c1790
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c (renamed from drivers/media/video/cx23885/cx23885-alsa.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.c (renamed from drivers/media/video/cx23885/cx23885-av.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.h (renamed from drivers/media/video/cx23885/cx23885-av.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c1684
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c (renamed from drivers/media/video/cx23885/cx23885-core.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c1356
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.c (renamed from drivers/media/video/cx23885/cx23885-f300.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.h (renamed from drivers/media/video/cx23885/cx23885-f300.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c (renamed from drivers/media/video/cx23885/cx23885-i2c.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c365
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.h (renamed from drivers/media/video/cx23885/cx23885-input.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c (renamed from drivers/media/video/cx23885/cx23885-ioctl.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.h (renamed from drivers/media/video/cx23885/cx23885-ioctl.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.c (renamed from drivers/media/video/cx23885/cx23885-ir.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.h (renamed from drivers/media/video/cx23885/cx23885-ir.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-reg.h (renamed from drivers/media/video/cx23885/cx23885-reg.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c (renamed from drivers/media/video/cx23885/cx23885-vbi.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c (renamed from drivers/media/video/cx23885/cx23885-video.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23885.h (renamed from drivers/media/video/cx23885/cx23885.h)0
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c (renamed from drivers/media/video/cx23885/cx23888-ir.c)0
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.h (renamed from drivers/media/video/cx23885/cx23888-ir.h)0
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.c (renamed from drivers/media/video/cx23885/netup-eeprom.c)0
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.h (renamed from drivers/media/video/cx23885/netup-eeprom.h)0
-rw-r--r--drivers/media/pci/cx23885/netup-init.c (renamed from drivers/media/video/cx23885/netup-init.c)0
-rw-r--r--drivers/media/pci/cx23885/netup-init.h (renamed from drivers/media/video/cx23885/netup-init.h)0
-rw-r--r--drivers/media/pci/cx25821/Kconfig (renamed from drivers/media/video/cx25821/Kconfig)0
-rw-r--r--drivers/media/pci/cx25821/Makefile13
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c (renamed from drivers/media/video/cx25821/cx25821-alsa.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-audio-upstream.c (renamed from drivers/media/video/cx25821/cx25821-audio-upstream.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-audio-upstream.h (renamed from drivers/media/video/cx25821/cx25821-audio-upstream.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-audio.h (renamed from drivers/media/video/cx25821/cx25821-audio.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-biffuncs.h (renamed from drivers/media/video/cx25821/cx25821-biffuncs.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-cards.c (renamed from drivers/media/video/cx25821/cx25821-cards.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c (renamed from drivers/media/video/cx25821/cx25821-core.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-gpio.c (renamed from drivers/media/video/cx25821/cx25821-gpio.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-i2c.c (renamed from drivers/media/video/cx25821/cx25821-i2c.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-defines.h (renamed from drivers/media/video/cx25821/cx25821-medusa-defines.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-reg.h (renamed from drivers/media/video/cx25821/cx25821-medusa-reg.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-video.c (renamed from drivers/media/video/cx25821/cx25821-medusa-video.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-video.h (renamed from drivers/media/video/cx25821/cx25821-medusa-video.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-reg.h (renamed from drivers/media/video/cx25821/cx25821-reg.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-sram.h (renamed from drivers/media/video/cx25821/cx25821-sram.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c (renamed from drivers/media/video/cx25821/cx25821-video-upstream-ch2.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h (renamed from drivers/media/video/cx25821/cx25821-video-upstream-ch2.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream.c (renamed from drivers/media/video/cx25821/cx25821-video-upstream.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream.h (renamed from drivers/media/video/cx25821/cx25821-video-upstream.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c (renamed from drivers/media/video/cx25821/cx25821-video.c)0
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.h (renamed from drivers/media/video/cx25821/cx25821-video.h)0
-rw-r--r--drivers/media/pci/cx25821/cx25821.h (renamed from drivers/media/video/cx25821/cx25821.h)0
-rw-r--r--drivers/media/pci/cx88/Kconfig86
-rw-r--r--drivers/media/pci/cx88/Makefile16
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c975
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c (renamed from drivers/media/video/cx88/cx88-blackbird.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c (renamed from drivers/media/video/cx88/cx88-cards.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-core.c1131
-rw-r--r--drivers/media/pci/cx88/cx88-dsp.c (renamed from drivers/media/video/cx88/cx88-dsp.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c1778
-rw-r--r--drivers/media/pci/cx88/cx88-i2c.c (renamed from drivers/media/video/cx88/cx88-i2c.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-input.c (renamed from drivers/media/video/cx88/cx88-input.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c (renamed from drivers/media/video/cx88/cx88-mpeg.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-reg.h (renamed from drivers/media/video/cx88/cx88-reg.h)0
-rw-r--r--drivers/media/pci/cx88/cx88-tvaudio.c (renamed from drivers/media/video/cx88/cx88-tvaudio.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c (renamed from drivers/media/video/cx88/cx88-vbi.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-video.c (renamed from drivers/media/video/cx88/cx88-video.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-vp3054-i2c.c (renamed from drivers/media/video/cx88/cx88-vp3054-i2c.c)0
-rw-r--r--drivers/media/pci/cx88/cx88-vp3054-i2c.h (renamed from drivers/media/video/cx88/cx88-vp3054-i2c.h)0
-rw-r--r--drivers/media/pci/cx88/cx88.h748
-rw-r--r--drivers/media/pci/ddbridge/Kconfig18
-rw-r--r--drivers/media/pci/ddbridge/Makefile14
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c (renamed from drivers/media/dvb/ddbridge/ddbridge-core.c)0
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-regs.h (renamed from drivers/media/dvb/ddbridge/ddbridge-regs.h)0
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h (renamed from drivers/media/dvb/ddbridge/ddbridge.h)0
-rw-r--r--drivers/media/pci/dm1105/Kconfig20
-rw-r--r--drivers/media/pci/dm1105/Makefile3
-rw-r--r--drivers/media/pci/dm1105/dm1105.c (renamed from drivers/media/dvb/dm1105/dm1105.c)0
-rw-r--r--drivers/media/pci/ivtv/Kconfig (renamed from drivers/media/video/ivtv/Kconfig)0
-rw-r--r--drivers/media/pci/ivtv/Makefile14
-rw-r--r--drivers/media/pci/ivtv/ivtv-cards.c (renamed from drivers/media/video/ivtv/ivtv-cards.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-cards.h (renamed from drivers/media/video/ivtv/ivtv-cards.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.c (renamed from drivers/media/video/ivtv/ivtv-controls.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.h (renamed from drivers/media/video/ivtv/ivtv-controls.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c (renamed from drivers/media/video/ivtv/ivtv-driver.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h (renamed from drivers/media/video/ivtv/ivtv-driver.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c1070
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.h (renamed from drivers/media/video/ivtv/ivtv-fileops.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-firmware.c402
-rw-r--r--drivers/media/pci/ivtv/ivtv-firmware.h (renamed from drivers/media/video/ivtv/ivtv-firmware.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-gpio.c (renamed from drivers/media/video/ivtv/ivtv-gpio.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-gpio.h (renamed from drivers/media/video/ivtv/ivtv-gpio.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-i2c.c (renamed from drivers/media/video/ivtv/ivtv-i2c.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-i2c.h (renamed from drivers/media/video/ivtv/ivtv-i2c.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c (renamed from drivers/media/video/ivtv/ivtv-ioctl.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.h (renamed from drivers/media/video/ivtv/ivtv-ioctl.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.c (renamed from drivers/media/video/ivtv/ivtv-irq.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.h (renamed from drivers/media/video/ivtv/ivtv-irq.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-mailbox.c (renamed from drivers/media/video/ivtv/ivtv-mailbox.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-mailbox.h (renamed from drivers/media/video/ivtv/ivtv-mailbox.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-queue.c (renamed from drivers/media/video/ivtv/ivtv-queue.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-queue.h (renamed from drivers/media/video/ivtv/ivtv-queue.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-routing.c (renamed from drivers/media/video/ivtv/ivtv-routing.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-routing.h (renamed from drivers/media/video/ivtv/ivtv-routing.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.c1014
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.h (renamed from drivers/media/video/ivtv/ivtv-streams.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-udma.c (renamed from drivers/media/video/ivtv/ivtv-udma.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-udma.h (renamed from drivers/media/video/ivtv/ivtv-udma.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-vbi.c (renamed from drivers/media/video/ivtv/ivtv-vbi.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-vbi.h (renamed from drivers/media/video/ivtv/ivtv-vbi.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-version.h (renamed from drivers/media/video/ivtv/ivtv-version.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-yuv.c (renamed from drivers/media/video/ivtv/ivtv-yuv.c)0
-rw-r--r--drivers/media/pci/ivtv/ivtv-yuv.h (renamed from drivers/media/video/ivtv/ivtv-yuv.h)0
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c (renamed from drivers/media/video/ivtv/ivtvfb.c)0
-rw-r--r--drivers/media/pci/mantis/Kconfig38
-rw-r--r--drivers/media/pci/mantis/Makefile28
-rw-r--r--drivers/media/pci/mantis/hopper_cards.c (renamed from drivers/media/dvb/mantis/hopper_cards.c)0
-rw-r--r--drivers/media/pci/mantis/hopper_vp3028.c (renamed from drivers/media/dvb/mantis/hopper_vp3028.c)0
-rw-r--r--drivers/media/pci/mantis/hopper_vp3028.h (renamed from drivers/media/dvb/mantis/hopper_vp3028.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_ca.c (renamed from drivers/media/dvb/mantis/mantis_ca.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_ca.h (renamed from drivers/media/dvb/mantis/mantis_ca.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_cards.c307
-rw-r--r--drivers/media/pci/mantis/mantis_common.h (renamed from drivers/media/dvb/mantis/mantis_common.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_core.c235
-rw-r--r--drivers/media/pci/mantis/mantis_core.h (renamed from drivers/media/dvb/mantis/mantis_core.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_dma.c (renamed from drivers/media/dvb/mantis/mantis_dma.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_dma.h (renamed from drivers/media/dvb/mantis/mantis_dma.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_dvb.c301
-rw-r--r--drivers/media/pci/mantis/mantis_dvb.h (renamed from drivers/media/dvb/mantis/mantis_dvb.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_evm.c (renamed from drivers/media/dvb/mantis/mantis_evm.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_hif.c (renamed from drivers/media/dvb/mantis/mantis_hif.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_hif.h (renamed from drivers/media/dvb/mantis/mantis_hif.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_i2c.c (renamed from drivers/media/dvb/mantis/mantis_i2c.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_i2c.h (renamed from drivers/media/dvb/mantis/mantis_i2c.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_input.c (renamed from drivers/media/dvb/mantis/mantis_input.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_ioc.c (renamed from drivers/media/dvb/mantis/mantis_ioc.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_ioc.h (renamed from drivers/media/dvb/mantis/mantis_ioc.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_link.h (renamed from drivers/media/dvb/mantis/mantis_link.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_pci.c (renamed from drivers/media/dvb/mantis/mantis_pci.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_pci.h (renamed from drivers/media/dvb/mantis/mantis_pci.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_pcmcia.c (renamed from drivers/media/dvb/mantis/mantis_pcmcia.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_reg.h (renamed from drivers/media/dvb/mantis/mantis_reg.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_uart.c (renamed from drivers/media/dvb/mantis/mantis_uart.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_uart.h (renamed from drivers/media/dvb/mantis/mantis_uart.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1033.c (renamed from drivers/media/dvb/mantis/mantis_vp1033.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1033.h (renamed from drivers/media/dvb/mantis/mantis_vp1033.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.c (renamed from drivers/media/dvb/mantis/mantis_vp1034.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.h (renamed from drivers/media/dvb/mantis/mantis_vp1034.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1041.c (renamed from drivers/media/dvb/mantis/mantis_vp1041.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp1041.h (renamed from drivers/media/dvb/mantis/mantis_vp1041.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp2033.c (renamed from drivers/media/dvb/mantis/mantis_vp2033.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp2033.h (renamed from drivers/media/dvb/mantis/mantis_vp2033.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp2040.c (renamed from drivers/media/dvb/mantis/mantis_vp2040.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp2040.h (renamed from drivers/media/dvb/mantis/mantis_vp2040.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp3028.c (renamed from drivers/media/dvb/mantis/mantis_vp3028.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp3028.h (renamed from drivers/media/dvb/mantis/mantis_vp3028.h)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp3030.c (renamed from drivers/media/dvb/mantis/mantis_vp3030.c)0
-rw-r--r--drivers/media/pci/mantis/mantis_vp3030.h (renamed from drivers/media/dvb/mantis/mantis_vp3030.h)0
-rw-r--r--drivers/media/pci/meye/Kconfig13
-rw-r--r--drivers/media/pci/meye/Makefile1
-rw-r--r--drivers/media/pci/meye/meye.c (renamed from drivers/media/video/meye.c)0
-rw-r--r--drivers/media/pci/meye/meye.h (renamed from drivers/media/video/meye.h)0
-rw-r--r--drivers/media/pci/ngene/Kconfig13
-rw-r--r--drivers/media/pci/ngene/Makefile14
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c823
-rw-r--r--drivers/media/pci/ngene/ngene-core.c1707
-rw-r--r--drivers/media/pci/ngene/ngene-dvb.c (renamed from drivers/media/dvb/ngene/ngene-dvb.c)0
-rw-r--r--drivers/media/pci/ngene/ngene-i2c.c (renamed from drivers/media/dvb/ngene/ngene-i2c.c)0
-rw-r--r--drivers/media/pci/ngene/ngene.h (renamed from drivers/media/dvb/ngene/ngene.h)0
-rw-r--r--drivers/media/pci/pluto2/Kconfig (renamed from drivers/media/dvb/pluto2/Kconfig)0
-rw-r--r--drivers/media/pci/pluto2/Makefile3
-rw-r--r--drivers/media/pci/pluto2/pluto2.c (renamed from drivers/media/dvb/pluto2/pluto2.c)0
-rw-r--r--drivers/media/pci/pt1/Kconfig (renamed from drivers/media/dvb/pt1/Kconfig)0
-rw-r--r--drivers/media/pci/pt1/Makefile5
-rw-r--r--drivers/media/pci/pt1/pt1.c (renamed from drivers/media/dvb/pt1/pt1.c)0
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007s.c (renamed from drivers/media/dvb/pt1/va1j5jf8007s.c)0
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007s.h (renamed from drivers/media/dvb/pt1/va1j5jf8007s.h)0
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007t.c (renamed from drivers/media/dvb/pt1/va1j5jf8007t.c)0
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007t.h (renamed from drivers/media/dvb/pt1/va1j5jf8007t.h)0
-rw-r--r--drivers/media/pci/saa7134/Kconfig64
-rw-r--r--drivers/media/pci/saa7134/Makefile16
-rw-r--r--drivers/media/pci/saa7134/saa6752hs.c (renamed from drivers/media/video/saa7134/saa6752hs.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c (renamed from drivers/media/video/saa7134/saa7134-alsa.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c (renamed from drivers/media/video/saa7134/saa7134-cards.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c (renamed from drivers/media/video/saa7134/saa7134-core.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c1936
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c (renamed from drivers/media/video/saa7134/saa7134-empress.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c (renamed from drivers/media/video/saa7134/saa7134-i2c.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c1041
-rw-r--r--drivers/media/pci/saa7134/saa7134-reg.h (renamed from drivers/media/video/saa7134/saa7134-reg.h)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c (renamed from drivers/media/video/saa7134/saa7134-ts.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c (renamed from drivers/media/video/saa7134/saa7134-tvaudio.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c (renamed from drivers/media/video/saa7134/saa7134-vbi.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c (renamed from drivers/media/video/saa7134/saa7134-video.c)0
-rw-r--r--drivers/media/pci/saa7134/saa7134.h855
-rw-r--r--drivers/media/pci/saa7146/Kconfig38
-rw-r--r--drivers/media/pci/saa7146/Makefile5
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c (renamed from drivers/media/video/hexium_gemini.c)0
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c (renamed from drivers/media/video/hexium_orion.c)0
-rw-r--r--drivers/media/pci/saa7146/mxb.c (renamed from drivers/media/video/mxb.c)0
-rw-r--r--drivers/media/pci/saa7164/Kconfig18
-rw-r--r--drivers/media/pci/saa7164/Makefile12
-rw-r--r--drivers/media/pci/saa7164/saa7164-api.c1524
-rw-r--r--drivers/media/pci/saa7164/saa7164-buffer.c (renamed from drivers/media/video/saa7164/saa7164-buffer.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-bus.c (renamed from drivers/media/video/saa7164/saa7164-bus.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-cards.c (renamed from drivers/media/video/saa7164/saa7164-cards.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-cmd.c (renamed from drivers/media/video/saa7164/saa7164-cmd.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c1488
-rw-r--r--drivers/media/pci/saa7164/saa7164-dvb.c (renamed from drivers/media/video/saa7164/saa7164-dvb.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c (renamed from drivers/media/video/saa7164/saa7164-encoder.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-fw.c (renamed from drivers/media/video/saa7164/saa7164-fw.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-i2c.c (renamed from drivers/media/video/saa7164/saa7164-i2c.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-reg.h (renamed from drivers/media/video/saa7164/saa7164-reg.h)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-types.h (renamed from drivers/media/video/saa7164/saa7164-types.h)0
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c (renamed from drivers/media/video/saa7164/saa7164-vbi.c)0
-rw-r--r--drivers/media/pci/saa7164/saa7164.h616
-rw-r--r--drivers/media/pci/sta2x11/Kconfig12
-rw-r--r--drivers/media/pci/sta2x11/Makefile1
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c (renamed from drivers/media/video/sta2x11_vip.c)0
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.h (renamed from drivers/media/video/sta2x11_vip.h)0
-rw-r--r--drivers/media/pci/ttpci/Kconfig159
-rw-r--r--drivers/media/pci/ttpci/Makefile21
-rw-r--r--drivers/media/pci/ttpci/av7110.c (renamed from drivers/media/dvb/ttpci/av7110.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110.h (renamed from drivers/media/dvb/ttpci/av7110.h)0
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c (renamed from drivers/media/dvb/ttpci/av7110_av.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110_av.h (renamed from drivers/media/dvb/ttpci/av7110_av.h)0
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.c (renamed from drivers/media/dvb/ttpci/av7110_ca.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.h (renamed from drivers/media/dvb/ttpci/av7110_ca.h)0
-rw-r--r--drivers/media/pci/ttpci/av7110_hw.c (renamed from drivers/media/dvb/ttpci/av7110_hw.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110_hw.h (renamed from drivers/media/dvb/ttpci/av7110_hw.h)0
-rw-r--r--drivers/media/pci/ttpci/av7110_ipack.c (renamed from drivers/media/dvb/ttpci/av7110_ipack.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110_ipack.h (renamed from drivers/media/dvb/ttpci/av7110_ipack.h)0
-rw-r--r--drivers/media/pci/ttpci/av7110_ir.c (renamed from drivers/media/dvb/ttpci/av7110_ir.c)0
-rw-r--r--drivers/media/pci/ttpci/av7110_v4l.c (renamed from drivers/media/dvb/ttpci/av7110_v4l.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-av.c (renamed from drivers/media/dvb/ttpci/budget-av.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c (renamed from drivers/media/dvb/ttpci/budget-ci.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-core.c (renamed from drivers/media/dvb/ttpci/budget-core.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-patch.c (renamed from drivers/media/dvb/ttpci/budget-patch.c)0
-rw-r--r--drivers/media/pci/ttpci/budget.c871
-rw-r--r--drivers/media/pci/ttpci/budget.h (renamed from drivers/media/dvb/ttpci/budget.h)0
-rw-r--r--drivers/media/pci/ttpci/ttpci-eeprom.c (renamed from drivers/media/dvb/ttpci/ttpci-eeprom.c)0
-rw-r--r--drivers/media/pci/ttpci/ttpci-eeprom.h (renamed from drivers/media/dvb/ttpci/ttpci-eeprom.h)0
-rw-r--r--drivers/media/pci/zoran/Kconfig74
-rw-r--r--drivers/media/pci/zoran/Makefile (renamed from drivers/media/video/zoran/Makefile)0
-rw-r--r--drivers/media/pci/zoran/videocodec.c (renamed from drivers/media/video/zoran/videocodec.c)0
-rw-r--r--drivers/media/pci/zoran/videocodec.h (renamed from drivers/media/video/zoran/videocodec.h)0
-rw-r--r--drivers/media/pci/zoran/zoran.h (renamed from drivers/media/video/zoran/zoran.h)0
-rw-r--r--drivers/media/pci/zoran/zoran_card.c (renamed from drivers/media/video/zoran/zoran_card.c)0
-rw-r--r--drivers/media/pci/zoran/zoran_card.h (renamed from drivers/media/video/zoran/zoran_card.h)0
-rw-r--r--drivers/media/pci/zoran/zoran_device.c (renamed from drivers/media/video/zoran/zoran_device.c)0
-rw-r--r--drivers/media/pci/zoran/zoran_device.h (renamed from drivers/media/video/zoran/zoran_device.h)0
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c (renamed from drivers/media/video/zoran/zoran_driver.c)0
-rw-r--r--drivers/media/pci/zoran/zoran_procfs.c (renamed from drivers/media/video/zoran/zoran_procfs.c)0
-rw-r--r--drivers/media/pci/zoran/zoran_procfs.h (renamed from drivers/media/video/zoran/zoran_procfs.h)0
-rw-r--r--drivers/media/pci/zoran/zr36016.c (renamed from drivers/media/video/zoran/zr36016.c)0
-rw-r--r--drivers/media/pci/zoran/zr36016.h (renamed from drivers/media/video/zoran/zr36016.h)0
-rw-r--r--drivers/media/pci/zoran/zr36050.c (renamed from drivers/media/video/zoran/zr36050.c)0
-rw-r--r--drivers/media/pci/zoran/zr36050.h (renamed from drivers/media/video/zoran/zr36050.h)0
-rw-r--r--drivers/media/pci/zoran/zr36057.h (renamed from drivers/media/video/zoran/zr36057.h)0
-rw-r--r--drivers/media/pci/zoran/zr36060.c (renamed from drivers/media/video/zoran/zr36060.c)0
-rw-r--r--drivers/media/pci/zoran/zr36060.h (renamed from drivers/media/video/zoran/zr36060.h)0
-rw-r--r--drivers/media/platform/Kconfig214
-rw-r--r--drivers/media/platform/Makefile49
-rw-r--r--drivers/media/platform/arv.c (renamed from drivers/media/video/arv.c)0
-rw-r--r--drivers/media/platform/blackfin/Kconfig (renamed from drivers/media/video/blackfin/Kconfig)0
-rw-r--r--drivers/media/platform/blackfin/Makefile (renamed from drivers/media/video/blackfin/Makefile)0
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c1068
-rw-r--r--drivers/media/platform/blackfin/ppi.c (renamed from drivers/media/video/blackfin/ppi.c)0
-rw-r--r--drivers/media/platform/coda.c1849
-rw-r--r--drivers/media/platform/coda.h216
-rw-r--r--drivers/media/platform/davinci/Kconfig121
-rw-r--r--drivers/media/platform/davinci/Makefile (renamed from drivers/media/video/davinci/Makefile)0
-rw-r--r--drivers/media/platform/davinci/ccdc_hw_device.h (renamed from drivers/media/video/davinci/ccdc_hw_device.h)0
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc.c1072
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc_regs.h (renamed from drivers/media/video/davinci/dm355_ccdc_regs.h)0
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc.c1081
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc_regs.h (renamed from drivers/media/video/davinci/dm644x_ccdc_regs.h)0
-rw-r--r--drivers/media/platform/davinci/isif.c1162
-rw-r--r--drivers/media/platform/davinci/isif_regs.h (renamed from drivers/media/video/davinci/isif_regs.h)0
-rw-r--r--drivers/media/platform/davinci/vpbe.c (renamed from drivers/media/video/davinci/vpbe.c)0
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c1838
-rw-r--r--drivers/media/platform/davinci/vpbe_osd.c (renamed from drivers/media/video/davinci/vpbe_osd.c)0
-rw-r--r--drivers/media/platform/davinci/vpbe_osd_regs.h (renamed from drivers/media/video/davinci/vpbe_osd_regs.h)0
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c (renamed from drivers/media/video/davinci/vpbe_venc.c)0
-rw-r--r--drivers/media/platform/davinci/vpbe_venc_regs.h (renamed from drivers/media/video/davinci/vpbe_venc_regs.h)0
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c2079
-rw-r--r--drivers/media/platform/davinci/vpif.c514
-rw-r--r--drivers/media/platform/davinci/vpif.h (renamed from drivers/media/video/davinci/vpif.h)0
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c2456
-rw-r--r--drivers/media/platform/davinci/vpif_capture.h (renamed from drivers/media/video/davinci/vpif_capture.h)0
-rw-r--r--drivers/media/platform/davinci/vpif_display.c2010
-rw-r--r--drivers/media/platform/davinci/vpif_display.h (renamed from drivers/media/video/davinci/vpif_display.h)0
-rw-r--r--drivers/media/platform/davinci/vpss.c482
-rw-r--r--drivers/media/platform/fsl-viu.c1690
-rw-r--r--drivers/media/platform/indycam.c (renamed from drivers/media/video/indycam.c)0
-rw-r--r--drivers/media/platform/indycam.h (renamed from drivers/media/video/indycam.h)0
-rw-r--r--drivers/media/platform/m2m-deinterlace.c1120
-rw-r--r--drivers/media/platform/marvell-ccic/Kconfig (renamed from drivers/media/video/marvell-ccic/Kconfig)0
-rw-r--r--drivers/media/platform/marvell-ccic/Makefile (renamed from drivers/media/video/marvell-ccic/Makefile)0
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c (renamed from drivers/media/video/marvell-ccic/cafe-driver.c)0
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c (renamed from drivers/media/video/marvell-ccic/mcam-core.c)0
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h (renamed from drivers/media/video/marvell-ccic/mcam-core.h)0
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c (renamed from drivers/media/video/marvell-ccic/mmp-driver.c)0
-rw-r--r--drivers/media/platform/mem2mem_testdev.c1130
-rw-r--r--drivers/media/platform/mx2_emmaprp.c1030
-rw-r--r--drivers/media/platform/omap/Kconfig (renamed from drivers/media/video/omap/Kconfig)0
-rw-r--r--drivers/media/platform/omap/Makefile8
-rw-r--r--drivers/media/platform/omap/omap_vout.c (renamed from drivers/media/video/omap/omap_vout.c)0
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c (renamed from drivers/media/video/omap/omap_vout_vrfb.c)0
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.h (renamed from drivers/media/video/omap/omap_vout_vrfb.h)0
-rw-r--r--drivers/media/platform/omap/omap_voutdef.h (renamed from drivers/media/video/omap/omap_voutdef.h)0
-rw-r--r--drivers/media/platform/omap/omap_voutlib.c (renamed from drivers/media/video/omap/omap_voutlib.c)0
-rw-r--r--drivers/media/platform/omap/omap_voutlib.h (renamed from drivers/media/video/omap/omap_voutlib.h)0
-rw-r--r--drivers/media/platform/omap24xxcam-dma.c601
-rw-r--r--drivers/media/platform/omap24xxcam.c1881
-rw-r--r--drivers/media/platform/omap24xxcam.h593
-rw-r--r--drivers/media/platform/omap3isp/Makefile (renamed from drivers/media/video/omap3isp/Makefile)0
-rw-r--r--drivers/media/platform/omap3isp/cfa_coef_table.h61
-rw-r--r--drivers/media/platform/omap3isp/gamma_table.h (renamed from drivers/media/video/omap3isp/gamma_table.h)0
-rw-r--r--drivers/media/platform/omap3isp/isp.c2241
-rw-r--r--drivers/media/platform/omap3isp/isp.h352
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c2583
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.h172
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c (renamed from drivers/media/video/omap3isp/ispccp2.c)0
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.h (renamed from drivers/media/video/omap3isp/ispccp2.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c1328
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.h (renamed from drivers/media/video/omap3isp/ispcsi2.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c (renamed from drivers/media/video/omap3isp/ispcsiphy.c)0
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.h (renamed from drivers/media/video/omap3isp/ispcsiphy.h)0
-rw-r--r--drivers/media/platform/omap3isp/isph3a.h (renamed from drivers/media/video/omap3isp/isph3a.h)0
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c368
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c423
-rw-r--r--drivers/media/platform/omap3isp/isphist.c518
-rw-r--r--drivers/media/platform/omap3isp/isphist.h (renamed from drivers/media/video/omap3isp/isphist.h)0
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c2348
-rw-r--r--drivers/media/platform/omap3isp/isppreview.h174
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c1158
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h (renamed from drivers/media/video/omap3isp/ispqueue.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispreg.h (renamed from drivers/media/video/omap3isp/ispreg.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c1778
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.h (renamed from drivers/media/video/omap3isp/ispresizer.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c (renamed from drivers/media/video/omap3isp/ispstat.c)0
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h (renamed from drivers/media/video/omap3isp/ispstat.h)0
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c1403
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h216
-rw-r--r--drivers/media/platform/omap3isp/luma_enhance_table.h (renamed from drivers/media/video/omap3isp/luma_enhance_table.h)0
-rw-r--r--drivers/media/platform/omap3isp/noise_filter_table.h (renamed from drivers/media/video/omap3isp/noise_filter_table.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/Kconfig (renamed from drivers/media/video/s5p-fimc/Kconfig)0
-rw-r--r--drivers/media/platform/s5p-fimc/Makefile (renamed from drivers/media/video/s5p-fimc/Makefile)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-capture.c (renamed from drivers/media/video/s5p-fimc/fimc-capture.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-core.c (renamed from drivers/media/video/s5p-fimc/fimc-core.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-core.h (renamed from drivers/media/video/s5p-fimc/fimc-core.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite-reg.c (renamed from drivers/media/video/s5p-fimc/fimc-lite-reg.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite-reg.h (renamed from drivers/media/video/s5p-fimc/fimc-lite-reg.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.c (renamed from drivers/media/video/s5p-fimc/fimc-lite.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.h (renamed from drivers/media/video/s5p-fimc/fimc-lite.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-m2m.c (renamed from drivers/media/video/s5p-fimc/fimc-m2m.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.c (renamed from drivers/media/video/s5p-fimc/fimc-mdevice.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.h (renamed from drivers/media/video/s5p-fimc/fimc-mdevice.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-reg.c (renamed from drivers/media/video/s5p-fimc/fimc-reg.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-reg.h (renamed from drivers/media/video/s5p-fimc/fimc-reg.h)0
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.c (renamed from drivers/media/video/s5p-fimc/mipi-csis.c)0
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.h (renamed from drivers/media/video/s5p-fimc/mipi-csis.h)0
-rw-r--r--drivers/media/platform/s5p-g2d/Makefile (renamed from drivers/media/video/s5p-g2d/Makefile)0
-rw-r--r--drivers/media/platform/s5p-g2d/g2d-hw.c (renamed from drivers/media/video/s5p-g2d/g2d-hw.c)0
-rw-r--r--drivers/media/platform/s5p-g2d/g2d-regs.h (renamed from drivers/media/video/s5p-g2d/g2d-regs.h)0
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c847
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.h (renamed from drivers/media/video/s5p-g2d/g2d.h)0
-rw-r--r--drivers/media/platform/s5p-jpeg/Makefile (renamed from drivers/media/video/s5p-jpeg/Makefile)0
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c1529
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h150
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw.h357
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-regs.h170
-rw-r--r--drivers/media/platform/s5p-mfc/Makefile (renamed from drivers/media/video/s5p-mfc/Makefile)0
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc.h (renamed from drivers/media/video/s5p-mfc/regs-mfc.h)0
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c1230
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c120
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h30
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h (renamed from drivers/media/video/s5p-mfc/s5p_mfc_common.h)0
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c343
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h29
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_debug.h48
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c1044
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.h23
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c1834
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.h23
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_intr.c92
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_intr.h26
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.c1397
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h93
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c137
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.h24
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_shm.c47
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_shm.h90
-rw-r--r--drivers/media/platform/s5p-tv/Kconfig86
-rw-r--r--drivers/media/platform/s5p-tv/Makefile19
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c1009
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c (renamed from drivers/media/video/s5p-tv/hdmiphy_drv.c)0
-rw-r--r--drivers/media/platform/s5p-tv/mixer.h (renamed from drivers/media/video/s5p-tv/mixer.h)0
-rw-r--r--drivers/media/platform/s5p-tv/mixer_drv.c487
-rw-r--r--drivers/media/platform/s5p-tv/mixer_grp_layer.c (renamed from drivers/media/video/s5p-tv/mixer_grp_layer.c)0
-rw-r--r--drivers/media/platform/s5p-tv/mixer_reg.c (renamed from drivers/media/video/s5p-tv/mixer_reg.c)0
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c1127
-rw-r--r--drivers/media/platform/s5p-tv/mixer_vp_layer.c (renamed from drivers/media/video/s5p-tv/mixer_vp_layer.c)0
-rw-r--r--drivers/media/platform/s5p-tv/regs-hdmi.h (renamed from drivers/media/video/s5p-tv/regs-hdmi.h)0
-rw-r--r--drivers/media/platform/s5p-tv/regs-mixer.h (renamed from drivers/media/video/s5p-tv/regs-mixer.h)0
-rw-r--r--drivers/media/platform/s5p-tv/regs-sdo.h63
-rw-r--r--drivers/media/platform/s5p-tv/regs-vp.h (renamed from drivers/media/video/s5p-tv/regs-vp.h)0
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c448
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c413
-rw-r--r--drivers/media/platform/sh_vou.c1510
-rw-r--r--drivers/media/platform/soc_camera/Kconfig87
-rw-r--r--drivers/media/platform/soc_camera/Makefile14
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c (renamed from drivers/media/video/atmel-isi.c)0
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c (renamed from drivers/media/video/mx1_camera.c)0
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c1924
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c1290
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c1723
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c (renamed from drivers/media/video/pxa_camera.c)0
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c (renamed from drivers/media/video/sh_mobile_ceu_camera.c)0
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c (renamed from drivers/media/video/sh_mobile_csi2.c)0
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c1605
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c206
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c (renamed from drivers/media/video/soc_mediabus.c)0
-rw-r--r--drivers/media/platform/timblogiw.c (renamed from drivers/media/video/timblogiw.c)0
-rw-r--r--drivers/media/platform/via-camera.c (renamed from drivers/media/video/via-camera.c)0
-rw-r--r--drivers/media/platform/via-camera.h (renamed from drivers/media/video/via-camera.h)0
-rw-r--r--drivers/media/platform/vino.c (renamed from drivers/media/video/vino.c)0
-rw-r--r--drivers/media/platform/vino.h (renamed from drivers/media/video/vino.h)0
-rw-r--r--drivers/media/platform/vivi.c1409
-rw-r--r--drivers/media/radio/radio-shark2.c13
-rw-r--r--drivers/media/radio/radio-si4713.c7
-rw-r--r--drivers/media/radio/radio-timb.c8
-rw-r--r--drivers/media/radio/radio-wl1273.c23
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c38
-rw-r--r--drivers/media/rc/Kconfig31
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/ati_remote.c11
-rw-r--r--drivers/media/rc/fintek-cir.c11
-rw-r--r--drivers/media/rc/iguanair.c220
-rw-r--r--drivers/media/rc/ir-lirc-codec.c35
-rw-r--r--drivers/media/rc/ir-nec-decoder.c4
-rw-r--r--drivers/media/rc/ir-raw.c6
-rw-r--r--drivers/media/rc/ir-rx51.c496
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c2
-rw-r--r--drivers/media/rc/mceusb.c28
-rw-r--r--drivers/media/rc/rc-loopback.c12
-rw-r--r--drivers/media/rc/ttusbir.c407
-rw-r--r--drivers/media/tuners/Kconfig231
-rw-r--r--drivers/media/tuners/Makefile37
-rw-r--r--drivers/media/tuners/fc0011.c (renamed from drivers/media/common/tuners/fc0011.c)0
-rw-r--r--drivers/media/tuners/fc0011.h (renamed from drivers/media/common/tuners/fc0011.h)0
-rw-r--r--drivers/media/tuners/fc0012-priv.h (renamed from drivers/media/common/tuners/fc0012-priv.h)0
-rw-r--r--drivers/media/tuners/fc0012.c (renamed from drivers/media/common/tuners/fc0012.c)0
-rw-r--r--drivers/media/tuners/fc0012.h (renamed from drivers/media/common/tuners/fc0012.h)0
-rw-r--r--drivers/media/tuners/fc0013-priv.h (renamed from drivers/media/common/tuners/fc0013-priv.h)0
-rw-r--r--drivers/media/tuners/fc0013.c (renamed from drivers/media/common/tuners/fc0013.c)0
-rw-r--r--drivers/media/tuners/fc0013.h (renamed from drivers/media/common/tuners/fc0013.h)0
-rw-r--r--drivers/media/tuners/fc001x-common.h (renamed from drivers/media/common/tuners/fc001x-common.h)0
-rw-r--r--drivers/media/tuners/max2165.c (renamed from drivers/media/common/tuners/max2165.c)0
-rw-r--r--drivers/media/tuners/max2165.h (renamed from drivers/media/common/tuners/max2165.h)0
-rw-r--r--drivers/media/tuners/max2165_priv.h (renamed from drivers/media/common/tuners/max2165_priv.h)0
-rw-r--r--drivers/media/tuners/mc44s803.c (renamed from drivers/media/common/tuners/mc44s803.c)0
-rw-r--r--drivers/media/tuners/mc44s803.h (renamed from drivers/media/common/tuners/mc44s803.h)0
-rw-r--r--drivers/media/tuners/mc44s803_priv.h (renamed from drivers/media/common/tuners/mc44s803_priv.h)0
-rw-r--r--drivers/media/tuners/mt2060.c (renamed from drivers/media/common/tuners/mt2060.c)0
-rw-r--r--drivers/media/tuners/mt2060.h (renamed from drivers/media/common/tuners/mt2060.h)0
-rw-r--r--drivers/media/tuners/mt2060_priv.h (renamed from drivers/media/common/tuners/mt2060_priv.h)0
-rw-r--r--drivers/media/tuners/mt2063.c (renamed from drivers/media/common/tuners/mt2063.c)0
-rw-r--r--drivers/media/tuners/mt2063.h (renamed from drivers/media/common/tuners/mt2063.h)0
-rw-r--r--drivers/media/tuners/mt20xx.c (renamed from drivers/media/common/tuners/mt20xx.c)0
-rw-r--r--drivers/media/tuners/mt20xx.h (renamed from drivers/media/common/tuners/mt20xx.h)0
-rw-r--r--drivers/media/tuners/mt2131.c (renamed from drivers/media/common/tuners/mt2131.c)0
-rw-r--r--drivers/media/tuners/mt2131.h (renamed from drivers/media/common/tuners/mt2131.h)0
-rw-r--r--drivers/media/tuners/mt2131_priv.h (renamed from drivers/media/common/tuners/mt2131_priv.h)0
-rw-r--r--drivers/media/tuners/mt2266.c (renamed from drivers/media/common/tuners/mt2266.c)0
-rw-r--r--drivers/media/tuners/mt2266.h (renamed from drivers/media/common/tuners/mt2266.h)0
-rw-r--r--drivers/media/tuners/mxl5005s.c (renamed from drivers/media/common/tuners/mxl5005s.c)0
-rw-r--r--drivers/media/tuners/mxl5005s.h (renamed from drivers/media/common/tuners/mxl5005s.h)0
-rw-r--r--drivers/media/tuners/mxl5007t.c (renamed from drivers/media/common/tuners/mxl5007t.c)0
-rw-r--r--drivers/media/tuners/mxl5007t.h (renamed from drivers/media/common/tuners/mxl5007t.h)0
-rw-r--r--drivers/media/tuners/qt1010.c480
-rw-r--r--drivers/media/tuners/qt1010.h (renamed from drivers/media/common/tuners/qt1010.h)0
-rw-r--r--drivers/media/tuners/qt1010_priv.h (renamed from drivers/media/common/tuners/qt1010_priv.h)0
-rw-r--r--drivers/media/tuners/tda18212.c319
-rw-r--r--drivers/media/tuners/tda18212.h (renamed from drivers/media/common/tuners/tda18212.h)0
-rw-r--r--drivers/media/tuners/tda18218.c342
-rw-r--r--drivers/media/tuners/tda18218.h (renamed from drivers/media/common/tuners/tda18218.h)0
-rw-r--r--drivers/media/tuners/tda18218_priv.h (renamed from drivers/media/common/tuners/tda18218_priv.h)0
-rw-r--r--drivers/media/tuners/tda18271-common.c (renamed from drivers/media/common/tuners/tda18271-common.c)0
-rw-r--r--drivers/media/tuners/tda18271-fe.c (renamed from drivers/media/common/tuners/tda18271-fe.c)0
-rw-r--r--drivers/media/tuners/tda18271-maps.c (renamed from drivers/media/common/tuners/tda18271-maps.c)0
-rw-r--r--drivers/media/tuners/tda18271-priv.h (renamed from drivers/media/common/tuners/tda18271-priv.h)0
-rw-r--r--drivers/media/tuners/tda18271.h (renamed from drivers/media/common/tuners/tda18271.h)0
-rw-r--r--drivers/media/tuners/tda827x.c (renamed from drivers/media/common/tuners/tda827x.c)0
-rw-r--r--drivers/media/tuners/tda827x.h (renamed from drivers/media/common/tuners/tda827x.h)0
-rw-r--r--drivers/media/tuners/tda8290.c (renamed from drivers/media/common/tuners/tda8290.c)0
-rw-r--r--drivers/media/tuners/tda8290.h (renamed from drivers/media/common/tuners/tda8290.h)0
-rw-r--r--drivers/media/tuners/tda9887.c (renamed from drivers/media/common/tuners/tda9887.c)0
-rw-r--r--drivers/media/tuners/tda9887.h (renamed from drivers/media/common/tuners/tda9887.h)0
-rw-r--r--drivers/media/tuners/tea5761.c (renamed from drivers/media/common/tuners/tea5761.c)0
-rw-r--r--drivers/media/tuners/tea5761.h (renamed from drivers/media/common/tuners/tea5761.h)0
-rw-r--r--drivers/media/tuners/tea5767.c (renamed from drivers/media/common/tuners/tea5767.c)0
-rw-r--r--drivers/media/tuners/tea5767.h (renamed from drivers/media/common/tuners/tea5767.h)0
-rw-r--r--drivers/media/tuners/tua9001.c (renamed from drivers/media/common/tuners/tua9001.c)0
-rw-r--r--drivers/media/tuners/tua9001.h (renamed from drivers/media/common/tuners/tua9001.h)0
-rw-r--r--drivers/media/tuners/tua9001_priv.h (renamed from drivers/media/common/tuners/tua9001_priv.h)0
-rw-r--r--drivers/media/tuners/tuner-i2c.h (renamed from drivers/media/common/tuners/tuner-i2c.h)0
-rw-r--r--drivers/media/tuners/tuner-simple.c (renamed from drivers/media/common/tuners/tuner-simple.c)0
-rw-r--r--drivers/media/tuners/tuner-simple.h (renamed from drivers/media/common/tuners/tuner-simple.h)0
-rw-r--r--drivers/media/tuners/tuner-types.c (renamed from drivers/media/common/tuners/tuner-types.c)0
-rw-r--r--drivers/media/tuners/tuner-xc2028-types.h (renamed from drivers/media/common/tuners/tuner-xc2028-types.h)0
-rw-r--r--drivers/media/tuners/tuner-xc2028.c1509
-rw-r--r--drivers/media/tuners/tuner-xc2028.h (renamed from drivers/media/common/tuners/tuner-xc2028.h)0
-rw-r--r--drivers/media/tuners/xc4000.c1757
-rw-r--r--drivers/media/tuners/xc4000.h (renamed from drivers/media/common/tuners/xc4000.h)0
-rw-r--r--drivers/media/tuners/xc5000.c1366
-rw-r--r--drivers/media/tuners/xc5000.h (renamed from drivers/media/common/tuners/xc5000.h)0
-rw-r--r--drivers/media/usb/Kconfig54
-rw-r--r--drivers/media/usb/Makefile22
-rw-r--r--drivers/media/usb/au0828/Kconfig18
-rw-r--r--drivers/media/usb/au0828/Makefile9
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c339
-rw-r--r--drivers/media/usb/au0828/au0828-cards.h (renamed from drivers/media/video/au0828/au0828-cards.h)0
-rw-r--r--drivers/media/usb/au0828/au0828-core.c282
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c500
-rw-r--r--drivers/media/usb/au0828/au0828-i2c.c401
-rw-r--r--drivers/media/usb/au0828/au0828-reg.h66
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c (renamed from drivers/media/video/au0828/au0828-vbi.c)0
-rw-r--r--drivers/media/usb/au0828/au0828-video.c2034
-rw-r--r--drivers/media/usb/au0828/au0828.h304
-rw-r--r--drivers/media/usb/b2c2/Kconfig15
-rw-r--r--drivers/media/usb/b2c2/Makefile5
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c587
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.h (renamed from drivers/media/dvb/b2c2/flexcop-usb.h)0
-rw-r--r--drivers/media/usb/cpia2/Kconfig (renamed from drivers/media/video/cpia2/Kconfig)0
-rw-r--r--drivers/media/usb/cpia2/Makefile (renamed from drivers/media/video/cpia2/Makefile)0
-rw-r--r--drivers/media/usb/cpia2/cpia2.h (renamed from drivers/media/video/cpia2/cpia2.h)0
-rw-r--r--drivers/media/usb/cpia2/cpia2_core.c2417
-rw-r--r--drivers/media/usb/cpia2/cpia2_registers.h (renamed from drivers/media/video/cpia2/cpia2_registers.h)0
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c (renamed from drivers/media/video/cpia2/cpia2_usb.c)0
-rw-r--r--drivers/media/usb/cpia2/cpia2_v4l.c1267
-rw-r--r--drivers/media/usb/cx231xx/Kconfig51
-rw-r--r--drivers/media/usb/cx231xx/Makefile15
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2197
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c (renamed from drivers/media/video/cx231xx/cx231xx-audio.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c (renamed from drivers/media/video/cx231xx/cx231xx-avcore.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c (renamed from drivers/media/video/cx231xx/cx231xx-cards.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-conf-reg.h (renamed from drivers/media/video/cx231xx/cx231xx-conf-reg.h)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c (renamed from drivers/media/video/cx231xx/cx231xx-core.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dif.h (renamed from drivers/media/video/cx231xx/cx231xx-dif.h)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c (renamed from drivers/media/video/cx231xx/cx231xx-dvb.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-i2c.c (renamed from drivers/media/video/cx231xx/cx231xx-i2c.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-input.c (renamed from drivers/media/video/cx231xx/cx231xx-input.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c (renamed from drivers/media/video/cx231xx/cx231xx-pcb-cfg.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h (renamed from drivers/media/video/cx231xx/cx231xx-pcb-cfg.h)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-reg.h (renamed from drivers/media/video/cx231xx/cx231xx-reg.h)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c (renamed from drivers/media/video/cx231xx/cx231xx-vbi.c)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.h (renamed from drivers/media/video/cx231xx/cx231xx-vbi.h)0
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c2670
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h (renamed from drivers/media/video/cx231xx/cx231xx.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig146
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile49
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c1435
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.h170
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c1087
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h111
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c1327
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.h325
-rw-r--r--drivers/media/usb/dvb-usb-v2/au6610.c206
-rw-r--r--drivers/media/usb/dvb-usb-v2/au6610.h32
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c919
-rw-r--r--drivers/media/usb/dvb-usb-v2/ce6230.c288
-rw-r--r--drivers/media/usb/dvb-usb-v2/ce6230.h61
-rw-r--r--drivers/media/usb/dvb-usb-v2/cypress_firmware.c125
-rw-r--r--drivers/media/usb/dvb-usb-v2/cypress_firmware.h31
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h392
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_common.h35
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c1046
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c77
-rw-r--r--drivers/media/usb/dvb-usb-v2/ec168.c376
-rw-r--r--drivers/media/usb/dvb-usb-v2/ec168.h63
-rw-r--r--drivers/media/usb/dvb-usb-v2/gl861.c175
-rw-r--r--drivers/media/usb/dvb-usb-v2/gl861.h12
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c799
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c1369
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.h (renamed from drivers/media/dvb/dvb-usb/lmedm04.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c (renamed from drivers/media/dvb/dvb-usb/mxl111sf-demod.c)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-demod.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c (renamed from drivers/media/dvb/dvb-usb/mxl111sf-gpio.c)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-gpio.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c (renamed from drivers/media/dvb/dvb-usb/mxl111sf-i2c.c)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-i2c.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c (renamed from drivers/media/dvb/dvb-usb/mxl111sf-phy.c)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-phy.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-reg.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c527
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h (renamed from drivers/media/dvb/dvb-usb/mxl111sf-tuner.h)0
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c1431
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.h160
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c1260
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h254
-rw-r--r--drivers/media/usb/dvb-usb-v2/usb_urb.c357
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig313
-rw-r--r--drivers/media/usb/dvb-usb/Makefile83
-rw-r--r--drivers/media/usb/dvb-usb/a800.c (renamed from drivers/media/dvb/dvb-usb/a800.c)0
-rw-r--r--drivers/media/usb/dvb-usb/af9005-fe.c (renamed from drivers/media/dvb/dvb-usb/af9005-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/af9005-remote.c (renamed from drivers/media/dvb/dvb-usb/af9005-remote.c)0
-rw-r--r--drivers/media/usb/dvb-usb/af9005-script.h (renamed from drivers/media/dvb/dvb-usb/af9005-script.h)0
-rw-r--r--drivers/media/usb/dvb-usb/af9005.c (renamed from drivers/media/dvb/dvb-usb/af9005.c)0
-rw-r--r--drivers/media/usb/dvb-usb/af9005.h (renamed from drivers/media/dvb/dvb-usb/af9005.h)0
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c (renamed from drivers/media/dvb/dvb-usb/az6027.c)0
-rw-r--r--drivers/media/usb/dvb-usb/az6027.h (renamed from drivers/media/dvb/dvb-usb/az6027.h)0
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-core.c (renamed from drivers/media/dvb/dvb-usb/cinergyT2-core.c)0
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-fe.c (renamed from drivers/media/dvb/dvb-usb/cinergyT2-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2.h (renamed from drivers/media/dvb/dvb-usb/cinergyT2.h)0
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c (renamed from drivers/media/dvb/dvb-usb/cxusb.c)0
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.h (renamed from drivers/media/dvb/dvb-usb/cxusb.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h (renamed from drivers/media/dvb/dvb-usb/dib0700.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c845
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c (renamed from drivers/media/dvb/dvb-usb/dib0700_devices.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dib07x0.h (renamed from drivers/media/dvb/dvb-usb/dib07x0.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c (renamed from drivers/media/dvb/dvb-usb/dibusb-common.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mb.c (renamed from drivers/media/dvb/dvb-usb/dibusb-mb.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mc.c (renamed from drivers/media/dvb/dvb-usb/dibusb-mc.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dibusb.h (renamed from drivers/media/dvb/dvb-usb/dibusb.h)0
-rw-r--r--drivers/media/usb/dvb-usb/digitv.c (renamed from drivers/media/dvb/dvb-usb/digitv.c)0
-rw-r--r--drivers/media/usb/dvb-usb/digitv.h (renamed from drivers/media/dvb/dvb-usb/digitv.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u-fe.c (renamed from drivers/media/dvb/dvb-usb/dtt200u-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u.c (renamed from drivers/media/dvb/dvb-usb/dtt200u.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u.h (renamed from drivers/media/dvb/dvb-usb/dtt200u.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dtv5100.c (renamed from drivers/media/dvb/dvb-usb/dtv5100.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dtv5100.h (renamed from drivers/media/dvb/dvb-usb/dtv5100.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-common.h (renamed from drivers/media/dvb/dvb-usb/dvb-usb-common.h)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-dvb.c288
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-firmware.c (renamed from drivers/media/dvb/dvb-usb/dvb-usb-firmware.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-i2c.c (renamed from drivers/media/dvb/dvb-usb/dvb-usb-i2c.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c (renamed from drivers/media/dvb/dvb-usb/dvb-usb-init.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-remote.c (renamed from drivers/media/dvb/dvb-usb/dvb-usb-remote.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-urb.c (renamed from drivers/media/dvb/dvb-usb/dvb-usb-urb.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb.h483
-rw-r--r--drivers/media/usb/dvb-usb/dvb_usb_dvb.c403
-rw-r--r--drivers/media/usb/dvb-usb/dvb_usb_remote.c117
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c (renamed from drivers/media/dvb/dvb-usb/dw2102.c)0
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.h (renamed from drivers/media/dvb/dvb-usb/dw2102.h)0
-rw-r--r--drivers/media/usb/dvb-usb/friio-fe.c (renamed from drivers/media/dvb/dvb-usb/friio-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/friio.c (renamed from drivers/media/dvb/dvb-usb/friio.c)0
-rw-r--r--drivers/media/usb/dvb-usb/friio.h (renamed from drivers/media/dvb/dvb-usb/friio.h)0
-rw-r--r--drivers/media/usb/dvb-usb/gp8psk-fe.c (renamed from drivers/media/dvb/dvb-usb/gp8psk-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/gp8psk.c (renamed from drivers/media/dvb/dvb-usb/gp8psk.c)0
-rw-r--r--drivers/media/usb/dvb-usb/gp8psk.h (renamed from drivers/media/dvb/dvb-usb/gp8psk.h)0
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c (renamed from drivers/media/dvb/dvb-usb/m920x.c)0
-rw-r--r--drivers/media/usb/dvb-usb/m920x.h (renamed from drivers/media/dvb/dvb-usb/m920x.h)0
-rw-r--r--drivers/media/usb/dvb-usb/nova-t-usb2.c (renamed from drivers/media/dvb/dvb-usb/nova-t-usb2.c)0
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c (renamed from drivers/media/dvb/dvb-usb/opera1.c)0
-rw-r--r--drivers/media/usb/dvb-usb/pctv452e.c1063
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c (renamed from drivers/media/dvb/dvb-usb/technisat-usb2.c)0
-rw-r--r--drivers/media/usb/dvb-usb/ttusb2.c (renamed from drivers/media/dvb/dvb-usb/ttusb2.c)0
-rw-r--r--drivers/media/usb/dvb-usb/ttusb2.h (renamed from drivers/media/dvb/dvb-usb/ttusb2.h)0
-rw-r--r--drivers/media/usb/dvb-usb/umt-010.c (renamed from drivers/media/dvb/dvb-usb/umt-010.c)0
-rw-r--r--drivers/media/usb/dvb-usb/usb-urb.c (renamed from drivers/media/dvb/dvb-usb/usb-urb.c)0
-rw-r--r--drivers/media/usb/dvb-usb/vp702x-fe.c (renamed from drivers/media/dvb/dvb-usb/vp702x-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/vp702x.c (renamed from drivers/media/dvb/dvb-usb/vp702x.c)0
-rw-r--r--drivers/media/usb/dvb-usb/vp702x.h (renamed from drivers/media/dvb/dvb-usb/vp702x.h)0
-rw-r--r--drivers/media/usb/dvb-usb/vp7045-fe.c (renamed from drivers/media/dvb/dvb-usb/vp7045-fe.c)0
-rw-r--r--drivers/media/usb/dvb-usb/vp7045.c (renamed from drivers/media/dvb/dvb-usb/vp7045.c)0
-rw-r--r--drivers/media/usb/dvb-usb/vp7045.h (renamed from drivers/media/dvb/dvb-usb/vp7045.h)0
-rw-r--r--drivers/media/usb/em28xx/Kconfig58
-rw-r--r--drivers/media/usb/em28xx/Makefile15
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c751
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c (renamed from drivers/media/video/em28xx/em28xx-cards.c)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c1260
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c (renamed from drivers/media/video/em28xx/em28xx-dvb.c)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c (renamed from drivers/media/video/em28xx/em28xx-i2c.c)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c (renamed from drivers/media/video/em28xx/em28xx-input.c)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h (renamed from drivers/media/video/em28xx/em28xx-reg.h)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c (renamed from drivers/media/video/em28xx/em28xx-vbi.c)0
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c2624
-rw-r--r--drivers/media/usb/em28xx/em28xx.h (renamed from drivers/media/video/em28xx/em28xx.h)0
-rw-r--r--drivers/media/usb/gspca/Kconfig425
-rw-r--r--drivers/media/usb/gspca/Makefile (renamed from drivers/media/video/gspca/Makefile)0
-rw-r--r--drivers/media/usb/gspca/autogain_functions.c (renamed from drivers/media/video/gspca/autogain_functions.c)0
-rw-r--r--drivers/media/usb/gspca/autogain_functions.h (renamed from drivers/media/video/gspca/autogain_functions.h)0
-rw-r--r--drivers/media/usb/gspca/benq.c (renamed from drivers/media/video/gspca/benq.c)0
-rw-r--r--drivers/media/usb/gspca/conex.c (renamed from drivers/media/video/gspca/conex.c)0
-rw-r--r--drivers/media/usb/gspca/cpia1.c (renamed from drivers/media/video/gspca/cpia1.c)0
-rw-r--r--drivers/media/usb/gspca/etoms.c (renamed from drivers/media/video/gspca/etoms.c)0
-rw-r--r--drivers/media/usb/gspca/finepix.c (renamed from drivers/media/video/gspca/finepix.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/Kconfig (renamed from drivers/media/video/gspca/gl860/Kconfig)0
-rw-r--r--drivers/media/usb/gspca/gl860/Makefile10
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-mi1320.c (renamed from drivers/media/video/gspca/gl860/gl860-mi1320.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-mi2020.c (renamed from drivers/media/video/gspca/gl860/gl860-mi2020.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-ov2640.c (renamed from drivers/media/video/gspca/gl860/gl860-ov2640.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-ov9655.c (renamed from drivers/media/video/gspca/gl860/gl860-ov9655.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.c (renamed from drivers/media/video/gspca/gl860/gl860.c)0
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.h (renamed from drivers/media/video/gspca/gl860/gl860.h)0
-rw-r--r--drivers/media/usb/gspca/gspca.c (renamed from drivers/media/video/gspca/gspca.c)0
-rw-r--r--drivers/media/usb/gspca/gspca.h (renamed from drivers/media/video/gspca/gspca.h)0
-rw-r--r--drivers/media/usb/gspca/jeilinj.c (renamed from drivers/media/video/gspca/jeilinj.c)0
-rw-r--r--drivers/media/usb/gspca/jl2005bcd.c (renamed from drivers/media/video/gspca/jl2005bcd.c)0
-rw-r--r--drivers/media/usb/gspca/jpeg.h (renamed from drivers/media/video/gspca/jpeg.h)0
-rw-r--r--drivers/media/usb/gspca/kinect.c (renamed from drivers/media/video/gspca/kinect.c)0
-rw-r--r--drivers/media/usb/gspca/konica.c (renamed from drivers/media/video/gspca/konica.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/Kconfig (renamed from drivers/media/video/gspca/m5602/Kconfig)0
-rw-r--r--drivers/media/usb/gspca/m5602/Makefile11
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_bridge.h (renamed from drivers/media/video/gspca/m5602/m5602_bridge.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_core.c (renamed from drivers/media/video/gspca/m5602/m5602_core.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.c (renamed from drivers/media/video/gspca/m5602/m5602_mt9m111.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.h (renamed from drivers/media/video/gspca/m5602/m5602_mt9m111.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.c (renamed from drivers/media/video/gspca/m5602/m5602_ov7660.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.h (renamed from drivers/media/video/gspca/m5602/m5602_ov7660.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.c (renamed from drivers/media/video/gspca/m5602/m5602_ov9650.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.h (renamed from drivers/media/video/gspca/m5602/m5602_ov9650.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.c (renamed from drivers/media/video/gspca/m5602/m5602_po1030.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.h (renamed from drivers/media/video/gspca/m5602/m5602_po1030.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.c (renamed from drivers/media/video/gspca/m5602/m5602_s5k4aa.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.h (renamed from drivers/media/video/gspca/m5602/m5602_s5k4aa.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.c (renamed from drivers/media/video/gspca/m5602/m5602_s5k83a.c)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.h (renamed from drivers/media/video/gspca/m5602/m5602_s5k83a.h)0
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_sensor.h (renamed from drivers/media/video/gspca/m5602/m5602_sensor.h)0
-rw-r--r--drivers/media/usb/gspca/mars.c (renamed from drivers/media/video/gspca/mars.c)0
-rw-r--r--drivers/media/usb/gspca/mr97310a.c (renamed from drivers/media/video/gspca/mr97310a.c)0
-rw-r--r--drivers/media/usb/gspca/nw80x.c (renamed from drivers/media/video/gspca/nw80x.c)0
-rw-r--r--drivers/media/usb/gspca/ov519.c (renamed from drivers/media/video/gspca/ov519.c)0
-rw-r--r--drivers/media/usb/gspca/ov534.c (renamed from drivers/media/video/gspca/ov534.c)0
-rw-r--r--drivers/media/usb/gspca/ov534_9.c (renamed from drivers/media/video/gspca/ov534_9.c)0
-rw-r--r--drivers/media/usb/gspca/pac207.c (renamed from drivers/media/video/gspca/pac207.c)0
-rw-r--r--drivers/media/usb/gspca/pac7302.c (renamed from drivers/media/video/gspca/pac7302.c)0
-rw-r--r--drivers/media/usb/gspca/pac7311.c (renamed from drivers/media/video/gspca/pac7311.c)0
-rw-r--r--drivers/media/usb/gspca/pac_common.h (renamed from drivers/media/video/gspca/pac_common.h)0
-rw-r--r--drivers/media/usb/gspca/se401.c (renamed from drivers/media/video/gspca/se401.c)0
-rw-r--r--drivers/media/usb/gspca/se401.h (renamed from drivers/media/video/gspca/se401.h)0
-rw-r--r--drivers/media/usb/gspca/sn9c2028.c (renamed from drivers/media/video/gspca/sn9c2028.c)0
-rw-r--r--drivers/media/usb/gspca/sn9c2028.h (renamed from drivers/media/video/gspca/sn9c2028.h)0
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c (renamed from drivers/media/video/gspca/sn9c20x.c)0
-rw-r--r--drivers/media/usb/gspca/sonixb.c (renamed from drivers/media/video/gspca/sonixb.c)0
-rw-r--r--drivers/media/usb/gspca/sonixj.c (renamed from drivers/media/video/gspca/sonixj.c)0
-rw-r--r--drivers/media/usb/gspca/spca1528.c (renamed from drivers/media/video/gspca/spca1528.c)0
-rw-r--r--drivers/media/usb/gspca/spca500.c (renamed from drivers/media/video/gspca/spca500.c)0
-rw-r--r--drivers/media/usb/gspca/spca501.c (renamed from drivers/media/video/gspca/spca501.c)0
-rw-r--r--drivers/media/usb/gspca/spca505.c (renamed from drivers/media/video/gspca/spca505.c)0
-rw-r--r--drivers/media/usb/gspca/spca506.c (renamed from drivers/media/video/gspca/spca506.c)0
-rw-r--r--drivers/media/usb/gspca/spca508.c (renamed from drivers/media/video/gspca/spca508.c)0
-rw-r--r--drivers/media/usb/gspca/spca561.c (renamed from drivers/media/video/gspca/spca561.c)0
-rw-r--r--drivers/media/usb/gspca/sq905.c (renamed from drivers/media/video/gspca/sq905.c)0
-rw-r--r--drivers/media/usb/gspca/sq905c.c344
-rw-r--r--drivers/media/usb/gspca/sq930x.c1164
-rw-r--r--drivers/media/usb/gspca/stk014.c (renamed from drivers/media/video/gspca/stk014.c)0
-rw-r--r--drivers/media/usb/gspca/stv0680.c (renamed from drivers/media/video/gspca/stv0680.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/Kconfig (renamed from drivers/media/video/gspca/stv06xx/Kconfig)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/Makefile10
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c (renamed from drivers/media/video/gspca/stv06xx/stv06xx.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx.h)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c (renamed from drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c (renamed from drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_sensor.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx_sensor.h)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c (renamed from drivers/media/video/gspca/stv06xx/stv06xx_st6422.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_st6422.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx_st6422.h)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c (renamed from drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c)0
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.h (renamed from drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h)0
-rw-r--r--drivers/media/usb/gspca/sunplus.c (renamed from drivers/media/video/gspca/sunplus.c)0
-rw-r--r--drivers/media/usb/gspca/t613.c (renamed from drivers/media/video/gspca/t613.c)0
-rw-r--r--drivers/media/usb/gspca/topro.c (renamed from drivers/media/video/gspca/topro.c)0
-rw-r--r--drivers/media/usb/gspca/tv8532.c (renamed from drivers/media/video/gspca/tv8532.c)0
-rw-r--r--drivers/media/usb/gspca/vc032x.c3850
-rw-r--r--drivers/media/usb/gspca/vicam.c (renamed from drivers/media/video/gspca/vicam.c)0
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c (renamed from drivers/media/video/gspca/w996Xcf.c)0
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c (renamed from drivers/media/video/gspca/xirlink_cit.c)0
-rw-r--r--drivers/media/usb/gspca/zc3xx-reg.h (renamed from drivers/media/video/gspca/zc3xx-reg.h)0
-rw-r--r--drivers/media/usb/gspca/zc3xx.c (renamed from drivers/media/video/gspca/zc3xx.c)0
-rw-r--r--drivers/media/usb/hdpvr/Kconfig (renamed from drivers/media/video/hdpvr/Kconfig)0
-rw-r--r--drivers/media/usb/hdpvr/Makefile7
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-control.c (renamed from drivers/media/video/hdpvr/hdpvr-control.c)0
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c (renamed from drivers/media/video/hdpvr/hdpvr-core.c)0
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-i2c.c (renamed from drivers/media/video/hdpvr/hdpvr-i2c.c)0
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c (renamed from drivers/media/video/hdpvr/hdpvr-video.c)0
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h (renamed from drivers/media/video/hdpvr/hdpvr.h)0
-rw-r--r--drivers/media/usb/pvrusb2/Kconfig65
-rw-r--r--drivers/media/usb/pvrusb2/Makefile22
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.c (renamed from drivers/media/video/pvrusb2/pvrusb2-audio.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.h (renamed from drivers/media/video/pvrusb2/pvrusb2-audio.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c (renamed from drivers/media/video/pvrusb2/pvrusb2-context.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.h (renamed from drivers/media/video/pvrusb2/pvrusb2-context.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c (renamed from drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h (renamed from drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.c (renamed from drivers/media/video/pvrusb2/pvrusb2-ctrl.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.h (renamed from drivers/media/video/pvrusb2/pvrusb2-ctrl.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c (renamed from drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h (renamed from drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debug.h (renamed from drivers/media/video/pvrusb2/pvrusb2-debug.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.c (renamed from drivers/media/video/pvrusb2/pvrusb2-debugifc.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.h (renamed from drivers/media/video/pvrusb2/pvrusb2-debugifc.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.c576
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.h (renamed from drivers/media/video/pvrusb2/pvrusb2-devattr.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-dvb.c (renamed from drivers/media/video/pvrusb2/pvrusb2-dvb.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-dvb.h (renamed from drivers/media/video/pvrusb2/pvrusb2-dvb.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.c (renamed from drivers/media/video/pvrusb2/pvrusb2-eeprom.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.h (renamed from drivers/media/video/pvrusb2/pvrusb2-eeprom.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.c (renamed from drivers/media/video/pvrusb2/pvrusb2-encoder.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.h (renamed from drivers/media/video/pvrusb2/pvrusb2-encoder.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h (renamed from drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h (renamed from drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c (renamed from drivers/media/video/pvrusb2/pvrusb2-hdw.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h (renamed from drivers/media/video/pvrusb2/pvrusb2-hdw.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c (renamed from drivers/media/video/pvrusb2/pvrusb2-i2c-core.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h (renamed from drivers/media/video/pvrusb2/pvrusb2-i2c-core.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c (renamed from drivers/media/video/pvrusb2/pvrusb2-io.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.h (renamed from drivers/media/video/pvrusb2/pvrusb2-io.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.c (renamed from drivers/media/video/pvrusb2/pvrusb2-ioread.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.h (renamed from drivers/media/video/pvrusb2/pvrusb2-ioread.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-main.c (renamed from drivers/media/video/pvrusb2/pvrusb2-main.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.c (renamed from drivers/media/video/pvrusb2/pvrusb2-std.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.h (renamed from drivers/media/video/pvrusb2/pvrusb2-std.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.c (renamed from drivers/media/video/pvrusb2/pvrusb2-sysfs.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.h (renamed from drivers/media/video/pvrusb2/pvrusb2-sysfs.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-util.h (renamed from drivers/media/video/pvrusb2/pvrusb2-util.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c (renamed from drivers/media/video/pvrusb2/pvrusb2-v4l2.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.h (renamed from drivers/media/video/pvrusb2/pvrusb2-v4l2.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c (renamed from drivers/media/video/pvrusb2/pvrusb2-video-v4l.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h (renamed from drivers/media/video/pvrusb2/pvrusb2-video-v4l.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.c (renamed from drivers/media/video/pvrusb2/pvrusb2-wm8775.c)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.h (renamed from drivers/media/video/pvrusb2/pvrusb2-wm8775.h)0
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2.h (renamed from drivers/media/video/pvrusb2/pvrusb2.h)0
-rw-r--r--drivers/media/usb/pwc/Kconfig (renamed from drivers/media/video/pwc/Kconfig)0
-rw-r--r--drivers/media/usb/pwc/Makefile4
-rw-r--r--drivers/media/usb/pwc/philips.txt (renamed from drivers/media/video/pwc/philips.txt)0
-rw-r--r--drivers/media/usb/pwc/pwc-ctrl.c (renamed from drivers/media/video/pwc/pwc-ctrl.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-dec1.c (renamed from drivers/media/video/pwc/pwc-dec1.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-dec1.h (renamed from drivers/media/video/pwc/pwc-dec1.h)0
-rw-r--r--drivers/media/usb/pwc/pwc-dec23.c (renamed from drivers/media/video/pwc/pwc-dec23.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-dec23.h (renamed from drivers/media/video/pwc/pwc-dec23.h)0
-rw-r--r--drivers/media/usb/pwc/pwc-if.c (renamed from drivers/media/video/pwc/pwc-if.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-kiara.c (renamed from drivers/media/video/pwc/pwc-kiara.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-kiara.h (renamed from drivers/media/video/pwc/pwc-kiara.h)0
-rw-r--r--drivers/media/usb/pwc/pwc-misc.c (renamed from drivers/media/video/pwc/pwc-misc.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-nala.h (renamed from drivers/media/video/pwc/pwc-nala.h)0
-rw-r--r--drivers/media/usb/pwc/pwc-timon.c (renamed from drivers/media/video/pwc/pwc-timon.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-timon.h (renamed from drivers/media/video/pwc/pwc-timon.h)0
-rw-r--r--drivers/media/usb/pwc/pwc-uncompress.c (renamed from drivers/media/video/pwc/pwc-uncompress.c)0
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c (renamed from drivers/media/video/pwc/pwc-v4l.c)0
-rw-r--r--drivers/media/usb/pwc/pwc.h (renamed from drivers/media/video/pwc/pwc.h)0
-rw-r--r--drivers/media/usb/s2255/Kconfig9
-rw-r--r--drivers/media/usb/s2255/Makefile2
-rw-r--r--drivers/media/usb/s2255/s2255drv.c2690
-rw-r--r--drivers/media/usb/siano/Kconfig10
-rw-r--r--drivers/media/usb/siano/Makefile6
-rw-r--r--drivers/media/usb/siano/smsusb.c (renamed from drivers/media/dvb/siano/smsusb.c)0
-rw-r--r--drivers/media/usb/sn9c102/Kconfig (renamed from drivers/media/video/sn9c102/Kconfig)0
-rw-r--r--drivers/media/usb/sn9c102/Makefile (renamed from drivers/media/video/sn9c102/Makefile)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102.h (renamed from drivers/media/video/sn9c102/sn9c102.h)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_config.h (renamed from drivers/media/video/sn9c102/sn9c102_config.h)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_core.c (renamed from drivers/media/video/sn9c102/sn9c102_core.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_devtable.h (renamed from drivers/media/video/sn9c102/sn9c102_devtable.h)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_hv7131d.c (renamed from drivers/media/video/sn9c102/sn9c102_hv7131d.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_hv7131r.c (renamed from drivers/media/video/sn9c102/sn9c102_hv7131r.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mi0343.c (renamed from drivers/media/video/sn9c102/sn9c102_mi0343.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mi0360.c (renamed from drivers/media/video/sn9c102/sn9c102_mi0360.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mt9v111.c (renamed from drivers/media/video/sn9c102/sn9c102_mt9v111.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_ov7630.c (renamed from drivers/media/video/sn9c102/sn9c102_ov7630.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_ov7660.c (renamed from drivers/media/video/sn9c102/sn9c102_ov7660.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_pas106b.c (renamed from drivers/media/video/sn9c102/sn9c102_pas106b.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_pas202bcb.c (renamed from drivers/media/video/sn9c102/sn9c102_pas202bcb.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_sensor.h (renamed from drivers/media/video/sn9c102/sn9c102_sensor.h)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c (renamed from drivers/media/video/sn9c102/sn9c102_tas5110c1b.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5110d.c (renamed from drivers/media/video/sn9c102/sn9c102_tas5110d.c)0
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c (renamed from drivers/media/video/sn9c102/sn9c102_tas5130d1b.c)0
-rw-r--r--drivers/media/usb/stk1160/Kconfig20
-rw-r--r--drivers/media/usb/stk1160/Makefile11
-rw-r--r--drivers/media/usb/stk1160/stk1160-ac97.c152
-rw-r--r--drivers/media/usb/stk1160/stk1160-core.c432
-rw-r--r--drivers/media/usb/stk1160/stk1160-i2c.c294
-rw-r--r--drivers/media/usb/stk1160/stk1160-reg.h93
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c740
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c518
-rw-r--r--drivers/media/usb/stk1160/stk1160.h208
-rw-r--r--drivers/media/usb/stkwebcam/Kconfig13
-rw-r--r--drivers/media/usb/stkwebcam/Makefile4
-rw-r--r--drivers/media/usb/stkwebcam/stk-sensor.c (renamed from drivers/media/video/stk-sensor.c)0
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c (renamed from drivers/media/video/stk-webcam.c)0
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.h (renamed from drivers/media/video/stk-webcam.h)0
-rw-r--r--drivers/media/usb/tlg2300/Kconfig (renamed from drivers/media/video/tlg2300/Kconfig)0
-rw-r--r--drivers/media/usb/tlg2300/Makefile9
-rw-r--r--drivers/media/usb/tlg2300/pd-alsa.c (renamed from drivers/media/video/tlg2300/pd-alsa.c)0
-rw-r--r--drivers/media/usb/tlg2300/pd-common.h (renamed from drivers/media/video/tlg2300/pd-common.h)0
-rw-r--r--drivers/media/usb/tlg2300/pd-dvb.c (renamed from drivers/media/video/tlg2300/pd-dvb.c)0
-rw-r--r--drivers/media/usb/tlg2300/pd-main.c (renamed from drivers/media/video/tlg2300/pd-main.c)0
-rw-r--r--drivers/media/usb/tlg2300/pd-radio.c (renamed from drivers/media/video/tlg2300/pd-radio.c)0
-rw-r--r--drivers/media/usb/tlg2300/pd-video.c (renamed from drivers/media/video/tlg2300/pd-video.c)0
-rw-r--r--drivers/media/usb/tlg2300/vendorcmds.h (renamed from drivers/media/video/tlg2300/vendorcmds.h)0
-rw-r--r--drivers/media/usb/tm6000/Kconfig (renamed from drivers/media/video/tm6000/Kconfig)0
-rw-r--r--drivers/media/usb/tm6000/Makefile15
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c529
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c (renamed from drivers/media/video/tm6000/tm6000-cards.c)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-core.c (renamed from drivers/media/video/tm6000/tm6000-core.c)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-dvb.c (renamed from drivers/media/video/tm6000/tm6000-dvb.c)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-i2c.c (renamed from drivers/media/video/tm6000/tm6000-i2c.c)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-input.c499
-rw-r--r--drivers/media/usb/tm6000/tm6000-regs.h (renamed from drivers/media/video/tm6000/tm6000-regs.h)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-stds.c (renamed from drivers/media/video/tm6000/tm6000-stds.c)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-usb-isoc.h (renamed from drivers/media/video/tm6000/tm6000-usb-isoc.h)0
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c1852
-rw-r--r--drivers/media/usb/tm6000/tm6000.h (renamed from drivers/media/video/tm6000/tm6000.h)0
-rw-r--r--drivers/media/usb/ttusb-budget/Kconfig18
-rw-r--r--drivers/media/usb/ttusb-budget/Makefile3
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c (renamed from drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c)0
-rw-r--r--drivers/media/usb/ttusb-dec/Kconfig (renamed from drivers/media/dvb/ttusb-dec/Kconfig)0
-rw-r--r--drivers/media/usb/ttusb-dec/Makefile3
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c (renamed from drivers/media/dvb/ttusb-dec/ttusb_dec.c)0
-rw-r--r--drivers/media/usb/ttusb-dec/ttusbdecfe.c (renamed from drivers/media/dvb/ttusb-dec/ttusbdecfe.c)0
-rw-r--r--drivers/media/usb/ttusb-dec/ttusbdecfe.h (renamed from drivers/media/dvb/ttusb-dec/ttusbdecfe.h)0
-rw-r--r--drivers/media/usb/usbvision/Kconfig12
-rw-r--r--drivers/media/usb/usbvision/Makefile6
-rw-r--r--drivers/media/usb/usbvision/usbvision-cards.c (renamed from drivers/media/video/usbvision/usbvision-cards.c)0
-rw-r--r--drivers/media/usb/usbvision/usbvision-cards.h (renamed from drivers/media/video/usbvision/usbvision-cards.h)0
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c (renamed from drivers/media/video/usbvision/usbvision-core.c)0
-rw-r--r--drivers/media/usb/usbvision/usbvision-i2c.c (renamed from drivers/media/video/usbvision/usbvision-i2c.c)0
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c1720
-rw-r--r--drivers/media/usb/usbvision/usbvision.h (renamed from drivers/media/video/usbvision/usbvision.h)0
-rw-r--r--drivers/media/usb/uvc/Kconfig (renamed from drivers/media/video/uvc/Kconfig)0
-rw-r--r--drivers/media/usb/uvc/Makefile (renamed from drivers/media/video/uvc/Makefile)0
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c (renamed from drivers/media/video/uvc/uvc_ctrl.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_debugfs.c (renamed from drivers/media/video/uvc/uvc_debugfs.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c2472
-rw-r--r--drivers/media/usb/uvc/uvc_entity.c (renamed from drivers/media/video/uvc/uvc_entity.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_isight.c (renamed from drivers/media/video/uvc/uvc_isight.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c (renamed from drivers/media/video/uvc/uvc_queue.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_status.c (renamed from drivers/media/video/uvc/uvc_status.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c (renamed from drivers/media/video/uvc/uvc_v4l2.c)0
-rw-r--r--drivers/media/usb/uvc/uvc_video.c1879
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h718
-rw-r--r--drivers/media/usb/zr364xx/Kconfig14
-rw-r--r--drivers/media/usb/zr364xx/Makefile2
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c (renamed from drivers/media/video/zr364xx.c)0
-rw-r--r--drivers/media/v4l2-core/Kconfig81
-rw-r--r--drivers/media/v4l2-core/Makefile35
-rw-r--r--drivers/media/v4l2-core/tuner-core.c (renamed from drivers/media/video/tuner-core.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c623
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c (renamed from drivers/media/video/v4l2-compat-ioctl32.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c (renamed from drivers/media/video/v4l2-ctrls.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c1003
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c (renamed from drivers/media/video/v4l2-device.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c (renamed from drivers/media/video/v4l2-event.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-fh.c (renamed from drivers/media/video/v4l2-fh.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-int-device.c (renamed from drivers/media/video/v4l2-int-device.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c (renamed from drivers/media/video/v4l2-ioctl.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c (renamed from drivers/media/video/v4l2-mem2mem.c)0
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c (renamed from drivers/media/video/v4l2-subdev.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c (renamed from drivers/media/video/videobuf-core.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c (renamed from drivers/media/video/videobuf-dma-contig.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c (renamed from drivers/media/video/videobuf-dma-sg.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf-dvb.c398
-rw-r--r--drivers/media/v4l2-core/videobuf-vmalloc.c (renamed from drivers/media/video/videobuf-vmalloc.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c2380
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c (renamed from drivers/media/video/videobuf2-dma-contig.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c (renamed from drivers/media/video/videobuf2-dma-sg.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf2-memops.c (renamed from drivers/media/video/videobuf2-memops.c)0
-rw-r--r--drivers/media/v4l2-core/videobuf2-vmalloc.c223
-rw-r--r--drivers/media/video/Kconfig1263
-rw-r--r--drivers/media/video/Makefile218
-rw-r--r--drivers/media/video/adp1653.c487
-rw-r--r--drivers/media/video/as3645a.c888
-rw-r--r--drivers/media/video/au0828/Kconfig18
-rw-r--r--drivers/media/video/au0828/Makefile9
-rw-r--r--drivers/media/video/au0828/au0828-cards.c339
-rw-r--r--drivers/media/video/au0828/au0828-core.c295
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c458
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c390
-rw-r--r--drivers/media/video/au0828/au0828-reg.h65
-rw-r--r--drivers/media/video/au0828/au0828-video.c1998
-rw-r--r--drivers/media/video/au0828/au0828.h302
-rw-r--r--drivers/media/video/blackfin/bfin_capture.c1063
-rw-r--r--drivers/media/video/bt8xx/Kconfig27
-rw-r--r--drivers/media/video/bt8xx/Makefile13
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c2413
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c1250
-rw-r--r--drivers/media/video/cx18/Kconfig35
-rw-r--r--drivers/media/video/cx18/Makefile13
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c223
-rw-r--r--drivers/media/video/cx18/cx18-driver.c1359
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c605
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c453
-rw-r--r--drivers/media/video/cx231xx/Kconfig51
-rw-r--r--drivers/media/video/cx231xx/Makefile16
-rw-r--r--drivers/media/video/cx231xx/cx231xx-417.c2195
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c2645
-rw-r--r--drivers/media/video/cx23885/Kconfig46
-rw-r--r--drivers/media/video/cx23885/Makefile15
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c1788
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c1680
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c1357
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c356
-rw-r--r--drivers/media/video/cx25821/Makefile13
-rw-r--r--drivers/media/video/cx25840/Makefile6
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c166
-rw-r--r--drivers/media/video/cx88/Kconfig86
-rw-r--r--drivers/media/video/cx88/Makefile16
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c975
-rw-r--r--drivers/media/video/cx88/cx88-core.c1131
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c1778
-rw-r--r--drivers/media/video/cx88/cx88.h748
-rw-r--r--drivers/media/video/davinci/Kconfig121
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c1072
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c1081
-rw-r--r--drivers/media/video/davinci/isif.c1162
-rw-r--r--drivers/media/video/davinci/vpbe_display.c1830
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2079
-rw-r--r--drivers/media/video/davinci/vpif.c514
-rw-r--r--drivers/media/video/davinci/vpif_capture.c2444
-rw-r--r--drivers/media/video/davinci/vpif_display.c1998
-rw-r--r--drivers/media/video/davinci/vpss.c482
-rw-r--r--drivers/media/video/em28xx/Kconfig58
-rw-r--r--drivers/media/video/em28xx/Makefile15
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c752
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c1264
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2606
-rw-r--r--drivers/media/video/fsl-viu.c1673
-rw-r--r--drivers/media/video/gspca/Kconfig425
-rw-r--r--drivers/media/video/gspca/gl860/Makefile10
-rw-r--r--drivers/media/video/gspca/m5602/Makefile11
-rw-r--r--drivers/media/video/gspca/sq905c.c347
-rw-r--r--drivers/media/video/gspca/sq930x.c1172
-rw-r--r--drivers/media/video/gspca/stv06xx/Makefile10
-rw-r--r--drivers/media/video/gspca/vc032x.c3853
-rw-r--r--drivers/media/video/hdpvr/Makefile7
-rw-r--r--drivers/media/video/imx074.c475
-rw-r--r--drivers/media/video/ivtv/Makefile14
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c1038
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c398
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c1018
-rw-r--r--drivers/media/video/mem2mem_testdev.c1120
-rw-r--r--drivers/media/video/mt9m001.c737
-rw-r--r--drivers/media/video/mt9m111.c1014
-rw-r--r--drivers/media/video/mt9t031.c857
-rw-r--r--drivers/media/video/mt9t112.c1125
-rw-r--r--drivers/media/video/mt9v022.c879
-rw-r--r--drivers/media/video/mx2_camera.c1884
-rw-r--r--drivers/media/video/mx2_emmaprp.c1016
-rw-r--r--drivers/media/video/mx3_camera.c1292
-rw-r--r--drivers/media/video/omap/Makefile8
-rw-r--r--drivers/media/video/omap1_camera.c1723
-rw-r--r--drivers/media/video/omap24xxcam-dma.c601
-rw-r--r--drivers/media/video/omap24xxcam.c1881
-rw-r--r--drivers/media/video/omap24xxcam.h593
-rw-r--r--drivers/media/video/omap3isp/cfa_coef_table.h61
-rw-r--r--drivers/media/video/omap3isp/isp.c2230
-rw-r--r--drivers/media/video/omap3isp/isp.h351
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c2535
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h209
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.c1305
-rw-r--r--drivers/media/video/omap3isp/isph3a_aewb.c374
-rw-r--r--drivers/media/video/omap3isp/isph3a_af.c429
-rw-r--r--drivers/media/video/omap3isp/isphist.c520
-rw-r--r--drivers/media/video/omap3isp/isppreview.c2369
-rw-r--r--drivers/media/video/omap3isp/isppreview.h173
-rw-r--r--drivers/media/video/omap3isp/ispqueue.c1157
-rw-r--r--drivers/media/video/omap3isp/ispresizer.c1776
-rw-r--r--drivers/media/video/omap3isp/ispvideo.c1392
-rw-r--r--drivers/media/video/omap3isp/ispvideo.h214
-rw-r--r--drivers/media/video/ov2640.c1108
-rw-r--r--drivers/media/video/ov5642.c1073
-rw-r--r--drivers/media/video/ov6650.c1053
-rw-r--r--drivers/media/video/ov772x.c1126
-rw-r--r--drivers/media/video/ov9640.c746
-rw-r--r--drivers/media/video/ov9740.c1005
-rw-r--r--drivers/media/video/pvrusb2/Kconfig65
-rw-r--r--drivers/media/video/pvrusb2/Makefile22
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c569
-rw-r--r--drivers/media/video/pwc/Makefile4
-rw-r--r--drivers/media/video/rj54n1cb0c.c1414
-rw-r--r--drivers/media/video/s2255drv.c2689
-rw-r--r--drivers/media/video/s5k6aa.c1670
-rw-r--r--drivers/media/video/s5p-g2d/g2d.c832
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c1515
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h150
-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.c1223
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_cmd.c120
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_cmd.h30
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c343
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h29
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_debug.h48
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_dec.c1044
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_dec.h23
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_enc.c1834
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_enc.h23
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_intr.c92
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_intr.h26
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_opr.c1397
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_opr.h93
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_pm.c137
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_pm.h24
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_shm.c47
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_shm.h90
-rw-r--r--drivers/media/video/s5p-tv/Kconfig86
-rw-r--r--drivers/media/video/s5p-tv/Makefile19
-rw-r--r--drivers/media/video/s5p-tv/hdmi_drv.c1007
-rw-r--r--drivers/media/video/s5p-tv/mixer_drv.c487
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c1112
-rw-r--r--drivers/media/video/s5p-tv/regs-sdo.h63
-rw-r--r--drivers/media/video/s5p-tv/sdo_drv.c452
-rw-r--r--drivers/media/video/s5p-tv/sii9234_drv.c422
-rw-r--r--drivers/media/video/saa7127.c855
-rw-r--r--drivers/media/video/saa7134/Kconfig64
-rw-r--r--drivers/media/video/saa7134/Makefile16
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c1936
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c1045
-rw-r--r--drivers/media/video/saa7134/saa7134.h856
-rw-r--r--drivers/media/video/saa7164/Kconfig18
-rw-r--r--drivers/media/video/saa7164/Makefile12
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c1519
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c1526
-rw-r--r--drivers/media/video/saa7164/saa7164.h617
-rw-r--r--drivers/media/video/sh_vou.c1497
-rw-r--r--drivers/media/video/smiapp-pll.c418
-rw-r--r--drivers/media/video/smiapp-pll.h103
-rw-r--r--drivers/media/video/smiapp/Makefile5
-rw-r--r--drivers/media/video/smiapp/smiapp-core.c2895
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.c132
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.h128
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.c306
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.h83
-rw-r--r--drivers/media/video/smiapp/smiapp-reg-defs.h503
-rw-r--r--drivers/media/video/smiapp/smiapp-reg.h122
-rw-r--r--drivers/media/video/smiapp/smiapp-regs.c273
-rw-r--r--drivers/media/video/smiapp/smiapp.h252
-rw-r--r--drivers/media/video/soc_camera.c1546
-rw-r--r--drivers/media/video/soc_camera_platform.c197
-rw-r--r--drivers/media/video/tcm825x.c937
-rw-r--r--drivers/media/video/tcm825x.h200
-rw-r--r--drivers/media/video/tlg2300/Makefile9
-rw-r--r--drivers/media/video/tm6000/Makefile15
-rw-r--r--drivers/media/video/tm6000/tm6000-alsa.c528
-rw-r--r--drivers/media/video/tm6000/tm6000-input.c498
-rw-r--r--drivers/media/video/tm6000/tm6000-video.c1818
-rw-r--r--drivers/media/video/tvp514x.c1166
-rw-r--r--drivers/media/video/tvp514x_regs.h287
-rw-r--r--drivers/media/video/tw9910.c956
-rw-r--r--drivers/media/video/usbvision/Kconfig12
-rw-r--r--drivers/media/video/usbvision/Makefile6
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c1690
-rw-r--r--drivers/media/video/uvc/uvc_driver.c2448
-rw-r--r--drivers/media/video/uvc/uvc_video.c1861
-rw-r--r--drivers/media/video/uvc/uvcvideo.h709
-rw-r--r--drivers/media/video/v4l2-common.c623
-rw-r--r--drivers/media/video/v4l2-dev.c1038
-rw-r--r--drivers/media/video/videobuf-dvb.c403
-rw-r--r--drivers/media/video/videobuf2-core.c2387
-rw-r--r--drivers/media/video/videobuf2-vmalloc.c222
-rw-r--r--drivers/media/video/vivi.c1385
-rw-r--r--drivers/media/video/zoran/Kconfig74
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/as102/Makefile2
-rw-r--r--drivers/staging/media/cxd2099/Makefile6
-rw-r--r--drivers/staging/media/cxd2099/cxd2099.c13
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c29
-rw-r--r--drivers/staging/media/easycap/Kconfig30
-rw-r--r--drivers/staging/media/easycap/Makefile10
-rw-r--r--drivers/staging/media/easycap/README141
-rw-r--r--drivers/staging/media/easycap/easycap.h567
-rw-r--r--drivers/staging/media/easycap/easycap_ioctl.c2443
-rw-r--r--drivers/staging/media/easycap/easycap_low.c968
-rw-r--r--drivers/staging/media/easycap/easycap_main.c4239
-rw-r--r--drivers/staging/media/easycap/easycap_settings.c696
-rw-r--r--drivers/staging/media/easycap/easycap_sound.c750
-rw-r--r--drivers/staging/media/easycap/easycap_testcard.c155
-rw-r--r--drivers/staging/media/go7007/Makefile6
-rw-r--r--drivers/staging/media/lirc/Kconfig6
-rw-r--r--drivers/staging/media/lirc/Makefile1
-rw-r--r--drivers/staging/media/lirc/lirc_ene0100.h169
-rw-r--r--drivers/staging/media/lirc/lirc_igorplugusb.c4
-rw-r--r--drivers/staging/media/lirc/lirc_ttusbir.c376
-rw-r--r--drivers/staging/media/lirc/lirc_zilog.c3
-rw-r--r--include/linux/dvb/frontend.h51
-rw-r--r--include/linux/dvb/version.h2
-rw-r--r--include/linux/omap3isp.h6
-rw-r--r--include/linux/v4l2-common.h8
-rw-r--r--include/media/ir-rx51.h10
-rw-r--r--include/media/omap3isp.h14
-rw-r--r--include/media/saa7146.h4
-rw-r--r--include/media/soc_camera.h12
-rw-r--r--include/media/v4l2-common.h4
-rw-r--r--include/media/v4l2-dev.h3
-rw-r--r--include/media/v4l2-subdev.h2
-rw-r--r--include/media/videobuf-dvb.h4
1839 files changed, 206793 insertions, 207264 deletions
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 362520992ced..9b7e4c557928 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -300,7 +300,7 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
@( \
for ident in $(IOCTLS) ; do \
entity=`echo $$ident | tr _ -` ; \
- id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
+ id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
echo "<!ENTITY $$entity \"<link" \
"linkend='$$id'><constant>$$ident</constant></link>\">" \
>>$@ ; \
diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml
index d64386237207..a7ea56c71a27 100644
--- a/Documentation/DocBook/media/dvb/audio.xml
+++ b/Documentation/DocBook/media/dvb/audio.xml
@@ -1,12 +1,16 @@
<title>DVB Audio Device</title>
<para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/audio.h</emphasis> in your
application.
</para>
<para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
the omission of the audio and video device.
</para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
<section id="audio_data_types">
<title>Audio Data Types</title>
@@ -558,6 +562,8 @@ role="subsection"><title>AUDIO_SELECT_SOURCE</title>
role="subsection"><title>AUDIO_SET_MUTE</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; with the <constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant> flag instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call asks the audio device to mute the stream that is currently being
@@ -730,6 +736,8 @@ role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+<constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant> control instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
@@ -772,6 +780,109 @@ role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
</row></tbody></tgroup></informaltable>
&return-value-dvb;
+</section><section id="AUDIO_BILINGUAL_CHANNEL_SELECT"
+role="subsection"><title>AUDIO_BILINGUAL_CHANNEL_SELECT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. It has been replaced by
+the V4L2 <constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant> control
+for MPEG decoders controlled through V4L2.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to select the requested channel for bilingual streams if possible.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_channel_select_t
+ch</para>
+</entry><entry
+ align="char">
+<para>Select the output format of the audio (mono left/right,
+ stereo).</para>
+</entry>
+ </row>
+</tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_GET_PTS"
+role="subsection"><title>AUDIO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. If you need this functionality,
+then please contact the linux-media mailing list (&v4l-ml;).</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
</section><section id="AUDIO_GET_STATUS"
role="subsection"><title>AUDIO_GET_STATUS</title>
<para>DESCRIPTION
diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml
index 5c4adb44b1c1..85eaf4fe2931 100644
--- a/Documentation/DocBook/media/dvb/ca.xml
+++ b/Documentation/DocBook/media/dvb/ca.xml
@@ -226,4 +226,357 @@ typedef struct ca_pid {
</entry>
</row></tbody></tgroup></informaltable>
</section>
+
+<section id="CA_RESET"
+role="subsection"><title>CA_RESET</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_RESET);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_RESET for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_CAP"
+role="subsection"><title>CA_GET_CAP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_CAP,
+ ca_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_CAP for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_SLOT_INFO"
+role="subsection"><title>CA_GET_SLOT_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_SLOT_INFO,
+ ca_slot_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_SLOT_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_slot_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_DESCR_INFO"
+role="subsection"><title>CA_GET_DESCR_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_DESCR_INFO,
+ ca_descr_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_DESCR_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_MSG"
+role="subsection"><title>CA_GET_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SEND_MSG"
+role="subsection"><title>CA_SEND_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SEND_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SEND_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_DESCR"
+role="subsection"><title>CA_SET_DESCR</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_DESCR,
+ ca_descr_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_DESCR for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_PID"
+role="subsection"><title>CA_SET_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_PID,
+ ca_pid_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_pid_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
</section>
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
index 37c17908aa40..86de89cfbd67 100644
--- a/Documentation/DocBook/media/dvb/demux.xml
+++ b/Documentation/DocBook/media/dvb/demux.xml
@@ -899,4 +899,232 @@ typedef enum {
<para>Invalid stc number.</para>
</entry>
</row></tbody></tgroup></informaltable>
- </section></section>
+ </section>
+
+<section id="DMX_GET_PES_PIDS"
+role="subsection"><title>DMX_GET_PES_PIDS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_PES_PIDS,
+ __u16[5]);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_PES_PIDS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16[5]
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_GET_CAPS"
+role="subsection"><title>DMX_GET_CAPS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_CAPS,
+ dmx_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_CAPS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_SET_SOURCE"
+role="subsection"><title>DMX_SET_SOURCE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_SET_SOURCE,
+ dmx_source_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_SOURCE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_source_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_ADD_PID"
+role="subsection"><title>DMX_ADD_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_ADD_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_ADD_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_REMOVE_PID"
+role="subsection"><title>DMX_REMOVE_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_REMOVE_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_REMOVE_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+
+</section>
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
index 2ab6ddcfc4e0..d36f8f93c4ff 100644
--- a/Documentation/DocBook/media/dvb/dvbapi.xml
+++ b/Documentation/DocBook/media/dvb/dvbapi.xml
@@ -28,7 +28,7 @@
<holder>Convergence GmbH</holder>
</copyright>
<copyright>
- <year>2009-2011</year>
+ <year>2009-2012</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index e633c097a8d1..d188be963a47 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -194,6 +194,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
APSK_16,
APSK_32,
DQPSK,
+ QAM_4_NR,
} fe_modulation_t;
</programlisting>
</section>
@@ -265,6 +266,7 @@ typedef enum fe_code_rate {
FEC_AUTO,
FEC_3_5,
FEC_9_10,
+ FEC_2_5,
} fe_code_rate_t;
</programlisting>
<para>which correspond to error correction rates of 1/2, 2/3, etc.,
@@ -351,7 +353,7 @@ typedef enum fe_delivery_system {
SYS_ISDBC,
SYS_ATSC,
SYS_ATSCMH,
- SYS_DMBTH,
+ SYS_DTMB,
SYS_CMMB,
SYS_DAB,
SYS_DVBT2,
@@ -567,28 +569,33 @@ typedef enum fe_delivery_system {
<title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
<para>RS frame mode.</para>
<para>Possible values are:</para>
+ <para id="atscmh-rs-frame-mode">
<programlisting>
typedef enum atscmh_rs_frame_mode {
ATSCMH_RSFRAME_PRI_ONLY = 0,
ATSCMH_RSFRAME_PRI_SEC = 1,
} atscmh_rs_frame_mode_t;
</programlisting>
+ </para>
</section>
<section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
<title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
<para>RS frame ensemble.</para>
<para>Possible values are:</para>
+ <para id="atscmh-rs-frame-ensemble">
<programlisting>
typedef enum atscmh_rs_frame_ensemble {
ATSCMH_RSFRAME_ENS_PRI = 0,
ATSCMH_RSFRAME_ENS_SEC = 1,
} atscmh_rs_frame_ensemble_t;
</programlisting>
+ </para>
</section>
<section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
<title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
<para>RS code mode (primary).</para>
<para>Possible values are:</para>
+ <para id="atscmh-rs-code-mode">
<programlisting>
typedef enum atscmh_rs_code_mode {
ATSCMH_RSCODE_211_187 = 0,
@@ -596,6 +603,7 @@ typedef enum atscmh_rs_code_mode {
ATSCMH_RSCODE_235_187 = 2,
} atscmh_rs_code_mode_t;
</programlisting>
+ </para>
</section>
<section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
<title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
@@ -613,23 +621,27 @@ typedef enum atscmh_rs_code_mode {
<title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
<para>Series Concatenated Convolutional Code Block Mode.</para>
<para>Possible values are:</para>
+ <para id="atscmh-sccc-block-mode">
<programlisting>
typedef enum atscmh_sccc_block_mode {
ATSCMH_SCCC_BLK_SEP = 0,
ATSCMH_SCCC_BLK_COMB = 1,
} atscmh_sccc_block_mode_t;
</programlisting>
+ </para>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
<para>Series Concatenated Convolutional Code Rate.</para>
<para>Possible values are:</para>
+ <para id="atscmh-sccc-code-mode">
<programlisting>
typedef enum atscmh_sccc_code_mode {
ATSCMH_SCCC_CODE_HLF = 0,
ATSCMH_SCCC_CODE_QTR = 1,
} atscmh_sccc_code_mode_t;
</programlisting>
+ </para>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
@@ -725,6 +737,9 @@ typedef enum fe_guard_interval {
GUARD_INTERVAL_1_128,
GUARD_INTERVAL_19_128,
GUARD_INTERVAL_19_256,
+ GUARD_INTERVAL_PN420,
+ GUARD_INTERVAL_PN595,
+ GUARD_INTERVAL_PN945,
} fe_guard_interval_t;
</programlisting>
@@ -733,6 +748,7 @@ typedef enum fe_guard_interval {
try to find the correct guard interval (if capable) and will use TMCC to fill
in the missing parameters.</para>
<para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+ <para>3) DTMB specifies PN420, PN595 and PN945.</para>
</section>
<section id="DTV-TRANSMISSION-MODE">
<title><constant>DTV_TRANSMISSION_MODE</constant></title>
@@ -749,6 +765,8 @@ typedef enum fe_transmit_mode {
TRANSMISSION_MODE_1K,
TRANSMISSION_MODE_16K,
TRANSMISSION_MODE_32K,
+ TRANSMISSION_MODE_C1,
+ TRANSMISSION_MODE_C3780,
} fe_transmit_mode_t;
</programlisting>
<para>Notes:</para>
@@ -760,6 +778,7 @@ typedef enum fe_transmit_mode {
use TMCC to fill in the missing parameters.</para>
<para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
<para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+ <para>5) DTMB specifies C1 and C3780.</para>
</section>
<section id="DTV-HIERARCHY">
<title><constant>DTV_HIERARCHY</constant></title>
@@ -784,7 +803,7 @@ typedef enum fe_hierarchy {
many data types via a single multiplex. The API will soon support this
at which point this section will be expanded.</para>
</section>
- <section id="DTV_ENUM_DELSYS">
+ <section id="DTV-ENUM-DELSYS">
<title><constant>DTV_ENUM_DELSYS</constant></title>
<para>A Multi standard frontend needs to advertise the delivery systems provided.
Applications need to enumerate the provided delivery systems, before using
@@ -796,6 +815,18 @@ typedef enum fe_hierarchy {
FE_GET_INFO. In the case of a legacy frontend, the result is just the same
as with FE_GET_INFO, but in a more structured format </para>
</section>
+ <section id="DTV-INTERLEAVING">
+ <title><constant>DTV_INTERLEAVING</constant></title>
+ <para id="fe-interleaving">Interleaving mode</para>
+ <programlisting>
+enum fe_interleaving {
+ INTERLEAVING_NONE,
+ INTERLEAVING_AUTO,
+ INTERLEAVING_240,
+ INTERLEAVING_720,
+};
+ </programlisting>
+ </section>
</section>
<section id="frontend-property-terrestrial-systems">
<title>Properties used on terrestrial delivery systems</title>
@@ -925,13 +956,31 @@ typedef enum fe_hierarchy {
<listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-PRI"><constant>DTV_ATSCMH_CODE_MODE_PRI</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-SEC"><constant>DTV_ATSCMH_CODE_MODE_SEC</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-PRI"><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-SEC"><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
- <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+ </itemizedlist>
+ </section>
+ <section id="dtmb-params">
+ <title>DTMB delivery system</title>
+ <para>The following parameters are valid for DTMB:</para>
+ <itemizedlist mark='opencircle'>
+ <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-INTERLEAVING"><constant>DTV_INTERLEAVING</constant></link></para></listitem>
</itemizedlist>
</section>
</section>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index aeaed59d0f1f..950bdfb4504b 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -66,7 +66,7 @@ supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET
<para>The usage of this field is deprecated, as it doesn't report all supported standards, and
will provide an incomplete information for frontends that support multiple delivery systems.
-Please use <link linkend="DTV_ENUM_DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
+Please use <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
</section>
<section id="fe-caps-t">
@@ -207,18 +207,44 @@ spec.</para>
<para>Several functions of the frontend device use the fe_status data type defined
by</para>
<programlisting>
- typedef enum fe_status {
- FE_HAS_SIGNAL = 0x01, /&#x22C6; found something above the noise level &#x22C6;/
- FE_HAS_CARRIER = 0x02, /&#x22C6; found a DVB signal &#x22C6;/
- FE_HAS_VITERBI = 0x04, /&#x22C6; FEC is stable &#x22C6;/
- FE_HAS_SYNC = 0x08, /&#x22C6; found sync bytes &#x22C6;/
- FE_HAS_LOCK = 0x10, /&#x22C6; everything's working... &#x22C6;/
- FE_TIMEDOUT = 0x20, /&#x22C6; no lock within the last ~2 seconds &#x22C6;/
- FE_REINIT = 0x40 /&#x22C6; frontend was reinitialized, &#x22C6;/
- } fe_status_t; /&#x22C6; application is recommned to reset &#x22C6;/
+typedef enum fe_status {
+ FE_HAS_SIGNAL = 0x01,
+ FE_HAS_CARRIER = 0x02,
+ FE_HAS_VITERBI = 0x04,
+ FE_HAS_SYNC = 0x08,
+ FE_HAS_LOCK = 0x10,
+ FE_TIMEDOUT = 0x20,
+ FE_REINIT = 0x40,
+} fe_status_t;
</programlisting>
-<para>to indicate the current state and/or state changes of the frontend hardware.
-</para>
+<para>to indicate the current state and/or state changes of the frontend hardware:
+</para>
+
+<informaltable><tgroup cols="2"><tbody>
+<row>
+<entry align="char">FE_HAS_SIGNAL</entry>
+<entry align="char">The frontend has found something above the noise level</entry>
+</row><row>
+<entry align="char">FE_HAS_CARRIER</entry>
+<entry align="char">The frontend has found a DVB signal</entry>
+</row><row>
+<entry align="char">FE_HAS_VITERBI</entry>
+<entry align="char">The frontend FEC code is stable</entry>
+</row><row>
+<entry align="char">FE_HAS_SYNC</entry>
+<entry align="char">Syncronization bytes was found</entry>
+</row><row>
+<entry align="char">FE_HAS_LOCK</entry>
+<entry align="char">The DVB were locked and everything is working</entry>
+</row><row>
+<entry align="char">FE_TIMEDOUT</entry>
+<entry align="char">no lock within the last about 2 seconds</entry>
+</row><row>
+<entry align="char">FE_REINIT</entry>
+<entry align="char">The frontend was reinitialized, application is
+recommended to reset DiSEqC, tone and parameters</entry>
+</row>
+</tbody></tgroup></informaltable>
</section>
@@ -238,7 +264,7 @@ and to add newer delivery systems.</para>
<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
order to be able to support the newer System Delivery like DVB-S2, DVB-T2,
DVB-C2, ISDB, etc.</para>
-<para>All kinds of parameters are combined as an union in the FrontendParameters structure:</para>
+<para>All kinds of parameters are combined as an union in the FrontendParameters structure:
<programlisting>
struct dvb_frontend_parameters {
uint32_t frequency; /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
@@ -251,12 +277,13 @@ struct dvb_frontend_parameters {
struct dvb_vsb_parameters vsb;
} u;
};
-</programlisting>
+</programlisting></para>
<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
</para>
+
<section id="dvb-qpsk-parameters">
<title>QPSK parameters</title>
<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
@@ -321,8 +348,8 @@ itself.
<section id="fe-code-rate-t">
<title>frontend code rate</title>
<para>The possible values for the <constant>fec_inner</constant> field used on
-<link refend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
-<link refend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
+<link linkend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
+<link linkend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
</para>
<programlisting>
typedef enum fe_code_rate {
@@ -347,9 +374,9 @@ detection.
<section id="fe-modulation-t">
<title>frontend modulation type for QAM, OFDM and VSB</title>
<para>For cable and terrestrial frontends, e. g. for
-<link refend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
-<link refend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
-<link refend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
+<link linkend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
+<link linkend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
+<link linkend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
it needs to specify the quadrature modulation mode which can be one of the following:
</para>
<programlisting>
@@ -370,8 +397,8 @@ it needs to specify the quadrature modulation mode which can be one of the follo
} fe_modulation_t;
</programlisting>
</section>
-<para>Finally, there are several more parameters for OFDM:
-</para>
+<section>
+<title>More OFDM parameters</title>
<section id="fe-transmit-mode-t">
<title>Number of carriers per channel</title>
<programlisting>
@@ -427,6 +454,7 @@ typedef enum fe_hierarchy {
} fe_hierarchy_t;
</programlisting>
</section>
+</section>
</section>
diff --git a/Documentation/DocBook/media/dvb/kdapi.xml b/Documentation/DocBook/media/dvb/kdapi.xml
index 6c67481eaa4b..6c11ec52cbee 100644
--- a/Documentation/DocBook/media/dvb/kdapi.xml
+++ b/Documentation/DocBook/media/dvb/kdapi.xml
@@ -2,7 +2,7 @@
<para>The kernel demux API defines a driver-internal interface for registering low-level,
hardware specific driver to a hardware independent demux layer. It is only of interest for
DVB device driver writers. The header file for this API is named <emphasis role="tt">demux.h</emphasis> and located in
-<emphasis role="tt">drivers/media/dvb/dvb-core</emphasis>.
+<emphasis role="tt">drivers/media/dvb-core</emphasis>.
</para>
<para>Maintainer note: This section must be reviewed. It is probably out of date.
</para>
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml
index 67d37e5ce597..a193e86941b5 100644
--- a/Documentation/DocBook/media/dvb/net.xml
+++ b/Documentation/DocBook/media/dvb/net.xml
@@ -26,4 +26,131 @@ struct dvb_net_if {
<title>DVB net Function Calls</title>
<para>To be written&#x2026;
</para>
+
+<section id="NET_ADD_IF"
+role="subsection"><title>NET_ADD_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_ADD_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_ADD_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_REMOVE_IF"
+role="subsection"><title>NET_REMOVE_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_REMOVE_IF);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_REMOVE_IF for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_GET_IF"
+role="subsection"><title>NET_GET_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_GET_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_GET_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
</section>
diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml
index 25fb823226b4..3ea1ca7e785e 100644
--- a/Documentation/DocBook/media/dvb/video.xml
+++ b/Documentation/DocBook/media/dvb/video.xml
@@ -15,6 +15,10 @@ the audio and video device as well as the video4linux device.
<para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
supported on some MPEG decoders made for DVD playback.
</para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
<section id="video_types">
<title>Video Data Types</title>
@@ -55,7 +59,7 @@ typedef enum {
</section>
<section id="video-stream-source-t">
-<title>video stream source</title>
+<title>video_stream_source_t</title>
<para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
the following values, depending on whether we are replaying from an internal (demuxer) or
external (user write) source.
@@ -76,7 +80,7 @@ call.
</section>
<section id="video-play-state-t">
-<title>video play state</title>
+<title>video_play_state_t</title>
<para>The following values can be returned by the VIDEO_GET_STATUS call representing the
state of video playback.
</para>
@@ -90,9 +94,9 @@ typedef enum {
</section>
<section id="video-command">
+<title>struct video_command</title>
<para>The structure must be zeroed before use by the application
This ensures it can be extended safely in the future.</para>
-<title>struct video-command</title>
<programlisting>
struct video_command {
__u32 cmd;
@@ -121,7 +125,7 @@ struct video_command {
</section>
<section id="video-size-t">
-<title>struct video_size-t</title>
+<title>video_size_t</title>
<programlisting>
typedef struct {
int w;
@@ -217,7 +221,7 @@ bits set according to the hardwares capabilities.
</section>
<section id="video-system">
-<title>video system</title>
+<title>video_system_t</title>
<para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
following system types can be set:
</para>
@@ -263,7 +267,7 @@ call expects the following format for that information:
</section>
<section id="video-spu">
-<title>video SPU</title>
+<title>struct video_spu</title>
<para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
following format:
</para>
@@ -277,12 +281,12 @@ following format:
</section>
<section id="video-spu-palette">
-<title>video SPU palette</title>
+<title>struct video_spu_palette</title>
<para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
</para>
<programlisting>
typedef
- struct video_spu_palette{
+ struct video_spu_palette {
int length;
uint8_t &#x22C6;palette;
} video_spu_palette_t;
@@ -290,13 +294,13 @@ following format:
</section>
<section id="video-navi-pack">
-<title>video NAVI pack</title>
+<title>struct video_navi_pack</title>
<para>In order to get the navigational data the following structure has to be passed to the ioctl
VIDEO_GET_NAVI:
</para>
<programlisting>
typedef
- struct video_navi_pack{
+ struct video_navi_pack {
int length; /&#x22C6; 0 ... 1024 &#x22C6;/
uint8_t data[1024];
} video_navi_pack_t;
@@ -305,7 +309,7 @@ VIDEO_GET_NAVI:
<section id="video-attributes-t">
-<title>video attributes</title>
+<title>video_attributes_t</title>
<para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
</para>
<programlisting>
@@ -541,6 +545,8 @@ VIDEO_GET_NAVI:
role="subsection"><title>VIDEO_STOP</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call asks the Video Device to stop playing the current stream.
@@ -598,6 +604,8 @@ role="subsection"><title>VIDEO_STOP</title>
role="subsection"><title>VIDEO_PLAY</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call asks the Video Device to start playing a video stream from the
@@ -634,6 +642,8 @@ role="subsection"><title>VIDEO_PLAY</title>
role="subsection"><title>VIDEO_FREEZE</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call suspends the live video stream being played. Decoding
@@ -674,6 +684,8 @@ role="subsection"><title>VIDEO_FREEZE</title>
role="subsection"><title>VIDEO_CONTINUE</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call restarts decoding and playing processes of the video stream
@@ -710,6 +722,9 @@ role="subsection"><title>VIDEO_CONTINUE</title>
role="subsection"><title>VIDEO_SELECT_SOURCE</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. This ioctl was also supported by the
+V4L2 ivtv driver, but that has been replaced by the ivtv-specific
+<constant>IVTV_IOC_PASSTHROUGH_MODE</constant> ioctl.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call informs the video device which source shall be used for the input
@@ -845,10 +860,160 @@ role="subsection"><title>VIDEO_GET_STATUS</title>
</row></tbody></tgroup></informaltable>
&return-value-dvb;
+</section><section id="VIDEO_GET_FRAME_COUNT"
+role="subsection"><title>VIDEO_GET_FRAME_COUNT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the number of displayed frames
+since the decoder was started.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_COUNT, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_COUNT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the number of frames displayed since the decoder was started.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_PTS"
+role="subsection"><title>VIDEO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_FRAME_RATE"
+role="subsection"><title>VIDEO_GET_FRAME_RATE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current framerate.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_RATE, unsigned int *rate);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_RATE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned int *rate
+</para>
+</entry><entry
+ align="char">
+<para>Returns the framerate in number of frames per 1000 seconds.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
</section><section id="VIDEO_GET_EVENT"
role="subsection"><title>VIDEO_GET_EVENT</title>
<para>DESCRIPTION
</para>
+<para>This ioctl is for DVB devices only. To get events from a V4L2 decoder use the V4L2
+&VIDIOC-DQEVENT; ioctl instead.</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
<para>This ioctl call returns an event of type video_event if available. If an event is
@@ -914,6 +1079,152 @@ role="subsection"><title>VIDEO_GET_EVENT</title>
</entry>
</row></tbody></tgroup></informaltable>
+</section><section id="VIDEO_COMMAND"
+role="subsection"><title>VIDEO_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl commands the decoder. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Commands the decoder.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_TRY_COMMAND"
+role="subsection"><title>VIDEO_TRY_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-TRY-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl tries a decoder command. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-TRY-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_TRY_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_TRY_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Try a decoder command.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_SIZE"
+role="subsection"><title>VIDEO_GET_SIZE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl returns the size and aspect ratio.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_SIZE, video_size_t *size);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_SIZE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_size_t *size
+</para>
+</entry><entry
+ align="char">
+<para>Returns the size and aspect ratio.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
</section><section id="VIDEO_SET_DISPLAY_FORMAT"
role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
<para>DESCRIPTION
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index 1078e45f189f..18b6fc9ff58b 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -178,23 +178,23 @@ Signal - NTSC for Studio Applications"</title>
1125-Line High-Definition Production"</title>
</biblioentry>
- <biblioentry id="en50067">
- <abbrev>EN&nbsp;50067</abbrev>
+ <biblioentry id="iec62106">
+ <abbrev>IEC&nbsp;62106</abbrev>
<authorgroup>
- <corpauthor>European Committee for Electrotechnical Standardization
-(<ulink url="http://www.cenelec.eu">http://www.cenelec.eu</ulink>)</corpauthor>
+ <corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
</authorgroup>
<title>Specification of the radio data system (RDS) for VHF/FM sound broadcasting
in the frequency range from 87,5 to 108,0 MHz</title>
</biblioentry>
<biblioentry id="nrsc4">
- <abbrev>NRSC-4</abbrev>
+ <abbrev>NRSC-4-B</abbrev>
<authorgroup>
<corpauthor>National Radio Systems Committee
(<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
</authorgroup>
- <title>NRSC-4: United States RBDS Standard</title>
+ <title>NRSC-4-B: United States RBDS Standard</title>
</biblioentry>
<biblioentry id="iso12232">
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index faa0fd14666a..98e8d088b3a5 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2468,21 +2468,9 @@ that used it. It was originally scheduled for removal in 2.6.35.
<structfield>reserved2</structfield> and removed
<constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
</listitem>
- </orderedlist>
- </section>
-
- <section>
- <title>V4L2 in Linux 3.6</title>
- <orderedlist>
<listitem>
<para>Added V4L2_CAP_VIDEO_M2M and V4L2_CAP_VIDEO_M2M_MPLANE capabilities.</para>
</listitem>
- </orderedlist>
- </section>
-
- <section>
- <title>V4L2 in Linux 3.6</title>
- <orderedlist>
<listitem>
<para>Added support for frequency band enumerations: &VIDIOC-ENUM-FREQ-BANDS;.</para>
</listitem>
@@ -2615,10 +2603,6 @@ ioctls.</para>
and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
</listitem>
<listitem>
- <para><link linkend="v4l2-auto-focus-area"><constant>
- V4L2_CID_AUTO_FOCUS_AREA</constant></link> control.</para>
- </listitem>
- <listitem>
<para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para>
</listitem>
</itemizedlist>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index b0964fb4e834..93b9c6872e53 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -3505,7 +3505,7 @@ This encodes up to 31 pre-defined programme types.</entry>
</row>
<row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
It is intended for static display on a receiver. It is the primary aid to listeners in programme service
-identification and selection. In Annex E of <xref linkend="en50067" />, the RDS specification,
+identification and selection. In Annex E of <xref linkend="iec62106" />, the RDS specification,
there is a full description of the correct character encoding for Programme Service name strings.
Also from RDS specification, PS is usually a single eight character text. However, it is also possible
to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
@@ -3519,7 +3519,7 @@ with steps of 8 characters. The result is it must always contain a string with s
what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
programme-related information or any other text. In these cases, RadioText should be used in addition to
<constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
-in Annex E of <xref linkend="en50067" />. The length of Radio Text strings depends on which RDS Block is being
+in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
used to transmit it, either 32 (2A block) or 64 (2B block). However, it is also possible
to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
@@ -3650,7 +3650,7 @@ manually or automatically if set to zero. Unit, range and step are driver-specif
</table>
<para>For more details about RDS specification, refer to
-<xref linkend="en50067" /> document, from CENELEC.</para>
+<xref linkend="iec62106" /> document, from CENELEC.</para>
</section>
<section id="flash-controls">
@@ -3717,232 +3717,231 @@ interface and may change in the future.</para>
use case involving camera or individually.
</para>
- </section>
+ <table pgwide="1" frame="none" id="flash-control-id">
+ <title>Flash Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
+ <entry>class</entry>
+ </row>
+ <row>
+ <entry spanname="descr">The FLASH class descriptor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
+ <entry>menu</entry>
+ </row>
+ <row id="v4l2-flash-led-mode">
+ <entry spanname="descr">Defines the mode of the flash LED,
+ the high-power white LED attached to the flash controller.
+ Setting this control may not be possible in presence of
+ some faults. See V4L2_CID_FLASH_FAULT.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
+ <entry>Off.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
+ <entry>Flash mode.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
+ <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
+ <entry>menu</entry>
+ </row>
+ <row id="v4l2-flash-strobe-source"><entry
+ spanname="descr">Defines the source of the flash LED
+ strobe.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
+ <entry>The flash strobe is triggered by using
+ the V4L2_CID_FLASH_STROBE control.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
+ <entry>The flash strobe is triggered by an
+ external source. Typically this is a sensor,
+ which makes it possible to synchronises the
+ flash strobe start to exposure start.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
+ <entry>button</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Strobe flash. Valid when
+ V4L2_CID_FLASH_LED_MODE is set to
+ V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+ is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+ control may not be possible in presence of some faults.
+ See V4L2_CID_FLASH_FAULT.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
+ <entry>button</entry>
+ </row>
+ <row><entry spanname="descr">Stop flash strobe immediately.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Strobe status: whether the flash
+ is strobing at the moment or not. This is a read-only
+ control.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Hardware timeout for flash. The
+ flash strobe is stopped after this period of time has
+ passed from the start of the strobe.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Intensity of the flash strobe when
+ the flash LED is in flash mode
+ (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+ (mA) if possible.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Intensity of the flash LED in
+ torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+ milliamps (mA) if possible. Setting this control may not
+ be possible in presence of some faults. See
+ V4L2_CID_FLASH_FAULT.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Intensity of the indicator LED.
+ The indicator LED may be fully independent of the flash
+ LED. The unit should be microamps (uA) if possible.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
+ <entry>bitmask</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Faults related to the flash. The
+ faults tell about specific problems in the flash chip
+ itself or the LEDs attached to it. Faults may prevent
+ further use of some of the flash controls. In particular,
+ V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+ if the fault affects the flash LED. Exactly which faults
+ have such an effect is chip dependent. Reading the faults
+ resets the control and returns the chip to a usable state
+ if possible.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
+ <entry>Flash controller voltage to the flash LED
+ has exceeded the limit specific to the flash
+ controller.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
+ <entry>The flash strobe was still on when
+ the timeout set by the user ---
+ V4L2_CID_FLASH_TIMEOUT control --- has expired.
+ Not all flash controllers may set this in all
+ such conditions.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
+ <entry>The flash controller has overheated.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
+ <entry>The short circuit protection of the flash
+ controller has been triggered.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
+ <entry>Current in the LED power supply has exceeded the limit
+ specific to the flash controller.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
+ <entry>The flash controller has detected a short or open
+ circuit condition on the indicator LED.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row><entry spanname="descr">Enable or disable charging of the xenon
+ flash capacitor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Is the flash ready to strobe?
+ Xenon flashes require their capacitors charged before
+ strobing. LED flashes often require a cooldown period
+ after strobe during which another strobe will not be
+ possible. This is a read-only control.</entry>
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</section>
-
- <table pgwide="1" frame="none" id="flash-control-id">
- <title>Flash Control IDs</title>
-
- <tgroup cols="4">
- <colspec colname="c1" colwidth="1*" />
- <colspec colname="c2" colwidth="6*" />
- <colspec colname="c3" colwidth="2*" />
- <colspec colname="c4" colwidth="6*" />
- <spanspec namest="c1" nameend="c2" spanname="id" />
- <spanspec namest="c2" nameend="c4" spanname="descr" />
- <thead>
- <row>
- <entry spanname="id" align="left">ID</entry>
- <entry align="left">Type</entry>
- </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
- </row>
- </thead>
- <tbody valign="top">
- <row><entry></entry></row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
- <entry>class</entry>
- </row>
- <row>
- <entry spanname="descr">The FLASH class descriptor.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
- <entry>menu</entry>
- </row>
- <row id="v4l2-flash-led-mode">
- <entry spanname="descr">Defines the mode of the flash LED,
- the high-power white LED attached to the flash controller.
- Setting this control may not be possible in presence of
- some faults. See V4L2_CID_FLASH_FAULT.</entry>
- </row>
- <row>
- <entrytbl spanname="descr" cols="2">
- <tbody valign="top">
- <row>
- <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
- <entry>Off.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
- <entry>Flash mode.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
- <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
- </row>
- </tbody>
- </entrytbl>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
- <entry>menu</entry>
- </row>
- <row id="v4l2-flash-strobe-source"><entry
- spanname="descr">Defines the source of the flash LED
- strobe.</entry>
- </row>
- <row>
- <entrytbl spanname="descr" cols="2">
- <tbody valign="top">
- <row>
- <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
- <entry>The flash strobe is triggered by using
- the V4L2_CID_FLASH_STROBE control.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
- <entry>The flash strobe is triggered by an
- external source. Typically this is a sensor,
- which makes it possible to synchronises the
- flash strobe start to exposure start.</entry>
- </row>
- </tbody>
- </entrytbl>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
- <entry>button</entry>
- </row>
- <row>
- <entry spanname="descr">Strobe flash. Valid when
- V4L2_CID_FLASH_LED_MODE is set to
- V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
- is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
- control may not be possible in presence of some faults.
- See V4L2_CID_FLASH_FAULT.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
- <entry>button</entry>
- </row>
- <row><entry spanname="descr">Stop flash strobe immediately.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
- <entry>boolean</entry>
- </row>
- <row>
- <entry spanname="descr">Strobe status: whether the flash
- is strobing at the moment or not. This is a read-only
- control.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
- <entry>integer</entry>
- </row>
- <row>
- <entry spanname="descr">Hardware timeout for flash. The
- flash strobe is stopped after this period of time has
- passed from the start of the strobe.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
- <entry>integer</entry>
- </row>
- <row>
- <entry spanname="descr">Intensity of the flash strobe when
- the flash LED is in flash mode
- (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
- (mA) if possible.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
- <entry>integer</entry>
- </row>
- <row>
- <entry spanname="descr">Intensity of the flash LED in
- torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
- milliamps (mA) if possible. Setting this control may not
- be possible in presence of some faults. See
- V4L2_CID_FLASH_FAULT.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
- <entry>integer</entry>
- </row>
- <row>
- <entry spanname="descr">Intensity of the indicator LED.
- The indicator LED may be fully independent of the flash
- LED. The unit should be microamps (uA) if possible.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
- <entry>bitmask</entry>
- </row>
- <row>
- <entry spanname="descr">Faults related to the flash. The
- faults tell about specific problems in the flash chip
- itself or the LEDs attached to it. Faults may prevent
- further use of some of the flash controls. In particular,
- V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
- if the fault affects the flash LED. Exactly which faults
- have such an effect is chip dependent. Reading the faults
- resets the control and returns the chip to a usable state
- if possible.</entry>
- </row>
- <row>
- <entrytbl spanname="descr" cols="2">
- <tbody valign="top">
- <row>
- <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
- <entry>Flash controller voltage to the flash LED
- has exceeded the limit specific to the flash
- controller.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
- <entry>The flash strobe was still on when
- the timeout set by the user ---
- V4L2_CID_FLASH_TIMEOUT control --- has expired.
- Not all flash controllers may set this in all
- such conditions.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
- <entry>The flash controller has overheated.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
- <entry>The short circuit protection of the flash
- controller has been triggered.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
- <entry>Current in the LED power supply has exceeded the limit
- specific to the flash controller.</entry>
- </row>
- <row>
- <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
- <entry>The flash controller has detected a short or open
- circuit condition on the indicator LED.</entry>
- </row>
- </tbody>
- </entrytbl>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
- <entry>boolean</entry>
- </row>
- <row><entry spanname="descr">Enable or disable charging of the xenon
- flash capacitor.</entry>
- </row>
- <row>
- <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
- <entry>boolean</entry>
- </row>
- <row>
- <entry spanname="descr">Is the flash ready to strobe?
- Xenon flashes require their capacitors charged before
- strobing. LED flashes often require a cooldown period
- after strobe during which another strobe will not be
- possible. This is a read-only control.</entry>
- </row>
- <row><entry></entry></row>
- </tbody>
- </tgroup>
- </table>
</section>
<section id="jpeg-controls">
diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml
index 38883a419e65..be2f33737323 100644
--- a/Documentation/DocBook/media/v4l/dev-rds.xml
+++ b/Documentation/DocBook/media/v4l/dev-rds.xml
@@ -6,7 +6,7 @@ information, on an inaudible audio subcarrier of a radio program. This
interface is aimed at devices capable of receiving and/or transmitting RDS
information.</para>
- <para>For more information see the core RDS standard <xref linkend="en50067" />
+ <para>For more information see the core RDS standard <xref linkend="iec62106" />
and the RBDS standard <xref linkend="nrsc4" />.</para>
<para>Note that the RBDS standard as is used in the USA is almost identical
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index a3d9dd093268..d15aaf83f56f 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -374,29 +374,29 @@
rectangle --- if it is supported by the hardware.</para>
<orderedlist>
- <listitem>Sink pad format. The user configures the sink pad
+ <listitem><para>Sink pad format. The user configures the sink pad
format. This format defines the parameters of the image the
- entity receives through the pad for further processing.</listitem>
+ entity receives through the pad for further processing.</para></listitem>
- <listitem>Sink pad actual crop selection. The sink pad crop
- defines the crop performed to the sink pad format.</listitem>
+ <listitem><para>Sink pad actual crop selection. The sink pad crop
+ defines the crop performed to the sink pad format.</para></listitem>
- <listitem>Sink pad actual compose selection. The size of the
+ <listitem><para>Sink pad actual compose selection. The size of the
sink pad compose rectangle defines the scaling ratio compared
to the size of the sink pad crop rectangle. The location of
the compose rectangle specifies the location of the actual
sink compose rectangle in the sink compose bounds
- rectangle.</listitem>
+ rectangle.</para></listitem>
- <listitem>Source pad actual crop selection. Crop on the source
+ <listitem><para>Source pad actual crop selection. Crop on the source
pad defines crop performed to the image in the sink compose
- bounds rectangle.</listitem>
+ bounds rectangle.</para></listitem>
- <listitem>Source pad format. The source pad format defines the
+ <listitem><para>Source pad format. The source pad format defines the
output pixel format of the subdev, as well as the other
parameters with the exception of the image width and height.
Width and height are defined by the size of the source pad
- actual crop selection.</listitem>
+ actual crop selection.</para></listitem>
</orderedlist>
<para>Accessing any of the above rectangles not supported by the
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
index 8eace3e2e7d4..2d3f0b1aefe0 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
@@ -22,8 +22,7 @@
with 10 bits per colour compressed to 8 bits each, using DPCM
compression. DPCM, differential pulse-code modulation, is lossy.
Each colour component consumes 8 bits of memory. In other respects
- this format is similar to <xref
- linkend="pixfmt-srggb10">.</xref></para>
+ this format is similar to <xref linkend="pixfmt-srggb10" />.</para>
</refsect1>
</refentry>
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
index e7ed5077834d..4c238ce068b0 100644
--- a/Documentation/DocBook/media/v4l/selection-api.xml
+++ b/Documentation/DocBook/media/v4l/selection-api.xml
@@ -40,6 +40,7 @@ cropping and composing rectangles have the same size.</para>
<section>
<title>Selection targets</title>
+ <para>
<figure id="sel-targets-capture">
<title>Cropping and composing targets</title>
<mediaobject>
@@ -52,12 +53,12 @@ cropping and composing rectangles have the same size.</para>
</textobject>
</mediaobject>
</figure>
+ </para>
+ <para>See <xref linkend="v4l2-selection-targets" /> for more
+ information.</para>
</section>
- See <xref linkend="v4l2-selection-targets" /> for more
- information.
-
<section>
<title>Configuration</title>
@@ -216,18 +217,17 @@ composing and cropping operations by setting the appropriate targets. The V4L2
API lacks any support for composing to and cropping from an image inside a
memory buffer. The application could configure a capture device to fill only a
part of an image by abusing V4L2 API. Cropping a smaller image from a larger
-one is achieved by setting the field <structfield>
-&v4l2-pix-format;::bytesperline </structfield>. Introducing an image offsets
-could be done by modifying field <structfield> &v4l2-buffer;::m:userptr
-</structfield> before calling <constant> VIDIOC_QBUF </constant>. Those
+one is achieved by setting the field
+&v4l2-pix-format;<structfield>::bytesperline</structfield>. Introducing an image offsets
+could be done by modifying field &v4l2-buffer;<structfield>::m_userptr</structfield>
+before calling <constant> VIDIOC_QBUF </constant>. Those
operations should be avoided because they are not portable (endianness), and do
not work for macroblock and Bayer formats and mmap buffers. The selection API
deals with configuration of buffer cropping/composing in a clear, intuitive and
portable way. Next, with the selection API the concepts of the padded target
-and constraints flags are introduced. Finally, <structname> &v4l2-crop;
-</structname> and <structname> &v4l2-cropcap; </structname> have no reserved
-fields. Therefore there is no way to extend their functionality. The new
-<structname> &v4l2-selection; </structname> provides a lot of place for future
+and constraints flags are introduced. Finally, &v4l2-crop; and &v4l2-cropcap;
+have no reserved fields. Therefore there is no way to extend their functionality.
+The new &v4l2-selection; provides a lot of place for future
extensions. Driver developers are encouraged to implement only selection API.
The former cropping API would be simulated using the new one. </para>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index eee6908c749f..0292ed106887 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -145,9 +145,12 @@ applications. -->
<authorinitials>hv</authorinitials>
<revremark>Added VIDIOC_ENUM_FREQ_BANDS.
</revremark>
+ </revision>
+
+ <revision>
<revnumber>3.5</revnumber>
<date>2012-05-07</date>
- <authorinitials>sa, sn</authorinitials>
+ <authorinitials>sa, sn, hv</authorinitials>
<revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
selections API. Improved the description of V4L2_CID_COLORFX
control, added V4L2_CID_COLORFX_CBCR control.
@@ -158,11 +161,8 @@ applications. -->
V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
and V4L2_CID_AUTO_FOCUS_RANGE.
- </revremark>
- <date>2012-05-01</date>
- <authorinitials>hv</authorinitials>
- <revremark>Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
- VIDIOC_DV_TIMINGS_CAP.
+ Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
+ VIDIOC_DV_TIMINGS_CAP.
</revremark>
</revision>
@@ -472,7 +472,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.5</subtitle>
+ <subtitle>Revision 3.6</subtitle>
<chapter id="common">
&sub-common;
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
index f76d8a6d9b92..b11ec75e21a1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
@@ -152,12 +152,10 @@ satisfactory parameters have been negotiated. If constraints flags have to be
violated at then ERANGE is returned. The error indicates that <emphasis> there
exist no rectangle </emphasis> that satisfies the constraints.</para>
- </refsect1>
-
<para>Selection targets and flags are documented in <xref
linkend="v4l2-selections-common"/>.</para>
- <section>
+ <para>
<figure id="sel-const-adjust">
<title>Size adjustments with constraint flags.</title>
<mediaobject>
@@ -170,9 +168,9 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
</textobject>
</mediaobject>
</figure>
- </section>
+ </para>
- <refsect1>
+ <para>
<table pgwide="1" frame="none" id="v4l2-selection">
<title>struct <structname>v4l2_selection</structname></title>
<tgroup cols="3">
@@ -208,6 +206,7 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
</tbody>
</tgroup>
</table>
+ </para>
</refsect1>
<refsect1>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index 77ff5be0809d..6a821a65a5ae 100644
--- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
@@ -155,6 +155,8 @@ or no buffers have been allocated yet, or the
<structfield>userptr</structfield> or
<structfield>length</structfield> are invalid.</para>
</listitem>
+ </varlistentry>
+ <varlistentry>
<term><errorcode>EIO</errorcode></term>
<listitem>
<para><constant>VIDIOC_DQBUF</constant> failed due to an
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index f33cc814a01d..1ba9e999af3f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -69,23 +69,22 @@
more information on how each selection target affects the image
processing pipeline inside the subdevice.</para>
- <section>
+ <refsect2>
<title>Types of selection targets</title>
<para>There are two types of selection targets: actual and bounds. The
actual targets are the targets which configure the hardware. The BOUNDS
target will return a rectangle that contain all possible actual
rectangles.</para>
- </section>
+ </refsect2>
- <section>
+ <refsect2>
<title>Discovering supported features</title>
<para>To discover which targets are supported, the user can
perform <constant>VIDIOC_SUBDEV_G_SELECTION</constant> on them.
Any unsupported target will return
<constant>EINVAL</constant>.</para>
- </section>
<para>Selection targets and flags are documented in <xref
linkend="v4l2-selections-common"/>.</para>
@@ -132,6 +131,7 @@
</tbody>
</tgroup>
</table>
+ </refsect2>
</refsect1>
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 4e8e8985cc17..f2413acfe241 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -29,7 +29,7 @@
<title>LINUX MEDIA INFRASTRUCTURE API</title>
<copyright>
- <year>2009-2011</year>
+ <year>2009-2012</year>
<holder>LinuxTV Developers</holder>
</copyright>
@@ -53,7 +53,7 @@ Foundation. A copy of the license is included in the chapter entitled
video and radio straming devices, including video cameras,
analog and digital TV receiver cards, AM/FM receiver cards,
streaming capture devices.</para>
- <para>It is divided into three parts.</para>
+ <para>It is divided into four parts.</para>
<para>The first part covers radio, capture,
cameras and analog TV devices.</para>
<para>The second part covers the
@@ -62,7 +62,8 @@ Foundation. A copy of the license is included in the chapter entitled
in fact it covers several different video standards including
DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
- <para>The third part covers Remote Controller API</para>
+ <para>The third part covers the Remote Controller API.</para>
+ <para>The fourth part covers the Media Controller API.</para>
<para>For additional information and for the latest development code,
see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -87,7 +88,7 @@ Foundation. A copy of the license is included in the chapter entitled
</author>
</authorgroup>
<copyright>
- <year>2009-2011</year>
+ <year>2009-2012</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index c4d963a67d6f..8eb92264ee04 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -30,7 +30,7 @@ with the device via the bus. The connection between the DVB-API-functionality
is done via callbacks, assigned in a static device-description (struct
dvb_usb_device) each device-driver has to have.
-For an example have a look in drivers/media/dvb/dvb-usb/vp7045*.
+For an example have a look in drivers/media/usb/dvb-usb/vp7045*.
Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the
ttusb; flexcop-usb already benefits from the generic flexcop-device) to use
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index afaff312bf41..a52924ef1285 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,15 @@ be removed from this file. The suggested deprecation period is 3 releases.
---------------------------
+What: support for i.mx25 in mx2_camera.c
+When: v3.8
+Why: it's been broken for a year. Furthermore, i.MX25 video capture
+ HW doesn't have much in common with i.MX27. A separate driver
+ will be needed for it.
+Who: Javier Martin<javier.martin@vista-silicon.com>
+
+---------------------------
+
What: ddebug_query="query" boot cmdline param
When: v3.8
Why: obsoleted by dyndbg="query" and module.dyndbg="query"
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 849b771c5e03..2152b0e7237d 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -178,7 +178,6 @@ Code Seq#(hex) Include File Comments
'V' C0 linux/ivtv.h conflict!
'V' C0 media/davinci/vpfe_capture.h conflict!
'V' C0 media/si4713.h conflict!
-'V' C0-CF drivers/media/video/mxb.h conflict!
'W' 00-1F linux/watchdog.h conflict!
'W' 00-1F linux/wanrouter.h conflict!
'W' 00-3F sound/asound.h conflict!
@@ -204,8 +203,6 @@ Code Seq#(hex) Include File Comments
'c' A0-AF arch/x86/include/asm/msr.h conflict!
'd' 00-FF linux/char/drm/drm/h conflict!
'd' 02-40 pcmcia/ds.h conflict!
-'d' 10-3F drivers/media/video/dabusb.h conflict!
-'d' C0-CF drivers/media/video/saa7191.h conflict!
'd' F0-FF linux/digi1.h
'e' all linux/digi1.h conflict!
'e' 00-1F drivers/net/irda/irtty-sir.h conflict!
@@ -267,9 +264,7 @@ Code Seq#(hex) Include File Comments
'v' 00-1F linux/ext2_fs.h conflict!
'v' 00-1F linux/fs.h conflict!
'v' 00-0F linux/sonypi.h conflict!
-'v' C0-DF media/pwc-ioctl.h conflict!
'v' C0-FF linux/meye.h conflict!
-'v' D0-DF drivers/media/video/cpia2/cpia2dev.h conflict!
'w' all CERN SCI driver
'y' 00-1F packet based user level communications
<mailto:zapman@interlan.net>
diff --git a/MAINTAINERS b/MAINTAINERS
index fdc0119963e7..91b79bae9c96 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2778,8 +2778,8 @@ FC0011 TUNER DRIVER
M: Michael Buesch <m@bues.ch>
L: linux-media@vger.kernel.org
S: Maintained
-F: drivers/media/common/tuners/fc0011.h
-F: drivers/media/common/tuners/fc0011.c
+F: drivers/media/tuners/fc0011.h
+F: drivers/media/tuners/fc0011.c
FANOTIFY
M: Eric Paris <eparis@redhat.com>
@@ -3124,49 +3124,49 @@ M: Frank Zago <frank@zago.net>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/finepix.c
+F: drivers/media/usb/gspca/finepix.c
GSPCA GL860 SUBDRIVER
M: Olivier Lorin <o.lorin@laposte.net>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/gl860/
+F: drivers/media/usb/gspca/gl860/
GSPCA M5602 SUBDRIVER
M: Erik Andren <erik.andren@gmail.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/m5602/
+F: drivers/media/usb/gspca/m5602/
GSPCA PAC207 SONIXB SUBDRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/pac207.c
+F: drivers/media/usb/gspca/pac207.c
GSPCA SN9C20X SUBDRIVER
M: Brian Johnson <brijohn@gmail.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/sn9c20x.c
+F: drivers/media/usb/gspca/sn9c20x.c
GSPCA T613 SUBDRIVER
M: Leandro Costantino <lcostantino@gmail.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/t613.c
+F: drivers/media/usb/gspca/t613.c
GSPCA USB WEBCAM DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
-F: drivers/media/video/gspca/
+F: drivers/media/usb/gspca/
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de>
@@ -5530,7 +5530,7 @@ W: http://www.isely.net/pvrusb2/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
S: Maintained
F: Documentation/video4linux/README.pvrusb2
-F: drivers/media/video/pvrusb2/
+F: drivers/media/usb/pvrusb2/
PWM SUBSYSTEM
M: Thierry Reding <thierry.reding@avionic-design.de>
@@ -5961,7 +5961,7 @@ M: Huang Shijie <shijie8@gmail.com>
M: Kang Yong <kangyong@telegent.com>
M: Zhang Xiaobing <xbzhang@telegent.com>
S: Supported
-F: drivers/media/video/tlg2300
+F: drivers/media/usb/tlg2300
SC1200 WDT DRIVER
M: Zwane Mwaikambo <zwane@arm.linux.org.uk>
@@ -7308,7 +7308,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
W: http://www.linux-projects.org
S: Maintained
F: Documentation/video4linux/sn9c102.txt
-F: drivers/media/video/sn9c102/
+F: drivers/media/usb/sn9c102/
USB SUBSYSTEM
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -7343,7 +7343,7 @@ L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
W: http://www.ideasonboard.org/uvc/
S: Maintained
-F: drivers/media/video/uvc/
+F: drivers/media/usb/uvc/
USB W996[87]CF DRIVER
M: Luca Risolia <luca.risolia@studio.unibo.it>
@@ -7382,7 +7382,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
W: http://royale.zerezo.com/zr364xx/
S: Maintained
F: Documentation/video4linux/zr364xx.txt
-F: drivers/media/video/zr364xx.c
+F: drivers/media/usb/zr364xx.c
USER-MODE LINUX (UML)
M: Jeff Dike <jdike@addtoit.com>
diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c
index f69ca4680049..3b6b640eed24 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/arch/arm/mach-imx/clk-imx27.c
@@ -239,8 +239,8 @@ int __init mx27_clocks_init(unsigned long fref)
clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0");
clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1");
clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0");
- clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu");
- clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu");
+ clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0");
+ clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0");
clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma");
clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma");
clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0");
diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h
index 436c5720fe6a..04822932cdd1 100644
--- a/arch/arm/mach-imx/devices-imx27.h
+++ b/arch/arm/mach-imx/devices-imx27.h
@@ -17,6 +17,10 @@ extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data;
#define imx27_add_fsl_usb2_udc(pdata) \
imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata)
+extern const struct imx_imx27_coda_data imx27_coda_data;
+#define imx27_add_coda() \
+ imx_add_imx27_coda(&imx27_coda_data)
+
extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data;
#define imx27_add_imx2_wdt() \
imx_add_imx2_wdt(&imx27_imx2_wdt_data)
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index f264ddddd47c..821d6aac411c 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -32,13 +32,13 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/leds.h>
-#include <linux/memblock.h>
#include <media/soc_camera.h>
#include <sound/tlv320aic32x4.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/system_info.h>
+#include <asm/memblock.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx27.h>
@@ -233,10 +233,8 @@ static void __init visstrim_camera_init(void)
static void __init visstrim_reserve(void)
{
/* reserve 4 MiB for mx2-camera */
- mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE,
+ mx2_camera_base = arm_memblock_steal(3 * MX2_CAMERA_BUF_SIZE,
MX2_CAMERA_BUF_SIZE);
- memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
- memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
}
/* GPIOs used as events for applications */
@@ -405,6 +403,47 @@ static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
.flags = IMX_SSI_DMA | IMX_SSI_SYN,
};
+/* coda */
+
+static void __init visstrim_coda_init(void)
+{
+ struct platform_device *pdev;
+ int dma;
+
+ pdev = imx27_add_coda();
+ dma = dma_declare_coherent_memory(&pdev->dev,
+ mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+ mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+ MX2_CAMERA_BUF_SIZE,
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+ if (!(dma & DMA_MEMORY_MAP))
+ return;
+}
+
+/* DMA deinterlace */
+static struct platform_device visstrim_deinterlace = {
+ .name = "m2m-deinterlace",
+ .id = 0,
+};
+
+static void __init visstrim_deinterlace_init(void)
+{
+ int ret = -ENOMEM;
+ struct platform_device *pdev = &visstrim_deinterlace;
+ int dma;
+
+ ret = platform_device_register(pdev);
+
+ dma = dma_declare_coherent_memory(&pdev->dev,
+ mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+ mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+ MX2_CAMERA_BUF_SIZE,
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+ if (!(dma & DMA_MEMORY_MAP))
+ return;
+}
+
+
static void __init visstrim_m10_revision(void)
{
int exp_version = 0;
@@ -467,7 +506,9 @@ static void __init visstrim_m10_board_init(void)
platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
&iclink_tvp5150, sizeof(iclink_tvp5150));
gpio_led_register_device(0, &visstrim_m10_led_data);
+ visstrim_deinterlace_init();
visstrim_camera_init();
+ visstrim_coda_init();
}
static void __init visstrim_m10_timer_init(void)
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index df2534de3361..ca07264bd3ae 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -34,6 +34,7 @@
#include <plat/gpmc.h>
#include <plat/onenand.h>
#include <plat/gpmc-smc91x.h>
+#include <plat/omap-pm.h>
#include <mach/board-rx51.h>
@@ -46,6 +47,10 @@
#include <../drivers/staging/iio/light/tsl2563.h>
#include <linux/lis3lv02d.h>
+#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
+#include <media/ir-rx51.h>
+#endif
+
#include "mux.h"
#include "hsmmc.h"
#include "common-board-devices.h"
@@ -1220,6 +1225,30 @@ static void __init rx51_init_tsc2005(void)
gpio_to_irq(RX51_TSC2005_IRQ_GPIO);
}
+#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
+static struct lirc_rx51_platform_data rx51_lirc_data = {
+ .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
+ .pwm_timer = 9, /* Use GPT 9 for CIR */
+};
+
+static struct platform_device rx51_lirc_device = {
+ .name = "lirc_rx51",
+ .id = -1,
+ .dev = {
+ .platform_data = &rx51_lirc_data,
+ },
+};
+
+static void __init rx51_init_lirc(void)
+{
+ platform_device_register(&rx51_lirc_device);
+}
+#else
+static void __init rx51_init_lirc(void)
+{
+}
+#endif
+
void __init rx51_peripherals_init(void)
{
rx51_i2c_init();
@@ -1230,6 +1259,7 @@ void __init rx51_peripherals_init(void)
rx51_init_wl1251();
rx51_init_tsc2005();
rx51_init_si4713();
+ rx51_init_lirc();
spi_register_board_info(rx51_peripherals_spi_board_info,
ARRAY_SIZE(rx51_peripherals_spi_board_info));
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index cb3e3eef55c0..6b46cee2f9cd 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -15,7 +15,11 @@ config IMX_HAVE_PLATFORM_GPIO_KEYS
config IMX_HAVE_PLATFORM_IMX21_HCD
bool
-
+
+config IMX_HAVE_PLATFORM_IMX27_CODA
+ bool
+ default y if SOC_IMX27
+
config IMX_HAVE_PLATFORM_IMX2_WDT
bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index c11ac8472beb..76f3195475d0 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC) += platform-fsl-usb2-udc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o
obj-y += platform-gpio-mxc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX21_HCD) += platform-imx21-hcd.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX27_CODA) += platform-imx27-coda.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX2_WDT) += platform-imx2-wdt.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMXDI_RTC) += platform-imxdi_rtc.o
obj-y += platform-imx-dma.o
diff --git a/arch/arm/plat-mxc/devices/platform-imx27-coda.c b/arch/arm/plat-mxc/devices/platform-imx27-coda.c
new file mode 100644
index 000000000000..8b12aacdf396
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-imx27-coda.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Vista Silicon
+ * 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 version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx27_coda_data imx27_coda_data __initconst = {
+ .iobase = MX27_VPU_BASE_ADDR,
+ .iosize = SZ_512,
+ .irq = MX27_INT_VPU,
+};
+#endif
+
+struct platform_device *__init imx_add_imx27_coda(
+ const struct imx_imx27_coda_data *data)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + data->iosize - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device_dmamask("coda-imx27", 0, res, 2, NULL,
+ 0, DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index a7f5bb1084d7..762780cad1bd 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -83,6 +83,14 @@ struct platform_device *__init imx_add_imx21_hcd(
const struct imx_imx21_hcd_data *data,
const struct mx21_usbh_platform_data *pdata);
+struct imx_imx27_coda_data {
+ resource_size_t iobase;
+ resource_size_t iosize;
+ resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx27_coda(
+ const struct imx_imx27_coda_data *data);
+
struct imx_imx2_wdt_data {
int id;
resource_size_t iobase;
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index e4cc7eb69bb2..92d555d5c25a 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -50,7 +50,7 @@
#include <linux/slab.h>
/* Steal the hardware definitions from the bttv driver. */
-#include "../media/video/bt8xx/bt848.h"
+#include "../media/pci/bt8xx/bt848.h"
#define BT8XXGPIO_NR_GPIOS 24 /* We have 24 GPIO pins */
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index d941581ab921..dd13e3a4c272 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -99,11 +99,6 @@ config VIDEO_DEV
depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
default y
-config VIDEO_V4L2_COMMON
- tristate
- depends on (I2C || I2C=n) && VIDEO_DEV
- default (I2C || I2C=n) && VIDEO_DEV
-
config VIDEO_V4L2_SUBDEV_API
bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
@@ -113,6 +108,8 @@ config VIDEO_V4L2_SUBDEV_API
This API is mostly used by camera interfaces in embedded platforms.
+source "drivers/media/v4l2-core/Kconfig"
+
#
# DVB Core
# Only enables if one of DTV is selected
@@ -138,28 +135,54 @@ config DVB_NET
You may want to disable the network support on embedded devices. If
unsure say Y.
+source "drivers/media/dvb-core/Kconfig"
+
comment "Media drivers"
-source "drivers/media/common/Kconfig"
source "drivers/media/rc/Kconfig"
#
-# Tuner drivers for DVB and V4L
+# V4L platform/mem2mem drivers
#
-source "drivers/media/common/tuners/Kconfig"
+source "drivers/media/usb/Kconfig"
+source "drivers/media/pci/Kconfig"
+source "drivers/media/platform/Kconfig"
+source "drivers/media/mmc/Kconfig"
+source "drivers/media/parport/Kconfig"
+source "drivers/media/radio/Kconfig"
+
+comment "Supported FireWire (IEEE 1394) Adapters"
+ depends on DVB_CORE && FIREWIRE
+source "drivers/media/firewire/Kconfig"
+
+# Common driver options
+source "drivers/media/common/Kconfig"
#
-# Video/Radio/Hybrid adapters
+# Ancillary drivers (tuners, i2c, frontends)
#
-source "drivers/media/video/Kconfig"
+config MEDIA_SUBDRV_AUTOSELECT
+ bool "Autoselect analog and hybrid tuner modules to build"
+ depends on MEDIA_TUNER
+ default y
+ help
+ By default, a TV driver auto-selects all possible tuners
+ thar could be used by the driver.
-source "drivers/media/radio/Kconfig"
+ This is generally the right thing to do, except when there
+ are strict constraints with regards to the kernel size.
-#
-# DVB adapters
-#
+ Use this option with care, as deselecting tuner drivers which
+ are in fact necessary will result in TV devices which cannot
+ be tuned due to lack of the tuning driver.
+
+ If unsure say Y.
+
+comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
-source "drivers/media/dvb/Kconfig"
+source "drivers/media/i2c/Kconfig"
+source "drivers/media/tuners/Kconfig"
+source "drivers/media/dvb-frontends/Kconfig"
endif # MEDIA_SUPPORT
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 64755c99ded2..b0b0193cd69d 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -8,7 +8,8 @@ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
obj-$(CONFIG_MEDIA_SUPPORT) += media.o
endif
-obj-y += common/ rc/ video/
+obj-y += tuners/ common/ rc/ platform/
+obj-y += i2c/ pci/ usb/ mmc/ firewire/ parport/
-obj-$(CONFIG_VIDEO_DEV) += radio/
-obj-$(CONFIG_DVB_CORE) += dvb/
+obj-$(CONFIG_VIDEO_DEV) += radio/ v4l2-core/
+obj-$(CONFIG_DVB_CORE) += dvb-core/ dvb-frontends/
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 769c6f8142d2..121b0110af3c 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,9 +1,3 @@
-config VIDEO_SAA7146
- tristate
- depends on I2C && PCI
-
-config VIDEO_SAA7146_VV
- tristate
- depends on VIDEO_V4L2
- select VIDEOBUF_DMA_SG
- select VIDEO_SAA7146
+source "drivers/media/common/b2c2/Kconfig"
+source "drivers/media/common/saa7146/Kconfig"
+source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index e3ec9639321b..b8e2e3a33a31 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,6 +1 @@
-saa7146-objs := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
-
-obj-y += tuners/
-obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
-obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
+obj-y += b2c2/ saa7146/ siano/
diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig
new file mode 100644
index 000000000000..1df9e578daa5
--- /dev/null
+++ b/drivers/media/common/b2c2/Kconfig
@@ -0,0 +1,28 @@
+config DVB_B2C2_FLEXCOP
+ tristate
+ depends on DVB_CORE && I2C
+ depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB
+ default y
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the digital TV receiver chip made by B2C2 Inc. included in
+ Technisats PCI cards and USB boxes.
+
+ Say Y if you own such a device and want to use it.
+
+# Selected via the PCI or USB flexcop drivers
+config DVB_B2C2_FLEXCOP_DEBUG
+ bool
diff --git a/drivers/media/common/b2c2/Makefile b/drivers/media/common/b2c2/Makefile
new file mode 100644
index 000000000000..24993a5b38ba
--- /dev/null
+++ b/drivers/media/common/b2c2/Makefile
@@ -0,0 +1,8 @@
+b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o
+b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o
+b2c2-flexcop-objs += flexcop-hw-filter.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h
index 437912e49824..437912e49824 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/common/b2c2/flexcop-common.h
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/common/b2c2/flexcop-eeprom.c
index a25373a9bd84..a25373a9bd84 100644
--- a/drivers/media/dvb/b2c2/flexcop-eeprom.c
+++ b/drivers/media/common/b2c2/flexcop-eeprom.c
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
index 850a6c606750..850a6c606750 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c
index 77e45475f4c7..77e45475f4c7 100644
--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+++ b/drivers/media/common/b2c2/flexcop-hw-filter.c
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c
index 965d5eb33752..965d5eb33752 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/common/b2c2/flexcop-i2c.c
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c
index f06f3a9070f5..f06f3a9070f5 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/common/b2c2/flexcop-misc.c
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/common/b2c2/flexcop-reg.h
index dc4528dcbb98..dc4528dcbb98 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/common/b2c2/flexcop-reg.h
diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c
index f2199e43e803..f2199e43e803 100644
--- a/drivers/media/dvb/b2c2/flexcop-sram.c
+++ b/drivers/media/common/b2c2/flexcop-sram.c
diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c
new file mode 100644
index 000000000000..412c5daf2b48
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop.c
@@ -0,0 +1,325 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop.c - main module part
+ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
+ * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
+ *
+ * Acknowledgements:
+ * John Jurrius from BBTI, Inc. for extensive support
+ * with code examples and data books
+ * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
+ *
+ * Contributions to the skystar2-driver have been done by
+ * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
+ * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
+ * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
+ * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
+ * filtering)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ */
+
+#include "flexcop.h"
+
+#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
+
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define DEBSTATUS ""
+#else
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+int b2c2_flexcop_debug;
+EXPORT_SYMBOL_GPL(b2c2_flexcop_debug);
+module_param_named(debug, b2c2_flexcop_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "set debug level (1=info,2=tuner,4=i2c,8=ts,"
+ "16=sram,32=reg (|-able))."
+ DEBSTATUS);
+#undef DEBSTATUS
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* global zero for ibi values */
+flexcop_ibi_value ibi_zero;
+
+static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+ return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
+}
+
+static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+ return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
+}
+
+static int flexcop_dvb_init(struct flexcop_device *fc)
+{
+ int ret = dvb_register_adapter(&fc->dvb_adapter,
+ "FlexCop Digital TV device", fc->owner,
+ fc->dev, adapter_nr);
+ if (ret < 0) {
+ err("error registering DVB adapter");
+ return ret;
+ }
+ fc->dvb_adapter.priv = fc;
+
+ fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
+ | DMX_MEMORY_BASED_FILTERING);
+ fc->demux.priv = fc;
+ fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
+ fc->demux.start_feed = flexcop_dvb_start_feed;
+ fc->demux.stop_feed = flexcop_dvb_stop_feed;
+ fc->demux.write_to_decoder = NULL;
+
+ ret = dvb_dmx_init(&fc->demux);
+ if (ret < 0) {
+ err("dvb_dmx failed: error %d", ret);
+ goto err_dmx;
+ }
+
+ fc->hw_frontend.source = DMX_FRONTEND_0;
+
+ fc->dmxdev.filternum = fc->demux.feednum;
+ fc->dmxdev.demux = &fc->demux.dmx;
+ fc->dmxdev.capabilities = 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;
+ }
+
+ 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;
+ 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;
+ }
+
+ 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;
+ }
+
+ 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:
+ fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
+err_dmx_add_hw_frontend:
+ dvb_dmxdev_release(&fc->dmxdev);
+err_dmx_dev:
+ dvb_dmx_release(&fc->demux);
+err_dmx:
+ dvb_unregister_adapter(&fc->dvb_adapter);
+ return ret;
+}
+
+static void flexcop_dvb_exit(struct flexcop_device *fc)
+{
+ if (fc->init_state & FC_STATE_DVB_INIT) {
+ dvb_net_release(&fc->dvbnet);
+
+ fc->demux.dmx.close(&fc->demux.dmx);
+ fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+ &fc->mem_frontend);
+ fc->demux.dmx.remove_frontend(&fc->demux.dmx,
+ &fc->hw_frontend);
+ dvb_dmxdev_release(&fc->dmxdev);
+ dvb_dmx_release(&fc->demux);
+ dvb_unregister_adapter(&fc->dvb_adapter);
+ deb_info("deinitialized dvb stuff\n");
+ }
+ fc->init_state &= ~FC_STATE_DVB_INIT;
+}
+
+/* these methods are necessary to achieve the long-term-goal of hiding the
+ * struct flexcop_device from the bus-parts */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
+{
+ dvb_dmx_swfilter(&fc->demux, buf, len);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_data);
+
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
+{
+ dvb_dmx_swfilter_packets(&fc->demux, buf, no);
+}
+EXPORT_SYMBOL(flexcop_pass_dmx_packets);
+
+static void flexcop_reset(struct flexcop_device *fc)
+{
+ flexcop_ibi_value v210, v204;
+
+ /* reset the flexcop itself */
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.raw = 0;
+ v210.sw_reset_210.reset_block_000 = 1;
+ v210.sw_reset_210.reset_block_100 = 1;
+ v210.sw_reset_210.reset_block_200 = 1;
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.reset_block_400 = 1;
+ v210.sw_reset_210.reset_block_500 = 1;
+ v210.sw_reset_210.reset_block_600 = 1;
+ v210.sw_reset_210.reset_block_700 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+ v210.sw_reset_210.Special_controls = 0xc259;
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
+
+ /* reset the periphical devices */
+
+ v204 = fc->read_ibi_reg(fc,misc_204);
+ v204.misc_204.Per_reset_sig = 0;
+ fc->write_ibi_reg(fc,misc_204,v204);
+ msleep(1);
+ v204.misc_204.Per_reset_sig = 1;
+ fc->write_ibi_reg(fc,misc_204,v204);
+}
+
+void flexcop_reset_block_300(struct flexcop_device *fc)
+{
+ flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
+ v210 = fc->read_ibi_reg(fc, sw_reset_210);
+
+ deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+ fc->write_ibi_reg(fc,ctrl_208,v208_save);
+}
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
+{
+ void *bus;
+ struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
+ GFP_KERNEL);
+ if (!fc) {
+ err("no memory");
+ return NULL;
+ }
+
+ bus = kzalloc(bus_specific_len, GFP_KERNEL);
+ if (!bus) {
+ err("no memory");
+ kfree(fc);
+ return NULL;
+ }
+
+ fc->bus_specific = bus;
+
+ return fc;
+}
+EXPORT_SYMBOL(flexcop_device_kmalloc);
+
+void flexcop_device_kfree(struct flexcop_device *fc)
+{
+ kfree(fc->bus_specific);
+ kfree(fc);
+}
+EXPORT_SYMBOL(flexcop_device_kfree);
+
+int flexcop_device_initialize(struct flexcop_device *fc)
+{
+ int ret;
+ ibi_zero.raw = 0;
+
+ flexcop_reset(fc);
+ flexcop_determine_revision(fc);
+ flexcop_sram_init(fc);
+ flexcop_hw_filter_init(fc);
+ flexcop_smc_ctrl(fc, 0);
+
+ ret = flexcop_dvb_init(fc);
+ if (ret)
+ goto error;
+
+ /* i2c has to be done before doing EEProm stuff -
+ * because the EEProm is accessed via i2c */
+ ret = flexcop_i2c_init(fc);
+ if (ret)
+ goto error;
+
+ /* do the MAC address reading after initializing the dvb_adapter */
+ if (fc->get_mac_addr(fc, 0) == 0) {
+ u8 *b = fc->dvb_adapter.proposed_mac;
+ info("MAC address = %pM", b);
+ flexcop_set_mac_filter(fc,b);
+ flexcop_mac_filter_ctrl(fc,1);
+ } else
+ warn("reading of MAC address failed.\n");
+
+ ret = flexcop_frontend_init(fc);
+ if (ret)
+ goto error;
+
+ flexcop_device_name(fc,"initialization of","complete");
+ return 0;
+
+error:
+ flexcop_device_exit(fc);
+ return ret;
+}
+EXPORT_SYMBOL(flexcop_device_initialize);
+
+void flexcop_device_exit(struct flexcop_device *fc)
+{
+ flexcop_frontend_exit(fc);
+ flexcop_i2c_exit(fc);
+ flexcop_dvb_exit(fc);
+}
+EXPORT_SYMBOL(flexcop_device_exit);
+
+static int flexcop_module_init(void)
+{
+ info(DRIVER_NAME " loaded successfully");
+ return 0;
+}
+
+static void flexcop_module_cleanup(void)
+{
+ info(DRIVER_NAME " unloaded successfully");
+}
+
+module_init(flexcop_module_init);
+module_exit(flexcop_module_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h
index 897b10c85ad9..897b10c85ad9 100644
--- a/drivers/media/dvb/b2c2/flexcop.h
+++ b/drivers/media/common/b2c2/flexcop.h
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
index 8f64bdbd72bb..8f64bdbd72bb 100644
--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
index c75830d7d942..c75830d7d942 100644
--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig
new file mode 100644
index 000000000000..769c6f8142d2
--- /dev/null
+++ b/drivers/media/common/saa7146/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_SAA7146
+ tristate
+ depends on I2C && PCI
+
+config VIDEO_SAA7146_VV
+ tristate
+ depends on VIDEO_V4L2
+ select VIDEOBUF_DMA_SG
+ select VIDEO_SAA7146
diff --git a/drivers/media/common/saa7146/Makefile b/drivers/media/common/saa7146/Makefile
new file mode 100644
index 000000000000..3219b00a8771
--- /dev/null
+++ b/drivers/media/common/saa7146/Makefile
@@ -0,0 +1,5 @@
+saa7146-objs := saa7146_i2c.o saa7146_core.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+
+obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
+obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
new file mode 100644
index 000000000000..bb6ee5191eb1
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -0,0 +1,592 @@
+/*
+ saa7146.o - driver for generic saa7146-based hardware
+
+ Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+
+ 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.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146.h>
+#include <linux/module.h>
+
+static int saa7146_num;
+
+unsigned int saa7146_debug;
+
+module_param(saa7146_debug, uint, 0644);
+MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
+
+#if 0
+static void dump_registers(struct saa7146_dev* dev)
+{
+ int i = 0;
+
+ pr_info(" @ %li jiffies:\n", jiffies);
+ for (i = 0; i <= 0x148; i += 4)
+ pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
+}
+#endif
+
+/****************************************************************************
+ * gpio and debi helper functions
+ ****************************************************************************/
+
+void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
+{
+ u32 value = 0;
+
+ BUG_ON(port > 3);
+
+ value = saa7146_read(dev, GPIO_CTRL);
+ value &= ~(0xff << (8*port));
+ value |= (data << (8*port));
+ saa7146_write(dev, GPIO_CTRL, value);
+}
+
+/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
+static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
+ unsigned long us1, unsigned long us2)
+{
+ unsigned long timeout;
+ int err;
+
+ /* wait for registers to be programmed */
+ timeout = jiffies + usecs_to_jiffies(us1);
+ while (1) {
+ err = time_after(jiffies, timeout);
+ if (saa7146_read(dev, MC2) & 2)
+ break;
+ if (err) {
+ pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+ dev->name, __func__);
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ /* wait for transfer to complete */
+ timeout = jiffies + usecs_to_jiffies(us2);
+ while (1) {
+ err = time_after(jiffies, timeout);
+ if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+ break;
+ saa7146_read(dev, MC2);
+ if (err) {
+ DEB_S("%s: %s timed out while waiting for transfer completion\n",
+ dev->name, __func__);
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
+ unsigned long us1, unsigned long us2)
+{
+ unsigned long loops;
+
+ /* wait for registers to be programmed */
+ loops = us1;
+ while (1) {
+ if (saa7146_read(dev, MC2) & 2)
+ break;
+ if (!loops--) {
+ pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+ dev->name, __func__);
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ /* wait for transfer to complete */
+ loops = us2 / 5;
+ while (1) {
+ if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+ break;
+ saa7146_read(dev, MC2);
+ if (!loops--) {
+ DEB_S("%s: %s timed out while waiting for transfer completion\n",
+ dev->name, __func__);
+ return -ETIMEDOUT;
+ }
+ udelay(5);
+ }
+
+ return 0;
+}
+
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+{
+ if (nobusyloop)
+ return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
+ else
+ return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
+}
+
+/****************************************************************************
+ * general helper functions
+ ****************************************************************************/
+
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
+ make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
+ may be triggered on highmem machines */
+static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
+{
+ struct scatterlist *sglist;
+ struct page *pg;
+ int i;
+
+ sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ sg_init_table(sglist, nr_pages);
+ for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+ pg = vmalloc_to_page(virt);
+ if (NULL == pg)
+ goto err;
+ BUG_ON(PageHighMem(pg));
+ sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return sglist;
+
+ err:
+ kfree(sglist);
+ return NULL;
+}
+
+/********************************************************************************/
+/* common page table functions */
+
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+{
+ int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
+ void *mem = vmalloc_32(length);
+ int slen = 0;
+
+ if (NULL == mem)
+ goto err_null;
+
+ if (!(pt->slist = vmalloc_to_sg(mem, pages)))
+ goto err_free_mem;
+
+ if (saa7146_pgtable_alloc(pci, pt))
+ goto err_free_slist;
+
+ pt->nents = pages;
+ slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
+ if (0 == slen)
+ goto err_free_pgtable;
+
+ if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
+ goto err_unmap_sg;
+
+ return mem;
+
+err_unmap_sg:
+ pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
+err_free_pgtable:
+ saa7146_pgtable_free(pci, pt);
+err_free_slist:
+ kfree(pt->slist);
+ pt->slist = NULL;
+err_free_mem:
+ vfree(mem);
+err_null:
+ return NULL;
+}
+
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
+{
+ pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
+ saa7146_pgtable_free(pci, pt);
+ kfree(pt->slist);
+ pt->slist = NULL;
+ vfree(mem);
+}
+
+void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
+{
+ if (NULL == pt->cpu)
+ return;
+ pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
+ pt->cpu = NULL;
+}
+
+int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
+{
+ __le32 *cpu;
+ dma_addr_t dma_addr = 0;
+
+ cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
+ if (NULL == cpu) {
+ return -ENOMEM;
+ }
+ pt->size = PAGE_SIZE;
+ pt->cpu = cpu;
+ pt->dma = dma_addr;
+
+ return 0;
+}
+
+int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
+ struct scatterlist *list, int sglen )
+{
+ __le32 *ptr, fill;
+ int nr_pages = 0;
+ int i,p;
+
+ BUG_ON(0 == sglen);
+ BUG_ON(list->offset > PAGE_SIZE);
+
+ /* if we have a user buffer, the first page may not be
+ aligned to a page boundary. */
+ pt->offset = list->offset;
+
+ ptr = pt->cpu;
+ for (i = 0; i < sglen; i++, list++) {
+/*
+ pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
+ i, sg_dma_address(list), sg_dma_len(list),
+ list->offset);
+*/
+ for (p = 0; p * 4096 < list->length; p++, ptr++) {
+ *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
+ nr_pages++;
+ }
+ }
+
+
+ /* safety; fill the page table up with the last valid page */
+ fill = *(ptr-1);
+ for(i=nr_pages;i<1024;i++) {
+ *ptr++ = fill;
+ }
+
+/*
+ ptr = pt->cpu;
+ pr_debug("offset: %d\n", pt->offset);
+ for(i=0;i<5;i++) {
+ pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
+ }
+*/
+ return 0;
+}
+
+/********************************************************************************/
+/* interrupt handler */
+static irqreturn_t interrupt_hw(int irq, void *dev_id)
+{
+ struct saa7146_dev *dev = dev_id;
+ u32 isr;
+ u32 ack_isr;
+
+ /* read out the interrupt status register */
+ ack_isr = isr = saa7146_read(dev, ISR);
+
+ /* is this our interrupt? */
+ if ( 0 == isr ) {
+ /* nope, some other device */
+ return IRQ_NONE;
+ }
+
+ if (dev->ext) {
+ if (dev->ext->irq_mask & isr) {
+ if (dev->ext->irq_func)
+ dev->ext->irq_func(dev, &isr);
+ isr &= ~dev->ext->irq_mask;
+ }
+ }
+ if (0 != (isr & (MASK_27))) {
+ DEB_INT("irq: RPS0 (0x%08x)\n", isr);
+ if (dev->vv_data && dev->vv_callback)
+ dev->vv_callback(dev,isr);
+ isr &= ~MASK_27;
+ }
+ if (0 != (isr & (MASK_28))) {
+ if (dev->vv_data && dev->vv_callback)
+ dev->vv_callback(dev,isr);
+ isr &= ~MASK_28;
+ }
+ if (0 != (isr & (MASK_16|MASK_17))) {
+ SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+ /* only wake up if we expect something */
+ if (0 != dev->i2c_op) {
+ dev->i2c_op = 0;
+ wake_up(&dev->i2c_wq);
+ } else {
+ u32 psr = saa7146_read(dev, PSR);
+ u32 ssr = saa7146_read(dev, SSR);
+ pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+ dev->name, isr, psr, ssr);
+ }
+ isr &= ~(MASK_16|MASK_17);
+ }
+ if( 0 != isr ) {
+ ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
+ isr);
+ ERR("disabling interrupt source(s)!\n");
+ SAA7146_IER_DISABLE(dev,isr);
+ }
+ saa7146_write(dev, ISR, ack_isr);
+ return IRQ_HANDLED;
+}
+
+/*********************************************************************************/
+/* configuration-functions */
+
+static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
+{
+ struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
+ struct saa7146_extension *ext = pci_ext->ext;
+ struct saa7146_dev *dev;
+ int err = -ENOMEM;
+
+ /* clear out mem for sure */
+ dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
+ if (!dev) {
+ ERR("out of memory\n");
+ goto out;
+ }
+
+ DEB_EE("pci:%p\n", pci);
+
+ err = pci_enable_device(pci);
+ if (err < 0) {
+ ERR("pci_enable_device() failed\n");
+ goto err_free;
+ }
+
+ /* enable bus-mastering */
+ pci_set_master(pci);
+
+ dev->pci = pci;
+
+ /* get chip-revision; this is needed to enable bug-fixes */
+ dev->revision = pci->revision;
+
+ /* remap the memory from virtual to physical address */
+
+ err = pci_request_region(pci, 0, "saa7146");
+ if (err < 0)
+ goto err_disable;
+
+ dev->mem = ioremap(pci_resource_start(pci, 0),
+ pci_resource_len(pci, 0));
+ if (!dev->mem) {
+ ERR("ioremap() failed\n");
+ err = -ENODEV;
+ goto err_release;
+ }
+
+ /* we don't do a master reset here anymore, it screws up
+ some boards that don't have an i2c-eeprom for configuration
+ values */
+/*
+ saa7146_write(dev, MC1, MASK_31);
+*/
+
+ /* disable all irqs */
+ saa7146_write(dev, IER, 0);
+
+ /* shut down all dma transfers and rps tasks */
+ saa7146_write(dev, MC1, 0x30ff0000);
+
+ /* clear out any rps-signals pending */
+ saa7146_write(dev, MC2, 0xf8000000);
+
+ /* request an interrupt for the saa7146 */
+ err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
+ dev->name, dev);
+ if (err < 0) {
+ ERR("request_irq() failed\n");
+ goto err_unmap;
+ }
+
+ err = -ENOMEM;
+
+ /* get memory for various stuff */
+ dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_rps0.dma_handle);
+ if (!dev->d_rps0.cpu_addr)
+ goto err_free_irq;
+ memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+ dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_rps1.dma_handle);
+ if (!dev->d_rps1.cpu_addr)
+ goto err_free_rps0;
+ memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+ dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_i2c.dma_handle);
+ if (!dev->d_i2c.cpu_addr)
+ goto err_free_rps1;
+ memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
+
+ /* the rest + print status message */
+
+ /* create a nice device name */
+ sprintf(dev->name, "saa7146 (%d)", saa7146_num);
+
+ pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
+ dev->mem, dev->revision, pci->irq,
+ pci->subsystem_vendor, pci->subsystem_device);
+ dev->ext = ext;
+
+ mutex_init(&dev->v4l2_lock);
+ spin_lock_init(&dev->int_slock);
+ spin_lock_init(&dev->slock);
+
+ mutex_init(&dev->i2c_lock);
+
+ dev->module = THIS_MODULE;
+ init_waitqueue_head(&dev->i2c_wq);
+
+ /* set some sane pci arbitrition values */
+ saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+
+ /* TODO: use the status code of the callback */
+
+ err = -ENODEV;
+
+ if (ext->probe && ext->probe(dev)) {
+ DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
+ goto err_free_i2c;
+ }
+
+ if (ext->attach(dev, pci_ext)) {
+ DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
+ goto err_free_i2c;
+ }
+ /* V4L extensions will set the pci drvdata to the v4l2_device in the
+ attach() above. So for those cards that do not use V4L we have to
+ set it explicitly. */
+ pci_set_drvdata(pci, &dev->v4l2_dev);
+
+ saa7146_num++;
+
+ err = 0;
+out:
+ return err;
+
+err_free_i2c:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
+ dev->d_i2c.dma_handle);
+err_free_rps1:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
+ dev->d_rps1.dma_handle);
+err_free_rps0:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
+ dev->d_rps0.dma_handle);
+err_free_irq:
+ free_irq(pci->irq, (void *)dev);
+err_unmap:
+ iounmap(dev->mem);
+err_release:
+ pci_release_region(pci, 0);
+err_disable:
+ pci_disable_device(pci);
+err_free:
+ kfree(dev);
+ goto out;
+}
+
+static void saa7146_remove_one(struct pci_dev *pdev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
+ struct {
+ void *addr;
+ dma_addr_t dma;
+ } dev_map[] = {
+ { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
+ { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
+ { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
+ { NULL, 0 }
+ }, *p;
+
+ DEB_EE("dev:%p\n", dev);
+
+ dev->ext->detach(dev);
+ /* Zero the PCI drvdata after use. */
+ pci_set_drvdata(pdev, NULL);
+
+ /* shut down all video dma transfers */
+ saa7146_write(dev, MC1, 0x00ff0000);
+
+ /* disable all irqs, release irq-routine */
+ saa7146_write(dev, IER, 0);
+
+ free_irq(pdev->irq, dev);
+
+ for (p = dev_map; p->addr; p++)
+ pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
+
+ iounmap(dev->mem);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ kfree(dev);
+
+ saa7146_num--;
+}
+
+/*********************************************************************************/
+/* extension handling functions */
+
+int saa7146_register_extension(struct saa7146_extension* ext)
+{
+ DEB_EE("ext:%p\n", ext);
+
+ ext->driver.name = ext->name;
+ ext->driver.id_table = ext->pci_tbl;
+ ext->driver.probe = saa7146_init_one;
+ ext->driver.remove = saa7146_remove_one;
+
+ pr_info("register extension '%s'\n", ext->name);
+ return pci_register_driver(&ext->driver);
+}
+
+int saa7146_unregister_extension(struct saa7146_extension* ext)
+{
+ DEB_EE("ext:%p\n", ext);
+ pr_info("unregister extension '%s'\n", ext->name);
+ pci_unregister_driver(&ext->driver);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(saa7146_register_extension);
+EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
+
+/* misc functions used by extension modules */
+EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
+EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
+EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
+EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
+EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
+EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
+
+EXPORT_SYMBOL_GPL(saa7146_setgpio);
+
+EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
+
+EXPORT_SYMBOL_GPL(saa7146_debug);
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
new file mode 100644
index 000000000000..b3890bd49df6
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -0,0 +1,664 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
+
+/****************************************************************************/
+/* resource management functions, shamelessly stolen from saa7134 driver */
+
+int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ if (fh->resources & bit) {
+ DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
+ bit, vv->resources);
+ /* have it already allocated */
+ return 1;
+ }
+
+ /* is it free? */
+ if (vv->resources & bit) {
+ DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
+ vv->resources, bit);
+ /* no, someone else uses it */
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ vv->resources |= bit;
+ DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
+ return 1;
+}
+
+void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ BUG_ON((fh->resources & bits) != bits);
+
+ fh->resources &= ~bits;
+ vv->resources &= ~bits;
+ DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
+}
+
+
+/********************************************************************************/
+/* common dma functions */
+
+void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
+ struct saa7146_buf *buf)
+{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ DEB_EE("dev:%p, buf:%p\n", dev, buf);
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
+ videobuf_dma_free(dma);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+
+/********************************************************************************/
+/* common buffer functions */
+
+int saa7146_buffer_queue(struct saa7146_dev *dev,
+ struct saa7146_dmaqueue *q,
+ struct saa7146_buf *buf)
+{
+ assert_spin_locked(&dev->slock);
+ DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
+
+ BUG_ON(!q);
+
+ if (NULL == q->curr) {
+ q->curr = buf;
+ DEB_D("immediately activating buffer %p\n", buf);
+ buf->activate(dev,buf,NULL);
+ } else {
+ list_add_tail(&buf->vb.queue,&q->queue);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ DEB_D("adding buffer %p to queue. (active buffer present)\n",
+ buf);
+ }
+ return 0;
+}
+
+void saa7146_buffer_finish(struct saa7146_dev *dev,
+ struct saa7146_dmaqueue *q,
+ int state)
+{
+ assert_spin_locked(&dev->slock);
+ DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
+ DEB_EE("q->curr:%p\n", q->curr);
+
+ BUG_ON(!q->curr);
+
+ /* finish current buffer */
+ if (NULL == q->curr) {
+ DEB_D("aiii. no current buffer\n");
+ return;
+ }
+
+ q->curr->vb.state = state;
+ do_gettimeofday(&q->curr->vb.ts);
+ wake_up(&q->curr->vb.done);
+
+ q->curr = NULL;
+}
+
+void saa7146_buffer_next(struct saa7146_dev *dev,
+ struct saa7146_dmaqueue *q, int vbi)
+{
+ struct saa7146_buf *buf,*next = NULL;
+
+ BUG_ON(!q);
+
+ DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
+
+ assert_spin_locked(&dev->slock);
+ if (!list_empty(&q->queue)) {
+ /* activate next one from queue */
+ buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
+ list_del(&buf->vb.queue);
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
+ q->curr = buf;
+ DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
+ buf, q->queue.prev, q->queue.next);
+ buf->activate(dev,buf,next);
+ } else {
+ DEB_INT("no next buffer. stopping.\n");
+ if( 0 != vbi ) {
+ /* turn off video-dma3 */
+ saa7146_write(dev,MC1, MASK_20);
+ } else {
+ /* nothing to do -- just prevent next video-dma1 transfer
+ by lowering the protection address */
+
+ // fixme: fix this for vflip != 0
+
+ saa7146_write(dev, PROT_ADDR1, 0);
+ saa7146_write(dev, MC2, (MASK_02|MASK_18));
+
+ /* write the address of the rps-program */
+ saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
+ /* turn on rps */
+ saa7146_write(dev, MC1, (MASK_12 | MASK_28));
+
+/*
+ printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
+ printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
+ printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
+ printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
+ printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
+ printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
+*/
+ }
+ del_timer(&q->timeout);
+ }
+}
+
+void saa7146_buffer_timeout(unsigned long data)
+{
+ struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
+ struct saa7146_dev *dev = q->dev;
+ unsigned long flags;
+
+ DEB_EE("dev:%p, dmaq:%p\n", dev, q);
+
+ spin_lock_irqsave(&dev->slock,flags);
+ if (q->curr) {
+ DEB_D("timeout on %p\n", q->curr);
+ saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
+ }
+
+ /* we don't restart the transfer here like other drivers do. when
+ a streaming capture is disabled, the timeout function will be
+ called for the current buffer. if we activate the next buffer now,
+ we mess up our capture logic. if a timeout occurs on another buffer,
+ then something is seriously broken before, so no need to buffer the
+ next capture IMHO... */
+/*
+ saa7146_buffer_next(dev,q);
+*/
+ spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+/********************************************************************************/
+/* file operations */
+
+static int fops_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_dev *dev = video_drvdata(file);
+ struct saa7146_fh *fh = NULL;
+ int result = 0;
+
+ DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
+
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+
+ DEB_D("using: %p\n", dev);
+
+ /* check if an extension is registered */
+ if( NULL == dev->ext ) {
+ DEB_S("no extension registered for this device\n");
+ result = -ENODEV;
+ goto out;
+ }
+
+ /* allocate per open data */
+ fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+ if (NULL == fh) {
+ DEB_S("cannot allocate memory for per open data\n");
+ result = -ENOMEM;
+ goto out;
+ }
+
+ v4l2_fh_init(&fh->fh, vdev);
+
+ file->private_data = &fh->fh;
+ fh->dev = dev;
+
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
+ DEB_S("initializing vbi...\n");
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ result = saa7146_vbi_uops.open(dev,file);
+ if (dev->ext_vv_data->vbi_fops.open)
+ dev->ext_vv_data->vbi_fops.open(file);
+ } else {
+ DEB_S("initializing video...\n");
+ result = saa7146_video_uops.open(dev,file);
+ }
+
+ if (0 != result) {
+ goto out;
+ }
+
+ if( 0 == try_module_get(dev->ext->module)) {
+ result = -EINVAL;
+ goto out;
+ }
+
+ result = 0;
+ v4l2_fh_add(&fh->fh);
+out:
+ if (fh && result != 0) {
+ kfree(fh);
+ file->private_data = NULL;
+ }
+ mutex_unlock(vdev->lock);
+ return result;
+}
+
+static int fops_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_fh *fh = file->private_data;
+ struct saa7146_dev *dev = fh->dev;
+
+ DEB_EE("file:%p\n", file);
+
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ saa7146_vbi_uops.release(dev,file);
+ if (dev->ext_vv_data->vbi_fops.release)
+ dev->ext_vv_data->vbi_fops.release(file);
+ } else {
+ saa7146_video_uops.release(dev,file);
+ }
+
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
+ module_put(dev->ext->module);
+ file->private_data = NULL;
+ kfree(fh);
+
+ mutex_unlock(vdev->lock);
+
+ return 0;
+}
+
+static int fops_mmap(struct file *file, struct vm_area_struct * vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_fh *fh = file->private_data;
+ struct videobuf_queue *q;
+ int res;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER: {
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
+ file, vma);
+ q = &fh->video_q;
+ break;
+ }
+ case VFL_TYPE_VBI: {
+ DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
+ file, vma);
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+ return -ENODEV;
+ q = &fh->vbi_q;
+ break;
+ }
+ default:
+ BUG();
+ return 0;
+ }
+
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ res = videobuf_mmap_mapper(q, vma);
+ mutex_unlock(vdev->lock);
+ return res;
+}
+
+static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_fh *fh = file->private_data;
+ struct videobuf_buffer *buf = NULL;
+ struct videobuf_queue *q;
+ unsigned int res = v4l2_ctrl_poll(file, wait);
+
+ DEB_EE("file:%p, poll:%p\n", file, wait);
+
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+ return res | POLLOUT | POLLWRNORM;
+ if( 0 == fh->vbi_q.streaming )
+ return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
+ q = &fh->vbi_q;
+ } else {
+ DEB_D("using video queue\n");
+ q = &fh->video_q;
+ }
+
+ if (!list_empty(&q->stream))
+ buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+
+ if (!buf) {
+ DEB_D("buf == NULL!\n");
+ return res | POLLERR;
+ }
+
+ poll_wait(file, &buf->done, wait);
+ if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
+ DEB_D("poll succeeded!\n");
+ return res | POLLIN | POLLRDNORM;
+ }
+
+ DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
+ return res;
+}
+
+static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ unsigned int res;
+
+ mutex_lock(vdev->lock);
+ res = __fops_poll(file, wait);
+ mutex_unlock(vdev->lock);
+ return res;
+}
+
+static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_fh *fh = file->private_data;
+ int ret;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+/*
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
+ file, data, (unsigned long)count);
+*/
+ return saa7146_video_uops.read(file,data,count,ppos);
+ case VFL_TYPE_VBI:
+/*
+ DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
+ file, data, (unsigned long)count);
+*/
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ ret = saa7146_vbi_uops.read(file, data, count, ppos);
+ mutex_unlock(vdev->lock);
+ return ret;
+ }
+ return -EINVAL;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_fh *fh = file->private_data;
+ int ret;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ return -EINVAL;
+ case VFL_TYPE_VBI:
+ if (fh->dev->ext_vv_data->vbi_fops.write) {
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+ mutex_unlock(vdev->lock);
+ return ret;
+ }
+ return -EINVAL;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_file_operations video_fops =
+{
+ .owner = THIS_MODULE,
+ .open = fops_open,
+ .release = fops_release,
+ .read = fops_read,
+ .write = fops_write,
+ .poll = fops_poll,
+ .mmap = fops_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static void vv_callback(struct saa7146_dev *dev, unsigned long status)
+{
+ u32 isr = status;
+
+ DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
+
+ if (0 != (isr & (MASK_27))) {
+ DEB_INT("irq: RPS0 (0x%08x)\n", isr);
+ saa7146_video_uops.irq_done(dev,isr);
+ }
+
+ if (0 != (isr & (MASK_28))) {
+ u32 mc2 = saa7146_read(dev, MC2);
+ if( 0 != (mc2 & MASK_15)) {
+ DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
+ wake_up(&dev->vv_data->vbi_wq);
+ saa7146_write(dev,MC2, MASK_31);
+ return;
+ }
+ DEB_INT("irq: RPS1 (0x%08x)\n", isr);
+ saa7146_vbi_uops.irq_done(dev,isr);
+ }
+}
+
+static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
+ .s_ctrl = saa7146_s_ctrl,
+};
+
+int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
+{
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ struct v4l2_pix_format *fmt;
+ struct v4l2_vbi_format *vbi;
+ struct saa7146_vv *vv;
+ int err;
+
+ err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
+ if (err)
+ return err;
+
+ v4l2_ctrl_handler_init(hdl, 6);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (hdl->error) {
+ err = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return err;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+
+ vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
+ if (vv == NULL) {
+ ERR("out of memory. aborting.\n");
+ v4l2_ctrl_handler_free(hdl);
+ return -ENOMEM;
+ }
+ ext_vv->vid_ops = saa7146_video_ioctl_ops;
+ ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
+ ext_vv->core_ops = &saa7146_video_ioctl_ops;
+
+ DEB_EE("dev:%p\n", dev);
+
+ /* set default values for video parts of the saa7146 */
+ saa7146_write(dev, BCS_CTRL, 0x80400040);
+
+ /* enable video-port pins */
+ saa7146_write(dev, MC1, (MASK_10 | MASK_26));
+
+ /* save per-device extension data (one extension can
+ handle different devices that might need different
+ configuration data) */
+ dev->ext_vv_data = ext_vv;
+
+ vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
+ if( NULL == vv->d_clipping.cpu_addr ) {
+ ERR("out of memory. aborting.\n");
+ kfree(vv);
+ v4l2_ctrl_handler_free(hdl);
+ return -1;
+ }
+ memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
+
+ saa7146_video_uops.init(dev,vv);
+ if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+ saa7146_vbi_uops.init(dev,vv);
+
+ fmt = &vv->ov_fb.fmt;
+ fmt->width = vv->standard->h_max_out;
+ fmt->height = vv->standard->v_max_out;
+ fmt->pixelformat = V4L2_PIX_FMT_RGB565;
+ fmt->bytesperline = 2 * fmt->width;
+ fmt->sizeimage = fmt->bytesperline * fmt->height;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt = &vv->video_fmt;
+ fmt->width = 384;
+ fmt->height = 288;
+ fmt->pixelformat = V4L2_PIX_FMT_BGR24;
+ fmt->field = V4L2_FIELD_ANY;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->bytesperline = 3 * fmt->width;
+ fmt->sizeimage = fmt->bytesperline * fmt->height;
+
+ vbi = &vv->vbi_fmt;
+ vbi->sampling_rate = 27000000;
+ vbi->offset = 248; /* todo */
+ vbi->samples_per_line = 720 * 2;
+ vbi->sample_format = V4L2_PIX_FMT_GREY;
+
+ /* fixme: this only works for PAL */
+ vbi->start[0] = 5;
+ vbi->count[0] = 16;
+ vbi->start[1] = 312;
+ vbi->count[1] = 16;
+
+ init_timer(&vv->vbi_read_timeout);
+
+ vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
+ dev->vv_data = vv;
+ dev->vv_callback = &vv_callback;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
+
+int saa7146_vv_release(struct saa7146_dev* dev)
+{
+ struct saa7146_vv *vv = dev->vv_data;
+
+ DEB_EE("dev:%p\n", dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ kfree(vv);
+ dev->vv_data = NULL;
+ dev->vv_callback = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
+
+int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+ char *name, int type)
+{
+ struct video_device *vfd;
+ int err;
+ int i;
+
+ DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
+
+ // released by vfd->release
+ vfd = video_device_alloc();
+ if (vfd == NULL)
+ return -ENOMEM;
+
+ vfd->fops = &video_fops;
+ if (type == VFL_TYPE_GRABBER)
+ vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
+ else
+ vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
+ vfd->release = video_device_release;
+ vfd->lock = &dev->v4l2_lock;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->tvnorms = 0;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+ vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
+ strlcpy(vfd->name, name, sizeof(vfd->name));
+ video_set_drvdata(vfd, dev);
+
+ err = video_register_device(vfd, type, -1);
+ if (err < 0) {
+ ERR("cannot register v4l2 device. skipping.\n");
+ video_device_release(vfd);
+ return err;
+ }
+
+ pr_info("%s: registered device %s [v4l2]\n",
+ dev->name, video_device_node_name(vfd));
+
+ *vid = vfd;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_register_device);
+
+int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
+{
+ DEB_EE("dev:%p\n", dev);
+
+ video_unregister_device(*vid);
+ *vid = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
+
+static int __init saa7146_vv_init_module(void)
+{
+ return 0;
+}
+
+
+static void __exit saa7146_vv_cleanup_module(void)
+{
+}
+
+module_init(saa7146_vv_init_module);
+module_exit(saa7146_vv_cleanup_module);
+
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index be746d1aee9a..be746d1aee9a 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
index 22027198129d..22027198129d 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index 1e71e374bbfe..1e71e374bbfe 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 6d14785d4747..6d14785d4747 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
deleted file mode 100644
index d6b1cf66042d..000000000000
--- a/drivers/media/common/saa7146_core.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- saa7146.o - driver for generic saa7146-based hardware
-
- Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
-
- 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.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146.h>
-#include <linux/module.h>
-
-LIST_HEAD(saa7146_devices);
-DEFINE_MUTEX(saa7146_devices_lock);
-
-static int saa7146_num;
-
-unsigned int saa7146_debug;
-
-module_param(saa7146_debug, uint, 0644);
-MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
-
-#if 0
-static void dump_registers(struct saa7146_dev* dev)
-{
- int i = 0;
-
- pr_info(" @ %li jiffies:\n", jiffies);
- for (i = 0; i <= 0x148; i += 4)
- pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
-}
-#endif
-
-/****************************************************************************
- * gpio and debi helper functions
- ****************************************************************************/
-
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
-{
- u32 value = 0;
-
- BUG_ON(port > 3);
-
- value = saa7146_read(dev, GPIO_CTRL);
- value &= ~(0xff << (8*port));
- value |= (data << (8*port));
- saa7146_write(dev, GPIO_CTRL, value);
-}
-
-/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
-static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
- unsigned long us1, unsigned long us2)
-{
- unsigned long timeout;
- int err;
-
- /* wait for registers to be programmed */
- timeout = jiffies + usecs_to_jiffies(us1);
- while (1) {
- err = time_after(jiffies, timeout);
- if (saa7146_read(dev, MC2) & 2)
- break;
- if (err) {
- pr_err("%s: %s timed out while waiting for registers getting programmed\n",
- dev->name, __func__);
- return -ETIMEDOUT;
- }
- msleep(1);
- }
-
- /* wait for transfer to complete */
- timeout = jiffies + usecs_to_jiffies(us2);
- while (1) {
- err = time_after(jiffies, timeout);
- if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
- break;
- saa7146_read(dev, MC2);
- if (err) {
- DEB_S("%s: %s timed out while waiting for transfer completion\n",
- dev->name, __func__);
- return -ETIMEDOUT;
- }
- msleep(1);
- }
-
- return 0;
-}
-
-static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
- unsigned long us1, unsigned long us2)
-{
- unsigned long loops;
-
- /* wait for registers to be programmed */
- loops = us1;
- while (1) {
- if (saa7146_read(dev, MC2) & 2)
- break;
- if (!loops--) {
- pr_err("%s: %s timed out while waiting for registers getting programmed\n",
- dev->name, __func__);
- return -ETIMEDOUT;
- }
- udelay(1);
- }
-
- /* wait for transfer to complete */
- loops = us2 / 5;
- while (1) {
- if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
- break;
- saa7146_read(dev, MC2);
- if (!loops--) {
- DEB_S("%s: %s timed out while waiting for transfer completion\n",
- dev->name, __func__);
- return -ETIMEDOUT;
- }
- udelay(5);
- }
-
- return 0;
-}
-
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
-{
- if (nobusyloop)
- return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
- else
- return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
-}
-
-/****************************************************************************
- * general helper functions
- ****************************************************************************/
-
-/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
- make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
- may be triggered on highmem machines */
-static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
-{
- struct scatterlist *sglist;
- struct page *pg;
- int i;
-
- sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
- if (NULL == sglist)
- return NULL;
- sg_init_table(sglist, nr_pages);
- for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
- pg = vmalloc_to_page(virt);
- if (NULL == pg)
- goto err;
- BUG_ON(PageHighMem(pg));
- sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
- }
- return sglist;
-
- err:
- kfree(sglist);
- return NULL;
-}
-
-/********************************************************************************/
-/* common page table functions */
-
-void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
-{
- int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
- void *mem = vmalloc_32(length);
- int slen = 0;
-
- if (NULL == mem)
- goto err_null;
-
- if (!(pt->slist = vmalloc_to_sg(mem, pages)))
- goto err_free_mem;
-
- if (saa7146_pgtable_alloc(pci, pt))
- goto err_free_slist;
-
- pt->nents = pages;
- slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
- if (0 == slen)
- goto err_free_pgtable;
-
- if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
- goto err_unmap_sg;
-
- return mem;
-
-err_unmap_sg:
- pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
-err_free_pgtable:
- saa7146_pgtable_free(pci, pt);
-err_free_slist:
- kfree(pt->slist);
- pt->slist = NULL;
-err_free_mem:
- vfree(mem);
-err_null:
- return NULL;
-}
-
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
-{
- pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
- saa7146_pgtable_free(pci, pt);
- kfree(pt->slist);
- pt->slist = NULL;
- vfree(mem);
-}
-
-void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
-{
- if (NULL == pt->cpu)
- return;
- pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
- pt->cpu = NULL;
-}
-
-int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
-{
- __le32 *cpu;
- dma_addr_t dma_addr = 0;
-
- cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
- if (NULL == cpu) {
- return -ENOMEM;
- }
- pt->size = PAGE_SIZE;
- pt->cpu = cpu;
- pt->dma = dma_addr;
-
- return 0;
-}
-
-int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
- struct scatterlist *list, int sglen )
-{
- __le32 *ptr, fill;
- int nr_pages = 0;
- int i,p;
-
- BUG_ON(0 == sglen);
- BUG_ON(list->offset > PAGE_SIZE);
-
- /* if we have a user buffer, the first page may not be
- aligned to a page boundary. */
- pt->offset = list->offset;
-
- ptr = pt->cpu;
- for (i = 0; i < sglen; i++, list++) {
-/*
- pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
- i, sg_dma_address(list), sg_dma_len(list),
- list->offset);
-*/
- for (p = 0; p * 4096 < list->length; p++, ptr++) {
- *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
- nr_pages++;
- }
- }
-
-
- /* safety; fill the page table up with the last valid page */
- fill = *(ptr-1);
- for(i=nr_pages;i<1024;i++) {
- *ptr++ = fill;
- }
-
-/*
- ptr = pt->cpu;
- pr_debug("offset: %d\n", pt->offset);
- for(i=0;i<5;i++) {
- pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
- }
-*/
- return 0;
-}
-
-/********************************************************************************/
-/* interrupt handler */
-static irqreturn_t interrupt_hw(int irq, void *dev_id)
-{
- struct saa7146_dev *dev = dev_id;
- u32 isr;
- u32 ack_isr;
-
- /* read out the interrupt status register */
- ack_isr = isr = saa7146_read(dev, ISR);
-
- /* is this our interrupt? */
- if ( 0 == isr ) {
- /* nope, some other device */
- return IRQ_NONE;
- }
-
- if (dev->ext) {
- if (dev->ext->irq_mask & isr) {
- if (dev->ext->irq_func)
- dev->ext->irq_func(dev, &isr);
- isr &= ~dev->ext->irq_mask;
- }
- }
- if (0 != (isr & (MASK_27))) {
- DEB_INT("irq: RPS0 (0x%08x)\n", isr);
- if (dev->vv_data && dev->vv_callback)
- dev->vv_callback(dev,isr);
- isr &= ~MASK_27;
- }
- if (0 != (isr & (MASK_28))) {
- if (dev->vv_data && dev->vv_callback)
- dev->vv_callback(dev,isr);
- isr &= ~MASK_28;
- }
- if (0 != (isr & (MASK_16|MASK_17))) {
- SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
- /* only wake up if we expect something */
- if (0 != dev->i2c_op) {
- dev->i2c_op = 0;
- wake_up(&dev->i2c_wq);
- } else {
- u32 psr = saa7146_read(dev, PSR);
- u32 ssr = saa7146_read(dev, SSR);
- pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
- dev->name, isr, psr, ssr);
- }
- isr &= ~(MASK_16|MASK_17);
- }
- if( 0 != isr ) {
- ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
- isr);
- ERR("disabling interrupt source(s)!\n");
- SAA7146_IER_DISABLE(dev,isr);
- }
- saa7146_write(dev, ISR, ack_isr);
- return IRQ_HANDLED;
-}
-
-/*********************************************************************************/
-/* configuration-functions */
-
-static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
-{
- struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
- struct saa7146_extension *ext = pci_ext->ext;
- struct saa7146_dev *dev;
- int err = -ENOMEM;
-
- /* clear out mem for sure */
- dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
- if (!dev) {
- ERR("out of memory\n");
- goto out;
- }
-
- DEB_EE("pci:%p\n", pci);
-
- err = pci_enable_device(pci);
- if (err < 0) {
- ERR("pci_enable_device() failed\n");
- goto err_free;
- }
-
- /* enable bus-mastering */
- pci_set_master(pci);
-
- dev->pci = pci;
-
- /* get chip-revision; this is needed to enable bug-fixes */
- dev->revision = pci->revision;
-
- /* remap the memory from virtual to physical address */
-
- err = pci_request_region(pci, 0, "saa7146");
- if (err < 0)
- goto err_disable;
-
- dev->mem = ioremap(pci_resource_start(pci, 0),
- pci_resource_len(pci, 0));
- if (!dev->mem) {
- ERR("ioremap() failed\n");
- err = -ENODEV;
- goto err_release;
- }
-
- /* we don't do a master reset here anymore, it screws up
- some boards that don't have an i2c-eeprom for configuration
- values */
-/*
- saa7146_write(dev, MC1, MASK_31);
-*/
-
- /* disable all irqs */
- saa7146_write(dev, IER, 0);
-
- /* shut down all dma transfers and rps tasks */
- saa7146_write(dev, MC1, 0x30ff0000);
-
- /* clear out any rps-signals pending */
- saa7146_write(dev, MC2, 0xf8000000);
-
- /* request an interrupt for the saa7146 */
- err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
- dev->name, dev);
- if (err < 0) {
- ERR("request_irq() failed\n");
- goto err_unmap;
- }
-
- err = -ENOMEM;
-
- /* get memory for various stuff */
- dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
- &dev->d_rps0.dma_handle);
- if (!dev->d_rps0.cpu_addr)
- goto err_free_irq;
- memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
- dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
- &dev->d_rps1.dma_handle);
- if (!dev->d_rps1.cpu_addr)
- goto err_free_rps0;
- memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
- dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
- &dev->d_i2c.dma_handle);
- if (!dev->d_i2c.cpu_addr)
- goto err_free_rps1;
- memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
-
- /* the rest + print status message */
-
- /* create a nice device name */
- sprintf(dev->name, "saa7146 (%d)", saa7146_num);
-
- pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
- dev->mem, dev->revision, pci->irq,
- pci->subsystem_vendor, pci->subsystem_device);
- dev->ext = ext;
-
- mutex_init(&dev->v4l2_lock);
- spin_lock_init(&dev->int_slock);
- spin_lock_init(&dev->slock);
-
- mutex_init(&dev->i2c_lock);
-
- dev->module = THIS_MODULE;
- init_waitqueue_head(&dev->i2c_wq);
-
- /* set some sane pci arbitrition values */
- saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
-
- /* TODO: use the status code of the callback */
-
- err = -ENODEV;
-
- if (ext->probe && ext->probe(dev)) {
- DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
- goto err_free_i2c;
- }
-
- if (ext->attach(dev, pci_ext)) {
- DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
- goto err_free_i2c;
- }
- /* V4L extensions will set the pci drvdata to the v4l2_device in the
- attach() above. So for those cards that do not use V4L we have to
- set it explicitly. */
- pci_set_drvdata(pci, &dev->v4l2_dev);
-
- INIT_LIST_HEAD(&dev->item);
- list_add_tail(&dev->item,&saa7146_devices);
- saa7146_num++;
-
- err = 0;
-out:
- return err;
-
-err_free_i2c:
- pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
- dev->d_i2c.dma_handle);
-err_free_rps1:
- pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
- dev->d_rps1.dma_handle);
-err_free_rps0:
- pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
- dev->d_rps0.dma_handle);
-err_free_irq:
- free_irq(pci->irq, (void *)dev);
-err_unmap:
- iounmap(dev->mem);
-err_release:
- pci_release_region(pci, 0);
-err_disable:
- pci_disable_device(pci);
-err_free:
- kfree(dev);
- goto out;
-}
-
-static void saa7146_remove_one(struct pci_dev *pdev)
-{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
- struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
- struct {
- void *addr;
- dma_addr_t dma;
- } dev_map[] = {
- { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
- { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
- { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
- { NULL, 0 }
- }, *p;
-
- DEB_EE("dev:%p\n", dev);
-
- dev->ext->detach(dev);
- /* Zero the PCI drvdata after use. */
- pci_set_drvdata(pdev, NULL);
-
- /* shut down all video dma transfers */
- saa7146_write(dev, MC1, 0x00ff0000);
-
- /* disable all irqs, release irq-routine */
- saa7146_write(dev, IER, 0);
-
- free_irq(pdev->irq, dev);
-
- for (p = dev_map; p->addr; p++)
- pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
-
- iounmap(dev->mem);
- pci_release_region(pdev, 0);
- list_del(&dev->item);
- pci_disable_device(pdev);
- kfree(dev);
-
- saa7146_num--;
-}
-
-/*********************************************************************************/
-/* extension handling functions */
-
-int saa7146_register_extension(struct saa7146_extension* ext)
-{
- DEB_EE("ext:%p\n", ext);
-
- ext->driver.name = ext->name;
- ext->driver.id_table = ext->pci_tbl;
- ext->driver.probe = saa7146_init_one;
- ext->driver.remove = saa7146_remove_one;
-
- pr_info("register extension '%s'\n", ext->name);
- return pci_register_driver(&ext->driver);
-}
-
-int saa7146_unregister_extension(struct saa7146_extension* ext)
-{
- DEB_EE("ext:%p\n", ext);
- pr_info("unregister extension '%s'\n", ext->name);
- pci_unregister_driver(&ext->driver);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(saa7146_register_extension);
-EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
-
-/* misc functions used by extension modules */
-EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
-EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
-EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
-EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
-EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
-EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
-
-EXPORT_SYMBOL_GPL(saa7146_setgpio);
-
-EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
-
-EXPORT_SYMBOL_GPL(saa7146_debug);
-EXPORT_SYMBOL_GPL(saa7146_devices);
-EXPORT_SYMBOL_GPL(saa7146_devices_lock);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
deleted file mode 100644
index 0cdbd742974a..000000000000
--- a/drivers/media/common/saa7146_fops.c
+++ /dev/null
@@ -1,641 +0,0 @@
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <media/saa7146_vv.h>
-#include <linux/module.h>
-
-/****************************************************************************/
-/* resource management functions, shamelessly stolen from saa7134 driver */
-
-int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- if (fh->resources & bit) {
- DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
- bit, vv->resources);
- /* have it already allocated */
- return 1;
- }
-
- /* is it free? */
- if (vv->resources & bit) {
- DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
- vv->resources, bit);
- /* no, someone else uses it */
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- vv->resources |= bit;
- DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
- return 1;
-}
-
-void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- BUG_ON((fh->resources & bits) != bits);
-
- fh->resources &= ~bits;
- vv->resources &= ~bits;
- DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
-}
-
-
-/********************************************************************************/
-/* common dma functions */
-
-void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
- struct saa7146_buf *buf)
-{
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- DEB_EE("dev:%p, buf:%p\n", dev, buf);
-
- BUG_ON(in_interrupt());
-
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-
-/********************************************************************************/
-/* common buffer functions */
-
-int saa7146_buffer_queue(struct saa7146_dev *dev,
- struct saa7146_dmaqueue *q,
- struct saa7146_buf *buf)
-{
- assert_spin_locked(&dev->slock);
- DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
-
- BUG_ON(!q);
-
- if (NULL == q->curr) {
- q->curr = buf;
- DEB_D("immediately activating buffer %p\n", buf);
- buf->activate(dev,buf,NULL);
- } else {
- list_add_tail(&buf->vb.queue,&q->queue);
- buf->vb.state = VIDEOBUF_QUEUED;
- DEB_D("adding buffer %p to queue. (active buffer present)\n",
- buf);
- }
- return 0;
-}
-
-void saa7146_buffer_finish(struct saa7146_dev *dev,
- struct saa7146_dmaqueue *q,
- int state)
-{
- assert_spin_locked(&dev->slock);
- DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
- DEB_EE("q->curr:%p\n", q->curr);
-
- BUG_ON(!q->curr);
-
- /* finish current buffer */
- if (NULL == q->curr) {
- DEB_D("aiii. no current buffer\n");
- return;
- }
-
- q->curr->vb.state = state;
- do_gettimeofday(&q->curr->vb.ts);
- wake_up(&q->curr->vb.done);
-
- q->curr = NULL;
-}
-
-void saa7146_buffer_next(struct saa7146_dev *dev,
- struct saa7146_dmaqueue *q, int vbi)
-{
- struct saa7146_buf *buf,*next = NULL;
-
- BUG_ON(!q);
-
- DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
-
- assert_spin_locked(&dev->slock);
- if (!list_empty(&q->queue)) {
- /* activate next one from queue */
- buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
- list_del(&buf->vb.queue);
- if (!list_empty(&q->queue))
- next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
- q->curr = buf;
- DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
- buf, q->queue.prev, q->queue.next);
- buf->activate(dev,buf,next);
- } else {
- DEB_INT("no next buffer. stopping.\n");
- if( 0 != vbi ) {
- /* turn off video-dma3 */
- saa7146_write(dev,MC1, MASK_20);
- } else {
- /* nothing to do -- just prevent next video-dma1 transfer
- by lowering the protection address */
-
- // fixme: fix this for vflip != 0
-
- saa7146_write(dev, PROT_ADDR1, 0);
- saa7146_write(dev, MC2, (MASK_02|MASK_18));
-
- /* write the address of the rps-program */
- saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
- /* turn on rps */
- saa7146_write(dev, MC1, (MASK_12 | MASK_28));
-
-/*
- printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
- printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
- printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
- printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
- printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
- printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
-*/
- }
- del_timer(&q->timeout);
- }
-}
-
-void saa7146_buffer_timeout(unsigned long data)
-{
- struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
- struct saa7146_dev *dev = q->dev;
- unsigned long flags;
-
- DEB_EE("dev:%p, dmaq:%p\n", dev, q);
-
- spin_lock_irqsave(&dev->slock,flags);
- if (q->curr) {
- DEB_D("timeout on %p\n", q->curr);
- saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
- }
-
- /* we don't restart the transfer here like other drivers do. when
- a streaming capture is disabled, the timeout function will be
- called for the current buffer. if we activate the next buffer now,
- we mess up our capture logic. if a timeout occurs on another buffer,
- then something is seriously broken before, so no need to buffer the
- next capture IMHO... */
-/*
- saa7146_buffer_next(dev,q);
-*/
- spin_unlock_irqrestore(&dev->slock,flags);
-}
-
-/********************************************************************************/
-/* file operations */
-
-static int fops_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_dev *dev = video_drvdata(file);
- struct saa7146_fh *fh = NULL;
- int result = 0;
-
- DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
-
- if (mutex_lock_interruptible(&saa7146_devices_lock))
- return -ERESTARTSYS;
-
- DEB_D("using: %p\n", dev);
-
- /* check if an extension is registered */
- if( NULL == dev->ext ) {
- DEB_S("no extension registered for this device\n");
- result = -ENODEV;
- goto out;
- }
-
- /* allocate per open data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- DEB_S("cannot allocate memory for per open data\n");
- result = -ENOMEM;
- goto out;
- }
-
- v4l2_fh_init(&fh->fh, vdev);
-
- file->private_data = &fh->fh;
- fh->dev = dev;
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- DEB_S("initializing vbi...\n");
- if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- result = saa7146_vbi_uops.open(dev,file);
- if (dev->ext_vv_data->vbi_fops.open)
- dev->ext_vv_data->vbi_fops.open(file);
- } else {
- DEB_S("initializing video...\n");
- result = saa7146_video_uops.open(dev,file);
- }
-
- if (0 != result) {
- goto out;
- }
-
- if( 0 == try_module_get(dev->ext->module)) {
- result = -EINVAL;
- goto out;
- }
-
- result = 0;
- v4l2_fh_add(&fh->fh);
-out:
- if (fh && result != 0) {
- kfree(fh);
- file->private_data = NULL;
- }
- mutex_unlock(&saa7146_devices_lock);
- return result;
-}
-
-static int fops_release(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
-
- DEB_EE("file:%p\n", file);
-
- if (mutex_lock_interruptible(&saa7146_devices_lock))
- return -ERESTARTSYS;
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- saa7146_vbi_uops.release(dev,file);
- if (dev->ext_vv_data->vbi_fops.release)
- dev->ext_vv_data->vbi_fops.release(file);
- } else {
- saa7146_video_uops.release(dev,file);
- }
-
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- module_put(dev->ext->module);
- file->private_data = NULL;
- kfree(fh);
-
- mutex_unlock(&saa7146_devices_lock);
-
- return 0;
-}
-
-static int fops_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct videobuf_queue *q;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER: {
- DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
- file, vma);
- q = &fh->video_q;
- break;
- }
- case VFL_TYPE_VBI: {
- DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
- file, vma);
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
- return -ENODEV;
- q = &fh->vbi_q;
- break;
- }
- default:
- BUG();
- return 0;
- }
-
- return videobuf_mmap_mapper(q,vma);
-}
-
-static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
- struct videobuf_buffer *buf = NULL;
- struct videobuf_queue *q;
- unsigned int res = v4l2_ctrl_poll(file, wait);
-
- DEB_EE("file:%p, poll:%p\n", file, wait);
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
- return res | POLLOUT | POLLWRNORM;
- if( 0 == fh->vbi_q.streaming )
- return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
- q = &fh->vbi_q;
- } else {
- DEB_D("using video queue\n");
- q = &fh->video_q;
- }
-
- if (!list_empty(&q->stream))
- buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-
- if (!buf) {
- DEB_D("buf == NULL!\n");
- return res | POLLERR;
- }
-
- poll_wait(file, &buf->done, wait);
- if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
- DEB_D("poll succeeded!\n");
- return res | POLLIN | POLLRDNORM;
- }
-
- DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
- return res;
-}
-
-static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
-/*
- DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
- file, data, (unsigned long)count);
-*/
- return saa7146_video_uops.read(file,data,count,ppos);
- case VFL_TYPE_VBI:
-/*
- DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
- file, data, (unsigned long)count);
-*/
- if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- return saa7146_vbi_uops.read(file,data,count,ppos);
- return -EINVAL;
- default:
- BUG();
- return 0;
- }
-}
-
-static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146_fh *fh = file->private_data;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- return -EINVAL;
- case VFL_TYPE_VBI:
- if (fh->dev->ext_vv_data->vbi_fops.write)
- return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
- else
- return -EINVAL;
- default:
- BUG();
- return -EINVAL;
- }
-}
-
-static const struct v4l2_file_operations video_fops =
-{
- .owner = THIS_MODULE,
- .open = fops_open,
- .release = fops_release,
- .read = fops_read,
- .write = fops_write,
- .poll = fops_poll,
- .mmap = fops_mmap,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static void vv_callback(struct saa7146_dev *dev, unsigned long status)
-{
- u32 isr = status;
-
- DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
-
- if (0 != (isr & (MASK_27))) {
- DEB_INT("irq: RPS0 (0x%08x)\n", isr);
- saa7146_video_uops.irq_done(dev,isr);
- }
-
- if (0 != (isr & (MASK_28))) {
- u32 mc2 = saa7146_read(dev, MC2);
- if( 0 != (mc2 & MASK_15)) {
- DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
- wake_up(&dev->vv_data->vbi_wq);
- saa7146_write(dev,MC2, MASK_31);
- return;
- }
- DEB_INT("irq: RPS1 (0x%08x)\n", isr);
- saa7146_vbi_uops.irq_done(dev,isr);
- }
-}
-
-static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
- .s_ctrl = saa7146_s_ctrl,
-};
-
-int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
-{
- struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
- struct v4l2_pix_format *fmt;
- struct v4l2_vbi_format *vbi;
- struct saa7146_vv *vv;
- int err;
-
- err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
- if (err)
- return err;
-
- v4l2_ctrl_handler_init(hdl, 6);
- v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
- v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 127, 1, 64);
- v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
- V4L2_CID_SATURATION, 0, 127, 1, 64);
- v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- if (hdl->error) {
- err = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return err;
- }
- dev->v4l2_dev.ctrl_handler = hdl;
-
- vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
- if (vv == NULL) {
- ERR("out of memory. aborting.\n");
- v4l2_ctrl_handler_free(hdl);
- return -ENOMEM;
- }
- ext_vv->vid_ops = saa7146_video_ioctl_ops;
- ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
- ext_vv->core_ops = &saa7146_video_ioctl_ops;
-
- DEB_EE("dev:%p\n", dev);
-
- /* set default values for video parts of the saa7146 */
- saa7146_write(dev, BCS_CTRL, 0x80400040);
-
- /* enable video-port pins */
- saa7146_write(dev, MC1, (MASK_10 | MASK_26));
-
- /* save per-device extension data (one extension can
- handle different devices that might need different
- configuration data) */
- dev->ext_vv_data = ext_vv;
-
- vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
- if( NULL == vv->d_clipping.cpu_addr ) {
- ERR("out of memory. aborting.\n");
- kfree(vv);
- v4l2_ctrl_handler_free(hdl);
- return -1;
- }
- memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
-
- saa7146_video_uops.init(dev,vv);
- if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
- saa7146_vbi_uops.init(dev,vv);
-
- fmt = &vv->ov_fb.fmt;
- fmt->width = vv->standard->h_max_out;
- fmt->height = vv->standard->v_max_out;
- fmt->pixelformat = V4L2_PIX_FMT_RGB565;
- fmt->bytesperline = 2 * fmt->width;
- fmt->sizeimage = fmt->bytesperline * fmt->height;
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
-
- fmt = &vv->video_fmt;
- fmt->width = 384;
- fmt->height = 288;
- fmt->pixelformat = V4L2_PIX_FMT_BGR24;
- fmt->field = V4L2_FIELD_ANY;
- fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->bytesperline = 3 * fmt->width;
- fmt->sizeimage = fmt->bytesperline * fmt->height;
-
- vbi = &vv->vbi_fmt;
- vbi->sampling_rate = 27000000;
- vbi->offset = 248; /* todo */
- vbi->samples_per_line = 720 * 2;
- vbi->sample_format = V4L2_PIX_FMT_GREY;
-
- /* fixme: this only works for PAL */
- vbi->start[0] = 5;
- vbi->count[0] = 16;
- vbi->start[1] = 312;
- vbi->count[1] = 16;
-
- init_timer(&vv->vbi_read_timeout);
-
- vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
- dev->vv_data = vv;
- dev->vv_callback = &vv_callback;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-
-int saa7146_vv_release(struct saa7146_dev* dev)
-{
- struct saa7146_vv *vv = dev->vv_data;
-
- DEB_EE("dev:%p\n", dev);
-
- v4l2_device_unregister(&dev->v4l2_dev);
- pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- kfree(vv);
- dev->vv_data = NULL;
- dev->vv_callback = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
-
-int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
- char *name, int type)
-{
- struct video_device *vfd;
- int err;
- int i;
-
- DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
-
- // released by vfd->release
- vfd = video_device_alloc();
- if (vfd == NULL)
- return -ENOMEM;
-
- vfd->fops = &video_fops;
- if (type == VFL_TYPE_GRABBER)
- vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
- else
- vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
- vfd->release = video_device_release;
- /* Locking in file operations other than ioctl should be done by
- the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- vfd->lock = &dev->v4l2_lock;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->tvnorms = 0;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
- for (i = 0; i < dev->ext_vv_data->num_stds; i++)
- vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
- strlcpy(vfd->name, name, sizeof(vfd->name));
- video_set_drvdata(vfd, dev);
-
- err = video_register_device(vfd, type, -1);
- if (err < 0) {
- ERR("cannot register v4l2 device. skipping.\n");
- video_device_release(vfd);
- return err;
- }
-
- pr_info("%s: registered device %s [v4l2]\n",
- dev->name, video_device_node_name(vfd));
-
- *vid = vfd;
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-
-int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
-{
- DEB_EE("dev:%p\n", dev);
-
- video_unregister_device(*vid);
- *vid = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-static int __init saa7146_vv_init_module(void)
-{
- return 0;
-}
-
-
-static void __exit saa7146_vv_cleanup_module(void)
-{
-}
-
-module_init(saa7146_vv_init_module);
-module_exit(saa7146_vv_cleanup_module);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
new file mode 100644
index 000000000000..425aeadfb49d
--- /dev/null
+++ b/drivers/media/common/siano/Kconfig
@@ -0,0 +1,17 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_SIANO_MDTV
+ tristate
+ depends on DVB_CORE && RC_CORE && HAS_DMA
+ depends on SMS_USB_DRV || SMS_SDIO_DRV
+ default y
+ ---help---
+ Choose Y or M here if you have MDTV receiver with a Siano chipset.
+
+ To compile this driver as a module, choose M here
+ (The module will be called smsmdtv).
+
+ Further documentation on this driver can be found on the WWW
+ at http://www.siano-ms.com/
diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile
new file mode 100644
index 000000000000..2a09279e0648
--- /dev/null
+++ b/drivers/media/common/siano/Makefile
@@ -0,0 +1,7 @@
+smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
+
+obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index 680c781c8dd6..680c781c8dd6 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
index d8cdf756f7cf..d8cdf756f7cf 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/common/siano/sms-cards.h
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 9cc55546cc30..9cc55546cc30 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index c592ae090397..c592ae090397 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c
index aa77e54a8fae..aa77e54a8fae 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/common/siano/smsdvb.c
diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
index e2657c2f0109..e2657c2f0109 100644
--- a/drivers/media/dvb/siano/smsendian.c
+++ b/drivers/media/common/siano/smsendian.c
diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/common/siano/smsendian.h
index 1624d6fd367b..1624d6fd367b 100644
--- a/drivers/media/dvb/siano/smsendian.h
+++ b/drivers/media/common/siano/smsendian.h
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 37bc5c4b8ad8..37bc5c4b8ad8 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/common/siano/smsir.h
index ae92b3a8587e..ae92b3a8587e 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/common/siano/smsir.h
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
deleted file mode 100644
index 94c6ff7a5da3..000000000000
--- a/drivers/media/common/tuners/Kconfig
+++ /dev/null
@@ -1,243 +0,0 @@
-config MEDIA_ATTACH
- bool "Load and attach frontend and tuner driver modules as needed"
- depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
- depends on MODULES
- default y if !EXPERT
- help
- Remove the static dependency of DVB card drivers on all
- frontend modules for all possible card variants. Instead,
- allow the card drivers to only load the frontend modules
- they require.
-
- Also, tuner module will automatically load a tuner driver
- when needed, for analog mode.
-
- This saves several KBytes of memory.
-
- Note: You will need module-init-tools v3.2 or later for this feature.
-
- If unsure say Y.
-
-config MEDIA_TUNER
- tristate
- depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
- default y
- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
- 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 && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
- select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-
-config MEDIA_TUNER_CUSTOMISE
- bool "Customize analog and hybrid tuner modules to build"
- depends on MEDIA_TUNER
- default y if EXPERT
- help
- This allows the user to deselect tuner drivers unnecessary
- for their hardware from the build. Use this option with care
- as deselecting tuner drivers which are in fact necessary will
- result in V4L/DVB devices which cannot be tuned due to lack of
- driver support
-
- If unsure say N.
-
-menu "Customize TV tuners"
- visible if MEDIA_TUNER_CUSTOMISE
- depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
-
-config MEDIA_TUNER_SIMPLE
- tristate "Simple tuner support"
- depends on MEDIA_SUPPORT && I2C
- select MEDIA_TUNER_TDA9887
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for various simple tuners.
-
-config MEDIA_TUNER_TDA8290
- tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
- depends on MEDIA_SUPPORT && I2C
- select MEDIA_TUNER_TDA827X
- select MEDIA_TUNER_TDA18271
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for Philips TDA8290+8275(a) tuner.
-
-config MEDIA_TUNER_TDA827X
- tristate "Philips TDA827X silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A DVB-T silicon tuner module. Say Y when you want to support this tuner.
-
-config MEDIA_TUNER_TDA18271
- tristate "NXP TDA18271 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A silicon tuner module. Say Y when you want to support this tuner.
-
-config MEDIA_TUNER_TDA9887
- tristate "TDA 9885/6/7 analog IF demodulator"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for Philips TDA9885/6/7
- analog IF demodulator.
-
-config MEDIA_TUNER_TEA5761
- tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
- depends on MEDIA_SUPPORT && I2C
- depends on EXPERIMENTAL
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for the Philips TEA5761 radio tuner.
-
-config MEDIA_TUNER_TEA5767
- tristate "TEA 5767 radio tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for the Philips TEA5767 radio tuner.
-
-config MEDIA_TUNER_MT20XX
- tristate "Microtune 2032 / 2050 tuners"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for the MT2032 / MT2050 tuner.
-
-config MEDIA_TUNER_MT2060
- tristate "Microtune MT2060 silicon IF tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon IF tuner MT2060 from Microtune.
-
-config MEDIA_TUNER_MT2063
- tristate "Microtune MT2063 silicon IF tuner"
- depends on MEDIA_SUPPORT && 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 MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2266 from Microtune.
-
-config MEDIA_TUNER_MT2131
- tristate "Microtune MT2131 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2131 from Microtune.
-
-config MEDIA_TUNER_QT1010
- tristate "Quantek QT1010 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner QT1010 from Quantek.
-
-config MEDIA_TUNER_XC2028
- tristate "XCeive xc2028/xc3028 tuners"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to include support for the xc2028/xc3028 tuners.
-
-config MEDIA_TUNER_XC5000
- tristate "Xceive XC5000 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner XC5000 from Xceive.
- This device is only used inside a SiP called together with a
- demodulator for now.
-
-config MEDIA_TUNER_XC4000
- tristate "Xceive XC4000 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner XC4000 from Xceive.
- This device is only used inside a SiP called together with a
- demodulator for now.
-
-config MEDIA_TUNER_MXL5005S
- tristate "MaxLinear MSL5005S silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner MXL5005S from MaxLinear.
-
-config MEDIA_TUNER_MXL5007T
- tristate "MaxLinear MxL5007T silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner MxL5007T from MaxLinear.
-
-config MEDIA_TUNER_MC44S803
- tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Freescale MC44S803 based tuners
-
-config MEDIA_TUNER_MAX2165
- tristate "Maxim MAX2165 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- A driver for the silicon tuner MAX2165 from Maxim.
-
-config MEDIA_TUNER_TDA18218
- tristate "NXP TDA18218 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- NXP TDA18218 silicon tuner driver.
-
-config MEDIA_TUNER_FC0011
- tristate "Fitipower FC0011 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Fitipower FC0011 silicon tuner driver.
-
-config MEDIA_TUNER_FC0012
- tristate "Fitipower FC0012 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Fitipower FC0012 silicon tuner driver.
-
-config MEDIA_TUNER_FC0013
- tristate "Fitipower FC0013 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Fitipower FC0013 silicon tuner driver.
-
-config MEDIA_TUNER_TDA18212
- tristate "NXP TDA18212 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- NXP TDA18212 silicon tuner driver.
-
-config MEDIA_TUNER_TUA9001
- tristate "Infineon TUA 9001 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
- default m if MEDIA_TUNER_CUSTOMISE
- help
- Infineon TUA 9001 silicon tuner driver.
-endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
deleted file mode 100644
index 891b80e60808..000000000000
--- a/drivers/media/common/tuners/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for common V4L/DVB tuners
-#
-
-tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
-
-obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
-obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
-# tuner-types will be merged into tuner-simple, in the future
-obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
-obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
-obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
-obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
-obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
-obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
-obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
-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
-obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
-obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
-obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
-obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
-obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
-obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
-obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
-obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
-obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
-obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
-
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
-ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c
deleted file mode 100644
index 2d79b1f5d5eb..000000000000
--- a/drivers/media/common/tuners/qt1010.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Driver for Quantek QT1010 silicon tuner
- *
- * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
- * Aapo Tahkola <aet@rasterburn.org>
- *
- * 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 "qt1010.h"
-#include "qt1010_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG "QT1010: " args); \
- } while (0)
-
-/* read single register */
-static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
-{
- struct i2c_msg msg[2] = {
- { .addr = priv->cfg->i2c_address,
- .flags = 0, .buf = &reg, .len = 1 },
- { .addr = priv->cfg->i2c_address,
- .flags = I2C_M_RD, .buf = val, .len = 1 },
- };
-
- if (i2c_transfer(priv->i2c, msg, 2) != 2) {
- printk(KERN_WARNING "qt1010 I2C read failed\n");
- return -EREMOTEIO;
- }
- return 0;
-}
-
-/* write single register */
-static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
-{
- u8 buf[2] = { reg, val };
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
- .flags = 0, .buf = buf, .len = 2 };
-
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
- printk(KERN_WARNING "qt1010 I2C write failed\n");
- return -EREMOTEIO;
- }
- return 0;
-}
-
-/* dump all registers */
-static void qt1010_dump_regs(struct qt1010_priv *priv)
-{
- u8 reg, val;
-
- for (reg = 0; ; reg++) {
- if (reg % 16 == 0) {
- if (reg)
- printk(KERN_CONT "\n");
- printk(KERN_DEBUG "%02x:", reg);
- }
- if (qt1010_readreg(priv, reg, &val) == 0)
- printk(KERN_CONT " %02x", val);
- else
- printk(KERN_CONT " --");
- if (reg == 0x2f)
- break;
- }
- printk(KERN_CONT "\n");
-}
-
-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;
- u8 i, tmpval, reg05;
- qt1010_i2c_oper_t rd[48] = {
- { QT1010_WR, 0x01, 0x80 },
- { QT1010_WR, 0x02, 0x3f },
- { QT1010_WR, 0x05, 0xff }, /* 02 c write */
- { QT1010_WR, 0x06, 0x44 },
- { QT1010_WR, 0x07, 0xff }, /* 04 c write */
- { QT1010_WR, 0x08, 0x08 },
- { QT1010_WR, 0x09, 0xff }, /* 06 c write */
- { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
- { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
- { QT1010_WR, 0x0c, 0xe1 },
- { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
- { QT1010_WR, 0x1b, 0x00 },
- { QT1010_WR, 0x1c, 0x89 },
- { QT1010_WR, 0x11, 0xff }, /* 13 c write */
- { QT1010_WR, 0x12, 0xff }, /* 14 c write */
- { QT1010_WR, 0x22, 0xff }, /* 15 c write */
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x1e, 0xd0 },
- { QT1010_RD, 0x22, 0xff }, /* 16 c read */
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_RD, 0x05, 0xff }, /* 20 c read */
- { QT1010_RD, 0x22, 0xff }, /* 21 c read */
- { QT1010_WR, 0x23, 0xd0 },
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x1e, 0xe0 },
- { QT1010_RD, 0x23, 0xff }, /* 25 c read */
- { QT1010_RD, 0x23, 0xff }, /* 26 c read */
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x24, 0xd0 },
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x1e, 0xf0 },
- { QT1010_RD, 0x24, 0xff }, /* 31 c read */
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x14, 0x7f },
- { QT1010_WR, 0x15, 0x7f },
- { QT1010_WR, 0x05, 0xff }, /* 35 c write */
- { QT1010_WR, 0x06, 0x00 },
- { QT1010_WR, 0x15, 0x1f },
- { QT1010_WR, 0x16, 0xff },
- { QT1010_WR, 0x18, 0xff },
- { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
- { QT1010_WR, 0x20, 0xff }, /* 41 c write */
- { QT1010_WR, 0x21, 0x53 },
- { QT1010_WR, 0x25, 0xff }, /* 43 c write */
- { QT1010_WR, 0x26, 0x15 },
- { QT1010_WR, 0x00, 0xff }, /* 45 c write */
- { QT1010_WR, 0x02, 0x00 },
- { QT1010_WR, 0x01, 0x00 }
- };
-
-#define FREQ1 32000000 /* 32 MHz */
-#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
-
- priv = fe->tuner_priv;
- 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->frequency = freq;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
- /* reg 05 base value */
- if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
- else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
- else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
- else reg05 = 0x74;
-
- /* 0x5 */
- rd[2].val = reg05;
-
- /* 07 - set frequency: 32 MHz scale */
- rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
-
- /* 09 - changes every 8/24 MHz */
- if (mod1 < 8000000) rd[6].val = 0x1d;
- else rd[6].val = 0x1c;
-
- /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
- if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
- else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
- else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
- else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
- else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
- else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
- else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
- else rd[7].val = 0x0a; /* +28 MHz */
-
- /* 0b - changes every 2/2 MHz */
- if (mod2 < 2000000) rd[8].val = 0x45;
- else rd[8].val = 0x44;
-
- /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
- tmpval = 0x78; /* byte, overflows intentionally */
- rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
-
- /* 11 */
- rd[13].val = 0xfd; /* TODO: correct value calculation */
-
- /* 12 */
- rd[14].val = 0x91; /* TODO: correct value calculation */
-
- /* 22 */
- if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
- else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
- else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
- else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
- else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
- else rd[15].val = 0xd0;
-
- /* 05 */
- rd[35].val = (reg05 & 0xf0);
-
- /* 1f */
- if (mod1 < 8000000) tmpval = 0x00;
- else if (mod1 < 12000000) tmpval = 0x01;
- else if (mod1 < 16000000) tmpval = 0x02;
- else if (mod1 < 24000000) tmpval = 0x03;
- else if (mod1 < 28000000) tmpval = 0x04;
- else tmpval = 0x05;
- rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
-
- /* 20 */
- if (mod1 < 8000000) tmpval = 0x00;
- else if (mod1 < 12000000) tmpval = 0x01;
- else if (mod1 < 20000000) tmpval = 0x02;
- else if (mod1 < 24000000) tmpval = 0x03;
- else if (mod1 < 28000000) tmpval = 0x04;
- else tmpval = 0x05;
- rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
-
- /* 25 */
- rd[43].val = priv->reg25_init_val;
-
- /* 00 */
- rd[45].val = 0x92; /* TODO: correct value calculation */
-
- dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
- "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
- "20:%02x 25:%02x 00:%02x", \
- freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
- rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
- rd[40].val, rd[41].val, rd[43].val, rd[45].val);
-
- for (i = 0; i < ARRAY_SIZE(rd); i++) {
- if (rd[i].oper == QT1010_WR) {
- err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
- } else { /* read is required to proper locking */
- err = qt1010_readreg(priv, rd[i].reg, &tmpval);
- }
- if (err) return err;
- }
-
- if (debug)
- qt1010_dump_regs(priv);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
- return 0;
-}
-
-static int qt1010_init_meas1(struct qt1010_priv *priv,
- u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
-{
- u8 i, val1, val2;
- int err;
-
- qt1010_i2c_oper_t i2c_data[] = {
- { QT1010_WR, reg, reg_init_val },
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x1e, oper },
- { QT1010_RD, reg, 0xff }
- };
-
- for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
- if (i2c_data[i].oper == QT1010_WR) {
- err = qt1010_writereg(priv, i2c_data[i].reg,
- i2c_data[i].val);
- } else {
- err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
- }
- if (err) return err;
- }
-
- do {
- val1 = val2;
- err = qt1010_readreg(priv, reg, &val2);
- if (err) return err;
- dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
- } while (val1 != val2);
- *retval = val1;
-
- return qt1010_writereg(priv, 0x1e, 0x00);
-}
-
-static u8 qt1010_init_meas2(struct qt1010_priv *priv,
- u8 reg_init_val, u8 *retval)
-{
- u8 i, val;
- int err;
- qt1010_i2c_oper_t i2c_data[] = {
- { QT1010_WR, 0x07, reg_init_val },
- { QT1010_WR, 0x22, 0xd0 },
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x1e, 0xd0 },
- { QT1010_RD, 0x22, 0xff },
- { QT1010_WR, 0x1e, 0x00 },
- { QT1010_WR, 0x22, 0xff }
- };
- for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
- if (i2c_data[i].oper == QT1010_WR) {
- err = qt1010_writereg(priv, i2c_data[i].reg,
- i2c_data[i].val);
- } else {
- err = qt1010_readreg(priv, i2c_data[i].reg, &val);
- }
- if (err) return err;
- }
- *retval = val;
- return 0;
-}
-
-static int qt1010_init(struct dvb_frontend *fe)
-{
- struct qt1010_priv *priv = fe->tuner_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int err = 0;
- u8 i, tmpval, *valptr = NULL;
-
- qt1010_i2c_oper_t i2c_data[] = {
- { QT1010_WR, 0x01, 0x80 },
- { QT1010_WR, 0x0d, 0x84 },
- { QT1010_WR, 0x0e, 0xb7 },
- { QT1010_WR, 0x2a, 0x23 },
- { QT1010_WR, 0x2c, 0xdc },
- { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
- { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
- { QT1010_WR, 0x2b, 0x70 },
- { QT1010_WR, 0x2a, 0x23 },
- { QT1010_M1, 0x26, 0x08 },
- { QT1010_M1, 0x82, 0xff },
- { QT1010_WR, 0x05, 0x14 },
- { QT1010_WR, 0x06, 0x44 },
- { QT1010_WR, 0x07, 0x28 },
- { QT1010_WR, 0x08, 0x0b },
- { QT1010_WR, 0x11, 0xfd },
- { QT1010_M1, 0x22, 0x0d },
- { QT1010_M1, 0xd0, 0xff },
- { QT1010_WR, 0x06, 0x40 },
- { QT1010_WR, 0x16, 0xf0 },
- { QT1010_WR, 0x02, 0x38 },
- { QT1010_WR, 0x03, 0x18 },
- { QT1010_WR, 0x20, 0xe0 },
- { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
- { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
- { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
- { QT1010_WR, 0x03, 0x19 },
- { QT1010_WR, 0x02, 0x3f },
- { QT1010_WR, 0x21, 0x53 },
- { QT1010_RD, 0x21, 0xff },
- { QT1010_WR, 0x11, 0xfd },
- { QT1010_WR, 0x05, 0x34 },
- { QT1010_WR, 0x06, 0x44 },
- { QT1010_WR, 0x08, 0x08 }
- };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
- for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
- switch (i2c_data[i].oper) {
- case QT1010_WR:
- err = qt1010_writereg(priv, i2c_data[i].reg,
- i2c_data[i].val);
- break;
- case QT1010_RD:
- if (i2c_data[i].val == 0x20)
- valptr = &priv->reg20_init_val;
- else
- valptr = &tmpval;
- err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
- break;
- case QT1010_M1:
- if (i2c_data[i].val == 0x25)
- valptr = &priv->reg25_init_val;
- else if (i2c_data[i].val == 0x1f)
- valptr = &priv->reg1f_init_val;
- else
- valptr = &tmpval;
- err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
- i2c_data[i].reg,
- i2c_data[i].val, valptr);
- i++;
- break;
- }
- if (err) return err;
- }
-
- for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
- if ((err = qt1010_init_meas2(priv, i, &tmpval)))
- return err;
-
- c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
- /* MSI Megasky 580 GL861 533000000 */
- return qt1010_set_params(fe);
-}
-
-static int qt1010_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
- return 0;
-}
-
-static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct qt1010_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
- return 0;
-}
-
-static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- *frequency = 36125000;
- return 0;
-}
-
-static const struct dvb_tuner_ops qt1010_tuner_ops = {
- .info = {
- .name = "Quantek QT1010",
- .frequency_min = QT1010_MIN_FREQ,
- .frequency_max = QT1010_MAX_FREQ,
- .frequency_step = QT1010_STEP,
- },
-
- .release = qt1010_release,
- .init = qt1010_init,
- /* TODO: implement sleep */
-
- .set_params = qt1010_set_params,
- .get_frequency = qt1010_get_frequency,
- .get_if_frequency = qt1010_get_if_frequency,
-};
-
-struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct qt1010_config *cfg)
-{
- struct qt1010_priv *priv = NULL;
- u8 id;
-
- priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
-
- priv->cfg = cfg;
- priv->i2c = i2c;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
-
-
- /* Try to detect tuner chip. Probably this is not correct register. */
- if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
- kfree(priv);
- return NULL;
- }
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
-
- printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
- memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- fe->tuner_priv = priv;
- return fe;
-}
-EXPORT_SYMBOL(qt1010_attach);
-
-MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c
deleted file mode 100644
index 602c2e392b17..000000000000
--- a/drivers/media/common/tuners/tda18212.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * NXP TDA18212HN silicon tuner 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "tda18212.h"
-
-struct tda18212_priv {
- struct tda18212_config *cfg;
- struct i2c_adapter *i2c;
-
- u32 if_frequency;
-};
-
-#define dbg(fmt, arg...) \
-do { \
- if (debug) \
- pr_info("%s: " fmt, __func__, ##arg); \
-} while (0)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-/* write multiple registers */
-static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
- int len)
-{
- int ret;
- u8 buf[len+1];
- struct i2c_msg msg[1] = {
- {
- .addr = priv->cfg->i2c_address,
- .flags = 0,
- .len = sizeof(buf),
- .buf = buf,
- }
- };
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(priv->i2c, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
- ret, reg, len);
- ret = -EREMOTEIO;
- }
- return ret;
-}
-
-/* read multiple registers */
-static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
- int len)
-{
- int ret;
- u8 buf[len];
- struct i2c_msg msg[2] = {
- {
- .addr = priv->cfg->i2c_address,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = priv->cfg->i2c_address,
- .flags = I2C_M_RD,
- .len = sizeof(buf),
- .buf = buf,
- }
- };
-
- ret = i2c_transfer(priv->i2c, msg, 2);
- if (ret == 2) {
- memcpy(val, buf, len);
- ret = 0;
- } else {
- pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
- ret, reg, len);
- ret = -EREMOTEIO;
- }
-
- return ret;
-}
-
-/* write single register */
-static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
-{
- return tda18212_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
-{
- return tda18212_rd_regs(priv, reg, val, 1);
-}
-
-#if 0 /* keep, useful when developing driver */
-static void tda18212_dump_regs(struct tda18212_priv *priv)
-{
- int i;
- u8 buf[256];
-
- #define TDA18212_RD_LEN 32
- for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
- tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
-
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
- sizeof(buf), true);
-
- return;
-}
-#endif
-
-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] = {
- /* 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",
- c->delivery_system, c->frequency, c->bandwidth_hz);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- switch (c->delivery_system) {
- case SYS_DVBT:
- switch (c->bandwidth_hz) {
- case 6000000:
- if_khz = priv->cfg->if_dvbt_6;
- i = DVBT_6;
- break;
- case 7000000:
- if_khz = priv->cfg->if_dvbt_7;
- i = DVBT_7;
- break;
- case 8000000:
- if_khz = priv->cfg->if_dvbt_8;
- i = DVBT_8;
- break;
- default:
- ret = -EINVAL;
- goto error;
- }
- break;
- 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 = DVBC_8;
- break;
- default:
- ret = -EINVAL;
- goto error;
- }
-
- ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
- if (ret)
- goto error;
-
- ret = tda18212_wr_reg(priv, 0x06, 0x00);
- if (ret)
- goto error;
-
- ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
- if (ret)
- goto error;
-
- buf[0] = 0x02;
- buf[1] = bw_params[i][1];
- buf[2] = 0x03; /* default value */
- 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;
- buf[7] = 0xc1;
- buf[8] = 0x01;
- ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
- 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 */
-
- return ret;
-
-error:
- dbg("failed:%d\n", ret);
- 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);
- fe->tuner_priv = NULL;
- return 0;
-}
-
-static const struct dvb_tuner_ops tda18212_tuner_ops = {
- .info = {
- .name = "NXP TDA18212",
-
- .frequency_min = 48000000,
- .frequency_max = 864000000,
- .frequency_step = 1000,
- },
-
- .release = tda18212_release,
-
- .set_params = tda18212_set_params,
- .get_if_frequency = tda18212_get_if_frequency,
-};
-
-struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
- struct tda18212_priv *priv = NULL;
- int ret;
- u8 val;
-
- priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
-
- priv->cfg = cfg;
- priv->i2c = i2c;
- fe->tuner_priv = priv;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- /* check if the tuner is there */
- ret = tda18212_rd_reg(priv, 0x00, &val);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
- dbg("ret:%d chip ID:%02x\n", ret, val);
- if (ret || val != 0xc7) {
- kfree(priv);
- return NULL;
- }
-
- pr_info("NXP TDA18212HN successfully identified\n");
-
- memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- return fe;
-}
-EXPORT_SYMBOL(tda18212_attach);
-
-MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
deleted file mode 100644
index dfb3a831df45..000000000000
--- a/drivers/media/common/tuners/tda18218.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * NXP TDA18218HN silicon tuner driver
- *
- * Copyright (C) 2010 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 "tda18218.h"
-#include "tda18218_priv.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-/* write multiple registers */
-static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
-{
- int ret = 0;
- u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
- struct i2c_msg msg[1] = {
- {
- .addr = priv->cfg->i2c_address,
- .flags = 0,
- .buf = buf,
- }
- };
-
- msg_len_max = priv->cfg->i2c_wr_max - 1;
- quotient = len / msg_len_max;
- remainder = len % msg_len_max;
- msg_len = msg_len_max;
- for (i = 0; (i <= quotient && remainder); i++) {
- if (i == quotient) /* set len of the last msg */
- msg_len = remainder;
-
- msg[0].len = msg_len + 1;
- buf[0] = reg + i * msg_len_max;
- memcpy(&buf[1], &val[i * msg_len_max], msg_len);
-
- ret = i2c_transfer(priv->i2c, msg, 1);
- if (ret != 1)
- break;
- }
-
- if (ret == 1) {
- ret = 0;
- } else {
- warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
- ret = -EREMOTEIO;
- }
-
- return ret;
-}
-
-/* read multiple registers */
-static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
-{
- int ret;
- u8 buf[reg+len]; /* we must start read always from reg 0x00 */
- struct i2c_msg msg[2] = {
- {
- .addr = priv->cfg->i2c_address,
- .flags = 0,
- .len = 1,
- .buf = "\x00",
- }, {
- .addr = priv->cfg->i2c_address,
- .flags = I2C_M_RD,
- .len = sizeof(buf),
- .buf = buf,
- }
- };
-
- ret = i2c_transfer(priv->i2c, msg, 2);
- if (ret == 2) {
- memcpy(val, &buf[reg], len);
- ret = 0;
- } else {
- warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
- ret = -EREMOTEIO;
- }
-
- return ret;
-}
-
-/* write single register */
-static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
-{
- return tda18218_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-
-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 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;
- /* TODO: find out correct AGC algorithm */
- u8 agc[][2] = {
- { R20_AGC11, 0x60 },
- { R23_AGC21, 0x02 },
- { R20_AGC11, 0xa0 },
- { R23_AGC21, 0x09 },
- { R20_AGC11, 0xe0 },
- { R23_AGC21, 0x0c },
- { R20_AGC11, 0x40 },
- { R23_AGC21, 0x01 },
- { R20_AGC11, 0x80 },
- { R23_AGC21, 0x08 },
- { R20_AGC11, 0xc0 },
- { R23_AGC21, 0x0b },
- { R24_AGC22, 0x1c },
- { R24_AGC22, 0x0c },
- };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- /* low-pass filter cut-off frequency */
- if (bw <= 6000000) {
- LP_Fc = 0;
- priv->if_frequency = 3000000;
- } else if (bw <= 7000000) {
- LP_Fc = 1;
- priv->if_frequency = 3500000;
- } else {
- LP_Fc = 2;
- priv->if_frequency = 4000000;
- }
-
- LO_Frac = c->frequency + priv->if_frequency;
-
- /* band-pass filter */
- if (LO_Frac < 188000000)
- BP_Filter = 3;
- else if (LO_Frac < 253000000)
- BP_Filter = 4;
- else if (LO_Frac < 343000000)
- BP_Filter = 5;
- else
- BP_Filter = 6;
-
- buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
- buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
- buf[2] = priv->regs[R1C_AGC2B];
- ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
- if (ret)
- goto error;
-
- buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
- buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
- buf[2] = (LO_Frac / 1000) << 4 |
- (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
- ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
- if (ret)
- goto error;
-
- buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
- ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
- if (ret)
- goto error;
-
- buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
- ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
- if (ret)
- goto error;
-
- /* trigger AGC */
- for (i = 0; i < ARRAY_SIZE(agc); i++) {
- ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
- if (ret)
- goto error;
- }
-
-error:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
- if (ret)
- dbg("%s: failed ret:%d", __func__, ret);
-
- 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;
- int ret;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- /* standby */
- ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
- if (ret)
- dbg("%s: failed ret:%d", __func__, ret);
-
- return ret;
-}
-
-static int tda18218_init(struct dvb_frontend *fe)
-{
- struct tda18218_priv *priv = fe->tuner_priv;
- int ret;
-
- /* TODO: calibrations */
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
- if (ret)
- dbg("%s: failed ret:%d", __func__, ret);
-
- return ret;
-}
-
-static int tda18218_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
- return 0;
-}
-
-static const struct dvb_tuner_ops tda18218_tuner_ops = {
- .info = {
- .name = "NXP TDA18218",
-
- .frequency_min = 174000000,
- .frequency_max = 864000000,
- .frequency_step = 1000,
- },
-
- .release = tda18218_release,
- .init = tda18218_init,
- .sleep = tda18218_sleep,
-
- .set_params = tda18218_set_params,
-
- .get_if_frequency = tda18218_get_if_frequency,
-};
-
-struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, struct tda18218_config *cfg)
-{
- struct tda18218_priv *priv = NULL;
- u8 val;
- int ret;
- /* chip default registers values */
- static u8 def_regs[] = {
- 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
- 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
- 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
- 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
- 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
- 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
- };
-
- priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
-
- priv->cfg = cfg;
- priv->i2c = i2c;
- fe->tuner_priv = priv;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
-
- /* check if the tuner is there */
- ret = tda18218_rd_reg(priv, R00_ID, &val);
- dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
- if (ret || val != def_regs[R00_ID]) {
- kfree(priv);
- return NULL;
- }
-
- info("NXP TDA18218HN successfully identified.");
-
- memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
- sizeof(struct dvb_tuner_ops));
- memcpy(priv->regs, def_regs, sizeof(def_regs));
-
- /* loop-through enabled chip default register values */
- if (priv->cfg->loop_through) {
- priv->regs[R17_PD1] = 0xb0;
- priv->regs[R18_PD2] = 0x59;
- }
-
- /* standby */
- ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
- if (ret)
- dbg("%s: failed ret:%d", __func__, ret);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
-
- return fe;
-}
-EXPORT_SYMBOL(tda18218_attach);
-
-MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
deleted file mode 100644
index ea0550eafe7d..000000000000
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ /dev/null
@@ -1,1510 +0,0 @@
-/* tuner-xc2028
- *
- * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
- *
- * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
- * - frontend interface
- *
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#include <linux/i2c.h>
-#include <asm/div64.h>
-#include <linux/firmware.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <media/tuner.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-#include "tuner-i2c.h"
-#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
-
-#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);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
- "1 keep device energized and with tuner ready all the times.\n"
- " Faster, but consumes more power and keeps the device hotter\n");
-
-static char audio_std[8];
-module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
-MODULE_PARM_DESC(audio_std,
- "Audio standard. XC3028 audio decoder explicitly "
- "needs to know what audio\n"
- "standard is needed for some video standards with audio A2 or NICAM.\n"
- "The valid values are:\n"
- "A2\n"
- "A2/A\n"
- "A2/B\n"
- "NICAM\n"
- "NICAM/A\n"
- "NICAM/B\n");
-
-static char firmware_name[30];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
- "default firmware name\n");
-
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(xc2028_list_mutex);
-
-/* struct for storing firmware table */
-struct firmware_description {
- unsigned int type;
- v4l2_std_id id;
- __u16 int_freq;
- unsigned char *ptr;
- unsigned int size;
-};
-
-struct firmware_properties {
- unsigned int type;
- v4l2_std_id id;
- v4l2_std_id std_req;
- __u16 int_freq;
- unsigned int scode_table;
- int scode_nr;
-};
-
-enum xc2028_state {
- XC2028_NO_FIRMWARE = 0,
- XC2028_WAITING_FIRMWARE,
- XC2028_ACTIVE,
- XC2028_SLEEP,
- XC2028_NODEV,
-};
-
-struct xc2028_data {
- struct list_head hybrid_tuner_instance_list;
- struct tuner_i2c_props i2c_props;
- __u32 frequency;
-
- enum xc2028_state state;
- const char *fname;
-
- struct firmware_description *firm;
- int firm_size;
- __u16 firm_version;
-
- __u16 hwmodel;
- __u16 hwvers;
-
- struct xc2028_ctrl ctrl;
-
- struct firmware_properties cur_fw;
-
- struct mutex lock;
-};
-
-#define i2c_send(priv, buf, size) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \
- if (size != _rc) \
- tuner_info("i2c output error: rc = %d (should be %d)\n",\
- _rc, (int)size); \
- if (priv->ctrl.msleep) \
- msleep(priv->ctrl.msleep); \
- _rc; \
-})
-
-#define i2c_rcv(priv, buf, size) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \
- if (size != _rc) \
- tuner_err("i2c input error: rc = %d (should be %d)\n", \
- _rc, (int)size); \
- _rc; \
-})
-
-#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \
- ibuf, isize); \
- if (isize != _rc) \
- tuner_err("i2c input error: rc = %d (should be %d)\n", \
- _rc, (int)isize); \
- if (priv->ctrl.msleep) \
- msleep(priv->ctrl.msleep); \
- _rc; \
-})
-
-#define send_seq(priv, data...) ({ \
- static u8 _val[] = data; \
- int _rc; \
- if (sizeof(_val) != \
- (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \
- _val, sizeof(_val)))) { \
- tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
- } else if (priv->ctrl.msleep) \
- msleep(priv->ctrl.msleep); \
- _rc; \
-})
-
-static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
-{
- unsigned char buf[2];
- unsigned char ibuf[2];
-
- tuner_dbg("%s %04x called\n", __func__, reg);
-
- buf[0] = reg >> 8;
- buf[1] = (unsigned char) reg;
-
- if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
- return -EIO;
-
- *val = (ibuf[1]) | (ibuf[0] << 8);
- return 0;
-}
-
-#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
-static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-{
- if (type & BASE)
- printk("BASE ");
- if (type & INIT1)
- printk("INIT1 ");
- if (type & F8MHZ)
- printk("F8MHZ ");
- if (type & MTS)
- printk("MTS ");
- if (type & D2620)
- printk("D2620 ");
- if (type & D2633)
- printk("D2633 ");
- if (type & DTV6)
- printk("DTV6 ");
- if (type & QAM)
- printk("QAM ");
- if (type & DTV7)
- printk("DTV7 ");
- if (type & DTV78)
- printk("DTV78 ");
- if (type & DTV8)
- printk("DTV8 ");
- if (type & FM)
- printk("FM ");
- if (type & INPUT1)
- printk("INPUT1 ");
- if (type & LCD)
- printk("LCD ");
- if (type & NOGD)
- printk("NOGD ");
- if (type & MONO)
- printk("MONO ");
- if (type & ATSC)
- printk("ATSC ");
- if (type & IF)
- printk("IF ");
- if (type & LG60)
- printk("LG60 ");
- if (type & ATI638)
- printk("ATI638 ");
- if (type & OREN538)
- printk("OREN538 ");
- if (type & OREN36)
- printk("OREN36 ");
- if (type & TOYOTA388)
- printk("TOYOTA388 ");
- if (type & TOYOTA794)
- printk("TOYOTA794 ");
- if (type & DIBCOM52)
- printk("DIBCOM52 ");
- if (type & ZARLINK456)
- printk("ZARLINK456 ");
- if (type & CHINA)
- printk("CHINA ");
- if (type & F6MHZ)
- printk("F6MHZ ");
- if (type & INPUT2)
- printk("INPUT2 ");
- if (type & SCODE)
- printk("SCODE ");
- if (type & HAS_IF)
- printk("HAS_IF_%d ", int_freq);
-}
-
-static v4l2_std_id parse_audio_std_option(void)
-{
- if (strcasecmp(audio_std, "A2") == 0)
- return V4L2_STD_A2;
- if (strcasecmp(audio_std, "A2/A") == 0)
- return V4L2_STD_A2_A;
- if (strcasecmp(audio_std, "A2/B") == 0)
- return V4L2_STD_A2_B;
- if (strcasecmp(audio_std, "NICAM") == 0)
- return V4L2_STD_NICAM;
- if (strcasecmp(audio_std, "NICAM/A") == 0)
- return V4L2_STD_NICAM_A;
- if (strcasecmp(audio_std, "NICAM/B") == 0)
- return V4L2_STD_NICAM_B;
-
- return 0;
-}
-
-static int check_device_status(struct xc2028_data *priv)
-{
- switch (priv->state) {
- case XC2028_NO_FIRMWARE:
- case XC2028_WAITING_FIRMWARE:
- return -EAGAIN;
- case XC2028_ACTIVE:
- case XC2028_SLEEP:
- return 0;
- case XC2028_NODEV:
- return -ENODEV;
- }
- return 0;
-}
-
-static void free_firmware(struct xc2028_data *priv)
-{
- int i;
- tuner_dbg("%s called\n", __func__);
-
- if (!priv->firm)
- return;
-
- for (i = 0; i < priv->firm_size; i++)
- kfree(priv->firm[i].ptr);
-
- kfree(priv->firm);
-
- priv->firm = NULL;
- priv->firm_size = 0;
- priv->state = XC2028_NO_FIRMWARE;
-
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-}
-
-static int load_all_firmwares(struct dvb_frontend *fe,
- const struct firmware *fw)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- const unsigned char *p, *endp;
- int rc = 0;
- int n, n_array;
- char name[33];
-
- tuner_dbg("%s called\n", __func__);
-
- p = fw->data;
- endp = p + fw->size;
-
- if (fw->size < sizeof(name) - 1 + 2 + 2) {
- tuner_err("Error: firmware file %s has invalid size!\n",
- priv->fname);
- goto corrupt;
- }
-
- memcpy(name, p, sizeof(name) - 1);
- name[sizeof(name) - 1] = 0;
- p += sizeof(name) - 1;
-
- priv->firm_version = get_unaligned_le16(p);
- p += 2;
-
- n_array = get_unaligned_le16(p);
- p += 2;
-
- tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
- n_array, priv->fname, name,
- priv->firm_version >> 8, priv->firm_version & 0xff);
-
- 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;
- goto err;
- }
- priv->firm_size = n_array;
-
- n = -1;
- while (p < endp) {
- __u32 type, size;
- v4l2_std_id id;
- __u16 int_freq = 0;
-
- n++;
- if (n >= n_array) {
- tuner_err("More firmware images in file than "
- "were expected!\n");
- goto corrupt;
- }
-
- /* Checks if there's enough bytes to read */
- if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
- goto header;
-
- type = get_unaligned_le32(p);
- p += sizeof(type);
-
- id = get_unaligned_le64(p);
- p += sizeof(id);
-
- if (type & HAS_IF) {
- int_freq = get_unaligned_le16(p);
- p += sizeof(int_freq);
- if (endp - p < sizeof(size))
- goto header;
- }
-
- size = get_unaligned_le32(p);
- p += sizeof(size);
-
- if (!size || size > endp - p) {
- tuner_err("Firmware type ");
- dump_firm_type(type);
- printk("(%x), id %llx is corrupted "
- "(size=%d, expected %d)\n",
- type, (unsigned long long)id,
- (unsigned)(endp - p), size);
- goto corrupt;
- }
-
- priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
- if (priv->firm[n].ptr == NULL) {
- tuner_err("Not enough memory to load firmware file.\n");
- rc = -ENOMEM;
- goto err;
- }
- tuner_dbg("Reading firmware type ");
- if (debug) {
- dump_firm_type_and_int_freq(type, int_freq);
- printk("(%x), id %llx, size=%d.\n",
- type, (unsigned long long)id, size);
- }
-
- memcpy(priv->firm[n].ptr, p, size);
- priv->firm[n].type = type;
- priv->firm[n].id = id;
- priv->firm[n].size = size;
- priv->firm[n].int_freq = int_freq;
-
- p += size;
- }
-
- if (n + 1 != priv->firm_size) {
- tuner_err("Firmware file is incomplete!\n");
- goto corrupt;
- }
-
- goto done;
-
-header:
- tuner_err("Firmware header is incomplete!\n");
-corrupt:
- rc = -EINVAL;
- tuner_err("Error: firmware file is corrupted!\n");
-
-err:
- tuner_info("Releasing partially loaded firmware file.\n");
- free_firmware(priv);
-
-done:
- if (rc == 0)
- tuner_dbg("Firmware files loaded.\n");
- else
- priv->state = XC2028_NODEV;
-
- return rc;
-}
-
-static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int i, best_i = -1, best_nr_matches = 0;
- unsigned int type_mask = 0;
-
- tuner_dbg("%s called, want type=", __func__);
- if (debug) {
- dump_firm_type(type);
- printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
- }
-
- if (!priv->firm) {
- tuner_err("Error! firmware not loaded\n");
- return -EINVAL;
- }
-
- if (((type & ~SCODE) == 0) && (*id == 0))
- *id = V4L2_STD_PAL;
-
- if (type & BASE)
- type_mask = BASE_TYPES;
- else if (type & SCODE) {
- type &= SCODE_TYPES;
- type_mask = SCODE_TYPES & ~HAS_IF;
- } else if (type & DTV_TYPES)
- type_mask = DTV_TYPES;
- else if (type & STD_SPECIFIC_TYPES)
- type_mask = STD_SPECIFIC_TYPES;
-
- type &= type_mask;
-
- if (!(type & SCODE))
- type_mask = ~0;
-
- /* Seek for exact match */
- for (i = 0; i < priv->firm_size; i++) {
- if ((type == (priv->firm[i].type & type_mask)) &&
- (*id == priv->firm[i].id))
- goto found;
- }
-
- /* Seek for generic video standard match */
- for (i = 0; i < priv->firm_size; i++) {
- v4l2_std_id match_mask;
- int nr_matches;
-
- if (type != (priv->firm[i].type & type_mask))
- continue;
-
- match_mask = *id & priv->firm[i].id;
- if (!match_mask)
- continue;
-
- if ((*id & match_mask) == *id)
- goto found; /* Supports all the requested standards */
-
- nr_matches = hweight64(match_mask);
- if (nr_matches > best_nr_matches) {
- best_nr_matches = nr_matches;
- best_i = i;
- }
- }
-
- if (best_nr_matches > 0) {
- tuner_dbg("Selecting best matching firmware (%d bits) for "
- "type=", best_nr_matches);
- dump_firm_type(type);
- printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
- i = best_i;
- goto found;
- }
-
- /*FIXME: Would make sense to seek for type "hint" match ? */
-
- i = -ENOENT;
- goto ret;
-
-found:
- *id = priv->firm[i].id;
-
-ret:
- tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
- if (debug) {
- dump_firm_type(type);
- printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
- }
- return i;
-}
-
-static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
-{
- struct xc2028_data *priv = fe->tuner_priv;
-
- /* analog side (tuner-core) uses i2c_adap->algo_data.
- * digital side is not guaranteed to have algo_data defined.
- *
- * digital side will always have fe->dvb defined.
- * analog side (tuner-core) doesn't (yet) define fe->dvb.
- */
-
- return (!fe->callback) ? -EINVAL :
- fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
- fe->dvb->priv : priv->i2c_props.adap->algo_data,
- DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
-}
-
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p, *endp, buf[priv->ctrl.max_len];
-
- tuner_dbg("%s called\n", __func__);
-
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
-
- tuner_info("Loading firmware for type=");
- dump_firm_type(priv->firm[pos].type);
- printk("(%x), id %016llx.\n", priv->firm[pos].type,
- (unsigned long long)*id);
-
- p = priv->firm[pos].ptr;
- endp = p + priv->firm[pos].size;
-
- while (p < endp) {
- __u16 size;
-
- /* Checks if there's enough bytes to read */
- if (p + sizeof(size) > endp) {
- tuner_err("Firmware chunk size is wrong\n");
- return -EINVAL;
- }
-
- size = le16_to_cpu(*(__u16 *) p);
- p += sizeof(size);
-
- if (size == 0xffff)
- return 0;
-
- if (!size) {
- /* Special callback command received */
- rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
- if (rc < 0) {
- tuner_err("Error at RESET code %d\n",
- (*p) & 0x7f);
- return -EINVAL;
- }
- continue;
- }
- if (size >= 0xff00) {
- switch (size) {
- case 0xff00:
- rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
- if (rc < 0) {
- tuner_err("Error at RESET code %d\n",
- (*p) & 0x7f);
- return -EINVAL;
- }
- break;
- default:
- tuner_info("Invalid RESET code %d\n",
- size & 0x7f);
- return -EINVAL;
-
- }
- continue;
- }
-
- /* Checks for a sleep command */
- if (size & 0x8000) {
- msleep(size & 0x7fff);
- continue;
- }
-
- if ((size + p > endp)) {
- tuner_err("missing bytes: need %d, have %d\n",
- size, (int)(endp - p));
- return -EINVAL;
- }
-
- buf[0] = *p;
- p++;
- size--;
-
- /* Sends message chunks */
- while (size > 0) {
- int len = (size < priv->ctrl.max_len - 1) ?
- size : priv->ctrl.max_len - 1;
-
- memcpy(buf + 1, p, len);
-
- rc = i2c_send(priv, buf, len + 1);
- if (rc < 0) {
- tuner_err("%d returned from send\n", rc);
- return -EINVAL;
- }
-
- p += len;
- size -= len;
- }
-
- /* silently fail if the frontend doesn't support I2C flush */
- rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
- if ((rc < 0) && (rc != -EINVAL)) {
- tuner_err("error executing flush: %d\n", rc);
- return rc;
- }
- }
- return 0;
-}
-
-static int load_scode(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id, __u16 int_freq, int scode)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p;
-
- tuner_dbg("%s called\n", __func__);
-
- if (!int_freq) {
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
- } else {
- for (pos = 0; pos < priv->firm_size; pos++) {
- if ((priv->firm[pos].int_freq == int_freq) &&
- (priv->firm[pos].type & HAS_IF))
- break;
- }
- if (pos == priv->firm_size)
- return -ENOENT;
- }
-
- p = priv->firm[pos].ptr;
-
- if (priv->firm[pos].type & HAS_IF) {
- if (priv->firm[pos].size != 12 * 16 || scode >= 16)
- return -EINVAL;
- p += 12 * scode;
- } else {
- /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
- * has a 2-byte size header in the firmware format. */
- if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
- le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
- return -EINVAL;
- p += 14 * scode + 2;
- }
-
- tuner_info("Loading SCODE for type=");
- dump_firm_type_and_int_freq(priv->firm[pos].type,
- priv->firm[pos].int_freq);
- printk("(%x), id %016llx.\n", priv->firm[pos].type,
- (unsigned long long)*id);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
- else
- rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
- if (rc < 0)
- return -EIO;
-
- rc = i2c_send(priv, p, 12);
- if (rc < 0)
- return -EIO;
-
- rc = send_seq(priv, {0x00, 0x8c});
- if (rc < 0)
- return -EIO;
-
- return 0;
-}
-
-static int check_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id std, __u16 int_freq)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- struct firmware_properties new_fw;
- int rc, retry_count = 0;
- u16 version, hwmodel;
- v4l2_std_id std0;
-
- tuner_dbg("%s called\n", __func__);
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- if (priv->ctrl.mts && !(type & FM))
- type |= MTS;
-
-retry:
- new_fw.type = type;
- new_fw.id = std;
- new_fw.std_req = std;
- new_fw.scode_table = SCODE | priv->ctrl.scode_table;
- new_fw.scode_nr = 0;
- new_fw.int_freq = int_freq;
-
- tuner_dbg("checking firmware, user requested type=");
- if (debug) {
- dump_firm_type(new_fw.type);
- printk("(%x), id %016llx, ", new_fw.type,
- (unsigned long long)new_fw.std_req);
- if (!int_freq) {
- printk("scode_tbl ");
- dump_firm_type(priv->ctrl.scode_table);
- printk("(%x), ", priv->ctrl.scode_table);
- } else
- printk("int_freq %d, ", new_fw.int_freq);
- printk("scode_nr %d\n", new_fw.scode_nr);
- }
-
- /*
- * No need to reload base firmware if it matches and if the tuner
- * is not at sleep mode
- */
- if ((priv->state == XC2028_ACTIVE) &&
- (((BASE | new_fw.type) & BASE_TYPES) ==
- (priv->cur_fw.type & BASE_TYPES))) {
- tuner_dbg("BASE firmware not changed.\n");
- goto skip_base;
- }
-
- /* Updating BASE - forget about all currently loaded firmware */
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-
- /* Reset is needed before loading firmware */
- rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
- if (rc < 0)
- goto fail;
-
- /* BASE firmwares are all std0 */
- std0 = 0;
- rc = load_firmware(fe, BASE | new_fw.type, &std0);
- if (rc < 0) {
- tuner_err("Error %d while loading base firmware\n",
- rc);
- goto fail;
- }
-
- /* Load INIT1, if needed */
- tuner_dbg("Load init1 firmware, if exists\n");
-
- rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
- if (rc == -ENOENT)
- rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
- &std0);
- if (rc < 0 && rc != -ENOENT) {
- tuner_err("Error %d while loading init1 firmware\n",
- rc);
- goto fail;
- }
-
-skip_base:
- /*
- * No need to reload standard specific firmware if base firmware
- * was not reloaded and requested video standards have not changed.
- */
- if (priv->cur_fw.type == (BASE | new_fw.type) &&
- priv->cur_fw.std_req == std) {
- tuner_dbg("Std-specific firmware already loaded.\n");
- goto skip_std_specific;
- }
-
- /* Reloading std-specific firmware forces a SCODE update */
- priv->cur_fw.scode_table = 0;
-
- rc = load_firmware(fe, new_fw.type, &new_fw.id);
- if (rc == -ENOENT)
- rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
-
- if (rc < 0)
- goto fail;
-
-skip_std_specific:
- if (priv->cur_fw.scode_table == new_fw.scode_table &&
- priv->cur_fw.scode_nr == new_fw.scode_nr) {
- tuner_dbg("SCODE firmware already loaded.\n");
- goto check_device;
- }
-
- if (new_fw.type & FM)
- goto check_device;
-
- /* Load SCODE firmware, if exists */
- tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
-
- rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
- new_fw.int_freq, new_fw.scode_nr);
-
-check_device:
- if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
- xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
- tuner_err("Unable to read tuner registers.\n");
- goto fail;
- }
-
- tuner_dbg("Device is Xceive %d version %d.%d, "
- "firmware version %d.%d\n",
- hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
- (version & 0xf0) >> 4, version & 0xf);
-
-
- if (priv->ctrl.read_not_reliable)
- goto read_not_reliable;
-
- /* Check firmware version against what we downloaded. */
- if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
- if (!priv->ctrl.read_not_reliable) {
- tuner_err("Incorrect readback of firmware version.\n");
- goto fail;
- } else {
- tuner_err("Returned an incorrect version. However, "
- "read is not reliable enough. Ignoring it.\n");
- hwmodel = 3028;
- }
- }
-
- /* Check that the tuner hardware model remains consistent over time. */
- if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
- priv->hwmodel = hwmodel;
- priv->hwvers = version & 0xff00;
- } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
- priv->hwvers != (version & 0xff00)) {
- tuner_err("Read invalid device hardware information - tuner "
- "hung?\n");
- goto fail;
- }
-
-read_not_reliable:
- memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-
- /*
- * By setting BASE in cur_fw.type only after successfully loading all
- * firmwares, we can:
- * 1. Identify that BASE firmware with type=0 has been loaded;
- * 2. Tell whether BASE firmware was just changed the next time through.
- */
- priv->cur_fw.type |= BASE;
- priv->state = XC2028_ACTIVE;
-
- return 0;
-
-fail:
- priv->state = XC2028_SLEEP;
-
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
- if (retry_count < 8) {
- msleep(50);
- retry_count++;
- tuner_dbg("Retrying firmware load\n");
- goto retry;
- }
-
- if (rc == -ENOENT)
- rc = -EINVAL;
- return rc;
-}
-
-static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- u16 frq_lock, signal = 0;
- int rc, i;
-
- tuner_dbg("%s called\n", __func__);
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- mutex_lock(&priv->lock);
-
- /* Sync Lock Indicator */
- for (i = 0; i < 3; i++) {
- rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
- if (rc < 0)
- goto ret;
-
- if (frq_lock)
- break;
- msleep(6);
- }
-
- /* Frequency didn't lock */
- if (frq_lock == 2)
- goto ret;
-
- /* Get SNR of the video signal */
- rc = xc2028_get_reg(priv, XREG_SNR, &signal);
- if (rc < 0)
- goto ret;
-
- /* Signal level is 3 bits only */
-
- signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
-
-ret:
- mutex_unlock(&priv->lock);
-
- *strength = signal;
-
- tuner_dbg("signal strength is %d\n", signal);
-
- return rc;
-}
-
-static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int i, rc;
- u16 frq_lock = 0;
- s16 afc_reg = 0;
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- mutex_lock(&priv->lock);
-
- /* Sync Lock Indicator */
- for (i = 0; i < 3; i++) {
- rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
- if (rc < 0)
- goto ret;
-
- if (frq_lock)
- break;
- msleep(6);
- }
-
- /* Frequency didn't lock */
- if (frq_lock == 2)
- goto ret;
-
- /* Get AFC */
- rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
- if (rc < 0)
- goto ret;
-
- *afc = afc_reg * 15625; /* Hz */
-
- tuner_dbg("AFC is %d Hz\n", *afc);
-
-ret:
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-#define DIV 15625
-
-static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
- enum v4l2_tuner_type new_type,
- unsigned int type,
- v4l2_std_id std,
- u16 int_freq)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = -EINVAL;
- unsigned char buf[4];
- u32 div, offset = 0;
-
- tuner_dbg("%s called\n", __func__);
-
- mutex_lock(&priv->lock);
-
- tuner_dbg("should set frequency %d kHz\n", freq / 1000);
-
- if (check_firmware(fe, type, std, int_freq) < 0)
- goto ret;
-
- /* On some cases xc2028 can disable video output, if
- * very weak signals are received. By sending a soft
- * reset, this is re-enabled. So, it is better to always
- * send a soft reset before changing channels, to be sure
- * that xc2028 will be in a safe state.
- * Maybe this might also be needed for DTV.
- */
- switch (new_type) {
- case V4L2_TUNER_ANALOG_TV:
- rc = send_seq(priv, {0x00, 0x00});
-
- /* Analog mode requires offset = 0 */
- break;
- case V4L2_TUNER_RADIO:
- /* Radio mode requires offset = 0 */
- break;
- case V4L2_TUNER_DIGITAL_TV:
- /*
- * Digital modes require an offset to adjust to the
- * proper frequency. The offset depends on what
- * firmware version is used.
- */
-
- /*
- * Adjust to the center frequency. This is calculated by the
- * formula: offset = 1.25MHz - BW/2
- * 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 /* DTV7 or DTV8 or DTV78 */
- offset = 2750000;
-
- /*
- * xc3028 additional "magic"
- * Depending on the firmware version, it needs some adjustments
- * to properly centralize the frequency. This seems to be
- * needed to compensate the SCODE table adjustments made by
- * newer firmwares
- */
-
- /*
- * 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 0
- /*
- * Still need tests for XC3028L (firmware 3.2 or upper)
- * So, for now, let's just comment the per-firmware
- * version of this change. Reports with xc3028l working
- * with and without the lines bellow are welcome
- */
-
- if (priv->firm_version < 0x0302) {
- if (priv->cur_fw.type & DTV7)
- offset += 500000;
- } else {
- if (priv->cur_fw.type & DTV7)
- offset -= 300000;
- else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
- offset += 200000;
- }
-#endif
- }
-
- div = (freq - offset + DIV / 2) / DIV;
-
- /* CMD= Set frequency */
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
- if (rc < 0)
- goto ret;
-
- /* Return code shouldn't be checked.
- The reset CLK is needed only with tm6000.
- Driver should work fine even if this fails.
- */
- if (priv->ctrl.msleep)
- msleep(priv->ctrl.msleep);
- do_tuner_callback(fe, XC2028_RESET_CLK, 1);
-
- msleep(10);
-
- buf[0] = 0xff & (div >> 24);
- buf[1] = 0xff & (div >> 16);
- buf[2] = 0xff & (div >> 8);
- buf[3] = 0xff & (div);
-
- rc = i2c_send(priv, buf, sizeof(buf));
- if (rc < 0)
- goto ret;
- msleep(100);
-
- priv->frequency = freq;
-
- tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
- buf[0], buf[1], buf[2], buf[3],
- freq / 1000000, (freq % 1000000) / 1000);
-
- rc = 0;
-
-ret:
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-static int xc2028_set_analog_freq(struct dvb_frontend *fe,
- struct analog_parameters *p)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- unsigned int type=0;
-
- tuner_dbg("%s called\n", __func__);
-
- if (p->mode == V4L2_TUNER_RADIO) {
- type |= FM;
- if (priv->ctrl.input1)
- type |= INPUT1;
- return generic_set_freq(fe, (625l * p->frequency) / 10,
- V4L2_TUNER_RADIO, type, 0, 0);
- }
-
- /* if std is not defined, choose one */
- if (!p->std)
- p->std = V4L2_STD_MN;
-
- /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
- if (!(p->std & V4L2_STD_MN))
- type |= F8MHZ;
-
- /* Add audio hack to std mask */
- p->std |= parse_audio_std_option();
-
- return generic_set_freq(fe, 62500l * p->frequency,
- V4L2_TUNER_ANALOG_TV, type, p->std, 0);
-}
-
-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;
- int rc;
- unsigned int type = 0;
- u16 demod = 0;
-
- tuner_dbg("%s called\n", __func__);
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- 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 <= 6000000)
- type |= QAM;
-
- switch (priv->ctrl.type) {
- case XC2028_D2633:
- type |= D2633;
- break;
- case XC2028_D2620:
- type |= D2620;
- break;
- case XC2028_AUTO:
- default:
- /* Zarlink seems to need D2633 */
- if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
- type |= D2633;
- 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 */
- if (priv->ctrl.demod) {
- demod = priv->ctrl.demod;
-
- /*
- * Newer firmwares require a 200 kHz offset only for ATSC
- */
- if (type == ATSC || priv->firm_version < 0x0302)
- demod += 200;
- /*
- * The DTV7 S-code table needs a 700 kHz shift.
- *
- * DTV7 is only used in Australia. Germany or Italy may also
- * use this firmware after initialization, but a tune to a UHF
- * channel should then cause DTV78 to be used.
- *
- * Unfortunately, on real-field tests, the s-code offset
- * didn't work as expected, as reported by
- * Robert Lowery <rglowery@exemail.com.au>
- */
- }
-
- return generic_set_freq(fe, c->frequency,
- V4L2_TUNER_DIGITAL_TV, type, 0, demod);
-}
-
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc;
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- /* Avoid firmware reload on slow devices or if PM disabled */
- if (no_poweroff || priv->ctrl.disable_power_mgmt)
- return 0;
-
- tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
- if (debug > 1) {
- tuner_dbg("Printing sleep stack trace:\n");
- dump_stack();
- }
-
- mutex_lock(&priv->lock);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
-
- priv->state = XC2028_SLEEP;
-
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-static int xc2028_dvb_release(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
-
- tuner_dbg("%s called\n", __func__);
-
- mutex_lock(&xc2028_list_mutex);
-
- /* only perform final cleanup if this is the last instance */
- if (hybrid_tuner_report_instance_count(priv) == 1) {
- free_firmware(priv);
- kfree(priv->ctrl.fname);
- priv->ctrl.fname = NULL;
- }
-
- if (priv)
- hybrid_tuner_release_state(priv);
-
- mutex_unlock(&xc2028_list_mutex);
-
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc;
-
- tuner_dbg("%s called\n", __func__);
-
- rc = check_device_status(priv);
- if (rc < 0)
- return rc;
-
- *frequency = priv->frequency;
-
- return 0;
-}
-
-static void load_firmware_cb(const struct firmware *fw,
- void *context)
-{
- struct dvb_frontend *fe = context;
- struct xc2028_data *priv = fe->tuner_priv;
- int rc;
-
- tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
- if (!fw) {
- tuner_err("Could not load firmware %s.\n", priv->fname);
- priv->state = XC2028_NODEV;
- return;
- }
-
- rc = load_all_firmwares(fe, fw);
-
- release_firmware(fw);
-
- if (rc < 0)
- return;
- priv->state = XC2028_SLEEP;
-}
-
-static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- struct xc2028_ctrl *p = priv_cfg;
- int rc = 0;
-
- tuner_dbg("%s called\n", __func__);
-
- mutex_lock(&priv->lock);
-
- /*
- * Copy the config data.
- * For the firmware name, keep a local copy of the string,
- * in order to avoid troubles during device release.
- */
- if (priv->ctrl.fname)
- kfree(priv->ctrl.fname);
- memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
- if (p->fname) {
- priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
- if (priv->ctrl.fname == NULL)
- rc = -ENOMEM;
- }
-
- /*
- * If firmware name changed, frees firmware. As free_firmware will
- * reset the status to NO_FIRMWARE, this forces a new request_firmware
- */
- if (!firmware_name[0] && p->fname &&
- priv->fname && strcmp(p->fname, priv->fname))
- free_firmware(priv);
-
- if (priv->ctrl.max_len < 9)
- priv->ctrl.max_len = 13;
-
- if (priv->state == XC2028_NO_FIRMWARE) {
- if (!firmware_name[0])
- priv->fname = priv->ctrl.fname;
- else
- priv->fname = firmware_name;
-
- rc = request_firmware_nowait(THIS_MODULE, 1,
- priv->fname,
- priv->i2c_props.adap->dev.parent,
- GFP_KERNEL,
- fe, load_firmware_cb);
- if (rc < 0) {
- tuner_err("Failed to request firmware %s\n",
- priv->fname);
- priv->state = XC2028_NODEV;
- }
- priv->state = XC2028_WAITING_FIRMWARE;
- }
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
- .info = {
- .name = "Xceive XC3028",
- .frequency_min = 42000000,
- .frequency_max = 864000000,
- .frequency_step = 50000,
- },
-
- .set_config = xc2028_set_config,
- .set_analog_params = xc2028_set_analog_freq,
- .release = xc2028_dvb_release,
- .get_frequency = xc2028_get_frequency,
- .get_rf_strength = xc2028_signal,
- .get_afc = xc2028_get_afc,
- .set_params = xc2028_set_params,
- .sleep = xc2028_sleep,
-};
-
-struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
- struct xc2028_config *cfg)
-{
- struct xc2028_data *priv;
- int instance;
-
- if (debug)
- printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
-
- if (NULL == cfg)
- return NULL;
-
- if (!fe) {
- printk(KERN_ERR "xc2028: No frontend!\n");
- return NULL;
- }
-
- mutex_lock(&xc2028_list_mutex);
-
- instance = hybrid_tuner_request_state(struct xc2028_data, priv,
- hybrid_tuner_instance_list,
- cfg->i2c_adap, cfg->i2c_addr,
- "xc2028");
- switch (instance) {
- case 0:
- /* memory allocation failure */
- goto fail;
- break;
- case 1:
- /* new tuner instance */
- priv->ctrl.max_len = 13;
-
- mutex_init(&priv->lock);
-
- fe->tuner_priv = priv;
- break;
- case 2:
- /* existing tuner instance */
- fe->tuner_priv = priv;
- break;
- }
-
- memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
- sizeof(xc2028_dvb_tuner_ops));
-
- tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
-
- if (cfg->ctrl)
- xc2028_set_config(fe, cfg->ctrl);
-
- mutex_unlock(&xc2028_list_mutex);
-
- return fe;
-fail:
- mutex_unlock(&xc2028_list_mutex);
-
- xc2028_dvb_release(fe);
- return NULL;
-}
-
-EXPORT_SYMBOL(xc2028_attach);
-
-MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
-MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
-MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
deleted file mode 100644
index 68397110b7d9..000000000000
--- a/drivers/media/common/tuners/xc4000.c
+++ /dev/null
@@ -1,1758 +0,0 @@
-/*
- * Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
- *
- * Copyright (c) 2007 Xceive Corporation
- * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
- * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
- * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <asm/unaligned.h>
-
-#include "dvb_frontend.h"
-
-#include "xc4000.h"
-#include "tuner-i2c.h"
-#include "tuner-xc2028-types.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
- "0 (default): use device-specific default mode).");
-
-static int audio_std;
-module_param(audio_std, int, 0644);
-MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
- "needs to know what audio standard is needed for some video standards "
- "with audio A2 or NICAM. The valid settings are a sum of:\n"
- " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
- " 2: use A2 instead of NICAM or BTSC\n"
- " 4: use SECAM/K3 instead of K1\n"
- " 8: use PAL-D/K audio for SECAM-D/K\n"
- "16: use FM radio input 1 instead of input 2\n"
- "32: use mono audio (the lower three bits are ignored)");
-
-static char firmware_name[30];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
- "default firmware name.");
-
-static DEFINE_MUTEX(xc4000_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
- printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
-
-/* struct for storing firmware table */
-struct firmware_description {
- unsigned int type;
- v4l2_std_id id;
- __u16 int_freq;
- unsigned char *ptr;
- unsigned int size;
-};
-
-struct firmware_properties {
- unsigned int type;
- v4l2_std_id id;
- v4l2_std_id std_req;
- __u16 int_freq;
- unsigned int scode_table;
- int scode_nr;
-};
-
-struct xc4000_priv {
- struct tuner_i2c_props i2c_props;
- struct list_head hybrid_tuner_instance_list;
- struct firmware_description *firm;
- int firm_size;
- u32 if_khz;
- u32 freq_hz;
- u32 bandwidth;
- u8 video_standard;
- u8 rf_mode;
- u8 default_pm;
- u8 dvb_amplitude;
- u8 set_smoothedcvbs;
- u8 ignore_i2c_write_errors;
- __u16 firm_version;
- struct firmware_properties cur_fw;
- __u16 hwmodel;
- __u16 hwvers;
- struct mutex lock;
-};
-
-#define XC4000_AUDIO_STD_B 1
-#define XC4000_AUDIO_STD_A2 2
-#define XC4000_AUDIO_STD_K3 4
-#define XC4000_AUDIO_STD_L 8
-#define XC4000_AUDIO_STD_INPUT1 16
-#define XC4000_AUDIO_STD_MONO 32
-
-#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
-
-/* Misc Defines */
-#define MAX_TV_STANDARD 24
-#define XC_MAX_I2C_WRITE_LENGTH 64
-#define XC_POWERED_DOWN 0x80000000U
-
-/* Signal Types */
-#define XC_RF_MODE_AIR 0
-#define XC_RF_MODE_CABLE 1
-
-/* Product id */
-#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
-#define XC_PRODUCT_ID_XC4000 0x0FA0
-#define XC_PRODUCT_ID_XC4100 0x1004
-
-/* Registers (Write-only) */
-#define XREG_INIT 0x00
-#define XREG_VIDEO_MODE 0x01
-#define XREG_AUDIO_MODE 0x02
-#define XREG_RF_FREQ 0x03
-#define XREG_D_CODE 0x04
-#define XREG_DIRECTSITTING_MODE 0x05
-#define XREG_SEEK_MODE 0x06
-#define XREG_POWER_DOWN 0x08
-#define XREG_SIGNALSOURCE 0x0A
-#define XREG_SMOOTHEDCVBS 0x0E
-#define XREG_AMPLITUDE 0x10
-
-/* Registers (Read-only) */
-#define XREG_ADC_ENV 0x00
-#define XREG_QUALITY 0x01
-#define XREG_FRAME_LINES 0x02
-#define XREG_HSYNC_FREQ 0x03
-#define XREG_LOCK 0x04
-#define XREG_FREQ_ERROR 0x05
-#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
- the driver for documentation purposes.
-
- This represents an I2C firmware file encoded as a
- string of unsigned char. Format is as follows:
-
- char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB
- char[1 ]=len0_LSB -> length of first write transaction
- char[2 ]=data0 -> first byte to be sent
- char[3 ]=data1
- char[4 ]=data2
- char[ ]=...
- char[M ]=dataN -> last byte to be sent
- char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB
- char[M+2]=len1_LSB -> length of second write transaction
- char[M+3]=data0
- char[M+4]=data1
- ...
- etc.
-
- The [len] value should be interpreted as follows:
-
- len= len_MSB _ len_LSB
- len=1111_1111_1111_1111 : End of I2C_SEQUENCE
- len=0000_0000_0000_0000 : Reset command: Do hardware reset
- len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767)
- len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms
-
- For the RESET and WAIT commands, the two following bytes will contain
- immediately the length of the following transaction.
-*/
-
-struct XC_TV_STANDARD {
- const char *Name;
- u16 audio_mode;
- u16 video_mode;
- u16 int_freq;
-};
-
-/* Tuner standards */
-#define XC4000_MN_NTSC_PAL_BTSC 0
-#define XC4000_MN_NTSC_PAL_A2 1
-#define XC4000_MN_NTSC_PAL_EIAJ 2
-#define XC4000_MN_NTSC_PAL_Mono 3
-#define XC4000_BG_PAL_A2 4
-#define XC4000_BG_PAL_NICAM 5
-#define XC4000_BG_PAL_MONO 6
-#define XC4000_I_PAL_NICAM 7
-#define XC4000_I_PAL_NICAM_MONO 8
-#define XC4000_DK_PAL_A2 9
-#define XC4000_DK_PAL_NICAM 10
-#define XC4000_DK_PAL_MONO 11
-#define XC4000_DK_SECAM_A2DK1 12
-#define XC4000_DK_SECAM_A2LDK3 13
-#define XC4000_DK_SECAM_A2MONO 14
-#define XC4000_DK_SECAM_NICAM 15
-#define XC4000_L_SECAM_NICAM 16
-#define XC4000_LC_SECAM_NICAM 17
-#define XC4000_DTV6 18
-#define XC4000_DTV8 19
-#define XC4000_DTV7_8 20
-#define XC4000_DTV7 21
-#define XC4000_FM_Radio_INPUT2 22
-#define XC4000_FM_Radio_INPUT1 23
-
-static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
- {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500},
- {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600},
- {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500},
- {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500},
- {"B/G-PAL-A2", 0x0000, 0x8159, 5640},
- {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740},
- {"B/G-PAL-MONO", 0x0078, 0x8159, 5500},
- {"I-PAL-NICAM", 0x0080, 0x8049, 6240},
- {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000},
- {"D/K-PAL-A2", 0x0000, 0x8049, 6380},
- {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200},
- {"D/K-PAL-MONO", 0x0078, 0x8049, 6500},
- {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340},
- {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000},
- {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500},
- {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200},
- {"L-SECAM-NICAM", 0x8080, 0x0009, 6200},
- {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200},
- {"DTV6", 0x00C0, 0x8002, 0},
- {"DTV8", 0x00C0, 0x800B, 0},
- {"DTV7/8", 0x00C0, 0x801B, 0},
- {"DTV7", 0x00C0, 0x8007, 0},
- {"FM Radio-INPUT2", 0x0008, 0x9800, 10700},
- {"FM Radio-INPUT1", 0x0008, 0x9000, 10700}
-};
-
-static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
-static int xc4000_tuner_reset(struct dvb_frontend *fe);
-static void xc_debug_dump(struct xc4000_priv *priv);
-
-static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
-{
- struct i2c_msg msg = { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- if (priv->ignore_i2c_write_errors == 0) {
- printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
- len);
- if (len == 4) {
- printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0],
- buf[1], buf[2], buf[3]);
- }
- return -EREMOTEIO;
- }
- }
- return 0;
-}
-
-static int xc4000_tuner_reset(struct dvb_frontend *fe)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- int ret;
-
- dprintk(1, "%s()\n", __func__);
-
- if (fe->callback) {
- ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
- fe->dvb->priv :
- priv->i2c_props.adap->algo_data,
- DVB_FRONTEND_COMPONENT_TUNER,
- XC4000_TUNER_RESET, 0);
- if (ret) {
- printk(KERN_ERR "xc4000: reset failed\n");
- return -EREMOTEIO;
- }
- } else {
- printk(KERN_ERR "xc4000: no tuner reset callback function, "
- "fatal\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
-{
- u8 buf[4];
- int result;
-
- buf[0] = (regAddr >> 8) & 0xFF;
- buf[1] = regAddr & 0xFF;
- buf[2] = (i2cData >> 8) & 0xFF;
- buf[3] = i2cData & 0xFF;
- result = xc_send_i2c_data(priv, buf, 4);
-
- return result;
-}
-
-static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
-
- int i, nbytes_to_send, result;
- unsigned int len, pos, index;
- u8 buf[XC_MAX_I2C_WRITE_LENGTH];
-
- index = 0;
- while ((i2c_sequence[index] != 0xFF) ||
- (i2c_sequence[index + 1] != 0xFF)) {
- len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
- if (len == 0x0000) {
- /* RESET command */
- /* NOTE: this is ignored, as the reset callback was */
- /* already called by check_firmware() */
- index += 2;
- } else if (len & 0x8000) {
- /* WAIT command */
- msleep(len & 0x7FFF);
- index += 2;
- } else {
- /* Send i2c data whilst ensuring individual transactions
- * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
- */
- index += 2;
- buf[0] = i2c_sequence[index];
- buf[1] = i2c_sequence[index + 1];
- pos = 2;
- while (pos < len) {
- if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
- nbytes_to_send =
- XC_MAX_I2C_WRITE_LENGTH;
- else
- nbytes_to_send = (len - pos + 2);
- for (i = 2; i < nbytes_to_send; i++) {
- buf[i] = i2c_sequence[index + pos +
- i - 2];
- }
- result = xc_send_i2c_data(priv, buf,
- nbytes_to_send);
-
- if (result != 0)
- return result;
-
- pos += nbytes_to_send - 2;
- }
- index += len;
- }
- }
- return 0;
-}
-
-static int xc_set_tv_standard(struct xc4000_priv *priv,
- u16 video_mode, u16 audio_mode)
-{
- int ret;
- dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
- dprintk(1, "%s() Standard = %s\n",
- __func__,
- xc4000_standard[priv->video_standard].Name);
-
- /* Don't complain when the request fails because of i2c stretching */
- priv->ignore_i2c_write_errors = 1;
-
- ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
- if (ret == 0)
- ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
-
- priv->ignore_i2c_write_errors = 0;
-
- return ret;
-}
-
-static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
-{
- dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
- rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
-
- if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
- rf_mode = XC_RF_MODE_CABLE;
- printk(KERN_ERR
- "%s(), Invalid mode, defaulting to CABLE",
- __func__);
- }
- return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
-}
-
-static const struct dvb_tuner_ops xc4000_tuner_ops;
-
-static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
-{
- u16 freq_code;
-
- dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
- if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
- (freq_hz < xc4000_tuner_ops.info.frequency_min))
- return -EINVAL;
-
- freq_code = (u16)(freq_hz / 15625);
-
- /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
- FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
- only be used for fast scanning for channel lock) */
- /* WAS: XREG_FINERFREQ */
- return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
-}
-
-static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
-{
- return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
-}
-
-static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
-{
- int result;
- u16 regData;
- u32 tmp;
-
- result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
- if (result != 0)
- return result;
-
- tmp = (u32)regData & 0xFFFFU;
- tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
- (*freq_error_hz) = tmp * 15625;
- return result;
-}
-
-static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
-{
- return xc4000_readreg(priv, XREG_LOCK, lock_status);
-}
-
-static int xc_get_version(struct xc4000_priv *priv,
- u8 *hw_majorversion, u8 *hw_minorversion,
- u8 *fw_majorversion, u8 *fw_minorversion)
-{
- u16 data;
- int result;
-
- result = xc4000_readreg(priv, XREG_VERSION, &data);
- if (result != 0)
- return result;
-
- (*hw_majorversion) = (data >> 12) & 0x0F;
- (*hw_minorversion) = (data >> 8) & 0x0F;
- (*fw_majorversion) = (data >> 4) & 0x0F;
- (*fw_minorversion) = data & 0x0F;
-
- return 0;
-}
-
-static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
-{
- u16 regData;
- int result;
-
- result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
- if (result != 0)
- return result;
-
- (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
- return result;
-}
-
-static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
-{
- return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
-}
-
-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;
- int watchdog_count = 40;
-
- while ((lock_state == 0) && (watchdog_count > 0)) {
- xc_get_lock_status(priv, &lock_state);
- if (lock_state != 1) {
- msleep(5);
- watchdog_count--;
- }
- }
- return lock_state;
-}
-
-static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
-{
- int found = 1;
- int result;
-
- dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
- /* Don't complain when the request fails because of i2c stretching */
- priv->ignore_i2c_write_errors = 1;
- result = xc_set_rf_frequency(priv, freq_hz);
- priv->ignore_i2c_write_errors = 0;
-
- if (result != 0)
- return 0;
-
- /* wait for lock only in analog TV mode */
- if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
- if (xc_wait_for_lock(priv) != 1)
- found = 0;
- }
-
- /* Wait for stats to stabilize.
- * Frame Lines needs two frame times after initial lock
- * before it is valid.
- */
- msleep(debug ? 100 : 10);
-
- if (debug)
- xc_debug_dump(priv);
-
- return found;
-}
-
-static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
-{
- u8 buf[2] = { reg >> 8, reg & 0xff };
- u8 bval[2] = { 0, 0 };
- struct i2c_msg msg[2] = {
- { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
- };
-
- if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
- printk(KERN_ERR "xc4000: I2C read failed\n");
- return -EREMOTEIO;
- }
-
- *val = (bval[0] << 8) | bval[1];
- return 0;
-}
-
-#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
-static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-{
- if (type & BASE)
- printk(KERN_CONT "BASE ");
- if (type & INIT1)
- printk(KERN_CONT "INIT1 ");
- if (type & F8MHZ)
- printk(KERN_CONT "F8MHZ ");
- if (type & MTS)
- printk(KERN_CONT "MTS ");
- if (type & D2620)
- printk(KERN_CONT "D2620 ");
- if (type & D2633)
- printk(KERN_CONT "D2633 ");
- if (type & DTV6)
- printk(KERN_CONT "DTV6 ");
- if (type & QAM)
- printk(KERN_CONT "QAM ");
- if (type & DTV7)
- printk(KERN_CONT "DTV7 ");
- if (type & DTV78)
- printk(KERN_CONT "DTV78 ");
- if (type & DTV8)
- printk(KERN_CONT "DTV8 ");
- if (type & FM)
- printk(KERN_CONT "FM ");
- if (type & INPUT1)
- printk(KERN_CONT "INPUT1 ");
- if (type & LCD)
- printk(KERN_CONT "LCD ");
- if (type & NOGD)
- printk(KERN_CONT "NOGD ");
- if (type & MONO)
- printk(KERN_CONT "MONO ");
- if (type & ATSC)
- printk(KERN_CONT "ATSC ");
- if (type & IF)
- printk(KERN_CONT "IF ");
- if (type & LG60)
- printk(KERN_CONT "LG60 ");
- if (type & ATI638)
- printk(KERN_CONT "ATI638 ");
- if (type & OREN538)
- printk(KERN_CONT "OREN538 ");
- if (type & OREN36)
- printk(KERN_CONT "OREN36 ");
- if (type & TOYOTA388)
- printk(KERN_CONT "TOYOTA388 ");
- if (type & TOYOTA794)
- printk(KERN_CONT "TOYOTA794 ");
- if (type & DIBCOM52)
- printk(KERN_CONT "DIBCOM52 ");
- if (type & ZARLINK456)
- printk(KERN_CONT "ZARLINK456 ");
- if (type & CHINA)
- printk(KERN_CONT "CHINA ");
- if (type & F6MHZ)
- printk(KERN_CONT "F6MHZ ");
- if (type & INPUT2)
- printk(KERN_CONT "INPUT2 ");
- if (type & SCODE)
- printk(KERN_CONT "SCODE ");
- if (type & HAS_IF)
- printk(KERN_CONT "HAS_IF_%d ", int_freq);
-}
-
-static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- int i, best_i = -1;
- unsigned int best_nr_diffs = 255U;
-
- if (!priv->firm) {
- printk(KERN_ERR "Error! firmware not loaded\n");
- return -EINVAL;
- }
-
- if (((type & ~SCODE) == 0) && (*id == 0))
- *id = V4L2_STD_PAL;
-
- /* Seek for generic video standard match */
- for (i = 0; i < priv->firm_size; i++) {
- v4l2_std_id id_diff_mask =
- (priv->firm[i].id ^ (*id)) & (*id);
- unsigned int type_diff_mask =
- (priv->firm[i].type ^ type)
- & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
- unsigned int nr_diffs;
-
- if (type_diff_mask
- & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
- continue;
-
- nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
- if (!nr_diffs) /* Supports all the requested standards */
- goto found;
-
- if (nr_diffs < best_nr_diffs) {
- best_nr_diffs = nr_diffs;
- best_i = i;
- }
- }
-
- /* FIXME: Would make sense to seek for type "hint" match ? */
- if (best_i < 0) {
- i = -ENOENT;
- goto ret;
- }
-
- if (best_nr_diffs > 0U) {
- printk(KERN_WARNING
- "Selecting best matching firmware (%u bits differ) for "
- "type=(%x), id %016llx:\n",
- best_nr_diffs, type, (unsigned long long)*id);
- i = best_i;
- }
-
-found:
- *id = priv->firm[i].id;
-
-ret:
- if (debug) {
- printk(KERN_DEBUG "%s firmware for type=",
- (i < 0) ? "Can't find" : "Found");
- dump_firm_type(type);
- printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
- }
- return i;
-}
-
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p;
-
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
-
- p = priv->firm[pos].ptr;
-
- /* Don't complain when the request fails because of i2c stretching */
- priv->ignore_i2c_write_errors = 1;
-
- rc = xc_load_i2c_sequence(fe, p);
-
- priv->ignore_i2c_write_errors = 0;
-
- return rc;
-}
-
-static int xc4000_fwupload(struct dvb_frontend *fe)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- const struct firmware *fw = NULL;
- const unsigned char *p, *endp;
- int rc = 0;
- int n, n_array;
- char name[33];
- const char *fname;
-
- if (firmware_name[0] != '\0')
- fname = firmware_name;
- else
- fname = XC4000_DEFAULT_FIRMWARE;
-
- dprintk(1, "Reading firmware %s\n", fname);
- rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
- if (rc < 0) {
- if (rc == -ENOENT)
- printk(KERN_ERR "Error: firmware %s not found.\n", fname);
- else
- printk(KERN_ERR "Error %d while requesting firmware %s\n",
- rc, fname);
-
- return rc;
- }
- p = fw->data;
- endp = p + fw->size;
-
- if (fw->size < sizeof(name) - 1 + 2 + 2) {
- printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
- fname);
- goto corrupt;
- }
-
- memcpy(name, p, sizeof(name) - 1);
- name[sizeof(name) - 1] = '\0';
- p += sizeof(name) - 1;
-
- priv->firm_version = get_unaligned_le16(p);
- p += 2;
-
- n_array = get_unaligned_le16(p);
- p += 2;
-
- dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
- n_array, fname, name,
- priv->firm_version >> 8, priv->firm_version & 0xff);
-
- 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;
- goto done;
- }
- priv->firm_size = n_array;
-
- n = -1;
- while (p < endp) {
- __u32 type, size;
- v4l2_std_id id;
- __u16 int_freq = 0;
-
- n++;
- if (n >= n_array) {
- printk(KERN_ERR "More firmware images in file than "
- "were expected!\n");
- goto corrupt;
- }
-
- /* Checks if there's enough bytes to read */
- if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
- goto header;
-
- type = get_unaligned_le32(p);
- p += sizeof(type);
-
- id = get_unaligned_le64(p);
- p += sizeof(id);
-
- if (type & HAS_IF) {
- int_freq = get_unaligned_le16(p);
- p += sizeof(int_freq);
- if (endp - p < sizeof(size))
- goto header;
- }
-
- size = get_unaligned_le32(p);
- p += sizeof(size);
-
- if (!size || size > endp - p) {
- printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
- type, (unsigned long long)id,
- (unsigned)(endp - p), size);
- goto corrupt;
- }
-
- priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
- if (priv->firm[n].ptr == NULL) {
- printk(KERN_ERR "Not enough memory to load firmware file.\n");
- rc = -ENOMEM;
- goto done;
- }
-
- if (debug) {
- printk(KERN_DEBUG "Reading firmware type ");
- dump_firm_type_and_int_freq(type, int_freq);
- printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
- type, (unsigned long long)id, size);
- }
-
- memcpy(priv->firm[n].ptr, p, size);
- priv->firm[n].type = type;
- priv->firm[n].id = id;
- priv->firm[n].size = size;
- priv->firm[n].int_freq = int_freq;
-
- p += size;
- }
-
- if (n + 1 != priv->firm_size) {
- printk(KERN_ERR "Firmware file is incomplete!\n");
- goto corrupt;
- }
-
- goto done;
-
-header:
- printk(KERN_ERR "Firmware header is incomplete!\n");
-corrupt:
- rc = -EINVAL;
- printk(KERN_ERR "Error: firmware file is corrupted!\n");
-
-done:
- release_firmware(fw);
- if (rc == 0)
- dprintk(1, "Firmware files loaded.\n");
-
- return rc;
-}
-
-static int load_scode(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id, __u16 int_freq, int scode)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p;
- u8 scode_buf[13];
- u8 indirect_mode[5];
-
- dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
-
- if (!int_freq) {
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
- } else {
- for (pos = 0; pos < priv->firm_size; pos++) {
- if ((priv->firm[pos].int_freq == int_freq) &&
- (priv->firm[pos].type & HAS_IF))
- break;
- }
- if (pos == priv->firm_size)
- return -ENOENT;
- }
-
- p = priv->firm[pos].ptr;
-
- if (priv->firm[pos].size != 12 * 16 || scode >= 16)
- return -EINVAL;
- p += 12 * scode;
-
- if (debug) {
- tuner_info("Loading SCODE for type=");
- dump_firm_type_and_int_freq(priv->firm[pos].type,
- priv->firm[pos].int_freq);
- printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
- (unsigned long long)*id);
- }
-
- scode_buf[0] = 0x00;
- memcpy(&scode_buf[1], p, 12);
-
- /* Enter direct-mode */
- rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
- if (rc < 0) {
- printk(KERN_ERR "failed to put device into direct mode!\n");
- return -EIO;
- }
-
- rc = xc_send_i2c_data(priv, scode_buf, 13);
- if (rc != 0) {
- /* Even if the send failed, make sure we set back to indirect
- mode */
- printk(KERN_ERR "Failed to set scode %d\n", rc);
- }
-
- /* Switch back to indirect-mode */
- memset(indirect_mode, 0, sizeof(indirect_mode));
- indirect_mode[4] = 0x88;
- xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
- msleep(10);
-
- return 0;
-}
-
-static int check_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id std, __u16 int_freq)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- struct firmware_properties new_fw;
- int rc = 0, is_retry = 0;
- u16 hwmodel;
- v4l2_std_id std0;
- u8 hw_major, hw_minor, fw_major, fw_minor;
-
- dprintk(1, "%s called\n", __func__);
-
- if (!priv->firm) {
- rc = xc4000_fwupload(fe);
- if (rc < 0)
- return rc;
- }
-
-retry:
- new_fw.type = type;
- new_fw.id = std;
- new_fw.std_req = std;
- new_fw.scode_table = SCODE;
- new_fw.scode_nr = 0;
- new_fw.int_freq = int_freq;
-
- dprintk(1, "checking firmware, user requested type=");
- if (debug) {
- dump_firm_type(new_fw.type);
- printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
- (unsigned long long)new_fw.std_req);
- if (!int_freq)
- printk(KERN_CONT "scode_tbl ");
- else
- printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
- printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
- }
-
- /* No need to reload base firmware if it matches */
- if (priv->cur_fw.type & BASE) {
- dprintk(1, "BASE firmware not changed.\n");
- goto skip_base;
- }
-
- /* Updating BASE - forget about all currently loaded firmware */
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-
- /* Reset is needed before loading firmware */
- rc = xc4000_tuner_reset(fe);
- if (rc < 0)
- goto fail;
-
- /* BASE firmwares are all std0 */
- std0 = 0;
- rc = load_firmware(fe, BASE, &std0);
- if (rc < 0) {
- printk(KERN_ERR "Error %d while loading base firmware\n", rc);
- goto fail;
- }
-
- /* Load INIT1, if needed */
- dprintk(1, "Load init1 firmware, if exists\n");
-
- rc = load_firmware(fe, BASE | INIT1, &std0);
- if (rc == -ENOENT)
- rc = load_firmware(fe, BASE | INIT1, &std0);
- if (rc < 0 && rc != -ENOENT) {
- tuner_err("Error %d while loading init1 firmware\n",
- rc);
- goto fail;
- }
-
-skip_base:
- /*
- * No need to reload standard specific firmware if base firmware
- * was not reloaded and requested video standards have not changed.
- */
- if (priv->cur_fw.type == (BASE | new_fw.type) &&
- priv->cur_fw.std_req == std) {
- dprintk(1, "Std-specific firmware already loaded.\n");
- goto skip_std_specific;
- }
-
- /* Reloading std-specific firmware forces a SCODE update */
- priv->cur_fw.scode_table = 0;
-
- /* Load the standard firmware */
- rc = load_firmware(fe, new_fw.type, &new_fw.id);
-
- if (rc < 0)
- goto fail;
-
-skip_std_specific:
- if (priv->cur_fw.scode_table == new_fw.scode_table &&
- priv->cur_fw.scode_nr == new_fw.scode_nr) {
- dprintk(1, "SCODE firmware already loaded.\n");
- goto check_device;
- }
-
- /* Load SCODE firmware, if exists */
- rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
- new_fw.int_freq, new_fw.scode_nr);
- if (rc != 0)
- dprintk(1, "load scode failed %d\n", rc);
-
-check_device:
- rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
-
- if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
- &fw_minor) != 0) {
- printk(KERN_ERR "Unable to read tuner registers.\n");
- goto fail;
- }
-
- dprintk(1, "Device is Xceive %d version %d.%d, "
- "firmware version %d.%d\n",
- hwmodel, hw_major, hw_minor, fw_major, fw_minor);
-
- /* Check firmware version against what we downloaded. */
- if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
- printk(KERN_WARNING
- "Incorrect readback of firmware version %d.%d.\n",
- fw_major, fw_minor);
- goto fail;
- }
-
- /* Check that the tuner hardware model remains consistent over time. */
- if (priv->hwmodel == 0 &&
- (hwmodel == XC_PRODUCT_ID_XC4000 ||
- hwmodel == XC_PRODUCT_ID_XC4100)) {
- priv->hwmodel = hwmodel;
- priv->hwvers = (hw_major << 8) | hw_minor;
- } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
- priv->hwvers != ((hw_major << 8) | hw_minor)) {
- printk(KERN_WARNING
- "Read invalid device hardware information - tuner "
- "hung?\n");
- goto fail;
- }
-
- memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-
- /*
- * By setting BASE in cur_fw.type only after successfully loading all
- * firmwares, we can:
- * 1. Identify that BASE firmware with type=0 has been loaded;
- * 2. Tell whether BASE firmware was just changed the next time through.
- */
- priv->cur_fw.type |= BASE;
-
- return 0;
-
-fail:
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
- if (!is_retry) {
- msleep(50);
- is_retry = 1;
- dprintk(1, "Retrying firmware load\n");
- goto retry;
- }
-
- if (rc == -ENOENT)
- rc = -EINVAL;
- return rc;
-}
-
-static void xc_debug_dump(struct xc4000_priv *priv)
-{
- u16 adc_envelope;
- u32 freq_error_hz = 0;
- u16 lock_status;
- 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;
-
- xc_get_adc_envelope(priv, &adc_envelope);
- dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
-
- xc_get_frequency_error(priv, &freq_error_hz);
- dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
-
- xc_get_lock_status(priv, &lock_status);
- dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
- lock_status);
-
- xc_get_version(priv, &hw_majorversion, &hw_minorversion,
- &fw_majorversion, &fw_minorversion);
- dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
- hw_majorversion, hw_minorversion,
- fw_majorversion, fw_minorversion);
-
- if (priv->video_standard < XC4000_DTV6) {
- xc_get_hsync_freq(priv, &hsync_freq_hz);
- dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
- hsync_freq_hz);
-
- xc_get_frame_lines(priv, &frame_lines);
- dprintk(1, "*** Frame lines = %d\n", frame_lines);
- }
-
- 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 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__, c->frequency);
-
- mutex_lock(&priv->lock);
-
- 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__);
- 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 = c->frequency - 1750000;
- type = DTV6;
- } else if (bw <= 7000000) {
- priv->video_standard = XC4000_DTV7;
- priv->freq_hz = c->frequency - 2250000;
- type = DTV7;
- } else {
- priv->video_standard = XC4000_DTV8;
- priv->freq_hz = c->frequency - 2750000;
- type = DTV8;
- }
- priv->rf_mode = XC_RF_MODE_AIR;
- break;
- default:
- printk(KERN_ERR "xc4000 delivery system not supported!\n");
- ret = -EINVAL;
- goto fail;
- }
-
- dprintk(1, "%s() frequency=%d (compensated)\n",
- __func__, priv->freq_hz);
-
- /* Make sure the correct firmware type is loaded */
- 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",
- priv->rf_mode);
- goto fail;
- } else {
- u16 video_mode, audio_mode;
- video_mode = xc4000_standard[priv->video_standard].video_mode;
- audio_mode = xc4000_standard[priv->video_standard].audio_mode;
- if (type == DTV6 && priv->firm_version != 0x0102)
- video_mode |= 0x0001;
- ret = xc_set_tv_standard(priv, video_mode, audio_mode);
- if (ret != 0) {
- printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
- /* DJH - do not return when it fails... */
- /* goto fail; */
- }
- }
-
- if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
- ret = 0;
- if (priv->dvb_amplitude != 0) {
- if (xc_write_reg(priv, XREG_AMPLITUDE,
- (priv->firm_version != 0x0102 ||
- priv->dvb_amplitude != 134 ?
- priv->dvb_amplitude : 132)) != 0)
- ret = -EREMOTEIO;
- }
- if (priv->set_smoothedcvbs != 0) {
- if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
- ret = -EREMOTEIO;
- }
- if (ret != 0) {
- printk(KERN_ERR "xc4000: setting registers failed\n");
- /* goto fail; */
- }
-
- xc_tune_channel(priv, priv->freq_hz);
-
- ret = 0;
-
-fail:
- mutex_unlock(&priv->lock);
-
- return ret;
-}
-
-static int xc4000_set_analog_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- unsigned int type = 0;
- int ret = -EREMOTEIO;
-
- if (params->mode == V4L2_TUNER_RADIO) {
- dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
- __func__, params->frequency);
-
- mutex_lock(&priv->lock);
-
- params->std = 0;
- priv->freq_hz = params->frequency * 125L / 2;
-
- if (audio_std & XC4000_AUDIO_STD_INPUT1) {
- priv->video_standard = XC4000_FM_Radio_INPUT1;
- type = FM | INPUT1;
- } else {
- priv->video_standard = XC4000_FM_Radio_INPUT2;
- type = FM | INPUT2;
- }
-
- goto tune_channel;
- }
-
- dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
- __func__, params->frequency);
-
- mutex_lock(&priv->lock);
-
- /* params->frequency is in units of 62.5khz */
- priv->freq_hz = params->frequency * 62500;
-
- params->std &= V4L2_STD_ALL;
- /* if std is not defined, choose one */
- if (!params->std)
- params->std = V4L2_STD_PAL_BG;
-
- if (audio_std & XC4000_AUDIO_STD_MONO)
- type = MONO;
-
- if (params->std & V4L2_STD_MN) {
- params->std = V4L2_STD_MN;
- if (audio_std & XC4000_AUDIO_STD_MONO) {
- priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
- } else if (audio_std & XC4000_AUDIO_STD_A2) {
- params->std |= V4L2_STD_A2;
- priv->video_standard = XC4000_MN_NTSC_PAL_A2;
- } else {
- params->std |= V4L2_STD_BTSC;
- priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
- }
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_BG) {
- params->std = V4L2_STD_PAL_BG;
- if (audio_std & XC4000_AUDIO_STD_MONO) {
- priv->video_standard = XC4000_BG_PAL_MONO;
- } else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
- if (!(audio_std & XC4000_AUDIO_STD_B)) {
- params->std |= V4L2_STD_NICAM_A;
- priv->video_standard = XC4000_BG_PAL_NICAM;
- } else {
- params->std |= V4L2_STD_NICAM_B;
- priv->video_standard = XC4000_BG_PAL_NICAM;
- }
- } else {
- if (!(audio_std & XC4000_AUDIO_STD_B)) {
- params->std |= V4L2_STD_A2_A;
- priv->video_standard = XC4000_BG_PAL_A2;
- } else {
- params->std |= V4L2_STD_A2_B;
- priv->video_standard = XC4000_BG_PAL_A2;
- }
- }
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_I) {
- /* default to NICAM audio standard */
- params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
- if (audio_std & XC4000_AUDIO_STD_MONO)
- priv->video_standard = XC4000_I_PAL_NICAM_MONO;
- else
- priv->video_standard = XC4000_I_PAL_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_DK) {
- params->std = V4L2_STD_PAL_DK;
- if (audio_std & XC4000_AUDIO_STD_MONO) {
- priv->video_standard = XC4000_DK_PAL_MONO;
- } else if (audio_std & XC4000_AUDIO_STD_A2) {
- params->std |= V4L2_STD_A2;
- priv->video_standard = XC4000_DK_PAL_A2;
- } else {
- params->std |= V4L2_STD_NICAM;
- priv->video_standard = XC4000_DK_PAL_NICAM;
- }
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_DK) {
- /* default to A2 audio standard */
- params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
- if (audio_std & XC4000_AUDIO_STD_L) {
- type = 0;
- priv->video_standard = XC4000_DK_SECAM_NICAM;
- } else if (audio_std & XC4000_AUDIO_STD_MONO) {
- priv->video_standard = XC4000_DK_SECAM_A2MONO;
- } else if (audio_std & XC4000_AUDIO_STD_K3) {
- params->std |= V4L2_STD_SECAM_K3;
- priv->video_standard = XC4000_DK_SECAM_A2LDK3;
- } else {
- priv->video_standard = XC4000_DK_SECAM_A2DK1;
- }
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_L) {
- /* default to NICAM audio standard */
- type = 0;
- params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
- priv->video_standard = XC4000_L_SECAM_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_LC) {
- /* default to NICAM audio standard */
- type = 0;
- params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
- priv->video_standard = XC4000_LC_SECAM_NICAM;
- goto tune_channel;
- }
-
-tune_channel:
- /* FIXME: it could be air. */
- priv->rf_mode = XC_RF_MODE_CABLE;
-
- if (check_firmware(fe, type, params->std,
- xc4000_standard[priv->video_standard].int_freq) != 0)
- goto fail;
-
- ret = xc_set_signal_source(priv, priv->rf_mode);
- if (ret != 0) {
- printk(KERN_ERR
- "xc4000: xc_set_signal_source(%d) failed\n",
- priv->rf_mode);
- goto fail;
- } else {
- u16 video_mode, audio_mode;
- video_mode = xc4000_standard[priv->video_standard].video_mode;
- audio_mode = xc4000_standard[priv->video_standard].audio_mode;
- if (priv->video_standard < XC4000_BG_PAL_A2) {
- if (type & NOGD)
- video_mode &= 0xFF7F;
- } else if (priv->video_standard < XC4000_I_PAL_NICAM) {
- if (priv->firm_version == 0x0102)
- video_mode &= 0xFEFF;
- if (audio_std & XC4000_AUDIO_STD_B)
- video_mode |= 0x0080;
- }
- ret = xc_set_tv_standard(priv, video_mode, audio_mode);
- if (ret != 0) {
- printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
- goto fail;
- }
- }
-
- if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
- ret = 0;
- if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
- ret = -EREMOTEIO;
- if (priv->set_smoothedcvbs != 0) {
- if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
- ret = -EREMOTEIO;
- }
- if (ret != 0) {
- printk(KERN_ERR "xc4000: setting registers failed\n");
- goto fail;
- }
-
- xc_tune_channel(priv, priv->freq_hz);
-
- ret = 0;
-
-fail:
- mutex_unlock(&priv->lock);
-
- 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;
-
- *freq = priv->freq_hz;
-
- if (debug) {
- mutex_lock(&priv->lock);
- if ((priv->cur_fw.type
- & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
- u16 snr = 0;
- if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
- mutex_unlock(&priv->lock);
- dprintk(1, "%s() freq = %u, SNR = %d\n",
- __func__, *freq, snr);
- return 0;
- }
- }
- mutex_unlock(&priv->lock);
- }
-
- dprintk(1, "%s()\n", __func__);
-
- return 0;
-}
-
-static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- dprintk(1, "%s()\n", __func__);
-
- *bw = priv->bandwidth;
- return 0;
-}
-
-static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- u16 lock_status = 0;
-
- mutex_lock(&priv->lock);
-
- if (priv->cur_fw.type & BASE)
- xc_get_lock_status(priv, &lock_status);
-
- *status = (lock_status == 1 ?
- TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
- if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
- *status &= (~TUNER_STATUS_STEREO);
-
- mutex_unlock(&priv->lock);
-
- dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
-
- return 0;
-}
-
-static int xc4000_sleep(struct dvb_frontend *fe)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
- int ret = 0;
-
- dprintk(1, "%s()\n", __func__);
-
- mutex_lock(&priv->lock);
-
- /* Avoid firmware reload on slow devices */
- if ((no_poweroff == 2 ||
- (no_poweroff == 0 && priv->default_pm != 0)) &&
- (priv->cur_fw.type & BASE) != 0) {
- /* force reset and firmware reload */
- priv->cur_fw.type = XC_POWERED_DOWN;
-
- if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
- printk(KERN_ERR
- "xc4000: %s() unable to shutdown tuner\n",
- __func__);
- ret = -EREMOTEIO;
- }
- msleep(20);
- }
-
- mutex_unlock(&priv->lock);
-
- return ret;
-}
-
-static int xc4000_init(struct dvb_frontend *fe)
-{
- dprintk(1, "%s()\n", __func__);
-
- return 0;
-}
-
-static int xc4000_release(struct dvb_frontend *fe)
-{
- struct xc4000_priv *priv = fe->tuner_priv;
-
- dprintk(1, "%s()\n", __func__);
-
- mutex_lock(&xc4000_list_mutex);
-
- if (priv)
- hybrid_tuner_release_state(priv);
-
- mutex_unlock(&xc4000_list_mutex);
-
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static const struct dvb_tuner_ops xc4000_tuner_ops = {
- .info = {
- .name = "Xceive XC4000",
- .frequency_min = 1000000,
- .frequency_max = 1023000000,
- .frequency_step = 50000,
- },
-
- .release = xc4000_release,
- .init = xc4000_init,
- .sleep = xc4000_sleep,
-
- .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
-};
-
-struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct xc4000_config *cfg)
-{
- struct xc4000_priv *priv = NULL;
- int instance;
- u16 id = 0;
-
- dprintk(1, "%s(%d-%04x)\n", __func__,
- i2c ? i2c_adapter_id(i2c) : -1,
- cfg ? cfg->i2c_address : -1);
-
- mutex_lock(&xc4000_list_mutex);
-
- instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
- hybrid_tuner_instance_list,
- i2c, cfg->i2c_address, "xc4000");
- switch (instance) {
- case 0:
- goto fail;
- break;
- case 1:
- /* new tuner instance */
- priv->bandwidth = 6000000;
- /* set default configuration */
- priv->if_khz = 4560;
- priv->default_pm = 0;
- priv->dvb_amplitude = 134;
- priv->set_smoothedcvbs = 1;
- mutex_init(&priv->lock);
- fe->tuner_priv = priv;
- break;
- default:
- /* existing tuner instance */
- fe->tuner_priv = priv;
- break;
- }
-
- if (cfg->if_khz != 0) {
- /* copy configuration if provided by the caller */
- priv->if_khz = cfg->if_khz;
- priv->default_pm = cfg->default_pm;
- priv->dvb_amplitude = cfg->dvb_amplitude;
- priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
- }
-
- /* Check if firmware has been loaded. It is possible that another
- instance of the driver has loaded the firmware.
- */
-
- if (instance == 1) {
- if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
- goto fail;
- } else {
- id = ((priv->cur_fw.type & BASE) != 0 ?
- priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
- }
-
- switch (id) {
- case XC_PRODUCT_ID_XC4000:
- case XC_PRODUCT_ID_XC4100:
- printk(KERN_INFO
- "xc4000: Successfully identified at address 0x%02x\n",
- cfg->i2c_address);
- printk(KERN_INFO
- "xc4000: Firmware has been loaded previously\n");
- break;
- case XC_PRODUCT_ID_FW_NOT_LOADED:
- printk(KERN_INFO
- "xc4000: Successfully identified at address 0x%02x\n",
- cfg->i2c_address);
- printk(KERN_INFO
- "xc4000: Firmware has not been loaded previously\n");
- break;
- default:
- printk(KERN_ERR
- "xc4000: Device not found at addr 0x%02x (0x%x)\n",
- cfg->i2c_address, id);
- goto fail;
- }
-
- mutex_unlock(&xc4000_list_mutex);
-
- memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- if (instance == 1) {
- int ret;
- mutex_lock(&priv->lock);
- ret = xc4000_fwupload(fe);
- mutex_unlock(&priv->lock);
- if (ret != 0)
- goto fail2;
- }
-
- return fe;
-fail:
- mutex_unlock(&xc4000_list_mutex);
-fail2:
- xc4000_release(fe);
- return NULL;
-}
-EXPORT_SYMBOL(xc4000_attach);
-
-MODULE_AUTHOR("Steven Toth, Davide Ferri");
-MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
deleted file mode 100644
index 362a8d7c9738..000000000000
--- a/drivers/media/common/tuners/xc5000.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- * Copyright (c) 2007 Xceive Corporation
- * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/dvb/frontend.h>
-#include <linux/i2c.h>
-
-#include "dvb_frontend.h"
-
-#include "xc5000.h"
-#include "tuner-i2c.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-static int no_poweroff;
-module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
- "\t\t1 keep device energized and with tuner ready all the times.\n"
- "\t\tFaster, but consumes more power and keeps the device hotter");
-
-static DEFINE_MUTEX(xc5000_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
- printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
-
-struct xc5000_priv {
- struct tuner_i2c_props i2c_props;
- struct list_head hybrid_tuner_instance_list;
-
- u32 if_khz;
- u16 xtal_khz;
- u32 freq_hz;
- u32 bandwidth;
- u8 video_standard;
- u8 rf_mode;
- u8 radio_input;
-
- int chip_id;
-};
-
-/* Misc Defines */
-#define MAX_TV_STANDARD 24
-#define XC_MAX_I2C_WRITE_LENGTH 64
-
-/* Signal Types */
-#define XC_RF_MODE_AIR 0
-#define XC_RF_MODE_CABLE 1
-
-/* Result codes */
-#define XC_RESULT_SUCCESS 0
-#define XC_RESULT_RESET_FAILURE 1
-#define XC_RESULT_I2C_WRITE_FAILURE 2
-#define XC_RESULT_I2C_READ_FAILURE 3
-#define XC_RESULT_OUT_OF_RANGE 5
-
-/* Product id */
-#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
-#define XC_PRODUCT_ID_FW_LOADED 0x1388
-
-/* Registers */
-#define XREG_INIT 0x00
-#define XREG_VIDEO_MODE 0x01
-#define XREG_AUDIO_MODE 0x02
-#define XREG_RF_FREQ 0x03
-#define XREG_D_CODE 0x04
-#define XREG_IF_OUT 0x05
-#define XREG_SEEK_MODE 0x07
-#define XREG_POWER_DOWN 0x0A /* Obsolete */
-/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
-#define XREG_OUTPUT_AMP 0x0B
-#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
-#define XREG_SMOOTHEDCVBS 0x0E
-#define XREG_XTALFREQ 0x0F
-#define XREG_FINERFREQ 0x10
-#define XREG_DDIMODE 0x11
-
-#define XREG_ADC_ENV 0x00
-#define XREG_QUALITY 0x01
-#define XREG_FRAME_LINES 0x02
-#define XREG_HSYNC_FREQ 0x03
-#define XREG_LOCK 0x04
-#define XREG_FREQ_ERROR 0x05
-#define XREG_SNR 0x06
-#define XREG_VERSION 0x07
-#define XREG_PRODUCT_ID 0x08
-#define XREG_BUSY 0x09
-#define XREG_BUILD 0x0D
-
-/*
- Basic firmware description. This will remain with
- the driver for documentation purposes.
-
- This represents an I2C firmware file encoded as a
- string of unsigned char. Format is as follows:
-
- char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB
- char[1 ]=len0_LSB -> length of first write transaction
- char[2 ]=data0 -> first byte to be sent
- char[3 ]=data1
- char[4 ]=data2
- char[ ]=...
- char[M ]=dataN -> last byte to be sent
- char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB
- char[M+2]=len1_LSB -> length of second write transaction
- char[M+3]=data0
- char[M+4]=data1
- ...
- etc.
-
- The [len] value should be interpreted as follows:
-
- len= len_MSB _ len_LSB
- len=1111_1111_1111_1111 : End of I2C_SEQUENCE
- len=0000_0000_0000_0000 : Reset command: Do hardware reset
- len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767)
- len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms
-
- For the RESET and WAIT commands, the two following bytes will contain
- immediately the length of the following transaction.
-
-*/
-struct XC_TV_STANDARD {
- char *Name;
- u16 AudioMode;
- u16 VideoMode;
-};
-
-/* Tuner standards */
-#define MN_NTSC_PAL_BTSC 0
-#define MN_NTSC_PAL_A2 1
-#define MN_NTSC_PAL_EIAJ 2
-#define MN_NTSC_PAL_Mono 3
-#define BG_PAL_A2 4
-#define BG_PAL_NICAM 5
-#define BG_PAL_MONO 6
-#define I_PAL_NICAM 7
-#define I_PAL_NICAM_MONO 8
-#define DK_PAL_A2 9
-#define DK_PAL_NICAM 10
-#define DK_PAL_MONO 11
-#define DK_SECAM_A2DK1 12
-#define DK_SECAM_A2LDK3 13
-#define DK_SECAM_A2MONO 14
-#define L_SECAM_NICAM 15
-#define LC_SECAM_NICAM 16
-#define DTV6 17
-#define DTV8 18
-#define DTV7_8 19
-#define DTV7 20
-#define FM_Radio_INPUT2 21
-#define FM_Radio_INPUT1 22
-#define FM_Radio_INPUT1_MONO 23
-
-static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
- {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
- {"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
- {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
- {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
- {"B/G-PAL-A2", 0x0A00, 0x8049},
- {"B/G-PAL-NICAM", 0x0C04, 0x8049},
- {"B/G-PAL-MONO", 0x0878, 0x8059},
- {"I-PAL-NICAM", 0x1080, 0x8009},
- {"I-PAL-NICAM-MONO", 0x0E78, 0x8009},
- {"D/K-PAL-A2", 0x1600, 0x8009},
- {"D/K-PAL-NICAM", 0x0E80, 0x8009},
- {"D/K-PAL-MONO", 0x1478, 0x8009},
- {"D/K-SECAM-A2 DK1", 0x1200, 0x8009},
- {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
- {"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
- {"L-SECAM-NICAM", 0x8E82, 0x0009},
- {"L'-SECAM-NICAM", 0x8E82, 0x4009},
- {"DTV6", 0x00C0, 0x8002},
- {"DTV8", 0x00C0, 0x800B},
- {"DTV7/8", 0x00C0, 0x801B},
- {"DTV7", 0x00C0, 0x8007},
- {"FM Radio-INPUT2", 0x9802, 0x9002},
- {"FM Radio-INPUT1", 0x0208, 0x9002},
- {"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
-};
-
-
-struct xc5000_fw_cfg {
- char *name;
- u16 size;
-};
-
-#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
-static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
- .name = XC5000A_FIRMWARE,
- .size = 12401,
-};
-
-#define XC5000C_FIRMWARE "dvb-fe-xc5000c-41.024.5.fw"
-static const struct xc5000_fw_cfg xc5000c_41_024_5 = {
- .name = XC5000C_FIRMWARE,
- .size = 16497,
-};
-
-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;
- }
-}
-
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
-static int xc5000_TunerReset(struct dvb_frontend *fe);
-
-static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
-{
- struct i2c_msg msg = { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = buf, .len = len };
-
- if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
- return XC_RESULT_I2C_WRITE_FAILURE;
- }
- return XC_RESULT_SUCCESS;
-}
-
-#if 0
-/* This routine is never used because the only time we read data from the
- i2c bus is when we read registers, and we want that to be an atomic i2c
- transaction in case we are on a multi-master bus */
-static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
-{
- struct i2c_msg msg = { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = buf, .len = len };
-
- if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
- return -EREMOTEIO;
- }
- return 0;
-}
-#endif
-
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
- u8 buf[2] = { reg >> 8, reg & 0xff };
- u8 bval[2] = { 0, 0 };
- struct i2c_msg msg[2] = {
- { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
- };
-
- if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
- printk(KERN_WARNING "xc5000: I2C read failed\n");
- return -EREMOTEIO;
- }
-
- *val = (bval[0] << 8) | bval[1];
- return XC_RESULT_SUCCESS;
-}
-
-static void xc_wait(int wait_ms)
-{
- msleep(wait_ms);
-}
-
-static int xc5000_TunerReset(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret;
-
- dprintk(1, "%s()\n", __func__);
-
- if (fe->callback) {
- ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
- fe->dvb->priv :
- priv->i2c_props.adap->algo_data,
- DVB_FRONTEND_COMPONENT_TUNER,
- XC5000_TUNER_RESET, 0);
- if (ret) {
- printk(KERN_ERR "xc5000: reset failed\n");
- return XC_RESULT_RESET_FAILURE;
- }
- } else {
- printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
- return XC_RESULT_RESET_FAILURE;
- }
- return XC_RESULT_SUCCESS;
-}
-
-static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
-{
- u8 buf[4];
- int WatchDogTimer = 100;
- int result;
-
- buf[0] = (regAddr >> 8) & 0xFF;
- buf[1] = regAddr & 0xFF;
- buf[2] = (i2cData >> 8) & 0xFF;
- buf[3] = i2cData & 0xFF;
- result = xc_send_i2c_data(priv, buf, 4);
- if (result == XC_RESULT_SUCCESS) {
- /* wait for busy flag to clear */
- while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
- result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
- if (result == XC_RESULT_SUCCESS) {
- if ((buf[0] == 0) && (buf[1] == 0)) {
- /* busy flag cleared */
- break;
- } else {
- xc_wait(5); /* wait 5 ms */
- WatchDogTimer--;
- }
- }
- }
- }
- if (WatchDogTimer < 0)
- result = XC_RESULT_I2C_WRITE_FAILURE;
-
- return result;
-}
-
-static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
-
- int i, nbytes_to_send, result;
- unsigned int len, pos, index;
- u8 buf[XC_MAX_I2C_WRITE_LENGTH];
-
- index = 0;
- while ((i2c_sequence[index] != 0xFF) ||
- (i2c_sequence[index + 1] != 0xFF)) {
- len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
- if (len == 0x0000) {
- /* RESET command */
- result = xc5000_TunerReset(fe);
- index += 2;
- if (result != XC_RESULT_SUCCESS)
- return result;
- } else if (len & 0x8000) {
- /* WAIT command */
- xc_wait(len & 0x7FFF);
- index += 2;
- } else {
- /* Send i2c data whilst ensuring individual transactions
- * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
- */
- index += 2;
- buf[0] = i2c_sequence[index];
- buf[1] = i2c_sequence[index + 1];
- pos = 2;
- while (pos < len) {
- if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
- nbytes_to_send =
- XC_MAX_I2C_WRITE_LENGTH;
- else
- nbytes_to_send = (len - pos + 2);
- for (i = 2; i < nbytes_to_send; i++) {
- buf[i] = i2c_sequence[index + pos +
- i - 2];
- }
- result = xc_send_i2c_data(priv, buf,
- nbytes_to_send);
-
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- pos += nbytes_to_send - 2;
- }
- index += len;
- }
- }
- return XC_RESULT_SUCCESS;
-}
-
-static int xc_initialize(struct xc5000_priv *priv)
-{
- dprintk(1, "%s()\n", __func__);
- return xc_write_reg(priv, XREG_INIT, 0);
-}
-
-static int xc_SetTVStandard(struct xc5000_priv *priv,
- u16 VideoMode, u16 AudioMode)
-{
- int ret;
- dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
- dprintk(1, "%s() Standard = %s\n",
- __func__,
- XC5000_Standard[priv->video_standard].Name);
-
- ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
- if (ret == XC_RESULT_SUCCESS)
- ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
-
- return ret;
-}
-
-static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
-{
- dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
- rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
-
- if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
- rf_mode = XC_RF_MODE_CABLE;
- printk(KERN_ERR
- "%s(), Invalid mode, defaulting to CABLE",
- __func__);
- }
- return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
-}
-
-static const struct dvb_tuner_ops xc5000_tuner_ops;
-
-static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
-{
- u16 freq_code;
-
- dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
- if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
- (freq_hz < xc5000_tuner_ops.info.frequency_min))
- return XC_RESULT_OUT_OF_RANGE;
-
- freq_code = (u16)(freq_hz / 15625);
-
- /* Starting in firmware version 1.1.44, Xceive recommends using the
- FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
- only be used for fast scanning for channel lock) */
- return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
-}
-
-
-static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
-{
- u32 freq_code = (freq_khz * 1024)/1000;
- dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
- __func__, freq_khz, freq_code);
-
- return xc_write_reg(priv, XREG_IF_OUT, freq_code);
-}
-
-
-static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
-{
- return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
-}
-
-static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
-{
- int result;
- u16 regData;
- u32 tmp;
-
- result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- tmp = (u32)regData;
- (*freq_error_hz) = (tmp * 15625) / 1000;
- return result;
-}
-
-static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
-{
- return xc5000_readreg(priv, XREG_LOCK, lock_status);
-}
-
-static int xc_get_version(struct xc5000_priv *priv,
- u8 *hw_majorversion, u8 *hw_minorversion,
- u8 *fw_majorversion, u8 *fw_minorversion)
-{
- u16 data;
- int result;
-
- result = xc5000_readreg(priv, XREG_VERSION, &data);
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- (*hw_majorversion) = (data >> 12) & 0x0F;
- (*hw_minorversion) = (data >> 8) & 0x0F;
- (*fw_majorversion) = (data >> 4) & 0x0F;
- (*fw_minorversion) = data & 0x0F;
-
- return 0;
-}
-
-static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
-{
- return xc5000_readreg(priv, XREG_BUILD, buildrev);
-}
-
-static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
-{
- u16 regData;
- int result;
-
- result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
- return result;
-}
-
-static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
-{
- return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
-}
-
-static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
-{
- return xc5000_readreg(priv, XREG_QUALITY, quality);
-}
-
-static u16 WaitForLock(struct xc5000_priv *priv)
-{
- u16 lockState = 0;
- int watchDogCount = 40;
-
- while ((lockState == 0) && (watchDogCount > 0)) {
- xc_get_lock_status(priv, &lockState);
- if (lockState != 1) {
- xc_wait(5);
- watchDogCount--;
- }
- }
- return lockState;
-}
-
-#define XC_TUNE_ANALOG 0
-#define XC_TUNE_DIGITAL 1
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
-{
- int found = 0;
-
- dprintk(1, "%s(%u)\n", __func__, freq_hz);
-
- if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
- return 0;
-
- if (mode == XC_TUNE_ANALOG) {
- if (WaitForLock(priv) == 1)
- found = 1;
- }
-
- return found;
-}
-
-static int xc_set_xtal(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret = XC_RESULT_SUCCESS;
-
- switch (priv->chip_id) {
- default:
- case XC5000A:
- /* 32.000 MHz xtal is default */
- break;
- case XC5000C:
- switch (priv->xtal_khz) {
- default:
- case 32000:
- /* 32.000 MHz xtal is default */
- break;
- case 31875:
- /* 31.875 MHz xtal configuration */
- ret = xc_write_reg(priv, 0x000f, 0x8081);
- break;
- }
- break;
- }
- return ret;
-}
-
-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",
- desired_fw->name);
-
- 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");
- ret = XC_RESULT_RESET_FAILURE;
- goto out;
- } else {
- printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
- fw->size);
- ret = XC_RESULT_SUCCESS;
- }
-
- if (fw->size != desired_fw->size) {
- printk(KERN_ERR "xc5000: firmware incorrect size\n");
- ret = XC_RESULT_RESET_FAILURE;
- } else {
- printk(KERN_INFO "xc5000: firmware uploading...\n");
- ret = xc_load_i2c_sequence(fe, fw->data);
- if (XC_RESULT_SUCCESS == ret)
- ret = xc_set_xtal(fe);
- if (XC_RESULT_SUCCESS == ret)
- printk(KERN_INFO "xc5000: firmware upload complete...\n");
- else
- printk(KERN_ERR "xc5000: firmware upload failed...\n");
- }
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static void xc_debug_dump(struct xc5000_priv *priv)
-{
- u16 adc_envelope;
- u32 freq_error_hz = 0;
- u16 lock_status;
- u32 hsync_freq_hz = 0;
- u16 frame_lines;
- u16 quality;
- u8 hw_majorversion = 0, hw_minorversion = 0;
- u8 fw_majorversion = 0, fw_minorversion = 0;
- u16 fw_buildversion = 0;
-
- /* Wait for stats to stabilize.
- * Frame Lines needs two frame times after initial lock
- * before it is valid.
- */
- xc_wait(100);
-
- xc_get_ADC_Envelope(priv, &adc_envelope);
- dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
-
- xc_get_frequency_error(priv, &freq_error_hz);
- dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
-
- xc_get_lock_status(priv, &lock_status);
- dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
- lock_status);
-
- xc_get_version(priv, &hw_majorversion, &hw_minorversion,
- &fw_majorversion, &fw_minorversion);
- xc_get_buildversion(priv, &fw_buildversion);
- dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
- hw_majorversion, hw_minorversion,
- fw_majorversion, fw_minorversion, fw_buildversion);
-
- xc_get_hsync_freq(priv, &hsync_freq_hz);
- dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
-
- xc_get_frame_lines(priv, &frame_lines);
- dprintk(1, "*** Frame lines = %d\n", frame_lines);
-
- xc_get_quality(priv, &quality);
- dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
-}
-
-static int xc5000_set_params(struct dvb_frontend *fe)
-{
- int ret, b;
- struct xc5000_priv *priv = fe->tuner_priv;
- 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) {
- dprintk(1, "Unable to load firmware and init tuner\n");
- return -EINVAL;
- }
- }
-
- 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_ISDBT:
- /* All ISDB-T are currently for 6 MHz bw */
- if (!bw)
- bw = 6000000;
- /* fall to OFDM handling */
- case SYS_DMBTH:
- case SYS_DVBT:
- case SYS_DVBT2:
- dprintk(1, "%s() OFDM\n", __func__);
- switch (bw) {
- case 6000000:
- priv->video_standard = DTV6;
- priv->freq_hz = freq - 1750000;
- break;
- case 7000000:
- priv->video_standard = DTV7;
- priv->freq_hz = freq - 2250000;
- break;
- case 8000000:
- priv->video_standard = DTV8;
- priv->freq_hz = freq - 2750000;
- break;
- default:
- printk(KERN_ERR "xc5000 bandwidth not set!\n");
- return -EINVAL;
- }
- priv->rf_mode = XC_RF_MODE_AIR;
- 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;
- }
- 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 to %d)\n",
- __func__, freq, priv->freq_hz);
-
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
- priv->rf_mode);
- return -EREMOTEIO;
- }
-
- ret = xc_SetTVStandard(priv,
- XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
- return -EREMOTEIO;
- }
-
- ret = xc_set_IF_frequency(priv, priv->if_khz);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
- priv->if_khz);
- return -EIO;
- }
-
- xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
-
- xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
-
- if (debug)
- xc_debug_dump(priv);
-
- priv->bandwidth = bw;
-
- return 0;
-}
-
-static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret;
- u16 id;
-
- ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
- if (ret == XC_RESULT_SUCCESS) {
- if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
- ret = XC_RESULT_RESET_FAILURE;
- else
- ret = XC_RESULT_SUCCESS;
- }
-
- dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
- ret == XC_RESULT_SUCCESS ? "True" : "False", id);
- return ret;
-}
-
-static int xc5000_set_tv_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret;
-
- dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
- __func__, params->frequency);
-
- /* Fix me: it could be air. */
- priv->rf_mode = params->mode;
- if (params->mode > XC_RF_MODE_CABLE)
- priv->rf_mode = XC_RF_MODE_CABLE;
-
- /* params->frequency is in units of 62.5khz */
- priv->freq_hz = params->frequency * 62500;
-
- /* FIX ME: Some video standards may have several possible audio
- standards. We simply default to one of them here.
- */
- if (params->std & V4L2_STD_MN) {
- /* default to BTSC audio standard */
- priv->video_standard = MN_NTSC_PAL_BTSC;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_BG) {
- /* default to NICAM audio standard */
- priv->video_standard = BG_PAL_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_I) {
- /* default to NICAM audio standard */
- priv->video_standard = I_PAL_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_PAL_DK) {
- /* default to NICAM audio standard */
- priv->video_standard = DK_PAL_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_DK) {
- /* default to A2 DK1 audio standard */
- priv->video_standard = DK_SECAM_A2DK1;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_L) {
- priv->video_standard = L_SECAM_NICAM;
- goto tune_channel;
- }
-
- if (params->std & V4L2_STD_SECAM_LC) {
- priv->video_standard = LC_SECAM_NICAM;
- goto tune_channel;
- }
-
-tune_channel:
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
- priv->rf_mode);
- return -EREMOTEIO;
- }
-
- ret = xc_SetTVStandard(priv,
- XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
- return -EREMOTEIO;
- }
-
- xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
-
- xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
-
- if (debug)
- xc_debug_dump(priv);
-
- return 0;
-}
-
-static int xc5000_set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
- u8 radio_input;
-
- dprintk(1, "%s() frequency=%d (in units of khz)\n",
- __func__, params->frequency);
-
- if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
- dprintk(1, "%s() radio input not configured\n", __func__);
- return -EINVAL;
- }
-
- if (priv->radio_input == XC5000_RADIO_FM1)
- radio_input = FM_Radio_INPUT1;
- else if (priv->radio_input == XC5000_RADIO_FM2)
- radio_input = FM_Radio_INPUT2;
- else if (priv->radio_input == XC5000_RADIO_FM1_MONO)
- radio_input = FM_Radio_INPUT1_MONO;
- else {
- dprintk(1, "%s() unknown radio input %d\n", __func__,
- priv->radio_input);
- return -EINVAL;
- }
-
- priv->freq_hz = params->frequency * 125 / 2;
-
- priv->rf_mode = XC_RF_MODE_AIR;
-
- ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
- XC5000_Standard[radio_input].AudioMode);
-
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
- return -EREMOTEIO;
- }
-
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
- priv->rf_mode);
- return -EREMOTEIO;
- }
-
- if ((priv->radio_input == XC5000_RADIO_FM1) ||
- (priv->radio_input == XC5000_RADIO_FM2))
- xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
- else if (priv->radio_input == XC5000_RADIO_FM1_MONO)
- xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
-
- xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
-
- return 0;
-}
-
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
- if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
- dprintk(1, "Unable to load firmware and init tuner\n");
- return -EINVAL;
- }
- }
-
- switch (params->mode) {
- case V4L2_TUNER_RADIO:
- ret = xc5000_set_radio_freq(fe, params);
- break;
- case V4L2_TUNER_ANALOG_TV:
- case V4L2_TUNER_DIGITAL_TV:
- ret = xc5000_set_tv_freq(fe, params);
- break;
- }
-
- return ret;
-}
-
-
-static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- dprintk(1, "%s()\n", __func__);
- *freq = priv->freq_hz;
- 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;
- dprintk(1, "%s()\n", __func__);
-
- *bw = priv->bandwidth;
- return 0;
-}
-
-static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- u16 lock_status = 0;
-
- xc_get_lock_status(priv, &lock_status);
-
- dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
-
- *status = lock_status;
-
- return 0;
-}
-
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- int ret = 0;
-
- if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
- ret = xc5000_fwupload(fe);
- if (ret != XC_RESULT_SUCCESS)
- return ret;
- }
-
- /* Start the tuner self-calibration process */
- ret |= xc_initialize(priv);
-
- /* Wait for calibration to complete.
- * We could continue but XC5000 will clock stretch subsequent
- * I2C transactions until calibration is complete. This way we
- * don't have to rely on clock stretching working.
- */
- xc_wait(100);
-
- /* Default to "CABLE" mode */
- ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
-
- return ret;
-}
-
-static int xc5000_sleep(struct dvb_frontend *fe)
-{
- int ret;
-
- dprintk(1, "%s()\n", __func__);
-
- /* Avoid firmware reload on slow devices */
- if (no_poweroff)
- return 0;
-
- /* According to Xceive technical support, the "powerdown" register
- was removed in newer versions of the firmware. The "supported"
- way to sleep the tuner is to pull the reset pin low for 10ms */
- ret = xc5000_TunerReset(fe);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
- "xc5000: %s() unable to shutdown tuner\n",
- __func__);
- return -EREMOTEIO;
- } else
- return XC_RESULT_SUCCESS;
-}
-
-static int xc5000_init(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- dprintk(1, "%s()\n", __func__);
-
- if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
- return -EREMOTEIO;
- }
-
- if (debug)
- xc_debug_dump(priv);
-
- return 0;
-}
-
-static int xc5000_release(struct dvb_frontend *fe)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
-
- dprintk(1, "%s()\n", __func__);
-
- mutex_lock(&xc5000_list_mutex);
-
- if (priv)
- hybrid_tuner_release_state(priv);
-
- mutex_unlock(&xc5000_list_mutex);
-
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
- struct xc5000_priv *priv = fe->tuner_priv;
- struct xc5000_config *p = priv_cfg;
-
- dprintk(1, "%s()\n", __func__);
-
- if (p->if_khz)
- priv->if_khz = p->if_khz;
-
- if (p->radio_input)
- priv->radio_input = p->radio_input;
-
- return 0;
-}
-
-
-static const struct dvb_tuner_ops xc5000_tuner_ops = {
- .info = {
- .name = "Xceive XC5000",
- .frequency_min = 1000000,
- .frequency_max = 1023000000,
- .frequency_step = 50000,
- },
-
- .release = xc5000_release,
- .init = xc5000_init,
- .sleep = xc5000_sleep,
-
- .set_config = xc5000_set_config,
- .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
-};
-
-struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- const struct xc5000_config *cfg)
-{
- struct xc5000_priv *priv = NULL;
- int instance;
- u16 id = 0;
-
- dprintk(1, "%s(%d-%04x)\n", __func__,
- i2c ? i2c_adapter_id(i2c) : -1,
- cfg ? cfg->i2c_address : -1);
-
- mutex_lock(&xc5000_list_mutex);
-
- instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
- hybrid_tuner_instance_list,
- i2c, cfg->i2c_address, "xc5000");
- switch (instance) {
- case 0:
- goto fail;
- break;
- case 1:
- /* new tuner instance */
- priv->bandwidth = 6000000;
- fe->tuner_priv = priv;
- break;
- default:
- /* existing tuner instance */
- fe->tuner_priv = priv;
- break;
- }
-
- if (priv->if_khz == 0) {
- /* If the IF hasn't been set yet, use the value provided by
- the caller (occurs in hybrid devices where the analog
- call to xc5000_attach occurs before the digital side) */
- priv->if_khz = cfg->if_khz;
- }
-
- if (priv->xtal_khz == 0)
- priv->xtal_khz = cfg->xtal_khz;
-
- 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.
- */
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
- goto fail;
-
- switch (id) {
- case XC_PRODUCT_ID_FW_LOADED:
- printk(KERN_INFO
- "xc5000: Successfully identified at address 0x%02x\n",
- cfg->i2c_address);
- printk(KERN_INFO
- "xc5000: Firmware has been loaded previously\n");
- break;
- case XC_PRODUCT_ID_FW_NOT_LOADED:
- printk(KERN_INFO
- "xc5000: Successfully identified at address 0x%02x\n",
- cfg->i2c_address);
- printk(KERN_INFO
- "xc5000: Firmware has not been loaded previously\n");
- break;
- default:
- printk(KERN_ERR
- "xc5000: Device not found at addr 0x%02x (0x%x)\n",
- cfg->i2c_address, id);
- goto fail;
- }
-
- mutex_unlock(&xc5000_list_mutex);
-
- memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- return fe;
-fail:
- mutex_unlock(&xc5000_list_mutex);
-
- xc5000_release(fe);
- return NULL;
-}
-EXPORT_SYMBOL(xc5000_attach);
-
-MODULE_AUTHOR("Steven Toth");
-MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(XC5000A_FIRMWARE);
-MODULE_FIRMWARE(XC5000C_FIRMWARE);
diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig
new file mode 100644
index 000000000000..fa7a2490ed5f
--- /dev/null
+++ b/drivers/media/dvb-core/Kconfig
@@ -0,0 +1,29 @@
+#
+# DVB device configuration
+#
+
+config DVB_MAX_ADAPTERS
+ int "maximum number of DVB/ATSC adapters"
+ depends on DVB_CORE
+ default 8
+ range 1 255
+ help
+ Maximum number of DVB/ATSC adapters. Increasing this number
+ increases the memory consumption of the DVB subsystem even
+ if a much lower number of DVB/ATSC adapters is present.
+ Only values in the range 4-32 are tested.
+
+ If you are unsure about this, use the default value 8
+
+config DVB_DYNAMIC_MINORS
+ bool "Dynamic DVB minor allocation"
+ depends on DVB_CORE
+ default n
+ help
+ If you say Y here, the DVB subsystem will use dynamic minor
+ allocation for any device that uses the DVB major number.
+ This means that you can have more than 4 of a single type
+ of device (like demuxes and frontends) per adapter, but udev
+ will be required to manage the device nodes.
+
+ If you are unsure about this, say N here.
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
index 8f22bcd7c1f9..8f22bcd7c1f9 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb-core/Makefile
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
index eb91fd808c16..eb91fd808c16 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb-core/demux.h
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
new file mode 100644
index 000000000000..889c9c16c6df
--- /dev/null
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -0,0 +1,1275 @@
+/*
+ * dmxdev.c - DVB demultiplexer device
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include "dmxdev.h"
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk if (debug) printk
+
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+ const u8 *src, size_t len)
+{
+ ssize_t free;
+
+ if (!len)
+ return 0;
+ if (!buf->data)
+ return 0;
+
+ free = dvb_ringbuffer_free(buf);
+ if (len > free) {
+ dprintk("dmxdev: buffer overflow\n");
+ return -EOVERFLOW;
+ }
+
+ return dvb_ringbuffer_write(buf, src, len);
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+ int non_blocking, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ size_t todo;
+ ssize_t avail;
+ ssize_t ret = 0;
+
+ if (!src->data)
+ return 0;
+
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ return ret;
+ }
+
+ for (todo = count; todo > 0; todo -= ret) {
+ if (non_blocking && dvb_ringbuffer_empty(src)) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
+
+ ret = wait_event_interruptible(src->queue,
+ !dvb_ringbuffer_empty(src) ||
+ (src->error != 0));
+ if (ret < 0)
+ break;
+
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ break;
+ }
+
+ avail = dvb_ringbuffer_avail(src);
+ if (avail > todo)
+ avail = todo;
+
+ ret = dvb_ringbuffer_read_user(src, buf, avail);
+ if (ret < 0)
+ break;
+
+ buf += ret;
+ }
+
+ return (count - todo) ? (count - todo) : ret;
+}
+
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
+{
+ struct list_head *head, *pos;
+
+ head = demux->get_frontends(demux);
+ if (!head)
+ return NULL;
+ list_for_each(pos, head)
+ if (DMX_FE_ENTRY(pos)->source == type)
+ return DMX_FE_ENTRY(pos);
+
+ return NULL;
+}
+
+static int dvb_dvr_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ struct dmx_frontend *front;
+
+ dprintk("function : %s\n", __func__);
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
+ if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+ if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ void *mem;
+ if (!dvbdev->readers) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EBUSY;
+ }
+ mem = vmalloc(DVR_BUFFER_SIZE);
+ if (!mem) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENOMEM;
+ }
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+ dvbdev->readers--;
+ }
+
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
+
+ if (!dmxdev->demux->write) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EOPNOTSUPP;
+ }
+
+ front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
+
+ if (!front) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EINVAL;
+ }
+ dmxdev->demux->disconnect_frontend(dmxdev->demux);
+ dmxdev->demux->connect_frontend(dmxdev->demux, front);
+ }
+ dvbdev->users++;
+ mutex_unlock(&dmxdev->mutex);
+ return 0;
+}
+
+static int dvb_dvr_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+
+ mutex_lock(&dmxdev->mutex);
+
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ dmxdev->demux->disconnect_frontend(dmxdev->demux);
+ dmxdev->demux->connect_frontend(dmxdev->demux,
+ dmxdev->dvr_orig_fe);
+ }
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ dvbdev->readers++;
+ if (dmxdev->dvr_buffer.data) {
+ void *mem = dmxdev->dvr_buffer.data;
+ mb();
+ spin_lock_irq(&dmxdev->lock);
+ dmxdev->dvr_buffer.data = NULL;
+ spin_unlock_irq(&dmxdev->lock);
+ vfree(mem);
+ }
+ }
+ /* TODO */
+ dvbdev->users--;
+ if (dvbdev->users == 1 && dmxdev->exit == 1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
+ return 0;
+}
+
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ int ret;
+
+ if (!dmxdev->demux->write)
+ return -EOPNOTSUPP;
+ if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+ ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+}
+
+static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+
+ if (dmxdev->exit)
+ return -ENODEV;
+
+ return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+ unsigned long size)
+{
+ struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+ void *newmem;
+ void *oldmem;
+
+ dprintk("function : %s\n", __func__);
+
+ if (buf->size == size)
+ return 0;
+ if (!size)
+ return -EINVAL;
+
+ newmem = vmalloc(size);
+ if (!newmem)
+ return -ENOMEM;
+
+ oldmem = buf->data;
+
+ spin_lock_irq(&dmxdev->lock);
+ buf->data = newmem;
+ buf->size = size;
+
+ /* reset and not flush in case the buffer shrinks */
+ dvb_ringbuffer_reset(buf);
+ spin_unlock_irq(&dmxdev->lock);
+
+ vfree(oldmem);
+
+ return 0;
+}
+
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+ *dmxdevfilter, int state)
+{
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ dmxdevfilter->state = state;
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+}
+
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+ unsigned long size)
+{
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+ void *newmem;
+ void *oldmem;
+
+ if (buf->size == size)
+ return 0;
+ if (!size)
+ return -EINVAL;
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ newmem = vmalloc(size);
+ if (!newmem)
+ return -ENOMEM;
+
+ oldmem = buf->data;
+
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ buf->data = newmem;
+ buf->size = size;
+
+ /* reset and not flush in case the buffer shrinks */
+ dvb_ringbuffer_reset(buf);
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ vfree(oldmem);
+
+ return 0;
+}
+
+static void dvb_dmxdev_filter_timeout(unsigned long data)
+{
+ struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+
+ dmxdevfilter->buffer.error = -ETIMEDOUT;
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+ dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ wake_up(&dmxdevfilter->buffer.queue);
+}
+
+static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
+
+ del_timer(&dmxdevfilter->timer);
+ if (para->timeout) {
+ dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+ dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+ dmxdevfilter->timer.expires =
+ jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
+ add_timer(&dmxdevfilter->timer);
+ }
+}
+
+static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
+ const u8 *buffer2, size_t buffer2_len,
+ struct dmx_section_filter *filter,
+ enum dmx_success success)
+{
+ struct dmxdev_filter *dmxdevfilter = filter->priv;
+ int ret;
+
+ if (dmxdevfilter->buffer.error) {
+ wake_up(&dmxdevfilter->buffer.queue);
+ return 0;
+ }
+ spin_lock(&dmxdevfilter->dev->lock);
+ if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+ del_timer(&dmxdevfilter->timer);
+ dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
+ ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+ buffer1_len);
+ if (ret == buffer1_len) {
+ ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+ buffer2_len);
+ }
+ if (ret < 0) {
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ dmxdevfilter->buffer.error = ret;
+ }
+ if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+ dmxdevfilter->state = DMXDEV_STATE_DONE;
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up(&dmxdevfilter->buffer.queue);
+ return 0;
+}
+
+static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
+ const u8 *buffer2, size_t buffer2_len,
+ struct dmx_ts_feed *feed,
+ enum dmx_success success)
+{
+ struct dmxdev_filter *dmxdevfilter = feed->priv;
+ struct dvb_ringbuffer *buffer;
+ int ret;
+
+ spin_lock(&dmxdevfilter->dev->lock);
+ if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ buffer = &dmxdevfilter->buffer;
+ else
+ buffer = &dmxdevfilter->dev->dvr_buffer;
+ if (buffer->error) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up(&buffer->queue);
+ return 0;
+ }
+ ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+ if (ret == buffer1_len)
+ ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+ if (ret < 0) {
+ dvb_ringbuffer_flush(buffer);
+ buffer->error = ret;
+ }
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up(&buffer->queue);
+ return 0;
+}
+
+/* stop feed but only mark the specified filter as stopped (state set) */
+static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmxdev_feed *feed;
+
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+ switch (dmxdevfilter->type) {
+ case DMXDEV_TYPE_SEC:
+ del_timer(&dmxdevfilter->timer);
+ dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
+ break;
+ case DMXDEV_TYPE_PES:
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+ feed->ts->stop_filtering(feed->ts);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* start feed associated with the specified filter */
+static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
+{
+ struct dmxdev_feed *feed;
+ int ret;
+
+ dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+ switch (filter->type) {
+ case DMXDEV_TYPE_SEC:
+ return filter->feed.sec->start_filtering(filter->feed.sec);
+ case DMXDEV_TYPE_PES:
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = feed->ts->start_filtering(feed->ts);
+ if (ret < 0) {
+ dvb_dmxdev_feed_stop(filter);
+ return ret;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* restart section feed if it has filters left associated with it,
+ otherwise release the feed */
+static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
+{
+ int i;
+ struct dmxdev *dmxdev = filter->dev;
+ u16 pid = filter->params.sec.pid;
+
+ for (i = 0; i < dmxdev->filternum; i++)
+ if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+ dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+ dmxdev->filter[i].params.sec.pid == pid) {
+ dvb_dmxdev_feed_start(&dmxdev->filter[i]);
+ return 0;
+ }
+
+ filter->dev->demux->release_section_feed(dmxdev->demux,
+ filter->feed.sec);
+
+ return 0;
+}
+
+static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmxdev_feed *feed;
+ struct dmx_demux *demux;
+
+ if (dmxdevfilter->state < DMXDEV_STATE_GO)
+ return 0;
+
+ switch (dmxdevfilter->type) {
+ case DMXDEV_TYPE_SEC:
+ if (!dmxdevfilter->feed.sec)
+ break;
+ dvb_dmxdev_feed_stop(dmxdevfilter);
+ if (dmxdevfilter->filter.sec)
+ dmxdevfilter->feed.sec->
+ release_filter(dmxdevfilter->feed.sec,
+ dmxdevfilter->filter.sec);
+ dvb_dmxdev_feed_restart(dmxdevfilter);
+ dmxdevfilter->feed.sec = NULL;
+ break;
+ case DMXDEV_TYPE_PES:
+ dvb_dmxdev_feed_stop(dmxdevfilter);
+ demux = dmxdevfilter->dev->demux;
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+ demux->release_ts_feed(demux, feed->ts);
+ feed->ts = NULL;
+ }
+ break;
+ default:
+ if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
+ return 0;
+ return -EINVAL;
+ }
+
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ return 0;
+}
+
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ /* delete all PIDs */
+ list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+ list_del(&feed->next);
+ kfree(feed);
+ }
+
+ BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
+static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
+{
+ if (dmxdevfilter->state < DMXDEV_STATE_SET)
+ return 0;
+
+ if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+ dvb_dmxdev_delete_pids(dmxdevfilter);
+
+ dmxdevfilter->type = DMXDEV_TYPE_NONE;
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+ return 0;
+}
+
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmxdev_feed *feed)
+{
+ struct timespec timeout = { 0 };
+ struct dmx_pes_filter_params *para = &filter->params.pes;
+ dmx_output_t otype;
+ int ret;
+ int ts_type;
+ dmx_pes_type_t ts_pes;
+ struct dmx_ts_feed *tsfeed;
+
+ feed->ts = NULL;
+ otype = para->output;
+
+ ts_pes = para->pes_type;
+
+ if (ts_pes < DMX_PES_OTHER)
+ ts_type = TS_DECODER;
+ else
+ ts_type = 0;
+
+ if (otype == DMX_OUT_TS_TAP)
+ ts_type |= TS_PACKET;
+ else if (otype == DMX_OUT_TSDEMUX_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX;
+ else if (otype == DMX_OUT_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+ ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+ dvb_dmxdev_ts_callback);
+ if (ret < 0)
+ return ret;
+
+ tsfeed = feed->ts;
+ tsfeed->priv = filter;
+
+ ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ ret = tsfeed->start_filtering(tsfeed);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
+{
+ struct dmxdev *dmxdev = filter->dev;
+ struct dmxdev_feed *feed;
+ void *mem;
+ int ret, i;
+
+ if (filter->state < DMXDEV_STATE_SET)
+ return -EINVAL;
+
+ if (filter->state >= DMXDEV_STATE_GO)
+ dvb_dmxdev_filter_stop(filter);
+
+ if (!filter->buffer.data) {
+ mem = vmalloc(filter->buffer.size);
+ if (!mem)
+ return -ENOMEM;
+ spin_lock_irq(&filter->dev->lock);
+ filter->buffer.data = mem;
+ spin_unlock_irq(&filter->dev->lock);
+ }
+
+ dvb_ringbuffer_flush(&filter->buffer);
+
+ switch (filter->type) {
+ case DMXDEV_TYPE_SEC:
+ {
+ struct dmx_sct_filter_params *para = &filter->params.sec;
+ struct dmx_section_filter **secfilter = &filter->filter.sec;
+ struct dmx_section_feed **secfeed = &filter->feed.sec;
+
+ *secfilter = NULL;
+ *secfeed = NULL;
+
+
+ /* find active filter/feed with same PID */
+ for (i = 0; i < dmxdev->filternum; i++) {
+ if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+ dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+ dmxdev->filter[i].params.sec.pid == para->pid) {
+ *secfeed = dmxdev->filter[i].feed.sec;
+ break;
+ }
+ }
+
+ /* if no feed found, try to allocate new one */
+ if (!*secfeed) {
+ ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+ secfeed,
+ dvb_dmxdev_section_callback);
+ if (ret < 0) {
+ printk("DVB (%s): could not alloc feed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+ (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+ if (ret < 0) {
+ printk("DVB (%s): could not set feed\n",
+ __func__);
+ dvb_dmxdev_feed_restart(filter);
+ return ret;
+ }
+ } else {
+ dvb_dmxdev_feed_stop(filter);
+ }
+
+ ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
+ if (ret < 0) {
+ dvb_dmxdev_feed_restart(filter);
+ filter->feed.sec->start_filtering(*secfeed);
+ dprintk("could not get filter\n");
+ return ret;
+ }
+
+ (*secfilter)->priv = filter;
+
+ memcpy(&((*secfilter)->filter_value[3]),
+ &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
+ memcpy(&(*secfilter)->filter_mask[3],
+ &para->filter.mask[1], DMX_FILTER_SIZE - 1);
+ memcpy(&(*secfilter)->filter_mode[3],
+ &para->filter.mode[1], DMX_FILTER_SIZE - 1);
+
+ (*secfilter)->filter_value[0] = para->filter.filter[0];
+ (*secfilter)->filter_mask[0] = para->filter.mask[0];
+ (*secfilter)->filter_mode[0] = para->filter.mode[0];
+ (*secfilter)->filter_mask[1] = 0;
+ (*secfilter)->filter_mask[2] = 0;
+
+ filter->todo = 0;
+
+ ret = filter->feed.sec->start_filtering(filter->feed.sec);
+ if (ret < 0)
+ return ret;
+
+ dvb_dmxdev_filter_timer(filter);
+ break;
+ }
+ case DMXDEV_TYPE_PES:
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+ if (ret < 0) {
+ dvb_dmxdev_filter_stop(filter);
+ return ret;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+ return 0;
+}
+
+static int dvb_demux_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ int i;
+ struct dmxdev_filter *dmxdevfilter;
+
+ if (!dmxdev->filter)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ for (i = 0; i < dmxdev->filternum; i++)
+ if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
+ break;
+
+ if (i == dmxdev->filternum) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EMFILE;
+ }
+
+ dmxdevfilter = &dmxdev->filter[i];
+ mutex_init(&dmxdevfilter->mutex);
+ file->private_data = dmxdevfilter;
+
+ dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+ dmxdevfilter->type = DMXDEV_TYPE_NONE;
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+ init_timer(&dmxdevfilter->timer);
+
+ dvbdev->users++;
+
+ mutex_unlock(&dmxdev->mutex);
+ return 0;
+}
+
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+ struct dmxdev_filter *dmxdevfilter)
+{
+ mutex_lock(&dmxdev->mutex);
+ mutex_lock(&dmxdevfilter->mutex);
+
+ dvb_dmxdev_filter_stop(dmxdevfilter);
+ dvb_dmxdev_filter_reset(dmxdevfilter);
+
+ if (dmxdevfilter->buffer.data) {
+ void *mem = dmxdevfilter->buffer.data;
+
+ spin_lock_irq(&dmxdev->lock);
+ dmxdevfilter->buffer.data = NULL;
+ spin_unlock_irq(&dmxdev->lock);
+ vfree(mem);
+ }
+
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
+ wake_up(&dmxdevfilter->buffer.queue);
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
+ return 0;
+}
+
+static inline void invert_mode(dmx_filter_t *filter)
+{
+ int i;
+
+ for (i = 0; i < DMX_FILTER_SIZE; i++)
+ filter->mode[i] ^= 0xff;
+}
+
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ /* only TS packet filters may have multiple PIDs */
+ if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+ (!list_empty(&filter->feed.ts)))
+ return -EINVAL;
+
+ feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+ if (feed == NULL)
+ return -ENOMEM;
+
+ feed->pid = pid;
+ list_add(&feed->next, &filter->feed.ts);
+
+ if (filter->state >= DMXDEV_STATE_GO)
+ return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+ return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+ if ((feed->pid == pid) && (feed->ts != NULL)) {
+ feed->ts->stop_filtering(feed->ts);
+ filter->dev->demux->release_ts_feed(filter->dev->demux,
+ feed->ts);
+ list_del(&feed->next);
+ kfree(feed);
+ }
+ }
+
+ return 0;
+}
+
+static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
+ struct dmxdev_filter *dmxdevfilter,
+ struct dmx_sct_filter_params *params)
+{
+ dprintk("function : %s\n", __func__);
+
+ dvb_dmxdev_filter_stop(dmxdevfilter);
+
+ dmxdevfilter->type = DMXDEV_TYPE_SEC;
+ memcpy(&dmxdevfilter->params.sec,
+ params, sizeof(struct dmx_sct_filter_params));
+ invert_mode(&dmxdevfilter->params.sec.filter);
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+ if (params->flags & DMX_IMMEDIATE_START)
+ return dvb_dmxdev_filter_start(dmxdevfilter);
+
+ return 0;
+}
+
+static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
+ struct dmxdev_filter *dmxdevfilter,
+ struct dmx_pes_filter_params *params)
+{
+ int ret;
+
+ dvb_dmxdev_filter_stop(dmxdevfilter);
+ dvb_dmxdev_filter_reset(dmxdevfilter);
+
+ if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
+ return -EINVAL;
+
+ dmxdevfilter->type = DMXDEV_TYPE_PES;
+ memcpy(&dmxdevfilter->params, params,
+ sizeof(struct dmx_pes_filter_params));
+ INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
+
+ dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+ dmxdevfilter->params.pes.pid);
+ if (ret < 0)
+ return ret;
+
+ if (params->flags & DMX_IMMEDIATE_START)
+ return dvb_dmxdev_filter_start(dmxdevfilter);
+
+ return 0;
+}
+
+static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
+ struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int result, hcount;
+ int done = 0;
+
+ if (dfil->todo <= 0) {
+ hcount = 3 + dfil->todo;
+ if (hcount > count)
+ hcount = count;
+ result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, hcount, ppos);
+ if (result < 0) {
+ dfil->todo = 0;
+ return result;
+ }
+ if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
+ return -EFAULT;
+ buf += result;
+ done = result;
+ count -= result;
+ dfil->todo -= result;
+ if (dfil->todo > -3)
+ return done;
+ dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
+ if (!count)
+ return done;
+ }
+ if (count > dfil->todo)
+ count = dfil->todo;
+ result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+ if (result < 0)
+ return result;
+ dfil->todo -= result;
+ return (result + done);
+}
+
+static ssize_t
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex))
+ return -ERESTARTSYS;
+
+ if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+ ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+ else
+ ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+
+ mutex_unlock(&dmxdevfilter->mutex);
+ return ret;
+}
+
+static int dvb_demux_do_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+ unsigned long arg = (unsigned long)parg;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ switch (cmd) {
+ case DMX_START:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ if (dmxdevfilter->state < DMXDEV_STATE_SET)
+ ret = -EINVAL;
+ else
+ ret = dvb_dmxdev_filter_start(dmxdevfilter);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_STOP:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_FILTER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_PES_FILTER:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_BUFFER_SIZE:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_GET_PES_PIDS:
+ if (!dmxdev->demux->get_pes_pids) {
+ ret = -EINVAL;
+ break;
+ }
+ dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
+ break;
+
+ case DMX_GET_CAPS:
+ if (!dmxdev->demux->get_caps) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
+ break;
+
+ case DMX_SET_SOURCE:
+ if (!dmxdev->demux->set_source) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+ break;
+
+ case DMX_GET_STC:
+ if (!dmxdev->demux->get_stc) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = dmxdev->demux->get_stc(dmxdev->demux,
+ ((struct dmx_stc *)parg)->num,
+ &((struct dmx_stc *)parg)->stc,
+ &((struct dmx_stc *)parg)->base);
+ break;
+
+ case DMX_ADD_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_REMOVE_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+}
+
+static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
+}
+
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
+{
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
+ unsigned int mask = 0;
+
+ if (!dmxdevfilter)
+ return -EINVAL;
+
+ poll_wait(file, &dmxdevfilter->buffer.queue, wait);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO &&
+ dmxdevfilter->state != DMXDEV_STATE_DONE &&
+ dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
+ return 0;
+
+ if (dmxdevfilter->buffer.error)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+ if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
+ return mask;
+}
+
+static int dvb_demux_release(struct inode *inode, struct file *file)
+{
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+
+ int ret;
+
+ ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+ mutex_lock(&dmxdev->mutex);
+ dmxdev->dvbdev->users--;
+ if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dmxdev->dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
+ return ret;
+}
+
+static const struct file_operations dvb_demux_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_demux_read,
+ .unlocked_ioctl = dvb_demux_ioctl,
+ .open = dvb_demux_open,
+ .release = dvb_demux_release,
+ .poll = dvb_demux_poll,
+ .llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_demux = {
+ .priv = NULL,
+ .users = 1,
+ .writers = 1,
+ .fops = &dvb_demux_fops
+};
+
+static int dvb_dvr_do_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ unsigned long arg = (unsigned long)parg;
+ int ret;
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ switch (cmd) {
+ case DMX_SET_BUFFER_SIZE:
+ ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+}
+
+static long dvb_dvr_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
+}
+
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ unsigned int mask = 0;
+
+ dprintk("function : %s\n", __func__);
+
+ poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ if (dmxdev->dvr_buffer.error)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+ if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+ } else
+ mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+
+ return mask;
+}
+
+static const struct file_operations dvb_dvr_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_dvr_read,
+ .write = dvb_dvr_write,
+ .unlocked_ioctl = dvb_dvr_ioctl,
+ .open = dvb_dvr_open,
+ .release = dvb_dvr_release,
+ .poll = dvb_dvr_poll,
+ .llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_dvr = {
+ .priv = NULL,
+ .readers = 1,
+ .users = 1,
+ .fops = &dvb_dvr_fops
+};
+
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+{
+ int i;
+
+ if (dmxdev->demux->open(dmxdev->demux) < 0)
+ return -EUSERS;
+
+ dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
+ if (!dmxdev->filter)
+ return -ENOMEM;
+
+ mutex_init(&dmxdev->mutex);
+ spin_lock_init(&dmxdev->lock);
+ for (i = 0; i < dmxdev->filternum; i++) {
+ dmxdev->filter[i].dev = dmxdev;
+ dmxdev->filter[i].buffer.data = NULL;
+ dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+ DMXDEV_STATE_FREE);
+ }
+
+ dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+ DVB_DEVICE_DEMUX);
+ dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+ dmxdev, DVB_DEVICE_DVR);
+
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_init);
+
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
+{
+ dmxdev->exit=1;
+ if (dmxdev->dvbdev->users > 1) {
+ wait_event(dmxdev->dvbdev->wait_queue,
+ dmxdev->dvbdev->users==1);
+ }
+ if (dmxdev->dvr_dvbdev->users > 1) {
+ wait_event(dmxdev->dvr_dvbdev->wait_queue,
+ dmxdev->dvr_dvbdev->users==1);
+ }
+
+ dvb_unregister_device(dmxdev->dvbdev);
+ dvb_unregister_device(dmxdev->dvr_dvbdev);
+
+ vfree(dmxdev->filter);
+ dmxdev->filter = NULL;
+ dmxdev->demux->close(dmxdev->demux);
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h
index 02ebe28f830d..02ebe28f830d 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb-core/dmxdev.h
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 26c44818a5ab..26c44818a5ab 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 9be65a3b931f..9be65a3b931f 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb-core/dvb_ca_en50221.h
index 7df2e141187a..7df2e141187a 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
+++ b/drivers/media/dvb-core/dvb_ca_en50221.h
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
new file mode 100644
index 000000000000..17cb81fd194c
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -0,0 +1,1318 @@
+/*
+ * dvb_demux.c - DVB kernel demux API
+ *
+ * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
+ * & Marcus Metzler <marcus@convergence.de>
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/crc32.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#include "dvb_demux.h"
+
+#define NOBUFS
+/*
+** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
+*/
+// #define DVB_DEMUX_SECTION_LOSS_LOG
+
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+ "enable transport stream continuity and TEI check");
+
+static int dvb_demux_speedcheck;
+module_param(dvb_demux_speedcheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_speedcheck,
+ "enable transport stream speed check");
+
+static int dvb_demux_feed_err_pkts = 1;
+module_param(dvb_demux_feed_err_pkts, int, 0644);
+MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
+ "when set to 0, drop packets with the TEI bit set (1 by default)");
+
+#define dprintk_tscheck(x...) do { \
+ if (dvb_demux_tscheck && printk_ratelimit()) \
+ printk(x); \
+ } while (0)
+
+/******************************************************************************
+ * static inlined helper functions
+ ******************************************************************************/
+
+static inline u16 section_length(const u8 *buf)
+{
+ return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
+}
+
+static inline u16 ts_pid(const u8 *buf)
+{
+ return ((buf[1] & 0x1f) << 8) + buf[2];
+}
+
+static inline u8 payload(const u8 *tsp)
+{
+ if (!(tsp[3] & 0x10)) // no payload?
+ return 0;
+
+ if (tsp[3] & 0x20) { // adaptation field?
+ if (tsp[4] > 183) // corrupted data?
+ return 0;
+ else
+ return 184 - 1 - tsp[4];
+ }
+
+ return 184;
+}
+
+static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
+{
+ return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
+}
+
+static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
+ size_t len)
+{
+ memcpy(d, s, len);
+}
+
+/******************************************************************************
+ * Software filter functions
+ ******************************************************************************/
+
+static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ int count = payload(buf);
+ int p;
+ //int ccok;
+ //u8 cc;
+
+ if (count == 0)
+ return -1;
+
+ p = 188 - count;
+
+ /*
+ cc = buf[3] & 0x0f;
+ ccok = ((feed->cc + 1) & 0x0f) == cc;
+ feed->cc = cc;
+ if (!ccok)
+ printk("missed packet!\n");
+ */
+
+ if (buf[1] & 0x40) // PUSI ?
+ feed->peslen = 0xfffa;
+
+ feed->peslen += count;
+
+ return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
+}
+
+static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
+ struct dvb_demux_filter *f)
+{
+ u8 neq = 0;
+ int i;
+
+ for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+ u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
+
+ if (f->maskandmode[i] & xor)
+ return 0;
+
+ neq |= f->maskandnotmode[i] & xor;
+ }
+
+ if (f->doneq && !neq)
+ return 0;
+
+ return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
+ NULL, 0, &f->filter, DMX_OK);
+}
+
+static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct dvb_demux_filter *f = feed->filter;
+ struct dmx_section_feed *sec = &feed->feed.sec;
+ int section_syntax_indicator;
+
+ if (!sec->is_filtering)
+ return 0;
+
+ if (!f)
+ return 0;
+
+ if (sec->check_crc) {
+ section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
+ if (section_syntax_indicator &&
+ demux->check_crc32(feed, sec->secbuf, sec->seclen))
+ return -1;
+ }
+
+ do {
+ if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
+ return -1;
+ } while ((f = f->next) && sec->is_filtering);
+
+ sec->seclen = 0;
+
+ return 0;
+}
+
+static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
+{
+ struct dmx_section_feed *sec = &feed->feed.sec;
+
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+ if (sec->secbufp < sec->tsfeedp) {
+ int i, n = sec->tsfeedp - sec->secbufp;
+
+ /*
+ * Section padding is done with 0xff bytes entirely.
+ * Due to speed reasons, we won't check all of them
+ * but just first and last.
+ */
+ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
+ printk("dvb_demux.c section ts padding loss: %d/%d\n",
+ n, sec->tsfeedp);
+ printk("dvb_demux.c pad data:");
+ for (i = 0; i < n; i++)
+ printk(" %02x", sec->secbuf[i]);
+ printk("\n");
+ }
+ }
+#endif
+
+ sec->tsfeedp = sec->secbufp = sec->seclen = 0;
+ sec->secbuf = sec->secbuf_base;
+}
+
+/*
+ * Losless Section Demux 1.4.1 by Emard
+ * Valsecchi Patrick:
+ * - middle of section A (no PUSI)
+ * - end of section A and start of section B
+ * (with PUSI pointing to the start of the second section)
+ *
+ * In this case, without feed->pusi_seen you'll receive a garbage section
+ * consisting of the end of section A. Basically because tsfeedp
+ * is incemented and the use=0 condition is not raised
+ * when the second packet arrives.
+ *
+ * Fix:
+ * when demux is started, let feed->pusi_seen = 0 to
+ * prevent initial feeding of garbage from the end of
+ * previous section. When you for the first time see PUSI=1
+ * then set feed->pusi_seen = 1
+ */
+static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
+ const u8 *buf, u8 len)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct dmx_section_feed *sec = &feed->feed.sec;
+ u16 limit, seclen, n;
+
+ if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
+ return 0;
+
+ if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+ printk("dvb_demux.c section buffer full loss: %d/%d\n",
+ sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
+ DMX_MAX_SECFEED_SIZE);
+#endif
+ len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
+ }
+
+ if (len <= 0)
+ return 0;
+
+ demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
+ sec->tsfeedp += len;
+
+ /*
+ * Dump all the sections we can find in the data (Emard)
+ */
+ limit = sec->tsfeedp;
+ if (limit > DMX_MAX_SECFEED_SIZE)
+ return -1; /* internal error should never happen */
+
+ /* to be sure always set secbuf */
+ sec->secbuf = sec->secbuf_base + sec->secbufp;
+
+ for (n = 0; sec->secbufp + 2 < limit; n++) {
+ seclen = section_length(sec->secbuf);
+ if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
+ || seclen + sec->secbufp > limit)
+ return 0;
+ sec->seclen = seclen;
+ sec->crc_val = ~0;
+ /* dump [secbuf .. secbuf+seclen) */
+ if (feed->pusi_seen)
+ dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+ else
+ printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
+ sec->secbufp += seclen; /* secbufp and secbuf moving together is */
+ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
+ }
+
+ return 0;
+}
+
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ u8 p, count;
+ int ccok, dc_i = 0;
+ u8 cc;
+
+ count = payload(buf);
+
+ if (count == 0) /* count == 0 if no payload or out of range */
+ return -1;
+
+ p = 188 - count; /* payload start */
+
+ cc = buf[3] & 0x0f;
+ ccok = ((feed->cc + 1) & 0x0f) == cc;
+ feed->cc = cc;
+
+ if (buf[3] & 0x20) {
+ /* adaption field present, check for discontinuity_indicator */
+ if ((buf[4] > 0) && (buf[5] & 0x80))
+ dc_i = 1;
+ }
+
+ if (!ccok || dc_i) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+ printk("dvb_demux.c discontinuity detected %d bytes lost\n",
+ count);
+ /*
+ * those bytes under sume circumstances will again be reported
+ * in the following dvb_dmx_swfilter_section_new
+ */
+#endif
+ /*
+ * Discontinuity detected. Reset pusi_seen = 0 to
+ * stop feeding of suspicious data until next PUSI=1 arrives
+ */
+ feed->pusi_seen = 0;
+ dvb_dmx_swfilter_section_new(feed);
+ }
+
+ if (buf[1] & 0x40) {
+ /* PUSI=1 (is set), section boundary is here */
+ if (count > 1 && buf[p] < count) {
+ const u8 *before = &buf[p + 1];
+ u8 before_len = buf[p];
+ const u8 *after = &before[before_len];
+ u8 after_len = count - 1 - before_len;
+
+ dvb_dmx_swfilter_section_copy_dump(feed, before,
+ before_len);
+ /* before start of new section, set pusi_seen = 1 */
+ feed->pusi_seen = 1;
+ dvb_dmx_swfilter_section_new(feed);
+ dvb_dmx_swfilter_section_copy_dump(feed, after,
+ after_len);
+ }
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+ else if (count > 0)
+ printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
+#endif
+ } else {
+ /* PUSI=0 (is not set), no section boundary */
+ dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
+ }
+
+ return 0;
+}
+
+static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ switch (feed->type) {
+ case DMX_TYPE_TS:
+ if (!feed->feed.ts.is_filtering)
+ break;
+ if (feed->ts_type & TS_PACKET) {
+ if (feed->ts_type & TS_PAYLOAD_ONLY)
+ dvb_dmx_swfilter_payload(feed, buf);
+ else
+ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
+ DMX_OK);
+ }
+ if (feed->ts_type & TS_DECODER)
+ if (feed->demux->write_to_decoder)
+ feed->demux->write_to_decoder(feed, buf, 188);
+ break;
+
+ case DMX_TYPE_SEC:
+ if (!feed->feed.sec.is_filtering)
+ break;
+ if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
+ feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+#define DVR_FEED(f) \
+ (((f)->type == DMX_TYPE_TS) && \
+ ((f)->feed.ts.is_filtering) && \
+ (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
+
+static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+{
+ struct dvb_demux_feed *feed;
+ u16 pid = ts_pid(buf);
+ int dvr_done = 0;
+
+ if (dvb_demux_speedcheck) {
+ struct timespec cur_time, delta_time;
+ u64 speed_bytes, speed_timedelta;
+
+ demux->speed_pkts_cnt++;
+
+ /* show speed every SPEED_PKTS_INTERVAL packets */
+ if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
+ cur_time = current_kernel_time();
+
+ if (demux->speed_last_time.tv_sec != 0 &&
+ demux->speed_last_time.tv_nsec != 0) {
+ delta_time = timespec_sub(cur_time,
+ demux->speed_last_time);
+ speed_bytes = (u64)demux->speed_pkts_cnt
+ * 188 * 8;
+ /* convert to 1024 basis */
+ speed_bytes = 1000 * div64_u64(speed_bytes,
+ 1024);
+ speed_timedelta =
+ (u64)timespec_to_ns(&delta_time);
+ speed_timedelta = div64_u64(speed_timedelta,
+ 1000000); /* nsec -> usec */
+ printk(KERN_INFO "TS speed %llu Kbits/sec \n",
+ div64_u64(speed_bytes,
+ speed_timedelta));
+ };
+
+ demux->speed_last_time = cur_time;
+ demux->speed_pkts_cnt = 0;
+ };
+ };
+
+ if (buf[1] & 0x80) {
+ dprintk_tscheck("TEI detected. "
+ "PID=0x%x data1=0x%x\n",
+ pid, buf[1]);
+ /* data in this packet cant be trusted - drop it unless
+ * module option dvb_demux_feed_err_pkts is set */
+ if (!dvb_demux_feed_err_pkts)
+ return;
+ } else /* if TEI bit is set, pid may be wrong- skip pkt counter */
+ if (demux->cnt_storage && dvb_demux_tscheck) {
+ /* check pkt counter */
+ if (pid < MAX_PID) {
+ if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+ dprintk_tscheck("TS packet counter mismatch. "
+ "PID=0x%x expected 0x%x "
+ "got 0x%x\n",
+ pid, demux->cnt_storage[pid],
+ buf[3] & 0xf);
+
+ demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+ };
+ /* end check */
+ };
+
+ list_for_each_entry(feed, &demux->feed_list, list_head) {
+ if ((feed->pid != pid) && (feed->pid != 0x2000))
+ continue;
+
+ /* copy each packet only once to the dvr device, even
+ * if a PID is in multiple filters (e.g. video + PCR) */
+ if ((DVR_FEED(feed)) && (dvr_done++))
+ continue;
+
+ if (feed->pid == pid)
+ dvb_dmx_swfilter_packet_type(feed, buf);
+ else if (feed->pid == 0x2000)
+ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+ }
+}
+
+void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+ size_t count)
+{
+ spin_lock(&demux->lock);
+
+ while (count--) {
+ if (buf[0] == 0x47)
+ dvb_dmx_swfilter_packet(demux, buf);
+ buf += 188;
+ }
+
+ spin_unlock(&demux->lock);
+}
+
+EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+
+static inline int find_next_packet(const u8 *buf, int pos, size_t count,
+ const int pktsize)
+{
+ int start = pos, lost;
+
+ while (pos < count) {
+ if (buf[pos] == 0x47 ||
+ (pktsize == 204 && buf[pos] == 0xB8))
+ break;
+ pos++;
+ }
+
+ lost = pos - start;
+ if (lost) {
+ /* This garbage is part of a valid packet? */
+ int backtrack = pos - pktsize;
+ if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
+ (pktsize == 204 && buf[backtrack] == 0xB8)))
+ return backtrack;
+ }
+
+ return pos;
+}
+
+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
+ size_t count, const int pktsize)
+{
+ int p = 0, i, j;
+ const u8 *q;
+
+ spin_lock(&demux->lock);
+
+ if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+ i = demux->tsbufp;
+ j = pktsize - i;
+ if (count < j) {
+ memcpy(&demux->tsbuf[i], buf, count);
+ demux->tsbufp += count;
+ goto bailout;
+ }
+ memcpy(&demux->tsbuf[i], buf, j);
+ if (demux->tsbuf[0] == 0x47) /* double check */
+ dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+ demux->tsbufp = 0;
+ p += j;
+ }
+
+ while (1) {
+ p = find_next_packet(buf, p, count, pktsize);
+ if (p >= count)
+ break;
+ if (count - p < pktsize)
+ break;
+
+ q = &buf[p];
+
+ if (pktsize == 204 && (*q == 0xB8)) {
+ memcpy(demux->tsbuf, q, 188);
+ demux->tsbuf[0] = 0x47;
+ q = demux->tsbuf;
+ }
+ dvb_dmx_swfilter_packet(demux, q);
+ p += pktsize;
+ }
+
+ i = count - p;
+ if (i) {
+ memcpy(demux->tsbuf, &buf[p], i);
+ demux->tsbufp = i;
+ if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
+ demux->tsbuf[0] = 0x47;
+ }
+
+bailout:
+ spin_unlock(&demux->lock);
+}
+
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ _dvb_dmx_swfilter(demux, buf, count, 188);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter);
+
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ _dvb_dmx_swfilter(demux, buf, count, 204);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ spin_lock(&demux->lock);
+
+ demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+
+ spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
+
+static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+{
+ int i;
+
+ for (i = 0; i < demux->filternum; i++)
+ if (demux->filter[i].state == DMX_STATE_FREE)
+ break;
+
+ if (i == demux->filternum)
+ return NULL;
+
+ demux->filter[i].state = DMX_STATE_ALLOCATED;
+
+ return &demux->filter[i];
+}
+
+static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
+{
+ int i;
+
+ for (i = 0; i < demux->feednum; i++)
+ if (demux->feed[i].state == DMX_STATE_FREE)
+ break;
+
+ if (i == demux->feednum)
+ return NULL;
+
+ demux->feed[i].state = DMX_STATE_ALLOCATED;
+
+ return &demux->feed[i];
+}
+
+static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux_feed *entry;
+
+ list_for_each_entry(entry, &feed->demux->feed_list, list_head)
+ if (entry == feed)
+ return 1;
+
+ return 0;
+}
+
+static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
+{
+ spin_lock_irq(&feed->demux->lock);
+ if (dvb_demux_feed_find(feed)) {
+ printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
+ __func__, feed->type, feed->state, feed->pid);
+ goto out;
+ }
+
+ list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+ spin_unlock_irq(&feed->demux->lock);
+}
+
+static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
+{
+ spin_lock_irq(&feed->demux->lock);
+ if (!(dvb_demux_feed_find(feed))) {
+ printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
+ __func__, feed->type, feed->state, feed->pid);
+ goto out;
+ }
+
+ list_del(&feed->list_head);
+out:
+ spin_unlock_irq(&feed->demux->lock);
+}
+
+static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
+ enum dmx_ts_pes pes_type,
+ size_t circular_buffer_size, struct timespec timeout)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ if (pid > DMX_MAX_PID)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&demux->mutex))
+ return -ERESTARTSYS;
+
+ if (ts_type & TS_DECODER) {
+ if (pes_type >= DMX_TS_PES_OTHER) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+
+ if (demux->pesfilter[pes_type] &&
+ demux->pesfilter[pes_type] != feed) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+
+ demux->pesfilter[pes_type] = feed;
+ demux->pids[pes_type] = pid;
+ }
+
+ dvb_demux_feed_add(feed);
+
+ feed->pid = pid;
+ feed->buffer_size = circular_buffer_size;
+ feed->timeout = timeout;
+ feed->ts_type = ts_type;
+ feed->pes_type = pes_type;
+
+ if (feed->buffer_size) {
+#ifdef NOBUFS
+ feed->buffer = NULL;
+#else
+ feed->buffer = vmalloc(feed->buffer_size);
+ if (!feed->buffer) {
+ mutex_unlock(&demux->mutex);
+ return -ENOMEM;
+ }
+#endif
+ }
+
+ feed->state = DMX_STATE_READY;
+ mutex_unlock(&demux->mutex);
+
+ return 0;
+}
+
+static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+ int ret;
+
+ if (mutex_lock_interruptible(&demux->mutex))
+ return -ERESTARTSYS;
+
+ if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+
+ if (!demux->start_feed) {
+ mutex_unlock(&demux->mutex);
+ return -ENODEV;
+ }
+
+ if ((ret = demux->start_feed(feed)) < 0) {
+ mutex_unlock(&demux->mutex);
+ return ret;
+ }
+
+ spin_lock_irq(&demux->lock);
+ ts_feed->is_filtering = 1;
+ feed->state = DMX_STATE_GO;
+ spin_unlock_irq(&demux->lock);
+ mutex_unlock(&demux->mutex);
+
+ return 0;
+}
+
+static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+ int ret;
+
+ mutex_lock(&demux->mutex);
+
+ if (feed->state < DMX_STATE_GO) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+
+ if (!demux->stop_feed) {
+ mutex_unlock(&demux->mutex);
+ return -ENODEV;
+ }
+
+ ret = demux->stop_feed(feed);
+
+ spin_lock_irq(&demux->lock);
+ ts_feed->is_filtering = 0;
+ feed->state = DMX_STATE_ALLOCATED;
+ spin_unlock_irq(&demux->lock);
+ mutex_unlock(&demux->mutex);
+
+ return ret;
+}
+
+static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
+ struct dmx_ts_feed **ts_feed,
+ dmx_ts_cb callback)
+{
+ struct dvb_demux *demux = (struct dvb_demux *)dmx;
+ struct dvb_demux_feed *feed;
+
+ if (mutex_lock_interruptible(&demux->mutex))
+ return -ERESTARTSYS;
+
+ if (!(feed = dvb_dmx_feed_alloc(demux))) {
+ mutex_unlock(&demux->mutex);
+ return -EBUSY;
+ }
+
+ feed->type = DMX_TYPE_TS;
+ feed->cb.ts = callback;
+ feed->demux = demux;
+ feed->pid = 0xffff;
+ feed->peslen = 0xfffa;
+ feed->buffer = NULL;
+
+ (*ts_feed) = &feed->feed.ts;
+ (*ts_feed)->parent = dmx;
+ (*ts_feed)->priv = NULL;
+ (*ts_feed)->is_filtering = 0;
+ (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
+ (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
+ (*ts_feed)->set = dmx_ts_feed_set;
+
+ if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
+ feed->state = DMX_STATE_FREE;
+ mutex_unlock(&demux->mutex);
+ return -EBUSY;
+ }
+
+ feed->filter->type = DMX_TYPE_TS;
+ feed->filter->feed = feed;
+ feed->filter->state = DMX_STATE_READY;
+
+ mutex_unlock(&demux->mutex);
+
+ return 0;
+}
+
+static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
+ struct dmx_ts_feed *ts_feed)
+{
+ struct dvb_demux *demux = (struct dvb_demux *)dmx;
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+ mutex_lock(&demux->mutex);
+
+ if (feed->state == DMX_STATE_FREE) {
+ mutex_unlock(&demux->mutex);
+ return -EINVAL;
+ }
+#ifndef NOBUFS
+ vfree(feed->buffer);
+ feed->buffer = NULL;
+#endif
+
+ feed->state = DMX_STATE_FREE;
+ feed->filter->state = DMX_STATE_FREE;
+
+ dvb_demux_feed_del(feed);
+
+ feed->pid = 0xffff;
+
+ if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
+ demux->pesfilter[feed->pes_type] = NULL;
+
+ mutex_unlock(&demux->mutex);
+ return 0;
+}
+
+/******************************************************************************
+ * dmx_section_feed API calls
+ ******************************************************************************/
+
+static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
+ struct dmx_section_filter **filter)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
+ struct dvb_demux_filter *dvbdmxfilter;
+
+ if (mutex_lock_interruptible(&dvbdemux->mutex))
+ return -ERESTARTSYS;
+
+ dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
+ if (!dvbdmxfilter) {
+ mutex_unlock(&dvbdemux->mutex);
+ return -EBUSY;
+ }
+
+ spin_lock_irq(&dvbdemux->lock);
+ *filter = &dvbdmxfilter->filter;
+ (*filter)->parent = feed;
+ (*filter)->priv = NULL;
+ dvbdmxfilter->feed = dvbdmxfeed;
+ dvbdmxfilter->type = DMX_TYPE_SEC;
+ dvbdmxfilter->state = DMX_STATE_READY;
+ dvbdmxfilter->next = dvbdmxfeed->filter;
+ dvbdmxfeed->filter = dvbdmxfilter;
+ spin_unlock_irq(&dvbdemux->lock);
+
+ mutex_unlock(&dvbdemux->mutex);
+ return 0;
+}
+
+static int dmx_section_feed_set(struct dmx_section_feed *feed,
+ u16 pid, size_t circular_buffer_size,
+ int check_crc)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ if (pid > 0x1fff)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
+
+ dvb_demux_feed_add(dvbdmxfeed);
+
+ dvbdmxfeed->pid = pid;
+ dvbdmxfeed->buffer_size = circular_buffer_size;
+ dvbdmxfeed->feed.sec.check_crc = check_crc;
+
+#ifdef NOBUFS
+ dvbdmxfeed->buffer = NULL;
+#else
+ dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
+ if (!dvbdmxfeed->buffer) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -ENOMEM;
+ }
+#endif
+
+ dvbdmxfeed->state = DMX_STATE_READY;
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
+{
+ int i;
+ struct dvb_demux_filter *f;
+ struct dmx_section_filter *sf;
+ u8 mask, mode, doneq;
+
+ if (!(f = dvbdmxfeed->filter))
+ return;
+ do {
+ sf = &f->filter;
+ doneq = 0;
+ for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+ mode = sf->filter_mode[i];
+ mask = sf->filter_mask[i];
+ f->maskandmode[i] = mask & mode;
+ doneq |= f->maskandnotmode[i] = mask & ~mode;
+ }
+ f->doneq = doneq ? 1 : 0;
+ } while ((f = f->next));
+}
+
+static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ int ret;
+
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
+
+ if (feed->is_filtering) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EBUSY;
+ }
+
+ if (!dvbdmxfeed->filter) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EINVAL;
+ }
+
+ dvbdmxfeed->feed.sec.tsfeedp = 0;
+ dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+ dvbdmxfeed->feed.sec.secbufp = 0;
+ dvbdmxfeed->feed.sec.seclen = 0;
+
+ if (!dvbdmx->start_feed) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -ENODEV;
+ }
+
+ prepare_secfilters(dvbdmxfeed);
+
+ if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
+ mutex_unlock(&dvbdmx->mutex);
+ return ret;
+ }
+
+ spin_lock_irq(&dvbdmx->lock);
+ feed->is_filtering = 1;
+ dvbdmxfeed->state = DMX_STATE_GO;
+ spin_unlock_irq(&dvbdmx->lock);
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ int ret;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ if (!dvbdmx->stop_feed) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -ENODEV;
+ }
+
+ ret = dvbdmx->stop_feed(dvbdmxfeed);
+
+ spin_lock_irq(&dvbdmx->lock);
+ dvbdmxfeed->state = DMX_STATE_READY;
+ feed->is_filtering = 0;
+ spin_unlock_irq(&dvbdmx->lock);
+
+ mutex_unlock(&dvbdmx->mutex);
+ return ret;
+}
+
+static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
+ struct dmx_section_filter *filter)
+{
+ struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ if (dvbdmxfilter->feed != dvbdmxfeed) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EINVAL;
+ }
+
+ if (feed->is_filtering)
+ feed->stop_filtering(feed);
+
+ spin_lock_irq(&dvbdmx->lock);
+ f = dvbdmxfeed->filter;
+
+ if (f == dvbdmxfilter) {
+ dvbdmxfeed->filter = dvbdmxfilter->next;
+ } else {
+ while (f->next != dvbdmxfilter)
+ f = f->next;
+ f->next = f->next->next;
+ }
+
+ dvbdmxfilter->state = DMX_STATE_FREE;
+ spin_unlock_irq(&dvbdmx->lock);
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
+ struct dmx_section_feed **feed,
+ dmx_section_cb callback)
+{
+ struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+ struct dvb_demux_feed *dvbdmxfeed;
+
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
+ return -ERESTARTSYS;
+
+ if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EBUSY;
+ }
+
+ dvbdmxfeed->type = DMX_TYPE_SEC;
+ dvbdmxfeed->cb.sec = callback;
+ dvbdmxfeed->demux = dvbdmx;
+ dvbdmxfeed->pid = 0xffff;
+ dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+ dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
+ dvbdmxfeed->feed.sec.tsfeedp = 0;
+ dvbdmxfeed->filter = NULL;
+ dvbdmxfeed->buffer = NULL;
+
+ (*feed) = &dvbdmxfeed->feed.sec;
+ (*feed)->is_filtering = 0;
+ (*feed)->parent = demux;
+ (*feed)->priv = NULL;
+
+ (*feed)->set = dmx_section_feed_set;
+ (*feed)->allocate_filter = dmx_section_feed_allocate_filter;
+ (*feed)->start_filtering = dmx_section_feed_start_filtering;
+ (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
+ (*feed)->release_filter = dmx_section_feed_release_filter;
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+static int dvbdmx_release_section_feed(struct dmx_demux *demux,
+ struct dmx_section_feed *feed)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ if (dvbdmxfeed->state == DMX_STATE_FREE) {
+ mutex_unlock(&dvbdmx->mutex);
+ return -EINVAL;
+ }
+#ifndef NOBUFS
+ vfree(dvbdmxfeed->buffer);
+ dvbdmxfeed->buffer = NULL;
+#endif
+ dvbdmxfeed->state = DMX_STATE_FREE;
+
+ dvb_demux_feed_del(dvbdmxfeed);
+
+ dvbdmxfeed->pid = 0xffff;
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
+/******************************************************************************
+ * dvb_demux kernel data API calls
+ ******************************************************************************/
+
+static int dvbdmx_open(struct dmx_demux *demux)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
+ return -EUSERS;
+
+ dvbdemux->users++;
+ return 0;
+}
+
+static int dvbdmx_close(struct dmx_demux *demux)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if (dvbdemux->users == 0)
+ return -ENODEV;
+
+ dvbdemux->users--;
+ //FIXME: release any unneeded resources if users==0
+ return 0;
+}
+
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+ void *p;
+
+ if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
+ return -EINVAL;
+
+ p = memdup_user(buf, count);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+ if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+ kfree(p);
+ return -ERESTARTSYS;
+ }
+ dvb_dmx_swfilter(dvbdemux, p, count);
+ kfree(p);
+ mutex_unlock(&dvbdemux->mutex);
+
+ if (signal_pending(current))
+ return -EINTR;
+ return count;
+}
+
+static int dvbdmx_add_frontend(struct dmx_demux *demux,
+ struct dmx_frontend *frontend)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+ struct list_head *head = &dvbdemux->frontend_list;
+
+ list_add(&(frontend->connectivity_list), head);
+
+ return 0;
+}
+
+static int dvbdmx_remove_frontend(struct dmx_demux *demux,
+ struct dmx_frontend *frontend)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+ struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
+
+ list_for_each_safe(pos, n, head) {
+ if (DMX_FE_ENTRY(pos) == frontend) {
+ list_del(pos);
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if (list_empty(&dvbdemux->frontend_list))
+ return NULL;
+
+ return &dvbdemux->frontend_list;
+}
+
+static int dvbdmx_connect_frontend(struct dmx_demux *demux,
+ struct dmx_frontend *frontend)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if (demux->frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvbdemux->mutex);
+
+ demux->frontend = frontend;
+ mutex_unlock(&dvbdemux->mutex);
+ return 0;
+}
+
+static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ mutex_lock(&dvbdemux->mutex);
+
+ demux->frontend = NULL;
+ mutex_unlock(&dvbdemux->mutex);
+ return 0;
+}
+
+static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
+ return 0;
+}
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux)
+{
+ int i;
+ struct dmx_demux *dmx = &dvbdemux->dmx;
+
+ dvbdemux->cnt_storage = NULL;
+ dvbdemux->users = 0;
+ dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
+
+ if (!dvbdemux->filter)
+ return -ENOMEM;
+
+ dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
+ if (!dvbdemux->feed) {
+ vfree(dvbdemux->filter);
+ dvbdemux->filter = NULL;
+ return -ENOMEM;
+ }
+ for (i = 0; i < dvbdemux->filternum; i++) {
+ dvbdemux->filter[i].state = DMX_STATE_FREE;
+ dvbdemux->filter[i].index = i;
+ }
+ for (i = 0; i < dvbdemux->feednum; i++) {
+ dvbdemux->feed[i].state = DMX_STATE_FREE;
+ dvbdemux->feed[i].index = i;
+ }
+
+ dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
+ if (!dvbdemux->cnt_storage)
+ printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+
+ INIT_LIST_HEAD(&dvbdemux->frontend_list);
+
+ for (i = 0; i < DMX_TS_PES_OTHER; i++) {
+ dvbdemux->pesfilter[i] = NULL;
+ dvbdemux->pids[i] = 0xffff;
+ }
+
+ INIT_LIST_HEAD(&dvbdemux->feed_list);
+
+ dvbdemux->playing = 0;
+ dvbdemux->recording = 0;
+ dvbdemux->tsbufp = 0;
+
+ if (!dvbdemux->check_crc32)
+ dvbdemux->check_crc32 = dvb_dmx_crc32;
+
+ if (!dvbdemux->memcopy)
+ dvbdemux->memcopy = dvb_dmx_memcopy;
+
+ dmx->frontend = NULL;
+ dmx->priv = dvbdemux;
+ dmx->open = dvbdmx_open;
+ dmx->close = dvbdmx_close;
+ dmx->write = dvbdmx_write;
+ dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
+ dmx->release_ts_feed = dvbdmx_release_ts_feed;
+ dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
+ dmx->release_section_feed = dvbdmx_release_section_feed;
+
+ dmx->add_frontend = dvbdmx_add_frontend;
+ dmx->remove_frontend = dvbdmx_remove_frontend;
+ dmx->get_frontends = dvbdmx_get_frontends;
+ dmx->connect_frontend = dvbdmx_connect_frontend;
+ dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
+ dmx->get_pes_pids = dvbdmx_get_pes_pids;
+
+ mutex_init(&dvbdemux->mutex);
+ spin_lock_init(&dvbdemux->lock);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmx_init);
+
+void dvb_dmx_release(struct dvb_demux *dvbdemux)
+{
+ vfree(dvbdemux->cnt_storage);
+ vfree(dvbdemux->filter);
+ vfree(dvbdemux->feed);
+}
+
+EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
index fa7188a253aa..fa7188a253aa 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb-core/dvb_demux.h
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb-core/dvb_filter.c
index 772003fb1821..772003fb1821 100644
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ b/drivers/media/dvb-core/dvb_filter.c
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.h b/drivers/media/dvb-core/dvb_filter.h
index 375e3be184b1..375e3be184b1 100644
--- a/drivers/media/dvb/dvb-core/dvb_filter.h
+++ b/drivers/media/dvb-core/dvb_filter.h
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
new file mode 100644
index 000000000000..aa4d4d85dc20
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -0,0 +1,2591 @@
+/*
+ * dvb_frontend.c: DVB frontend tuning interface/thread
+ *
+ *
+ * Copyright (C) 1999-2001 Ralph Metzler
+ * Marcus Metzler
+ * Holger Waechtler
+ * for convergence integrated media GmbH
+ *
+ * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
+ *
+ * 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.
+ * 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>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <asm/processor.h>
+
+#include "dvb_frontend.h"
+#include "dvbdev.h"
+#include <linux/dvb/version.h>
+
+static int dvb_frontend_debug;
+static int dvb_shutdown_timeout;
+static int dvb_force_auto_inversion;
+static int dvb_override_tune_delay;
+static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
+
+module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
+MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
+module_param(dvb_shutdown_timeout, int, 0644);
+MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+module_param(dvb_force_auto_inversion, int, 0644);
+MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
+module_param(dvb_override_tune_delay, int, 0644);
+MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+module_param(dvb_powerdown_on_sleep, int, 0644);
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
+
+#define dprintk if (dvb_frontend_debug) printk
+
+#define FESTATE_IDLE 1
+#define FESTATE_RETUNE 2
+#define FESTATE_TUNING_FAST 4
+#define FESTATE_TUNING_SLOW 8
+#define FESTATE_TUNED 16
+#define FESTATE_ZIGZAG_FAST 32
+#define FESTATE_ZIGZAG_SLOW 64
+#define FESTATE_DISEQC 128
+#define FESTATE_ERROR 256
+#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
+#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
+#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
+#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW 1
+/*
+ * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
+ * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
+ * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
+ * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
+ * FESTATE_TUNED. The frontend has successfully locked on.
+ * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
+ * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
+ * FESTATE_DISEQC. A DISEQC command has just been issued.
+ * FESTATE_WAITFORLOCK. When we're waiting for a lock.
+ * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
+ * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
+ * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
+ */
+
+#define DVB_FE_NO_EXIT 0
+#define DVB_FE_NORMAL_EXIT 1
+#define DVB_FE_DEVICE_REMOVED 2
+
+static DEFINE_MUTEX(frontend_mutex);
+
+struct dvb_frontend_private {
+
+ /* thread/frontend values */
+ struct dvb_device *dvbdev;
+ struct dvb_frontend_parameters parameters_out;
+ struct dvb_fe_events events;
+ struct semaphore sem;
+ struct list_head list_head;
+ wait_queue_head_t wait_queue;
+ struct task_struct *thread;
+ unsigned long release_jiffies;
+ unsigned int exit;
+ unsigned int wakeup;
+ fe_status_t status;
+ unsigned long tune_mode_flags;
+ unsigned int delay;
+ unsigned int reinitialise;
+ int tone;
+ int voltage;
+
+ /* swzigzag values */
+ unsigned int state;
+ unsigned int bending;
+ int lnb_drift;
+ unsigned int inversion;
+ unsigned int auto_step;
+ unsigned int auto_sub_step;
+ unsigned int started_auto_step;
+ unsigned int min_delay;
+ unsigned int max_drift;
+ unsigned int step_size;
+ int quality;
+ unsigned int check_wrapped;
+ enum dvbfe_search algo_status;
+};
+
+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_DTMB:
+ return DVBV3_OFDM;
+ case SYS_ATSC:
+ case SYS_ATSCMH:
+ case SYS_DVBC_ANNEX_B:
+ return DVBV3_ATSC;
+ case SYS_UNDEFINED:
+ case SYS_ISDBC:
+ case SYS_DVBH:
+ case SYS_DAB:
+ 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)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_fe_events *events = &fepriv->events;
+ struct dvb_frontend_event *e;
+ int wp;
+
+ dprintk ("%s\n", __func__);
+
+ if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
+ dtv_get_frontend(fe, &fepriv->parameters_out);
+
+ mutex_lock(&events->mtx);
+
+ wp = (events->eventw + 1) % MAX_EVENT;
+ if (wp == events->eventr) {
+ events->overflow = 1;
+ events->eventr = (events->eventr + 1) % MAX_EVENT;
+ }
+
+ e = &events->events[events->eventw];
+ e->status = status;
+ e->parameters = fepriv->parameters_out;
+
+ events->eventw = wp;
+
+ mutex_unlock(&events->mtx);
+
+ wake_up_interruptible (&events->wait_queue);
+}
+
+static int dvb_frontend_get_event(struct dvb_frontend *fe,
+ struct dvb_frontend_event *event, int flags)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_fe_events *events = &fepriv->events;
+
+ dprintk ("%s\n", __func__);
+
+ if (events->overflow) {
+ events->overflow = 0;
+ return -EOVERFLOW;
+ }
+
+ if (events->eventw == events->eventr) {
+ int ret;
+
+ if (flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ up(&fepriv->sem);
+
+ ret = wait_event_interruptible (events->wait_queue,
+ events->eventw != events->eventr);
+
+ if (down_interruptible (&fepriv->sem))
+ return -ERESTARTSYS;
+
+ if (ret < 0)
+ return ret;
+ }
+
+ mutex_lock(&events->mtx);
+ *event = events->events[events->eventr];
+ events->eventr = (events->eventr + 1) % MAX_EVENT;
+ mutex_unlock(&events->mtx);
+
+ return 0;
+}
+
+static void dvb_frontend_clear_events(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_fe_events *events = &fepriv->events;
+
+ mutex_lock(&events->mtx);
+ events->eventr = events->eventw;
+ mutex_unlock(&events->mtx);
+}
+
+static void dvb_frontend_init(struct dvb_frontend *fe)
+{
+ dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
+ fe->dvb->num,
+ fe->id,
+ fe->ops.info.name);
+
+ if (fe->ops.init)
+ fe->ops.init(fe);
+ if (fe->ops.tuner_ops.init) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.init(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+}
+
+void dvb_frontend_reinitialise(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ fepriv->reinitialise = 1;
+ dvb_frontend_wakeup(fe);
+}
+EXPORT_SYMBOL(dvb_frontend_reinitialise);
+
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
+{
+ int q2;
+
+ dprintk ("%s\n", __func__);
+
+ if (locked)
+ (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+ else
+ (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
+
+ q2 = fepriv->quality - 128;
+ q2 *= q2;
+
+ fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
+}
+
+/**
+ * Performs automatic twiddling of frontend parameters.
+ *
+ * @param fe The frontend concerned.
+ * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
+ * @returns Number of complete iterations that have been performed.
+ */
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
+{
+ int autoinversion;
+ int ready = 0;
+ int fe_set_err = 0;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ 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)) &&
+ (c->inversion == INVERSION_AUTO));
+
+ /* setup parameters correctly */
+ while(!ready) {
+ /* calculate the lnb_drift */
+ fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
+
+ /* wrap the auto_step if we've exceeded the maximum drift */
+ if (fepriv->lnb_drift > fepriv->max_drift) {
+ fepriv->auto_step = 0;
+ fepriv->auto_sub_step = 0;
+ fepriv->lnb_drift = 0;
+ }
+
+ /* perform inversion and +/- zigzag */
+ switch(fepriv->auto_sub_step) {
+ case 0:
+ /* try with the current inversion and current drift setting */
+ ready = 1;
+ break;
+
+ case 1:
+ if (!autoinversion) break;
+
+ fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+ ready = 1;
+ break;
+
+ case 2:
+ if (fepriv->lnb_drift == 0) break;
+
+ fepriv->lnb_drift = -fepriv->lnb_drift;
+ ready = 1;
+ break;
+
+ case 3:
+ if (fepriv->lnb_drift == 0) break;
+ if (!autoinversion) break;
+
+ fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+ fepriv->lnb_drift = -fepriv->lnb_drift;
+ ready = 1;
+ break;
+
+ default:
+ fepriv->auto_step++;
+ fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
+ break;
+ }
+
+ if (!ready) fepriv->auto_sub_step++;
+ }
+
+ /* if this attempt would hit where we started, indicate a complete
+ * iteration has occurred */
+ if ((fepriv->auto_step == fepriv->started_auto_step) &&
+ (fepriv->auto_sub_step == 0) && check_wrapped) {
+ return 1;
+ }
+
+ dprintk("%s: drift:%i inversion:%i auto_step:%i "
+ "auto_sub_step:%i started_auto_step:%i\n",
+ __func__, fepriv->lnb_drift, fepriv->inversion,
+ fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+
+ /* set the frontend itself */
+ c->frequency += fepriv->lnb_drift;
+ if (autoinversion)
+ c->inversion = fepriv->inversion;
+ tmp = *c;
+ if (fe->ops.set_frontend)
+ fe_set_err = fe->ops.set_frontend(fe);
+ *c = tmp;
+ if (fe_set_err < 0) {
+ fepriv->state = FESTATE_ERROR;
+ return fe_set_err;
+ }
+
+ c->frequency = original_frequency;
+ c->inversion = original_inversion;
+
+ fepriv->auto_sub_step++;
+ return 0;
+}
+
+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) {
+ fepriv->delay = 3*HZ;
+ fepriv->quality = 0;
+ return;
+ }
+
+ /* 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);
+ *c = tmp;
+ if (retval < 0)
+ fepriv->state = FESTATE_ERROR;
+ else
+ fepriv->state = FESTATE_TUNED;
+ }
+ fepriv->delay = 3*HZ;
+ fepriv->quality = 0;
+ return;
+ }
+
+ /* get the frontend status */
+ if (fepriv->state & FESTATE_RETUNE) {
+ s = 0;
+ } else {
+ if (fe->ops.read_status)
+ fe->ops.read_status(fe, &s);
+ if (s != fepriv->status) {
+ dvb_frontend_add_event(fe, s);
+ fepriv->status = s;
+ }
+ }
+
+ /* if we're not tuned, and we have a lock, move to the TUNED state */
+ if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ fepriv->state = FESTATE_TUNED;
+
+ /* if we're tuned, then we have determined the correct inversion */
+ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+ (c->inversion == INVERSION_AUTO)) {
+ c->inversion = fepriv->inversion;
+ }
+ return;
+ }
+
+ /* if we are tuned already, check we're still locked */
+ if (fepriv->state & FESTATE_TUNED) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+ /* we're tuned, and the lock is still good... */
+ if (s & FE_HAS_LOCK) {
+ return;
+ } else { /* if we _WERE_ tuned, but now don't have a lock */
+ fepriv->state = FESTATE_ZIGZAG_FAST;
+ fepriv->started_auto_step = fepriv->auto_step;
+ fepriv->check_wrapped = 0;
+ }
+ }
+
+ /* don't actually do anything if we're in the LOSTLOCK state,
+ * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+ if ((fepriv->state & FESTATE_LOSTLOCK) &&
+ (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ return;
+ }
+
+ /* don't do anything if we're in the DISEQC state, since this
+ * might be someone with a motorized dish controlled by DISEQC.
+ * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
+ if (fepriv->state & FESTATE_DISEQC) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+ return;
+ }
+
+ /* if we're in the RETUNE state, set everything up for a brand
+ * new scan, keeping the current inversion setting, as the next
+ * tune is _very_ likely to require the same */
+ if (fepriv->state & FESTATE_RETUNE) {
+ fepriv->lnb_drift = 0;
+ fepriv->auto_step = 0;
+ fepriv->auto_sub_step = 0;
+ fepriv->started_auto_step = 0;
+ fepriv->check_wrapped = 0;
+ }
+
+ /* fast zigzag. */
+ if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+ fepriv->delay = fepriv->min_delay;
+
+ /* perform a tune */
+ retval = dvb_frontend_swzigzag_autotune(fe,
+ fepriv->check_wrapped);
+ if (retval < 0) {
+ return;
+ } else if (retval) {
+ /* OK, if we've run out of trials at the fast speed.
+ * Drop back to slow for the _next_ attempt */
+ fepriv->state = FESTATE_SEARCHING_SLOW;
+ fepriv->started_auto_step = fepriv->auto_step;
+ return;
+ }
+ fepriv->check_wrapped = 1;
+
+ /* if we've just retuned, enter the ZIGZAG_FAST state.
+ * This ensures we cannot return from an
+ * FE_SET_FRONTEND ioctl before the first frontend tune
+ * occurs */
+ if (fepriv->state & FESTATE_RETUNE) {
+ fepriv->state = FESTATE_TUNING_FAST;
+ }
+ }
+
+ /* slow zigzag */
+ if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+ dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+ /* Note: don't bother checking for wrapping; we stay in this
+ * state until we get a lock */
+ dvb_frontend_swzigzag_autotune(fe, 0);
+ }
+}
+
+static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ if (fepriv->exit != DVB_FE_NO_EXIT)
+ return 1;
+
+ if (fepriv->dvbdev->writers == 1)
+ if (time_after_eq(jiffies, fepriv->release_jiffies +
+ dvb_shutdown_timeout * HZ))
+ return 1;
+
+ return 0;
+}
+
+static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ if (fepriv->wakeup) {
+ fepriv->wakeup = 0;
+ return 1;
+ }
+ return dvb_frontend_is_exiting(fe);
+}
+
+static void dvb_frontend_wakeup(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ fepriv->wakeup = 1;
+ wake_up_interruptible(&fepriv->wait_queue);
+}
+
+static int dvb_frontend_thread(void *data)
+{
+ struct dvb_frontend *fe = data;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ fe_status_t s;
+ enum dvbfe_algo algo;
+
+ bool re_tune = false;
+
+ dprintk("%s\n", __func__);
+
+ fepriv->check_wrapped = 0;
+ fepriv->quality = 0;
+ fepriv->delay = 3*HZ;
+ fepriv->status = 0;
+ fepriv->wakeup = 0;
+ fepriv->reinitialise = 0;
+
+ dvb_frontend_init(fe);
+
+ set_freezable();
+ while (1) {
+ up(&fepriv->sem); /* is locked when we enter the thread... */
+restart:
+ wait_event_interruptible_timeout(fepriv->wait_queue,
+ dvb_frontend_should_wakeup(fe) || kthread_should_stop()
+ || freezing(current),
+ fepriv->delay);
+
+ if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
+ /* got signal or quitting */
+ fepriv->exit = DVB_FE_NORMAL_EXIT;
+ break;
+ }
+
+ if (try_to_freeze())
+ goto restart;
+
+ if (down_interruptible(&fepriv->sem))
+ break;
+
+ if (fepriv->reinitialise) {
+ dvb_frontend_init(fe);
+ if (fe->ops.set_tone && fepriv->tone != -1)
+ fe->ops.set_tone(fe, fepriv->tone);
+ if (fe->ops.set_voltage && fepriv->voltage != -1)
+ fe->ops.set_voltage(fe, fepriv->voltage);
+ fepriv->reinitialise = 0;
+ }
+
+ /* do an iteration of the tuning loop */
+ if (fe->ops.get_frontend_algo) {
+ algo = fe->ops.get_frontend_algo(fe);
+ switch (algo) {
+ case DVBFE_ALGO_HW:
+ dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+
+ if (fepriv->state & FESTATE_RETUNE) {
+ dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+ re_tune = true;
+ fepriv->state = FESTATE_TUNED;
+ } else {
+ re_tune = false;
+ }
+
+ if (fe->ops.tune)
+ 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__);
+ dvb_frontend_add_event(fe, s);
+ fepriv->status = s;
+ }
+ break;
+ case DVBFE_ALGO_SW:
+ dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
+ dvb_frontend_swzigzag(fe);
+ break;
+ case DVBFE_ALGO_CUSTOM:
+ dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+ if (fepriv->state & FESTATE_RETUNE) {
+ dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+ fepriv->state = FESTATE_TUNED;
+ }
+ /* Case where we are going to search for a carrier
+ * User asked us to retune again for some reason, possibly
+ * requesting a search with a new set of parameters
+ */
+ if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+ if (fe->ops.search) {
+ 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.
+ */
+ } else {
+ fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+ }
+ }
+ /* Track the carrier if the search was successful */
+ if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
+ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+ fepriv->delay = HZ / 2;
+ }
+ 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 */
+ fepriv->status = s;
+ if (!(s & FE_HAS_LOCK)) {
+ fepriv->delay = HZ / 10;
+ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+ } else {
+ fepriv->delay = 60 * HZ;
+ }
+ }
+ break;
+ default:
+ dprintk("%s: UNDEFINED ALGO !\n", __func__);
+ break;
+ }
+ } else {
+ dvb_frontend_swzigzag(fe);
+ }
+ }
+
+ if (dvb_powerdown_on_sleep) {
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (fe->ops.tuner_ops.sleep) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.sleep(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.sleep)
+ fe->ops.sleep(fe);
+ }
+
+ fepriv->thread = NULL;
+ if (kthread_should_stop())
+ fepriv->exit = DVB_FE_DEVICE_REMOVED;
+ else
+ fepriv->exit = DVB_FE_NO_EXIT;
+ mb();
+
+ dvb_frontend_wakeup(fe);
+ return 0;
+}
+
+static void dvb_frontend_stop(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ dprintk ("%s\n", __func__);
+
+ fepriv->exit = DVB_FE_NORMAL_EXIT;
+ mb();
+
+ if (!fepriv->thread)
+ return;
+
+ kthread_stop(fepriv->thread);
+
+ sema_init(&fepriv->sem, 1);
+ fepriv->state = FESTATE_IDLE;
+
+ /* paranoia check in case a signal arrived */
+ if (fepriv->thread)
+ printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+ fepriv->thread);
+}
+
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+ return ((curtime.tv_usec < lasttime.tv_usec) ?
+ 1000000 - lasttime.tv_usec + curtime.tv_usec :
+ curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+ curtime->tv_usec += add_usec;
+ if (curtime->tv_usec >= 1000000) {
+ curtime->tv_usec -= 1000000;
+ curtime->tv_sec++;
+ }
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+ struct timeval lasttime;
+ s32 delta, newdelta;
+
+ timeval_usec_add(waketime, add_usec);
+
+ do_gettimeofday(&lasttime);
+ delta = timeval_usec_diff(lasttime, *waketime);
+ if (delta > 2500) {
+ msleep((delta - 1500) / 1000);
+ do_gettimeofday(&lasttime);
+ newdelta = timeval_usec_diff(lasttime, *waketime);
+ delta = (newdelta > delta) ? 0 : newdelta;
+ }
+ if (delta > 0)
+ udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
+static int dvb_frontend_start(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct task_struct *fe_thread;
+
+ dprintk ("%s\n", __func__);
+
+ if (fepriv->thread) {
+ if (fepriv->exit == DVB_FE_NO_EXIT)
+ return 0;
+ else
+ dvb_frontend_stop (fe);
+ }
+
+ if (signal_pending(current))
+ return -EINTR;
+ if (down_interruptible (&fepriv->sem))
+ return -EINTR;
+
+ fepriv->state = FESTATE_IDLE;
+ fepriv->exit = DVB_FE_NO_EXIT;
+ fepriv->thread = NULL;
+ mb();
+
+ fe_thread = kthread_run(dvb_frontend_thread, fe,
+ "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
+ if (IS_ERR(fe_thread)) {
+ ret = PTR_ERR(fe_thread);
+ printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
+ up(&fepriv->sem);
+ return ret;
+ }
+ fepriv->thread = fe_thread;
+ return 0;
+}
+
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
+ u32 *freq_min, u32 *freq_max)
+{
+ *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+ if (fe->ops.info.frequency_max == 0)
+ *freq_max = fe->ops.tuner_ops.info.frequency_max;
+ else if (fe->ops.tuner_ops.info.frequency_max == 0)
+ *freq_max = fe->ops.info.frequency_max;
+ else
+ *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+ if (*freq_min == 0 || *freq_max == 0)
+ printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+ fe->dvb->num,fe->id);
+}
+
+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 && 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, c->frequency, freq_min, freq_max);
+ return -EINVAL;
+ }
+
+ /* range check: symbol rate */
+ 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 &&
+ c->symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (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, c->symbol_rate,
+ fe->ops.info.symbol_rate_min,
+ fe->ops.info.symbol_rate_max);
+ return -EINVAL;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+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;
+
+ dprintk("%s() Clearing cache for delivery system %d\n", __func__,
+ c->delivery_system);
+
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->bandwidth_hz = 0; /* AUTO */
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+ c->hierarchy = HIERARCHY_AUTO;
+ c->symbol_rate = 0;
+ c->code_rate_HP = FEC_AUTO;
+ c->code_rate_LP = FEC_AUTO;
+ 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 = 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;
+}
+
+#define _DTV_CMD(n, s, b) \
+[n] = { \
+ .name = #n, \
+ .cmd = n, \
+ .set = s,\
+ .buffer = b \
+}
+
+static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+ _DTV_CMD(DTV_TUNE, 1, 0),
+ _DTV_CMD(DTV_CLEAR, 1, 0),
+
+ /* Set */
+ _DTV_CMD(DTV_FREQUENCY, 1, 0),
+ _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
+ _DTV_CMD(DTV_MODULATION, 1, 0),
+ _DTV_CMD(DTV_INVERSION, 1, 0),
+ _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
+ _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
+ _DTV_CMD(DTV_INNER_FEC, 1, 0),
+ _DTV_CMD(DTV_VOLTAGE, 1, 0),
+ _DTV_CMD(DTV_TONE, 1, 0),
+ _DTV_CMD(DTV_PILOT, 1, 0),
+ _DTV_CMD(DTV_ROLLOFF, 1, 0),
+ _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
+ _DTV_CMD(DTV_HIERARCHY, 1, 0),
+ _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
+ _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
+ _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
+ _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
+ _DTV_CMD(DTV_INTERLEAVING, 1, 0),
+
+ _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
+ _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
+ _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
+ _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
+
+ _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+ _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+
+ /* Get */
+ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+ _DTV_CMD(DTV_API_VERSION, 0, 0),
+ _DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
+ _DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
+ _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
+ _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
+ _DTV_CMD(DTV_HIERARCHY, 0, 0),
+ _DTV_CMD(DTV_INTERLEAVING, 0, 0),
+
+ _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
+
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
+
+ _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+};
+
+static void dtv_property_dump(struct dtv_property *tvp)
+{
+ int i;
+
+ if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+ printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
+ __func__, tvp->cmd);
+ return;
+ }
+
+ dprintk("%s() tvp.cmd = 0x%08x (%s)\n"
+ ,__func__
+ ,tvp->cmd
+ ,dtv_cmds[ tvp->cmd ].name);
+
+ if(dtv_cmds[ tvp->cmd ].buffer) {
+
+ dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+ ,__func__
+ ,tvp->u.buffer.len);
+
+ for(i = 0; i < tvp->u.buffer.len; i++)
+ dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+ ,__func__
+ ,i
+ ,tvp->u.buffer.data[i]);
+
+ } else
+ dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
+}
+
+/* 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 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 (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 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 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;
+ 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;
+ c->transmission_mode = p->u.ofdm.transmission_mode;
+ c->guard_interval = p->u.ofdm.guard_interval;
+ c->hierarchy = p->u.ofdm.hierarchy_information;
+ break;
+ case DVBV3_ATSC:
+ dprintk("%s() Preparing ATSC req\n", __func__);
+ c->modulation = p->u.vsb.modulation;
+ if (c->delivery_system == SYS_ATSCMH)
+ break;
+ 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 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;
+
+ p->frequency = c->frequency;
+ p->inversion = c->inversion;
+
+ 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 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 DVBV3_OFDM:
+ dprintk("%s() Preparing OFDM req\n", __func__);
+
+ switch (c->bandwidth_hz) {
+ case 10000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
+ break;
+ case 8000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ 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;
+ p->u.ofdm.transmission_mode = c->transmission_mode;
+ p->u.ofdm.guard_interval = c->guard_interval;
+ p->u.ofdm.hierarchy_information = c->hierarchy;
+ break;
+ case DVBV3_ATSC:
+ dprintk("%s() Preparing VSB req\n", __func__);
+ p->u.vsb.modulation = c->modulation;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * 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 int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p_out)
+{
+ int r;
+
+ 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;
+ }
+
+ /* As everything is in cache, get_frontend fops are always supported */
+ return 0;
+}
+
+static int dvb_frontend_ioctl_legacy(struct file *file,
+ unsigned int cmd, void *parg);
+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)
+{
+ 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;
+ case DTV_MODULATION:
+ tvp->u.data = c->modulation;
+ break;
+ case DTV_BANDWIDTH_HZ:
+ tvp->u.data = c->bandwidth_hz;
+ break;
+ case DTV_INVERSION:
+ tvp->u.data = c->inversion;
+ break;
+ case DTV_SYMBOL_RATE:
+ tvp->u.data = c->symbol_rate;
+ break;
+ case DTV_INNER_FEC:
+ tvp->u.data = c->fec_inner;
+ break;
+ case DTV_PILOT:
+ tvp->u.data = c->pilot;
+ break;
+ case DTV_ROLLOFF:
+ tvp->u.data = c->rolloff;
+ break;
+ case DTV_DELIVERY_SYSTEM:
+ tvp->u.data = c->delivery_system;
+ break;
+ case DTV_VOLTAGE:
+ tvp->u.data = c->voltage;
+ break;
+ case DTV_TONE:
+ tvp->u.data = c->sectone;
+ break;
+ case DTV_API_VERSION:
+ tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+ break;
+ case DTV_CODE_RATE_HP:
+ tvp->u.data = c->code_rate_HP;
+ break;
+ case DTV_CODE_RATE_LP:
+ tvp->u.data = c->code_rate_LP;
+ break;
+ case DTV_GUARD_INTERVAL:
+ tvp->u.data = c->guard_interval;
+ break;
+ case DTV_TRANSMISSION_MODE:
+ tvp->u.data = c->transmission_mode;
+ break;
+ case DTV_HIERARCHY:
+ tvp->u.data = c->hierarchy;
+ break;
+ case DTV_INTERLEAVING:
+ tvp->u.data = c->interleaving;
+ break;
+
+ /* ISDB-T Support here */
+ case DTV_ISDBT_PARTIAL_RECEPTION:
+ tvp->u.data = c->isdbt_partial_reception;
+ break;
+ case DTV_ISDBT_SOUND_BROADCASTING:
+ tvp->u.data = c->isdbt_sb_mode;
+ break;
+ case DTV_ISDBT_SB_SUBCHANNEL_ID:
+ tvp->u.data = c->isdbt_sb_subchannel;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_IDX:
+ tvp->u.data = c->isdbt_sb_segment_idx;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_COUNT:
+ tvp->u.data = c->isdbt_sb_segment_count;
+ break;
+ case DTV_ISDBT_LAYER_ENABLED:
+ tvp->u.data = c->isdbt_layer_enabled;
+ break;
+ case DTV_ISDBT_LAYERA_FEC:
+ tvp->u.data = c->layer[0].fec;
+ break;
+ case DTV_ISDBT_LAYERA_MODULATION:
+ tvp->u.data = c->layer[0].modulation;
+ break;
+ case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+ tvp->u.data = c->layer[0].segment_count;
+ break;
+ case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+ tvp->u.data = c->layer[0].interleaving;
+ break;
+ case DTV_ISDBT_LAYERB_FEC:
+ tvp->u.data = c->layer[1].fec;
+ break;
+ case DTV_ISDBT_LAYERB_MODULATION:
+ tvp->u.data = c->layer[1].modulation;
+ break;
+ case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+ tvp->u.data = c->layer[1].segment_count;
+ break;
+ case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+ tvp->u.data = c->layer[1].interleaving;
+ break;
+ case DTV_ISDBT_LAYERC_FEC:
+ tvp->u.data = c->layer[2].fec;
+ break;
+ case DTV_ISDBT_LAYERC_MODULATION:
+ tvp->u.data = c->layer[2].modulation;
+ break;
+ case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+ tvp->u.data = c->layer[2].segment_count;
+ break;
+ case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+ tvp->u.data = c->layer[2].interleaving;
+ break;
+ case DTV_ISDBS_TS_ID:
+ tvp->u.data = c->isdbs_ts_id;
+ break;
+ case DTV_DVBT2_PLP_ID:
+ tvp->u.data = c->dvbt2_plp_id;
+ break;
+
+ /* ATSC-MH */
+ case DTV_ATSCMH_FIC_VER:
+ tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
+ break;
+ case DTV_ATSCMH_PARADE_ID:
+ tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
+ break;
+ case DTV_ATSCMH_NOG:
+ tvp->u.data = fe->dtv_property_cache.atscmh_nog;
+ break;
+ case DTV_ATSCMH_TNOG:
+ tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
+ break;
+ case DTV_ATSCMH_SGN:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
+ break;
+ case DTV_ATSCMH_PRC:
+ tvp->u.data = fe->dtv_property_cache.atscmh_prc;
+ break;
+ case DTV_ATSCMH_RS_FRAME_MODE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
+ break;
+ case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
+ break;
+ case DTV_ATSCMH_RS_CODE_MODE_PRI:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
+ break;
+ case DTV_ATSCMH_RS_CODE_MODE_SEC:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
+ break;
+ case DTV_ATSCMH_SCCC_BLOCK_MODE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_A:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_B:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_C:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_D:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Allow the frontend to override outgoing properties */
+ if (fe->ops.get_property) {
+ r = fe->ops.get_property(fe, tvp);
+ if (r < 0)
+ return r;
+ }
+
+ dtv_property_dump(tvp);
+
+ 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;
+ }
+ /*
+ * Get a delivery system that is compatible with DVBv3
+ * NOTE: in order for this to work with softwares like Kaffeine that
+ * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
+ * DVB-S, drivers that support both should put the SYS_DVBS entry
+ * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
+ * The real fix is that userspace applications should not use DVBv3
+ * and not trust on calling FE_SET_FRONTEND to switch the delivery
+ * system.
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (fe->ops.delsys[ncaps] == desired_system) {
+ delsys = desired_system;
+ break;
+ }
+ ncaps++;
+ }
+ if (delsys == SYS_UNDEFINED) {
+ dprintk("%s() Couldn't find a delivery system that matches %d\n",
+ __func__, desired_system);
+ }
+ } 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 DTMB
+ * 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;
+
+ /* Allow the frontend to validate incoming properties */
+ if (fe->ops.set_property) {
+ r = fe->ops.set_property(fe, tvp);
+ if (r < 0)
+ return r;
+ }
+
+ switch(tvp->cmd) {
+ case DTV_CLEAR:
+ /*
+ * Reset a cache of data specific to the frontend here. This does
+ * not effect hardware.
+ */
+ dvb_frontend_clear_cache(fe);
+ break;
+ case DTV_TUNE:
+ /* interpret the cache of data, build either a traditional frontend
+ * tunerequest so we can pass validation in the FE_SET_FRONTEND
+ * ioctl.
+ */
+ c->state = tvp->cmd;
+ dprintk("%s() Finalised property cache\n", __func__);
+
+ r = dtv_set_frontend(fe);
+ break;
+ case DTV_FREQUENCY:
+ c->frequency = tvp->u.data;
+ break;
+ case DTV_MODULATION:
+ c->modulation = tvp->u.data;
+ break;
+ case DTV_BANDWIDTH_HZ:
+ c->bandwidth_hz = tvp->u.data;
+ break;
+ case DTV_INVERSION:
+ c->inversion = tvp->u.data;
+ break;
+ case DTV_SYMBOL_RATE:
+ c->symbol_rate = tvp->u.data;
+ break;
+ case DTV_INNER_FEC:
+ c->fec_inner = tvp->u.data;
+ break;
+ case DTV_PILOT:
+ c->pilot = tvp->u.data;
+ break;
+ case DTV_ROLLOFF:
+ c->rolloff = tvp->u.data;
+ break;
+ case DTV_DELIVERY_SYSTEM:
+ r = set_delivery_system(fe, tvp->u.data);
+ break;
+ case DTV_VOLTAGE:
+ c->voltage = tvp->u.data;
+ r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+ (void *)c->voltage);
+ break;
+ case DTV_TONE:
+ c->sectone = tvp->u.data;
+ r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+ (void *)c->sectone);
+ break;
+ case DTV_CODE_RATE_HP:
+ c->code_rate_HP = tvp->u.data;
+ break;
+ case DTV_CODE_RATE_LP:
+ c->code_rate_LP = tvp->u.data;
+ break;
+ case DTV_GUARD_INTERVAL:
+ c->guard_interval = tvp->u.data;
+ break;
+ case DTV_TRANSMISSION_MODE:
+ c->transmission_mode = tvp->u.data;
+ break;
+ case DTV_HIERARCHY:
+ c->hierarchy = tvp->u.data;
+ break;
+ case DTV_INTERLEAVING:
+ c->interleaving = tvp->u.data;
+ break;
+
+ /* ISDB-T Support here */
+ case DTV_ISDBT_PARTIAL_RECEPTION:
+ c->isdbt_partial_reception = tvp->u.data;
+ break;
+ case DTV_ISDBT_SOUND_BROADCASTING:
+ c->isdbt_sb_mode = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SUBCHANNEL_ID:
+ c->isdbt_sb_subchannel = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_IDX:
+ c->isdbt_sb_segment_idx = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_COUNT:
+ c->isdbt_sb_segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYER_ENABLED:
+ c->isdbt_layer_enabled = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_FEC:
+ c->layer[0].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_MODULATION:
+ c->layer[0].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+ c->layer[0].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+ c->layer[0].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_FEC:
+ c->layer[1].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_MODULATION:
+ c->layer[1].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+ c->layer[1].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+ c->layer[1].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_FEC:
+ c->layer[2].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_MODULATION:
+ c->layer[2].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+ c->layer[2].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+ c->layer[2].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBS_TS_ID:
+ c->isdbs_ts_id = tvp->u.data;
+ break;
+ case DTV_DVBT2_PLP_ID:
+ c->dvbt2_plp_id = tvp->u.data;
+ break;
+
+ /* ATSC-MH */
+ case DTV_ATSCMH_PARADE_ID:
+ fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
+ break;
+ case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+ fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+static int dvb_frontend_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_frontend *fe = dvbdev->priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int err = -EOPNOTSUPP;
+
+ dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
+
+ if (fepriv->exit != DVB_FE_NO_EXIT)
+ return -ENODEV;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
+ (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
+ cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+ return -EPERM;
+
+ if (down_interruptible (&fepriv->sem))
+ return -ERESTARTSYS;
+
+ if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+ err = dvb_frontend_ioctl_properties(file, cmd, parg);
+ else {
+ c->state = DTV_UNDEFINED;
+ err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+ }
+
+ up(&fepriv->sem);
+ return err;
+}
+
+static int dvb_frontend_ioctl_properties(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 err = 0;
+
+ struct dtv_properties *tvps = NULL;
+ struct dtv_property *tvp = NULL;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ if(cmd == FE_SET_PROPERTY) {
+ tvps = (struct dtv_properties __user *)parg;
+
+ dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+ dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+ /* Put an arbitrary limit on the number of messages that can
+ * be sent at once */
+ if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+ return -EINVAL;
+
+ tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+ if (!tvp) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ for (i = 0; i < tvps->num; i++) {
+ err = dtv_property_process_set(fe, tvp + i, file);
+ if (err < 0)
+ goto out;
+ (tvp + i)->result = err;
+ }
+
+ if (c->state == DTV_TUNE)
+ dprintk("%s() Property cache is full, tuning\n", __func__);
+
+ } else
+ if(cmd == FE_GET_PROPERTY) {
+ tvps = (struct dtv_properties __user *)parg;
+
+ dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+ dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+ /* Put an arbitrary limit on the number of messages that can
+ * be sent at once */
+ if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+ return -EINVAL;
+
+ tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+ if (!tvp) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+ err = -EFAULT;
+ 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, c, tvp + i, file);
+ if (err < 0)
+ goto out;
+ (tvp + i)->result = err;
+ }
+
+ if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ } else
+ err = -EOPNOTSUPP;
+
+out:
+ kfree(tvp);
+ 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_DVBS:
+ case SYS_DVBS2:
+ case SYS_ISDBS:
+ case SYS_TURBO:
+ 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_DTMB:
+ 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 err = -EOPNOTSUPP;
+
+ 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;
+ err = 0;
+ break;
+ }
+
+ case FE_READ_STATUS: {
+ fe_status_t* status = parg;
+
+ /* if retune was requested but hasn't occurred yet, prevent
+ * that user get signal state from previous tuning */
+ if (fepriv->state == FESTATE_RETUNE ||
+ fepriv->state == FESTATE_ERROR) {
+ err=0;
+ *status = 0;
+ break;
+ }
+
+ if (fe->ops.read_status)
+ err = fe->ops.read_status(fe, status);
+ break;
+ }
+ case FE_READ_BER:
+ if (fe->ops.read_ber)
+ err = fe->ops.read_ber(fe, (__u32*) parg);
+ break;
+
+ case FE_READ_SIGNAL_STRENGTH:
+ if (fe->ops.read_signal_strength)
+ err = fe->ops.read_signal_strength(fe, (__u16*) parg);
+ break;
+
+ case FE_READ_SNR:
+ if (fe->ops.read_snr)
+ err = fe->ops.read_snr(fe, (__u16*) parg);
+ break;
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ if (fe->ops.read_ucblocks)
+ err = fe->ops.read_ucblocks(fe, (__u32*) parg);
+ break;
+
+
+ case FE_DISEQC_RESET_OVERLOAD:
+ if (fe->ops.diseqc_reset_overload) {
+ err = fe->ops.diseqc_reset_overload(fe);
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_DISEQC_SEND_MASTER_CMD:
+ if (fe->ops.diseqc_send_master_cmd) {
+ err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_DISEQC_SEND_BURST:
+ if (fe->ops.diseqc_send_burst) {
+ err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_SET_TONE:
+ if (fe->ops.set_tone) {
+ err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
+ fepriv->tone = (fe_sec_tone_mode_t) parg;
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_SET_VOLTAGE:
+ if (fe->ops.set_voltage) {
+ err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
+ fepriv->voltage = (fe_sec_voltage_t) parg;
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_DISHNETWORK_SEND_LEGACY_CMD:
+ if (fe->ops.dishnetwork_send_legacy_command) {
+ err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ } else if (fe->ops.set_voltage) {
+ /*
+ * NOTE: This is a fallback condition. Some frontends
+ * (stv0299 for instance) take longer than 8msec to
+ * respond to a set_voltage command. Those switches
+ * need custom routines to switch properly. For all
+ * other frontends, the following should work ok.
+ * Dish network legacy switches (as used by Dish500)
+ * are controlled by sending 9-bit command words
+ * spaced 8msec apart.
+ * the actual command word is switch/port dependent
+ * so it is up to the userspace application to send
+ * the right command.
+ * The command must always start with a '0' after
+ * initialization, so parg is 8 bits and does not
+ * include the initialization or start bit
+ */
+ unsigned long swcmd = ((unsigned long) parg) << 1;
+ struct timeval nexttime;
+ struct timeval tv[10];
+ int i;
+ u8 last = 1;
+ if (dvb_frontend_debug)
+ printk("%s switch command: 0x%04lx\n", __func__, swcmd);
+ do_gettimeofday(&nexttime);
+ if (dvb_frontend_debug)
+ memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+ /* before sending a command, initialize by sending
+ * a 32ms 18V to the switch
+ */
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
+ dvb_frontend_sleep_until(&nexttime, 32000);
+
+ for (i = 0; i < 9; i++) {
+ if (dvb_frontend_debug)
+ do_gettimeofday(&tv[i + 1]);
+ if ((swcmd & 0x01) != last) {
+ /* set voltage to (last ? 13V : 18V) */
+ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+ last = (last) ? 0 : 1;
+ }
+ swcmd = swcmd >> 1;
+ if (i != 8)
+ dvb_frontend_sleep_until(&nexttime, 8000);
+ }
+ if (dvb_frontend_debug) {
+ printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+ __func__, fe->dvb->num);
+ for (i = 1; i < 10; i++)
+ printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+ }
+ err = 0;
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
+ }
+ break;
+
+ case FE_DISEQC_RECV_SLAVE_REPLY:
+ if (fe->ops.diseqc_recv_slave_reply)
+ err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+ break;
+
+ case FE_ENABLE_HIGH_LNB_VOLTAGE:
+ if (fe->ops.enable_high_lnb_voltage)
+ err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
+ break;
+
+ case FE_SET_FRONTEND:
+ err = set_delivery_system(fe, SYS_UNDEFINED);
+ if (err)
+ break;
+
+ 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:
+ err = dtv_get_frontend(fe, parg);
+ break;
+
+ case FE_SET_FRONTEND_TUNE_MODE:
+ fepriv->tune_mode_flags = (unsigned long) parg;
+ err = 0;
+ break;
+ };
+
+ return err;
+}
+
+
+static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_frontend *fe = dvbdev->priv;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+ dprintk ("%s\n", __func__);
+
+ poll_wait (file, &fepriv->events.wait_queue, wait);
+
+ if (fepriv->events.eventw != fepriv->events.eventr)
+ return (POLLIN | POLLRDNORM | POLLPRI);
+
+ return 0;
+}
+
+static int dvb_frontend_open(struct inode *inode, 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 dvb_adapter *adapter = fe->dvb;
+ int ret;
+
+ dprintk ("%s\n", __func__);
+ if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+ return -ENODEV;
+
+ if (adapter->mfe_shared) {
+ mutex_lock (&adapter->mfe_lock);
+
+ if (adapter->mfe_dvbdev == NULL)
+ adapter->mfe_dvbdev = dvbdev;
+
+ else if (adapter->mfe_dvbdev != dvbdev) {
+ struct dvb_device
+ *mfedev = adapter->mfe_dvbdev;
+ struct dvb_frontend
+ *mfe = mfedev->priv;
+ struct dvb_frontend_private
+ *mfepriv = mfe->frontend_priv;
+ int mferetry = (dvb_mfe_wait_time << 1);
+
+ mutex_unlock (&adapter->mfe_lock);
+ while (mferetry-- && (mfedev->users != -1 ||
+ mfepriv->thread != NULL)) {
+ if(msleep_interruptible(500)) {
+ if(signal_pending(current))
+ return -EINTR;
+ }
+ }
+
+ mutex_lock (&adapter->mfe_lock);
+ if(adapter->mfe_dvbdev != dvbdev) {
+ mfedev = adapter->mfe_dvbdev;
+ mfe = mfedev->priv;
+ mfepriv = mfe->frontend_priv;
+ if (mfedev->users != -1 ||
+ mfepriv->thread != NULL) {
+ mutex_unlock (&adapter->mfe_lock);
+ return -EBUSY;
+ }
+ adapter->mfe_dvbdev = dvbdev;
+ }
+ }
+ }
+
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+ if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+ goto err0;
+
+ /* If we took control of the bus, we need to force
+ reinitialization. This is because many ts_bus_ctrl()
+ functions strobe the RESET pin on the demod, and if the
+ frontend thread already exists then the dvb_init() routine
+ won't get called (which is what usually does initial
+ register configuration). */
+ fepriv->reinitialise = 1;
+ }
+
+ if ((ret = dvb_generic_open (inode, file)) < 0)
+ goto err1;
+
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ /* normal tune mode when opened R/W */
+ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+ fepriv->tone = -1;
+ fepriv->voltage = -1;
+
+ ret = dvb_frontend_start (fe);
+ if (ret)
+ goto err2;
+
+ /* empty event queue */
+ fepriv->events.eventr = fepriv->events.eventw = 0;
+ }
+
+ if (adapter->mfe_shared)
+ mutex_unlock (&adapter->mfe_lock);
+ return ret;
+
+err2:
+ dvb_generic_release(inode, file);
+err1:
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+ if (adapter->mfe_shared)
+ mutex_unlock (&adapter->mfe_lock);
+ return ret;
+}
+
+static int dvb_frontend_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_frontend *fe = dvbdev->priv;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int ret;
+
+ dprintk ("%s\n", __func__);
+
+ 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;
+ wake_up(&dvbdev->wait_queue);
+ }
+ if (fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
+ }
+
+ return ret;
+}
+
+static const struct file_operations dvb_frontend_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dvb_generic_ioctl,
+ .poll = dvb_frontend_poll,
+ .open = dvb_frontend_open,
+ .release = dvb_frontend_release,
+ .llseek = noop_llseek,
+};
+
+int dvb_frontend_suspend(struct dvb_frontend *fe)
+{
+ int ret = 0;
+
+ dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
+ fe->id);
+
+ if (fe->ops.tuner_ops.sleep)
+ ret = fe->ops.tuner_ops.sleep(fe);
+
+ if (fe->ops.sleep)
+ ret = fe->ops.sleep(fe);
+
+ return ret;
+}
+EXPORT_SYMBOL(dvb_frontend_suspend);
+
+int dvb_frontend_resume(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int ret = 0;
+
+ dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
+ fe->id);
+
+ if (fe->ops.init)
+ ret = fe->ops.init(fe);
+
+ if (fe->ops.tuner_ops.init)
+ ret = fe->ops.tuner_ops.init(fe);
+
+ fepriv->state = FESTATE_RETUNE;
+ dvb_frontend_wakeup(fe);
+
+ return ret;
+}
+EXPORT_SYMBOL(dvb_frontend_resume);
+
+int dvb_register_frontend(struct dvb_adapter* dvb,
+ struct dvb_frontend* fe)
+{
+ struct dvb_frontend_private *fepriv;
+ static const struct dvb_device dvbdev_template = {
+ .users = ~0,
+ .writers = 1,
+ .readers = (~0)-1,
+ .fops = &dvb_frontend_fops,
+ .kernel_ioctl = dvb_frontend_ioctl
+ };
+
+ dprintk ("%s\n", __func__);
+
+ if (mutex_lock_interruptible(&frontend_mutex))
+ return -ERESTARTSYS;
+
+ fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
+ if (fe->frontend_priv == NULL) {
+ mutex_unlock(&frontend_mutex);
+ return -ENOMEM;
+ }
+ fepriv = fe->frontend_priv;
+
+ sema_init(&fepriv->sem, 1);
+ init_waitqueue_head (&fepriv->wait_queue);
+ init_waitqueue_head (&fepriv->events.wait_queue);
+ mutex_init(&fepriv->events.mtx);
+ fe->dvb = dvb;
+ fepriv->inversion = INVERSION_OFF;
+
+ printk ("DVB: registering adapter %i frontend %i (%s)...\n",
+ fe->dvb->num,
+ fe->id,
+ fe->ops.info.name);
+
+ 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;
+}
+EXPORT_SYMBOL(dvb_register_frontend);
+
+int dvb_unregister_frontend(struct dvb_frontend* fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ dprintk ("%s\n", __func__);
+
+ mutex_lock(&frontend_mutex);
+ dvb_frontend_stop (fe);
+ mutex_unlock(&frontend_mutex);
+
+ if (fepriv->dvbdev->users < -1)
+ wait_event(fepriv->dvbdev->wait_queue,
+ fepriv->dvbdev->users==-1);
+
+ mutex_lock(&frontend_mutex);
+ dvb_unregister_device (fepriv->dvbdev);
+
+ /* fe is invalid now */
+ kfree(fepriv);
+ mutex_unlock(&frontend_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_frontend);
+
+#ifdef CONFIG_MEDIA_ATTACH
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+ void *ptr;
+
+ if (fe->ops.release_sec) {
+ fe->ops.release_sec(fe);
+ symbol_put_addr(fe->ops.release_sec);
+ }
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ symbol_put_addr(fe->ops.tuner_ops.release);
+ }
+ if (fe->ops.analog_ops.release) {
+ fe->ops.analog_ops.release(fe);
+ symbol_put_addr(fe->ops.analog_ops.release);
+ }
+ ptr = (void*)fe->ops.release;
+ if (ptr) {
+ fe->ops.release(fe);
+ symbol_put_addr(ptr);
+ }
+}
+#else
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+ if (fe->ops.release_sec)
+ fe->ops.release_sec(fe);
+ if (fe->ops.tuner_ops.release)
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.analog_ops.release)
+ fe->ops.analog_ops.release(fe);
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+#endif
+EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
new file mode 100644
index 000000000000..db309db79bd6
--- /dev/null
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -0,0 +1,427 @@
+/*
+ * dvb_frontend.h
+ *
+ * Copyright (C) 2001 convergence integrated media GmbH
+ * Copyright (C) 2004 convergence GmbH
+ *
+ * Written by Ralph Metzler
+ * Overhauled by Holger Waechtler
+ * Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _DVB_FRONTEND_H_
+#define _DVB_FRONTEND_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/dvb/frontend.h>
+
+#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;
+
+struct dvb_tuner_info {
+ char name[128];
+
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_step;
+
+ u32 bandwidth_min;
+ u32 bandwidth_max;
+ u32 bandwidth_step;
+};
+
+struct analog_parameters {
+ unsigned int frequency;
+ unsigned int mode;
+ unsigned int audmode;
+ u64 std;
+};
+
+enum dvbfe_modcod {
+ DVBFE_MODCOD_DUMMY_PLFRAME = 0,
+ DVBFE_MODCOD_QPSK_1_4,
+ DVBFE_MODCOD_QPSK_1_3,
+ DVBFE_MODCOD_QPSK_2_5,
+ DVBFE_MODCOD_QPSK_1_2,
+ DVBFE_MODCOD_QPSK_3_5,
+ DVBFE_MODCOD_QPSK_2_3,
+ DVBFE_MODCOD_QPSK_3_4,
+ DVBFE_MODCOD_QPSK_4_5,
+ DVBFE_MODCOD_QPSK_5_6,
+ DVBFE_MODCOD_QPSK_8_9,
+ DVBFE_MODCOD_QPSK_9_10,
+ DVBFE_MODCOD_8PSK_3_5,
+ DVBFE_MODCOD_8PSK_2_3,
+ DVBFE_MODCOD_8PSK_3_4,
+ DVBFE_MODCOD_8PSK_5_6,
+ DVBFE_MODCOD_8PSK_8_9,
+ DVBFE_MODCOD_8PSK_9_10,
+ DVBFE_MODCOD_16APSK_2_3,
+ DVBFE_MODCOD_16APSK_3_4,
+ DVBFE_MODCOD_16APSK_4_5,
+ DVBFE_MODCOD_16APSK_5_6,
+ DVBFE_MODCOD_16APSK_8_9,
+ DVBFE_MODCOD_16APSK_9_10,
+ DVBFE_MODCOD_32APSK_3_4,
+ DVBFE_MODCOD_32APSK_4_5,
+ DVBFE_MODCOD_32APSK_5_6,
+ DVBFE_MODCOD_32APSK_8_9,
+ DVBFE_MODCOD_32APSK_9_10,
+ DVBFE_MODCOD_RESERVED_1,
+ DVBFE_MODCOD_BPSK_1_3,
+ DVBFE_MODCOD_BPSK_1_4,
+ DVBFE_MODCOD_RESERVED_2
+};
+
+enum tuner_param {
+ DVBFE_TUNER_FREQUENCY = (1 << 0),
+ DVBFE_TUNER_TUNERSTEP = (1 << 1),
+ DVBFE_TUNER_IFFREQ = (1 << 2),
+ DVBFE_TUNER_BANDWIDTH = (1 << 3),
+ DVBFE_TUNER_REFCLOCK = (1 << 4),
+ DVBFE_TUNER_IQSENSE = (1 << 5),
+ DVBFE_TUNER_DUMMY = (1 << 31)
+};
+
+/*
+ * ALGO_HW: (Hardware Algorithm)
+ * ----------------------------------------------------------------
+ * Devices that support this algorithm do everything in hardware
+ * and no software support is needed to handle them.
+ * Requesting these devices to LOCK is the only thing required,
+ * device is supposed to do everything in the hardware.
+ *
+ * ALGO_SW: (Software Algorithm)
+ * ----------------------------------------------------------------
+ * These are dumb devices, that require software to do everything
+ *
+ * ALGO_CUSTOM: (Customizable Agorithm)
+ * ----------------------------------------------------------------
+ * Devices having this algorithm can be customized to have specific
+ * algorithms in the frontend driver, rather than simply doing a
+ * software zig-zag. In this case the zigzag maybe hardware assisted
+ * or it maybe completely done in hardware. In all cases, usage of
+ * this algorithm, in conjunction with the search and track
+ * callbacks, utilizes the driver specific algorithm.
+ *
+ * ALGO_RECOVERY: (Recovery Algorithm)
+ * ----------------------------------------------------------------
+ * These devices have AUTO recovery capabilities from LOCK failure
+ */
+enum dvbfe_algo {
+ DVBFE_ALGO_HW = (1 << 0),
+ DVBFE_ALGO_SW = (1 << 1),
+ DVBFE_ALGO_CUSTOM = (1 << 2),
+ DVBFE_ALGO_RECOVERY = (1 << 31)
+};
+
+struct tuner_state {
+ u32 frequency;
+ u32 tunerstep;
+ u32 ifreq;
+ u32 bandwidth;
+ u32 iqsense;
+ u32 refclock;
+};
+
+/*
+ * search callback possible return status
+ *
+ * DVBFE_ALGO_SEARCH_SUCCESS
+ * The frontend search algorithm completed and returned successfully
+ *
+ * DVBFE_ALGO_SEARCH_ASLEEP
+ * The frontend search algorithm is sleeping
+ *
+ * DVBFE_ALGO_SEARCH_FAILED
+ * The frontend search for a signal failed
+ *
+ * DVBFE_ALGO_SEARCH_INVALID
+ * The frontend search algorith was probably supplied with invalid
+ * parameters and the search is an invalid one
+ *
+ * DVBFE_ALGO_SEARCH_ERROR
+ * The frontend search algorithm failed due to some error
+ *
+ * DVBFE_ALGO_SEARCH_AGAIN
+ * The frontend search algorithm was requested to search again
+ */
+enum dvbfe_search {
+ DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
+ DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
+ DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
+ DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
+ DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
+ DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
+};
+
+
+struct dvb_tuner_ops {
+
+ struct dvb_tuner_info info;
+
+ int (*release)(struct dvb_frontend *fe);
+ int (*init)(struct dvb_frontend *fe);
+ int (*sleep)(struct dvb_frontend *fe);
+
+ /** This is for simple PLLs - set all parameters in one go. */
+ 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, u8 *buf, int buf_len);
+
+ /** This is to allow setting tuner-specific configs */
+ int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
+ int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+ int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
+
+#define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
+ int (*get_status)(struct dvb_frontend *fe, u32 *status);
+ int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
+ int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
+
+ /** These are provided separately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter separately. */
+ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+
+ /*
+ * These are provided separately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter separately.
+ */
+ int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+ int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+};
+
+struct analog_demod_info {
+ char *name;
+};
+
+struct analog_demod_ops {
+
+ struct analog_demod_info info;
+
+ void (*set_params)(struct dvb_frontend *fe,
+ struct analog_parameters *params);
+ int (*has_signal)(struct dvb_frontend *fe);
+ int (*get_afc)(struct dvb_frontend *fe);
+ void (*tuner_status)(struct dvb_frontend *fe);
+ void (*standby)(struct dvb_frontend *fe);
+ void (*release)(struct dvb_frontend *fe);
+ int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+ /** This is to allow setting tuner-specific configuration */
+ 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);
+
+ int (*init)(struct dvb_frontend* fe);
+ int (*sleep)(struct dvb_frontend* fe);
+
+ int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
+
+ /* if this is set, it overrides the default swzigzag */
+ int (*tune)(struct dvb_frontend* fe,
+ bool re_tune,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status);
+ /* get frontend tuning algorithm from the module */
+ 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);
+ int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
+
+ 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);
+ int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
+ int (*read_snr)(struct dvb_frontend* fe, u16* snr);
+ int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
+
+ int (*diseqc_reset_overload)(struct dvb_frontend* fe);
+ int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+ int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
+ int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+ int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+ int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+ int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+ int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+ int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+ int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
+
+ /* 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_tuner_ops tuner_ops;
+ struct analog_demod_ops analog_ops;
+
+ int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+ int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+};
+
+#ifdef __DVB_CORE__
+#define MAX_EVENT 8
+
+struct dvb_fe_events {
+ struct dvb_frontend_event events[MAX_EVENT];
+ int eventw;
+ int eventr;
+ int overflow;
+ wait_queue_head_t wait_queue;
+ struct mutex mtx;
+};
+#endif
+
+struct dtv_frontend_properties {
+
+ /* Cache State */
+ u32 state;
+
+ u32 frequency;
+ fe_modulation_t modulation;
+
+ fe_sec_voltage_t voltage;
+ fe_sec_tone_mode_t sectone;
+ fe_spectral_inversion_t inversion;
+ fe_code_rate_t fec_inner;
+ fe_transmit_mode_t transmission_mode;
+ u32 bandwidth_hz; /* 0 = AUTO */
+ fe_guard_interval_t guard_interval;
+ fe_hierarchy_t hierarchy;
+ u32 symbol_rate;
+ fe_code_rate_t code_rate_HP;
+ fe_code_rate_t code_rate_LP;
+
+ fe_pilot_t pilot;
+ fe_rolloff_t rolloff;
+
+ fe_delivery_system_t delivery_system;
+
+ enum fe_interleaving interleaving;
+
+ /* ISDB-T specifics */
+ u8 isdbt_partial_reception;
+ u8 isdbt_sb_mode;
+ u8 isdbt_sb_subchannel;
+ u32 isdbt_sb_segment_idx;
+ u32 isdbt_sb_segment_count;
+ u8 isdbt_layer_enabled;
+ struct {
+ u8 segment_count;
+ fe_code_rate_t fec;
+ fe_modulation_t modulation;
+ u8 interleaving;
+ } layer[3];
+
+ /* ISDB-T specifics */
+ u32 isdbs_ts_id;
+
+ /* DVB-T2 specifics */
+ u32 dvbt2_plp_id;
+
+ /* ATSC-MH specifics */
+ u8 atscmh_fic_ver;
+ u8 atscmh_parade_id;
+ u8 atscmh_nog;
+ u8 atscmh_tnog;
+ u8 atscmh_sgn;
+ u8 atscmh_prc;
+
+ u8 atscmh_rs_frame_mode;
+ u8 atscmh_rs_frame_ensemble;
+ u8 atscmh_rs_code_mode_pri;
+ u8 atscmh_rs_code_mode_sec;
+ u8 atscmh_sccc_block_mode;
+ u8 atscmh_sccc_code_mode_a;
+ u8 atscmh_sccc_code_mode_b;
+ u8 atscmh_sccc_code_mode_c;
+ u8 atscmh_sccc_code_mode_d;
+};
+
+struct dvb_frontend {
+ struct dvb_frontend_ops ops;
+ struct dvb_adapter *dvb;
+ void *demodulator_priv;
+ void *tuner_priv;
+ void *frontend_priv;
+ void *sec_priv;
+ 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;
+};
+
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+ struct dvb_frontend *fe);
+
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
+
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
+
+extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
+extern int dvb_frontend_suspend(struct dvb_frontend *fe);
+extern int dvb_frontend_resume(struct dvb_frontend *fe);
+
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
+#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb-core/dvb_math.c
index beb7c93aa6cb..beb7c93aa6cb 100644
--- a/drivers/media/dvb/dvb-core/dvb_math.c
+++ b/drivers/media/dvb-core/dvb_math.c
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb-core/dvb_math.h
index aecc867e9404..aecc867e9404 100644
--- a/drivers/media/dvb/dvb-core/dvb_math.h
+++ b/drivers/media/dvb-core/dvb_math.h
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 8766ce8c354d..8766ce8c354d 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h
index 1e53acd50cf4..1e53acd50cf4 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/drivers/media/dvb-core/dvb_net.h
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index a5712cd7c65f..a5712cd7c65f 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
index 41f04dae69b6..41f04dae69b6 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb-core/dvb_ringbuffer.h
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 39eab73b01ae..39eab73b01ae 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
new file mode 100644
index 000000000000..93a9470d3f0c
--- /dev/null
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -0,0 +1,146 @@
+/*
+ * dvbdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _DVBDEV_H_
+#define _DVBDEV_H_
+
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+
+#define DVB_MAJOR 212
+
+#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
+ #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
+#else
+ #define DVB_MAX_ADAPTERS 8
+#endif
+
+#define DVB_UNSET (-1)
+
+#define DVB_DEVICE_VIDEO 0
+#define DVB_DEVICE_AUDIO 1
+#define DVB_DEVICE_SEC 2
+#define DVB_DEVICE_FRONTEND 3
+#define DVB_DEVICE_DEMUX 4
+#define DVB_DEVICE_DVR 5
+#define DVB_DEVICE_CA 6
+#define DVB_DEVICE_NET 7
+#define DVB_DEVICE_OSD 8
+
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
+ static short adapter_nr[] = \
+ {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
+ module_param_array(adapter_nr, short, NULL, 0444); \
+ MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
+
+struct dvb_frontend;
+
+struct dvb_adapter {
+ int num;
+ struct list_head list_head;
+ struct list_head device_list;
+ const char *name;
+ u8 proposed_mac [6];
+ void* priv;
+
+ struct device *device;
+
+ struct module *module;
+
+ int mfe_shared; /* indicates mutually exclusive frontends */
+ struct dvb_device *mfe_dvbdev; /* frontend device in use */
+ struct mutex mfe_lock; /* access lock for thread creation */
+};
+
+
+struct dvb_device {
+ struct list_head list_head;
+ const struct file_operations *fops;
+ struct dvb_adapter *adapter;
+ int type;
+ int minor;
+ u32 id;
+
+ /* in theory, 'users' can vanish now,
+ but I don't want to change too much now... */
+ int readers;
+ int writers;
+ int users;
+
+ wait_queue_head_t wait_queue;
+ /* don't really need those !? -- FIXME: use video_usercopy */
+ int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
+
+ void *priv;
+};
+
+
+extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+ struct module *module, struct device *device,
+ short *adapter_nums);
+extern int dvb_unregister_adapter (struct dvb_adapter *adap);
+
+extern int dvb_register_device (struct dvb_adapter *adap,
+ struct dvb_device **pdvbdev,
+ const struct dvb_device *template,
+ void *priv,
+ int type);
+
+extern void dvb_unregister_device (struct dvb_device *dvbdev);
+
+extern int dvb_generic_open (struct inode *inode, struct file *file);
+extern int dvb_generic_release (struct inode *inode, struct file *file);
+extern long dvb_generic_ioctl (struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy() someday... */
+
+extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file, unsigned int cmd, void *arg));
+
+/** generic DVB attach function. */
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ void *__r = NULL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (void *) __a(ARGS); \
+ if (__r == NULL) \
+ symbol_put(FUNCTION); \
+ } else { \
+ printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+ } \
+ __r; \
+})
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+#endif
+
+#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
new file mode 100644
index 000000000000..5efec73a32d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -0,0 +1,741 @@
+menu "Customise DVB Frontends"
+ visible if !MEDIA_SUBDRV_AUTOSELECT
+
+comment "Multistandard (satellite) frontends"
+ depends on DVB_CORE
+
+config DVB_STB0899
+ tristate "STB0899 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
+ to support this demodulator based frontends
+
+config DVB_STB6100
+ tristate "STB6100 based tuners"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A Silicon tuner from ST used in conjunction with the STB0899
+ demodulator. Say Y when you want to support this tuner.
+
+config DVB_STV090x
+ tristate "STV0900/STV0903(A/B) based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
+ Say Y when you want to support these frontends.
+
+config DVB_STV6110x
+ tristate "STV6110/(A) based tuners"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A Silicon tuner that supports DVB-S and DVB-S2 modes
+
+comment "Multistandard (cable + terrestrial) frontends"
+ depends on DVB_CORE
+
+config DVB_DRXK
+ tristate "Micronas DRXK based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Micronas DRX-K DVB-C/T demodulator.
+
+ Say Y when you want to support this frontend.
+
+config DVB_TDA18271C2DD
+ tristate "NXP TDA18271C2 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ NXP TDA18271 silicon tuner.
+
+ Say Y when you want to support this tuner.
+
+comment "DVB-S (satellite) frontends"
+ depends on DVB_CORE
+
+config DVB_CX24110
+ tristate "Conexant CX24110 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_CX24123
+ tristate "Conexant CX24123 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_MT312
+ tristate "Zarlink VP310/MT312/ZL10313 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10036
+ tristate "Zarlink ZL10036 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10039
+ tristate "Zarlink ZL10039 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_S5H1420
+ tristate "Samsung S5H1420 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV0288
+ tristate "ST STV0288 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STB6000
+ tristate "ST STB6000 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_STV0299
+ tristate "ST STV0299 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV6110
+ tristate "ST STV6110 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_STV0900
+ tristate "ST STV0900 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
+
+config DVB_TDA8083
+ tristate "Philips TDA8083 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10086
+ tristate "Philips TDA10086 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA8261
+ tristate "Philips TDA8261 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_VES1X93
+ tristate "VLSI VES1893 or VES1993 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TUNER_ITD1000
+ tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TUNER_CX24113
+ tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
+config DVB_TDA826X
+ tristate "Philips TDA826X silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUA6100
+ tristate "Infineon TUA6100 PLL"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S PLL chip.
+
+config DVB_CX24116
+ tristate "Conexant CX24116 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_SI21XX
+ tristate "Silicon Labs SI21XX based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_DS3000
+ tristate "Montage Tehnology DS3000 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_MB86A16
+ tristate "Fujitsu MB86A16 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S/DSS Direct Conversion reveiver.
+ Say Y when you want to support this frontend.
+
+config DVB_TDA10071
+ tristate "NXP TDA10071"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+comment "DVB-T (terrestrial) frontends"
+ depends on DVB_CORE
+
+config DVB_SP8870
+ tristate "Spase sp8870 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_SP887X
+ tristate "Spase sp887x based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_CX22700
+ tristate "Conexant CX22700 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_CX22702
+ tristate "Conexant cx22702 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_S5H1432
+ tristate "Samsung s5h1432 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_DRXD
+ tristate "Micronas DRXD driver"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ Note: this driver was based on vendor driver reference code (released
+ under the GPL) as opposed to the existing drx397xd driver, which
+ was written via reverse engineering.
+
+config DVB_L64781
+ tristate "LSI L64781"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA1004X
+ tristate "Philips TDA10045H/TDA10046H based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ This driver needs external firmware. Please use the commands
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_NXT6000
+ tristate "NxtWave Communications NXT6000 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_MT352
+ tristate "Zarlink MT352 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10353
+ tristate "Zarlink ZL10353 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_DIB3000MB
+ tristate "DiBcom 3000M-B"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+
+config DVB_DIB3000MC
+ tristate "DiBcom 3000P/M-C"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+
+config DVB_DIB7000M
+ tristate "DiBcom 7000MA/MB/PA/PB/MC"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+
+config DVB_DIB7000P
+ tristate "DiBcom 7000PC"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+
+config DVB_DIB9000
+ tristate "DiBcom 9000"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+ to support this frontend.
+
+config DVB_TDA10048
+ tristate "Philips TDA10048HN based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+config DVB_AF9013
+ tristate "Afatech AF9013 demodulator"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+config DVB_EC100
+ tristate "E3C EC100"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+config DVB_HD29L2
+ tristate "HDIC HD29L2"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+config DVB_STV0367
+ tristate "ST STV0367 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T/C tuner module. Say Y when you want to support this frontend.
+
+config DVB_CXD2820R
+ tristate "Sony CXD2820R"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ 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 !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+config DVB_RTL2832
+ tristate "Realtek RTL2832 DVB-T"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
+comment "DVB-C (cable) frontends"
+ depends on DVB_CORE
+
+config DVB_VES1820
+ tristate "VLSI VES1820 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10021
+ tristate "Philips TDA10021 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10023
+ tristate "Philips TDA10023 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV0297
+ tristate "ST STV0297 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
+ depends on DVB_CORE
+
+config DVB_NXT200X
+ tristate "NxtWave Communications NXT2002/NXT2004 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+ This driver needs external firmware. Please use the commands
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_OR51211
+ tristate "Oren OR51211 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+ download it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+config DVB_OR51132
+ tristate "Oren OR51132 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+ This driver needs external firmware. Please use the commands
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
+ download firmwares for 8VSB and QAM64/256, respectively. Copy them to
+ /usr/lib/hotplug/firmware or /lib/firmware (depending on
+ configuration of firmware hotplug).
+
+config DVB_BCM3510
+ tristate "Broadcom BCM3510"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
+ support this frontend.
+
+config DVB_LGDT330X
+ tristate "LG Electronics LGDT3302/LGDT3303 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+config DVB_LGDT3305
+ tristate "LG Electronics LGDT3304 and LGDT3305 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+config DVB_LG2160
+ tristate "LG Electronics LG216x based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC/MH demodulator module. Say Y when you want
+ to support this frontend.
+
+config DVB_S5H1409
+ tristate "Samsung S5H1409 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+config DVB_AU8522
+ depends on I2C
+ tristate
+
+config DVB_AU8522_DTV
+ tristate "Auvitek AU8522 based DTV demod"
+ depends on DVB_CORE && I2C
+ select DVB_AU8522
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+ you want to enable DTV demodulation support for this frontend.
+
+config DVB_AU8522_V4L
+ tristate "Auvitek AU8522 based ATV demod"
+ depends on VIDEO_V4L2 && I2C
+ select DVB_AU8522
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+ you want to enable ATV demodulation support for this frontend.
+
+config DVB_S5H1411
+ tristate "Samsung S5H1411 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
+comment "ISDB-T (terrestrial) frontends"
+ depends on DVB_CORE
+
+config DVB_S921
+ tristate "Sharp S921 frontend"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
+ Say Y when you want to support this frontend.
+
+config DVB_DIB8000
+ tristate "DiBcom 8000MB/MC"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
+ Say Y when you want to support this frontend.
+
+config DVB_MB86A20S
+ tristate "Fujitsu mb86a20s"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
+ Say Y when you want to support this frontend.
+
+comment "Digital terrestrial only tuners/PLL"
+ depends on DVB_CORE
+
+config DVB_PLL
+ tristate "Generic I2C PLL based tuners"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ This module drives a number of tuners based on PLL chips with a
+ common I2C interface. Say Y when you want to support these tuners.
+
+config DVB_TUNER_DIB0070
+ tristate "DiBcom DiB0070 silicon base-band tuner"
+ depends on I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon baseband tuner DiB0070 from DiBcom.
+ This device is only used inside a SiP called together with a
+ demodulator for now.
+
+config DVB_TUNER_DIB0090
+ tristate "DiBcom DiB0090 silicon base-band tuner"
+ depends on I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon baseband tuner DiB0090 from DiBcom.
+ This device is only used inside a SiP called together with a
+ demodulator for now.
+
+comment "SEC control devices for DVB-S"
+ depends on DVB_CORE
+
+config DVB_LNBP21
+ tristate "LNBP21/LNBH24 SEC controllers"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An SEC control chips.
+
+config DVB_LNBP22
+ tristate "LNBP22 SEC controllers"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ LNB power supply and control voltage
+ regulator chip with step-up converter
+ and I2C interface.
+ Say Y when you want to support this chip.
+
+config DVB_ISL6405
+ tristate "ISL6405 SEC controller"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An SEC control chip.
+
+config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ An SEC control chip.
+
+config DVB_ISL6423
+ tristate "ISL6423 SEC controller"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A SEC controller chip from Intersil
+
+config DVB_A8293
+ tristate "Allegro A8293"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+
+config DVB_LGS8GL5
+ tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_LGS8GXX
+ tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
+ depends on DVB_CORE && I2C
+ select FW_LOADER
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_ATBM8830
+ tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA665x
+ tristate "TDA665x tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+ Say Y when you want to support this chip.
+
+ Currently supported tuners:
+ * Panasonic ENV57H12D5 (ET-50DT)
+
+config DVB_IX2505V
+ tristate "Sharp IX2505V silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_IT913X_FE
+ tristate "it913x frontend and it9137 tuner"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ 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 !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-S tuner module.
+ Say Y when you want to support this frontend.
+
+config DVB_AF9033
+ tristate "Afatech AF9033 DVB-T demodulator"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+
+comment "Tools to develop new frontends"
+
+config DVB_DUMMY_FE
+ tristate "Dummy frontend driver"
+ default n
+endmenu
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
new file mode 100644
index 000000000000..7eb73bbd2e26
--- /dev/null
+++ b/drivers/media/dvb-frontends/Makefile
@@ -0,0 +1,105 @@
+#
+# Makefile for the kernel DVB frontend device drivers.
+#
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/tuners/
+
+stb0899-objs := stb0899_drv.o stb0899_algo.o
+stv0900-objs := stv0900_core.o stv0900_sw.o
+drxd-objs := drxd_firm.o drxd_hard.o
+cxd2820r-objs := cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
+drxk-objs := drxk_hard.o
+
+obj-$(CONFIG_DVB_PLL) += dvb-pll.o
+obj-$(CONFIG_DVB_STV0299) += stv0299.o
+obj-$(CONFIG_DVB_STB0899) += stb0899.o
+obj-$(CONFIG_DVB_STB6100) += stb6100.o
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+obj-$(CONFIG_DVB_CX22700) += cx22700.o
+obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
+obj-$(CONFIG_DVB_CX24110) += cx24110.o
+obj-$(CONFIG_DVB_TDA8083) += tda8083.o
+obj-$(CONFIG_DVB_L64781) += l64781.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
+obj-$(CONFIG_DVB_MT312) += mt312.o
+obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
+obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
+obj-$(CONFIG_DVB_SP887X) += sp887x.o
+obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
+obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL10036) += zl10036.o
+obj-$(CONFIG_DVB_ZL10039) += zl10039.o
+obj-$(CONFIG_DVB_ZL10353) += zl10353.o
+obj-$(CONFIG_DVB_CX22702) += cx22702.o
+obj-$(CONFIG_DVB_DRXD) += drxd.o
+obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_TDA10023) += tda10023.o
+obj-$(CONFIG_DVB_STV0297) += stv0297.o
+obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
+obj-$(CONFIG_DVB_OR51211) += or51211.o
+obj-$(CONFIG_DVB_OR51132) += or51132.o
+obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+obj-$(CONFIG_DVB_LG2160) += lg2160.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
+obj-$(CONFIG_DVB_ISL6405) += isl6405.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
+obj-$(CONFIG_DVB_TDA10086) += tda10086.o
+obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TDA8261) += tda8261.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
+obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
+obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
+obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
+obj-$(CONFIG_DVB_AU8522) += au8522_common.o
+obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
+obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
+obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
+obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
+obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
+obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
+obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+obj-$(CONFIG_DVB_AF9013) += af9013.o
+obj-$(CONFIG_DVB_CX24116) += cx24116.o
+obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_STV0288) += stv0288.o
+obj-$(CONFIG_DVB_STB6000) += stb6000.o
+obj-$(CONFIG_DVB_S921) += s921.o
+obj-$(CONFIG_DVB_STV6110) += stv6110.o
+obj-$(CONFIG_DVB_STV0900) += stv0900.o
+obj-$(CONFIG_DVB_STV090x) += stv090x.o
+obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_ISL6423) += isl6423.o
+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
+obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
+obj-$(CONFIG_DVB_STV0367) += stv0367.o
+obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+obj-$(CONFIG_DVB_DRXK) += drxk.o
+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_RTL2832) += rtl2832.o
+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_AF9033) += af9033.o
+
diff --git a/drivers/media/dvb/frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c
index cff44a389b40..cff44a389b40 100644
--- a/drivers/media/dvb/frontends/a8293.c
+++ b/drivers/media/dvb-frontends/a8293.c
diff --git a/drivers/media/dvb/frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h
index ed29e5504f76..ed29e5504f76 100644
--- a/drivers/media/dvb/frontends/a8293.h
+++ b/drivers/media/dvb-frontends/a8293.h
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index 5bc570d77846..5bc570d77846 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h
index b973fc5a0384..b973fc5a0384 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb-frontends/af9013.h
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h
index fa848af6e9b4..fa848af6e9b4 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb-frontends/af9013_priv.h
diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index a38998286260..a38998286260 100644
--- a/drivers/media/dvb/frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index 9e302c3f0f7d..9e302c3f0f7d 100644
--- a/drivers/media/dvb/frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index 0b783b9ed75e..0b783b9ed75e 100644
--- a/drivers/media/dvb/frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c
new file mode 100644
index 000000000000..4e11dc4b1335
--- /dev/null
+++ b/drivers/media/dvb-frontends/atbm8830.c
@@ -0,0 +1,508 @@
+/*
+ * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ * ATBM8830, ATBM8831
+ *
+ * Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/div64.h>
+#include "dvb_frontend.h"
+
+#include "atbm8830.h"
+#include "atbm8830_priv.h"
+
+#define dprintk(args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "atbm8830: " args); \
+ } while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
+{
+ int ret = 0;
+ u8 dev_addr;
+ u8 buf1[] = { reg >> 8, reg & 0xFF };
+ u8 buf2[] = { data };
+ struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+ struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
+
+ dev_addr = priv->config->demod_address;
+ msg1.addr = dev_addr;
+ msg2.addr = dev_addr;
+
+ if (debug >= 2)
+ dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
+
+ ret = i2c_transfer(priv->i2c, &msg1, 1);
+ if (ret != 1)
+ return -EIO;
+
+ ret = i2c_transfer(priv->i2c, &msg2, 1);
+ return (ret != 1) ? -EIO : 0;
+}
+
+static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
+{
+ int ret;
+ u8 dev_addr;
+
+ u8 buf1[] = { reg >> 8, reg & 0xFF };
+ u8 buf2[] = { 0 };
+ struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+ struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
+
+ dev_addr = priv->config->demod_address;
+ msg1.addr = dev_addr;
+ msg2.addr = dev_addr;
+
+ ret = i2c_transfer(priv->i2c, &msg1, 1);
+ if (ret != 1) {
+ dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
+ return -EIO;
+ }
+
+ ret = i2c_transfer(priv->i2c, &msg2, 1);
+ if (ret != 1)
+ return -EIO;
+
+ *p_data = buf2[0];
+ if (debug >= 2)
+ dprintk("%s: reg=0x%04X, data=0x%02X\n",
+ __func__, reg, buf2[0]);
+
+ return 0;
+}
+
+/* Lock register latch so that multi-register read is atomic */
+static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
+{
+ return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
+}
+
+static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+ u32 val;
+ u64 t;
+
+ /* 0x100000 * freq / 30.4MHz */
+ t = (u64)0x100000 * freq;
+ do_div(t, 30400);
+ val = t;
+
+ atbm8830_write_reg(priv, REG_OSC_CLK, val);
+ atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
+ atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
+
+ return 0;
+}
+
+static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+
+ u32 fs = priv->config->osc_clk_freq;
+ u64 t;
+ u32 val;
+ u8 dat;
+
+ if (freq != 0) {
+ /* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
+ t = (u64) 2 * 31416 * (freq - fs);
+ t <<= 22;
+ do_div(t, fs);
+ do_div(t, 1000);
+ val = t;
+
+ atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
+ atbm8830_write_reg(priv, REG_IF_FREQ, val);
+ atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
+ atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
+
+ atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+ dat &= 0xFC;
+ atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+ } else {
+ /* Zero IF */
+ atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
+
+ atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+ dat &= 0xFC;
+ dat |= 0x02;
+ atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+
+ if (priv->config->zif_swap_iq)
+ atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
+ else
+ atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
+ }
+
+ return 0;
+}
+
+static int is_locked(struct atbm_state *priv, u8 *locked)
+{
+ u8 status;
+
+ atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
+
+ if (locked != NULL)
+ *locked = (status == 1);
+ return 0;
+}
+
+static int set_agc_config(struct atbm_state *priv,
+ u8 min, u8 max, u8 hold_loop)
+{
+ /* no effect if both min and max are zero */
+ if (!min && !max)
+ return 0;
+
+ atbm8830_write_reg(priv, REG_AGC_MIN, min);
+ atbm8830_write_reg(priv, REG_AGC_MAX, max);
+ atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
+
+ return 0;
+}
+
+static int set_static_channel_mode(struct atbm_state *priv)
+{
+ int i;
+
+ for (i = 0; i < 5; i++)
+ atbm8830_write_reg(priv, 0x099B + i, 0x08);
+
+ atbm8830_write_reg(priv, 0x095B, 0x7F);
+ atbm8830_write_reg(priv, 0x09CB, 0x01);
+ atbm8830_write_reg(priv, 0x09CC, 0x7F);
+ atbm8830_write_reg(priv, 0x09CD, 0x7F);
+ atbm8830_write_reg(priv, 0x0E01, 0x20);
+
+ /* For single carrier */
+ atbm8830_write_reg(priv, 0x0B03, 0x0A);
+ atbm8830_write_reg(priv, 0x0935, 0x10);
+ atbm8830_write_reg(priv, 0x0936, 0x08);
+ atbm8830_write_reg(priv, 0x093E, 0x08);
+ atbm8830_write_reg(priv, 0x096E, 0x06);
+
+ /* frame_count_max0 */
+ atbm8830_write_reg(priv, 0x0B09, 0x00);
+ /* frame_count_max1 */
+ atbm8830_write_reg(priv, 0x0B0A, 0x08);
+
+ return 0;
+}
+
+static int set_ts_config(struct atbm_state *priv)
+{
+ const struct atbm8830_config *cfg = priv->config;
+
+ /*Set parallel/serial ts mode*/
+ atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
+ atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
+ /*Set ts sampling edge*/
+ atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
+ cfg->ts_sampling_edge ? 1 : 0);
+ /*Set ts clock freerun*/
+ atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
+ cfg->ts_clk_gated ? 0 : 1);
+
+ return 0;
+}
+
+static int atbm8830_init(struct dvb_frontend *fe)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+ const struct atbm8830_config *cfg = priv->config;
+
+ /*Set oscillator frequency*/
+ set_osc_freq(priv, cfg->osc_clk_freq);
+
+ /*Set IF frequency*/
+ set_if_freq(priv, cfg->if_freq);
+
+ /*Set AGC Config*/
+ set_agc_config(priv, cfg->agc_min, cfg->agc_max,
+ cfg->agc_hold_loop);
+
+ /*Set static channel mode*/
+ set_static_channel_mode(priv);
+
+ set_ts_config(priv);
+ /*Turn off DSP reset*/
+ atbm8830_write_reg(priv, 0x000A, 0);
+
+ /*SW version test*/
+ atbm8830_write_reg(priv, 0x020C, 11);
+
+ /* Run */
+ atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
+
+ return 0;
+}
+
+
+static void atbm8830_release(struct dvb_frontend *fe)
+{
+ struct atbm_state *state = fe->demodulator_priv;
+ dprintk("%s\n", __func__);
+
+ kfree(state);
+}
+
+static int atbm8830_set_fe(struct dvb_frontend *fe)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+ int i;
+ u8 locked = 0;
+ dprintk("%s\n", __func__);
+
+ /* set frequency */
+ 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);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* start auto lock */
+ for (i = 0; i < 10; i++) {
+ mdelay(100);
+ dprintk("Try %d\n", i);
+ is_locked(priv, &locked);
+ if (locked != 0) {
+ dprintk("ATBM8830 locked!\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+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 */
+ c->inversion = INVERSION_OFF;
+
+ /* bandwidth */
+ c->bandwidth_hz = 8000000;
+
+ c->code_rate_HP = FEC_AUTO;
+ c->code_rate_LP = FEC_AUTO;
+
+ c->modulation = QAM_AUTO;
+
+ /* transmission mode */
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+
+ /* guard interval */
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+
+ /* hierarchy */
+ c->hierarchy = HIERARCHY_NONE;
+
+ return 0;
+}
+
+static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ fesettings->min_delay_ms = 0;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+ u8 locked = 0;
+ u8 agc_locked = 0;
+
+ dprintk("%s\n", __func__);
+ *fe_status = 0;
+
+ is_locked(priv, &locked);
+ if (locked) {
+ *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ }
+ dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+
+ atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
+ dprintk("AGC Lock: %d\n", agc_locked);
+
+ return 0;
+}
+
+static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+ u32 frame_err;
+ u8 t;
+
+ dprintk("%s\n", __func__);
+
+ atbm8830_reglatch_lock(priv, 1);
+
+ atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
+ frame_err = t & 0x7F;
+ frame_err <<= 8;
+ atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
+ frame_err |= t;
+
+ atbm8830_reglatch_lock(priv, 0);
+
+ *ber = frame_err * 100 / 32767;
+
+ dprintk("%s: ber=0x%x\n", __func__, *ber);
+ return 0;
+}
+
+static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+ u32 pwm;
+ u8 t;
+
+ dprintk("%s\n", __func__);
+ atbm8830_reglatch_lock(priv, 1);
+
+ atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
+ pwm = t & 0x03;
+ pwm <<= 8;
+ atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
+ pwm |= t;
+
+ atbm8830_reglatch_lock(priv, 0);
+
+ dprintk("AGC PWM = 0x%02X\n", pwm);
+ pwm = 0x400 - pwm;
+
+ *signal = pwm * 0x10000 / 0x400;
+
+ return 0;
+}
+
+static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ dprintk("%s\n", __func__);
+ *snr = 0;
+ return 0;
+}
+
+static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ dprintk("%s\n", __func__);
+ *ucblocks = 0;
+ return 0;
+}
+
+static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct atbm_state *priv = fe->demodulator_priv;
+
+ return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
+}
+
+static struct dvb_frontend_ops atbm8830_ops = {
+ .delsys = { SYS_DTMB },
+ .info = {
+ .name = "AltoBeam ATBM8830/8831 DMB-TH",
+ .frequency_min = 474000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 10000,
+ .caps =
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO
+ },
+
+ .release = atbm8830_release,
+
+ .init = atbm8830_init,
+ .sleep = NULL,
+ .write = NULL,
+ .i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
+
+ .set_frontend = atbm8830_set_fe,
+ .get_frontend = atbm8830_get_fe,
+ .get_tune_settings = atbm8830_get_tune_settings,
+
+ .read_status = atbm8830_read_status,
+ .read_ber = atbm8830_read_ber,
+ .read_signal_strength = atbm8830_read_signal_strength,
+ .read_snr = atbm8830_read_snr,
+ .read_ucblocks = atbm8830_read_ucblocks,
+};
+
+struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct atbm_state *priv = NULL;
+ u8 data = 0;
+
+ dprintk("%s()\n", __func__);
+
+ if (config == NULL || i2c == NULL)
+ return NULL;
+
+ priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
+ if (priv == NULL)
+ goto error_out;
+
+ priv->config = config;
+ priv->i2c = i2c;
+
+ /* check if the demod is there */
+ if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
+ dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
+ __func__, priv->config->demod_address);
+ goto error_out;
+ }
+ dprintk("atbm8830 chip id: 0x%02X\n", data);
+
+ memcpy(&priv->frontend.ops, &atbm8830_ops,
+ sizeof(struct dvb_frontend_ops));
+ priv->frontend.demodulator_priv = priv;
+
+ atbm8830_init(&priv->frontend);
+
+ atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
+
+ return &priv->frontend;
+
+error_out:
+ dprintk("%s() error_out\n", __func__);
+ kfree(priv);
+ return NULL;
+
+}
+EXPORT_SYMBOL(atbm8830_attach);
+
+MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h
index 024273374bd8..024273374bd8 100644
--- a/drivers/media/dvb/frontends/atbm8830.h
+++ b/drivers/media/dvb-frontends/atbm8830.h
diff --git a/drivers/media/dvb/frontends/atbm8830_priv.h b/drivers/media/dvb-frontends/atbm8830_priv.h
index d460058d497e..d460058d497e 100644
--- a/drivers/media/dvb/frontends/atbm8830_priv.h
+++ b/drivers/media/dvb-frontends/atbm8830_priv.h
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
index 565dcf31af57..565dcf31af57 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb-frontends/au8522.h
diff --git a/drivers/media/dvb-frontends/au8522_common.c b/drivers/media/dvb-frontends/au8522_common.c
new file mode 100644
index 000000000000..3559ff230045
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_common.c
@@ -0,0 +1,277 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+ Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+ Copyright (C) 2005-2008 Auvitek International, Ltd.
+ Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
+
+ 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/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522_priv.h"
+
+static int debug;
+
+#define dprintk(arg...)\
+ do { if (debug)\
+ printk(arg);\
+ } while (0)
+
+/* Despite the name "hybrid_tuner", the framework works just as well for
+ hybrid demodulators as well... */
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(au8522_list_mutex);
+
+/* 16 bit registers, 8 bit values */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
+
+ struct i2c_msg msg = { .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ "ret == %i)\n", __func__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+EXPORT_SYMBOL(au8522_writereg);
+
+u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+ int ret;
+ u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return b1[0];
+}
+EXPORT_SYMBOL(au8522_readreg);
+
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (state->operational_mode == AU8522_ANALOG_MODE) {
+ /* We're being asked to manage the gate even though we're
+ not in digital mode. This can occur if we get switched
+ over to analog mode before the dvb_frontend kernel thread
+ has completely shutdown */
+ return 0;
+ }
+
+ if (enable)
+ return au8522_writereg(state, 0x106, 1);
+ else
+ return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
+
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (enable)
+ return au8522_writereg(state, 0x106, 1);
+ else
+ return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+ u8 client_address)
+{
+ int ret;
+
+ mutex_lock(&au8522_list_mutex);
+ ret = hybrid_tuner_request_state(struct au8522_state, (*state),
+ hybrid_tuner_instance_list,
+ i2c, client_address, "au8522");
+ mutex_unlock(&au8522_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(au8522_get_state);
+
+void au8522_release_state(struct au8522_state *state)
+{
+ mutex_lock(&au8522_list_mutex);
+ if (state != NULL)
+ hybrid_tuner_release_state(state);
+ mutex_unlock(&au8522_list_mutex);
+}
+EXPORT_SYMBOL(au8522_release_state);
+
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+ struct au8522_led_config *led_config = state->config->led_cfg;
+ u8 val;
+
+ /* bail out if we can't control an LED */
+ if (!led_config || !led_config->gpio_output ||
+ !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+ return 0;
+
+ val = au8522_readreg(state, 0x4000 |
+ (led_config->gpio_output & ~0xc000));
+ if (onoff) {
+ /* enable GPIO output */
+ val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+ val |= (led_config->gpio_output_enable & 0xff);
+ } else {
+ /* disable GPIO output */
+ val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+ val |= (led_config->gpio_output_disable & 0xff);
+ }
+ return au8522_writereg(state, 0x8000 |
+ (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+ struct au8522_led_config *led_config = state->config->led_cfg;
+ int i, ret = 0;
+
+ /* bail out if we can't control an LED */
+ if (!led_config || !led_config->gpio_leds ||
+ !led_config->num_led_states || !led_config->led_states)
+ return 0;
+
+ if (led < 0) {
+ /* if LED is already lit, then leave it as-is */
+ if (state->led_state)
+ return 0;
+ else
+ led *= -1;
+ }
+
+ /* toggle LED if changing state */
+ if (state->led_state != led) {
+ u8 val;
+
+ dprintk("%s: %d\n", __func__, led);
+
+ au8522_led_gpio_enable(state, 1);
+
+ val = au8522_readreg(state, 0x4000 |
+ (led_config->gpio_leds & ~0xc000));
+
+ /* start with all leds off */
+ for (i = 0; i < led_config->num_led_states; i++)
+ val &= ~led_config->led_states[i];
+
+ /* set selected LED state */
+ if (led < led_config->num_led_states)
+ val |= led_config->led_states[led];
+ else if (led_config->num_led_states)
+ val |=
+ led_config->led_states[led_config->num_led_states - 1];
+
+ ret = au8522_writereg(state, 0x8000 |
+ (led_config->gpio_leds & ~0xc000), val);
+ if (ret < 0)
+ return ret;
+
+ state->led_state = led;
+
+ if (led == 0)
+ au8522_led_gpio_enable(state, 0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_led_ctrl);
+
+int au8522_init(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ state->operational_mode = AU8522_DIGITAL_MODE;
+
+ /* Clear out any state associated with the digital side of the
+ chip, so that when it gets powered back up it won't think
+ that it is already tuned */
+ state->current_frequency = 0;
+
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ au8522_i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_init);
+
+int au8522_sleep(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ /* Only power down if the digital side is currently using the chip */
+ if (state->operational_mode == AU8522_ANALOG_MODE) {
+ /* We're not in one of the expected power modes, which means
+ that the DVB thread is probably telling us to go to sleep
+ even though the analog frontend has already started using
+ the chip. So ignore the request */
+ return 0;
+ }
+
+ /* turn off led */
+ au8522_led_ctrl(state, 0);
+
+ /* Power down the chip */
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ state->current_frequency = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_sleep);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
new file mode 100644
index 000000000000..5243ba6295cc
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -0,0 +1,839 @@
+/*
+ * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * 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.
+ */
+
+/* Developer notes:
+ *
+ * VBI support is not yet working
+ * Enough is implemented here for CVBS and S-Video inputs, but the actual
+ * analog demodulator code isn't implemented (not needed for xc5000 since it
+ * has its own demodulator and outputs CVBS)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
+#include "au8522.h"
+#include "au8522_priv.h"
+
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+
+static int au8522_analog_debug;
+
+
+module_param_named(analog_debug, au8522_analog_debug, int, 0644);
+
+MODULE_PARM_DESC(analog_debug,
+ "Analog debugging messages [0=Off (default) 1=On]");
+
+struct au8522_register_config {
+ u16 reg_name;
+ u8 reg_val[8];
+};
+
+
+/* Video Decoder Filter Coefficients
+ The values are as follows from left to right
+ 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
+*/
+static const struct au8522_register_config filter_coef[] = {
+ {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
+ {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
+ {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
+ {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
+ {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
+ {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
+ {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
+ {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
+ {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
+ {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
+ {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
+ {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
+ {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
+ {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
+ {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
+ {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
+ {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
+ {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
+ {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
+ {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
+ {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
+ {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
+
+};
+#define NUM_FILTER_COEF (sizeof(filter_coef)\
+ / sizeof(struct au8522_register_config))
+
+
+/* Registers 0x060b through 0x0652 are the LP Filter coefficients
+ The values are as follows from left to right
+ 0="SIF" 1="ATVRF/ATVRF13"
+ Note: the "ATVRF/ATVRF13" mode has never been tested
+*/
+static const struct au8522_register_config lpfilter_coef[] = {
+ {0x060b, {0x21, 0x0b} },
+ {0x060c, {0xad, 0xad} },
+ {0x060d, {0x70, 0xf0} },
+ {0x060e, {0xea, 0xe9} },
+ {0x060f, {0xdd, 0xdd} },
+ {0x0610, {0x08, 0x64} },
+ {0x0611, {0x60, 0x60} },
+ {0x0612, {0xf8, 0xb2} },
+ {0x0613, {0x01, 0x02} },
+ {0x0614, {0xe4, 0xb4} },
+ {0x0615, {0x19, 0x02} },
+ {0x0616, {0xae, 0x2e} },
+ {0x0617, {0xee, 0xc5} },
+ {0x0618, {0x56, 0x56} },
+ {0x0619, {0x30, 0x58} },
+ {0x061a, {0xf9, 0xf8} },
+ {0x061b, {0x24, 0x64} },
+ {0x061c, {0x07, 0x07} },
+ {0x061d, {0x30, 0x30} },
+ {0x061e, {0xa9, 0xed} },
+ {0x061f, {0x09, 0x0b} },
+ {0x0620, {0x42, 0xc2} },
+ {0x0621, {0x1d, 0x2a} },
+ {0x0622, {0xd6, 0x56} },
+ {0x0623, {0x95, 0x8b} },
+ {0x0624, {0x2b, 0x2b} },
+ {0x0625, {0x30, 0x24} },
+ {0x0626, {0x3e, 0x3e} },
+ {0x0627, {0x62, 0xe2} },
+ {0x0628, {0xe9, 0xf5} },
+ {0x0629, {0x99, 0x19} },
+ {0x062a, {0xd4, 0x11} },
+ {0x062b, {0x03, 0x04} },
+ {0x062c, {0xb5, 0x85} },
+ {0x062d, {0x1e, 0x20} },
+ {0x062e, {0x2a, 0xea} },
+ {0x062f, {0xd7, 0xd2} },
+ {0x0630, {0x15, 0x15} },
+ {0x0631, {0xa3, 0xa9} },
+ {0x0632, {0x1f, 0x1f} },
+ {0x0633, {0xf9, 0xd1} },
+ {0x0634, {0xc0, 0xc3} },
+ {0x0635, {0x4d, 0x8d} },
+ {0x0636, {0x21, 0x31} },
+ {0x0637, {0x83, 0x83} },
+ {0x0638, {0x08, 0x8c} },
+ {0x0639, {0x19, 0x19} },
+ {0x063a, {0x45, 0xa5} },
+ {0x063b, {0xef, 0xec} },
+ {0x063c, {0x8a, 0x8a} },
+ {0x063d, {0xf4, 0xf6} },
+ {0x063e, {0x8f, 0x8f} },
+ {0x063f, {0x44, 0x0c} },
+ {0x0640, {0xef, 0xf0} },
+ {0x0641, {0x66, 0x66} },
+ {0x0642, {0xcc, 0xd2} },
+ {0x0643, {0x41, 0x41} },
+ {0x0644, {0x63, 0x93} },
+ {0x0645, {0x8e, 0x8e} },
+ {0x0646, {0xa2, 0x42} },
+ {0x0647, {0x7b, 0x7b} },
+ {0x0648, {0x04, 0x04} },
+ {0x0649, {0x00, 0x00} },
+ {0x064a, {0x40, 0x40} },
+ {0x064b, {0x8c, 0x98} },
+ {0x064c, {0x00, 0x00} },
+ {0x064d, {0x63, 0xc3} },
+ {0x064e, {0x04, 0x04} },
+ {0x064f, {0x20, 0x20} },
+ {0x0650, {0x00, 0x00} },
+ {0x0651, {0x40, 0x40} },
+ {0x0652, {0x01, 0x01} },
+};
+#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
+ / sizeof(struct au8522_register_config))
+
+static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct au8522_state, sd);
+}
+
+static void setup_vbi(struct au8522_state *state, int aud_input)
+{
+ int i;
+
+ /* These are set to zero regardless of what mode we're in */
+ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
+ 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
+ 0x00);
+ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
+ 0x00);
+
+ /* Setup the VBI registers */
+ for (i = 0x30; i < 0x60; i++)
+ au8522_writereg(state, i, 0x40);
+
+ /* For some reason, every register is 0x40 except register 0x44
+ (confirmed via the HVR-950q USB capture) */
+ au8522_writereg(state, 0x44, 0x60);
+
+ /* Enable VBI (we always do this regardless of whether the user is
+ viewing closed caption info) */
+ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
+ AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
+
+}
+
+static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
+{
+ int i;
+ int filter_coef_type;
+
+ /* Provide reasonable defaults for picture tuning values */
+ au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
+ au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
+ state->brightness = 0xed - 128;
+ au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
+ state->contrast = 0x79;
+ au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
+ au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
+ state->saturation = 0x80;
+ au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
+ au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
+ state->hue = 0x00;
+
+ /* Other decoder registers */
+ au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
+
+ if (input_mode == 0x23) {
+ /* S-Video input mapping */
+ au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
+ } else {
+ /* All other modes (CVBS/ATVRF etc.) */
+ au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
+ }
+
+ au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
+ AU8522_TVDEC_PGA_REG012H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
+ AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
+ au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
+ AU8522_TVDED_DBG_MODE_REG060H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+ AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+ au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
+ AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
+ AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
+ AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
+ AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
+ AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
+ AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
+ AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
+ AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
+ AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
+ if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+ input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
+ } else {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+ }
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
+ AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
+ AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
+ AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
+ au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
+ au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
+ AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
+ au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
+ au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
+ AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
+ AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
+ AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
+ AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
+ AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
+ AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
+ au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
+ AU8522_TOREGAAGC_REG0E5H_CVBS);
+ au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
+
+ setup_vbi(state, 0);
+
+ if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+ input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ /* Despite what the table says, for the HVR-950q we still need
+ to be in CVBS mode for the S-Video input (reason unknown). */
+ /* filter_coef_type = 3; */
+ filter_coef_type = 5;
+ } else {
+ filter_coef_type = 5;
+ }
+
+ /* Load the Video Decoder Filter Coefficients */
+ for (i = 0; i < NUM_FILTER_COEF; i++) {
+ au8522_writereg(state, filter_coef[i].reg_name,
+ filter_coef[i].reg_val[filter_coef_type]);
+ }
+
+ /* It's not clear what these registers are for, but they are always
+ set to the same value regardless of what mode we're in */
+ au8522_writereg(state, AU8522_REG42EH, 0x87);
+ au8522_writereg(state, AU8522_REG42FH, 0xa2);
+ au8522_writereg(state, AU8522_REG430H, 0xbf);
+ au8522_writereg(state, AU8522_REG431H, 0xcb);
+ au8522_writereg(state, AU8522_REG432H, 0xa1);
+ au8522_writereg(state, AU8522_REG433H, 0x41);
+ au8522_writereg(state, AU8522_REG434H, 0x88);
+ au8522_writereg(state, AU8522_REG435H, 0xc2);
+ au8522_writereg(state, AU8522_REG436H, 0x3c);
+}
+
+static void au8522_setup_cvbs_mode(struct au8522_state *state)
+{
+ /* here we're going to try the pre-programmed route */
+ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+ /* PGA in automatic mode */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+ /* Enable clamping control */
+ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
+
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+ AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+ setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
+{
+ /* here we're going to try the pre-programmed route */
+ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+
+ /* It's not clear why we have to have the PGA in automatic mode while
+ enabling clamp control, but it's what Windows does */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+ /* Enable clamping control */
+ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
+
+ /* Disable automatic PGA (since the CVBS is coming from the tuner) */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+ /* Set input mode to CVBS on channel 4 with SIF audio input enabled */
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+ AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+ setup_decoder_defaults(state,
+ AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+static void au8522_setup_svideo_mode(struct au8522_state *state)
+{
+ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
+ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
+
+ /* Set input to Y on Channe1, C on Channel 3 */
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
+ AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+ /* PGA in automatic mode */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+ /* Enable clamping control */
+ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
+
+ setup_decoder_defaults(state,
+ AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void disable_audio_input(struct au8522_state *state)
+{
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
+ au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
+
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
+}
+
+/* 0=disable, 1=SIF */
+static void set_audio_input(struct au8522_state *state, int aud_input)
+{
+ int i;
+
+ /* Note that this function needs to be used in conjunction with setting
+ the input routing via register 0x81 */
+
+ if (aud_input == AU8522_AUDIO_NONE) {
+ disable_audio_input(state);
+ return;
+ }
+
+ if (aud_input != AU8522_AUDIO_SIF) {
+ /* The caller asked for a mode we don't currently support */
+ printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
+ aud_input);
+ return;
+ }
+
+ /* Load the Audio Decoder Filter Coefficients */
+ for (i = 0; i < NUM_LPFILTER_COEF; i++) {
+ au8522_writereg(state, lpfilter_coef[i].reg_name,
+ lpfilter_coef[i].reg_val[0]);
+ }
+
+ /* Setup audio */
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
+ au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
+ au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
+ msleep(150);
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
+ msleep(1);
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
+ msleep(50);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
+ msleep(80);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
+ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
+ au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
+ au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
+ msleep(70);
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
+ au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
+ au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct au8522_state *state = to_state(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ state->brightness = ctrl->value;
+ au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
+ ctrl->value - 128);
+ break;
+ case V4L2_CID_CONTRAST:
+ state->contrast = ctrl->value;
+ au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
+ ctrl->value);
+ break;
+ case V4L2_CID_SATURATION:
+ state->saturation = ctrl->value;
+ au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
+ ctrl->value);
+ au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
+ ctrl->value);
+ break;
+ case V4L2_CID_HUE:
+ state->hue = ctrl->value;
+ au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
+ ctrl->value >> 8);
+ au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
+ ctrl->value & 0xFF);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ /* Not yet implemented */
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct au8522_state *state = to_state(sd);
+
+ /* Note that we are using values cached in the state structure instead
+ of reading the registers due to issues with i2c reads not working
+ properly/consistently yet on the HVR-950q */
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ /* Not yet supported */
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int au8522_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct au8522_state *state = to_state(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = au8522_readreg(state, reg->reg & 0xffff);
+ return 0;
+}
+
+static int au8522_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct au8522_state *state = to_state(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ au8522_writereg(state, reg->reg, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct au8522_state *state = to_state(sd);
+
+ if (enable) {
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ 0x01);
+ msleep(1);
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+ } else {
+ /* This does not completely power down the device
+ (it only reduces it from around 140ma to 80ma) */
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ 1 << 5);
+ }
+ return 0;
+}
+
+static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1,
+ AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
+ default:
+ break;
+ }
+
+ qc->type = 0;
+ return -EINVAL;
+}
+
+static int au8522_reset(struct v4l2_subdev *sd, u32 val)
+{
+ struct au8522_state *state = to_state(sd);
+
+ state->operational_mode = AU8522_ANALOG_MODE;
+
+ /* Clear out any state associated with the digital side of the
+ chip, so that when it gets powered back up it won't think
+ that it is already tuned */
+ state->current_frequency = 0;
+
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ return 0;
+}
+
+static int au8522_s_video_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ struct au8522_state *state = to_state(sd);
+
+ au8522_reset(sd, 0);
+
+ if (input == AU8522_COMPOSITE_CH1) {
+ au8522_setup_cvbs_mode(state);
+ } else if (input == AU8522_SVIDEO_CH13) {
+ au8522_setup_svideo_mode(state);
+ } else if (input == AU8522_COMPOSITE_CH4_SIF) {
+ au8522_setup_cvbs_tuner_mode(state);
+ } else {
+ printk(KERN_ERR "au8522 mode not currently supported\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int au8522_s_audio_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ struct au8522_state *state = to_state(sd);
+ set_audio_input(state, input);
+ return 0;
+}
+
+static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ int val = 0;
+ struct au8522_state *state = to_state(sd);
+ u8 lock_status;
+
+ /* Interrogate the decoder to see if we are getting a real signal */
+ lock_status = au8522_readreg(state, 0x00);
+ if (lock_status == 0xa2)
+ vt->signal = 0xffff;
+ else
+ vt->signal = 0x00;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ val = V4L2_TUNER_SUB_MONO;
+ vt->rxsubchans = val;
+ vt->audmode = V4L2_TUNER_MODE_STEREO;
+ return 0;
+}
+
+static int au8522_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct au8522_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
+
+static int au8522_log_status(struct v4l2_subdev *sd)
+{
+ /* FIXME: Add some status info here */
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops au8522_core_ops = {
+ .log_status = au8522_log_status,
+ .g_chip_ident = au8522_g_chip_ident,
+ .g_ctrl = au8522_g_ctrl,
+ .s_ctrl = au8522_s_ctrl,
+ .queryctrl = au8522_queryctrl,
+ .reset = au8522_reset,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = au8522_g_register,
+ .s_register = au8522_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
+ .g_tuner = au8522_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
+ .s_routing = au8522_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops au8522_video_ops = {
+ .s_routing = au8522_s_video_routing,
+ .s_stream = au8522_s_stream,
+};
+
+static const struct v4l2_subdev_ops au8522_ops = {
+ .core = &au8522_core_ops,
+ .tuner = &au8522_tuner_ops,
+ .audio = &au8522_audio_ops,
+ .video = &au8522_video_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int au8522_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct au8522_state *state;
+ struct v4l2_subdev *sd;
+ int instance;
+ struct au8522_config *demod_config;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ return -EIO;
+ }
+
+ /* allocate memory for the internal state */
+ instance = au8522_get_state(&state, client->adapter, client->addr);
+ switch (instance) {
+ case 0:
+ printk(KERN_ERR "au8522_decoder allocation failed\n");
+ return -EIO;
+ case 1:
+ /* new demod instance */
+ printk(KERN_INFO "au8522_decoder creating new instance...\n");
+ break;
+ default:
+ /* existing demod instance */
+ printk(KERN_INFO "au8522_decoder attach existing instance.\n");
+ break;
+ }
+
+ demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
+ if (demod_config == NULL) {
+ if (instance == 1)
+ kfree(state);
+ return -ENOMEM;
+ }
+ demod_config->demod_address = 0x8e >> 1;
+
+ state->config = demod_config;
+ state->i2c = client->adapter;
+
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &au8522_ops);
+
+ state->c = client;
+ state->vid_input = AU8522_COMPOSITE_CH1;
+ state->aud_input = AU8522_AUDIO_NONE;
+ state->id = 8522;
+ state->rev = 0;
+
+ /* Jam open the i2c gate to the tuner */
+ au8522_writereg(state, 0x106, 1);
+
+ return 0;
+}
+
+static int au8522_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ v4l2_device_unregister_subdev(sd);
+ au8522_release_state(to_state(sd));
+ return 0;
+}
+
+static const struct i2c_device_id au8522_id[] = {
+ {"au8522", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, au8522_id);
+
+static struct i2c_driver au8522_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "au8522",
+ },
+ .probe = au8522_probe,
+ .remove = au8522_remove,
+ .id_table = au8522_id,
+};
+
+module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c
new file mode 100644
index 000000000000..a68974f6d708
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -0,0 +1,828 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+#include "au8522_priv.h"
+
+static int debug;
+
+#define dprintk(arg...)\
+ do { if (debug)\
+ printk(arg);\
+ } while (0)
+
+struct mse2snr_tab {
+ u16 val;
+ u16 data;
+};
+
+/* VSB SNR lookup table */
+static struct mse2snr_tab vsb_mse2snr_tab[] = {
+ { 0, 270 },
+ { 2, 250 },
+ { 3, 240 },
+ { 5, 230 },
+ { 7, 220 },
+ { 9, 210 },
+ { 12, 200 },
+ { 13, 195 },
+ { 15, 190 },
+ { 17, 185 },
+ { 19, 180 },
+ { 21, 175 },
+ { 24, 170 },
+ { 27, 165 },
+ { 31, 160 },
+ { 32, 158 },
+ { 33, 156 },
+ { 36, 152 },
+ { 37, 150 },
+ { 39, 148 },
+ { 40, 146 },
+ { 41, 144 },
+ { 43, 142 },
+ { 44, 140 },
+ { 48, 135 },
+ { 50, 130 },
+ { 43, 142 },
+ { 53, 125 },
+ { 56, 120 },
+ { 256, 115 },
+};
+
+/* QAM64 SNR lookup table */
+static struct mse2snr_tab qam64_mse2snr_tab[] = {
+ { 15, 0 },
+ { 16, 290 },
+ { 17, 288 },
+ { 18, 286 },
+ { 19, 284 },
+ { 20, 282 },
+ { 21, 281 },
+ { 22, 279 },
+ { 23, 277 },
+ { 24, 275 },
+ { 25, 273 },
+ { 26, 271 },
+ { 27, 269 },
+ { 28, 268 },
+ { 29, 266 },
+ { 30, 264 },
+ { 31, 262 },
+ { 32, 260 },
+ { 33, 259 },
+ { 34, 258 },
+ { 35, 256 },
+ { 36, 255 },
+ { 37, 254 },
+ { 38, 252 },
+ { 39, 251 },
+ { 40, 250 },
+ { 41, 249 },
+ { 42, 248 },
+ { 43, 246 },
+ { 44, 245 },
+ { 45, 244 },
+ { 46, 242 },
+ { 47, 241 },
+ { 48, 240 },
+ { 50, 239 },
+ { 51, 238 },
+ { 53, 237 },
+ { 54, 236 },
+ { 56, 235 },
+ { 57, 234 },
+ { 59, 233 },
+ { 60, 232 },
+ { 62, 231 },
+ { 63, 230 },
+ { 65, 229 },
+ { 67, 228 },
+ { 68, 227 },
+ { 70, 226 },
+ { 71, 225 },
+ { 73, 224 },
+ { 74, 223 },
+ { 76, 222 },
+ { 78, 221 },
+ { 80, 220 },
+ { 82, 219 },
+ { 85, 218 },
+ { 88, 217 },
+ { 90, 216 },
+ { 92, 215 },
+ { 93, 214 },
+ { 94, 212 },
+ { 95, 211 },
+ { 97, 210 },
+ { 99, 209 },
+ { 101, 208 },
+ { 102, 207 },
+ { 104, 206 },
+ { 107, 205 },
+ { 111, 204 },
+ { 114, 203 },
+ { 118, 202 },
+ { 122, 201 },
+ { 125, 200 },
+ { 128, 199 },
+ { 130, 198 },
+ { 132, 197 },
+ { 256, 190 },
+};
+
+/* QAM256 SNR lookup table */
+static struct mse2snr_tab qam256_mse2snr_tab[] = {
+ { 15, 0 },
+ { 16, 400 },
+ { 17, 398 },
+ { 18, 396 },
+ { 19, 394 },
+ { 20, 392 },
+ { 21, 390 },
+ { 22, 388 },
+ { 23, 386 },
+ { 24, 384 },
+ { 25, 382 },
+ { 26, 380 },
+ { 27, 379 },
+ { 28, 378 },
+ { 29, 377 },
+ { 30, 376 },
+ { 31, 375 },
+ { 32, 374 },
+ { 33, 373 },
+ { 34, 372 },
+ { 35, 371 },
+ { 36, 370 },
+ { 37, 362 },
+ { 38, 354 },
+ { 39, 346 },
+ { 40, 338 },
+ { 41, 330 },
+ { 42, 328 },
+ { 43, 326 },
+ { 44, 324 },
+ { 45, 322 },
+ { 46, 320 },
+ { 47, 319 },
+ { 48, 318 },
+ { 49, 317 },
+ { 50, 316 },
+ { 51, 315 },
+ { 52, 314 },
+ { 53, 313 },
+ { 54, 312 },
+ { 55, 311 },
+ { 56, 310 },
+ { 57, 308 },
+ { 58, 306 },
+ { 59, 304 },
+ { 60, 302 },
+ { 61, 300 },
+ { 62, 298 },
+ { 65, 295 },
+ { 68, 294 },
+ { 70, 293 },
+ { 73, 292 },
+ { 76, 291 },
+ { 78, 290 },
+ { 79, 289 },
+ { 81, 288 },
+ { 82, 287 },
+ { 83, 286 },
+ { 84, 285 },
+ { 85, 284 },
+ { 86, 283 },
+ { 88, 282 },
+ { 89, 281 },
+ { 256, 280 },
+};
+
+static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+ u16 *snr)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __func__);
+
+ for (i = 0; i < sz; i++) {
+ if (mse < tab[i].val) {
+ *snr = tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ dprintk("%s() snr=%d\n", __func__, *snr);
+ return ret;
+}
+
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 r0b5, r0b6, r0b7;
+ char *ifmhz;
+
+ switch (if_freq) {
+ case AU8522_IF_3_25MHZ:
+ ifmhz = "3.25";
+ r0b5 = 0x00;
+ r0b6 = 0x3d;
+ r0b7 = 0xa0;
+ break;
+ case AU8522_IF_4MHZ:
+ ifmhz = "4.00";
+ r0b5 = 0x00;
+ r0b6 = 0x4b;
+ r0b7 = 0xd9;
+ break;
+ case AU8522_IF_6MHZ:
+ ifmhz = "6.00";
+ r0b5 = 0xfb;
+ r0b6 = 0x8e;
+ r0b7 = 0x39;
+ break;
+ default:
+ dprintk("%s() IF Frequency not supported\n", __func__);
+ return -EINVAL;
+ }
+ dprintk("%s() %s MHz\n", __func__, ifmhz);
+ au8522_writereg(state, 0x80b5, r0b5);
+ au8522_writereg(state, 0x80b6, r0b6);
+ au8522_writereg(state, 0x80b7, r0b7);
+
+ return 0;
+}
+
+/* VSB Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} VSB_mod_tab[] = {
+ { 0x8090, 0x84 },
+ { 0x4092, 0x11 },
+ { 0x2005, 0x00 },
+ { 0x8091, 0x80 },
+ { 0x80a3, 0x0c },
+ { 0x80a4, 0xe8 },
+ { 0x8081, 0xc4 },
+ { 0x80a5, 0x40 },
+ { 0x80a7, 0x40 },
+ { 0x80a6, 0x67 },
+ { 0x8262, 0x20 },
+ { 0x821c, 0x30 },
+ { 0x80d8, 0x1a },
+ { 0x8227, 0xa0 },
+ { 0x8121, 0xff },
+ { 0x80a8, 0xf0 },
+ { 0x80a9, 0x05 },
+ { 0x80aa, 0x77 },
+ { 0x80ab, 0xf0 },
+ { 0x80ac, 0x05 },
+ { 0x80ad, 0x77 },
+ { 0x80ae, 0x41 },
+ { 0x80af, 0x66 },
+ { 0x821b, 0xcc },
+ { 0x821d, 0x80 },
+ { 0x80a4, 0xe8 },
+ { 0x8231, 0x13 },
+};
+
+/* QAM64 Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} QAM64_mod_tab[] = {
+ { 0x00a3, 0x09 },
+ { 0x00a4, 0x00 },
+ { 0x0081, 0xc4 },
+ { 0x00a5, 0x40 },
+ { 0x00aa, 0x77 },
+ { 0x00ad, 0x77 },
+ { 0x00a6, 0x67 },
+ { 0x0262, 0x20 },
+ { 0x021c, 0x30 },
+ { 0x00b8, 0x3e },
+ { 0x00b9, 0xf0 },
+ { 0x00ba, 0x01 },
+ { 0x00bb, 0x18 },
+ { 0x00bc, 0x50 },
+ { 0x00bd, 0x00 },
+ { 0x00be, 0xea },
+ { 0x00bf, 0xef },
+ { 0x00c0, 0xfc },
+ { 0x00c1, 0xbd },
+ { 0x00c2, 0x1f },
+ { 0x00c3, 0xfc },
+ { 0x00c4, 0xdd },
+ { 0x00c5, 0xaf },
+ { 0x00c6, 0x00 },
+ { 0x00c7, 0x38 },
+ { 0x00c8, 0x30 },
+ { 0x00c9, 0x05 },
+ { 0x00ca, 0x4a },
+ { 0x00cb, 0xd0 },
+ { 0x00cc, 0x01 },
+ { 0x00cd, 0xd9 },
+ { 0x00ce, 0x6f },
+ { 0x00cf, 0xf9 },
+ { 0x00d0, 0x70 },
+ { 0x00d1, 0xdf },
+ { 0x00d2, 0xf7 },
+ { 0x00d3, 0xc2 },
+ { 0x00d4, 0xdf },
+ { 0x00d5, 0x02 },
+ { 0x00d6, 0x9a },
+ { 0x00d7, 0xd0 },
+ { 0x0250, 0x0d },
+ { 0x0251, 0xcd },
+ { 0x0252, 0xe0 },
+ { 0x0253, 0x05 },
+ { 0x0254, 0xa7 },
+ { 0x0255, 0xff },
+ { 0x0256, 0xed },
+ { 0x0257, 0x5b },
+ { 0x0258, 0xae },
+ { 0x0259, 0xe6 },
+ { 0x025a, 0x3d },
+ { 0x025b, 0x0f },
+ { 0x025c, 0x0d },
+ { 0x025d, 0xea },
+ { 0x025e, 0xf2 },
+ { 0x025f, 0x51 },
+ { 0x0260, 0xf5 },
+ { 0x0261, 0x06 },
+ { 0x021a, 0x00 },
+ { 0x0546, 0x40 },
+ { 0x0210, 0xc7 },
+ { 0x0211, 0xaa },
+ { 0x0212, 0xab },
+ { 0x0213, 0x02 },
+ { 0x0502, 0x00 },
+ { 0x0121, 0x04 },
+ { 0x0122, 0x04 },
+ { 0x052e, 0x10 },
+ { 0x00a4, 0xca },
+ { 0x00a7, 0x40 },
+ { 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} QAM256_mod_tab[] = {
+ { 0x80a3, 0x09 },
+ { 0x80a4, 0x00 },
+ { 0x8081, 0xc4 },
+ { 0x80a5, 0x40 },
+ { 0x80aa, 0x77 },
+ { 0x80ad, 0x77 },
+ { 0x80a6, 0x67 },
+ { 0x8262, 0x20 },
+ { 0x821c, 0x30 },
+ { 0x80b8, 0x3e },
+ { 0x80b9, 0xf0 },
+ { 0x80ba, 0x01 },
+ { 0x80bb, 0x18 },
+ { 0x80bc, 0x50 },
+ { 0x80bd, 0x00 },
+ { 0x80be, 0xea },
+ { 0x80bf, 0xef },
+ { 0x80c0, 0xfc },
+ { 0x80c1, 0xbd },
+ { 0x80c2, 0x1f },
+ { 0x80c3, 0xfc },
+ { 0x80c4, 0xdd },
+ { 0x80c5, 0xaf },
+ { 0x80c6, 0x00 },
+ { 0x80c7, 0x38 },
+ { 0x80c8, 0x30 },
+ { 0x80c9, 0x05 },
+ { 0x80ca, 0x4a },
+ { 0x80cb, 0xd0 },
+ { 0x80cc, 0x01 },
+ { 0x80cd, 0xd9 },
+ { 0x80ce, 0x6f },
+ { 0x80cf, 0xf9 },
+ { 0x80d0, 0x70 },
+ { 0x80d1, 0xdf },
+ { 0x80d2, 0xf7 },
+ { 0x80d3, 0xc2 },
+ { 0x80d4, 0xdf },
+ { 0x80d5, 0x02 },
+ { 0x80d6, 0x9a },
+ { 0x80d7, 0xd0 },
+ { 0x8250, 0x0d },
+ { 0x8251, 0xcd },
+ { 0x8252, 0xe0 },
+ { 0x8253, 0x05 },
+ { 0x8254, 0xa7 },
+ { 0x8255, 0xff },
+ { 0x8256, 0xed },
+ { 0x8257, 0x5b },
+ { 0x8258, 0xae },
+ { 0x8259, 0xe6 },
+ { 0x825a, 0x3d },
+ { 0x825b, 0x0f },
+ { 0x825c, 0x0d },
+ { 0x825d, 0xea },
+ { 0x825e, 0xf2 },
+ { 0x825f, 0x51 },
+ { 0x8260, 0xf5 },
+ { 0x8261, 0x06 },
+ { 0x821a, 0x00 },
+ { 0x8546, 0x40 },
+ { 0x8210, 0x26 },
+ { 0x8211, 0xf6 },
+ { 0x8212, 0x84 },
+ { 0x8213, 0x02 },
+ { 0x8502, 0x01 },
+ { 0x8121, 0x04 },
+ { 0x8122, 0x04 },
+ { 0x852e, 0x10 },
+ { 0x80a4, 0xca },
+ { 0x80a7, 0x40 },
+ { 0x8526, 0x01 },
+};
+
+static int au8522_enable_modulation(struct dvb_frontend *fe,
+ fe_modulation_t m)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ int i;
+
+ dprintk("%s(0x%08x)\n", __func__, m);
+
+ switch (m) {
+ case VSB_8:
+ dprintk("%s() VSB_8\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+ au8522_writereg(state,
+ VSB_mod_tab[i].reg,
+ VSB_mod_tab[i].data);
+ au8522_set_if(fe, state->config->vsb_if);
+ break;
+ case QAM_64:
+ dprintk("%s() QAM 64\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+ au8522_writereg(state,
+ QAM64_mod_tab[i].reg,
+ QAM64_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
+ break;
+ case QAM_256:
+ dprintk("%s() QAM 256\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
+ au8522_writereg(state,
+ QAM256_mod_tab[i].reg,
+ QAM256_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
+ break;
+ default:
+ dprintk("%s() Invalid modulation\n", __func__);
+ return -EINVAL;
+ }
+
+ state->current_modulation = m;
+
+ return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+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__, c->frequency);
+
+ if ((state->current_frequency == c->frequency) &&
+ (state->current_modulation == c->modulation))
+ return 0;
+
+ 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);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Allow the tuner to settle */
+ msleep(100);
+
+ au8522_enable_modulation(fe, c->modulation);
+
+ state->current_frequency = c->frequency;
+
+ return 0;
+}
+
+static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 reg;
+ u32 tuner_status = 0;
+
+ *status = 0;
+
+ if (state->current_modulation == VSB_8) {
+ dprintk("%s() Checking VSB_8\n", __func__);
+ reg = au8522_readreg(state, 0x4088);
+ if ((reg & 0x03) == 0x03)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+ } else {
+ dprintk("%s() Checking QAM\n", __func__);
+ reg = au8522_readreg(state, 0x4541);
+ if (reg & 0x80)
+ *status |= FE_HAS_VITERBI;
+ if (reg & 0x20)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+ }
+
+ switch (state->config->status_mode) {
+ case AU8522_DEMODLOCKING:
+ dprintk("%s() DEMODLOCKING\n", __func__);
+ if (*status & FE_HAS_VITERBI)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ case AU8522_TUNERLOCKING:
+ /* Get the tuner status */
+ dprintk("%s() TUNERLOCKING\n", __func__);
+ if (fe->ops.tuner_ops.get_status) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (tuner_status)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ }
+ state->fe_status = *status;
+
+ if (*status & FE_HAS_LOCK)
+ /* turn on LED, if it isn't on already */
+ au8522_led_ctrl(state, -1);
+ else
+ /* turn off LED */
+ au8522_led_ctrl(state, 0);
+
+ dprintk("%s() status 0x%08x\n", __func__, *status);
+
+ return 0;
+}
+
+static int au8522_led_status(struct au8522_state *state, const u16 *snr)
+{
+ struct au8522_led_config *led_config = state->config->led_cfg;
+ int led;
+ u16 strong;
+
+ /* bail out if we can't control an LED */
+ if (!led_config)
+ return 0;
+
+ if (0 == (state->fe_status & FE_HAS_LOCK))
+ return au8522_led_ctrl(state, 0);
+ else if (state->current_modulation == QAM_256)
+ strong = led_config->qam256_strong;
+ else if (state->current_modulation == QAM_64)
+ strong = led_config->qam64_strong;
+ else /* (state->current_modulation == VSB_8) */
+ strong = led_config->vsb8_strong;
+
+ if (*snr >= strong)
+ led = 2;
+ else
+ led = 1;
+
+ if ((state->led_state) &&
+ (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
+ /* snr didn't change enough to bother
+ * changing the color of the led */
+ return 0;
+
+ return au8522_led_ctrl(state, led);
+}
+
+static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ int ret = -EINVAL;
+
+ dprintk("%s()\n", __func__);
+
+ if (state->current_modulation == QAM_256)
+ ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+ ARRAY_SIZE(qam256_mse2snr_tab),
+ au8522_readreg(state, 0x4522),
+ snr);
+ else if (state->current_modulation == QAM_64)
+ ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+ ARRAY_SIZE(qam64_mse2snr_tab),
+ au8522_readreg(state, 0x4522),
+ snr);
+ else /* VSB_8 */
+ ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+ ARRAY_SIZE(vsb_mse2snr_tab),
+ au8522_readreg(state, 0x4311),
+ snr);
+
+ if (state->config->led_cfg)
+ au8522_led_status(state, snr);
+
+ return ret;
+}
+
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+ u16 *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)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ if (state->current_modulation == VSB_8)
+ *ucblocks = au8522_readreg(state, 0x4087);
+ else
+ *ucblocks = au8522_readreg(state, 0x4543);
+
+ return 0;
+}
+
+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 dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct au8522_state *state = fe->demodulator_priv;
+
+ c->frequency = state->current_frequency;
+ c->modulation = state->current_modulation;
+
+ return 0;
+}
+
+static int au8522_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static struct dvb_frontend_ops au8522_ops;
+
+
+static void au8522_release(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ au8522_release_state(state);
+}
+
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct au8522_state *state = NULL;
+ int instance;
+
+ /* allocate memory for the internal state */
+ instance = au8522_get_state(&state, i2c, config->demod_address);
+ switch (instance) {
+ case 0:
+ dprintk("%s state allocation failed\n", __func__);
+ break;
+ case 1:
+ /* new demod instance */
+ dprintk("%s using new instance\n", __func__);
+ break;
+ default:
+ /* existing demod instance */
+ dprintk("%s using existing instance\n", __func__);
+ break;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->operational_mode = AU8522_DIGITAL_MODE;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &au8522_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ state->frontend.ops.analog_ops.i2c_gate_ctrl = au8522_analog_i2c_gate_ctrl;
+
+ if (au8522_init(&state->frontend) != 0) {
+ printk(KERN_ERR "%s: Failed to initialize correctly\n",
+ __func__);
+ goto error;
+ }
+
+ /* Note: Leaving the I2C gate open here. */
+ au8522_i2c_gate_ctrl(&state->frontend, 1);
+
+ return &state->frontend;
+
+error:
+ au8522_release_state(state);
+ return NULL;
+}
+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",
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = au8522_init,
+ .sleep = au8522_sleep,
+ .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
+ .set_frontend = au8522_set_frontend,
+ .get_frontend = au8522_get_frontend,
+ .get_tune_settings = au8522_get_tune_settings,
+ .read_status = au8522_read_status,
+ .read_ber = au8522_read_ber,
+ .read_signal_strength = au8522_read_signal_strength,
+ .read_snr = au8522_read_snr,
+ .read_ucblocks = au8522_read_ucblocks,
+ .release = au8522_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
new file mode 100644
index 000000000000..0529699a27bd
--- /dev/null
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -0,0 +1,446 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+ Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+ Copyright (C) 2005-2008 Auvitek International, Ltd.
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+#include "tuner-i2c.h"
+
+#define AU8522_ANALOG_MODE 0
+#define AU8522_DIGITAL_MODE 1
+
+struct au8522_state {
+ struct i2c_client *c;
+ struct i2c_adapter *i2c;
+
+ u8 operational_mode;
+
+ /* Used for sharing of the state between analog and digital mode */
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+
+ /* configuration settings */
+ const struct au8522_config *config;
+
+ struct dvb_frontend frontend;
+
+ u32 current_frequency;
+ fe_modulation_t current_modulation;
+
+ u32 fe_status;
+ unsigned int led_state;
+
+ /* Analog settings */
+ struct v4l2_subdev sd;
+ v4l2_std_id std;
+ int vid_input;
+ int aud_input;
+ u32 id;
+ u32 rev;
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ s16 hue;
+};
+
+/* These are routines shared by both the VSB/QAM demodulator and the analog
+ decoder */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
+u8 au8522_readreg(struct au8522_state *state, u16 reg);
+int au8522_init(struct dvb_frontend *fe);
+int au8522_sleep(struct dvb_frontend *fe);
+
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+ u8 client_address);
+void au8522_release_state(struct au8522_state *state);
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_led_ctrl(struct au8522_state *state, int led);
+
+/* REGISTERS */
+#define AU8522_INPUT_CONTROL_REG081H 0x081
+#define AU8522_PGA_CONTROL_REG082H 0x082
+#define AU8522_CLAMPING_CONTROL_REG083H 0x083
+
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5
+#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6
+#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7
+#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8
+#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9
+#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA
+#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB
+#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC
+#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD
+#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE
+#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF
+
+/* Receiver registers */
+#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0
+#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1
+#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2
+#define AU8522_TOREGAGC1_REG0B3H 0x0B3
+#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4
+#define AU8522_FRMREGBBH_REG0B5H 0x0B5
+#define AU8522_FRMREGBBM_REG0B6H 0x0B6
+#define AU8522_FRMREGBBL_REG0B7H 0x0B7
+/* 0xB8 TO 0xD7 are the filter coefficients */
+#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8
+#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9
+#define AU8522_TOREGAGC2_REG0DAH 0x0DA
+#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB
+#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC
+#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD
+#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE
+#define AU8522_TOREGFREQ_REG0DFH 0x0DF
+
+#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB
+#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC
+#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED
+
+#define AU8522_CHIP_MODE_REG0FEH 0x0FE
+
+/* I2C bus control registers */
+#define AU8522_I2C_CONTROL_REG0_REG090H 0x090
+#define AU8522_I2C_CONTROL_REG1_REG091H 0x091
+#define AU8522_I2C_STATUS_REG092H 0x092
+#define AU8522_I2C_WR_DATA0_REG093H 0x093
+#define AU8522_I2C_WR_DATA1_REG094H 0x094
+#define AU8522_I2C_WR_DATA2_REG095H 0x095
+#define AU8522_I2C_WR_DATA3_REG096H 0x096
+#define AU8522_I2C_WR_DATA4_REG097H 0x097
+#define AU8522_I2C_WR_DATA5_REG098H 0x098
+#define AU8522_I2C_WR_DATA6_REG099H 0x099
+#define AU8522_I2C_WR_DATA7_REG09AH 0x09A
+#define AU8522_I2C_RD_DATA0_REG09BH 0x09B
+#define AU8522_I2C_RD_DATA1_REG09CH 0x09C
+#define AU8522_I2C_RD_DATA2_REG09DH 0x09D
+#define AU8522_I2C_RD_DATA3_REG09EH 0x09E
+#define AU8522_I2C_RD_DATA4_REG09FH 0x09F
+#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0
+#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1
+#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2
+
+#define AU8522_ENA_USB_REG101H 0x101
+
+#define AU8522_I2S_CTRL_0_REG110H 0x110
+#define AU8522_I2S_CTRL_1_REG111H 0x111
+#define AU8522_I2S_CTRL_2_REG112H 0x112
+
+#define AU8522_FRMREGFFECONTROL_REG121H 0x121
+#define AU8522_FRMREGDFECONTROL_REG122H 0x122
+
+#define AU8522_CARRFREQOFFSET0_REG201H 0x201
+#define AU8522_CARRFREQOFFSET1_REG202H 0x202
+
+#define AU8522_DECIMATION_GAIN_REG21AH 0x21A
+#define AU8522_FRMREGIFSLP_REG21BH 0x21B
+#define AU8522_FRMREGTHRDL2_REG21CH 0x21C
+#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D
+#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E
+#define AU8522_FRMREGPLLMODE_REG21FH 0x21F
+#define AU8522_FRMREGCSTHRD_REG220H 0x220
+#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221
+#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222
+#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223
+#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224
+#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225
+#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226
+#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227
+#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228
+
+/* Analog TV Decoder */
+#define AU8522_TVDEC_STATUS_REG000H 0x000
+#define AU8522_TVDEC_INT_STATUS_REG001H 0x001
+#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002
+#define AU8522_TVDEC_SHARPNESSREG009H 0x009
+#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A
+#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B
+#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C
+#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D
+#define AU8522_TVDEC_HUE_H_REG00EH 0x00E
+#define AU8522_TVDEC_HUE_L_REG00FH 0x00F
+#define AU8522_TVDEC_INT_MASK_REG010H 0x010
+#define AU8522_VIDEO_MODE_REG011H 0x011
+#define AU8522_TVDEC_PGA_REG012H 0x012
+#define AU8522_TVDEC_COMB_MODE_REG015H 0x015
+#define AU8522_REG016H 0x016
+#define AU8522_TVDED_DBG_MODE_REG060H 0x060
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B
+#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E
+#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F
+
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4
+#define AU8522_TOREGAAGC_REG0E5H 0x0E5
+
+#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401
+#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402
+#define AU8522_FILTER_COEF_R410 0x410
+#define AU8522_FILTER_COEF_R411 0x411
+#define AU8522_FILTER_COEF_R412 0x412
+#define AU8522_FILTER_COEF_R413 0x413
+#define AU8522_FILTER_COEF_R414 0x414
+#define AU8522_FILTER_COEF_R415 0x415
+#define AU8522_FILTER_COEF_R416 0x416
+#define AU8522_FILTER_COEF_R417 0x417
+#define AU8522_FILTER_COEF_R418 0x418
+#define AU8522_FILTER_COEF_R419 0x419
+#define AU8522_FILTER_COEF_R41A 0x41A
+#define AU8522_FILTER_COEF_R41B 0x41B
+#define AU8522_FILTER_COEF_R41C 0x41C
+#define AU8522_FILTER_COEF_R41D 0x41D
+#define AU8522_FILTER_COEF_R41E 0x41E
+#define AU8522_FILTER_COEF_R41F 0x41F
+#define AU8522_FILTER_COEF_R420 0x420
+#define AU8522_FILTER_COEF_R421 0x421
+#define AU8522_FILTER_COEF_R422 0x422
+#define AU8522_FILTER_COEF_R423 0x423
+#define AU8522_FILTER_COEF_R424 0x424
+#define AU8522_FILTER_COEF_R425 0x425
+#define AU8522_FILTER_COEF_R426 0x426
+#define AU8522_FILTER_COEF_R427 0x427
+#define AU8522_FILTER_COEF_R428 0x428
+#define AU8522_FILTER_COEF_R429 0x429
+#define AU8522_FILTER_COEF_R42A 0x42A
+#define AU8522_FILTER_COEF_R42B 0x42B
+#define AU8522_FILTER_COEF_R42C 0x42C
+#define AU8522_FILTER_COEF_R42D 0x42D
+
+/* VBI Control Registers */
+#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004
+#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005
+#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006
+#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017
+#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018
+#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019
+#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A
+#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B
+#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F
+#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022
+#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023
+
+#define AU8522_REG071H 0x071
+#define AU8522_REG072H 0x072
+#define AU8522_REG074H 0x074
+#define AU8522_REG075H 0x075
+
+/* Digital Demodulator Registers */
+#define AU8522_FRAME_COUNT0_REG084H 0x084
+#define AU8522_RS_STATUS_G0_REG085H 0x085
+#define AU8522_RS_STATUS_B0_REG086H 0x086
+#define AU8522_RS_STATUS_E_REG087H 0x087
+#define AU8522_DEMODULATION_STATUS_REG088H 0x088
+#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6
+#define AU8522_TSPORT_CONTROL_REG10BH 0x10B
+#define AU8522_TSTHES_REG10CH 0x10C
+#define AU8522_FRMREGDFEKEEP_REG301H 0x301
+#define AU8522_DFE_AVERAGE_REG302H 0x302
+#define AU8522_FRMREGEQLERRWIN_REG303H 0x303
+#define AU8522_FRMREGFFEKEEP_REG304H 0x304
+#define AU8522_FRMREGDFECONTROL1_REG305H 0x305
+#define AU8522_FRMREGEQLERRLOW_REG306H 0x306
+
+#define AU8522_REG42EH 0x42E
+#define AU8522_REG42FH 0x42F
+#define AU8522_REG430H 0x430
+#define AU8522_REG431H 0x431
+#define AU8522_REG432H 0x432
+#define AU8522_REG433H 0x433
+#define AU8522_REG434H 0x434
+#define AU8522_REG435H 0x435
+#define AU8522_REG436H 0x436
+
+/* GPIO Registers */
+#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0
+#define AU8522_GPIO_STATUS_REG0E1H 0x0E1
+#define AU8522_GPIO_DATA_REG0E2H 0x0E2
+
+/* Audio Control Registers */
+#define AU8522_AUDIOAGC_REG0EEH 0x0EE
+#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0
+#define AU8522_AUDIO_MODE_REG0F1H 0x0F1
+#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2
+#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3
+#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4
+#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7
+#define AU8522_REG0F9H 0x0F9
+
+#define AU8522_AUDIOAGC2_REG605H 0x605
+#define AU8522_AUDIOFREQ_REG606H 0x606
+
+
+/**************************************************************/
+
+/* Format control 1 */
+
+/* VCR Mode 7-6 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_YES 0x80
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_NO 0x40
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_AUTO 0x00
+/* Field len 5-4 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_625 0x20
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 0x10
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_AUTO 0x00
+/* Line len (us) 3-2 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_64_000 0x0b
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 0x08
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_556 0x04
+/* Subcarrier freq 1-0 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO 0x03
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_443 0x02
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN 0x01
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_50 0x00
+
+/* Format control 2 */
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT 0x00
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC 0x01
+
+
+#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4
+#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4
+#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4
+#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68
+#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28
+/* CH1 AS Y,CH3 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23
+/* CH2 AS Y,CH4 AS C */
+#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A
+#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02
+
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD
+#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD
+
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01
+#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01
+
+/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
+#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79
+#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80
+#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80
+#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00
+#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00
+#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F
+#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00
+#define AU8522_REG016H_CVBS 0x00
+#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00
+#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19
+#define AU8522_REG0F9H_AUDIO 0x20
+#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7
+#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A
+#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32
+#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19
+#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23
+#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41
+#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
+#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15
+#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
+#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
+#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
+#define AU8522_REG071H_CVBS 0x18
+#define AU8522_REG072H_CVBS 0x30
+#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0
+#define AU8522_REG074H_CVBS 0x80
+#define AU8522_REG075H_CVBS 0xF0
+#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB
+#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04
+#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00
+#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00
+#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE
+#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE
+#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00
+#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40
+
+/* Enables Closed captioning */
+#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index 033cd7ad3ca2..033cd7ad3ca2 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
index f4575c0cc446..f4575c0cc446 100644
--- a/drivers/media/dvb/frontends/bcm3510.h
+++ b/drivers/media/dvb-frontends/bcm3510.h
diff --git a/drivers/media/dvb/frontends/bcm3510_priv.h b/drivers/media/dvb-frontends/bcm3510_priv.h
index 3bb1bc2a04f0..3bb1bc2a04f0 100644
--- a/drivers/media/dvb/frontends/bcm3510_priv.h
+++ b/drivers/media/dvb-frontends/bcm3510_priv.h
diff --git a/drivers/media/dvb/frontends/bsbe1-d01a.h b/drivers/media/dvb-frontends/bsbe1-d01a.h
index 7ed3c424178c..7ed3c424178c 100644
--- a/drivers/media/dvb/frontends/bsbe1-d01a.h
+++ b/drivers/media/dvb-frontends/bsbe1-d01a.h
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb-frontends/bsbe1.h
index 53e4d0dbb745..53e4d0dbb745 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb-frontends/bsbe1.h
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb-frontends/bsru6.h
index c2a578e1314d..c2a578e1314d 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb-frontends/bsru6.h
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c
index f2a90f990ce3..f2a90f990ce3 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb-frontends/cx22700.c
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h
index 4757a930ca05..4757a930ca05 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb-frontends/cx22700.h
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb-frontends/cx22702.c
index edc8eafc5c09..edc8eafc5c09 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb-frontends/cx22702.c
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h
index f154e1f428eb..f154e1f428eb 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb-frontends/cx22702.h
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c
index 3180f5b2a6a6..3180f5b2a6a6 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb-frontends/cx24110.c
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h
index fdcceee91f3a..fdcceee91f3a 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb-frontends/cx24110.h
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c
index 3883c3b31aef..3883c3b31aef 100644
--- a/drivers/media/dvb/frontends/cx24113.c
+++ b/drivers/media/dvb-frontends/cx24113.c
diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h
index 01eb7b9c28f4..01eb7b9c28f4 100644
--- a/drivers/media/dvb/frontends/cx24113.h
+++ b/drivers/media/dvb-frontends/cx24113.h
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
index b48879186537..b48879186537 100644
--- a/drivers/media/dvb/frontends/cx24116.c
+++ b/drivers/media/dvb-frontends/cx24116.c
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h
index 7d90ab949c03..7d90ab949c03 100644
--- a/drivers/media/dvb/frontends/cx24116.h
+++ b/drivers/media/dvb-frontends/cx24116.h
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c
index 7e28b4ee7d4f..7e28b4ee7d4f 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb-frontends/cx24123.c
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h
index 51ae866e9fed..51ae866e9fed 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb-frontends/cx24123.h
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index 5aa306ebb7ef..5aa306ebb7ef 100644
--- a/drivers/media/dvb/frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index ed3b0ba624de..ed3b0ba624de 100644
--- a/drivers/media/dvb/frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 3bba37d74f57..3bba37d74f57 100644
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
index 9a9822cad9cd..9a9822cad9cd 100644
--- a/drivers/media/dvb/frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
new file mode 100644
index 000000000000..e5dd22bc16be
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -0,0 +1,452 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 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 "cxd2820r_priv.h"
+
+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, bw_i;
+ u32 if_freq, if_ctl;
+ u64 num;
+ u8 buf[3], bw_param;
+ u8 bw_params1[][5] = {
+ { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+ { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+ { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+ };
+ u8 bw_params2[][2] = {
+ { 0x1f, 0xdc }, /* 6 MHz */
+ { 0x12, 0xf8 }, /* 7 MHz */
+ { 0x01, 0xe0 }, /* 8 MHz */
+ };
+ struct reg_val_mask tab[] = {
+ { 0x00080, 0x00, 0xff },
+ { 0x00081, 0x03, 0xff },
+ { 0x00085, 0x07, 0xff },
+ { 0x00088, 0x01, 0xff },
+
+ { 0x00070, priv->cfg.ts_mode, 0xff },
+ { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+ { 0x000a5, 0x00, 0x01 },
+ { 0x00082, 0x20, 0x60 },
+ { 0x000c2, 0xc3, 0xff },
+ { 0x0016a, 0x50, 0xff },
+ { 0x00427, 0x41, 0xff },
+ };
+
+ 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)
+ goto error;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ if (priv->delivery_system != SYS_DVBT) {
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+ tab[i].val, tab[i].mask);
+ if (ret)
+ goto error;
+ }
+ }
+
+ priv->delivery_system = SYS_DVBT;
+ priv->ber_running = 0; /* tune stops BER counter */
+
+ /* 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 *= 0x1000000;
+ if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+ buf[0] = ((if_ctl >> 16) & 0xff);
+ buf[1] = ((if_ctl >> 8) & 0xff);
+ buf[2] = ((if_ctl >> 0) & 0xff);
+
+ ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+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;
+ int ret;
+ u8 buf[2];
+
+ ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 6) & 0x03) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ }
+
+ switch ((buf[1] >> 1) & 0x03) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+
+ switch ((buf[1] >> 3) & 0x03) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch ((buf[0] >> 3) & 0x07) {
+ case 0:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ switch ((buf[0] >> 0) & 0x07) {
+ case 0:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch ((buf[1] >> 5) & 0x07) {
+ case 0:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 0) & 0x01) {
+ case 0:
+ c->inversion = INVERSION_OFF;
+ break;
+ case 1:
+ c->inversion = INVERSION_ON;
+ break;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[3], start_ber = 0;
+ *ber = 0;
+
+ if (priv->ber_running) {
+ ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+ *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+ start_ber = 1;
+ }
+ } else {
+ priv->ber_running = 1;
+ start_ber = 1;
+ }
+
+ if (start_ber) {
+ /* (re)start BER */
+ ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+
+ ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x0f) << 8 | buf[1];
+ tmp = ~tmp & 0x0fff;
+
+ /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+ *strength = tmp * 0xffff / 0x0fff;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+ /* report SNR in dB * 10 */
+
+ ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x1f) << 8 | buf[1];
+ #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+ if (tmp)
+ *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+ / 100);
+ else
+ *snr = 0;
+
+ dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ /* no way to read ? */
+ return 0;
+}
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[4];
+ *status = 0;
+
+ ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
+ if (ret)
+ goto error;
+
+ if ((buf[0] & 0x07) == 6) {
+ ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
+ if (ret)
+ goto error;
+
+ if (((buf[1] >> 3) & 0x01) == 1) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ } else {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC;
+ }
+ } else {
+ ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
+ if (ret)
+ goto error;
+
+ if ((buf[2] & 0x0f) >= 4) {
+ ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
+ if (ret)
+ goto error;
+
+ if (((buf[3] >> 4) & 0x01) == 1)
+ *status |= FE_HAS_SIGNAL;
+ }
+ }
+
+ dbg("%s: lock=%*ph", __func__, 4, buf);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_init_t(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+
+ ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ struct reg_val_mask tab[] = {
+ { 0x000ff, 0x1f, 0xff },
+ { 0x00085, 0x00, 0xff },
+ { 0x00088, 0x01, 0xff },
+ { 0x00081, 0x00, 0xff },
+ { 0x00080, 0x00, 0xff },
+ };
+
+ dbg("%s", __func__);
+
+ priv->delivery_system = SYS_UNDEFINED;
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_tune_settings_t(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;
+}
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
index 3a5759e0d235..3a5759e0d235 100644
--- a/drivers/media/dvb/frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c
index 3b024bfe980a..3b024bfe980a 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb-frontends/dib0070.c
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h
index 45c31fae3967..45c31fae3967 100644
--- a/drivers/media/dvb/frontends/dib0070.h
+++ b/drivers/media/dvb-frontends/dib0070.h
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index d9fe60b4be48..d9fe60b4be48 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h
index 781dc49de45b..781dc49de45b 100644
--- a/drivers/media/dvb/frontends/dib0090.h
+++ b/drivers/media/dvb-frontends/dib0090.h
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index 404f63a6f26b..404f63a6f26b 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c
index af91e0c92339..af91e0c92339 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb-frontends/dib3000mb.c
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb-frontends/dib3000mb_priv.h
index 9dc235aa44b7..9dc235aa44b7 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb-frontends/dib3000mb_priv.h
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c
index ffad181a9692..ffad181a9692 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb-frontends/dib3000mc.c
diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h
index d75ffad2d752..d75ffad2d752 100644
--- a/drivers/media/dvb/frontends/dib3000mc.h
+++ b/drivers/media/dvb-frontends/dib3000mc.h
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c
index 148bf79236fb..148bf79236fb 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb-frontends/dib7000m.c
diff --git a/drivers/media/dvb/frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h
index 81fcf2241c64..81fcf2241c64 100644
--- a/drivers/media/dvb/frontends/dib7000m.h
+++ b/drivers/media/dvb-frontends/dib7000m.h
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 3e1eefada0e8..3e1eefada0e8 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
index b61b03a6e1ed..b61b03a6e1ed 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 1f3bcb5a1de8..1f3bcb5a1de8 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 39591bb172c1..39591bb172c1 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c
index 6201c59a78dd..6201c59a78dd 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb-frontends/dib9000.c
diff --git a/drivers/media/dvb/frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h
index b5781a48034c..b5781a48034c 100644
--- a/drivers/media/dvb/frontends/dib9000.h
+++ b/drivers/media/dvb-frontends/dib9000.h
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c
index 43be7238311e..43be7238311e 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb-frontends/dibx000_common.c
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h
index 5f484881d7b1..5f484881d7b1 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb-frontends/dibx000_common.h
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
index 216c8c3702f8..216c8c3702f8 100644
--- a/drivers/media/dvb/frontends/drxd.h
+++ b/drivers/media/dvb-frontends/drxd.h
diff --git a/drivers/media/dvb/frontends/drxd_firm.c b/drivers/media/dvb-frontends/drxd_firm.c
index 5418b0b1dadc..5418b0b1dadc 100644
--- a/drivers/media/dvb/frontends/drxd_firm.c
+++ b/drivers/media/dvb-frontends/drxd_firm.c
diff --git a/drivers/media/dvb/frontends/drxd_firm.h b/drivers/media/dvb-frontends/drxd_firm.h
index 41597e89941c..41597e89941c 100644
--- a/drivers/media/dvb/frontends/drxd_firm.h
+++ b/drivers/media/dvb-frontends/drxd_firm.h
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index f380eb43e9d5..f380eb43e9d5 100644
--- a/drivers/media/dvb/frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
diff --git a/drivers/media/dvb/frontends/drxd_map_firm.h b/drivers/media/dvb-frontends/drxd_map_firm.h
index 6bc553abf215..6bc553abf215 100644
--- a/drivers/media/dvb/frontends/drxd_map_firm.h
+++ b/drivers/media/dvb-frontends/drxd_map_firm.h
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
index d615d7d055a2..d615d7d055a2 100644
--- a/drivers/media/dvb/frontends/drxk.h
+++ b/drivers/media/dvb-frontends/drxk.h
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 1ab8154542da..1ab8154542da 100644
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
index 6bb9fc4a7b96..6bb9fc4a7b96 100644
--- a/drivers/media/dvb/frontends/drxk_hard.h
+++ b/drivers/media/dvb-frontends/drxk_hard.h
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h
index 23e16c12f234..23e16c12f234 100644
--- a/drivers/media/dvb/frontends/drxk_map.h
+++ b/drivers/media/dvb-frontends/drxk_map.h
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c
index 4c8ac2657c4a..4c8ac2657c4a 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb-frontends/ds3000.c
diff --git a/drivers/media/dvb/frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
index 1b736888ea37..1b736888ea37 100644
--- a/drivers/media/dvb/frontends/ds3000.h
+++ b/drivers/media/dvb-frontends/ds3000.h
diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c
new file mode 100644
index 000000000000..6d8fe8843237
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb-pll.c
@@ -0,0 +1,820 @@
+/*
+ * descriptions + helper functions for simple dvb plls.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "dvb-pll.h"
+
+struct dvb_pll_priv {
+ /* pll number */
+ int nr;
+
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int id[DVB_PLL_MAX] =
+ { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
+struct dvb_pll_desc {
+ char *name;
+ u32 min;
+ u32 max;
+ u32 iffreq;
+ void (*set)(struct dvb_frontend *fe, u8 *buf);
+ u8 *initdata;
+ u8 *initdata2;
+ u8 *sleepdata;
+ int count;
+ struct {
+ u32 limit;
+ u32 stepsize;
+ u8 config;
+ u8 cb;
+ } entries[12];
+};
+
+/* ----------------------------------------------------------- */
+/* descriptions */
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+ .name = "Thomson dtt7579",
+ .min = 177000000,
+ .max = 858000000,
+ .iffreq= 36166667,
+ .sleepdata = (u8[]){ 2, 0xb4, 0x03 },
+ .count = 4,
+ .entries = {
+ { 443250000, 166667, 0xb4, 0x02 },
+ { 542000000, 166667, 0xb4, 0x08 },
+ { 771000000, 166667, 0xbc, 0x08 },
+ { 999999999, 166667, 0xf4, 0x08 },
+ },
+};
+
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 7000000)
+ buf[3] |= 0x10;
+}
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+ .name = "Thomson dtt759x",
+ .min = 177000000,
+ .max = 896000000,
+ .set = thomson_dtt759x_bw,
+ .iffreq= 36166667,
+ .sleepdata = (u8[]){ 2, 0x84, 0x03 },
+ .count = 5,
+ .entries = {
+ { 264000000, 166667, 0xb4, 0x02 },
+ { 470000000, 166667, 0xbc, 0x02 },
+ { 735000000, 166667, 0xbc, 0x08 },
+ { 835000000, 166667, 0xf4, 0x08 },
+ { 999999999, 166667, 0xfc, 0x08 },
+ },
+};
+
+static void thomson_dtt7520x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 8000000)
+ buf[3] ^= 0x10;
+}
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
+ .name = "Thomson dtt7520x",
+ .min = 185000000,
+ .max = 900000000,
+ .set = thomson_dtt7520x_bw,
+ .iffreq = 36166667,
+ .count = 7,
+ .entries = {
+ { 305000000, 166667, 0xb4, 0x12 },
+ { 405000000, 166667, 0xbc, 0x12 },
+ { 445000000, 166667, 0xbc, 0x12 },
+ { 465000000, 166667, 0xf4, 0x18 },
+ { 735000000, 166667, 0xfc, 0x18 },
+ { 835000000, 166667, 0xbc, 0x18 },
+ { 999999999, 166667, 0xfc, 0x18 },
+ },
+};
+
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
+ .name = "LG z201",
+ .min = 174000000,
+ .max = 862000000,
+ .iffreq= 36166667,
+ .sleepdata = (u8[]){ 2, 0xbc, 0x03 },
+ .count = 5,
+ .entries = {
+ { 157500000, 166667, 0xbc, 0x01 },
+ { 443250000, 166667, 0xbc, 0x02 },
+ { 542000000, 166667, 0xbc, 0x04 },
+ { 830000000, 166667, 0xf4, 0x04 },
+ { 999999999, 166667, 0xfc, 0x04 },
+ },
+};
+
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
+ .name = "unknown 1", /* used by dntv live dvb-t */
+ .min = 174000000,
+ .max = 862000000,
+ .iffreq= 36166667,
+ .count = 9,
+ .entries = {
+ { 150000000, 166667, 0xb4, 0x01 },
+ { 173000000, 166667, 0xbc, 0x01 },
+ { 250000000, 166667, 0xb4, 0x02 },
+ { 400000000, 166667, 0xbc, 0x02 },
+ { 420000000, 166667, 0xf4, 0x02 },
+ { 470000000, 166667, 0xfc, 0x02 },
+ { 600000000, 166667, 0xbc, 0x08 },
+ { 730000000, 166667, 0xf4, 0x08 },
+ { 999999999, 166667, 0xfc, 0x08 },
+ },
+};
+
+/* Infineon TUA6010XS
+ * used in Thomson Cable Tuner
+ */
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
+ .name = "Infineon TUA6010XS",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq= 36125000,
+ .count = 3,
+ .entries = {
+ { 115750000, 62500, 0x8e, 0x03 },
+ { 403250000, 62500, 0x8e, 0x06 },
+ { 999999999, 62500, 0x8e, 0x85 },
+ },
+};
+
+/* Panasonic env57h1xd5 (some Philips PLL ?) */
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+ .name = "Panasonic ENV57H1XD5",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq= 36125000,
+ .count = 4,
+ .entries = {
+ { 153000000, 166667, 0xc2, 0x41 },
+ { 470000000, 166667, 0xc2, 0x42 },
+ { 526000000, 166667, 0xc2, 0x84 },
+ { 999999999, 166667, 0xc2, 0xa4 },
+ },
+};
+
+/* Philips TDA6650/TDA6651
+ * used in Panasonic ENV77H11D5
+ */
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 8000000)
+ buf[3] |= 0x08;
+}
+
+static struct dvb_pll_desc dvb_pll_tda665x = {
+ .name = "Philips TDA6650/TDA6651",
+ .min = 44250000,
+ .max = 858000000,
+ .set = tda665x_bw,
+ .iffreq= 36166667,
+ .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
+ .count = 12,
+ .entries = {
+ { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
+ { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
+ { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
+ { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
+ { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
+ { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
+ { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
+ { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
+ { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
+ { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
+ }
+};
+
+/* Infineon TUA6034
+ * used in LG TDTP E102P
+ */
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
+{
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 7000000)
+ buf[3] |= 0x08;
+}
+
+static struct dvb_pll_desc dvb_pll_tua6034 = {
+ .name = "Infineon TUA6034",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq= 36166667,
+ .count = 3,
+ .set = tua6034_bw,
+ .entries = {
+ { 174500000, 62500, 0xce, 0x01 },
+ { 230000000, 62500, 0xce, 0x02 },
+ { 999999999, 62500, 0xce, 0x04 },
+ },
+};
+
+/* ALPS TDED4
+ * used in Nebula-Cards and USB boxes
+ */
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
+{
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 8000000)
+ buf[3] |= 0x04;
+}
+
+static struct dvb_pll_desc dvb_pll_tded4 = {
+ .name = "ALPS TDED4",
+ .min = 47000000,
+ .max = 863000000,
+ .iffreq= 36166667,
+ .set = tded4_bw,
+ .count = 4,
+ .entries = {
+ { 153000000, 166667, 0x85, 0x01 },
+ { 470000000, 166667, 0x85, 0x02 },
+ { 823000000, 166667, 0x85, 0x08 },
+ { 999999999, 166667, 0x85, 0x88 },
+ }
+};
+
+/* ALPS TDHU2
+ * used in AverTVHD MCE A180
+ */
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
+ .name = "ALPS TDHU2",
+ .min = 54000000,
+ .max = 864000000,
+ .iffreq= 44000000,
+ .count = 4,
+ .entries = {
+ { 162000000, 62500, 0x85, 0x01 },
+ { 426000000, 62500, 0x85, 0x02 },
+ { 782000000, 62500, 0x85, 0x08 },
+ { 999999999, 62500, 0x85, 0x88 },
+ }
+};
+
+/* Samsung TBMV30111IN / TBMV30712IN1
+ * used in Air2PC ATSC - 2nd generation (nxt2002)
+ */
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+ .name = "Samsung TBMV30111IN / TBMV30712IN1",
+ .min = 54000000,
+ .max = 860000000,
+ .iffreq= 44000000,
+ .count = 6,
+ .entries = {
+ { 172000000, 166667, 0xb4, 0x01 },
+ { 214000000, 166667, 0xb4, 0x02 },
+ { 467000000, 166667, 0xbc, 0x02 },
+ { 721000000, 166667, 0xbc, 0x08 },
+ { 841000000, 166667, 0xf4, 0x08 },
+ { 999999999, 166667, 0xfc, 0x02 },
+ }
+};
+
+/*
+ * Philips SD1878 Tuner.
+ */
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+ .name = "Philips SD1878",
+ .min = 950000,
+ .max = 2150000,
+ .iffreq= 249, /* zero-IF, offset 249 is to round up */
+ .count = 4,
+ .entries = {
+ { 1250000, 500, 0xc4, 0x00},
+ { 1450000, 500, 0xc4, 0x40},
+ { 2050000, 500, 0xc4, 0x80},
+ { 2150000, 500, 0xc4, 0xc0},
+ },
+};
+
+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 = (c->symbol_rate * 27) / 32000;
+ struct i2c_msg msg = {
+ .addr = priv->pll_i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 4
+ };
+ int result;
+ u8 lpf;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ printk(KERN_ERR "%s: i2c_transfer failed:%d",
+ __func__, result);
+
+ if (b_w <= 10000)
+ lpf = 0xc;
+ else if (b_w <= 12000)
+ lpf = 0x2;
+ else if (b_w <= 14000)
+ lpf = 0xa;
+ else if (b_w <= 16000)
+ lpf = 0x6;
+ else if (b_w <= 18000)
+ lpf = 0xe;
+ else if (b_w <= 20000)
+ lpf = 0x1;
+ else if (b_w <= 22000)
+ lpf = 0x9;
+ else if (b_w <= 24000)
+ lpf = 0x5;
+ else if (b_w <= 26000)
+ lpf = 0xd;
+ else if (b_w <= 28000)
+ lpf = 0x3;
+ else
+ lpf = 0xb;
+ buf[2] ^= 0x1c; /* Flip bits 3-5 */
+ /* Set lpf */
+ buf[2] |= ((lpf >> 2) & 0x3) << 3;
+ buf[3] |= (lpf & 0x3) << 2;
+
+ return;
+}
+
+static struct dvb_pll_desc dvb_pll_opera1 = {
+ .name = "Opera Tuner",
+ .min = 900000,
+ .max = 2250000,
+ .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 },
+ .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 },
+ .iffreq= 0,
+ .set = opera1_bw,
+ .count = 8,
+ .entries = {
+ { 1064000, 500, 0xf9, 0xc2 },
+ { 1169000, 500, 0xf9, 0xe2 },
+ { 1299000, 500, 0xf9, 0x20 },
+ { 1444000, 500, 0xf9, 0x40 },
+ { 1606000, 500, 0xf9, 0x60 },
+ { 1777000, 500, 0xf9, 0x80 },
+ { 1941000, 500, 0xf9, 0xa0 },
+ { 2250000, 500, 0xf9, 0xc0 },
+ }
+};
+
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = {
+ .addr = priv->pll_i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 4
+ };
+ int result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ printk(KERN_ERR "%s: i2c_transfer failed:%d",
+ __func__, result);
+
+ buf[2] = 0x9e;
+ buf[3] = 0x90;
+
+ return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+ .name = "Samsung DTOS403IH102A",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq = 36125000,
+ .count = 8,
+ .set = samsung_dtos403ih102a_set,
+ .entries = {
+ { 135000000, 62500, 0xbe, 0x01 },
+ { 177000000, 62500, 0xf6, 0x01 },
+ { 370000000, 62500, 0xbe, 0x02 },
+ { 450000000, 62500, 0xf6, 0x02 },
+ { 466000000, 62500, 0xfe, 0x02 },
+ { 538000000, 62500, 0xbe, 0x08 },
+ { 826000000, 62500, 0xf6, 0x08 },
+ { 999999999, 62500, 0xfe, 0x08 },
+ }
+};
+
+/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
+static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
+ .name = "Samsung TDTC9251DH0",
+ .min = 48000000,
+ .max = 863000000,
+ .iffreq = 36166667,
+ .count = 3,
+ .entries = {
+ { 157500000, 166667, 0xcc, 0x09 },
+ { 443000000, 166667, 0xcc, 0x0a },
+ { 863000000, 166667, 0xcc, 0x08 },
+ }
+};
+
+/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
+static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
+ .name = "Samsung TBDU18132",
+ .min = 950000,
+ .max = 2150000, /* guesses */
+ .iffreq = 0,
+ .count = 2,
+ .entries = {
+ { 1550000, 125, 0x84, 0x82 },
+ { 4095937, 125, 0x84, 0x80 },
+ }
+ /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
+ * by this driver. The two extra bits are 0x60 in the third byte. 15
+ * bits is enough for over 4 GHz, which is enough to cover the range
+ * of this tuner. We could use the additional divisor bits by adding
+ * more entries, e.g.
+ { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
+ { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
+ { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
+};
+
+/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
+static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
+ .name = "Samsung TBMU24112",
+ .min = 950000,
+ .max = 2150000, /* guesses */
+ .iffreq = 0,
+ .count = 2,
+ .entries = {
+ { 1500000, 125, 0x84, 0x18 },
+ { 9999999, 125, 0x84, 0x08 },
+ }
+};
+
+/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
+/* byte 4 : 1 * * AGD R3 R2 R1 R0
+ * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
+ * Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+ * 47 - 153 0 * 0 0 0 0 0 1 0x01
+ * 153 - 430 0 * 0 0 0 0 1 0 0x02
+ * 430 - 822 0 * 0 0 1 0 0 0 0x08
+ * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
+static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
+ .name = "ALPS TDEE4",
+ .min = 47000000,
+ .max = 862000000,
+ .iffreq = 36125000,
+ .count = 4,
+ .entries = {
+ { 153000000, 62500, 0x95, 0x01 },
+ { 430000000, 62500, 0x95, 0x02 },
+ { 822000000, 62500, 0x95, 0x08 },
+ { 999999999, 62500, 0x95, 0x88 },
+ }
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+ [DVB_PLL_UNDEFINED] = NULL,
+ [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
+ [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
+ [DVB_PLL_THOMSON_DTT7520X] = &dvb_pll_thomson_dtt7520x,
+ [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
+ [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
+ [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
+ [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
+ [DVB_PLL_TUA6034] = &dvb_pll_tua6034,
+ [DVB_PLL_TDA665X] = &dvb_pll_tda665x,
+ [DVB_PLL_TDED4] = &dvb_pll_tded4,
+ [DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4,
+ [DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
+ [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
+ [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+ [DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
+ [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0,
+ [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132,
+ [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112,
+};
+
+/* ----------------------------------------------------------- */
+/* code */
+
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
+ const u32 frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct dvb_pll_desc *desc = priv->pll_desc;
+ u32 div;
+ int i;
+
+ if (frequency && (frequency < desc->min || frequency > desc->max))
+ return -EINVAL;
+
+ for (i = 0; i < desc->count; i++) {
+ if (frequency > desc->entries[i].limit)
+ continue;
+ break;
+ }
+
+ if (debug)
+ printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+ frequency, i, desc->count);
+ if (i == desc->count)
+ return -EINVAL;
+
+ div = (frequency + desc->iffreq +
+ desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
+ buf[0] = div >> 8;
+ buf[1] = div & 0xff;
+ buf[2] = desc->entries[i].config;
+ buf[3] = desc->entries[i].cb;
+
+ if (desc->set)
+ desc->set(fe, buf);
+
+ if (debug)
+ printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+ desc->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+ // calculate the frequency we set it to
+ return (div * desc->entries[i].stepsize) - desc->iffreq;
+}
+
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ if (priv->pll_desc->sleepdata) {
+ struct i2c_msg msg = { .flags = 0,
+ .addr = priv->pll_i2c_address,
+ .buf = priv->pll_desc->sleepdata + 1,
+ .len = priv->pll_desc->sleepdata[0] };
+
+ int result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+ return 0;
+ }
+ /* Shouldn't be called when initdata is NULL, maybe BUG()? */
+ return -EINVAL;
+}
+
+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 =
+ { .addr = priv->pll_i2c_address, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ int result;
+ u32 frequency = 0;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ result = dvb_pll_configure(fe, buf, c->frequency);
+ if (result < 0)
+ return result;
+ else
+ frequency = result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ priv->frequency = frequency;
+ priv->bandwidth = c->bandwidth_hz;
+
+ return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe,
+ 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;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ result = dvb_pll_configure(fe, buf + 1, c->frequency);
+ if (result < 0)
+ return result;
+ else
+ frequency = result;
+
+ buf[0] = priv->pll_i2c_address;
+
+ priv->frequency = frequency;
+ priv->bandwidth = c->bandwidth_hz;
+
+ return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int dvb_pll_init(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ if (priv->pll_desc->initdata) {
+ struct i2c_msg msg = { .flags = 0,
+ .addr = priv->pll_i2c_address,
+ .buf = priv->pll_desc->initdata + 1,
+ .len = priv->pll_desc->initdata[0] };
+
+ int result;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ return result;
+ if (priv->pll_desc->initdata2) {
+ msg.buf = priv->pll_desc->initdata2 + 1;
+ msg.len = priv->pll_desc->initdata2[0];
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ return result;
+ }
+ return 0;
+ }
+ /* Shouldn't be called when initdata is NULL, maybe BUG()? */
+ return -EINVAL;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+ .release = dvb_pll_release,
+ .sleep = dvb_pll_sleep,
+ .init = dvb_pll_init,
+ .set_params = dvb_pll_set_params,
+ .calc_regs = dvb_pll_calc_regs,
+ .get_frequency = dvb_pll_get_frequency,
+ .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
+ struct i2c_adapter *i2c,
+ unsigned int pll_desc_id)
+{
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 };
+ struct dvb_pll_priv *priv = NULL;
+ int ret;
+ struct dvb_pll_desc *desc;
+
+ if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+ (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+ pll_desc_id = id[dvb_pll_devcount];
+
+ BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+ desc = pll_list[pll_desc_id];
+
+ if (i2c != NULL) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer (i2c, &msg, 1);
+ if (ret != 1)
+ return NULL;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+ priv->pll_desc = desc;
+ priv->nr = dvb_pll_devcount++;
+
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ strncpy(fe->ops.tuner_ops.info.name, desc->name,
+ sizeof(fe->ops.tuner_ops.info.name));
+ fe->ops.tuner_ops.info.frequency_min = desc->min;
+ fe->ops.tuner_ops.info.frequency_max = desc->max;
+ if (!desc->initdata)
+ fe->ops.tuner_ops.init = NULL;
+ if (!desc->sleepdata)
+ fe->ops.tuner_ops.sleep = NULL;
+
+ fe->tuner_priv = priv;
+
+ if ((debug) || (id[priv->nr] == pll_desc_id)) {
+ printk("dvb-pll[%d]", priv->nr);
+ if (i2c != NULL)
+ printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+ printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+ id[priv->nr] == pll_desc_id ?
+ "insmod option" : "autodetected");
+ }
+
+ return fe;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
+MODULE_DESCRIPTION("dvb pll library");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
new file mode 100644
index 000000000000..4de754f76ce9
--- /dev/null
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -0,0 +1,57 @@
+/*
+ * descriptions + helper functions for simple dvb plls.
+ */
+
+#ifndef __DVB_PLL_H__
+#define __DVB_PLL_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#define DVB_PLL_UNDEFINED 0
+#define DVB_PLL_THOMSON_DTT7579 1
+#define DVB_PLL_THOMSON_DTT759X 2
+#define DVB_PLL_LG_Z201 3
+#define DVB_PLL_UNKNOWN_1 4
+#define DVB_PLL_TUA6010XS 5
+#define DVB_PLL_ENV57H1XD5 6
+#define DVB_PLL_TUA6034 7
+#define DVB_PLL_TDA665X 8
+#define DVB_PLL_TDED4 9
+#define DVB_PLL_TDHU2 10
+#define DVB_PLL_SAMSUNG_TBMV 11
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
+#define DVB_PLL_OPERA1 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
+#define DVB_PLL_SAMSUNG_TDTC9251DH0 15
+#define DVB_PLL_SAMSUNG_TBDU18132 16
+#define DVB_PLL_SAMSUNG_TBMU24112 17
+#define DVB_PLL_TDEE4 18
+#define DVB_PLL_THOMSON_DTT7520X 19
+
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param pll_desc_id dvb_pll_desc to use.
+ * @return Frontend pointer on success, NULL on failure
+ */
+#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+ int pll_addr,
+ struct i2c_adapter *i2c,
+ unsigned int pll_desc_id);
+#else
+static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+ int pll_addr,
+ struct i2c_adapter *i2c,
+ unsigned int pll_desc_id)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c
index dcfc902c8678..dcfc902c8678 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h
index 1fcb987d6386..1fcb987d6386 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.h
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h
diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb-frontends/ec100.c
index c56fddbf53b7..c56fddbf53b7 100644
--- a/drivers/media/dvb/frontends/ec100.c
+++ b/drivers/media/dvb-frontends/ec100.c
diff --git a/drivers/media/dvb/frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h
index ee8e52417958..ee8e52417958 100644
--- a/drivers/media/dvb/frontends/ec100.h
+++ b/drivers/media/dvb-frontends/ec100.h
diff --git a/drivers/media/dvb/frontends/ec100_priv.h b/drivers/media/dvb-frontends/ec100_priv.h
index 5c990144bc47..5c990144bc47 100644
--- a/drivers/media/dvb/frontends/ec100_priv.h
+++ b/drivers/media/dvb-frontends/ec100_priv.h
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb-frontends/eds1547.h
index c983f2f85802..c983f2f85802 100644
--- a/drivers/media/dvb/frontends/eds1547.h
+++ b/drivers/media/dvb-frontends/eds1547.h
diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c
index a00318190837..a00318190837 100644
--- a/drivers/media/dvb/frontends/hd29l2.c
+++ b/drivers/media/dvb-frontends/hd29l2.c
diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h
index a7a64431364d..a7a64431364d 100644
--- a/drivers/media/dvb/frontends/hd29l2.h
+++ b/drivers/media/dvb-frontends/hd29l2.h
diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb-frontends/hd29l2_priv.h
index ba16dc3ec2bd..ba16dc3ec2bd 100644
--- a/drivers/media/dvb/frontends/hd29l2_priv.h
+++ b/drivers/media/dvb-frontends/hd29l2_priv.h
diff --git a/drivers/media/dvb/frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c
index 33d33f4d8867..33d33f4d8867 100644
--- a/drivers/media/dvb/frontends/isl6405.c
+++ b/drivers/media/dvb-frontends/isl6405.c
diff --git a/drivers/media/dvb/frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
index 1c793d37576b..1c793d37576b 100644
--- a/drivers/media/dvb/frontends/isl6405.h
+++ b/drivers/media/dvb-frontends/isl6405.h
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c
index 684c8ec166cb..684c8ec166cb 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb-frontends/isl6421.c
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index 47e4518a042d..47e4518a042d 100644
--- a/drivers/media/dvb/frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
diff --git a/drivers/media/dvb/frontends/isl6423.c b/drivers/media/dvb-frontends/isl6423.c
index dca5bebfeeb5..dca5bebfeeb5 100644
--- a/drivers/media/dvb/frontends/isl6423.c
+++ b/drivers/media/dvb-frontends/isl6423.c
diff --git a/drivers/media/dvb/frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h
index e1a37fba01ca..e1a37fba01ca 100644
--- a/drivers/media/dvb/frontends/isl6423.h
+++ b/drivers/media/dvb-frontends/isl6423.h
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb-frontends/it913x-fe-priv.h
index eb6fd8aebdb3..eb6fd8aebdb3 100644
--- a/drivers/media/dvb/frontends/it913x-fe-priv.h
+++ b/drivers/media/dvb-frontends/it913x-fe-priv.h
diff --git a/drivers/media/dvb-frontends/it913x-fe.c b/drivers/media/dvb-frontends/it913x-fe.c
new file mode 100644
index 000000000000..6e1c6eb340b7
--- /dev/null
+++ b/drivers/media/dvb-frontends/it913x-fe.c
@@ -0,0 +1,1045 @@
+/*
+ * Driver for it913x-fe Frontend
+ *
+ * with support for on chip it9137 integral tuner
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9137 Copyright (C) ITE Tech Inc.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "dvb_frontend.h"
+#include "it913x-fe.h"
+#include "it913x-fe-priv.h"
+
+static int it913x_debug;
+
+module_param_named(debug, it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+ if (level & it913x_debug) \
+ printk(KERN_DEBUG "it913x-fe: " args); \
+} while (0)
+
+#define deb_info(args...) dprintk(0x01, args)
+#define debug_data_snipet(level, name, p) \
+ 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;
+ fe_modulation_t constellation;
+ fe_transmit_mode_t transmission_mode;
+ u8 priority;
+ u32 crystalFrequency;
+ u32 adcFrequency;
+ u8 tuner_type;
+ struct adctable *table;
+ fe_status_t it913x_status;
+ u16 tun_xtal;
+ u8 tun_fdiv;
+ u8 tun_clk_mode;
+ u32 tun_fn_min;
+ u32 ucblocks;
+};
+
+static int it913x_read_reg(struct it913x_fe_state *state,
+ u32 reg, u8 *data, u8 count)
+{
+ int ret;
+ u8 pro = PRO_DMOD; /* All reads from demodulator */
+ u8 b[4];
+ struct i2c_msg msg[2] = {
+ { .addr = state->i2c_addr + (pro << 1), .flags = 0,
+ .buf = b, .len = sizeof(b) },
+ { .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
+ .buf = data, .len = count }
+ };
+ b[0] = (u8) reg >> 24;
+ b[1] = (u8)(reg >> 16) & 0xff;
+ b[2] = (u8)(reg >> 8) & 0xff;
+ b[3] = (u8) reg & 0xff;
+
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+ return ret;
+}
+
+static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
+{
+ int ret;
+ u8 b[1];
+ ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
+ return (ret < 0) ? -ENODEV : b[0];
+}
+
+static int it913x_write(struct it913x_fe_state *state,
+ u8 pro, u32 reg, u8 buf[], u8 count)
+{
+ u8 b[256];
+ struct i2c_msg msg[1] = {
+ { .addr = state->i2c_addr + (pro << 1), .flags = 0,
+ .buf = b, .len = count + 4 }
+ };
+ int ret;
+
+ b[0] = (u8) reg >> 24;
+ b[1] = (u8)(reg >> 16) & 0xff;
+ b[2] = (u8)(reg >> 8) & 0xff;
+ b[3] = (u8) reg & 0xff;
+ memcpy(&b[4], buf, count);
+
+ ret = i2c_transfer(state->i2c_adap, msg, 1);
+
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int it913x_write_reg(struct it913x_fe_state *state,
+ u8 pro, u32 reg, u32 data)
+{
+ int ret;
+ u8 b[4];
+ u8 s;
+
+ b[0] = data >> 24;
+ b[1] = (data >> 16) & 0xff;
+ b[2] = (data >> 8) & 0xff;
+ b[3] = data & 0xff;
+ /* expand write as needed */
+ if (data < 0x100)
+ s = 3;
+ else if (data < 0x1000)
+ s = 2;
+ else if (data < 0x100000)
+ s = 1;
+ else
+ s = 0;
+
+ ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
+
+ return ret;
+}
+
+static int it913x_fe_script_loader(struct it913x_fe_state *state,
+ struct it913xset *loadscript)
+{
+ int ret, i;
+ if (loadscript == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < 1000; ++i) {
+ if (loadscript[i].pro == 0xff)
+ break;
+ ret = it913x_write(state, loadscript[i].pro,
+ loadscript[i].address,
+ loadscript[i].reg, loadscript[i].count);
+ if (ret < 0)
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int it913x_init_tuner(struct it913x_fe_state *state)
+{
+ int ret, i, reg;
+ u8 val, nv_val;
+ u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+ u8 b[2];
+
+ reg = it913x_read_reg_u8(state, 0xec86);
+ switch (reg) {
+ case 0:
+ state->tun_clk_mode = reg;
+ state->tun_xtal = 2000;
+ state->tun_fdiv = 3;
+ val = 16;
+ break;
+ case -ENODEV:
+ return -ENODEV;
+ case 1:
+ default:
+ state->tun_clk_mode = reg;
+ state->tun_xtal = 640;
+ state->tun_fdiv = 1;
+ val = 6;
+ break;
+ }
+
+ reg = it913x_read_reg_u8(state, 0xed03);
+
+ if (reg < 0)
+ return -ENODEV;
+ else if (reg < ARRAY_SIZE(nv))
+ nv_val = nv[reg];
+ else
+ nv_val = 2;
+
+ for (i = 0; i < 50; i++) {
+ ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
+ reg = (b[1] << 8) + b[0];
+ if (reg > 0)
+ break;
+ if (ret < 0)
+ return -ENODEV;
+ udelay(2000);
+ }
+ state->tun_fn_min = state->tun_xtal * reg;
+ state->tun_fn_min /= (state->tun_fdiv * nv_val);
+ deb_info("Tuner fn_min %d", state->tun_fn_min);
+
+ 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,
+ u32 bandwidth, u32 frequency_m)
+{
+ struct it913xset *set_tuner = set_it9137_template;
+ int ret, reg;
+ u32 frequency = frequency_m / 1000;
+ u32 freq, temp_f, tmp;
+ u16 iqik_m_cal;
+ u16 n_div;
+ u8 n;
+ u8 l_band;
+ 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) {
+ l_band = 0;
+ lna_band = 0;
+ } else if (frequency > 440000 && frequency <= 484000) {
+ l_band = 1;
+ lna_band = 1;
+ } else if (frequency > 484000 && frequency <= 533000) {
+ l_band = 1;
+ lna_band = 2;
+ } else if (frequency > 533000 && frequency <= 587000) {
+ l_band = 1;
+ lna_band = 3;
+ } else if (frequency > 587000 && frequency <= 645000) {
+ l_band = 1;
+ lna_band = 4;
+ } else if (frequency > 645000 && frequency <= 710000) {
+ l_band = 1;
+ lna_band = 5;
+ } else if (frequency > 710000 && frequency <= 782000) {
+ l_band = 1;
+ lna_band = 6;
+ } else if (frequency > 782000 && frequency <= 860000) {
+ l_band = 1;
+ lna_band = 7;
+ } else if (frequency > 1450000 && frequency <= 1492000) {
+ l_band = 1;
+ lna_band = 0;
+ } else if (frequency > 1660000 && frequency <= 1685000) {
+ l_band = 1;
+ lna_band = 1;
+ } else
+ return -EINVAL;
+ set_tuner[0].reg[0] = lna_band;
+
+ switch (bandwidth) {
+ case 5000000:
+ bw = 0;
+ break;
+ case 6000000:
+ bw = 2;
+ break;
+ case 7000000:
+ bw = 4;
+ break;
+ default:
+ case 8000000:
+ bw = 6;
+ break;
+ }
+
+ set_tuner[1].reg[0] = bw;
+ set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
+
+ if (frequency > 53000 && frequency <= 74000) {
+ n_div = 48;
+ n = 0;
+ } else if (frequency > 74000 && frequency <= 111000) {
+ n_div = 32;
+ n = 1;
+ } else if (frequency > 111000 && frequency <= 148000) {
+ n_div = 24;
+ n = 2;
+ } else if (frequency > 148000 && frequency <= 222000) {
+ n_div = 16;
+ n = 3;
+ } else if (frequency > 222000 && frequency <= 296000) {
+ n_div = 12;
+ n = 4;
+ } else if (frequency > 296000 && frequency <= 445000) {
+ n_div = 8;
+ n = 5;
+ } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
+ n_div = 6;
+ n = 6;
+ } else if (frequency > state->tun_fn_min && frequency <= 950000) {
+ n_div = 4;
+ n = 7;
+ } else if (frequency > 1450000 && frequency <= 1680000) {
+ n_div = 2;
+ n = 0;
+ } else
+ return -EINVAL;
+
+ reg = it913x_read_reg_u8(state, 0xed81);
+ iqik_m_cal = (u16)reg * n_div;
+
+ if (reg < 0x20) {
+ if (state->tun_clk_mode == 0)
+ iqik_m_cal = (iqik_m_cal * 9) >> 5;
+ else
+ iqik_m_cal >>= 1;
+ } else {
+ iqik_m_cal = 0x40 - iqik_m_cal;
+ if (state->tun_clk_mode == 0)
+ iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+ else
+ iqik_m_cal = ~(iqik_m_cal >> 1);
+ }
+
+ temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
+ freq = temp_f / state->tun_xtal;
+ tmp = freq * state->tun_xtal;
+
+ if ((temp_f - tmp) >= (state->tun_xtal >> 1))
+ freq++;
+
+ freq += (u32) n << 13;
+ /* Frequency OMEGA_IQIK_M_CAL_MID*/
+ temp_f = freq + (u32)iqik_m_cal;
+
+ set_tuner[3].reg[0] = temp_f & 0xff;
+ set_tuner[4].reg[0] = (temp_f >> 8) & 0xff;
+
+ deb_info("High Frequency = %04x", temp_f);
+
+ /* Lower frequency */
+ set_tuner[5].reg[0] = freq & 0xff;
+ set_tuner[6].reg[0] = (freq >> 8) & 0xff;
+
+ deb_info("low Frequency = %04x", freq);
+
+ ret = it913x_fe_script_loader(state, set_tuner);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_select_bw(struct it913x_fe_state *state,
+ u32 bandwidth, u32 adcFrequency)
+{
+ int ret, i;
+ u8 buffer[256];
+ u32 coeff[8];
+ u16 bfsfcw_fftinx_ratio;
+ u16 fftinx_bfsfcw_ratio;
+ u8 count;
+ u8 bw;
+ u8 adcmultiplier;
+
+ deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
+
+ switch (bandwidth) {
+ case 5000000:
+ bw = 3;
+ break;
+ case 6000000:
+ bw = 0;
+ break;
+ case 7000000:
+ bw = 1;
+ break;
+ default:
+ case 8000000:
+ bw = 2;
+ break;
+ }
+ ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
+
+ if (state->table == NULL)
+ return -EINVAL;
+
+ /* In write order */
+ coeff[0] = state->table[bw].coeff_1_2048;
+ coeff[1] = state->table[bw].coeff_2_2k;
+ coeff[2] = state->table[bw].coeff_1_8191;
+ coeff[3] = state->table[bw].coeff_1_8192;
+ coeff[4] = state->table[bw].coeff_1_8193;
+ coeff[5] = state->table[bw].coeff_2_8k;
+ coeff[6] = state->table[bw].coeff_1_4096;
+ coeff[7] = state->table[bw].coeff_2_4k;
+ bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
+ fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
+
+ /* ADC multiplier */
+ ret = it913x_read_reg_u8(state, ADC_X_2);
+ if (ret < 0)
+ return -EINVAL;
+
+ adcmultiplier = ret;
+
+ count = 0;
+
+ /* Build Buffer for COEFF Registers */
+ for (i = 0; i < 8; i++) {
+ if (adcmultiplier == 1)
+ coeff[i] /= 2;
+ buffer[count++] = (coeff[i] >> 24) & 0x3;
+ buffer[count++] = (coeff[i] >> 16) & 0xff;
+ buffer[count++] = (coeff[i] >> 8) & 0xff;
+ buffer[count++] = coeff[i] & 0xff;
+ }
+
+ /* bfsfcw_fftinx_ratio register 0x21-0x22 */
+ buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
+ buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
+ /* fftinx_bfsfcw_ratio register 0x23-0x24 */
+ buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
+ buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
+ /* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
+ ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
+
+ for (i = 0; i < 42; i += 8)
+ debug_data_snipet(0x1, "Buffer", &buffer[i]);
+
+ return ret;
+}
+
+
+
+static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ int ret, i;
+ fe_status_t old_status = state->it913x_status;
+ *status = 0;
+
+ if (state->it913x_status == 0) {
+ ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+ if (ret == 0x1) {
+ *status |= FE_HAS_SIGNAL;
+ for (i = 0; i < 40; i++) {
+ ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
+ if (ret == 0x1)
+ break;
+ msleep(25);
+ }
+ if (ret == 0x1)
+ *status |= FE_HAS_CARRIER
+ | FE_HAS_VITERBI
+ | FE_HAS_SYNC;
+ state->it913x_status = *status;
+ }
+ }
+
+ if (state->it913x_status & FE_HAS_SYNC) {
+ ret = it913x_read_reg_u8(state, TPSD_LOCK);
+ if (ret == 0x1)
+ *status |= FE_HAS_LOCK
+ | state->it913x_status;
+ else
+ state->it913x_status = 0;
+ if (old_status != state->it913x_status)
+ ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
+ }
+
+ 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 = 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)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ 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)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ u8 reg[5];
+ /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
+ 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)
+{
+ 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 dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ u8 reg[8];
+
+ it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
+
+ if (reg[3] < 3)
+ p->modulation = fe_con[reg[3]];
+
+ if (reg[0] < 3)
+ p->transmission_mode = fe_mode[reg[0]];
+
+ if (reg[1] < 4)
+ p->guard_interval = fe_gi[reg[1]];
+
+ if (reg[2] < 4)
+ p->hierarchy = fe_hi[reg[2]];
+
+ state->priority = reg[5];
+
+ 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 dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ int i;
+ u8 empty_ch, last_ch;
+
+ state->it913x_status = 0;
+
+ /* Set bw*/
+ it913x_fe_select_bw(state, p->bandwidth_hz,
+ state->adcFrequency);
+
+ /* Training Mode Off */
+ it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
+
+ /* Clear Empty Channel */
+ it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
+
+ /* Clear bits */
+ it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
+ /* LED on */
+ it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+ /* Select Band*/
+ if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
+ i = 0;
+ else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
+ i = 1;
+ else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
+ i = 2;
+ else
+ return -EOPNOTSUPP;
+
+ it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
+
+ deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
+ switch (state->tuner_type) {
+ case IT9135_38:
+ case IT9135_51:
+ case IT9135_52:
+ case IT9135_60:
+ case IT9135_61:
+ case IT9135_62:
+ it9137_set_tuner(state,
+ p->bandwidth_hz, p->frequency);
+ break;
+ default:
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ break;
+ }
+ /* LED off */
+ it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+ /* Trigger ofsm */
+ it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+ last_ch = 2;
+ for (i = 0; i < 40; ++i) {
+ empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
+ if (last_ch == 1 && empty_ch == 1)
+ break;
+ if (last_ch == 2 && empty_ch == 2)
+ return 0;
+ last_ch = empty_ch;
+ msleep(25);
+ }
+ for (i = 0; i < 40; ++i) {
+ if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
+ break;
+ msleep(25);
+ }
+
+ state->frequency = p->frequency;
+ return 0;
+}
+
+static int it913x_fe_suspend(struct it913x_fe_state *state)
+{
+ int ret, i;
+ u8 b;
+
+ ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
+
+ ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+
+ for (i = 0; i < 128; i++) {
+ ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
+ if (ret < 0)
+ return -ENODEV;
+ if (b == 0)
+ break;
+
+ }
+
+ ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
+ /* Turn LED off */
+ ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+
+ ret |= it913x_fe_script_loader(state, it9137_tuner_off);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Power sequence */
+/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */
+/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */
+
+static int it913x_fe_sleep(struct dvb_frontend *fe)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ return it913x_fe_suspend(state);
+}
+
+static u32 compute_div(u32 a, u32 b, u32 x)
+{
+ u32 res = 0;
+ u32 c = 0;
+ u32 i = 0;
+
+ if (a > b) {
+ c = a / b;
+ a = a - c * b;
+ }
+
+ for (i = 0; i < x; i++) {
+ if (a >= b) {
+ res += 1;
+ a -= b;
+ }
+ a <<= 1;
+ res <<= 1;
+ }
+
+ res = (c << x) + res;
+
+ return res;
+}
+
+static int it913x_fe_start(struct it913x_fe_state *state)
+{
+ struct it913xset *set_lna;
+ struct it913xset *set_mode;
+ int ret;
+ u8 adf = (state->config->adf & 0xf);
+ u32 adc, xtal;
+ u8 b[4];
+
+ if (state->config->chip_ver == 1)
+ ret = it913x_init_tuner(state);
+
+ info("ADF table value :%02x", adf);
+
+ if (adf < 10) {
+ state->crystalFrequency = fe_clockTable[adf].xtal ;
+ state->table = fe_clockTable[adf].table;
+ state->adcFrequency = state->table->adcFrequency;
+
+ adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
+ xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
+
+ } else
+ return -EINVAL;
+
+ /* 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);
+ ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+
+ ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
+ ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
+ ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
+
+ b[0] = xtal & 0xff;
+ b[1] = (xtal >> 8) & 0xff;
+ b[2] = (xtal >> 16) & 0xff;
+ b[3] = (xtal >> 24);
+ ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
+
+ b[0] = adc & 0xff;
+ b[1] = (adc >> 8) & 0xff;
+ 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 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:
+ 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;
+
+ /* Always solo frontend */
+ set_mode = set_solo_fe;
+ ret |= it913x_fe_script_loader(state, set_mode);
+
+ ret |= it913x_fe_suspend(state);
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_fe_init(struct dvb_frontend *fe)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ int ret = 0;
+ /* Power Up Tuner - common all versions */
+ ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
+
+ ret |= it913x_fe_script_loader(state, init_1);
+
+ ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
+
+ ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static void it913x_fe_release(struct dvb_frontend *fe)
+{
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops;
+
+struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
+ 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->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)
+ goto error;
+
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(it913x_fe_attach);
+
+static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
+ .delsys = { SYS_DVBT },
+ .info = {
+ .name = "it913x-fe DVB-T",
+ .frequency_min = 51000000,
+ .frequency_max = 1680000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | 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,
+ },
+
+ .release = it913x_fe_release,
+
+ .init = it913x_fe_init,
+ .sleep = it913x_fe_sleep,
+
+ .set_frontend = it913x_fe_set_frontend,
+ .get_frontend = it913x_fe_get_frontend,
+
+ .read_status = it913x_fe_read_status,
+ .read_signal_strength = it913x_fe_read_signal_strength,
+ .read_snr = it913x_fe_read_snr,
+ .read_ber = it913x_fe_read_ber,
+ .read_ucblocks = it913x_fe_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+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 07fa4594c12b..07fa4594c12b 100644
--- a/drivers/media/dvb/frontends/it913x-fe.h
+++ b/drivers/media/dvb-frontends/it913x-fe.h
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c
index 316457584fe7..316457584fe7 100644
--- a/drivers/media/dvb/frontends/itd1000.c
+++ b/drivers/media/dvb-frontends/itd1000.c
diff --git a/drivers/media/dvb/frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h
index 5e18df071b88..5e18df071b88 100644
--- a/drivers/media/dvb/frontends/itd1000.h
+++ b/drivers/media/dvb-frontends/itd1000.h
diff --git a/drivers/media/dvb/frontends/itd1000_priv.h b/drivers/media/dvb-frontends/itd1000_priv.h
index 08ca851223c9..08ca851223c9 100644
--- a/drivers/media/dvb/frontends/itd1000_priv.h
+++ b/drivers/media/dvb-frontends/itd1000_priv.h
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c
index bc5a82082aaa..bc5a82082aaa 100644
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ b/drivers/media/dvb-frontends/ix2505v.c
diff --git a/drivers/media/dvb/frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h
index 67e89d616d50..67e89d616d50 100644
--- a/drivers/media/dvb/frontends/ix2505v.h
+++ b/drivers/media/dvb-frontends/ix2505v.h
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c
index 36fcf559e361..36fcf559e361 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb-frontends/l64781.c
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h
index 1305a9e7fb0b..1305a9e7fb0b 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb-frontends/l64781.h
diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c
index cc11260e99df..cc11260e99df 100644
--- a/drivers/media/dvb/frontends/lg2160.c
+++ b/drivers/media/dvb-frontends/lg2160.c
diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h
index 9e2c0f41199a..9e2c0f41199a 100644
--- a/drivers/media/dvb/frontends/lg2160.h
+++ b/drivers/media/dvb-frontends/lg2160.h
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c
index 1d2c47378cf8..1d2c47378cf8 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb-frontends/lgdt3305.c
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h
index 02172eca4d47..02172eca4d47 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb-frontends/lgdt3305.h
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index e046622df0e4..e046622df0e4 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
index 9012504f0f2d..9012504f0f2d 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb-frontends/lgdt330x.h
diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb-frontends/lgdt330x_priv.h
index 38c76695abfe..38c76695abfe 100644
--- a/drivers/media/dvb/frontends/lgdt330x_priv.h
+++ b/drivers/media/dvb-frontends/lgdt330x_priv.h
diff --git a/drivers/media/dvb-frontends/lgs8gl5.c b/drivers/media/dvb-frontends/lgs8gl5.c
new file mode 100644
index 000000000000..416cce3fefc7
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gl5.c
@@ -0,0 +1,453 @@
+/*
+ Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+ Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ Timothy Lee <timothy.lee@siriushk.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET 0x02
+#define REG_RESET_OFF 0x01
+#define REG_03 0x03
+#define REG_04 0x04
+#define REG_07 0x07
+#define REG_09 0x09
+#define REG_0A 0x0a
+#define REG_0B 0x0b
+#define REG_0C 0x0c
+#define REG_37 0x37
+#define REG_STRENGTH 0x4b
+#define REG_STRENGTH_MASK 0x7f
+#define REG_STRENGTH_CARRIER 0x80
+#define REG_INVERSION 0x7c
+#define REG_INVERSION_ON 0x80
+#define REG_7D 0x7d
+#define REG_7E 0x7e
+#define REG_A2 0xa2
+#define REG_STATUS 0xa4
+#define REG_STATUS_SYNC 0x04
+#define REG_STATUS_LOCK 0x01
+
+
+struct lgs8gl5_state {
+ struct i2c_adapter *i2c;
+ const struct lgs8gl5_config *config;
+ struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "lgs8gl5: " args); \
+ } while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = {reg, data};
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1)
+ dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
+ __func__, reg, data, ret);
+ return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
+{
+ int ret;
+ u8 b0[] = {reg};
+ u8 b1[] = {0};
+ struct i2c_msg msg[2] = {
+ {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ },
+ {
+ .addr = state->config->demod_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret != 2)
+ return -EIO;
+
+ return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+ lgs8gl5_read_reg(state, reg);
+ lgs8gl5_write_reg(state, reg, data);
+ return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO: Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+ int ret;
+ u8 b0[] = {reg};
+ u8 b1[] = {0};
+ u8 b2[] = {reg, data};
+ struct i2c_msg msg[3] = {
+ {
+ .addr = state->config->demod_address + 2,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ },
+ {
+ .addr = state->config->demod_address + 2,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ },
+ {
+ .addr = state->config->demod_address + 2,
+ .flags = 0,
+ .buf = b2,
+ .len = 2
+ },
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 3);
+ return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state *state)
+{
+ u8 val;
+
+ dprintk("%s\n", __func__);
+
+ val = lgs8gl5_read_reg(state, REG_RESET);
+ lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+ lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+ msleep(5);
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state *state)
+{
+ u8 val;
+ int n;
+
+ dprintk("%s\n", __func__);
+
+ lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+ lgs8gl5_soft_reset(state);
+ lgs8gl5_update_reg(state, REG_07, 0x10);
+ lgs8gl5_update_reg(state, REG_07, 0x10);
+ lgs8gl5_write_reg(state, REG_09, 0x0e);
+ lgs8gl5_write_reg(state, REG_0A, 0xe5);
+ lgs8gl5_write_reg(state, REG_0B, 0x35);
+ lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+ lgs8gl5_update_reg(state, REG_03, 0x00);
+ lgs8gl5_update_reg(state, REG_7E, 0x01);
+ lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+ lgs8gl5_update_reg(state, REG_04, 0x02);
+ lgs8gl5_update_reg(state, REG_37, 0x01);
+ lgs8gl5_soft_reset(state);
+
+ /* Wait for carrier */
+ for (n = 0; n < 10; n++) {
+ val = lgs8gl5_read_reg(state, REG_STRENGTH);
+ dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+ if (val & REG_STRENGTH_CARRIER)
+ break;
+ msleep(4);
+ }
+ if (!(val & REG_STRENGTH_CARRIER))
+ return;
+
+ /* Wait for lock */
+ for (n = 0; n < 20; n++) {
+ val = lgs8gl5_read_reg(state, REG_STATUS);
+ dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+ if (val & REG_STATUS_LOCK)
+ break;
+ msleep(12);
+ }
+ if (!(val & REG_STATUS_LOCK))
+ return;
+
+ lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+ lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend *fe)
+{
+ struct lgs8gl5_state *state = fe->demodulator_priv;
+
+ dprintk("%s\n", __func__);
+
+ lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+ lgs8gl5_soft_reset(state);
+ lgs8gl5_update_reg(state, REG_07, 0x10);
+ lgs8gl5_update_reg(state, REG_07, 0x10);
+ lgs8gl5_write_reg(state, REG_09, 0x0e);
+ lgs8gl5_write_reg(state, REG_0A, 0xe5);
+ lgs8gl5_write_reg(state, REG_0B, 0x35);
+ lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+ return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct lgs8gl5_state *state = fe->demodulator_priv;
+ u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+ u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+ *status = 0;
+
+ if ((level & REG_STRENGTH_MASK) > 0)
+ *status |= FE_HAS_SIGNAL;
+ if (level & REG_STRENGTH_CARRIER)
+ *status |= FE_HAS_CARRIER;
+ if (flags & REG_STATUS_SYNC)
+ *status |= FE_HAS_SYNC;
+ if (flags & REG_STATUS_LOCK)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ *ber = 0;
+
+ return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+ struct lgs8gl5_state *state = fe->demodulator_priv;
+ u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+ *signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+ return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lgs8gl5_state *state = fe->demodulator_priv;
+ u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+ *snr = (level & REG_STRENGTH_MASK) << 8;
+
+ return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+
+ return 0;
+}
+
+
+static int
+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->bandwidth_hz != 8000000)
+ return -EINVAL;
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* lgs8gl5_set_inversion(state, p->inversion); */
+
+ lgs8gl5_start_demod(state);
+
+ return 0;
+}
+
+
+static int
+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);
+
+ p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+ 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;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ fesettings->min_delay_ms = 240;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend *fe)
+{
+ struct lgs8gl5_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
+{
+ struct lgs8gl5_state *state = NULL;
+
+ dprintk("%s\n", __func__);
+
+ /* Allocate memory for the internal state */
+ state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* Setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* Check if the demod is there */
+ if (lgs8gl5_read_reg(state, REG_RESET) < 0)
+ goto error;
+
+ /* Create dvb_frontend */
+ memcpy(&state->frontend.ops, &lgs8gl5_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(lgs8gl5_attach);
+
+
+static struct dvb_frontend_ops lgs8gl5_ops = {
+ .delsys = { SYS_DTMB },
+ .info = {
+ .name = "Legend Silicon LGS-8GL5 DMB-TH",
+ .frequency_min = 474000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 10000,
+ .frequency_tolerance = 0,
+ .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 = lgs8gl5_release,
+
+ .init = lgs8gl5_init,
+
+ .set_frontend = lgs8gl5_set_frontend,
+ .get_frontend = lgs8gl5_get_frontend,
+ .get_tune_settings = lgs8gl5_get_tune_settings,
+
+ .read_status = lgs8gl5_read_status,
+ .read_ber = lgs8gl5_read_ber,
+ .read_signal_strength = lgs8gl5_read_signal_strength,
+ .read_snr = lgs8gl5_read_snr,
+ .read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h
index d14176787a7d..d14176787a7d 100644
--- a/drivers/media/dvb/frontends/lgs8gl5.h
+++ b/drivers/media/dvb-frontends/lgs8gl5.h
diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c
new file mode 100644
index 000000000000..3c92f36ea5c7
--- /dev/null
+++ b/drivers/media/dvb-frontends/lgs8gxx.c
@@ -0,0 +1,1075 @@
+/*
+ * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ * LGS8913, LGS8GL5, LGS8G75
+ * experimental support LGS8G42, LGS8G52
+ *
+ * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
+ * Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
+ *
+ * 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 <asm/div64.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+
+#include "lgs8gxx.h"
+#include "lgs8gxx_priv.h"
+
+#define dprintk(args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "lgs8gxx: " args); \
+ } while (0)
+
+static int debug;
+static int fake_signal_str = 1;
+
+#define LGS8GXX_FIRMWARE "lgs8g75.fw"
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+module_param(fake_signal_str, int, 0644);
+MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
+"Signal strength calculation is slow.(default:on).");
+
+/* LGS8GXX internal helper functions */
+
+static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
+
+ msg.addr = priv->config->demod_address;
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
+ msg.addr += 0x02;
+
+ if (debug >= 2)
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
+
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ __func__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
+{
+ int ret;
+ u8 dev_addr;
+
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {
+ { .flags = 0, .buf = b0, .len = 1 },
+ { .flags = I2C_M_RD, .buf = b1, .len = 1 },
+ };
+
+ dev_addr = priv->config->demod_address;
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
+ dev_addr += 0x02;
+ msg[1].addr = msg[0].addr = dev_addr;
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret != 2) {
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
+ return -1;
+ }
+
+ *p_data = b1[0];
+ if (debug >= 2)
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
+ return 0;
+}
+
+static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
+{
+ lgs8gxx_write_reg(priv, 0x02, 0x00);
+ msleep(1);
+ lgs8gxx_write_reg(priv, 0x02, 0x01);
+ msleep(100);
+
+ return 0;
+}
+
+static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
+ u8 val, u8 delay, u8 tries)
+{
+ u8 t;
+ int i;
+
+ for (i = 0; i < tries; i++) {
+ lgs8gxx_read_reg(priv, reg, &t);
+
+ if ((t & mask) == val)
+ return 0;
+ msleep(delay);
+ }
+
+ return 1;
+}
+
+static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
+{
+ const struct lgs8gxx_config *config = priv->config;
+ u8 if_conf;
+
+ if_conf = 0x10; /* AGC output on, RF_AGC output off; */
+
+ if_conf |=
+ ((config->ext_adc) ? 0x80 : 0x00) |
+ ((config->if_neg_center) ? 0x04 : 0x00) |
+ ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
+ ((config->adc_signed) ? 0x02 : 0x00) |
+ ((config->if_neg_edge) ? 0x01 : 0x00);
+
+ if (config->ext_adc &&
+ (config->prod == LGS8GXX_PROD_LGS8G52)) {
+ lgs8gxx_write_reg(priv, 0xBA, 0x40);
+ }
+
+ lgs8gxx_write_reg(priv, 0x07, if_conf);
+
+ return 0;
+}
+
+static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
+{
+ u64 val;
+ u32 v32;
+ u32 if_clk;
+
+ if_clk = priv->config->if_clk_freq;
+
+ val = freq;
+ if (freq != 0) {
+ val <<= 32;
+ if (if_clk != 0)
+ do_div(val, if_clk);
+ v32 = val & 0xFFFFFFFF;
+ dprintk("Set IF Freq to %dkHz\n", freq);
+ } else {
+ v32 = 0;
+ dprintk("Set IF Freq to baseband\n");
+ }
+ dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
+ lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
+ lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
+ lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
+ } else {
+ lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
+ lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
+ lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
+ lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+ }
+
+ return 0;
+}
+
+static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
+{
+ u64 val;
+ u32 v32 = 0;
+ u8 reg_addr, t;
+ int i;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ reg_addr = 0x23;
+ else
+ reg_addr = 0x48;
+
+ for (i = 0; i < 4; i++) {
+ lgs8gxx_read_reg(priv, reg_addr, &t);
+ v32 <<= 8;
+ v32 |= t;
+ reg_addr--;
+ }
+
+ val = v32;
+ val *= priv->config->if_clk_freq;
+ val >>= 32;
+ dprintk("AFC = %u kHz\n", (u32)val);
+ return 0;
+}
+
+static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
+{
+ u8 t;
+ u8 prod = priv->config->prod;
+
+ if (prod == LGS8GXX_PROD_LGS8913)
+ lgs8gxx_write_reg(priv, 0xC6, 0x01);
+
+ if (prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ t &= (~0x04);
+ lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ } else if (prod == LGS8GXX_PROD_LGS8913 ||
+ prod == LGS8GXX_PROD_LGS8GL5 ||
+ prod == LGS8GXX_PROD_LGS8G42 ||
+ prod == LGS8GXX_PROD_LGS8G52 ||
+ prod == LGS8GXX_PROD_LGS8G54) {
+ lgs8gxx_read_reg(priv, 0x7E, &t);
+ lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
+
+ /* clear FEC self reset */
+ lgs8gxx_read_reg(priv, 0xC5, &t);
+ lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+ }
+
+ if (prod == LGS8GXX_PROD_LGS8913) {
+ /* FEC auto detect */
+ lgs8gxx_write_reg(priv, 0xC1, 0x03);
+
+ lgs8gxx_read_reg(priv, 0x7C, &t);
+ t = (t & 0x8C) | 0x03;
+ lgs8gxx_write_reg(priv, 0x7C, t);
+
+ /* BER test mode */
+ lgs8gxx_read_reg(priv, 0xC3, &t);
+ t = (t & 0xEF) | 0x10;
+ lgs8gxx_write_reg(priv, 0xC3, t);
+ }
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G52)
+ lgs8gxx_write_reg(priv, 0xD9, 0x40);
+
+ return 0;
+}
+
+static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
+{
+ u8 t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ u8 t2;
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ t &= (~0x80);
+ lgs8gxx_write_reg(priv, 0x0C, t);
+
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ lgs8gxx_read_reg(priv, 0x19, &t2);
+
+ if (((t&0x03) == 0x01) && (t2&0x01)) {
+ lgs8gxx_write_reg(priv, 0x6E, 0x05);
+ lgs8gxx_write_reg(priv, 0x39, 0x02);
+ lgs8gxx_write_reg(priv, 0x39, 0x03);
+ lgs8gxx_write_reg(priv, 0x3D, 0x05);
+ lgs8gxx_write_reg(priv, 0x3E, 0x28);
+ lgs8gxx_write_reg(priv, 0x53, 0x80);
+ } else {
+ lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ }
+
+ lgs8gxx_soft_reset(priv);
+ return 0;
+ }
+
+ /* turn off auto-detect; manual settings */
+ lgs8gxx_write_reg(priv, 0x7E, 0);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+ lgs8gxx_write_reg(priv, 0xC1, 0);
+
+ lgs8gxx_read_reg(priv, 0xC5, &t);
+ t = (t & 0xE0) | 0x06;
+ lgs8gxx_write_reg(priv, 0xC5, t);
+
+ lgs8gxx_soft_reset(priv);
+
+ return 0;
+}
+
+static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
+{
+ int ret = 0;
+ u8 t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ ret = lgs8gxx_read_reg(priv, 0x13, &t);
+ else
+ ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+ if (ret != 0)
+ return ret;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ *locked = ((t & 0x80) == 0x80) ? 1 : 0;
+ else
+ *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+ return 0;
+}
+
+/* Wait for Code Acquisition Lock */
+static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
+{
+ int ret = 0;
+ u8 reg, mask, val;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg = 0x13;
+ mask = 0x80;
+ val = 0x80;
+ } else {
+ reg = 0x4B;
+ mask = 0xC0;
+ val = 0xC0;
+ }
+
+ ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
+ *locked = (ret == 0) ? 1 : 0;
+
+ return 0;
+}
+
+static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
+ u8 *finished)
+{
+ int ret = 0;
+ u8 reg, mask, val;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg = 0x1f;
+ mask = 0xC0;
+ val = 0x80;
+ } else {
+ reg = 0xA4;
+ mask = 0x03;
+ val = 0x01;
+ }
+
+ ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
+ *finished = (ret == 0) ? 1 : 0;
+
+ return 0;
+}
+
+static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
+ u8 *locked)
+{
+ int err = 0;
+ u8 ad_fini = 0;
+ u8 t1, t2;
+
+ if (gi == GI_945)
+ dprintk("try GI 945\n");
+ else if (gi == GI_595)
+ dprintk("try GI 595\n");
+ else if (gi == GI_420)
+ dprintk("try GI 420\n");
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x0C, &t1);
+ lgs8gxx_read_reg(priv, 0x18, &t2);
+ t1 &= ~(GI_MASK);
+ t1 |= gi;
+ t2 &= 0xFE;
+ t2 |= cpn ? 0x01 : 0x00;
+ lgs8gxx_write_reg(priv, 0x0C, t1);
+ lgs8gxx_write_reg(priv, 0x18, t2);
+ } else {
+ lgs8gxx_write_reg(priv, 0x04, gi);
+ }
+ lgs8gxx_soft_reset(priv);
+ err = lgs8gxx_wait_ca_lock(priv, locked);
+ if (err || !(*locked))
+ return err;
+ err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
+ if (err != 0)
+ return err;
+ if (ad_fini) {
+ dprintk("auto detect finished\n");
+ } else
+ *locked = 0;
+
+ return 0;
+}
+
+static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
+ u8 *detected_param, u8 *gi)
+{
+ int i, j;
+ int err = 0;
+ u8 locked = 0, tmp_gi;
+
+ dprintk("%s\n", __func__);
+
+ lgs8gxx_set_mode_auto(priv);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_write_reg(priv, 0x67, 0xAA);
+ lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+ } else {
+ /* Guard Interval */
+ lgs8gxx_write_reg(priv, 0x03, 00);
+ }
+
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ tmp_gi = GI_945;
+ err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
+ if (err)
+ goto out;
+ if (locked)
+ goto locked;
+ }
+ for (j = 0; j < 2; j++) {
+ tmp_gi = GI_420;
+ err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
+ if (err)
+ goto out;
+ if (locked)
+ goto locked;
+ }
+ tmp_gi = GI_595;
+ err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
+ if (err)
+ goto out;
+ if (locked)
+ goto locked;
+ }
+
+locked:
+ if ((err == 0) && (locked == 1)) {
+ u8 t;
+
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0xA2, &t);
+ *detected_param = t;
+ } else {
+ lgs8gxx_read_reg(priv, 0x1F, &t);
+ *detected_param = t & 0x3F;
+ }
+
+ if (tmp_gi == GI_945)
+ dprintk("GI 945 locked\n");
+ else if (tmp_gi == GI_595)
+ dprintk("GI 595 locked\n");
+ else if (tmp_gi == GI_420)
+ dprintk("GI 420 locked\n");
+ *gi = tmp_gi;
+ }
+ if (!locked)
+ err = -1;
+
+out:
+ return err;
+}
+
+static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
+{
+ s8 err;
+ u8 gi = 0x2;
+ u8 detected_param = 0;
+
+ err = lgs8gxx_auto_detect(priv, &detected_param, &gi);
+
+ if (err != 0) {
+ dprintk("lgs8gxx_auto_detect failed\n");
+ } else
+ dprintk("detected param = 0x%02X\n", detected_param);
+
+ /* Apply detected parameters */
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+ u8 inter_leave_len = detected_param & TIM_MASK ;
+ /* Fix 8913 time interleaver detection bug */
+ inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
+ detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
+ detected_param |= inter_leave_len;
+ }
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ u8 t;
+ lgs8gxx_read_reg(priv, 0x19, &t);
+ t &= 0x81;
+ t |= detected_param << 1;
+ lgs8gxx_write_reg(priv, 0x19, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0x7D, detected_param);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+ lgs8gxx_write_reg(priv, 0xC0, detected_param);
+ }
+ /* lgs8gxx_soft_reset(priv); */
+
+ /* Enter manual mode */
+ lgs8gxx_set_mode_manual(priv);
+
+ switch (gi) {
+ case GI_945:
+ priv->curr_gi = 945; break;
+ case GI_595:
+ priv->curr_gi = 595; break;
+ case GI_420:
+ priv->curr_gi = 420; break;
+ default:
+ priv->curr_gi = 945; break;
+ }
+}
+
+static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
+ u8 serial, u8 clk_pol, u8 clk_gated)
+{
+ int ret = 0;
+ u8 t, reg_addr;
+
+ reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
+ ret = lgs8gxx_read_reg(priv, reg_addr, &t);
+ if (ret != 0)
+ return ret;
+
+ t &= 0xF8;
+ t |= serial ? TS_SERIAL : TS_PARALLEL;
+ t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
+ t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
+
+ ret = lgs8gxx_write_reg(priv, reg_addr, t);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+/* A/D input peak-to-peak voltage range */
+static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
+ u8 sel)
+{
+ u8 r26 = 0x73, r27 = 0x90;
+
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
+ return 0;
+
+ r26 |= (sel & 0x01) << 7;
+ r27 |= (sel & 0x02) >> 1;
+ lgs8gxx_write_reg(priv, 0x26, r26);
+ lgs8gxx_write_reg(priv, 0x27, r27);
+
+ return 0;
+}
+
+/* LGS8913 demod frontend functions */
+
+static int lgs8913_init(struct lgs8gxx_state *priv)
+{
+ u8 t;
+
+ /* LGS8913 specific */
+ lgs8gxx_write_reg(priv, 0xc1, 0x3);
+
+ lgs8gxx_read_reg(priv, 0x7c, &t);
+ lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);
+
+ /* LGS8913 specific */
+ lgs8gxx_read_reg(priv, 0xc3, &t);
+ lgs8gxx_write_reg(priv, 0xc3, t&0x10);
+
+
+ return 0;
+}
+
+static int lgs8g75_init_data(struct lgs8gxx_state *priv)
+{
+ const struct firmware *fw;
+ int rc;
+ int i;
+
+ rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev);
+ if (rc)
+ return rc;
+
+ lgs8gxx_write_reg(priv, 0xC6, 0x40);
+
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+
+ lgs8gxx_write_reg(priv, 0x3A, 0x00);
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+ lgs8gxx_write_reg(priv, 0x3B, 0x00);
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+ for (i = 0; i < fw->size; i++) {
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+ lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
+ lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
+ lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
+ }
+
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+ release_firmware(fw);
+ return 0;
+}
+
+static int lgs8gxx_init(struct dvb_frontend *fe)
+{
+ struct lgs8gxx_state *priv =
+ (struct lgs8gxx_state *)fe->demodulator_priv;
+ const struct lgs8gxx_config *config = priv->config;
+ u8 data = 0;
+ s8 err;
+ dprintk("%s\n", __func__);
+
+ lgs8gxx_read_reg(priv, 0, &data);
+ dprintk("reg 0 = 0x%02X\n", data);
+
+ if (config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8g75_set_adc_vpp(priv, config->adc_vpp);
+
+ /* Setup MPEG output format */
+ err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
+ config->ts_clk_pol,
+ config->ts_clk_gated);
+ if (err != 0)
+ return -EIO;
+
+ if (config->prod == LGS8GXX_PROD_LGS8913)
+ lgs8913_init(priv);
+ lgs8gxx_set_if_freq(priv, priv->config->if_freq);
+ lgs8gxx_set_ad_mode(priv);
+
+ return 0;
+}
+
+static void lgs8gxx_release(struct dvb_frontend *fe)
+{
+ struct lgs8gxx_state *state = fe->demodulator_priv;
+ dprintk("%s\n", __func__);
+
+ kfree(state);
+}
+
+
+static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+ if (len != 2)
+ return -EINVAL;
+
+ return lgs8gxx_write_reg(priv, buf[0], buf[1]);
+}
+
+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);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* start auto lock */
+ lgs8gxx_auto_lock(priv);
+
+ msleep(10);
+
+ return 0;
+}
+
+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 */
+ /* inversion status */
+ fe_params->inversion = INVERSION_OFF;
+
+ /* bandwidth */
+ fe_params->bandwidth_hz = 8000000;
+
+ fe_params->code_rate_HP = FEC_AUTO;
+ fe_params->code_rate_LP = FEC_AUTO;
+
+ fe_params->modulation = QAM_AUTO;
+
+ /* transmission mode */
+ fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
+
+ /* guard interval */
+ fe_params->guard_interval = GUARD_INTERVAL_AUTO;
+
+ /* hierarchy */
+ fe_params->hierarchy = HIERARCHY_NONE;
+
+ return 0;
+}
+
+static
+int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ /* FIXME: copy from tda1004x.c */
+ fesettings->min_delay_ms = 800;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+ s8 ret;
+ u8 t, locked = 0;
+
+ dprintk("%s\n", __func__);
+ *fe_status = 0;
+
+ lgs8gxx_get_afc_phase(priv);
+ lgs8gxx_is_locked(priv, &locked);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ if (locked)
+ *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ return 0;
+ }
+
+ ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+ if (ret != 0)
+ return -EIO;
+
+ dprintk("Reg 0x4B: 0x%02X\n", t);
+
+ *fe_status = 0;
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+ if ((t & 0x40) == 0x40)
+ *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ if ((t & 0x80) == 0x80)
+ *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ } else {
+ if ((t & 0x80) == 0x80)
+ *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ }
+
+ /* success */
+ dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+ return 0;
+}
+
+static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
+{
+ u16 v;
+ u8 agc_lvl[2], cat;
+
+ dprintk("%s()\n", __func__);
+ lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);
+ lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);
+
+ v = agc_lvl[0];
+ v <<= 8;
+ v |= agc_lvl[1];
+
+ dprintk("agc_lvl: 0x%04X\n", v);
+
+ if (v < 0x100)
+ cat = 0;
+ else if (v < 0x190)
+ cat = 5;
+ else if (v < 0x2A8)
+ cat = 4;
+ else if (v < 0x381)
+ cat = 3;
+ else if (v < 0x400)
+ cat = 2;
+ else if (v == 0x400)
+ cat = 1;
+ else
+ cat = 0;
+
+ *signal = cat * 65535 / 5;
+
+ return 0;
+}
+
+static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+ u8 t; s8 ret;
+ s16 max_strength = 0;
+ u8 str;
+ u16 i, gi = priv->curr_gi;
+
+ dprintk("%s\n", __func__);
+
+ ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+ if (ret != 0)
+ return -EIO;
+
+ if (fake_signal_str) {
+ if ((t & 0xC0) == 0xC0) {
+ dprintk("Fake signal strength\n");
+ *signal = 0x7FFF;
+ } else
+ *signal = 0;
+ return 0;
+ }
+
+ dprintk("gi = %d\n", gi);
+ for (i = 0; i < gi; i++) {
+
+ if ((i & 0xFF) == 0)
+ lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));
+ lgs8gxx_write_reg(priv, 0x83, i & 0xFF);
+
+ lgs8gxx_read_reg(priv, 0x94, &str);
+ if (max_strength < str)
+ max_strength = str;
+ }
+
+ *signal = max_strength;
+ dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+ lgs8gxx_read_reg(priv, 0x95, &t);
+ dprintk("%s: AVG Noise=0x%02X\n", __func__, t);
+
+ return 0;
+}
+
+static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+ u8 t;
+ s16 v = 0;
+
+ dprintk("%s\n", __func__);
+
+ lgs8gxx_read_reg(priv, 0xB1, &t);
+ v |= t;
+ v <<= 8;
+ lgs8gxx_read_reg(priv, 0xB0, &t);
+ v |= t;
+
+ *signal = v;
+ dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+ return 0;
+}
+
+static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+ return lgs8913_read_signal_strength(priv, signal);
+ else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ return lgs8g75_read_signal_strength(priv, signal);
+ else
+ return lgs8gxx_read_signal_agc(priv, signal);
+}
+
+static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+ u8 t;
+ *snr = 0;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8gxx_read_reg(priv, 0x34, &t);
+ else
+ lgs8gxx_read_reg(priv, 0x95, &t);
+ dprintk("AVG Noise=0x%02X\n", t);
+ *snr = 256 - t;
+ *snr <<= 8;
+ dprintk("snr=0x%x\n", *snr);
+
+ return 0;
+}
+
+static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
+ return 0;
+}
+
+static void packet_counter_start(struct lgs8gxx_state *priv)
+{
+ u8 orig, t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x30, &orig);
+ orig &= 0xE7;
+ t = orig | 0x10;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ t = orig | 0x18;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ t = orig | 0x10;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0xC6, 0x01);
+ lgs8gxx_write_reg(priv, 0xC6, 0x41);
+ lgs8gxx_write_reg(priv, 0xC6, 0x01);
+ }
+}
+
+static void packet_counter_stop(struct lgs8gxx_state *priv)
+{
+ u8 t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x30, &t);
+ t &= 0xE7;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0xC6, 0x81);
+ }
+}
+
+static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+ u8 reg_err, reg_total, t;
+ u32 total_cnt = 0, err_cnt = 0;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ packet_counter_start(priv);
+ msleep(200);
+ packet_counter_stop(priv);
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg_total = 0x28; reg_err = 0x2C;
+ } else {
+ reg_total = 0xD0; reg_err = 0xD4;
+ }
+
+ for (i = 0; i < 4; i++) {
+ total_cnt <<= 8;
+ lgs8gxx_read_reg(priv, reg_total+3-i, &t);
+ total_cnt |= t;
+ }
+ for (i = 0; i < 4; i++) {
+ err_cnt <<= 8;
+ lgs8gxx_read_reg(priv, reg_err+3-i, &t);
+ err_cnt |= t;
+ }
+ dprintk("error=%d total=%d\n", err_cnt, total_cnt);
+
+ if (total_cnt == 0)
+ *ber = 0;
+ else
+ *ber = err_cnt * 100 / total_cnt;
+
+ dprintk("%s: ber=0x%x\n", __func__, *ber);
+ return 0;
+}
+
+static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct lgs8gxx_state *priv = fe->demodulator_priv;
+
+ if (priv->config->tuner_address == 0)
+ return 0;
+ if (enable) {
+ u8 v = 0x80 | priv->config->tuner_address;
+ return lgs8gxx_write_reg(priv, 0x01, v);
+ }
+ return lgs8gxx_write_reg(priv, 0x01, 0);
+}
+
+static struct dvb_frontend_ops lgs8gxx_ops = {
+ .delsys = { SYS_DTMB },
+ .info = {
+ .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
+ .frequency_min = 474000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 10000,
+ .caps =
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO
+ },
+
+ .release = lgs8gxx_release,
+
+ .init = lgs8gxx_init,
+ .write = lgs8gxx_write,
+ .i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
+
+ .set_frontend = lgs8gxx_set_fe,
+ .get_frontend = lgs8gxx_get_fe,
+ .get_tune_settings = lgs8gxx_get_tune_settings,
+
+ .read_status = lgs8gxx_read_status,
+ .read_ber = lgs8gxx_read_ber,
+ .read_signal_strength = lgs8gxx_read_signal_strength,
+ .read_snr = lgs8gxx_read_snr,
+ .read_ucblocks = lgs8gxx_read_ucblocks,
+};
+
+struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct lgs8gxx_state *priv = NULL;
+ u8 data = 0;
+
+ dprintk("%s()\n", __func__);
+
+ if (config == NULL || i2c == NULL)
+ return NULL;
+
+ priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);
+ if (priv == NULL)
+ goto error_out;
+
+ priv->config = config;
+ priv->i2c = i2c;
+
+ /* check if the demod is there */
+ if (lgs8gxx_read_reg(priv, 0, &data) != 0) {
+ dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",
+ __func__, priv->config->demod_address);
+ goto error_out;
+ }
+
+ lgs8gxx_read_reg(priv, 1, &data);
+
+ memcpy(&priv->frontend.ops, &lgs8gxx_ops,
+ sizeof(struct dvb_frontend_ops));
+ priv->frontend.demodulator_priv = priv;
+
+ if (config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8g75_init_data(priv);
+
+ return &priv->frontend;
+
+error_out:
+ dprintk("%s() error_out\n", __func__);
+ kfree(priv);
+ return NULL;
+
+}
+EXPORT_SYMBOL(lgs8gxx_attach);
+
+MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(LGS8GXX_FIRMWARE);
diff --git a/drivers/media/dvb/frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h
index 33c3c5e162fa..33c3c5e162fa 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.h
+++ b/drivers/media/dvb-frontends/lgs8gxx.h
diff --git a/drivers/media/dvb/frontends/lgs8gxx_priv.h b/drivers/media/dvb-frontends/lgs8gxx_priv.h
index 8ef376f1414d..8ef376f1414d 100644
--- a/drivers/media/dvb/frontends/lgs8gxx_priv.h
+++ b/drivers/media/dvb-frontends/lgs8gxx_priv.h
diff --git a/drivers/media/dvb/frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h
index c059b165318f..c059b165318f 100644
--- a/drivers/media/dvb/frontends/lnbh24.h
+++ b/drivers/media/dvb-frontends/lnbh24.h
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c
index 13437259eeac..13437259eeac 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb-frontends/lnbp21.c
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h
index fcdf1c650dde..fcdf1c650dde 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb-frontends/lnbp21.h
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c
index 84ad0390a4a1..84ad0390a4a1 100644
--- a/drivers/media/dvb/frontends/lnbp22.c
+++ b/drivers/media/dvb-frontends/lnbp22.c
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h
index 63e2dec7e68a..63e2dec7e68a 100644
--- a/drivers/media/dvb/frontends/lnbp22.h
+++ b/drivers/media/dvb-frontends/lnbp22.h
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
new file mode 100644
index 000000000000..633815ed90ca
--- /dev/null
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -0,0 +1,919 @@
+/*
+ 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)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 data;
+
+ data = m88rs2000_demod_read(state, 0xb2);
+ data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+ switch (volt) {
+ case SEC_VOLTAGE_18:
+ data &= ~0x03;
+ break;
+ case SEC_VOLTAGE_13:
+ data &= ~0x03;
+ data |= 0x01;
+ break;
+ case SEC_VOLTAGE_OFF:
+ break;
+ }
+
+ m88rs2000_demod_write(state, 0xb2, data);
+
+ 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_SYNC | 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)
+{
+ 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;
+ }
+ 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++) {
+ 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
index 59acdb696873..59acdb696873 100644
--- a/drivers/media/dvb/frontends/m88rs2000.h
+++ b/drivers/media/dvb-frontends/m88rs2000.h
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 9ae40abfd71a..9ae40abfd71a 100644
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h
index 6ea8c376394f..6ea8c376394f 100644
--- a/drivers/media/dvb/frontends/mb86a16.h
+++ b/drivers/media/dvb-frontends/mb86a16.h
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb-frontends/mb86a16_priv.h
index 360a35acfe84..360a35acfe84 100644
--- a/drivers/media/dvb/frontends/mb86a16_priv.h
+++ b/drivers/media/dvb-frontends/mb86a16_priv.h
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index fade566927c3..fade566927c3 100644
--- a/drivers/media/dvb/frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
diff --git a/drivers/media/dvb/frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index bf22e77888b9..bf22e77888b9 100644
--- a/drivers/media/dvb/frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index e20bf13aa860..e20bf13aa860 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h
index 29e3bb5496b8..29e3bb5496b8 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb-frontends/mt312.h
diff --git a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb-frontends/mt312_priv.h
index a3959f94d639..a3959f94d639 100644
--- a/drivers/media/dvb/frontends/mt312_priv.h
+++ b/drivers/media/dvb-frontends/mt312_priv.h
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c
index 2c3b50e828d7..2c3b50e828d7 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb-frontends/mt352.c
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h
index ca2562d6f289..ca2562d6f289 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb-frontends/mt352.h
diff --git a/drivers/media/dvb/frontends/mt352_priv.h b/drivers/media/dvb-frontends/mt352_priv.h
index 44ad0d4c8f12..44ad0d4c8f12 100644
--- a/drivers/media/dvb/frontends/mt352_priv.h
+++ b/drivers/media/dvb-frontends/mt352_priv.h
diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c
new file mode 100644
index 000000000000..8e288940a61f
--- /dev/null
+++ b/drivers/media/dvb-frontends/nxt200x.c
@@ -0,0 +1,1242 @@
+/*
+ * Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ * Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com>
+ * Copyright (C) 2006 Michael Krufky <mkrufky@m1k.net>
+ * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ * and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
+ * AverTVHD MCE A180 (NXT2004)
+ * ATI HDTV Wonder (NXT2004)
+ *
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * download/extract the appropriate firmware, and then copy it to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+#include "nxt200x.h"
+
+struct nxt200x_state {
+
+ struct i2c_adapter* i2c;
+ const struct nxt200x_config* config;
+ struct dvb_frontend frontend;
+
+ /* demodulator private data */
+ nxt_chip_type demod_chip;
+ u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) do { if (debug) pr_debug(args); } while (0)
+
+static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
+{
+ int err;
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
+ __func__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
+{
+ int err;
+ struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
+ __func__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
+ const u8 *buf, u8 len)
+{
+ u8 buf2 [len+1];
+ int err;
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+
+ buf2[0] = reg;
+ memcpy(&buf2[1], buf, len);
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
+ __func__, state->config->demod_address, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
+{
+ u8 reg2 [] = { reg };
+
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+ int err;
+
+ if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+ pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
+ __func__, state->config->demod_address, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static u16 nxt200x_crc(u16 crc, u8 c)
+{
+ u8 i;
+ u16 input = (u16) c & 0xFF;
+
+ input<<=8;
+ for(i=0; i<8; i++) {
+ if((crc^input) & 0x8000)
+ crc=(crc<<1)^CRC_CCIT_MASK;
+ else
+ crc<<=1;
+ input<<=1;
+ }
+ return crc;
+}
+
+static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+ u8 attr, len2, buf;
+ dprintk("%s\n", __func__);
+
+ /* set mutli register register */
+ nxt200x_writebytes(state, 0x35, &reg, 1);
+
+ /* send the actual data */
+ nxt200x_writebytes(state, 0x36, data, len);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ len2 = len;
+ buf = 0x02;
+ break;
+ case NXT2004:
+ /* probably not right, but gives correct values */
+ attr = 0x02;
+ if (reg & 0x80) {
+ attr = attr << 1;
+ if (reg & 0x04)
+ attr = attr >> 1;
+ }
+ /* set write bit */
+ len2 = ((attr << 4) | 0x10) | len;
+ buf = 0x80;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* set multi register length */
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* toggle the multireg write bit */
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ nxt200x_readbytes(state, 0x21, &buf, 1);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ if ((buf & 0x02) == 0)
+ return 0;
+ break;
+ case NXT2004:
+ if (buf == 0)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ pr_warn("Error writing multireg register 0x%02X\n", reg);
+
+ return 0;
+}
+
+static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+ int i;
+ u8 buf, len2, attr;
+ dprintk("%s\n", __func__);
+
+ /* set mutli register register */
+ nxt200x_writebytes(state, 0x35, &reg, 1);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ /* set multi register length */
+ len2 = len & 0x80;
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* read the actual data */
+ nxt200x_readbytes(state, reg, data, len);
+ return 0;
+ break;
+ case NXT2004:
+ /* probably not right, but gives correct values */
+ attr = 0x02;
+ if (reg & 0x80) {
+ attr = attr << 1;
+ if (reg & 0x04)
+ attr = attr >> 1;
+ }
+
+ /* set multi register length */
+ len2 = (attr << 4) | len;
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* toggle the multireg bit*/
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ /* read the actual data */
+ for(i = 0; i < len; i++) {
+ nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
+ }
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+}
+
+static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
+{
+ u8 buf, stopval, counter = 0;
+ dprintk("%s\n", __func__);
+
+ /* set correct stop value */
+ switch (state->demod_chip) {
+ case NXT2002:
+ stopval = 0x40;
+ break;
+ case NXT2004:
+ stopval = 0x10;
+ break;
+ default:
+ stopval = 0;
+ break;
+ }
+
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x22, &buf, 1);
+
+ while (counter < 20) {
+ nxt200x_readbytes(state, 0x31, &buf, 1);
+ if (buf & stopval)
+ return;
+ msleep(10);
+ counter++;
+ }
+
+ pr_warn("Timeout waiting for nxt200x to stop. This is ok after "
+ "firmware upload.\n");
+ return;
+}
+
+static void nxt200x_microcontroller_start (struct nxt200x_state* state)
+{
+ u8 buf;
+ dprintk("%s\n", __func__);
+
+ buf = 0x00;
+ nxt200x_writebytes(state, 0x22, &buf, 1);
+}
+
+static void nxt2004_microcontroller_init (struct nxt200x_state* state)
+{
+ u8 buf[9];
+ u8 counter = 0;
+ dprintk("%s\n", __func__);
+
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x2b, buf, 1);
+ buf[0] = 0x70;
+ nxt200x_writebytes(state, 0x34, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x35, buf, 1);
+ buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
+ buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
+ nxt200x_writebytes(state, 0x36, buf, 9);
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x21, buf, 1);
+
+ while (counter < 20) {
+ nxt200x_readbytes(state, 0x21, buf, 1);
+ if (buf[0] == 0)
+ return;
+ msleep(10);
+ counter++;
+ }
+
+ pr_warn("Timeout waiting for nxt2004 to init.\n");
+
+ return;
+}
+
+static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
+{
+ u8 buf, count = 0;
+
+ dprintk("%s\n", __func__);
+
+ dprintk("Tuner Bytes: %*ph\n", 4, data + 1);
+
+ /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
+ * direct write is required for Philips TUV1236D and ALPS TDHU2 */
+ switch (state->demod_chip) {
+ case NXT2004:
+ if (i2c_writebytes(state, data[0], data+1, 4))
+ pr_warn("error writing to tuner\n");
+ /* wait until we have a lock */
+ while (count < 20) {
+ i2c_readbytes(state, data[0], &buf, 1);
+ if (buf & 0x40)
+ return 0;
+ msleep(100);
+ count++;
+ }
+ pr_warn("timeout waiting for tuner lock\n");
+ break;
+ case NXT2002:
+ /* set the i2c transfer speed to the tuner */
+ buf = 0x03;
+ nxt200x_writebytes(state, 0x20, &buf, 1);
+
+ /* setup to transfer 4 bytes via i2c */
+ buf = 0x04;
+ nxt200x_writebytes(state, 0x34, &buf, 1);
+
+ /* write actual tuner bytes */
+ nxt200x_writebytes(state, 0x36, data+1, 4);
+
+ /* set tuner i2c address */
+ buf = data[0] << 1;
+ nxt200x_writebytes(state, 0x35, &buf, 1);
+
+ /* write UC Opmode to begin transfer */
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ while (count < 20) {
+ nxt200x_readbytes(state, 0x21, &buf, 1);
+ if ((buf & 0x80)== 0x00)
+ return 0;
+ msleep(100);
+ count++;
+ }
+ pr_warn("timeout error writing to tuner\n");
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void nxt200x_agc_reset(struct nxt200x_state* state)
+{
+ u8 buf;
+ dprintk("%s\n", __func__);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ buf = 0x08;
+ nxt200x_writebytes(state, 0x08, &buf, 1);
+ buf = 0x00;
+ nxt200x_writebytes(state, 0x08, &buf, 1);
+ break;
+ case NXT2004:
+ nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
+ buf = 0x08;
+ nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+ buf = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 buf[3], written = 0, chunkpos = 0;
+ u16 rambase, position, crc = 0;
+
+ dprintk("%s\n", __func__);
+ dprintk("Firmware is %zu bytes\n", fw->size);
+
+ /* Get the RAM base for this nxt2002 */
+ nxt200x_readbytes(state, 0x10, buf, 1);
+
+ if (buf[0] & 0x10)
+ rambase = 0x1000;
+ else
+ rambase = 0x0000;
+
+ dprintk("rambase on this nxt2002 is %04X\n", rambase);
+
+ /* Hold the micro in reset while loading firmware */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ for (position = 0; position < fw->size; position++) {
+ if (written == 0) {
+ crc = 0;
+ chunkpos = 0x28;
+ buf[0] = ((rambase + position) >> 8);
+ buf[1] = (rambase + position) & 0xFF;
+ buf[2] = 0x81;
+ /* write starting address */
+ nxt200x_writebytes(state, 0x29, buf, 3);
+ }
+ written++;
+ chunkpos++;
+
+ if ((written % 4) == 0)
+ nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
+
+ crc = nxt200x_crc(crc, fw->data[position]);
+
+ if ((written == 255) || (position+1 == fw->size)) {
+ /* write remaining bytes of firmware */
+ nxt200x_writebytes(state, chunkpos+4-(written %4),
+ &fw->data[position-(written %4) + 1],
+ written %4);
+ buf[0] = crc << 8;
+ buf[1] = crc & 0xFF;
+
+ /* write crc */
+ nxt200x_writebytes(state, 0x2C, buf, 2);
+
+ /* do a read to stop things */
+ nxt200x_readbytes(state, 0x2A, buf, 1);
+
+ /* set transfer mode to complete */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ written = 0;
+ }
+ }
+
+ return 0;
+};
+
+static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 buf[3];
+ u16 rambase, position, crc=0;
+
+ dprintk("%s\n", __func__);
+ dprintk("Firmware is %zu bytes\n", fw->size);
+
+ /* set rambase */
+ rambase = 0x1000;
+
+ /* hold the micro in reset while loading firmware */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf,1);
+
+ /* calculate firmware CRC */
+ for (position = 0; position < fw->size; position++) {
+ crc = nxt200x_crc(crc, fw->data[position]);
+ }
+
+ buf[0] = rambase >> 8;
+ buf[1] = rambase & 0xFF;
+ buf[2] = 0x81;
+ /* write starting address */
+ nxt200x_writebytes(state,0x29,buf,3);
+
+ for (position = 0; position < fw->size;) {
+ nxt200x_writebytes(state, 0x2C, &fw->data[position],
+ fw->size-position > 255 ? 255 : fw->size-position);
+ position += (fw->size-position > 255 ? 255 : fw->size-position);
+ }
+ buf[0] = crc >> 8;
+ buf[1] = crc & 0xFF;
+
+ dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
+
+ /* write crc */
+ nxt200x_writebytes(state, 0x2C, buf,2);
+
+ /* do a read to stop things */
+ nxt200x_readbytes(state, 0x2C, buf, 1);
+
+ /* set transfer mode to complete */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf,1);
+
+ return 0;
+};
+
+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];
+
+ /* stop the micro first */
+ nxt200x_microcontroller_stop(state);
+
+ if (state->demod_chip == NXT2004) {
+ /* make sure demod is set to digital */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x17, buf, 1);
+ }
+
+ /* set additional params */
+ switch (p->modulation) {
+ case QAM_64:
+ case QAM_256:
+ /* Set punctured clock for QAM */
+ /* This is just a guess since I am unable to test it */
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 1);
+ break;
+ case VSB_8:
+ /* Set non-punctured clock for VSB */
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ if (fe->ops.tuner_ops.calc_regs) {
+ /* get tuning information */
+ fe->ops.tuner_ops.calc_regs(fe, buf, 5);
+
+ /* write frequency information */
+ nxt200x_writetuner(state, buf);
+ }
+
+ /* reset the agc now that tuning has been completed */
+ nxt200x_agc_reset(state);
+
+ /* set target power level */
+ switch (p->modulation) {
+ case QAM_64:
+ case QAM_256:
+ buf[0] = 0x74;
+ break;
+ case VSB_8:
+ buf[0] = 0x70;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x42, buf, 1);
+
+ /* configure sdm */
+ switch (state->demod_chip) {
+ case NXT2002:
+ buf[0] = 0x87;
+ break;
+ case NXT2004:
+ buf[0] = 0x07;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* write sdm1 input */
+ buf[0] = 0x10;
+ buf[1] = 0x00;
+ switch (state->demod_chip) {
+ case NXT2002:
+ nxt200x_writereg_multibyte(state, 0x58, buf, 2);
+ break;
+ case NXT2004:
+ nxt200x_writebytes(state, 0x58, buf, 2);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* write sdmx input */
+ switch (p->modulation) {
+ case QAM_64:
+ buf[0] = 0x68;
+ break;
+ case QAM_256:
+ buf[0] = 0x64;
+ break;
+ case VSB_8:
+ buf[0] = 0x60;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ buf[1] = 0x00;
+ switch (state->demod_chip) {
+ case NXT2002:
+ nxt200x_writereg_multibyte(state, 0x5C, buf, 2);
+ break;
+ case NXT2004:
+ nxt200x_writebytes(state, 0x5C, buf, 2);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* write adc power lpf fc */
+ buf[0] = 0x05;
+ nxt200x_writebytes(state, 0x43, buf, 1);
+
+ if (state->demod_chip == NXT2004) {
+ /* write ??? */
+ buf[0] = 0x00;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x46, buf, 2);
+ }
+
+ /* write accumulator2 input */
+ buf[0] = 0x80;
+ buf[1] = 0x00;
+ switch (state->demod_chip) {
+ case NXT2002:
+ nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
+ break;
+ case NXT2004:
+ nxt200x_writebytes(state, 0x4B, buf, 2);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* write kg1 */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x4D, buf, 1);
+
+ /* write sdm12 lpf fc */
+ buf[0] = 0x44;
+ nxt200x_writebytes(state, 0x55, buf, 1);
+
+ /* write agc control reg */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ if (state->demod_chip == NXT2004) {
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x24;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x44;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ }
+
+ /* write agc ucgp0 */
+ switch (p->modulation) {
+ case QAM_64:
+ buf[0] = 0x02;
+ break;
+ case QAM_256:
+ buf[0] = 0x03;
+ break;
+ case VSB_8:
+ buf[0] = 0x00;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x30, buf, 1);
+
+ /* write agc control reg */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ /* write accumulator2 input */
+ buf[0] = 0x80;
+ buf[1] = 0x00;
+ switch (state->demod_chip) {
+ case NXT2002:
+ nxt200x_writereg_multibyte(state, 0x49, buf, 2);
+ nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
+ break;
+ case NXT2004:
+ nxt200x_writebytes(state, 0x49, buf, 2);
+ nxt200x_writebytes(state, 0x4B, buf, 2);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* write agc control reg */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ nxt200x_microcontroller_start(state);
+
+ if (state->demod_chip == NXT2004) {
+ nxt2004_microcontroller_init(state);
+
+ /* ???? */
+ buf[0] = 0xF0;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x5C, buf, 2);
+ }
+
+ /* adjacent channel detection should be done here, but I don't
+ have any stations with this need so I cannot test it */
+
+ return 0;
+}
+
+static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 lock;
+ nxt200x_readbytes(state, 0x31, &lock, 1);
+
+ *status = 0;
+ if (lock & 0x20) {
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ *status |= FE_HAS_LOCK;
+ }
+ return 0;
+}
+
+static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[3];
+
+ nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+
+ *ber = ((b[0] << 8) + b[1]) * 8;
+
+ return 0;
+}
+
+static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[2];
+ u16 temp = 0;
+
+ /* setup to read cluster variance */
+ b[0] = 0x00;
+ nxt200x_writebytes(state, 0xA1, b, 1);
+
+ /* get multreg val */
+ nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+ temp = (b[0] << 8) | b[1];
+ *strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+ return 0;
+}
+
+static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[2];
+ u16 temp = 0, temp2;
+ u32 snrdb = 0;
+
+ /* setup to read cluster variance */
+ b[0] = 0x00;
+ nxt200x_writebytes(state, 0xA1, b, 1);
+
+ /* get multreg val from 0xA6 */
+ nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+ temp = (b[0] << 8) | b[1];
+ temp2 = 0x7FFF - temp;
+
+ /* snr will be in db */
+ if (temp2 > 0x7F00)
+ snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+ else if (temp2 > 0x7EC0)
+ snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+ else if (temp2 > 0x7C00)
+ snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+ else
+ snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+ /* the value reported back from the frontend will be FFFF=32db 0000=0db */
+ *snr = snrdb * (0xFFFF/32000);
+
+ return 0;
+}
+
+static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[3];
+
+ nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+ *ucblocks = b[2];
+
+ return 0;
+}
+
+static int nxt200x_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ const struct firmware *fw;
+ int ret;
+ u8 buf[2];
+
+ /* request the firmware, this will block until someone uploads it */
+ pr_debug("%s: Waiting for firmware upload (%s)...\n",
+ __func__, NXT2002_DEFAULT_FIRMWARE);
+ ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
+ state->i2c->dev.parent);
+ pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
+ if (ret) {
+ pr_err("%s: No firmware uploaded (timeout or file not found?)"
+ "\n", __func__);
+ return ret;
+ }
+
+ ret = nxt2002_load_firmware(fe, fw);
+ release_firmware(fw);
+ if (ret) {
+ pr_err("%s: Writing firmware to device failed\n", __func__);
+ return ret;
+ }
+ pr_info("%s: Firmware upload complete\n", __func__);
+
+ /* Put the micro into reset */
+ nxt200x_microcontroller_stop(state);
+
+ /* ensure transfer is complete */
+ buf[0]=0x00;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ /* Put the micro into reset for real this time */
+ nxt200x_microcontroller_stop(state);
+
+ /* soft reset everything (agc,frontend,eq,fec)*/
+ buf[0] = 0x0F;
+ nxt200x_writebytes(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x08, buf, 1);
+
+ /* write agc sdm configure */
+ buf[0] = 0xF1;
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* write mod output format */
+ buf[0] = 0x20;
+ nxt200x_writebytes(state, 0x09, buf, 1);
+
+ /* write fec mpeg mode */
+ buf[0] = 0x7E;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0xE9, buf, 2);
+
+ /* write mux selection */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xCC, buf, 1);
+
+ return 0;
+}
+
+static int nxt2004_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ const struct firmware *fw;
+ int ret;
+ u8 buf[3];
+
+ /* ??? */
+ buf[0]=0x00;
+ nxt200x_writebytes(state, 0x1E, buf, 1);
+
+ /* request the firmware, this will block until someone uploads it */
+ pr_debug("%s: Waiting for firmware upload (%s)...\n",
+ __func__, NXT2004_DEFAULT_FIRMWARE);
+ ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
+ state->i2c->dev.parent);
+ pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
+ if (ret) {
+ pr_err("%s: No firmware uploaded (timeout or file not found?)"
+ "\n", __func__);
+ return ret;
+ }
+
+ ret = nxt2004_load_firmware(fe, fw);
+ release_firmware(fw);
+ if (ret) {
+ pr_err("%s: Writing firmware to device failed\n", __func__);
+ return ret;
+ }
+ pr_info("%s: Firmware upload complete\n", __func__);
+
+ /* ensure transfer is complete */
+ buf[0] = 0x01;
+ nxt200x_writebytes(state, 0x19, buf, 1);
+
+ nxt2004_microcontroller_init(state);
+ nxt200x_microcontroller_stop(state);
+ nxt200x_microcontroller_stop(state);
+ nxt2004_microcontroller_init(state);
+ nxt200x_microcontroller_stop(state);
+
+ /* soft reset everything (agc,frontend,eq,fec)*/
+ buf[0] = 0xFF;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ /* write agc sdm configure */
+ buf[0] = 0xD7;
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x07;
+ buf[1] = 0xfe;
+ nxt200x_writebytes(state, 0x35, buf, 2);
+ buf[0] = 0x12;
+ nxt200x_writebytes(state, 0x34, buf, 1);
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x21, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x01;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* write fec mpeg mode */
+ buf[0] = 0x7E;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0xE9, buf, 2);
+
+ /* write mux selection */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xCC, buf, 1);
+
+ /* ???*/
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ /* ???*/
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x01;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x70;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x40;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ nxt200x_readbytes(state, 0x10, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writebytes(state, 0x10, buf, 1);
+ nxt200x_readbytes(state, 0x0A, buf, 1);
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+
+ nxt2004_microcontroller_init(state);
+
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+ buf[0] = 0x7E;
+ nxt200x_writebytes(state, 0xE9, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xEA, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x44;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* initialize tuner */
+ nxt200x_readbytes(state, 0x10, buf, 1);
+ buf[0] = 0x12;
+ nxt200x_writebytes(state, 0x10, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x13, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x16, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ nxt200x_writebytes(state, 0x17, buf, 1);
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ nxt200x_writebytes(state, 0x17, buf, 1);
+
+ return 0;
+}
+
+static int nxt200x_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ int ret = 0;
+
+ if (!state->initialised) {
+ switch (state->demod_chip) {
+ case NXT2002:
+ ret = nxt2002_init(fe);
+ break;
+ case NXT2004:
+ ret = nxt2004_init(fe);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ state->initialised = 1;
+ }
+ return ret;
+}
+
+static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 500;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static void nxt200x_release(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops nxt200x_ops;
+
+struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct nxt200x_state* state = NULL;
+ u8 buf [] = {0,0,0,0,0};
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->initialised = 0;
+
+ /* read card id */
+ nxt200x_readbytes(state, 0x00, buf, 5);
+ dprintk("NXT info: %*ph\n", 5, buf);
+
+ /* set demod chip */
+ switch (buf[0]) {
+ case 0x04:
+ state->demod_chip = NXT2002;
+ pr_info("NXT2002 Detected\n");
+ break;
+ case 0x05:
+ state->demod_chip = NXT2004;
+ pr_info("NXT2004 Detected\n");
+ break;
+ default:
+ goto error;
+ }
+
+ /* make sure demod chip is supported */
+ switch (state->demod_chip) {
+ case NXT2002:
+ if (buf[0] != 0x04) goto error; /* device id */
+ if (buf[1] != 0x02) goto error; /* fab id */
+ if (buf[2] != 0x11) goto error; /* month */
+ if (buf[3] != 0x20) goto error; /* year msb */
+ if (buf[4] != 0x00) goto error; /* year lsb */
+ break;
+ case NXT2004:
+ if (buf[0] != 0x05) goto error; /* device id */
+ break;
+ default:
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ pr_err("Unknown/Unsupported NXT chip: %*ph\n", 5, buf);
+ return NULL;
+}
+
+static struct dvb_frontend_ops nxt200x_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
+ .info = {
+ .name = "Nextwave NXT200X VSB/QAM frontend",
+ .frequency_min = 54000000,
+ .frequency_max = 860000000,
+ .frequency_stepsize = 166666, /* stepsize is just a guess */
+ .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_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
+ },
+
+ .release = nxt200x_release,
+
+ .init = nxt200x_init,
+ .sleep = nxt200x_sleep,
+
+ .set_frontend = nxt200x_setup_frontend_parameters,
+ .get_tune_settings = nxt200x_get_tune_settings,
+
+ .read_status = nxt200x_read_status,
+ .read_ber = nxt200x_read_ber,
+ .read_signal_strength = nxt200x_read_signal_strength,
+ .read_snr = nxt200x_read_snr,
+ .read_ucblocks = nxt200x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt200x_attach);
+
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
index f3c84583770f..f3c84583770f 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb-frontends/nxt200x.h
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c
index 90ae6c72c0e3..90ae6c72c0e3 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb-frontends/nxt6000.c
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h
index 878eb38a075e..878eb38a075e 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb-frontends/nxt6000.h
diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb-frontends/nxt6000_priv.h
index 0422e580038a..0422e580038a 100644
--- a/drivers/media/dvb/frontends/nxt6000_priv.h
+++ b/drivers/media/dvb-frontends/nxt6000_priv.h
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c
index 5ef921823c15..5ef921823c15 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb-frontends/or51132.c
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
index 1b8e04d973c8..1b8e04d973c8 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb-frontends/or51132.h
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
index c625b57b4333..c625b57b4333 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb-frontends/or51211.c
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h
index 3ce0508b898e..3ce0508b898e 100644
--- a/drivers/media/dvb/frontends/or51211.h
+++ b/drivers/media/dvb-frontends/or51211.h
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
new file mode 100644
index 000000000000..8fa8b0854e76
--- /dev/null
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -0,0 +1,757 @@
+/*
+ * 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_get_frontend(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[3];
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+ if (ret)
+ goto err;
+
+ dbg("%s: TPS=%*ph", __func__, 3, buf);
+
+ switch ((buf[0] >> 2) & 3) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ }
+
+ switch ((buf[2] >> 2) & 1) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ }
+
+ switch ((buf[2] >> 0) & 3) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch ((buf[0] >> 4) & 7) {
+ case 0:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ switch ((buf[1] >> 3) & 7) {
+ case 0:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch ((buf[1] >> 0) & 7) {
+ case 0:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ return 0;
+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)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret, hierarchy, constellation;
+ u8 buf[2], tmp;
+ u16 tmp16;
+#define CONSTELLATION_NUM 3
+#define HIERARCHY_NUM 4
+ static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+ { 70705899, 70705899, 70705899, 70705899 },
+ { 82433173, 82433173, 87483115, 94445660 },
+ { 92888734, 92888734, 95487525, 99770748 },
+ };
+
+ if (priv->sleeping)
+ return 0;
+
+ /* reports SNR in resolution of 0.1 dB */
+
+ ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
+ if (ret)
+ goto err;
+
+ constellation = (tmp >> 2) & 0x03; /* [3:2] */
+ if (constellation > CONSTELLATION_NUM - 1)
+ goto err;
+
+ hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
+ if (hierarchy > HIERARCHY_NUM - 1)
+ goto err;
+
+ ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
+ if (ret)
+ goto err;
+
+ tmp16 = buf[0] << 8 | buf[1];
+
+ if (tmp16)
+ *snr = (snr_constant[constellation][hierarchy] -
+ intlog10(tmp16)) / ((1 << 24) / 100);
+ else
+ *snr = 0;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+ if (ret)
+ goto err;
+
+ *ber = buf[0] << 8 | buf[1];
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+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)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 if_agc_raw, if_agc;
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+ if (ret)
+ goto err;
+
+ if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
+
+ if (if_agc_raw & (1 << 9))
+ if_agc = -(~(if_agc_raw - 1) & 0x1ff);
+ else
+ if_agc = if_agc_raw;
+
+ *strength = (u8) (55 - if_agc / 182);
+ *strength |= *strength << 8;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+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,
+ .get_frontend = rtl2830_get_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
index 1c6ee91749c2..1c6ee91749c2 100644
--- a/drivers/media/dvb/frontends/rtl2830.h
+++ b/drivers/media/dvb-frontends/rtl2830.h
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index 9b20557ccf6c..9b20557ccf6c 100644
--- a/drivers/media/dvb/frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 28269ccaeab7..28269ccaeab7 100644
--- a/drivers/media/dvb/frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index d94dc9a3fa62..d94dc9a3fa62 100644
--- a/drivers/media/dvb/frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 0ce9502da8ba..0ce9502da8ba 100644
--- a/drivers/media/dvb/frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c
index f71b06221e14..f71b06221e14 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb-frontends/s5h1409.c
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
index 91f2ebd1a534..91f2ebd1a534 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb-frontends/s5h1409.h
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c
index 6cc4b7a9dd60..6cc4b7a9dd60 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb-frontends/s5h1411.c
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
index 45ec0f82989c..45ec0f82989c 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb-frontends/s5h1411.h
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c
index e2fec9ebf947..e2fec9ebf947 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb-frontends/s5h1420.c
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h
index ff308136d865..ff308136d865 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb-frontends/s5h1420.h
diff --git a/drivers/media/dvb/frontends/s5h1420_priv.h b/drivers/media/dvb-frontends/s5h1420_priv.h
index d9c58d281816..d9c58d281816 100644
--- a/drivers/media/dvb/frontends/s5h1420_priv.h
+++ b/drivers/media/dvb-frontends/s5h1420_priv.h
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c
index 8352ce1c9556..8352ce1c9556 100644
--- a/drivers/media/dvb/frontends/s5h1432.c
+++ b/drivers/media/dvb-frontends/s5h1432.c
diff --git a/drivers/media/dvb/frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h
index b57438c32546..b57438c32546 100644
--- a/drivers/media/dvb/frontends/s5h1432.h
+++ b/drivers/media/dvb-frontends/s5h1432.h
diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb-frontends/s921.c
index cd2288c07147..cd2288c07147 100644
--- a/drivers/media/dvb/frontends/s921.c
+++ b/drivers/media/dvb-frontends/s921.c
diff --git a/drivers/media/dvb/frontends/s921.h b/drivers/media/dvb-frontends/s921.h
index f220d8299c81..f220d8299c81 100644
--- a/drivers/media/dvb/frontends/s921.h
+++ b/drivers/media/dvb-frontends/s921.h
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c
index a68a64800df7..a68a64800df7 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb-frontends/si21xx.c
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h
index 141b5b8a5f63..141b5b8a5f63 100644
--- a/drivers/media/dvb/frontends/si21xx.h
+++ b/drivers/media/dvb-frontends/si21xx.h
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c
index e37274c8f14e..e37274c8f14e 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb-frontends/sp8870.c
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h
index a764a793c7d8..a764a793c7d8 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb-frontends/sp8870.h
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c
index f4096ccb226e..f4096ccb226e 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb-frontends/sp887x.c
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h
index 04eff6e0eef3..04eff6e0eef3 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb-frontends/sp887x.h
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
index 117a56926dca..117a56926dca 100644
--- a/drivers/media/dvb/frontends/stb0899_algo.c
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
diff --git a/drivers/media/dvb/frontends/stb0899_cfg.h b/drivers/media/dvb-frontends/stb0899_cfg.h
index 0867906d3ff3..0867906d3ff3 100644
--- a/drivers/media/dvb/frontends/stb0899_cfg.h
+++ b/drivers/media/dvb-frontends/stb0899_cfg.h
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 5d7f8a9b451b..5d7f8a9b451b 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
diff --git a/drivers/media/dvb/frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
index 98b200ce0c34..98b200ce0c34 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.h
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
diff --git a/drivers/media/dvb/frontends/stb0899_priv.h b/drivers/media/dvb-frontends/stb0899_priv.h
index 82395b912815..82395b912815 100644
--- a/drivers/media/dvb/frontends/stb0899_priv.h
+++ b/drivers/media/dvb-frontends/stb0899_priv.h
diff --git a/drivers/media/dvb/frontends/stb0899_reg.h b/drivers/media/dvb-frontends/stb0899_reg.h
index ba1ed56304a0..ba1ed56304a0 100644
--- a/drivers/media/dvb/frontends/stb0899_reg.h
+++ b/drivers/media/dvb-frontends/stb0899_reg.h
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c
index a0c3c526b132..a0c3c526b132 100644
--- a/drivers/media/dvb/frontends/stb6000.c
+++ b/drivers/media/dvb-frontends/stb6000.c
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h
index 7be479c22d5b..7be479c22d5b 100644
--- a/drivers/media/dvb/frontends/stb6000.h
+++ b/drivers/media/dvb-frontends/stb6000.h
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index 2e93e65d2cdb..2e93e65d2cdb 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
index 2ab096614b3f..2ab096614b3f 100644
--- a/drivers/media/dvb/frontends/stb6100.h
+++ b/drivers/media/dvb-frontends/stb6100.h
diff --git a/drivers/media/dvb/frontends/stb6100_cfg.h b/drivers/media/dvb-frontends/stb6100_cfg.h
index 6314d18c797a..6314d18c797a 100644
--- a/drivers/media/dvb/frontends/stb6100_cfg.h
+++ b/drivers/media/dvb-frontends/stb6100_cfg.h
diff --git a/drivers/media/dvb/frontends/stb6100_proc.h b/drivers/media/dvb-frontends/stb6100_proc.h
index 112163a48622..112163a48622 100644
--- a/drivers/media/dvb/frontends/stb6100_proc.h
+++ b/drivers/media/dvb-frontends/stb6100_proc.h
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c
index 632b25156e4c..632b25156e4c 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb-frontends/stv0288.c
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h
index f2b53db0606d..f2b53db0606d 100644
--- a/drivers/media/dvb/frontends/stv0288.h
+++ b/drivers/media/dvb-frontends/stv0288.h
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c
index d40f226160ef..d40f226160ef 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb-frontends/stv0297.c
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h
index 3f8f9468f387..3f8f9468f387 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb-frontends/stv0297.h
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c
index 057b5f8effc0..057b5f8effc0 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb-frontends/stv0299.c
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h
index ba219b767a69..ba219b767a69 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb-frontends/stv0299.h
diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 2a8aaeb1112d..2a8aaeb1112d 100644
--- a/drivers/media/dvb/frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
diff --git a/drivers/media/dvb/frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h
index 93cc4a57eea0..93cc4a57eea0 100644
--- a/drivers/media/dvb/frontends/stv0367.h
+++ b/drivers/media/dvb-frontends/stv0367.h
diff --git a/drivers/media/dvb/frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h
index 995db0689ddd..995db0689ddd 100644
--- a/drivers/media/dvb/frontends/stv0367_priv.h
+++ b/drivers/media/dvb-frontends/stv0367_priv.h
diff --git a/drivers/media/dvb/frontends/stv0367_regs.h b/drivers/media/dvb-frontends/stv0367_regs.h
index a96fbdc7e25e..a96fbdc7e25e 100644
--- a/drivers/media/dvb/frontends/stv0367_regs.h
+++ b/drivers/media/dvb-frontends/stv0367_regs.h
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h
index 91c7ee8b2313..91c7ee8b2313 100644
--- a/drivers/media/dvb/frontends/stv0900.h
+++ b/drivers/media/dvb-frontends/stv0900.h
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index 7f1badaf0d03..7f1badaf0d03 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
diff --git a/drivers/media/dvb/frontends/stv0900_init.h b/drivers/media/dvb-frontends/stv0900_init.h
index b684df9995d8..b684df9995d8 100644
--- a/drivers/media/dvb/frontends/stv0900_init.h
+++ b/drivers/media/dvb-frontends/stv0900_init.h
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb-frontends/stv0900_priv.h
index e0ea74c8e093..e0ea74c8e093 100644
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/drivers/media/dvb-frontends/stv0900_priv.h
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb-frontends/stv0900_reg.h
index 731afe93a823..731afe93a823 100644
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ b/drivers/media/dvb-frontends/stv0900_reg.h
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index 4af20780fb9c..4af20780fb9c 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index ea86a5603e57..ea86a5603e57 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 29cdc2b71314..29cdc2b71314 100644
--- a/drivers/media/dvb/frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb-frontends/stv090x_priv.h
index 5b780c80d496..5b780c80d496 100644
--- a/drivers/media/dvb/frontends/stv090x_priv.h
+++ b/drivers/media/dvb-frontends/stv090x_priv.h
diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb-frontends/stv090x_reg.h
index 93741ee14297..93741ee14297 100644
--- a/drivers/media/dvb/frontends/stv090x_reg.h
+++ b/drivers/media/dvb-frontends/stv090x_reg.h
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c
index 20b5fa92c53e..20b5fa92c53e 100644
--- a/drivers/media/dvb/frontends/stv6110.c
+++ b/drivers/media/dvb-frontends/stv6110.c
diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h
index fe71bba6a26e..fe71bba6a26e 100644
--- a/drivers/media/dvb/frontends/stv6110.h
+++ b/drivers/media/dvb-frontends/stv6110.h
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index f36cab12bdc7..f36cab12bdc7 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index 47516753929a..47516753929a 100644
--- a/drivers/media/dvb/frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h
index 0ec936a660a7..0ec936a660a7 100644
--- a/drivers/media/dvb/frontends/stv6110x_priv.h
+++ b/drivers/media/dvb-frontends/stv6110x_priv.h
diff --git a/drivers/media/dvb/frontends/stv6110x_reg.h b/drivers/media/dvb-frontends/stv6110x_reg.h
index 93e5c70e5fd8..93e5c70e5fd8 100644
--- a/drivers/media/dvb/frontends/stv6110x_reg.h
+++ b/drivers/media/dvb-frontends/stv6110x_reg.h
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c
index 1bff7f457e19..1bff7f457e19 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb-frontends/tda10021.c
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c
index ca1e0d54b69a..ca1e0d54b69a 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb-frontends/tda10023.c
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h
index 04d19418bf20..04d19418bf20 100644
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ b/drivers/media/dvb-frontends/tda1002x.h
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c
index 71fb63299de7..71fb63299de7 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb-frontends/tda10048.c
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h
index fb2ef5ac9487..fb2ef5ac9487 100644
--- a/drivers/media/dvb/frontends/tda10048.h
+++ b/drivers/media/dvb-frontends/tda10048.h
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c
index 35d72b46aa1e..35d72b46aa1e 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb-frontends/tda1004x.c
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h
index 4e27ffb0f14e..4e27ffb0f14e 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb-frontends/tda1004x.h
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 703c3d05f9f4..703c3d05f9f4 100644
--- a/drivers/media/dvb/frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
diff --git a/drivers/media/dvb/frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index 21163c4b555c..21163c4b555c 100644
--- a/drivers/media/dvb/frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb-frontends/tda10071_priv.h
index 0fa85cfa70c2..0fa85cfa70c2 100644
--- a/drivers/media/dvb/frontends/tda10071_priv.h
+++ b/drivers/media/dvb-frontends/tda10071_priv.h
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c
index fcfe2e080cb0..fcfe2e080cb0 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb-frontends/tda10086.c
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h
index 61148c558d8d..61148c558d8d 100644
--- a/drivers/media/dvb/frontends/tda10086.h
+++ b/drivers/media/dvb-frontends/tda10086.h
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
index ad7c72e8f517..ad7c72e8f517 100644
--- a/drivers/media/dvb/frontends/tda18271c2dd.c
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h
index 1389c74e12ce..1389c74e12ce 100644
--- a/drivers/media/dvb/frontends/tda18271c2dd.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd.h
diff --git a/drivers/media/dvb/frontends/tda18271c2dd_maps.h b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
index b87661b9df14..b87661b9df14 100644
--- a/drivers/media/dvb/frontends/tda18271c2dd_maps.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c
index 2c1c759a4f42..2c1c759a4f42 100644
--- a/drivers/media/dvb/frontends/tda665x.c
+++ b/drivers/media/dvb-frontends/tda665x.c
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h
index ec7927aa75ae..ec7927aa75ae 100644
--- a/drivers/media/dvb/frontends/tda665x.h
+++ b/drivers/media/dvb-frontends/tda665x.h
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c
index 15912c96926a..15912c96926a 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb-frontends/tda8083.c
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h
index 5a03c14a10e8..5a03c14a10e8 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb-frontends/tda8083.h
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c
index 53c7d8f1df28..53c7d8f1df28 100644
--- a/drivers/media/dvb/frontends/tda8261.c
+++ b/drivers/media/dvb-frontends/tda8261.c
diff --git a/drivers/media/dvb/frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h
index 006e45351b94..006e45351b94 100644
--- a/drivers/media/dvb/frontends/tda8261.h
+++ b/drivers/media/dvb-frontends/tda8261.h
diff --git a/drivers/media/dvb/frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
index 1af1ee49b542..1af1ee49b542 100644
--- a/drivers/media/dvb/frontends/tda8261_cfg.h
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c
index 04bbcc24de0a..04bbcc24de0a 100644
--- a/drivers/media/dvb/frontends/tda826x.c
+++ b/drivers/media/dvb-frontends/tda826x.c
diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
index 89e97926ab23..89e97926ab23 100644
--- a/drivers/media/dvb/frontends/tda826x.h
+++ b/drivers/media/dvb-frontends/tda826x.h
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb-frontends/tdhd1.h
index 17750985db0c..17750985db0c 100644
--- a/drivers/media/dvb/frontends/tdhd1.h
+++ b/drivers/media/dvb-frontends/tdhd1.h
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c
index 029384d1fddd..029384d1fddd 100644
--- a/drivers/media/dvb/frontends/tua6100.c
+++ b/drivers/media/dvb-frontends/tua6100.c
diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h
index f83dbd5e42ae..f83dbd5e42ae 100644
--- a/drivers/media/dvb/frontends/tua6100.h
+++ b/drivers/media/dvb-frontends/tua6100.h
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c
index bb42b563c42d..bb42b563c42d 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb-frontends/ves1820.c
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h
index e902ed634ec3..e902ed634ec3 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb-frontends/ves1820.h
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c
index 9c17eacaec24..9c17eacaec24 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb-frontends/ves1x93.c
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h
index 8a5a49e808f6..8a5a49e808f6 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb-frontends/ves1x93.h
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb-frontends/z0194a.h
index 96d86d6eb473..96d86d6eb473 100644
--- a/drivers/media/dvb/frontends/z0194a.h
+++ b/drivers/media/dvb-frontends/z0194a.h
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c
index 0903d461b8fa..0903d461b8fa 100644
--- a/drivers/media/dvb/frontends/zl10036.c
+++ b/drivers/media/dvb-frontends/zl10036.c
diff --git a/drivers/media/dvb/frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h
index d84b8f8215e9..d84b8f8215e9 100644
--- a/drivers/media/dvb/frontends/zl10036.h
+++ b/drivers/media/dvb-frontends/zl10036.h
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
index eff9c5fde50a..eff9c5fde50a 100644
--- a/drivers/media/dvb/frontends/zl10039.c
+++ b/drivers/media/dvb-frontends/zl10039.c
diff --git a/drivers/media/dvb/frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h
index 5eee7ea162a1..5eee7ea162a1 100644
--- a/drivers/media/dvb/frontends/zl10039.h
+++ b/drivers/media/dvb-frontends/zl10039.h
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c
index 82946cd517f5..82946cd517f5 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb-frontends/zl10353.c
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h
index 6e3ca9eed048..6e3ca9eed048 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb-frontends/zl10353.h
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb-frontends/zl10353_priv.h
index e0dd1d3e09dd..e0dd1d3e09dd 100644
--- a/drivers/media/dvb/frontends/zl10353_priv.h
+++ b/drivers/media/dvb-frontends/zl10353_priv.h
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
deleted file mode 100644
index f6e40b3a44cc..000000000000
--- a/drivers/media/dvb/Kconfig
+++ /dev/null
@@ -1,91 +0,0 @@
-#
-# DVB device configuration
-#
-
-config DVB_MAX_ADAPTERS
- int "maximum number of DVB/ATSC adapters"
- depends on DVB_CORE
- default 8
- range 1 255
- help
- Maximum number of DVB/ATSC adapters. Increasing this number
- increases the memory consumption of the DVB subsystem even
- if a much lower number of DVB/ATSC adapters is present.
- Only values in the range 4-32 are tested.
-
- If you are unsure about this, use the default value 8
-
-config DVB_DYNAMIC_MINORS
- bool "Dynamic DVB minor allocation"
- depends on DVB_CORE
- default n
- help
- If you say Y here, the DVB subsystem will use dynamic minor
- allocation for any device that uses the DVB major number.
- This means that you can have more than 4 of a single type
- of device (like demuxes and frontends) per adapter, but udev
- will be required to manage the device nodes.
-
- If you are unsure about this, say N here.
-
-menuconfig DVB_CAPTURE_DRIVERS
- bool "DVB/ATSC adapters"
- depends on DVB_CORE
- default y
- ---help---
- Say Y to select Digital TV adapters
-
-if DVB_CAPTURE_DRIVERS && DVB_CORE
-
-comment "Supported SAA7146 based PCI Adapters"
- depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/ttpci/Kconfig"
-
-comment "Supported USB Adapters"
- depends on DVB_CORE && USB && I2C
-source "drivers/media/dvb/dvb-usb/Kconfig"
-source "drivers/media/dvb/ttusb-budget/Kconfig"
-source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/siano/Kconfig"
-
-comment "Supported FlexCopII (B2C2) Adapters"
- depends on DVB_CORE && (PCI || USB) && I2C
-source "drivers/media/dvb/b2c2/Kconfig"
-
-comment "Supported BT878 Adapters"
- depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/bt8xx/Kconfig"
-
-comment "Supported Pluto2 Adapters"
- depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/pluto2/Kconfig"
-
-comment "Supported SDMC DM1105 Adapters"
- depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/dm1105/Kconfig"
-
-comment "Supported FireWire (IEEE 1394) Adapters"
- depends on DVB_CORE && FIREWIRE
-source "drivers/media/dvb/firewire/Kconfig"
-
-comment "Supported Earthsoft PT1 Adapters"
- depends on DVB_CORE && PCI && I2C
-source "drivers/media/dvb/pt1/Kconfig"
-
-comment "Supported Mantis Adapters"
- depends on DVB_CORE && PCI && I2C
- source "drivers/media/dvb/mantis/Kconfig"
-
-comment "Supported nGene Adapters"
- depends on DVB_CORE && PCI && I2C
- source "drivers/media/dvb/ngene/Kconfig"
-
-comment "Supported ddbridge ('Octopus') Adapters"
- depends on DVB_CORE && PCI && I2C
- source "drivers/media/dvb/ddbridge/Kconfig"
-
-comment "Supported DVB Frontends"
- depends on DVB_CORE
-source "drivers/media/dvb/frontends/Kconfig"
-
-endif # DVB_CAPTURE_DRIVERS
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
deleted file mode 100644
index b2cefe637a64..000000000000
--- a/drivers/media/dvb/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Makefile for the kernel multimedia device drivers.
-#
-
-obj-y := dvb-core/ \
- frontends/ \
- ttpci/ \
- ttusb-dec/ \
- ttusb-budget/ \
- b2c2/ \
- bt8xx/ \
- dvb-usb/ \
- pluto2/ \
- siano/ \
- dm1105/ \
- pt1/ \
- mantis/ \
- ngene/ \
- ddbridge/
-
-obj-$(CONFIG_DVB_FIREDTV) += firewire/
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
deleted file mode 100644
index 9e5781400744..000000000000
--- a/drivers/media/dvb/b2c2/Kconfig
+++ /dev/null
@@ -1,45 +0,0 @@
-config DVB_B2C2_FLEXCOP
- tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
- depends on DVB_CORE && I2C
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_MT312 if !DVB_FE_CUSTOMISE
- select DVB_NXT200X if !DVB_FE_CUSTOMISE
- select DVB_STV0297 if !DVB_FE_CUSTOMISE
- select DVB_BCM3510 if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_S5H1420 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
- select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select DVB_CX24123 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
- help
- Support for the digital TV receiver chip made by B2C2 Inc. included in
- Technisats PCI cards and USB boxes.
-
- Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_PCI
- tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
- depends on DVB_B2C2_FLEXCOP && PCI && I2C
- help
- Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
-
- Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_USB
- tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
- depends on DVB_B2C2_FLEXCOP && USB && I2C
- help
- Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
-
- Say Y if you own such a device and want to use it.
-
-config DVB_B2C2_FLEXCOP_DEBUG
- bool "Enable debug for the B2C2 FlexCop drivers"
- depends on DVB_B2C2_FLEXCOP
- help
- Say Y if you want to enable the module option to control debug messages
- of all B2C2 FlexCop drivers.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
deleted file mode 100644
index 3d04a8dba99e..000000000000
--- a/drivers/media/dvb/b2c2/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
- flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
-
-ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
-b2c2-flexcop-objs += flexcop-dma.o
-endif
-
-b2c2-flexcop-pci-objs = flexcop-pci.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
-
-b2c2-flexcop-usb-objs = flexcop-usb.o
-obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
deleted file mode 100644
index 26c666dd3514..000000000000
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop-usb.c - covers the USB part
- * see flexcop.c for copyright information
- */
-#define FC_LOG_PREFIX "flexcop_usb"
-#include "flexcop-usb.h"
-#include "flexcop-common.h"
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
-
-/* debug */
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define dprintk(level,args...) \
- do { if ((debug & level)) printk(args); } while (0)
-
-#define debug_dump(b, l, method) do {\
- int i; \
- for (i = 0; i < l; i++) \
- method("%02x ", b[i]); \
- method("\n"); \
-} while (0)
-
-#define DEBSTATUS ""
-#else
-#define dprintk(level, args...)
-#define debug_dump(b, l, method)
-#define DEBSTATUS " (debugging is not enabled)"
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
- "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
-#undef DEBSTATUS
-
-#define deb_info(args...) dprintk(0x01, args)
-#define deb_ts(args...) dprintk(0x02, args)
-#define deb_ctrl(args...) dprintk(0x04, args)
-#define deb_i2c(args...) dprintk(0x08, args)
-#define deb_v8(args...) dprintk(0x10, args)
-
-/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
- * in the IBI address, to make the V8 code simpler.
- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
- * in general: 0000 0HHH 000L LL00
- * IBI ADDRESS FORMAT: RHHH BLLL
- *
- * where R is the read(1)/write(0) bit, B is the busy bit
- * and HHH and LLL are the two sets of three bits from the PCI address.
- */
-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
- (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
- (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
-
-/*
- * DKT 020228
- * - forget about this VENDOR_BUFFER_SIZE, read and write register
- * deal with DWORD or 4 bytes, that should be should from now on
- * - from now on, we don't support anything older than firm 1.00
- * I eliminated the write register as a 2 trip of writing hi word and lo word
- * and force this to write only 4 bytes at a time.
- * NOTE: this should work with all the firmware from 1.00 and newer
- */
-static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
-{
- struct flexcop_usb *fc_usb = fc->bus_specific;
- u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
- u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
- u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
- (read ? 0x80 : 0);
-
- int len = usb_control_msg(fc_usb->udev,
- read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
- request,
- request_type, /* 0xc0 read or 0x40 write */
- wAddress,
- 0,
- val,
- sizeof(u32),
- B2C2_WAIT_FOR_OPERATION_RDW * HZ);
-
- if (len != sizeof(u32)) {
- err("error while %s dword from %d (%d).", read ? "reading" :
- "writing", wAddress, wRegOffsPCI);
- return -EIO;
- }
- return 0;
-}
-/*
- * DKT 010817 - add support for V8 memory read/write and flash update
- */
-static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
- flexcop_usb_request_t req, u8 page, u16 wAddress,
- u8 *pbBuffer, u32 buflen)
-{
- u8 request_type = USB_TYPE_VENDOR;
- u16 wIndex;
- int nWaitTime, pipe, len;
- wIndex = page << 8;
-
- switch (req) {
- case B2C2_USB_READ_V8_MEM:
- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
- request_type |= USB_DIR_IN;
- pipe = B2C2_USB_CTRL_PIPE_IN;
- break;
- case B2C2_USB_WRITE_V8_MEM:
- wIndex |= pbBuffer[0];
- request_type |= USB_DIR_OUT;
- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
- pipe = B2C2_USB_CTRL_PIPE_OUT;
- break;
- case B2C2_USB_FLASH_BLOCK:
- request_type |= USB_DIR_OUT;
- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
- pipe = B2C2_USB_CTRL_PIPE_OUT;
- break;
- default:
- deb_info("unsupported request for v8_mem_req %x.\n", req);
- return -EINVAL;
- }
- deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
- wAddress, wIndex, buflen);
-
- len = usb_control_msg(fc_usb->udev, pipe,
- req,
- request_type,
- wAddress,
- wIndex,
- pbBuffer,
- buflen,
- nWaitTime * HZ);
-
- debug_dump(pbBuffer, len, deb_v8);
- return len == buflen ? 0 : -EIO;
-}
-
-#define bytes_left_to_read_on_page(paddr,buflen) \
- ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
- ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
-
-static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
- flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
- u32 addr, int extended, u8 *buf, u32 len)
-{
- int i,ret = 0;
- u16 wMax;
- u32 pagechunk = 0;
-
- switch(req) {
- case B2C2_USB_READ_V8_MEM:
- wMax = USB_MEM_READ_MAX;
- break;
- case B2C2_USB_WRITE_V8_MEM:
- wMax = USB_MEM_WRITE_MAX;
- break;
- case B2C2_USB_FLASH_BLOCK:
- wMax = USB_FLASH_MAX;
- break;
- default:
- return -EINVAL;
- break;
- }
- for (i = 0; i < len;) {
- pagechunk =
- wMax < bytes_left_to_read_on_page(addr, len) ?
- wMax :
- bytes_left_to_read_on_page(addr, len);
- deb_info("%x\n",
- (addr & V8_MEMORY_PAGE_MASK) |
- (V8_MEMORY_EXTENDED*extended));
-
- ret = flexcop_usb_v8_memory_req(fc_usb, req,
- page_start + (addr / V8_MEMORY_PAGE_SIZE),
- (addr & V8_MEMORY_PAGE_MASK) |
- (V8_MEMORY_EXTENDED*extended),
- &buf[i], pagechunk);
-
- if (ret < 0)
- return ret;
- addr += pagechunk;
- len -= pagechunk;
- }
- return 0;
-}
-
-static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
-{
- return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
- V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
- fc->dvb_adapter.proposed_mac, 6);
-}
-
-#if 0
-static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
- flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
- u16 buflen, u8 *pvBuffer)
-{
- u16 wValue;
- u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
- int nWaitTime = 2,
- pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
- wValue = (func << 8) | extra;
-
- len = usb_control_msg(fc_usb->udev,pipe,
- B2C2_USB_UTILITY,
- request_type,
- wValue,
- wIndex,
- pvBuffer,
- buflen,
- nWaitTime * HZ);
- return len == buflen ? 0 : -EIO;
-}
-#endif
-
-/* usb i2c stuff */
-static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
- flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
- u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
-{
- struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
- u16 wValue, wIndex;
- int nWaitTime,pipe,len;
- u8 request_type = USB_TYPE_VENDOR;
-
- switch (func) {
- case USB_FUNC_I2C_WRITE:
- case USB_FUNC_I2C_MULTIWRITE:
- case USB_FUNC_I2C_REPEATWRITE:
- /* DKT 020208 - add this to support special case of DiSEqC */
- case USB_FUNC_I2C_CHECKWRITE:
- pipe = B2C2_USB_CTRL_PIPE_OUT;
- nWaitTime = 2;
- request_type |= USB_DIR_OUT;
- break;
- case USB_FUNC_I2C_READ:
- case USB_FUNC_I2C_REPEATREAD:
- pipe = B2C2_USB_CTRL_PIPE_IN;
- nWaitTime = 2;
- request_type |= USB_DIR_IN;
- break;
- default:
- deb_info("unsupported function for i2c_req %x\n", func);
- return -EINVAL;
- }
- wValue = (func << 8) | (i2c->port << 4);
- wIndex = (chipaddr << 8 ) | addr;
-
- deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
- func, request_type, req,
- wValue & 0xff, wValue >> 8,
- wIndex & 0xff, wIndex >> 8);
-
- len = usb_control_msg(fc_usb->udev,pipe,
- req,
- request_type,
- wValue,
- wIndex,
- buf,
- buflen,
- nWaitTime * HZ);
- return len == buflen ? 0 : -EREMOTEIO;
-}
-
-/* actual bus specific access functions,
- make sure prototype are/will be equal to pci */
-static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
- flexcop_ibi_register reg)
-{
- flexcop_ibi_value val;
- val.raw = 0;
- flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
- return val;
-}
-
-static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
- flexcop_ibi_register reg, flexcop_ibi_value val)
-{
- return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
-}
-
-static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
- flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
-{
- if (op == FC_READ)
- return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
- USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
- else
- return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
- USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
-}
-
-static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
- u8 *buffer, int buffer_length)
-{
- u8 *b;
- int l;
-
- deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
- fc_usb->tmp_buffer_length, buffer_length);
-
- if (fc_usb->tmp_buffer_length > 0) {
- memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
- buffer_length);
- fc_usb->tmp_buffer_length += buffer_length;
- b = fc_usb->tmp_buffer;
- l = fc_usb->tmp_buffer_length;
- } else {
- b=buffer;
- l=buffer_length;
- }
-
- while (l >= 190) {
- if (*b == 0xff) {
- switch (*(b+1) & 0x03) {
- case 0x01: /* media packet */
- if (*(b+2) == 0x47)
- flexcop_pass_dmx_packets(
- fc_usb->fc_dev, b+2, 1);
- else
- deb_ts(
- "not ts packet %02x %02x %02x %02x \n",
- *(b+2), *(b+3),
- *(b+4), *(b+5));
- b += 190;
- l -= 190;
- break;
- default:
- deb_ts("wrong packet type\n");
- l = 0;
- break;
- }
- } else {
- deb_ts("wrong header\n");
- l = 0;
- }
- }
-
- if (l>0)
- memcpy(fc_usb->tmp_buffer, b, l);
- fc_usb->tmp_buffer_length = l;
-}
-
-static void flexcop_usb_urb_complete(struct urb *urb)
-{
- struct flexcop_usb *fc_usb = urb->context;
- int i;
-
- if (urb->actual_length > 0)
- deb_ts("urb completed, bufsize: %d actlen; %d\n",
- urb->transfer_buffer_length, urb->actual_length);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- if (urb->iso_frame_desc[i].status < 0) {
- err("iso frame descriptor %d has an error: %d\n", i,
- urb->iso_frame_desc[i].status);
- } else
- if (urb->iso_frame_desc[i].actual_length > 0) {
- deb_ts("passed %d bytes to the demux\n",
- urb->iso_frame_desc[i].actual_length);
-
- flexcop_usb_process_frame(fc_usb,
- urb->transfer_buffer +
- urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].actual_length);
- }
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
- usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
-{
- /* submit/kill iso packets */
- return 0;
-}
-
-static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
-{
- int i;
- for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
- if (fc_usb->iso_urb[i] != NULL) {
- deb_ts("unlinking/killing urb no. %d\n",i);
- usb_kill_urb(fc_usb->iso_urb[i]);
- usb_free_urb(fc_usb->iso_urb[i]);
- }
-
- if (fc_usb->iso_buffer != NULL)
- pci_free_consistent(NULL,
- fc_usb->buffer_size, fc_usb->iso_buffer,
- fc_usb->dma_addr);
-}
-
-static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
-{
- u16 frame_size = le16_to_cpu(
- fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
- int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
- frame_size, i, j, ret;
- int buffer_offset = 0;
-
- deb_ts("creating %d iso-urbs with %d frames "
- "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
- B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
-
- fc_usb->iso_buffer = pci_alloc_consistent(NULL,
- bufsize, &fc_usb->dma_addr);
- if (fc_usb->iso_buffer == NULL)
- return -ENOMEM;
-
- memset(fc_usb->iso_buffer, 0, bufsize);
- fc_usb->buffer_size = bufsize;
-
- /* creating iso urbs */
- for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
- fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
- GFP_ATOMIC);
- if (fc_usb->iso_urb[i] == NULL) {
- ret = -ENOMEM;
- goto urb_error;
- }
- }
-
- /* initialising and submitting iso urbs */
- for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
- int frame_offset = 0;
- struct urb *urb = fc_usb->iso_urb[i];
- deb_ts("initializing and submitting urb no. %d "
- "(buf_offset: %d).\n", i, buffer_offset);
-
- urb->dev = fc_usb->udev;
- urb->context = fc_usb;
- urb->complete = flexcop_usb_urb_complete;
- urb->pipe = B2C2_USB_DATA_PIPE;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->interval = 1;
- urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
- urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
- urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
-
- buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
- for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
- deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
- i, j, frame_offset);
- urb->iso_frame_desc[j].offset = frame_offset;
- urb->iso_frame_desc[j].length = frame_size;
- frame_offset += frame_size;
- }
-
- if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
- err("submitting urb %d failed with %d.", i, ret);
- goto urb_error;
- }
- deb_ts("submitted urb no. %d.\n",i);
- }
-
- /* SRAM */
- flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
- FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
- FC_SRAM_DEST_TARGET_WAN_USB);
- flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
- flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
- return 0;
-
-urb_error:
- flexcop_usb_transfer_exit(fc_usb);
- return ret;
-}
-
-static int flexcop_usb_init(struct flexcop_usb *fc_usb)
-{
- /* use the alternate setting with the larges buffer */
- usb_set_interface(fc_usb->udev,0,1);
- switch (fc_usb->udev->speed) {
- case USB_SPEED_LOW:
- err("cannot handle USB speed because it is too slow.");
- return -ENODEV;
- break;
- case USB_SPEED_FULL:
- info("running at FULL speed.");
- break;
- case USB_SPEED_HIGH:
- info("running at HIGH speed.");
- break;
- case USB_SPEED_UNKNOWN: /* fall through */
- default:
- err("cannot handle USB speed because it is unknown.");
- return -ENODEV;
- }
- usb_set_intfdata(fc_usb->uintf, fc_usb);
- return 0;
-}
-
-static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
-{
- usb_set_intfdata(fc_usb->uintf, NULL);
-}
-
-static int flexcop_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct flexcop_usb *fc_usb = NULL;
- struct flexcop_device *fc = NULL;
- int ret;
-
- if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
- err("out of memory\n");
- return -ENOMEM;
- }
-
- /* general flexcop init */
- fc_usb = fc->bus_specific;
- fc_usb->fc_dev = fc;
-
- fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
- fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
- fc->i2c_request = flexcop_usb_i2c_request;
- fc->get_mac_addr = flexcop_usb_get_mac_addr;
-
- fc->stream_control = flexcop_usb_stream_control;
-
- fc->pid_filtering = 1;
- fc->bus_type = FC_USB;
-
- fc->dev = &udev->dev;
- fc->owner = THIS_MODULE;
-
- /* bus specific part */
- fc_usb->udev = udev;
- fc_usb->uintf = intf;
- if ((ret = flexcop_usb_init(fc_usb)) != 0)
- goto err_kfree;
-
- /* init flexcop */
- if ((ret = flexcop_device_initialize(fc)) != 0)
- goto err_usb_exit;
-
- /* xfer init */
- if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
- goto err_fc_exit;
-
- info("%s successfully initialized and connected.", DRIVER_NAME);
- return 0;
-
-err_fc_exit:
- flexcop_device_exit(fc);
-err_usb_exit:
- flexcop_usb_exit(fc_usb);
-err_kfree:
- flexcop_device_kfree(fc);
- return ret;
-}
-
-static void flexcop_usb_disconnect(struct usb_interface *intf)
-{
- struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
- flexcop_usb_transfer_exit(fc_usb);
- flexcop_device_exit(fc_usb->fc_dev);
- flexcop_usb_exit(fc_usb);
- flexcop_device_kfree(fc_usb->fc_dev);
- info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
-}
-
-static struct usb_device_id flexcop_usb_table [] = {
- { USB_DEVICE(0x0af7, 0x0101) },
- { }
-};
-MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver flexcop_usb_driver = {
- .name = "b2c2_flexcop_usb",
- .probe = flexcop_usb_probe,
- .disconnect = flexcop_usb_disconnect,
- .id_table = flexcop_usb_table,
-};
-
-module_usb_driver(flexcop_usb_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
deleted file mode 100644
index b1e8c99f469b..000000000000
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
- * flexcop.c - main module part
- * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
- * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
- *
- * Acknowledgements:
- * John Jurrius from BBTI, Inc. for extensive support
- * with code examples and data books
- * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
- *
- * Contributions to the skystar2-driver have been done by
- * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
- * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
- * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
- * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
- * filtering)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- */
-
-#include "flexcop.h"
-
-#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
-
-#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define DEBSTATUS ""
-#else
-#define DEBSTATUS " (debugging is not enabled)"
-#endif
-
-int b2c2_flexcop_debug;
-module_param_named(debug, b2c2_flexcop_debug, int, 0644);
-MODULE_PARM_DESC(debug,
- "set debug level (1=info,2=tuner,4=i2c,8=ts,"
- "16=sram,32=reg (|-able))."
- DEBSTATUS);
-#undef DEBSTATUS
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* global zero for ibi values */
-flexcop_ibi_value ibi_zero;
-
-static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct flexcop_device *fc = dvbdmxfeed->demux->priv;
- return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
-}
-
-static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct flexcop_device *fc = dvbdmxfeed->demux->priv;
- return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
-}
-
-static int flexcop_dvb_init(struct flexcop_device *fc)
-{
- int ret = dvb_register_adapter(&fc->dvb_adapter,
- "FlexCop Digital TV device", fc->owner,
- fc->dev, adapter_nr);
- if (ret < 0) {
- err("error registering DVB adapter");
- return ret;
- }
- fc->dvb_adapter.priv = fc;
-
- fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
- | DMX_MEMORY_BASED_FILTERING);
- fc->demux.priv = fc;
- fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
- fc->demux.start_feed = flexcop_dvb_start_feed;
- fc->demux.stop_feed = flexcop_dvb_stop_feed;
- fc->demux.write_to_decoder = NULL;
-
- ret = dvb_dmx_init(&fc->demux);
- if (ret < 0) {
- err("dvb_dmx failed: error %d", ret);
- goto err_dmx;
- }
-
- fc->hw_frontend.source = DMX_FRONTEND_0;
-
- fc->dmxdev.filternum = fc->demux.feednum;
- fc->dmxdev.demux = &fc->demux.dmx;
- fc->dmxdev.capabilities = 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;
- }
-
- 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;
- 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;
- }
-
- 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;
- }
-
- 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:
- fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
-err_dmx_add_hw_frontend:
- dvb_dmxdev_release(&fc->dmxdev);
-err_dmx_dev:
- dvb_dmx_release(&fc->demux);
-err_dmx:
- dvb_unregister_adapter(&fc->dvb_adapter);
- return ret;
-}
-
-static void flexcop_dvb_exit(struct flexcop_device *fc)
-{
- if (fc->init_state & FC_STATE_DVB_INIT) {
- dvb_net_release(&fc->dvbnet);
-
- fc->demux.dmx.close(&fc->demux.dmx);
- fc->demux.dmx.remove_frontend(&fc->demux.dmx,
- &fc->mem_frontend);
- fc->demux.dmx.remove_frontend(&fc->demux.dmx,
- &fc->hw_frontend);
- dvb_dmxdev_release(&fc->dmxdev);
- dvb_dmx_release(&fc->demux);
- dvb_unregister_adapter(&fc->dvb_adapter);
- deb_info("deinitialized dvb stuff\n");
- }
- fc->init_state &= ~FC_STATE_DVB_INIT;
-}
-
-/* these methods are necessary to achieve the long-term-goal of hiding the
- * struct flexcop_device from the bus-parts */
-void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
-{
- dvb_dmx_swfilter(&fc->demux, buf, len);
-}
-EXPORT_SYMBOL(flexcop_pass_dmx_data);
-
-void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
-{
- dvb_dmx_swfilter_packets(&fc->demux, buf, no);
-}
-EXPORT_SYMBOL(flexcop_pass_dmx_packets);
-
-static void flexcop_reset(struct flexcop_device *fc)
-{
- flexcop_ibi_value v210, v204;
-
- /* reset the flexcop itself */
- fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
-
- v210.raw = 0;
- v210.sw_reset_210.reset_block_000 = 1;
- v210.sw_reset_210.reset_block_100 = 1;
- v210.sw_reset_210.reset_block_200 = 1;
- v210.sw_reset_210.reset_block_300 = 1;
- v210.sw_reset_210.reset_block_400 = 1;
- v210.sw_reset_210.reset_block_500 = 1;
- v210.sw_reset_210.reset_block_600 = 1;
- v210.sw_reset_210.reset_block_700 = 1;
- v210.sw_reset_210.Block_reset_enable = 0xb2;
- v210.sw_reset_210.Special_controls = 0xc259;
- fc->write_ibi_reg(fc,sw_reset_210,v210);
- msleep(1);
-
- /* reset the periphical devices */
-
- v204 = fc->read_ibi_reg(fc,misc_204);
- v204.misc_204.Per_reset_sig = 0;
- fc->write_ibi_reg(fc,misc_204,v204);
- msleep(1);
- v204.misc_204.Per_reset_sig = 1;
- fc->write_ibi_reg(fc,misc_204,v204);
-}
-
-void flexcop_reset_block_300(struct flexcop_device *fc)
-{
- flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
- v210 = fc->read_ibi_reg(fc, sw_reset_210);
-
- deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
- fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
-
- v210.sw_reset_210.reset_block_300 = 1;
- v210.sw_reset_210.Block_reset_enable = 0xb2;
-
- fc->write_ibi_reg(fc,sw_reset_210,v210);
- fc->write_ibi_reg(fc,ctrl_208,v208_save);
-}
-
-struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
-{
- void *bus;
- struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
- GFP_KERNEL);
- if (!fc) {
- err("no memory");
- return NULL;
- }
-
- bus = kzalloc(bus_specific_len, GFP_KERNEL);
- if (!bus) {
- err("no memory");
- kfree(fc);
- return NULL;
- }
-
- fc->bus_specific = bus;
-
- return fc;
-}
-EXPORT_SYMBOL(flexcop_device_kmalloc);
-
-void flexcop_device_kfree(struct flexcop_device *fc)
-{
- kfree(fc->bus_specific);
- kfree(fc);
-}
-EXPORT_SYMBOL(flexcop_device_kfree);
-
-int flexcop_device_initialize(struct flexcop_device *fc)
-{
- int ret;
- ibi_zero.raw = 0;
-
- flexcop_reset(fc);
- flexcop_determine_revision(fc);
- flexcop_sram_init(fc);
- flexcop_hw_filter_init(fc);
- flexcop_smc_ctrl(fc, 0);
-
- ret = flexcop_dvb_init(fc);
- if (ret)
- goto error;
-
- /* i2c has to be done before doing EEProm stuff -
- * because the EEProm is accessed via i2c */
- ret = flexcop_i2c_init(fc);
- if (ret)
- goto error;
-
- /* do the MAC address reading after initializing the dvb_adapter */
- if (fc->get_mac_addr(fc, 0) == 0) {
- u8 *b = fc->dvb_adapter.proposed_mac;
- info("MAC address = %pM", b);
- flexcop_set_mac_filter(fc,b);
- flexcop_mac_filter_ctrl(fc,1);
- } else
- warn("reading of MAC address failed.\n");
-
- ret = flexcop_frontend_init(fc);
- if (ret)
- goto error;
-
- flexcop_device_name(fc,"initialization of","complete");
- return 0;
-
-error:
- flexcop_device_exit(fc);
- return ret;
-}
-EXPORT_SYMBOL(flexcop_device_initialize);
-
-void flexcop_device_exit(struct flexcop_device *fc)
-{
- flexcop_frontend_exit(fc);
- flexcop_i2c_exit(fc);
- flexcop_dvb_exit(fc);
-}
-EXPORT_SYMBOL(flexcop_device_exit);
-
-static int flexcop_module_init(void)
-{
- info(DRIVER_NAME " loaded successfully");
- return 0;
-}
-
-static void flexcop_module_cleanup(void)
-{
- info(DRIVER_NAME " unloaded successfully");
-}
-
-module_init(flexcop_module_init);
-module_exit(flexcop_module_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
deleted file mode 100644
index 8668e634c7ec..000000000000
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-config DVB_BT8XX
- tristate "BT8xx based PCI cards"
- depends on DVB_CORE && PCI && I2C && VIDEO_BT848
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_SP887X if !DVB_FE_CUSTOMISE
- select DVB_NXT6000 if !DVB_FE_CUSTOMISE
- select DVB_CX24110 if !DVB_FE_CUSTOMISE
- select DVB_OR51211 if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- help
- Support for PCI cards based on the Bt8xx PCI bridge. Examples are
- the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
- the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
- some AVerMedia cards.
-
- Since these cards have no MPEG decoder onboard, they transmit
- only compressed MPEG data over the PCI bus, so you need
- an external software decoder to watch TV on your computer.
-
- Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
deleted file mode 100644
index 0713b3af2050..000000000000
--- a/drivers/media/dvb/bt8xx/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/video/bt8xx
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
deleted file mode 100644
index 66f52f116b60..000000000000
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- CA-driver for TwinHan DST Frontend/Card
-
- Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/dvb/ca.h>
-#include "dvbdev.h"
-#include "dvb_frontend.h"
-#include "dst_ca.h"
-#include "dst_common.h"
-
-#define DST_CA_ERROR 0
-#define DST_CA_NOTICE 1
-#define DST_CA_INFO 2
-#define DST_CA_DEBUG 3
-
-#define dprintk(x, y, z, format, arg...) do { \
- if (z) { \
- if ((x > DST_CA_ERROR) && (x > y)) \
- printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
- else if ((x > DST_CA_NOTICE) && (x > y)) \
- printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
- else if ((x > DST_CA_INFO) && (x > y)) \
- printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
- else if ((x > DST_CA_DEBUG) && (x > y)) \
- printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
- } else { \
- if (x > y) \
- printk(format, ## arg); \
- } \
-} while(0)
-
-
-static DEFINE_MUTEX(dst_ca_mutex);
-static unsigned int verbose = 5;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
-
-/* Need some more work */
-static int ca_set_slot_descr(void)
-{
- /* We could make this more graceful ? */
- return -EOPNOTSUPP;
-}
-
-/* Need some more work */
-static int ca_set_pid(void)
-{
- /* We could make this more graceful ? */
- return -EOPNOTSUPP;
-}
-
-static void put_command_and_length(u8 *data, int command, int length)
-{
- data[0] = (command >> 16) & 0xff;
- data[1] = (command >> 8) & 0xff;
- data[2] = command & 0xff;
- data[3] = length;
-}
-
-static void put_checksum(u8 *check_string, int length)
-{
- dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
- dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
- check_string[length] = dst_check_sum (check_string, length);
- dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
-}
-
-static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
-{
- u8 reply;
-
- mutex_lock(&state->dst_mutex);
- dst_comm_init(state);
- msleep(65);
-
- if (write_dst(state, data, len)) {
- dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
- dst_error_recovery(state);
- goto error;
- }
- if ((dst_pio_disable(state)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
- goto error;
- }
- if (read_dst(state, &reply, GET_ACK) < 0) {
- dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
- dst_error_recovery(state);
- goto error;
- }
- if (read) {
- if (! dst_wait_dst_ready(state, LONG_DELAY)) {
- dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
- goto error;
- }
- if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
- dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
- dst_error_recovery(state);
- goto error;
- }
- }
- mutex_unlock(&state->dst_mutex);
- return 0;
-
-error:
- mutex_unlock(&state->dst_mutex);
- return -EIO;
-}
-
-
-static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
-{
- u8 dst_ca_comm_err = 0;
-
- while (dst_ca_comm_err < RETRIES) {
- dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
- if (dst_ci_command(state, data, ca_string, len, read)) { // If error
- dst_error_recovery(state);
- dst_ca_comm_err++; // work required here.
- } else {
- break;
- }
- }
-
- if(dst_ca_comm_err == RETRIES)
- return -1;
-
- return 0;
-}
-
-
-
-static int ca_get_app_info(struct dst_state *state)
-{
- int length, str_length;
- static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
-
- put_checksum(&command[0], command[0]);
- if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
- return -1;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
- dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
- dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
- state->messages[7], (state->messages[8] << 8) | state->messages[9],
- (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
- dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
-
- // Transform dst message to correct application_info message
- length = state->messages[5];
- str_length = length - 6;
- if (str_length < 0) {
- str_length = 0;
- dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
- }
-
- // First, the command and length fields
- put_command_and_length(&state->messages[0], CA_APP_INFO, length);
-
- // Copy application_type, application_manufacturer and manufacturer_code
- memcpy(&state->messages[4], &state->messages[7], 5);
-
- // Set string length and copy string
- state->messages[9] = str_length;
- memcpy(&state->messages[10], &state->messages[12], str_length);
-
- return 0;
-}
-
-static int ca_get_ca_info(struct dst_state *state)
-{
- int srcPtr, dstPtr, i, num_ids;
- static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
- const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
-
- put_checksum(&slot_command[0], slot_command[0]);
- if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
- return -1;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
-
- // Print raw data
- dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
- for (i = 0; i < state->messages[0] + 1; i++) {
- dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
- }
- dprintk(verbose, DST_CA_INFO, 0, "]\n");
-
- // Set the command and length of the output
- num_ids = state->messages[in_num_ids_pos];
- if (num_ids >= 100) {
- num_ids = 100;
- dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
- }
- put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
-
- dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
- srcPtr = in_system_id_pos;
- dstPtr = out_system_id_pos;
- for(i = 0; i < num_ids; i++) {
- dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
- // Append to output
- state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
- state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
- srcPtr += 2;
- dstPtr += 2;
- }
- dprintk(verbose, DST_CA_INFO, 0, "]\n");
-
- return 0;
-}
-
-static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
-{
- int i;
- u8 slot_cap[256];
- static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
-
- put_checksum(&slot_command[0], slot_command[0]);
- if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
- return -1;
- }
- dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
-
- /* Will implement the rest soon */
-
- dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
- dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
- for (i = 0; i < slot_cap[0] + 1; i++)
- dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
- dprintk(verbose, DST_CA_INFO, 0, "\n");
-
- p_ca_caps->slot_num = 1;
- p_ca_caps->slot_type = 1;
- p_ca_caps->descr_num = slot_cap[7];
- p_ca_caps->descr_type = 1;
-
- if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
- return -EFAULT;
-
- return 0;
-}
-
-/* Need some more work */
-static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
- return -EOPNOTSUPP;
-}
-
-
-static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
-{
- int i;
- static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
-
- u8 *slot_info = state->messages;
-
- put_checksum(&slot_command[0], 7);
- if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
- return -1;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
-
- /* Will implement the rest soon */
-
- dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
- dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
- for (i = 0; i < 8; i++)
- dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
- dprintk(verbose, DST_CA_INFO, 0, "\n");
-
- if (slot_info[4] & 0x80) {
- p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
- p_ca_slot_info->num = 1;
- p_ca_slot_info->type = CA_CI;
- } else if (slot_info[4] & 0x40) {
- p_ca_slot_info->flags = CA_CI_MODULE_READY;
- p_ca_slot_info->num = 1;
- p_ca_slot_info->type = CA_CI;
- } else
- p_ca_slot_info->flags = 0;
-
- if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
- u8 i = 0;
- u32 command = 0;
-
- if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
- return -EFAULT;
-
- if (p_ca_message->msg) {
- dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
-
- for (i = 0; i < 3; i++) {
- command = command | p_ca_message->msg[i];
- if (i < 2)
- command = command << 8;
- }
- dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
-
- switch (command) {
- case CA_APP_INFO:
- memcpy(p_ca_message->msg, state->messages, 128);
- if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
- return -EFAULT;
- break;
- case CA_INFO:
- memcpy(p_ca_message->msg, state->messages, 128);
- if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
- return -EFAULT;
- break;
- }
- }
-
- return 0;
-}
-
-static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
-{
- if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
- hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
- hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
- } else {
- if (length > 247) {
- dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
- return -1;
- }
- hw_buffer->msg[0] = (length & 0xff) + 7;
- hw_buffer->msg[1] = 0x40;
- hw_buffer->msg[2] = 0x03;
- hw_buffer->msg[3] = 0x00;
- hw_buffer->msg[4] = 0x03;
- hw_buffer->msg[5] = length & 0xff;
- hw_buffer->msg[6] = 0x00;
-
- /*
- * Need to compute length for EN50221 section 8.3.2, for the time being
- * assuming 8.3.2 is not applicable
- */
- memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
- }
-
- return 0;
-}
-
-static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
-{
- if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
- dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
- rdc_reset_state(state);
- return -1;
- }
- dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
-
- return 0;
-}
-
-static u32 asn_1_decode(u8 *asn_1_array)
-{
- u8 length_field = 0, word_count = 0, count = 0;
- u32 length = 0;
-
- length_field = asn_1_array[0];
- dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
- if (length_field < 0x80) {
- length = length_field & 0x7f;
- dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
- } else {
- word_count = length_field & 0x7f;
- for (count = 0; count < word_count; count++) {
- length = length << 8;
- length += asn_1_array[count + 1];
- dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
- }
- }
- return length;
-}
-
-static int debug_string(u8 *msg, u32 length, u32 offset)
-{
- u32 i;
-
- dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
- for (i = offset; i < length; i++)
- dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
- dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
-
- return 0;
-}
-
-
-static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
-{
- u32 length = 0;
- u8 tag_length = 8;
-
- length = asn_1_decode(&p_ca_message->msg[3]);
- dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
- debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */
-
- memset(hw_buffer->msg, '\0', length);
- handle_dst_tag(state, p_ca_message, hw_buffer, length);
- put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
-
- debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */
- write_to_8820(state, hw_buffer, (length + tag_length), reply);
-
- return 0;
-}
-
-
-/* Board supports CA PMT reply ? */
-static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
-{
- int ca_pmt_reply_test = 0;
-
- /* Do test board */
- /* Not there yet but soon */
-
- /* CA PMT Reply capable */
- if (ca_pmt_reply_test) {
- if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
- return -1;
- }
-
- /* Process CA PMT Reply */
- /* will implement soon */
- dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
- }
- /* CA PMT Reply not capable */
- if (!ca_pmt_reply_test) {
- if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
- return -1;
- }
- dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
- /* put a dummy message */
-
- }
- return 0;
-}
-
-static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
-{
- int i = 0;
-
- u32 command = 0;
- struct ca_msg *hw_buffer;
- int result = 0;
-
- if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- dprintk(verbose, DST_CA_DEBUG, 1, " ");
-
- if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
- result = -EFAULT;
- goto free_mem_and_exit;
- }
-
-
- if (p_ca_message->msg) {
- /* EN50221 tag */
- command = 0;
-
- for (i = 0; i < 3; i++) {
- command = command | p_ca_message->msg[i];
- if (i < 2)
- command = command << 8;
- }
- dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
-
- switch (command) {
- case CA_PMT:
- dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
- if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
- break;
- case CA_PMT_REPLY:
- dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
- /* Have to handle the 2 basic types of cards here */
- if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
- break;
- case CA_APP_INFO_ENQUIRY: // only for debugging
- dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
-
- if ((ca_get_app_info(state)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
- break;
- case CA_INFO_ENQUIRY:
- dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
-
- if ((ca_get_ca_info(state)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
- break;
- }
- }
-free_mem_and_exit:
- kfree (hw_buffer);
-
- return result;
-}
-
-static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
-{
- struct dvb_device *dvbdev;
- struct dst_state *state;
- struct ca_slot_info *p_ca_slot_info;
- struct ca_caps *p_ca_caps;
- struct ca_msg *p_ca_message;
- void __user *arg = (void __user *)ioctl_arg;
- int result = 0;
-
- mutex_lock(&dst_ca_mutex);
- dvbdev = file->private_data;
- state = (struct dst_state *)dvbdev->priv;
- p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
- p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
- p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
- if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- result = -ENOMEM;
- goto free_mem_and_exit;
- }
-
- /* We have now only the standard ioctl's, the driver is upposed to handle internals. */
- switch (cmd) {
- case CA_SEND_MSG:
- dprintk(verbose, DST_CA_INFO, 1, " Sending message");
- if ((ca_send_message(state, p_ca_message, arg)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- break;
- case CA_GET_MSG:
- dprintk(verbose, DST_CA_INFO, 1, " Getting message");
- if ((ca_get_message(state, p_ca_message, arg)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
- break;
- case CA_RESET:
- dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
- dst_error_bailout(state);
- msleep(4000);
- break;
- case CA_GET_SLOT_INFO:
- dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
- if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
- break;
- case CA_GET_CAP:
- dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
- if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
- break;
- case CA_GET_DESCR_INFO:
- dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
- if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
- break;
- case CA_SET_DESCR:
- dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
- if ((ca_set_slot_descr()) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
- break;
- case CA_SET_PID:
- dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
- if ((ca_set_pid()) < 0) {
- dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
- result = -1;
- goto free_mem_and_exit;
- }
- dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
- default:
- result = -EOPNOTSUPP;
- };
- free_mem_and_exit:
- kfree (p_ca_message);
- kfree (p_ca_slot_info);
- kfree (p_ca_caps);
-
- mutex_unlock(&dst_ca_mutex);
- return result;
-}
-
-static int dst_ca_open(struct inode *inode, struct file *file)
-{
- dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
- try_module_get(THIS_MODULE);
-
- return 0;
-}
-
-static int dst_ca_release(struct inode *inode, struct file *file)
-{
- dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
- module_put(THIS_MODULE);
-
- return 0;
-}
-
-static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
-{
- ssize_t bytes_read = 0;
-
- dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
-
- return bytes_read;
-}
-
-static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
-{
- dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
-
- return 0;
-}
-
-static const struct file_operations dst_ca_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = dst_ca_ioctl,
- .open = dst_ca_open,
- .release = dst_ca_release,
- .read = dst_ca_read,
- .write = dst_ca_write,
- .llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_ca = {
- .priv = NULL,
- .users = 1,
- .readers = 1,
- .writers = 1,
- .fops = &dst_ca_fops
-};
-
-struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
-{
- struct dvb_device *dvbdev;
-
- dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
- if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
- dst->dst_ca = dvbdev;
- return dst->dst_ca;
- }
-
- return NULL;
-}
-
-EXPORT_SYMBOL(dst_ca_attach);
-
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig
deleted file mode 100644
index d099e1a12c85..000000000000
--- a/drivers/media/dvb/ddbridge/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config DVB_DDBRIDGE
- tristate "Digital Devices bridge support"
- depends on DVB_CORE && PCI && I2C
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_STV6110x if !DVB_FE_CUSTOMISE
- select DVB_STV090x if !DVB_FE_CUSTOMISE
- select DVB_DRXK if !DVB_FE_CUSTOMISE
- select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
- ---help---
- Support for cards with the Digital Devices PCI express bridge:
- - Octopus PCIe Bridge
- - Octopus mini PCIe Bridge
- - Octopus LE
- - DuoFlex S2 Octopus
- - DuoFlex CT Octopus
- - cineS2(v6)
-
- Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile
deleted file mode 100644
index 38019bafb862..000000000000
--- a/drivers/media/dvb/ddbridge/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the ddbridge device driver
-#
-
-ddbridge-objs := ddbridge-core.o
-
-obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
deleted file mode 100644
index f3de0a4d63f2..000000000000
--- a/drivers/media/dvb/dm1105/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-config DVB_DM1105
- tristate "SDMC DM1105 based PCI cards"
- depends on DVB_CORE && PCI && I2C
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_STV0288 if !DVB_FE_CUSTOMISE
- select DVB_STB6000 if !DVB_FE_CUSTOMISE
- select DVB_CX24116 if !DVB_FE_CUSTOMISE
- select DVB_SI21XX if !DVB_FE_CUSTOMISE
- select DVB_DS3000 if !DVB_FE_CUSTOMISE
- depends on RC_CORE
- help
- Support for cards based on the SDMC DM1105 PCI chip like
- DvbWorld 2002
-
- Since these cards have no MPEG decoder onboard, they transmit
- only compressed MPEG data over the PCI bus, so you need
- an external software decoder to watch TV on your computer.
-
- Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile
deleted file mode 100644
index 95a008b71fe5..000000000000
--- a/drivers/media/dvb/dm1105/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_DM1105) += dm1105.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
deleted file mode 100644
index 73970cd97af1..000000000000
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- * dmxdev.c - DVB demultiplexer device
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- * for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/ioctl.h>
-#include <linux/wait.h>
-#include <asm/uaccess.h>
-#include "dmxdev.h"
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk if (debug) printk
-
-static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
- const u8 *src, size_t len)
-{
- ssize_t free;
-
- if (!len)
- return 0;
- if (!buf->data)
- return 0;
-
- free = dvb_ringbuffer_free(buf);
- if (len > free) {
- dprintk("dmxdev: buffer overflow\n");
- return -EOVERFLOW;
- }
-
- return dvb_ringbuffer_write(buf, src, len);
-}
-
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
- int non_blocking, char __user *buf,
- size_t count, loff_t *ppos)
-{
- size_t todo;
- ssize_t avail;
- ssize_t ret = 0;
-
- if (!src->data)
- return 0;
-
- if (src->error) {
- ret = src->error;
- dvb_ringbuffer_flush(src);
- return ret;
- }
-
- for (todo = count; todo > 0; todo -= ret) {
- if (non_blocking && dvb_ringbuffer_empty(src)) {
- ret = -EWOULDBLOCK;
- break;
- }
-
- ret = wait_event_interruptible(src->queue,
- !dvb_ringbuffer_empty(src) ||
- (src->error != 0));
- if (ret < 0)
- break;
-
- if (src->error) {
- ret = src->error;
- dvb_ringbuffer_flush(src);
- break;
- }
-
- avail = dvb_ringbuffer_avail(src);
- if (avail > todo)
- avail = todo;
-
- ret = dvb_ringbuffer_read_user(src, buf, avail);
- if (ret < 0)
- break;
-
- buf += ret;
- }
-
- return (count - todo) ? (count - todo) : ret;
-}
-
-static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
-{
- struct list_head *head, *pos;
-
- head = demux->get_frontends(demux);
- if (!head)
- return NULL;
- list_for_each(pos, head)
- if (DMX_FE_ENTRY(pos)->source == type)
- return DMX_FE_ENTRY(pos);
-
- return NULL;
-}
-
-static int dvb_dvr_open(struct inode *inode, struct file *file)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
- struct dmx_frontend *front;
-
- dprintk("function : %s\n", __func__);
-
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- if (dmxdev->exit) {
- mutex_unlock(&dmxdev->mutex);
- return -ENODEV;
- }
-
- if ((file->f_flags & O_ACCMODE) == O_RDWR) {
- if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
- mutex_unlock(&dmxdev->mutex);
- return -EOPNOTSUPP;
- }
- }
-
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- void *mem;
- if (!dvbdev->readers) {
- mutex_unlock(&dmxdev->mutex);
- return -EBUSY;
- }
- mem = vmalloc(DVR_BUFFER_SIZE);
- if (!mem) {
- mutex_unlock(&dmxdev->mutex);
- return -ENOMEM;
- }
- dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
- dvbdev->readers--;
- }
-
- if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
- dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
-
- if (!dmxdev->demux->write) {
- mutex_unlock(&dmxdev->mutex);
- return -EOPNOTSUPP;
- }
-
- front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
-
- if (!front) {
- mutex_unlock(&dmxdev->mutex);
- return -EINVAL;
- }
- dmxdev->demux->disconnect_frontend(dmxdev->demux);
- dmxdev->demux->connect_frontend(dmxdev->demux, front);
- }
- dvbdev->users++;
- mutex_unlock(&dmxdev->mutex);
- return 0;
-}
-
-static int dvb_dvr_release(struct inode *inode, struct file *file)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
-
- mutex_lock(&dmxdev->mutex);
-
- if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
- dmxdev->demux->disconnect_frontend(dmxdev->demux);
- dmxdev->demux->connect_frontend(dmxdev->demux,
- dmxdev->dvr_orig_fe);
- }
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- dvbdev->readers++;
- if (dmxdev->dvr_buffer.data) {
- void *mem = dmxdev->dvr_buffer.data;
- mb();
- spin_lock_irq(&dmxdev->lock);
- dmxdev->dvr_buffer.data = NULL;
- spin_unlock_irq(&dmxdev->lock);
- vfree(mem);
- }
- }
- /* TODO */
- dvbdev->users--;
- if (dvbdev->users == 1 && dmxdev->exit == 1) {
- fops_put(file->f_op);
- file->f_op = NULL;
- mutex_unlock(&dmxdev->mutex);
- wake_up(&dvbdev->wait_queue);
- } else
- mutex_unlock(&dmxdev->mutex);
-
- return 0;
-}
-
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
- int ret;
-
- if (!dmxdev->demux->write)
- return -EOPNOTSUPP;
- if ((file->f_flags & O_ACCMODE) != O_WRONLY)
- return -EINVAL;
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- if (dmxdev->exit) {
- mutex_unlock(&dmxdev->mutex);
- return -ENODEV;
- }
- ret = dmxdev->demux->write(dmxdev->demux, buf, count);
- mutex_unlock(&dmxdev->mutex);
- return ret;
-}
-
-static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
-
- if (dmxdev->exit)
- return -ENODEV;
-
- return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
-}
-
-static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
- unsigned long size)
-{
- struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
- void *newmem;
- void *oldmem;
-
- dprintk("function : %s\n", __func__);
-
- if (buf->size == size)
- return 0;
- if (!size)
- return -EINVAL;
-
- newmem = vmalloc(size);
- if (!newmem)
- return -ENOMEM;
-
- oldmem = buf->data;
-
- spin_lock_irq(&dmxdev->lock);
- buf->data = newmem;
- buf->size = size;
-
- /* reset and not flush in case the buffer shrinks */
- dvb_ringbuffer_reset(buf);
- spin_unlock_irq(&dmxdev->lock);
-
- vfree(oldmem);
-
- return 0;
-}
-
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
- *dmxdevfilter, int state)
-{
- spin_lock_irq(&dmxdevfilter->dev->lock);
- dmxdevfilter->state = state;
- spin_unlock_irq(&dmxdevfilter->dev->lock);
-}
-
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
- unsigned long size)
-{
- struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
- void *newmem;
- void *oldmem;
-
- if (buf->size == size)
- return 0;
- if (!size)
- return -EINVAL;
- if (dmxdevfilter->state >= DMXDEV_STATE_GO)
- return -EBUSY;
-
- newmem = vmalloc(size);
- if (!newmem)
- return -ENOMEM;
-
- oldmem = buf->data;
-
- spin_lock_irq(&dmxdevfilter->dev->lock);
- buf->data = newmem;
- buf->size = size;
-
- /* reset and not flush in case the buffer shrinks */
- dvb_ringbuffer_reset(buf);
- spin_unlock_irq(&dmxdevfilter->dev->lock);
-
- vfree(oldmem);
-
- return 0;
-}
-
-static void dvb_dmxdev_filter_timeout(unsigned long data)
-{
- struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
-
- dmxdevfilter->buffer.error = -ETIMEDOUT;
- spin_lock_irq(&dmxdevfilter->dev->lock);
- dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
- spin_unlock_irq(&dmxdevfilter->dev->lock);
- wake_up(&dmxdevfilter->buffer.queue);
-}
-
-static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
-{
- struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
-
- del_timer(&dmxdevfilter->timer);
- if (para->timeout) {
- dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
- dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
- dmxdevfilter->timer.expires =
- jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
- add_timer(&dmxdevfilter->timer);
- }
-}
-
-static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
- const u8 *buffer2, size_t buffer2_len,
- struct dmx_section_filter *filter,
- enum dmx_success success)
-{
- struct dmxdev_filter *dmxdevfilter = filter->priv;
- int ret;
-
- if (dmxdevfilter->buffer.error) {
- wake_up(&dmxdevfilter->buffer.queue);
- return 0;
- }
- spin_lock(&dmxdevfilter->dev->lock);
- if (dmxdevfilter->state != DMXDEV_STATE_GO) {
- spin_unlock(&dmxdevfilter->dev->lock);
- return 0;
- }
- del_timer(&dmxdevfilter->timer);
- dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
- buffer1[0], buffer1[1],
- buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
- ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
- buffer1_len);
- if (ret == buffer1_len) {
- ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
- buffer2_len);
- }
- if (ret < 0) {
- dvb_ringbuffer_flush(&dmxdevfilter->buffer);
- dmxdevfilter->buffer.error = ret;
- }
- if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
- dmxdevfilter->state = DMXDEV_STATE_DONE;
- spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&dmxdevfilter->buffer.queue);
- return 0;
-}
-
-static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
- const u8 *buffer2, size_t buffer2_len,
- struct dmx_ts_feed *feed,
- enum dmx_success success)
-{
- struct dmxdev_filter *dmxdevfilter = feed->priv;
- struct dvb_ringbuffer *buffer;
- int ret;
-
- spin_lock(&dmxdevfilter->dev->lock);
- if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
- spin_unlock(&dmxdevfilter->dev->lock);
- return 0;
- }
-
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
- || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
- buffer = &dmxdevfilter->buffer;
- else
- buffer = &dmxdevfilter->dev->dvr_buffer;
- if (buffer->error) {
- spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&buffer->queue);
- return 0;
- }
- ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
- if (ret == buffer1_len)
- ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
- if (ret < 0) {
- dvb_ringbuffer_flush(buffer);
- buffer->error = ret;
- }
- spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&buffer->queue);
- return 0;
-}
-
-/* stop feed but only mark the specified filter as stopped (state set) */
-static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
-{
- struct dmxdev_feed *feed;
-
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
- switch (dmxdevfilter->type) {
- case DMXDEV_TYPE_SEC:
- del_timer(&dmxdevfilter->timer);
- dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
- break;
- case DMXDEV_TYPE_PES:
- list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
- feed->ts->stop_filtering(feed->ts);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/* start feed associated with the specified filter */
-static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
-{
- struct dmxdev_feed *feed;
- int ret;
-
- dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
-
- switch (filter->type) {
- case DMXDEV_TYPE_SEC:
- return filter->feed.sec->start_filtering(filter->feed.sec);
- case DMXDEV_TYPE_PES:
- list_for_each_entry(feed, &filter->feed.ts, next) {
- ret = feed->ts->start_filtering(feed->ts);
- if (ret < 0) {
- dvb_dmxdev_feed_stop(filter);
- return ret;
- }
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* restart section feed if it has filters left associated with it,
- otherwise release the feed */
-static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
-{
- int i;
- struct dmxdev *dmxdev = filter->dev;
- u16 pid = filter->params.sec.pid;
-
- for (i = 0; i < dmxdev->filternum; i++)
- if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
- dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
- dmxdev->filter[i].params.sec.pid == pid) {
- dvb_dmxdev_feed_start(&dmxdev->filter[i]);
- return 0;
- }
-
- filter->dev->demux->release_section_feed(dmxdev->demux,
- filter->feed.sec);
-
- return 0;
-}
-
-static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
-{
- struct dmxdev_feed *feed;
- struct dmx_demux *demux;
-
- if (dmxdevfilter->state < DMXDEV_STATE_GO)
- return 0;
-
- switch (dmxdevfilter->type) {
- case DMXDEV_TYPE_SEC:
- if (!dmxdevfilter->feed.sec)
- break;
- dvb_dmxdev_feed_stop(dmxdevfilter);
- if (dmxdevfilter->filter.sec)
- dmxdevfilter->feed.sec->
- release_filter(dmxdevfilter->feed.sec,
- dmxdevfilter->filter.sec);
- dvb_dmxdev_feed_restart(dmxdevfilter);
- dmxdevfilter->feed.sec = NULL;
- break;
- case DMXDEV_TYPE_PES:
- dvb_dmxdev_feed_stop(dmxdevfilter);
- demux = dmxdevfilter->dev->demux;
- list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
- demux->release_ts_feed(demux, feed->ts);
- feed->ts = NULL;
- }
- break;
- default:
- if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
- return 0;
- return -EINVAL;
- }
-
- dvb_ringbuffer_flush(&dmxdevfilter->buffer);
- return 0;
-}
-
-static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
-{
- struct dmxdev_feed *feed, *tmp;
-
- /* delete all PIDs */
- list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
- list_del(&feed->next);
- kfree(feed);
- }
-
- BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
-}
-
-static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
-{
- if (dmxdevfilter->state < DMXDEV_STATE_SET)
- return 0;
-
- if (dmxdevfilter->type == DMXDEV_TYPE_PES)
- dvb_dmxdev_delete_pids(dmxdevfilter);
-
- dmxdevfilter->type = DMXDEV_TYPE_NONE;
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- return 0;
-}
-
-static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
- struct dmxdev_filter *filter,
- struct dmxdev_feed *feed)
-{
- struct timespec timeout = { 0 };
- struct dmx_pes_filter_params *para = &filter->params.pes;
- dmx_output_t otype;
- int ret;
- int ts_type;
- dmx_pes_type_t ts_pes;
- struct dmx_ts_feed *tsfeed;
-
- feed->ts = NULL;
- otype = para->output;
-
- ts_pes = para->pes_type;
-
- if (ts_pes < DMX_PES_OTHER)
- ts_type = TS_DECODER;
- else
- ts_type = 0;
-
- if (otype == DMX_OUT_TS_TAP)
- ts_type |= TS_PACKET;
- else if (otype == DMX_OUT_TSDEMUX_TAP)
- ts_type |= TS_PACKET | TS_DEMUX;
- else if (otype == DMX_OUT_TAP)
- ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
-
- ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
- dvb_dmxdev_ts_callback);
- if (ret < 0)
- return ret;
-
- tsfeed = feed->ts;
- tsfeed->priv = filter;
-
- ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
- return ret;
- }
-
- ret = tsfeed->start_filtering(tsfeed);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
- return ret;
- }
-
- return 0;
-}
-
-static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
-{
- struct dmxdev *dmxdev = filter->dev;
- struct dmxdev_feed *feed;
- void *mem;
- int ret, i;
-
- if (filter->state < DMXDEV_STATE_SET)
- return -EINVAL;
-
- if (filter->state >= DMXDEV_STATE_GO)
- dvb_dmxdev_filter_stop(filter);
-
- if (!filter->buffer.data) {
- mem = vmalloc(filter->buffer.size);
- if (!mem)
- return -ENOMEM;
- spin_lock_irq(&filter->dev->lock);
- filter->buffer.data = mem;
- spin_unlock_irq(&filter->dev->lock);
- }
-
- dvb_ringbuffer_flush(&filter->buffer);
-
- switch (filter->type) {
- case DMXDEV_TYPE_SEC:
- {
- struct dmx_sct_filter_params *para = &filter->params.sec;
- struct dmx_section_filter **secfilter = &filter->filter.sec;
- struct dmx_section_feed **secfeed = &filter->feed.sec;
-
- *secfilter = NULL;
- *secfeed = NULL;
-
-
- /* find active filter/feed with same PID */
- for (i = 0; i < dmxdev->filternum; i++) {
- if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
- dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
- dmxdev->filter[i].params.sec.pid == para->pid) {
- *secfeed = dmxdev->filter[i].feed.sec;
- break;
- }
- }
-
- /* if no feed found, try to allocate new one */
- if (!*secfeed) {
- ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
- secfeed,
- dvb_dmxdev_section_callback);
- if (ret < 0) {
- printk("DVB (%s): could not alloc feed\n",
- __func__);
- return ret;
- }
-
- ret = (*secfeed)->set(*secfeed, para->pid, 32768,
- (para->flags & DMX_CHECK_CRC) ? 1 : 0);
- if (ret < 0) {
- printk("DVB (%s): could not set feed\n",
- __func__);
- dvb_dmxdev_feed_restart(filter);
- return ret;
- }
- } else {
- dvb_dmxdev_feed_stop(filter);
- }
-
- ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
- if (ret < 0) {
- dvb_dmxdev_feed_restart(filter);
- filter->feed.sec->start_filtering(*secfeed);
- dprintk("could not get filter\n");
- return ret;
- }
-
- (*secfilter)->priv = filter;
-
- memcpy(&((*secfilter)->filter_value[3]),
- &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
- memcpy(&(*secfilter)->filter_mask[3],
- &para->filter.mask[1], DMX_FILTER_SIZE - 1);
- memcpy(&(*secfilter)->filter_mode[3],
- &para->filter.mode[1], DMX_FILTER_SIZE - 1);
-
- (*secfilter)->filter_value[0] = para->filter.filter[0];
- (*secfilter)->filter_mask[0] = para->filter.mask[0];
- (*secfilter)->filter_mode[0] = para->filter.mode[0];
- (*secfilter)->filter_mask[1] = 0;
- (*secfilter)->filter_mask[2] = 0;
-
- filter->todo = 0;
-
- ret = filter->feed.sec->start_filtering(filter->feed.sec);
- if (ret < 0)
- return ret;
-
- dvb_dmxdev_filter_timer(filter);
- break;
- }
- case DMXDEV_TYPE_PES:
- list_for_each_entry(feed, &filter->feed.ts, next) {
- ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
- if (ret < 0) {
- dvb_dmxdev_filter_stop(filter);
- return ret;
- }
- }
- break;
- default:
- return -EINVAL;
- }
-
- dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
- return 0;
-}
-
-static int dvb_demux_open(struct inode *inode, struct file *file)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
- int i;
- struct dmxdev_filter *dmxdevfilter;
-
- if (!dmxdev->filter)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- for (i = 0; i < dmxdev->filternum; i++)
- if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
- break;
-
- if (i == dmxdev->filternum) {
- mutex_unlock(&dmxdev->mutex);
- return -EMFILE;
- }
-
- dmxdevfilter = &dmxdev->filter[i];
- mutex_init(&dmxdevfilter->mutex);
- file->private_data = dmxdevfilter;
-
- dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
- dmxdevfilter->type = DMXDEV_TYPE_NONE;
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- init_timer(&dmxdevfilter->timer);
-
- dvbdev->users++;
-
- mutex_unlock(&dmxdev->mutex);
- return 0;
-}
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
- struct dmxdev_filter *dmxdevfilter)
-{
- mutex_lock(&dmxdev->mutex);
- mutex_lock(&dmxdevfilter->mutex);
-
- dvb_dmxdev_filter_stop(dmxdevfilter);
- dvb_dmxdev_filter_reset(dmxdevfilter);
-
- if (dmxdevfilter->buffer.data) {
- void *mem = dmxdevfilter->buffer.data;
-
- spin_lock_irq(&dmxdev->lock);
- dmxdevfilter->buffer.data = NULL;
- spin_unlock_irq(&dmxdev->lock);
- vfree(mem);
- }
-
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
- wake_up(&dmxdevfilter->buffer.queue);
- mutex_unlock(&dmxdevfilter->mutex);
- mutex_unlock(&dmxdev->mutex);
- return 0;
-}
-
-static inline void invert_mode(dmx_filter_t *filter)
-{
- int i;
-
- for (i = 0; i < DMX_FILTER_SIZE; i++)
- filter->mode[i] ^= 0xff;
-}
-
-static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
- struct dmxdev_filter *filter, u16 pid)
-{
- struct dmxdev_feed *feed;
-
- if ((filter->type != DMXDEV_TYPE_PES) ||
- (filter->state < DMXDEV_STATE_SET))
- return -EINVAL;
-
- /* only TS packet filters may have multiple PIDs */
- if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
- (!list_empty(&filter->feed.ts)))
- return -EINVAL;
-
- feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
- if (feed == NULL)
- return -ENOMEM;
-
- feed->pid = pid;
- list_add(&feed->next, &filter->feed.ts);
-
- if (filter->state >= DMXDEV_STATE_GO)
- return dvb_dmxdev_start_feed(dmxdev, filter, feed);
-
- return 0;
-}
-
-static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
- struct dmxdev_filter *filter, u16 pid)
-{
- struct dmxdev_feed *feed, *tmp;
-
- if ((filter->type != DMXDEV_TYPE_PES) ||
- (filter->state < DMXDEV_STATE_SET))
- return -EINVAL;
-
- list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
- if ((feed->pid == pid) && (feed->ts != NULL)) {
- feed->ts->stop_filtering(feed->ts);
- filter->dev->demux->release_ts_feed(filter->dev->demux,
- feed->ts);
- list_del(&feed->next);
- kfree(feed);
- }
- }
-
- return 0;
-}
-
-static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
- struct dmxdev_filter *dmxdevfilter,
- struct dmx_sct_filter_params *params)
-{
- dprintk("function : %s\n", __func__);
-
- dvb_dmxdev_filter_stop(dmxdevfilter);
-
- dmxdevfilter->type = DMXDEV_TYPE_SEC;
- memcpy(&dmxdevfilter->params.sec,
- params, sizeof(struct dmx_sct_filter_params));
- invert_mode(&dmxdevfilter->params.sec.filter);
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
- if (params->flags & DMX_IMMEDIATE_START)
- return dvb_dmxdev_filter_start(dmxdevfilter);
-
- return 0;
-}
-
-static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
- struct dmxdev_filter *dmxdevfilter,
- struct dmx_pes_filter_params *params)
-{
- int ret;
-
- dvb_dmxdev_filter_stop(dmxdevfilter);
- dvb_dmxdev_filter_reset(dmxdevfilter);
-
- if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
- return -EINVAL;
-
- dmxdevfilter->type = DMXDEV_TYPE_PES;
- memcpy(&dmxdevfilter->params, params,
- sizeof(struct dmx_pes_filter_params));
- INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
-
- dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
- ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
- dmxdevfilter->params.pes.pid);
- if (ret < 0)
- return ret;
-
- if (params->flags & DMX_IMMEDIATE_START)
- return dvb_dmxdev_filter_start(dmxdevfilter);
-
- return 0;
-}
-
-static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
- struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int result, hcount;
- int done = 0;
-
- if (dfil->todo <= 0) {
- hcount = 3 + dfil->todo;
- if (hcount > count)
- hcount = count;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
- file->f_flags & O_NONBLOCK,
- buf, hcount, ppos);
- if (result < 0) {
- dfil->todo = 0;
- return result;
- }
- if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
- return -EFAULT;
- buf += result;
- done = result;
- count -= result;
- dfil->todo -= result;
- if (dfil->todo > -3)
- return done;
- dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
- if (!count)
- return done;
- }
- if (count > dfil->todo)
- count = dfil->todo;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
- if (result < 0)
- return result;
- dfil->todo -= result;
- return (result + done);
-}
-
-static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- struct dmxdev_filter *dmxdevfilter = file->private_data;
- int ret;
-
- if (mutex_lock_interruptible(&dmxdevfilter->mutex))
- return -ERESTARTSYS;
-
- if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
- ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
- else
- ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
-
- mutex_unlock(&dmxdevfilter->mutex);
- return ret;
-}
-
-static int dvb_demux_do_ioctl(struct file *file,
- unsigned int cmd, void *parg)
-{
- struct dmxdev_filter *dmxdevfilter = file->private_data;
- struct dmxdev *dmxdev = dmxdevfilter->dev;
- unsigned long arg = (unsigned long)parg;
- int ret = 0;
-
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- switch (cmd) {
- case DMX_START:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
- if (dmxdevfilter->state < DMXDEV_STATE_SET)
- ret = -EINVAL;
- else
- ret = dvb_dmxdev_filter_start(dmxdevfilter);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_STOP:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
- ret = dvb_dmxdev_filter_stop(dmxdevfilter);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_SET_FILTER:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
- ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_SET_PES_FILTER:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
- ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_SET_BUFFER_SIZE:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
- ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_GET_PES_PIDS:
- if (!dmxdev->demux->get_pes_pids) {
- ret = -EINVAL;
- break;
- }
- dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
- break;
-
- case DMX_GET_CAPS:
- if (!dmxdev->demux->get_caps) {
- ret = -EINVAL;
- break;
- }
- ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
- break;
-
- case DMX_SET_SOURCE:
- if (!dmxdev->demux->set_source) {
- ret = -EINVAL;
- break;
- }
- ret = dmxdev->demux->set_source(dmxdev->demux, parg);
- break;
-
- case DMX_GET_STC:
- if (!dmxdev->demux->get_stc) {
- ret = -EINVAL;
- break;
- }
- ret = dmxdev->demux->get_stc(dmxdev->demux,
- ((struct dmx_stc *)parg)->num,
- &((struct dmx_stc *)parg)->stc,
- &((struct dmx_stc *)parg)->base);
- break;
-
- case DMX_ADD_PID:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- ret = -ERESTARTSYS;
- break;
- }
- ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- case DMX_REMOVE_PID:
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- ret = -ERESTARTSYS;
- break;
- }
- ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
- mutex_unlock(&dmxdevfilter->mutex);
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
- mutex_unlock(&dmxdev->mutex);
- return ret;
-}
-
-static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
-}
-
-static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
-{
- struct dmxdev_filter *dmxdevfilter = file->private_data;
- unsigned int mask = 0;
-
- if (!dmxdevfilter)
- return -EINVAL;
-
- poll_wait(file, &dmxdevfilter->buffer.queue, wait);
-
- if (dmxdevfilter->state != DMXDEV_STATE_GO &&
- dmxdevfilter->state != DMXDEV_STATE_DONE &&
- dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
- return 0;
-
- if (dmxdevfilter->buffer.error)
- mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
- if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
- mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
- return mask;
-}
-
-static int dvb_demux_release(struct inode *inode, struct file *file)
-{
- struct dmxdev_filter *dmxdevfilter = file->private_data;
- struct dmxdev *dmxdev = dmxdevfilter->dev;
-
- int ret;
-
- ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
-
- mutex_lock(&dmxdev->mutex);
- dmxdev->dvbdev->users--;
- if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
- fops_put(file->f_op);
- file->f_op = NULL;
- mutex_unlock(&dmxdev->mutex);
- wake_up(&dmxdev->dvbdev->wait_queue);
- } else
- mutex_unlock(&dmxdev->mutex);
-
- return ret;
-}
-
-static const struct file_operations dvb_demux_fops = {
- .owner = THIS_MODULE,
- .read = dvb_demux_read,
- .unlocked_ioctl = dvb_demux_ioctl,
- .open = dvb_demux_open,
- .release = dvb_demux_release,
- .poll = dvb_demux_poll,
- .llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_demux = {
- .priv = NULL,
- .users = 1,
- .writers = 1,
- .fops = &dvb_demux_fops
-};
-
-static int dvb_dvr_do_ioctl(struct file *file,
- unsigned int cmd, void *parg)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
- unsigned long arg = (unsigned long)parg;
- int ret;
-
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- switch (cmd) {
- case DMX_SET_BUFFER_SIZE:
- ret = dvb_dvr_set_buffer_size(dmxdev, arg);
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
- mutex_unlock(&dmxdev->mutex);
- return ret;
-}
-
-static long dvb_dvr_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
-}
-
-static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dmxdev *dmxdev = dvbdev->priv;
- unsigned int mask = 0;
-
- dprintk("function : %s\n", __func__);
-
- poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
-
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- if (dmxdev->dvr_buffer.error)
- mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
- if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
- mask |= (POLLIN | POLLRDNORM | POLLPRI);
- } else
- mask |= (POLLOUT | POLLWRNORM | POLLPRI);
-
- return mask;
-}
-
-static const struct file_operations dvb_dvr_fops = {
- .owner = THIS_MODULE,
- .read = dvb_dvr_read,
- .write = dvb_dvr_write,
- .unlocked_ioctl = dvb_dvr_ioctl,
- .open = dvb_dvr_open,
- .release = dvb_dvr_release,
- .poll = dvb_dvr_poll,
- .llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_dvr = {
- .priv = NULL,
- .readers = 1,
- .users = 1,
- .fops = &dvb_dvr_fops
-};
-
-int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
-{
- int i;
-
- if (dmxdev->demux->open(dmxdev->demux) < 0)
- return -EUSERS;
-
- dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
- if (!dmxdev->filter)
- return -ENOMEM;
-
- mutex_init(&dmxdev->mutex);
- spin_lock_init(&dmxdev->lock);
- for (i = 0; i < dmxdev->filternum; i++) {
- dmxdev->filter[i].dev = dmxdev;
- dmxdev->filter[i].buffer.data = NULL;
- dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
- DMXDEV_STATE_FREE);
- }
-
- dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
- DVB_DEVICE_DEMUX);
- dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
- dmxdev, DVB_DEVICE_DVR);
-
- dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
-
- return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_init);
-
-void dvb_dmxdev_release(struct dmxdev *dmxdev)
-{
- dmxdev->exit=1;
- if (dmxdev->dvbdev->users > 1) {
- wait_event(dmxdev->dvbdev->wait_queue,
- dmxdev->dvbdev->users==1);
- }
- if (dmxdev->dvr_dvbdev->users > 1) {
- wait_event(dmxdev->dvr_dvbdev->wait_queue,
- dmxdev->dvr_dvbdev->users==1);
- }
-
- dvb_unregister_device(dmxdev->dvbdev);
- dvb_unregister_device(dmxdev->dvr_dvbdev);
-
- vfree(dmxdev->filter);
- dmxdev->filter = NULL;
- dmxdev->demux->close(dmxdev->demux);
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
deleted file mode 100644
index d82469f842e2..000000000000
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * dvb_demux.c - DVB kernel demux API
- *
- * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
- * & Marcus Metzler <marcus@convergence.de>
- * for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/string.h>
-#include <linux/crc32.h>
-#include <asm/uaccess.h>
-#include <asm/div64.h>
-
-#include "dvb_demux.h"
-
-#define NOBUFS
-/*
-** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
-*/
-// #define DVB_DEMUX_SECTION_LOSS_LOG
-
-static int dvb_demux_tscheck;
-module_param(dvb_demux_tscheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_tscheck,
- "enable transport stream continuity and TEI check");
-
-static int dvb_demux_speedcheck;
-module_param(dvb_demux_speedcheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_speedcheck,
- "enable transport stream speed check");
-
-#define dprintk_tscheck(x...) do { \
- if (dvb_demux_tscheck && printk_ratelimit()) \
- printk(x); \
- } while (0)
-
-/******************************************************************************
- * static inlined helper functions
- ******************************************************************************/
-
-static inline u16 section_length(const u8 *buf)
-{
- return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
-}
-
-static inline u16 ts_pid(const u8 *buf)
-{
- return ((buf[1] & 0x1f) << 8) + buf[2];
-}
-
-static inline u8 payload(const u8 *tsp)
-{
- if (!(tsp[3] & 0x10)) // no payload?
- return 0;
-
- if (tsp[3] & 0x20) { // adaptation field?
- if (tsp[4] > 183) // corrupted data?
- return 0;
- else
- return 184 - 1 - tsp[4];
- }
-
- return 184;
-}
-
-static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
-{
- return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
-}
-
-static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
- size_t len)
-{
- memcpy(d, s, len);
-}
-
-/******************************************************************************
- * Software filter functions
- ******************************************************************************/
-
-static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
- const u8 *buf)
-{
- int count = payload(buf);
- int p;
- //int ccok;
- //u8 cc;
-
- if (count == 0)
- return -1;
-
- p = 188 - count;
-
- /*
- cc = buf[3] & 0x0f;
- ccok = ((feed->cc + 1) & 0x0f) == cc;
- feed->cc = cc;
- if (!ccok)
- printk("missed packet!\n");
- */
-
- if (buf[1] & 0x40) // PUSI ?
- feed->peslen = 0xfffa;
-
- feed->peslen += count;
-
- return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
-}
-
-static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
- struct dvb_demux_filter *f)
-{
- u8 neq = 0;
- int i;
-
- for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
- u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
-
- if (f->maskandmode[i] & xor)
- return 0;
-
- neq |= f->maskandnotmode[i] & xor;
- }
-
- if (f->doneq && !neq)
- return 0;
-
- return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
- NULL, 0, &f->filter, DMX_OK);
-}
-
-static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct dvb_demux_filter *f = feed->filter;
- struct dmx_section_feed *sec = &feed->feed.sec;
- int section_syntax_indicator;
-
- if (!sec->is_filtering)
- return 0;
-
- if (!f)
- return 0;
-
- if (sec->check_crc) {
- section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
- if (section_syntax_indicator &&
- demux->check_crc32(feed, sec->secbuf, sec->seclen))
- return -1;
- }
-
- do {
- if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
- return -1;
- } while ((f = f->next) && sec->is_filtering);
-
- sec->seclen = 0;
-
- return 0;
-}
-
-static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
-{
- struct dmx_section_feed *sec = &feed->feed.sec;
-
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
- if (sec->secbufp < sec->tsfeedp) {
- int i, n = sec->tsfeedp - sec->secbufp;
-
- /*
- * Section padding is done with 0xff bytes entirely.
- * Due to speed reasons, we won't check all of them
- * but just first and last.
- */
- if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
- printk("dvb_demux.c section ts padding loss: %d/%d\n",
- n, sec->tsfeedp);
- printk("dvb_demux.c pad data:");
- for (i = 0; i < n; i++)
- printk(" %02x", sec->secbuf[i]);
- printk("\n");
- }
- }
-#endif
-
- sec->tsfeedp = sec->secbufp = sec->seclen = 0;
- sec->secbuf = sec->secbuf_base;
-}
-
-/*
- * Losless Section Demux 1.4.1 by Emard
- * Valsecchi Patrick:
- * - middle of section A (no PUSI)
- * - end of section A and start of section B
- * (with PUSI pointing to the start of the second section)
- *
- * In this case, without feed->pusi_seen you'll receive a garbage section
- * consisting of the end of section A. Basically because tsfeedp
- * is incemented and the use=0 condition is not raised
- * when the second packet arrives.
- *
- * Fix:
- * when demux is started, let feed->pusi_seen = 0 to
- * prevent initial feeding of garbage from the end of
- * previous section. When you for the first time see PUSI=1
- * then set feed->pusi_seen = 1
- */
-static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
- const u8 *buf, u8 len)
-{
- struct dvb_demux *demux = feed->demux;
- struct dmx_section_feed *sec = &feed->feed.sec;
- u16 limit, seclen, n;
-
- if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
- return 0;
-
- if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
- printk("dvb_demux.c section buffer full loss: %d/%d\n",
- sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
- DMX_MAX_SECFEED_SIZE);
-#endif
- len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
- }
-
- if (len <= 0)
- return 0;
-
- demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
- sec->tsfeedp += len;
-
- /*
- * Dump all the sections we can find in the data (Emard)
- */
- limit = sec->tsfeedp;
- if (limit > DMX_MAX_SECFEED_SIZE)
- return -1; /* internal error should never happen */
-
- /* to be sure always set secbuf */
- sec->secbuf = sec->secbuf_base + sec->secbufp;
-
- for (n = 0; sec->secbufp + 2 < limit; n++) {
- seclen = section_length(sec->secbuf);
- if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
- || seclen + sec->secbufp > limit)
- return 0;
- sec->seclen = seclen;
- sec->crc_val = ~0;
- /* dump [secbuf .. secbuf+seclen) */
- if (feed->pusi_seen)
- dvb_dmx_swfilter_section_feed(feed);
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
- else
- printk("dvb_demux.c pusi not seen, discarding section data\n");
-#endif
- sec->secbufp += seclen; /* secbufp and secbuf moving together is */
- sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
- }
-
- return 0;
-}
-
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
- const u8 *buf)
-{
- u8 p, count;
- int ccok, dc_i = 0;
- u8 cc;
-
- count = payload(buf);
-
- if (count == 0) /* count == 0 if no payload or out of range */
- return -1;
-
- p = 188 - count; /* payload start */
-
- cc = buf[3] & 0x0f;
- ccok = ((feed->cc + 1) & 0x0f) == cc;
- feed->cc = cc;
-
- if (buf[3] & 0x20) {
- /* adaption field present, check for discontinuity_indicator */
- if ((buf[4] > 0) && (buf[5] & 0x80))
- dc_i = 1;
- }
-
- if (!ccok || dc_i) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
- printk("dvb_demux.c discontinuity detected %d bytes lost\n",
- count);
- /*
- * those bytes under sume circumstances will again be reported
- * in the following dvb_dmx_swfilter_section_new
- */
-#endif
- /*
- * Discontinuity detected. Reset pusi_seen = 0 to
- * stop feeding of suspicious data until next PUSI=1 arrives
- */
- feed->pusi_seen = 0;
- dvb_dmx_swfilter_section_new(feed);
- }
-
- if (buf[1] & 0x40) {
- /* PUSI=1 (is set), section boundary is here */
- if (count > 1 && buf[p] < count) {
- const u8 *before = &buf[p + 1];
- u8 before_len = buf[p];
- const u8 *after = &before[before_len];
- u8 after_len = count - 1 - before_len;
-
- dvb_dmx_swfilter_section_copy_dump(feed, before,
- before_len);
- /* before start of new section, set pusi_seen = 1 */
- feed->pusi_seen = 1;
- dvb_dmx_swfilter_section_new(feed);
- dvb_dmx_swfilter_section_copy_dump(feed, after,
- after_len);
- }
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
- else if (count > 0)
- printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
-#endif
- } else {
- /* PUSI=0 (is not set), no section boundary */
- dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
- }
-
- return 0;
-}
-
-static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
- const u8 *buf)
-{
- switch (feed->type) {
- case DMX_TYPE_TS:
- if (!feed->feed.ts.is_filtering)
- break;
- if (feed->ts_type & TS_PACKET) {
- if (feed->ts_type & TS_PAYLOAD_ONLY)
- dvb_dmx_swfilter_payload(feed, buf);
- else
- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
- DMX_OK);
- }
- if (feed->ts_type & TS_DECODER)
- if (feed->demux->write_to_decoder)
- feed->demux->write_to_decoder(feed, buf, 188);
- break;
-
- case DMX_TYPE_SEC:
- if (!feed->feed.sec.is_filtering)
- break;
- if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
- feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
- break;
-
- default:
- break;
- }
-}
-
-#define DVR_FEED(f) \
- (((f)->type == DMX_TYPE_TS) && \
- ((f)->feed.ts.is_filtering) && \
- (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
-
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
-{
- struct dvb_demux_feed *feed;
- u16 pid = ts_pid(buf);
- int dvr_done = 0;
-
- if (dvb_demux_speedcheck) {
- struct timespec cur_time, delta_time;
- u64 speed_bytes, speed_timedelta;
-
- demux->speed_pkts_cnt++;
-
- /* show speed every SPEED_PKTS_INTERVAL packets */
- if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
- cur_time = current_kernel_time();
-
- if (demux->speed_last_time.tv_sec != 0 &&
- demux->speed_last_time.tv_nsec != 0) {
- delta_time = timespec_sub(cur_time,
- demux->speed_last_time);
- speed_bytes = (u64)demux->speed_pkts_cnt
- * 188 * 8;
- /* convert to 1024 basis */
- speed_bytes = 1000 * div64_u64(speed_bytes,
- 1024);
- speed_timedelta =
- (u64)timespec_to_ns(&delta_time);
- speed_timedelta = div64_u64(speed_timedelta,
- 1000000); /* nsec -> usec */
- printk(KERN_INFO "TS speed %llu Kbits/sec \n",
- div64_u64(speed_bytes,
- speed_timedelta));
- };
-
- demux->speed_last_time = cur_time;
- demux->speed_pkts_cnt = 0;
- };
- };
-
- if (demux->cnt_storage && dvb_demux_tscheck) {
- /* check pkt counter */
- if (pid < MAX_PID) {
- if (buf[1] & 0x80)
- dprintk_tscheck("TEI detected. "
- "PID=0x%x data1=0x%x\n",
- pid, buf[1]);
-
- if ((buf[3] & 0xf) != demux->cnt_storage[pid])
- dprintk_tscheck("TS packet counter mismatch. "
- "PID=0x%x expected 0x%x "
- "got 0x%x\n",
- pid, demux->cnt_storage[pid],
- buf[3] & 0xf);
-
- demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
- };
- /* end check */
- };
-
- list_for_each_entry(feed, &demux->feed_list, list_head) {
- if ((feed->pid != pid) && (feed->pid != 0x2000))
- continue;
-
- /* copy each packet only once to the dvr device, even
- * if a PID is in multiple filters (e.g. video + PCR) */
- if ((DVR_FEED(feed)) && (dvr_done++))
- continue;
-
- if (feed->pid == pid)
- dvb_dmx_swfilter_packet_type(feed, buf);
- else if (feed->pid == 0x2000)
- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
- }
-}
-
-void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
- size_t count)
-{
- spin_lock(&demux->lock);
-
- while (count--) {
- if (buf[0] == 0x47)
- dvb_dmx_swfilter_packet(demux, buf);
- buf += 188;
- }
-
- spin_unlock(&demux->lock);
-}
-
-EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
-
-static inline int find_next_packet(const u8 *buf, int pos, size_t count,
- const int pktsize)
-{
- int start = pos, lost;
-
- while (pos < count) {
- if (buf[pos] == 0x47 ||
- (pktsize == 204 && buf[pos] == 0xB8))
- break;
- pos++;
- }
-
- lost = pos - start;
- if (lost) {
- /* This garbage is part of a valid packet? */
- int backtrack = pos - pktsize;
- if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
- (pktsize == 204 && buf[backtrack] == 0xB8)))
- return backtrack;
- }
-
- return pos;
-}
-
-/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
-static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
- size_t count, const int pktsize)
-{
- int p = 0, i, j;
- const u8 *q;
-
- spin_lock(&demux->lock);
-
- if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
- i = demux->tsbufp;
- j = pktsize - i;
- if (count < j) {
- memcpy(&demux->tsbuf[i], buf, count);
- demux->tsbufp += count;
- goto bailout;
- }
- memcpy(&demux->tsbuf[i], buf, j);
- if (demux->tsbuf[0] == 0x47) /* double check */
- dvb_dmx_swfilter_packet(demux, demux->tsbuf);
- demux->tsbufp = 0;
- p += j;
- }
-
- while (1) {
- p = find_next_packet(buf, p, count, pktsize);
- if (p >= count)
- break;
- if (count - p < pktsize)
- break;
-
- q = &buf[p];
-
- if (pktsize == 204 && (*q == 0xB8)) {
- memcpy(demux->tsbuf, q, 188);
- demux->tsbuf[0] = 0x47;
- q = demux->tsbuf;
- }
- dvb_dmx_swfilter_packet(demux, q);
- p += pktsize;
- }
-
- i = count - p;
- if (i) {
- memcpy(demux->tsbuf, &buf[p], i);
- demux->tsbufp = i;
- if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
- demux->tsbuf[0] = 0x47;
- }
-
-bailout:
- spin_unlock(&demux->lock);
-}
-
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
- _dvb_dmx_swfilter(demux, buf, count, 188);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter);
-
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
- _dvb_dmx_swfilter(demux, buf, count, 204);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_204);
-
-void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
- spin_lock(&demux->lock);
-
- demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
-
- spin_unlock(&demux->lock);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
-
-static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
-{
- int i;
-
- for (i = 0; i < demux->filternum; i++)
- if (demux->filter[i].state == DMX_STATE_FREE)
- break;
-
- if (i == demux->filternum)
- return NULL;
-
- demux->filter[i].state = DMX_STATE_ALLOCATED;
-
- return &demux->filter[i];
-}
-
-static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
-{
- int i;
-
- for (i = 0; i < demux->feednum; i++)
- if (demux->feed[i].state == DMX_STATE_FREE)
- break;
-
- if (i == demux->feednum)
- return NULL;
-
- demux->feed[i].state = DMX_STATE_ALLOCATED;
-
- return &demux->feed[i];
-}
-
-static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
-{
- struct dvb_demux_feed *entry;
-
- list_for_each_entry(entry, &feed->demux->feed_list, list_head)
- if (entry == feed)
- return 1;
-
- return 0;
-}
-
-static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
-{
- spin_lock_irq(&feed->demux->lock);
- if (dvb_demux_feed_find(feed)) {
- printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
- __func__, feed->type, feed->state, feed->pid);
- goto out;
- }
-
- list_add(&feed->list_head, &feed->demux->feed_list);
-out:
- spin_unlock_irq(&feed->demux->lock);
-}
-
-static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
-{
- spin_lock_irq(&feed->demux->lock);
- if (!(dvb_demux_feed_find(feed))) {
- printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
- __func__, feed->type, feed->state, feed->pid);
- goto out;
- }
-
- list_del(&feed->list_head);
-out:
- spin_unlock_irq(&feed->demux->lock);
-}
-
-static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
- enum dmx_ts_pes pes_type,
- size_t circular_buffer_size, struct timespec timeout)
-{
- struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
- struct dvb_demux *demux = feed->demux;
-
- if (pid > DMX_MAX_PID)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&demux->mutex))
- return -ERESTARTSYS;
-
- if (ts_type & TS_DECODER) {
- if (pes_type >= DMX_TS_PES_OTHER) {
- mutex_unlock(&demux->mutex);
- return -EINVAL;
- }
-
- if (demux->pesfilter[pes_type] &&
- demux->pesfilter[pes_type] != feed) {
- mutex_unlock(&demux->mutex);
- return -EINVAL;
- }
-
- demux->pesfilter[pes_type] = feed;
- demux->pids[pes_type] = pid;
- }
-
- dvb_demux_feed_add(feed);
-
- feed->pid = pid;
- feed->buffer_size = circular_buffer_size;
- feed->timeout = timeout;
- feed->ts_type = ts_type;
- feed->pes_type = pes_type;
-
- if (feed->buffer_size) {
-#ifdef NOBUFS
- feed->buffer = NULL;
-#else
- feed->buffer = vmalloc(feed->buffer_size);
- if (!feed->buffer) {
- mutex_unlock(&demux->mutex);
- return -ENOMEM;
- }
-#endif
- }
-
- feed->state = DMX_STATE_READY;
- mutex_unlock(&demux->mutex);
-
- return 0;
-}
-
-static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
-{
- struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
- struct dvb_demux *demux = feed->demux;
- int ret;
-
- if (mutex_lock_interruptible(&demux->mutex))
- return -ERESTARTSYS;
-
- if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
- mutex_unlock(&demux->mutex);
- return -EINVAL;
- }
-
- if (!demux->start_feed) {
- mutex_unlock(&demux->mutex);
- return -ENODEV;
- }
-
- if ((ret = demux->start_feed(feed)) < 0) {
- mutex_unlock(&demux->mutex);
- return ret;
- }
-
- spin_lock_irq(&demux->lock);
- ts_feed->is_filtering = 1;
- feed->state = DMX_STATE_GO;
- spin_unlock_irq(&demux->lock);
- mutex_unlock(&demux->mutex);
-
- return 0;
-}
-
-static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
-{
- struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
- struct dvb_demux *demux = feed->demux;
- int ret;
-
- mutex_lock(&demux->mutex);
-
- if (feed->state < DMX_STATE_GO) {
- mutex_unlock(&demux->mutex);
- return -EINVAL;
- }
-
- if (!demux->stop_feed) {
- mutex_unlock(&demux->mutex);
- return -ENODEV;
- }
-
- ret = demux->stop_feed(feed);
-
- spin_lock_irq(&demux->lock);
- ts_feed->is_filtering = 0;
- feed->state = DMX_STATE_ALLOCATED;
- spin_unlock_irq(&demux->lock);
- mutex_unlock(&demux->mutex);
-
- return ret;
-}
-
-static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
- struct dmx_ts_feed **ts_feed,
- dmx_ts_cb callback)
-{
- struct dvb_demux *demux = (struct dvb_demux *)dmx;
- struct dvb_demux_feed *feed;
-
- if (mutex_lock_interruptible(&demux->mutex))
- return -ERESTARTSYS;
-
- if (!(feed = dvb_dmx_feed_alloc(demux))) {
- mutex_unlock(&demux->mutex);
- return -EBUSY;
- }
-
- feed->type = DMX_TYPE_TS;
- feed->cb.ts = callback;
- feed->demux = demux;
- feed->pid = 0xffff;
- feed->peslen = 0xfffa;
- feed->buffer = NULL;
-
- (*ts_feed) = &feed->feed.ts;
- (*ts_feed)->parent = dmx;
- (*ts_feed)->priv = NULL;
- (*ts_feed)->is_filtering = 0;
- (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
- (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
- (*ts_feed)->set = dmx_ts_feed_set;
-
- if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
- feed->state = DMX_STATE_FREE;
- mutex_unlock(&demux->mutex);
- return -EBUSY;
- }
-
- feed->filter->type = DMX_TYPE_TS;
- feed->filter->feed = feed;
- feed->filter->state = DMX_STATE_READY;
-
- mutex_unlock(&demux->mutex);
-
- return 0;
-}
-
-static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
- struct dmx_ts_feed *ts_feed)
-{
- struct dvb_demux *demux = (struct dvb_demux *)dmx;
- struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-
- mutex_lock(&demux->mutex);
-
- if (feed->state == DMX_STATE_FREE) {
- mutex_unlock(&demux->mutex);
- return -EINVAL;
- }
-#ifndef NOBUFS
- vfree(feed->buffer);
- feed->buffer = NULL;
-#endif
-
- feed->state = DMX_STATE_FREE;
- feed->filter->state = DMX_STATE_FREE;
-
- dvb_demux_feed_del(feed);
-
- feed->pid = 0xffff;
-
- if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
- demux->pesfilter[feed->pes_type] = NULL;
-
- mutex_unlock(&demux->mutex);
- return 0;
-}
-
-/******************************************************************************
- * dmx_section_feed API calls
- ******************************************************************************/
-
-static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
- struct dmx_section_filter **filter)
-{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
- struct dvb_demux_filter *dvbdmxfilter;
-
- if (mutex_lock_interruptible(&dvbdemux->mutex))
- return -ERESTARTSYS;
-
- dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
- if (!dvbdmxfilter) {
- mutex_unlock(&dvbdemux->mutex);
- return -EBUSY;
- }
-
- spin_lock_irq(&dvbdemux->lock);
- *filter = &dvbdmxfilter->filter;
- (*filter)->parent = feed;
- (*filter)->priv = NULL;
- dvbdmxfilter->feed = dvbdmxfeed;
- dvbdmxfilter->type = DMX_TYPE_SEC;
- dvbdmxfilter->state = DMX_STATE_READY;
- dvbdmxfilter->next = dvbdmxfeed->filter;
- dvbdmxfeed->filter = dvbdmxfilter;
- spin_unlock_irq(&dvbdemux->lock);
-
- mutex_unlock(&dvbdemux->mutex);
- return 0;
-}
-
-static int dmx_section_feed_set(struct dmx_section_feed *feed,
- u16 pid, size_t circular_buffer_size,
- int check_crc)
-{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
- if (pid > 0x1fff)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
-
- dvb_demux_feed_add(dvbdmxfeed);
-
- dvbdmxfeed->pid = pid;
- dvbdmxfeed->buffer_size = circular_buffer_size;
- dvbdmxfeed->feed.sec.check_crc = check_crc;
-
-#ifdef NOBUFS
- dvbdmxfeed->buffer = NULL;
-#else
- dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
- if (!dvbdmxfeed->buffer) {
- mutex_unlock(&dvbdmx->mutex);
- return -ENOMEM;
- }
-#endif
-
- dvbdmxfeed->state = DMX_STATE_READY;
- mutex_unlock(&dvbdmx->mutex);
- return 0;
-}
-
-static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
-{
- int i;
- struct dvb_demux_filter *f;
- struct dmx_section_filter *sf;
- u8 mask, mode, doneq;
-
- if (!(f = dvbdmxfeed->filter))
- return;
- do {
- sf = &f->filter;
- doneq = 0;
- for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
- mode = sf->filter_mode[i];
- mask = sf->filter_mask[i];
- f->maskandmode[i] = mask & mode;
- doneq |= f->maskandnotmode[i] = mask & ~mode;
- }
- f->doneq = doneq ? 1 : 0;
- } while ((f = f->next));
-}
-
-static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
-{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- int ret;
-
- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
-
- if (feed->is_filtering) {
- mutex_unlock(&dvbdmx->mutex);
- return -EBUSY;
- }
-
- if (!dvbdmxfeed->filter) {
- mutex_unlock(&dvbdmx->mutex);
- return -EINVAL;
- }
-
- dvbdmxfeed->feed.sec.tsfeedp = 0;
- dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
- dvbdmxfeed->feed.sec.secbufp = 0;
- dvbdmxfeed->feed.sec.seclen = 0;
-
- if (!dvbdmx->start_feed) {
- mutex_unlock(&dvbdmx->mutex);
- return -ENODEV;
- }
-
- prepare_secfilters(dvbdmxfeed);
-
- if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
- mutex_unlock(&dvbdmx->mutex);
- return ret;
- }
-
- spin_lock_irq(&dvbdmx->lock);
- feed->is_filtering = 1;
- dvbdmxfeed->state = DMX_STATE_GO;
- spin_unlock_irq(&dvbdmx->lock);
-
- mutex_unlock(&dvbdmx->mutex);
- return 0;
-}
-
-static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
-{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- int ret;
-
- mutex_lock(&dvbdmx->mutex);
-
- if (!dvbdmx->stop_feed) {
- mutex_unlock(&dvbdmx->mutex);
- return -ENODEV;
- }
-
- ret = dvbdmx->stop_feed(dvbdmxfeed);
-
- spin_lock_irq(&dvbdmx->lock);
- dvbdmxfeed->state = DMX_STATE_READY;
- feed->is_filtering = 0;
- spin_unlock_irq(&dvbdmx->lock);
-
- mutex_unlock(&dvbdmx->mutex);
- return ret;
-}
-
-static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
- struct dmx_section_filter *filter)
-{
- struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
- mutex_lock(&dvbdmx->mutex);
-
- if (dvbdmxfilter->feed != dvbdmxfeed) {
- mutex_unlock(&dvbdmx->mutex);
- return -EINVAL;
- }
-
- if (feed->is_filtering)
- feed->stop_filtering(feed);
-
- spin_lock_irq(&dvbdmx->lock);
- f = dvbdmxfeed->filter;
-
- if (f == dvbdmxfilter) {
- dvbdmxfeed->filter = dvbdmxfilter->next;
- } else {
- while (f->next != dvbdmxfilter)
- f = f->next;
- f->next = f->next->next;
- }
-
- dvbdmxfilter->state = DMX_STATE_FREE;
- spin_unlock_irq(&dvbdmx->lock);
- mutex_unlock(&dvbdmx->mutex);
- return 0;
-}
-
-static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
- struct dmx_section_feed **feed,
- dmx_section_cb callback)
-{
- struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
- struct dvb_demux_feed *dvbdmxfeed;
-
- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
-
- if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
- mutex_unlock(&dvbdmx->mutex);
- return -EBUSY;
- }
-
- dvbdmxfeed->type = DMX_TYPE_SEC;
- dvbdmxfeed->cb.sec = callback;
- dvbdmxfeed->demux = dvbdmx;
- dvbdmxfeed->pid = 0xffff;
- dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
- dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
- dvbdmxfeed->feed.sec.tsfeedp = 0;
- dvbdmxfeed->filter = NULL;
- dvbdmxfeed->buffer = NULL;
-
- (*feed) = &dvbdmxfeed->feed.sec;
- (*feed)->is_filtering = 0;
- (*feed)->parent = demux;
- (*feed)->priv = NULL;
-
- (*feed)->set = dmx_section_feed_set;
- (*feed)->allocate_filter = dmx_section_feed_allocate_filter;
- (*feed)->start_filtering = dmx_section_feed_start_filtering;
- (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
- (*feed)->release_filter = dmx_section_feed_release_filter;
-
- mutex_unlock(&dvbdmx->mutex);
- return 0;
-}
-
-static int dvbdmx_release_section_feed(struct dmx_demux *demux,
- struct dmx_section_feed *feed)
-{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
- struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
-
- mutex_lock(&dvbdmx->mutex);
-
- if (dvbdmxfeed->state == DMX_STATE_FREE) {
- mutex_unlock(&dvbdmx->mutex);
- return -EINVAL;
- }
-#ifndef NOBUFS
- vfree(dvbdmxfeed->buffer);
- dvbdmxfeed->buffer = NULL;
-#endif
- dvbdmxfeed->state = DMX_STATE_FREE;
-
- dvb_demux_feed_del(dvbdmxfeed);
-
- dvbdmxfeed->pid = 0xffff;
-
- mutex_unlock(&dvbdmx->mutex);
- return 0;
-}
-
-/******************************************************************************
- * dvb_demux kernel data API calls
- ******************************************************************************/
-
-static int dvbdmx_open(struct dmx_demux *demux)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
- return -EUSERS;
-
- dvbdemux->users++;
- return 0;
-}
-
-static int dvbdmx_close(struct dmx_demux *demux)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- if (dvbdemux->users == 0)
- return -ENODEV;
-
- dvbdemux->users--;
- //FIXME: release any unneeded resources if users==0
- return 0;
-}
-
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- void *p;
-
- if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
- return -EINVAL;
-
- p = memdup_user(buf, count);
- if (IS_ERR(p))
- return PTR_ERR(p);
- if (mutex_lock_interruptible(&dvbdemux->mutex)) {
- kfree(p);
- return -ERESTARTSYS;
- }
- dvb_dmx_swfilter(dvbdemux, p, count);
- kfree(p);
- mutex_unlock(&dvbdemux->mutex);
-
- if (signal_pending(current))
- return -EINTR;
- return count;
-}
-
-static int dvbdmx_add_frontend(struct dmx_demux *demux,
- struct dmx_frontend *frontend)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- struct list_head *head = &dvbdemux->frontend_list;
-
- list_add(&(frontend->connectivity_list), head);
-
- return 0;
-}
-
-static int dvbdmx_remove_frontend(struct dmx_demux *demux,
- struct dmx_frontend *frontend)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
-
- list_for_each_safe(pos, n, head) {
- if (DMX_FE_ENTRY(pos) == frontend) {
- list_del(pos);
- return 0;
- }
- }
-
- return -ENODEV;
-}
-
-static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- if (list_empty(&dvbdemux->frontend_list))
- return NULL;
-
- return &dvbdemux->frontend_list;
-}
-
-static int dvbdmx_connect_frontend(struct dmx_demux *demux,
- struct dmx_frontend *frontend)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- if (demux->frontend)
- return -EINVAL;
-
- mutex_lock(&dvbdemux->mutex);
-
- demux->frontend = frontend;
- mutex_unlock(&dvbdemux->mutex);
- return 0;
-}
-
-static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- mutex_lock(&dvbdemux->mutex);
-
- demux->frontend = NULL;
- mutex_unlock(&dvbdemux->mutex);
- return 0;
-}
-
-static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
-{
- struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
- memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
- return 0;
-}
-
-int dvb_dmx_init(struct dvb_demux *dvbdemux)
-{
- int i;
- struct dmx_demux *dmx = &dvbdemux->dmx;
-
- dvbdemux->cnt_storage = NULL;
- dvbdemux->users = 0;
- dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
-
- if (!dvbdemux->filter)
- return -ENOMEM;
-
- dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
- if (!dvbdemux->feed) {
- vfree(dvbdemux->filter);
- dvbdemux->filter = NULL;
- return -ENOMEM;
- }
- for (i = 0; i < dvbdemux->filternum; i++) {
- dvbdemux->filter[i].state = DMX_STATE_FREE;
- dvbdemux->filter[i].index = i;
- }
- for (i = 0; i < dvbdemux->feednum; i++) {
- dvbdemux->feed[i].state = DMX_STATE_FREE;
- dvbdemux->feed[i].index = i;
- }
-
- dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
- if (!dvbdemux->cnt_storage)
- printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
-
- INIT_LIST_HEAD(&dvbdemux->frontend_list);
-
- for (i = 0; i < DMX_TS_PES_OTHER; i++) {
- dvbdemux->pesfilter[i] = NULL;
- dvbdemux->pids[i] = 0xffff;
- }
-
- INIT_LIST_HEAD(&dvbdemux->feed_list);
-
- dvbdemux->playing = 0;
- dvbdemux->recording = 0;
- dvbdemux->tsbufp = 0;
-
- if (!dvbdemux->check_crc32)
- dvbdemux->check_crc32 = dvb_dmx_crc32;
-
- if (!dvbdemux->memcopy)
- dvbdemux->memcopy = dvb_dmx_memcopy;
-
- dmx->frontend = NULL;
- dmx->priv = dvbdemux;
- dmx->open = dvbdmx_open;
- dmx->close = dvbdmx_close;
- dmx->write = dvbdmx_write;
- dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
- dmx->release_ts_feed = dvbdmx_release_ts_feed;
- dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
- dmx->release_section_feed = dvbdmx_release_section_feed;
-
- dmx->add_frontend = dvbdmx_add_frontend;
- dmx->remove_frontend = dvbdmx_remove_frontend;
- dmx->get_frontends = dvbdmx_get_frontends;
- dmx->connect_frontend = dvbdmx_connect_frontend;
- dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
- dmx->get_pes_pids = dvbdmx_get_pes_pids;
-
- mutex_init(&dvbdemux->mutex);
- spin_lock_init(&dvbdemux->lock);
-
- return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmx_init);
-
-void dvb_dmx_release(struct dvb_demux *dvbdemux)
-{
- vfree(dvbdemux->cnt_storage);
- vfree(dvbdemux->filter);
- vfree(dvbdemux->feed);
-}
-
-EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
deleted file mode 100644
index aebcdf221dda..000000000000
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ /dev/null
@@ -1,2563 +0,0 @@
-/*
- * dvb_frontend.c: DVB frontend tuning interface/thread
- *
- *
- * Copyright (C) 1999-2001 Ralph Metzler
- * Marcus Metzler
- * Holger Waechtler
- * for convergence integrated media GmbH
- *
- * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
- *
- * 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.
- * 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>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/semaphore.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/freezer.h>
-#include <linux/jiffies.h>
-#include <linux/kthread.h>
-#include <asm/processor.h>
-
-#include "dvb_frontend.h"
-#include "dvbdev.h"
-#include <linux/dvb/version.h>
-
-static int dvb_frontend_debug;
-static int dvb_shutdown_timeout;
-static int dvb_force_auto_inversion;
-static int dvb_override_tune_delay;
-static int dvb_powerdown_on_sleep = 1;
-static int dvb_mfe_wait_time = 5;
-
-module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
-MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0644);
-MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0644);
-MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0644);
-MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
-module_param(dvb_mfe_wait_time, int, 0644);
-MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
-
-#define dprintk if (dvb_frontend_debug) printk
-
-#define FESTATE_IDLE 1
-#define FESTATE_RETUNE 2
-#define FESTATE_TUNING_FAST 4
-#define FESTATE_TUNING_SLOW 8
-#define FESTATE_TUNED 16
-#define FESTATE_ZIGZAG_FAST 32
-#define FESTATE_ZIGZAG_SLOW 64
-#define FESTATE_DISEQC 128
-#define FESTATE_ERROR 256
-#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
-#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
-#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
-#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
-
-#define FE_ALGO_HW 1
-/*
- * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
- * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
- * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
- * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
- * FESTATE_TUNED. The frontend has successfully locked on.
- * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
- * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
- * FESTATE_DISEQC. A DISEQC command has just been issued.
- * FESTATE_WAITFORLOCK. When we're waiting for a lock.
- * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
- * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
- * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
- */
-
-#define DVB_FE_NO_EXIT 0
-#define DVB_FE_NORMAL_EXIT 1
-#define DVB_FE_DEVICE_REMOVED 2
-
-static DEFINE_MUTEX(frontend_mutex);
-
-struct dvb_frontend_private {
-
- /* thread/frontend values */
- struct dvb_device *dvbdev;
- struct dvb_frontend_parameters parameters_out;
- struct dvb_fe_events events;
- struct semaphore sem;
- struct list_head list_head;
- wait_queue_head_t wait_queue;
- struct task_struct *thread;
- unsigned long release_jiffies;
- unsigned int exit;
- unsigned int wakeup;
- fe_status_t status;
- unsigned long tune_mode_flags;
- unsigned int delay;
- unsigned int reinitialise;
- int tone;
- int voltage;
-
- /* swzigzag values */
- unsigned int state;
- unsigned int bending;
- int lnb_drift;
- unsigned int inversion;
- unsigned int auto_step;
- unsigned int auto_sub_step;
- unsigned int started_auto_step;
- unsigned int min_delay;
- unsigned int max_drift;
- unsigned int step_size;
- int quality;
- unsigned int check_wrapped;
- enum dvbfe_search algo_status;
-};
-
-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_ATSCMH:
- case SYS_DVBC_ANNEX_B:
- return DVBV3_ATSC;
- case SYS_UNDEFINED:
- case SYS_ISDBC:
- case SYS_DVBH:
- case SYS_DAB:
- 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)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_fe_events *events = &fepriv->events;
- struct dvb_frontend_event *e;
- int wp;
-
- dprintk ("%s\n", __func__);
-
- if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
- dtv_get_frontend(fe, &fepriv->parameters_out);
-
- mutex_lock(&events->mtx);
-
- wp = (events->eventw + 1) % MAX_EVENT;
- if (wp == events->eventr) {
- events->overflow = 1;
- events->eventr = (events->eventr + 1) % MAX_EVENT;
- }
-
- e = &events->events[events->eventw];
- e->status = status;
- e->parameters = fepriv->parameters_out;
-
- events->eventw = wp;
-
- mutex_unlock(&events->mtx);
-
- wake_up_interruptible (&events->wait_queue);
-}
-
-static int dvb_frontend_get_event(struct dvb_frontend *fe,
- struct dvb_frontend_event *event, int flags)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_fe_events *events = &fepriv->events;
-
- dprintk ("%s\n", __func__);
-
- if (events->overflow) {
- events->overflow = 0;
- return -EOVERFLOW;
- }
-
- if (events->eventw == events->eventr) {
- int ret;
-
- if (flags & O_NONBLOCK)
- return -EWOULDBLOCK;
-
- up(&fepriv->sem);
-
- ret = wait_event_interruptible (events->wait_queue,
- events->eventw != events->eventr);
-
- if (down_interruptible (&fepriv->sem))
- return -ERESTARTSYS;
-
- if (ret < 0)
- return ret;
- }
-
- mutex_lock(&events->mtx);
- *event = events->events[events->eventr];
- events->eventr = (events->eventr + 1) % MAX_EVENT;
- mutex_unlock(&events->mtx);
-
- return 0;
-}
-
-static void dvb_frontend_clear_events(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_fe_events *events = &fepriv->events;
-
- mutex_lock(&events->mtx);
- events->eventr = events->eventw;
- mutex_unlock(&events->mtx);
-}
-
-static void dvb_frontend_init(struct dvb_frontend *fe)
-{
- dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
- fe->dvb->num,
- fe->id,
- fe->ops.info.name);
-
- if (fe->ops.init)
- fe->ops.init(fe);
- if (fe->ops.tuner_ops.init) {
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.init(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-}
-
-void dvb_frontend_reinitialise(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- fepriv->reinitialise = 1;
- dvb_frontend_wakeup(fe);
-}
-EXPORT_SYMBOL(dvb_frontend_reinitialise);
-
-static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
-{
- int q2;
-
- dprintk ("%s\n", __func__);
-
- if (locked)
- (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
- else
- (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
-
- q2 = fepriv->quality - 128;
- q2 *= q2;
-
- fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
-}
-
-/**
- * Performs automatic twiddling of frontend parameters.
- *
- * @param fe The frontend concerned.
- * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
- * @returns Number of complete iterations that have been performed.
- */
-static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
-{
- int autoinversion;
- int ready = 0;
- int fe_set_err = 0;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- 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)) &&
- (c->inversion == INVERSION_AUTO));
-
- /* setup parameters correctly */
- while(!ready) {
- /* calculate the lnb_drift */
- fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
-
- /* wrap the auto_step if we've exceeded the maximum drift */
- if (fepriv->lnb_drift > fepriv->max_drift) {
- fepriv->auto_step = 0;
- fepriv->auto_sub_step = 0;
- fepriv->lnb_drift = 0;
- }
-
- /* perform inversion and +/- zigzag */
- switch(fepriv->auto_sub_step) {
- case 0:
- /* try with the current inversion and current drift setting */
- ready = 1;
- break;
-
- case 1:
- if (!autoinversion) break;
-
- fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
- ready = 1;
- break;
-
- case 2:
- if (fepriv->lnb_drift == 0) break;
-
- fepriv->lnb_drift = -fepriv->lnb_drift;
- ready = 1;
- break;
-
- case 3:
- if (fepriv->lnb_drift == 0) break;
- if (!autoinversion) break;
-
- fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
- fepriv->lnb_drift = -fepriv->lnb_drift;
- ready = 1;
- break;
-
- default:
- fepriv->auto_step++;
- fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
- break;
- }
-
- if (!ready) fepriv->auto_sub_step++;
- }
-
- /* if this attempt would hit where we started, indicate a complete
- * iteration has occurred */
- if ((fepriv->auto_step == fepriv->started_auto_step) &&
- (fepriv->auto_sub_step == 0) && check_wrapped) {
- return 1;
- }
-
- dprintk("%s: drift:%i inversion:%i auto_step:%i "
- "auto_sub_step:%i started_auto_step:%i\n",
- __func__, fepriv->lnb_drift, fepriv->inversion,
- fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
-
- /* set the frontend itself */
- c->frequency += fepriv->lnb_drift;
- if (autoinversion)
- c->inversion = fepriv->inversion;
- tmp = *c;
- if (fe->ops.set_frontend)
- fe_set_err = fe->ops.set_frontend(fe);
- *c = tmp;
- if (fe_set_err < 0) {
- fepriv->state = FESTATE_ERROR;
- return fe_set_err;
- }
-
- c->frequency = original_frequency;
- c->inversion = original_inversion;
-
- fepriv->auto_sub_step++;
- return 0;
-}
-
-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) {
- fepriv->delay = 3*HZ;
- fepriv->quality = 0;
- return;
- }
-
- /* 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);
- *c = tmp;
- if (retval < 0)
- fepriv->state = FESTATE_ERROR;
- else
- fepriv->state = FESTATE_TUNED;
- }
- fepriv->delay = 3*HZ;
- fepriv->quality = 0;
- return;
- }
-
- /* get the frontend status */
- if (fepriv->state & FESTATE_RETUNE) {
- s = 0;
- } else {
- if (fe->ops.read_status)
- fe->ops.read_status(fe, &s);
- if (s != fepriv->status) {
- dvb_frontend_add_event(fe, s);
- fepriv->status = s;
- }
- }
-
- /* if we're not tuned, and we have a lock, move to the TUNED state */
- if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
- dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
- fepriv->state = FESTATE_TUNED;
-
- /* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
- (c->inversion == INVERSION_AUTO)) {
- c->inversion = fepriv->inversion;
- }
- return;
- }
-
- /* if we are tuned already, check we're still locked */
- if (fepriv->state & FESTATE_TUNED) {
- dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
- /* we're tuned, and the lock is still good... */
- if (s & FE_HAS_LOCK) {
- return;
- } else { /* if we _WERE_ tuned, but now don't have a lock */
- fepriv->state = FESTATE_ZIGZAG_FAST;
- fepriv->started_auto_step = fepriv->auto_step;
- fepriv->check_wrapped = 0;
- }
- }
-
- /* don't actually do anything if we're in the LOSTLOCK state,
- * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
- if ((fepriv->state & FESTATE_LOSTLOCK) &&
- (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
- dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
- return;
- }
-
- /* don't do anything if we're in the DISEQC state, since this
- * might be someone with a motorized dish controlled by DISEQC.
- * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
- if (fepriv->state & FESTATE_DISEQC) {
- dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
- return;
- }
-
- /* if we're in the RETUNE state, set everything up for a brand
- * new scan, keeping the current inversion setting, as the next
- * tune is _very_ likely to require the same */
- if (fepriv->state & FESTATE_RETUNE) {
- fepriv->lnb_drift = 0;
- fepriv->auto_step = 0;
- fepriv->auto_sub_step = 0;
- fepriv->started_auto_step = 0;
- fepriv->check_wrapped = 0;
- }
-
- /* fast zigzag. */
- if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
- fepriv->delay = fepriv->min_delay;
-
- /* perform a tune */
- retval = dvb_frontend_swzigzag_autotune(fe,
- fepriv->check_wrapped);
- if (retval < 0) {
- return;
- } else if (retval) {
- /* OK, if we've run out of trials at the fast speed.
- * Drop back to slow for the _next_ attempt */
- fepriv->state = FESTATE_SEARCHING_SLOW;
- fepriv->started_auto_step = fepriv->auto_step;
- return;
- }
- fepriv->check_wrapped = 1;
-
- /* if we've just retuned, enter the ZIGZAG_FAST state.
- * This ensures we cannot return from an
- * FE_SET_FRONTEND ioctl before the first frontend tune
- * occurs */
- if (fepriv->state & FESTATE_RETUNE) {
- fepriv->state = FESTATE_TUNING_FAST;
- }
- }
-
- /* slow zigzag */
- if (fepriv->state & FESTATE_SEARCHING_SLOW) {
- dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
- /* Note: don't bother checking for wrapping; we stay in this
- * state until we get a lock */
- dvb_frontend_swzigzag_autotune(fe, 0);
- }
-}
-
-static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- if (fepriv->exit != DVB_FE_NO_EXIT)
- return 1;
-
- if (fepriv->dvbdev->writers == 1)
- if (time_after_eq(jiffies, fepriv->release_jiffies +
- dvb_shutdown_timeout * HZ))
- return 1;
-
- return 0;
-}
-
-static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- if (fepriv->wakeup) {
- fepriv->wakeup = 0;
- return 1;
- }
- return dvb_frontend_is_exiting(fe);
-}
-
-static void dvb_frontend_wakeup(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- fepriv->wakeup = 1;
- wake_up_interruptible(&fepriv->wait_queue);
-}
-
-static int dvb_frontend_thread(void *data)
-{
- struct dvb_frontend *fe = data;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- fe_status_t s;
- enum dvbfe_algo algo;
-
- bool re_tune = false;
-
- dprintk("%s\n", __func__);
-
- fepriv->check_wrapped = 0;
- fepriv->quality = 0;
- fepriv->delay = 3*HZ;
- fepriv->status = 0;
- fepriv->wakeup = 0;
- fepriv->reinitialise = 0;
-
- dvb_frontend_init(fe);
-
- set_freezable();
- while (1) {
- up(&fepriv->sem); /* is locked when we enter the thread... */
-restart:
- wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe) || kthread_should_stop()
- || freezing(current),
- fepriv->delay);
-
- if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
- /* got signal or quitting */
- fepriv->exit = DVB_FE_NORMAL_EXIT;
- break;
- }
-
- if (try_to_freeze())
- goto restart;
-
- if (down_interruptible(&fepriv->sem))
- break;
-
- if (fepriv->reinitialise) {
- dvb_frontend_init(fe);
- if (fe->ops.set_tone && fepriv->tone != -1)
- fe->ops.set_tone(fe, fepriv->tone);
- if (fe->ops.set_voltage && fepriv->voltage != -1)
- fe->ops.set_voltage(fe, fepriv->voltage);
- fepriv->reinitialise = 0;
- }
-
- /* do an iteration of the tuning loop */
- if (fe->ops.get_frontend_algo) {
- algo = fe->ops.get_frontend_algo(fe);
- switch (algo) {
- case DVBFE_ALGO_HW:
- dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
-
- if (fepriv->state & FESTATE_RETUNE) {
- dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
- re_tune = true;
- fepriv->state = FESTATE_TUNED;
- } else {
- re_tune = false;
- }
-
- if (fe->ops.tune)
- 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__);
- dvb_frontend_add_event(fe, s);
- fepriv->status = s;
- }
- break;
- case DVBFE_ALGO_SW:
- dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
- dvb_frontend_swzigzag(fe);
- break;
- case DVBFE_ALGO_CUSTOM:
- dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
- if (fepriv->state & FESTATE_RETUNE) {
- dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
- fepriv->state = FESTATE_TUNED;
- }
- /* Case where we are going to search for a carrier
- * User asked us to retune again for some reason, possibly
- * requesting a search with a new set of parameters
- */
- if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
- if (fe->ops.search) {
- 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.
- */
- } else {
- fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
- }
- }
- /* Track the carrier if the search was successful */
- if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
- fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
- fepriv->delay = HZ / 2;
- }
- 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 */
- fepriv->status = s;
- if (!(s & FE_HAS_LOCK)) {
- fepriv->delay = HZ / 10;
- fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
- } else {
- fepriv->delay = 60 * HZ;
- }
- }
- break;
- default:
- dprintk("%s: UNDEFINED ALGO !\n", __func__);
- break;
- }
- } else {
- dvb_frontend_swzigzag(fe);
- }
- }
-
- if (dvb_powerdown_on_sleep) {
- if (fe->ops.set_voltage)
- fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
- if (fe->ops.tuner_ops.sleep) {
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.sleep(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- if (fe->ops.sleep)
- fe->ops.sleep(fe);
- }
-
- fepriv->thread = NULL;
- if (kthread_should_stop())
- fepriv->exit = DVB_FE_DEVICE_REMOVED;
- else
- fepriv->exit = DVB_FE_NO_EXIT;
- mb();
-
- dvb_frontend_wakeup(fe);
- return 0;
-}
-
-static void dvb_frontend_stop(struct dvb_frontend *fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- dprintk ("%s\n", __func__);
-
- fepriv->exit = DVB_FE_NORMAL_EXIT;
- mb();
-
- if (!fepriv->thread)
- return;
-
- kthread_stop(fepriv->thread);
-
- sema_init(&fepriv->sem, 1);
- fepriv->state = FESTATE_IDLE;
-
- /* paranoia check in case a signal arrived */
- if (fepriv->thread)
- printk("dvb_frontend_stop: warning: thread %p won't exit\n",
- fepriv->thread);
-}
-
-s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
-{
- return ((curtime.tv_usec < lasttime.tv_usec) ?
- 1000000 - lasttime.tv_usec + curtime.tv_usec :
- curtime.tv_usec - lasttime.tv_usec);
-}
-EXPORT_SYMBOL(timeval_usec_diff);
-
-static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
-{
- curtime->tv_usec += add_usec;
- if (curtime->tv_usec >= 1000000) {
- curtime->tv_usec -= 1000000;
- curtime->tv_sec++;
- }
-}
-
-/*
- * Sleep until gettimeofday() > waketime + add_usec
- * This needs to be as precise as possible, but as the delay is
- * usually between 2ms and 32ms, it is done using a scheduled msleep
- * followed by usleep (normally a busy-wait loop) for the remainder
- */
-void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
-{
- struct timeval lasttime;
- s32 delta, newdelta;
-
- timeval_usec_add(waketime, add_usec);
-
- do_gettimeofday(&lasttime);
- delta = timeval_usec_diff(lasttime, *waketime);
- if (delta > 2500) {
- msleep((delta - 1500) / 1000);
- do_gettimeofday(&lasttime);
- newdelta = timeval_usec_diff(lasttime, *waketime);
- delta = (newdelta > delta) ? 0 : newdelta;
- }
- if (delta > 0)
- udelay(delta);
-}
-EXPORT_SYMBOL(dvb_frontend_sleep_until);
-
-static int dvb_frontend_start(struct dvb_frontend *fe)
-{
- int ret;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct task_struct *fe_thread;
-
- dprintk ("%s\n", __func__);
-
- if (fepriv->thread) {
- if (fepriv->exit == DVB_FE_NO_EXIT)
- return 0;
- else
- dvb_frontend_stop (fe);
- }
-
- if (signal_pending(current))
- return -EINTR;
- if (down_interruptible (&fepriv->sem))
- return -EINTR;
-
- fepriv->state = FESTATE_IDLE;
- fepriv->exit = DVB_FE_NO_EXIT;
- fepriv->thread = NULL;
- mb();
-
- fe_thread = kthread_run(dvb_frontend_thread, fe,
- "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
- if (IS_ERR(fe_thread)) {
- ret = PTR_ERR(fe_thread);
- printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
- up(&fepriv->sem);
- return ret;
- }
- fepriv->thread = fe_thread;
- return 0;
-}
-
-static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
- u32 *freq_min, u32 *freq_max)
-{
- *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
-
- if (fe->ops.info.frequency_max == 0)
- *freq_max = fe->ops.tuner_ops.info.frequency_max;
- else if (fe->ops.tuner_ops.info.frequency_max == 0)
- *freq_max = fe->ops.info.frequency_max;
- else
- *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
-
- if (*freq_min == 0 || *freq_max == 0)
- printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
- fe->dvb->num,fe->id);
-}
-
-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 && 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, c->frequency, freq_min, freq_max);
- return -EINVAL;
- }
-
- /* range check: symbol rate */
- 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 &&
- c->symbol_rate < fe->ops.info.symbol_rate_min) ||
- (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, c->symbol_rate,
- fe->ops.info.symbol_rate_min,
- fe->ops.info.symbol_rate_max);
- return -EINVAL;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-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;
-
- dprintk("%s() Clearing cache for delivery system %d\n", __func__,
- c->delivery_system);
-
- c->transmission_mode = TRANSMISSION_MODE_AUTO;
- c->bandwidth_hz = 0; /* AUTO */
- c->guard_interval = GUARD_INTERVAL_AUTO;
- c->hierarchy = HIERARCHY_AUTO;
- c->symbol_rate = 0;
- c->code_rate_HP = FEC_AUTO;
- c->code_rate_LP = FEC_AUTO;
- 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 = 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;
-}
-
-#define _DTV_CMD(n, s, b) \
-[n] = { \
- .name = #n, \
- .cmd = n, \
- .set = s,\
- .buffer = b \
-}
-
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
- _DTV_CMD(DTV_TUNE, 1, 0),
- _DTV_CMD(DTV_CLEAR, 1, 0),
-
- /* Set */
- _DTV_CMD(DTV_FREQUENCY, 1, 0),
- _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
- _DTV_CMD(DTV_MODULATION, 1, 0),
- _DTV_CMD(DTV_INVERSION, 1, 0),
- _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
- _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
- _DTV_CMD(DTV_INNER_FEC, 1, 0),
- _DTV_CMD(DTV_VOLTAGE, 1, 0),
- _DTV_CMD(DTV_TONE, 1, 0),
- _DTV_CMD(DTV_PILOT, 1, 0),
- _DTV_CMD(DTV_ROLLOFF, 1, 0),
- _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
- _DTV_CMD(DTV_HIERARCHY, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
- _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
- _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
-
- _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
- _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
- _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
- _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
-
- /* Get */
- _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
- _DTV_CMD(DTV_API_VERSION, 0, 0),
- _DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
- _DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
- _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),
-
- _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
- _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
- _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
- _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
- _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
-};
-
-static void dtv_property_dump(struct dtv_property *tvp)
-{
- int i;
-
- if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
- printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
- __func__, tvp->cmd);
- return;
- }
-
- dprintk("%s() tvp.cmd = 0x%08x (%s)\n"
- ,__func__
- ,tvp->cmd
- ,dtv_cmds[ tvp->cmd ].name);
-
- if(dtv_cmds[ tvp->cmd ].buffer) {
-
- dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
- ,__func__
- ,tvp->u.buffer.len);
-
- for(i = 0; i < tvp->u.buffer.len; i++)
- dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
- ,__func__
- ,i
- ,tvp->u.buffer.data[i]);
-
- } else
- dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
-}
-
-/* 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 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 (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 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 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;
- 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;
- c->transmission_mode = p->u.ofdm.transmission_mode;
- c->guard_interval = p->u.ofdm.guard_interval;
- c->hierarchy = p->u.ofdm.hierarchy_information;
- break;
- case DVBV3_ATSC:
- dprintk("%s() Preparing ATSC req\n", __func__);
- c->modulation = p->u.vsb.modulation;
- if (c->delivery_system == SYS_ATSCMH)
- break;
- 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 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;
-
- p->frequency = c->frequency;
- p->inversion = c->inversion;
-
- 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 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 DVBV3_OFDM:
- dprintk("%s() Preparing OFDM req\n", __func__);
-
- switch (c->bandwidth_hz) {
- case 10000000:
- p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
- break;
- case 8000000:
- p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
- 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;
- p->u.ofdm.transmission_mode = c->transmission_mode;
- p->u.ofdm.guard_interval = c->guard_interval;
- p->u.ofdm.hierarchy_information = c->hierarchy;
- break;
- case DVBV3_ATSC:
- dprintk("%s() Preparing VSB req\n", __func__);
- p->u.vsb.modulation = c->modulation;
- break;
- }
- return 0;
-}
-
-/**
- * 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 int dtv_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p_out)
-{
- int r;
-
- 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;
- }
-
- /* As everything is in cache, get_frontend fops are always supported */
- return 0;
-}
-
-static int dvb_frontend_ioctl_legacy(struct file *file,
- unsigned int cmd, void *parg);
-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)
-{
- 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;
- case DTV_MODULATION:
- tvp->u.data = c->modulation;
- break;
- case DTV_BANDWIDTH_HZ:
- tvp->u.data = c->bandwidth_hz;
- break;
- case DTV_INVERSION:
- tvp->u.data = c->inversion;
- break;
- case DTV_SYMBOL_RATE:
- tvp->u.data = c->symbol_rate;
- break;
- case DTV_INNER_FEC:
- tvp->u.data = c->fec_inner;
- break;
- case DTV_PILOT:
- tvp->u.data = c->pilot;
- break;
- case DTV_ROLLOFF:
- tvp->u.data = c->rolloff;
- break;
- case DTV_DELIVERY_SYSTEM:
- tvp->u.data = c->delivery_system;
- break;
- case DTV_VOLTAGE:
- tvp->u.data = c->voltage;
- break;
- case DTV_TONE:
- tvp->u.data = c->sectone;
- break;
- case DTV_API_VERSION:
- tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
- break;
- case DTV_CODE_RATE_HP:
- tvp->u.data = c->code_rate_HP;
- break;
- case DTV_CODE_RATE_LP:
- tvp->u.data = c->code_rate_LP;
- break;
- case DTV_GUARD_INTERVAL:
- tvp->u.data = c->guard_interval;
- break;
- case DTV_TRANSMISSION_MODE:
- tvp->u.data = c->transmission_mode;
- break;
- case DTV_HIERARCHY:
- tvp->u.data = c->hierarchy;
- break;
-
- /* ISDB-T Support here */
- case DTV_ISDBT_PARTIAL_RECEPTION:
- tvp->u.data = c->isdbt_partial_reception;
- break;
- case DTV_ISDBT_SOUND_BROADCASTING:
- tvp->u.data = c->isdbt_sb_mode;
- break;
- case DTV_ISDBT_SB_SUBCHANNEL_ID:
- tvp->u.data = c->isdbt_sb_subchannel;
- break;
- case DTV_ISDBT_SB_SEGMENT_IDX:
- tvp->u.data = c->isdbt_sb_segment_idx;
- break;
- case DTV_ISDBT_SB_SEGMENT_COUNT:
- tvp->u.data = c->isdbt_sb_segment_count;
- break;
- case DTV_ISDBT_LAYER_ENABLED:
- tvp->u.data = c->isdbt_layer_enabled;
- break;
- case DTV_ISDBT_LAYERA_FEC:
- tvp->u.data = c->layer[0].fec;
- break;
- case DTV_ISDBT_LAYERA_MODULATION:
- tvp->u.data = c->layer[0].modulation;
- break;
- case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
- tvp->u.data = c->layer[0].segment_count;
- break;
- case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
- tvp->u.data = c->layer[0].interleaving;
- break;
- case DTV_ISDBT_LAYERB_FEC:
- tvp->u.data = c->layer[1].fec;
- break;
- case DTV_ISDBT_LAYERB_MODULATION:
- tvp->u.data = c->layer[1].modulation;
- break;
- case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
- tvp->u.data = c->layer[1].segment_count;
- break;
- case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
- tvp->u.data = c->layer[1].interleaving;
- break;
- case DTV_ISDBT_LAYERC_FEC:
- tvp->u.data = c->layer[2].fec;
- break;
- case DTV_ISDBT_LAYERC_MODULATION:
- tvp->u.data = c->layer[2].modulation;
- break;
- case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
- tvp->u.data = c->layer[2].segment_count;
- break;
- case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
- tvp->u.data = c->layer[2].interleaving;
- break;
- case DTV_ISDBS_TS_ID:
- tvp->u.data = c->isdbs_ts_id;
- break;
- case DTV_DVBT2_PLP_ID:
- tvp->u.data = c->dvbt2_plp_id;
- break;
-
- /* ATSC-MH */
- case DTV_ATSCMH_FIC_VER:
- tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
- break;
- case DTV_ATSCMH_PARADE_ID:
- tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
- break;
- case DTV_ATSCMH_NOG:
- tvp->u.data = fe->dtv_property_cache.atscmh_nog;
- break;
- case DTV_ATSCMH_TNOG:
- tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
- break;
- case DTV_ATSCMH_SGN:
- tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
- break;
- case DTV_ATSCMH_PRC:
- tvp->u.data = fe->dtv_property_cache.atscmh_prc;
- break;
- case DTV_ATSCMH_RS_FRAME_MODE:
- tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
- break;
- case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
- tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
- break;
- case DTV_ATSCMH_RS_CODE_MODE_PRI:
- tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
- break;
- case DTV_ATSCMH_RS_CODE_MODE_SEC:
- tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
- break;
- case DTV_ATSCMH_SCCC_BLOCK_MODE:
- tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
- break;
- case DTV_ATSCMH_SCCC_CODE_MODE_A:
- tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
- break;
- case DTV_ATSCMH_SCCC_CODE_MODE_B:
- tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
- break;
- case DTV_ATSCMH_SCCC_CODE_MODE_C:
- tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
- break;
- case DTV_ATSCMH_SCCC_CODE_MODE_D:
- tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Allow the frontend to override outgoing properties */
- if (fe->ops.get_property) {
- r = fe->ops.get_property(fe, tvp);
- if (r < 0)
- return r;
- }
-
- dtv_property_dump(tvp);
-
- 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;
- }
- /*
- * Get a delivery system that is compatible with DVBv3
- * NOTE: in order for this to work with softwares like Kaffeine that
- * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
- * DVB-S, drivers that support both should put the SYS_DVBS entry
- * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
- * The real fix is that userspace applications should not use DVBv3
- * and not trust on calling FE_SET_FRONTEND to switch the delivery
- * system.
- */
- ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
- if (fe->ops.delsys[ncaps] == desired_system) {
- delsys = desired_system;
- break;
- }
- ncaps++;
- }
- if (delsys == SYS_UNDEFINED) {
- dprintk("%s() Couldn't find a delivery system that matches %d\n",
- __func__, desired_system);
- }
- } 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;
-
- /* Allow the frontend to validate incoming properties */
- if (fe->ops.set_property) {
- r = fe->ops.set_property(fe, tvp);
- if (r < 0)
- return r;
- }
-
- switch(tvp->cmd) {
- case DTV_CLEAR:
- /*
- * Reset a cache of data specific to the frontend here. This does
- * not effect hardware.
- */
- dvb_frontend_clear_cache(fe);
- break;
- case DTV_TUNE:
- /* interpret the cache of data, build either a traditional frontend
- * tunerequest so we can pass validation in the FE_SET_FRONTEND
- * ioctl.
- */
- c->state = tvp->cmd;
- dprintk("%s() Finalised property cache\n", __func__);
-
- r = dtv_set_frontend(fe);
- break;
- case DTV_FREQUENCY:
- c->frequency = tvp->u.data;
- break;
- case DTV_MODULATION:
- c->modulation = tvp->u.data;
- break;
- case DTV_BANDWIDTH_HZ:
- c->bandwidth_hz = tvp->u.data;
- break;
- case DTV_INVERSION:
- c->inversion = tvp->u.data;
- break;
- case DTV_SYMBOL_RATE:
- c->symbol_rate = tvp->u.data;
- break;
- case DTV_INNER_FEC:
- c->fec_inner = tvp->u.data;
- break;
- case DTV_PILOT:
- c->pilot = tvp->u.data;
- break;
- case DTV_ROLLOFF:
- c->rolloff = tvp->u.data;
- break;
- case DTV_DELIVERY_SYSTEM:
- r = set_delivery_system(fe, tvp->u.data);
- break;
- case DTV_VOLTAGE:
- c->voltage = tvp->u.data;
- r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
- (void *)c->voltage);
- break;
- case DTV_TONE:
- c->sectone = tvp->u.data;
- r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
- (void *)c->sectone);
- break;
- case DTV_CODE_RATE_HP:
- c->code_rate_HP = tvp->u.data;
- break;
- case DTV_CODE_RATE_LP:
- c->code_rate_LP = tvp->u.data;
- break;
- case DTV_GUARD_INTERVAL:
- c->guard_interval = tvp->u.data;
- break;
- case DTV_TRANSMISSION_MODE:
- c->transmission_mode = tvp->u.data;
- break;
- case DTV_HIERARCHY:
- c->hierarchy = tvp->u.data;
- break;
-
- /* ISDB-T Support here */
- case DTV_ISDBT_PARTIAL_RECEPTION:
- c->isdbt_partial_reception = tvp->u.data;
- break;
- case DTV_ISDBT_SOUND_BROADCASTING:
- c->isdbt_sb_mode = tvp->u.data;
- break;
- case DTV_ISDBT_SB_SUBCHANNEL_ID:
- c->isdbt_sb_subchannel = tvp->u.data;
- break;
- case DTV_ISDBT_SB_SEGMENT_IDX:
- c->isdbt_sb_segment_idx = tvp->u.data;
- break;
- case DTV_ISDBT_SB_SEGMENT_COUNT:
- c->isdbt_sb_segment_count = tvp->u.data;
- break;
- case DTV_ISDBT_LAYER_ENABLED:
- c->isdbt_layer_enabled = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERA_FEC:
- c->layer[0].fec = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERA_MODULATION:
- c->layer[0].modulation = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
- c->layer[0].segment_count = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
- c->layer[0].interleaving = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERB_FEC:
- c->layer[1].fec = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERB_MODULATION:
- c->layer[1].modulation = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
- c->layer[1].segment_count = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
- c->layer[1].interleaving = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERC_FEC:
- c->layer[2].fec = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERC_MODULATION:
- c->layer[2].modulation = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
- c->layer[2].segment_count = tvp->u.data;
- break;
- case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
- c->layer[2].interleaving = tvp->u.data;
- break;
- case DTV_ISDBS_TS_ID:
- c->isdbs_ts_id = tvp->u.data;
- break;
- case DTV_DVBT2_PLP_ID:
- c->dvbt2_plp_id = tvp->u.data;
- break;
-
- /* ATSC-MH */
- case DTV_ATSCMH_PARADE_ID:
- fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
- break;
- case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
- fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
- break;
-
- default:
- return -EINVAL;
- }
-
- return r;
-}
-
-static int dvb_frontend_ioctl(struct file *file,
- unsigned int cmd, void *parg)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dvb_frontend *fe = dvbdev->priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- int err = -EOPNOTSUPP;
-
- dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
-
- if (fepriv->exit != DVB_FE_NO_EXIT)
- return -ENODEV;
-
- if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
- (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
- cmd == FE_DISEQC_RECV_SLAVE_REPLY))
- return -EPERM;
-
- if (down_interruptible (&fepriv->sem))
- return -ERESTARTSYS;
-
- if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
- err = dvb_frontend_ioctl_properties(file, cmd, parg);
- else {
- c->state = DTV_UNDEFINED;
- err = dvb_frontend_ioctl_legacy(file, cmd, parg);
- }
-
- up(&fepriv->sem);
- return err;
-}
-
-static int dvb_frontend_ioctl_properties(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 err = 0;
-
- struct dtv_properties *tvps = NULL;
- struct dtv_property *tvp = NULL;
- int i;
-
- dprintk("%s\n", __func__);
-
- if(cmd == FE_SET_PROPERTY) {
- tvps = (struct dtv_properties __user *)parg;
-
- dprintk("%s() properties.num = %d\n", __func__, tvps->num);
- dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
- /* Put an arbitrary limit on the number of messages that can
- * be sent at once */
- if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
- return -EINVAL;
-
- tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
- if (!tvp) {
- err = -ENOMEM;
- goto out;
- }
-
- if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
- err = -EFAULT;
- goto out;
- }
-
- for (i = 0; i < tvps->num; i++) {
- err = dtv_property_process_set(fe, tvp + i, file);
- if (err < 0)
- goto out;
- (tvp + i)->result = err;
- }
-
- if (c->state == DTV_TUNE)
- dprintk("%s() Property cache is full, tuning\n", __func__);
-
- } else
- if(cmd == FE_GET_PROPERTY) {
- tvps = (struct dtv_properties __user *)parg;
-
- dprintk("%s() properties.num = %d\n", __func__, tvps->num);
- dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
- /* Put an arbitrary limit on the number of messages that can
- * be sent at once */
- if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
- return -EINVAL;
-
- tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
- if (!tvp) {
- err = -ENOMEM;
- goto out;
- }
-
- if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
- err = -EFAULT;
- 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, c, tvp + i, file);
- if (err < 0)
- goto out;
- (tvp + i)->result = err;
- }
-
- if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
- err = -EFAULT;
- goto out;
- }
-
- } else
- err = -EOPNOTSUPP;
-
-out:
- kfree(tvp);
- 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_DVBS:
- case SYS_DVBS2:
- case SYS_ISDBS:
- case SYS_TURBO:
- 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) {
- cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
- DVB_FE_IOCTL_PRE);
- if (cb_err < 0)
- return cb_err;
- if (cb_err > 0)
- return 0;
- /* fe_ioctl_override returning 0 allows
- * dvb-core to continue handling the ioctl */
- }
-
- 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;
- err = 0;
- break;
- }
-
- case FE_READ_STATUS: {
- fe_status_t* status = parg;
-
- /* if retune was requested but hasn't occurred yet, prevent
- * that user get signal state from previous tuning */
- if (fepriv->state == FESTATE_RETUNE ||
- fepriv->state == FESTATE_ERROR) {
- err=0;
- *status = 0;
- break;
- }
-
- if (fe->ops.read_status)
- err = fe->ops.read_status(fe, status);
- break;
- }
- case FE_READ_BER:
- if (fe->ops.read_ber)
- err = fe->ops.read_ber(fe, (__u32*) parg);
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- if (fe->ops.read_signal_strength)
- err = fe->ops.read_signal_strength(fe, (__u16*) parg);
- break;
-
- case FE_READ_SNR:
- if (fe->ops.read_snr)
- err = fe->ops.read_snr(fe, (__u16*) parg);
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- if (fe->ops.read_ucblocks)
- err = fe->ops.read_ucblocks(fe, (__u32*) parg);
- break;
-
-
- case FE_DISEQC_RESET_OVERLOAD:
- if (fe->ops.diseqc_reset_overload) {
- err = fe->ops.diseqc_reset_overload(fe);
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- if (fe->ops.diseqc_send_master_cmd) {
- err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_DISEQC_SEND_BURST:
- if (fe->ops.diseqc_send_burst) {
- err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_SET_TONE:
- if (fe->ops.set_tone) {
- err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
- fepriv->tone = (fe_sec_tone_mode_t) parg;
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_SET_VOLTAGE:
- if (fe->ops.set_voltage) {
- err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
- fepriv->voltage = (fe_sec_voltage_t) parg;
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_DISHNETWORK_SEND_LEGACY_CMD:
- if (fe->ops.dishnetwork_send_legacy_command) {
- err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- } else if (fe->ops.set_voltage) {
- /*
- * NOTE: This is a fallback condition. Some frontends
- * (stv0299 for instance) take longer than 8msec to
- * respond to a set_voltage command. Those switches
- * need custom routines to switch properly. For all
- * other frontends, the following should work ok.
- * Dish network legacy switches (as used by Dish500)
- * are controlled by sending 9-bit command words
- * spaced 8msec apart.
- * the actual command word is switch/port dependent
- * so it is up to the userspace application to send
- * the right command.
- * The command must always start with a '0' after
- * initialization, so parg is 8 bits and does not
- * include the initialization or start bit
- */
- unsigned long swcmd = ((unsigned long) parg) << 1;
- struct timeval nexttime;
- struct timeval tv[10];
- int i;
- u8 last = 1;
- if (dvb_frontend_debug)
- printk("%s switch command: 0x%04lx\n", __func__, swcmd);
- do_gettimeofday(&nexttime);
- if (dvb_frontend_debug)
- memcpy(&tv[0], &nexttime, sizeof(struct timeval));
- /* before sending a command, initialize by sending
- * a 32ms 18V to the switch
- */
- fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
- dvb_frontend_sleep_until(&nexttime, 32000);
-
- for (i = 0; i < 9; i++) {
- if (dvb_frontend_debug)
- do_gettimeofday(&tv[i + 1]);
- if ((swcmd & 0x01) != last) {
- /* set voltage to (last ? 13V : 18V) */
- fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
- last = (last) ? 0 : 1;
- }
- swcmd = swcmd >> 1;
- if (i != 8)
- dvb_frontend_sleep_until(&nexttime, 8000);
- }
- if (dvb_frontend_debug) {
- printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
- __func__, fe->dvb->num);
- for (i = 1; i < 10; i++)
- printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
- }
- err = 0;
- fepriv->state = FESTATE_DISEQC;
- fepriv->status = 0;
- }
- break;
-
- case FE_DISEQC_RECV_SLAVE_REPLY:
- if (fe->ops.diseqc_recv_slave_reply)
- err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
- break;
-
- case FE_ENABLE_HIGH_LNB_VOLTAGE:
- if (fe->ops.enable_high_lnb_voltage)
- err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
- break;
-
- case FE_SET_FRONTEND:
- err = set_delivery_system(fe, SYS_UNDEFINED);
- if (err)
- break;
-
- 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:
- err = dtv_get_frontend(fe, parg);
- break;
-
- case FE_SET_FRONTEND_TUNE_MODE:
- fepriv->tune_mode_flags = (unsigned long) parg;
- err = 0;
- break;
- };
-
- if (fe->dvb->fe_ioctl_override) {
- cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
- DVB_FE_IOCTL_POST);
- if (cb_err < 0)
- return cb_err;
- }
-
- return err;
-}
-
-
-static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dvb_frontend *fe = dvbdev->priv;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
- dprintk ("%s\n", __func__);
-
- poll_wait (file, &fepriv->events.wait_queue, wait);
-
- if (fepriv->events.eventw != fepriv->events.eventr)
- return (POLLIN | POLLRDNORM | POLLPRI);
-
- return 0;
-}
-
-static int dvb_frontend_open(struct inode *inode, 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 dvb_adapter *adapter = fe->dvb;
- int ret;
-
- dprintk ("%s\n", __func__);
- if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
- return -ENODEV;
-
- if (adapter->mfe_shared) {
- mutex_lock (&adapter->mfe_lock);
-
- if (adapter->mfe_dvbdev == NULL)
- adapter->mfe_dvbdev = dvbdev;
-
- else if (adapter->mfe_dvbdev != dvbdev) {
- struct dvb_device
- *mfedev = adapter->mfe_dvbdev;
- struct dvb_frontend
- *mfe = mfedev->priv;
- struct dvb_frontend_private
- *mfepriv = mfe->frontend_priv;
- int mferetry = (dvb_mfe_wait_time << 1);
-
- mutex_unlock (&adapter->mfe_lock);
- while (mferetry-- && (mfedev->users != -1 ||
- mfepriv->thread != NULL)) {
- if(msleep_interruptible(500)) {
- if(signal_pending(current))
- return -EINTR;
- }
- }
-
- mutex_lock (&adapter->mfe_lock);
- if(adapter->mfe_dvbdev != dvbdev) {
- mfedev = adapter->mfe_dvbdev;
- mfe = mfedev->priv;
- mfepriv = mfe->frontend_priv;
- if (mfedev->users != -1 ||
- mfepriv->thread != NULL) {
- mutex_unlock (&adapter->mfe_lock);
- return -EBUSY;
- }
- adapter->mfe_dvbdev = dvbdev;
- }
- }
- }
-
- if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
- if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
- goto err0;
-
- /* If we took control of the bus, we need to force
- reinitialization. This is because many ts_bus_ctrl()
- functions strobe the RESET pin on the demod, and if the
- frontend thread already exists then the dvb_init() routine
- won't get called (which is what usually does initial
- register configuration). */
- fepriv->reinitialise = 1;
- }
-
- if ((ret = dvb_generic_open (inode, file)) < 0)
- goto err1;
-
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
- /* normal tune mode when opened R/W */
- fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
- fepriv->tone = -1;
- fepriv->voltage = -1;
-
- ret = dvb_frontend_start (fe);
- if (ret)
- goto err2;
-
- /* empty event queue */
- fepriv->events.eventr = fepriv->events.eventw = 0;
- }
-
- if (adapter->mfe_shared)
- mutex_unlock (&adapter->mfe_lock);
- return ret;
-
-err2:
- dvb_generic_release(inode, file);
-err1:
- if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
- fe->ops.ts_bus_ctrl(fe, 0);
-err0:
- if (adapter->mfe_shared)
- mutex_unlock (&adapter->mfe_lock);
- return ret;
-}
-
-static int dvb_frontend_release(struct inode *inode, struct file *file)
-{
- struct dvb_device *dvbdev = file->private_data;
- struct dvb_frontend *fe = dvbdev->priv;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- int ret;
-
- dprintk ("%s\n", __func__);
-
- 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;
- wake_up(&dvbdev->wait_queue);
- }
- if (fe->ops.ts_bus_ctrl)
- fe->ops.ts_bus_ctrl(fe, 0);
- }
-
- return ret;
-}
-
-static const struct file_operations dvb_frontend_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = dvb_generic_ioctl,
- .poll = dvb_frontend_poll,
- .open = dvb_frontend_open,
- .release = dvb_frontend_release,
- .llseek = noop_llseek,
-};
-
-int dvb_register_frontend(struct dvb_adapter* dvb,
- struct dvb_frontend* fe)
-{
- struct dvb_frontend_private *fepriv;
- static const struct dvb_device dvbdev_template = {
- .users = ~0,
- .writers = 1,
- .readers = (~0)-1,
- .fops = &dvb_frontend_fops,
- .kernel_ioctl = dvb_frontend_ioctl
- };
-
- dprintk ("%s\n", __func__);
-
- if (mutex_lock_interruptible(&frontend_mutex))
- return -ERESTARTSYS;
-
- fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
- if (fe->frontend_priv == NULL) {
- mutex_unlock(&frontend_mutex);
- return -ENOMEM;
- }
- fepriv = fe->frontend_priv;
-
- sema_init(&fepriv->sem, 1);
- init_waitqueue_head (&fepriv->wait_queue);
- init_waitqueue_head (&fepriv->events.wait_queue);
- mutex_init(&fepriv->events.mtx);
- fe->dvb = dvb;
- fepriv->inversion = INVERSION_OFF;
-
- printk ("DVB: registering adapter %i frontend %i (%s)...\n",
- fe->dvb->num,
- fe->id,
- fe->ops.info.name);
-
- 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;
-}
-EXPORT_SYMBOL(dvb_register_frontend);
-
-int dvb_unregister_frontend(struct dvb_frontend* fe)
-{
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- dprintk ("%s\n", __func__);
-
- mutex_lock(&frontend_mutex);
- dvb_frontend_stop (fe);
- mutex_unlock(&frontend_mutex);
-
- if (fepriv->dvbdev->users < -1)
- wait_event(fepriv->dvbdev->wait_queue,
- fepriv->dvbdev->users==-1);
-
- mutex_lock(&frontend_mutex);
- dvb_unregister_device (fepriv->dvbdev);
-
- /* fe is invalid now */
- kfree(fepriv);
- mutex_unlock(&frontend_mutex);
- return 0;
-}
-EXPORT_SYMBOL(dvb_unregister_frontend);
-
-#ifdef CONFIG_MEDIA_ATTACH
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
- void *ptr;
-
- if (fe->ops.release_sec) {
- fe->ops.release_sec(fe);
- symbol_put_addr(fe->ops.release_sec);
- }
- if (fe->ops.tuner_ops.release) {
- fe->ops.tuner_ops.release(fe);
- symbol_put_addr(fe->ops.tuner_ops.release);
- }
- if (fe->ops.analog_ops.release) {
- fe->ops.analog_ops.release(fe);
- symbol_put_addr(fe->ops.analog_ops.release);
- }
- ptr = (void*)fe->ops.release;
- if (ptr) {
- fe->ops.release(fe);
- symbol_put_addr(ptr);
- }
-}
-#else
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
- if (fe->ops.release_sec)
- fe->ops.release_sec(fe);
- if (fe->ops.tuner_ops.release)
- fe->ops.tuner_ops.release(fe);
- if (fe->ops.analog_ops.release)
- fe->ops.analog_ops.release(fe);
- if (fe->ops.release)
- fe->ops.release(fe);
-}
-#endif
-EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
deleted file mode 100644
index 7c64c09103a9..000000000000
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * dvb_frontend.h
- *
- * Copyright (C) 2001 convergence integrated media GmbH
- * Copyright (C) 2004 convergence GmbH
- *
- * Written by Ralph Metzler
- * Overhauled by Holger Waechtler
- * Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- *
- */
-
-#ifndef _DVB_FRONTEND_H_
-#define _DVB_FRONTEND_H_
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/dvb/frontend.h>
-
-#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;
-
-struct dvb_tuner_info {
- char name[128];
-
- u32 frequency_min;
- u32 frequency_max;
- u32 frequency_step;
-
- u32 bandwidth_min;
- u32 bandwidth_max;
- u32 bandwidth_step;
-};
-
-struct analog_parameters {
- unsigned int frequency;
- unsigned int mode;
- unsigned int audmode;
- u64 std;
-};
-
-enum dvbfe_modcod {
- DVBFE_MODCOD_DUMMY_PLFRAME = 0,
- DVBFE_MODCOD_QPSK_1_4,
- DVBFE_MODCOD_QPSK_1_3,
- DVBFE_MODCOD_QPSK_2_5,
- DVBFE_MODCOD_QPSK_1_2,
- DVBFE_MODCOD_QPSK_3_5,
- DVBFE_MODCOD_QPSK_2_3,
- DVBFE_MODCOD_QPSK_3_4,
- DVBFE_MODCOD_QPSK_4_5,
- DVBFE_MODCOD_QPSK_5_6,
- DVBFE_MODCOD_QPSK_8_9,
- DVBFE_MODCOD_QPSK_9_10,
- DVBFE_MODCOD_8PSK_3_5,
- DVBFE_MODCOD_8PSK_2_3,
- DVBFE_MODCOD_8PSK_3_4,
- DVBFE_MODCOD_8PSK_5_6,
- DVBFE_MODCOD_8PSK_8_9,
- DVBFE_MODCOD_8PSK_9_10,
- DVBFE_MODCOD_16APSK_2_3,
- DVBFE_MODCOD_16APSK_3_4,
- DVBFE_MODCOD_16APSK_4_5,
- DVBFE_MODCOD_16APSK_5_6,
- DVBFE_MODCOD_16APSK_8_9,
- DVBFE_MODCOD_16APSK_9_10,
- DVBFE_MODCOD_32APSK_3_4,
- DVBFE_MODCOD_32APSK_4_5,
- DVBFE_MODCOD_32APSK_5_6,
- DVBFE_MODCOD_32APSK_8_9,
- DVBFE_MODCOD_32APSK_9_10,
- DVBFE_MODCOD_RESERVED_1,
- DVBFE_MODCOD_BPSK_1_3,
- DVBFE_MODCOD_BPSK_1_4,
- DVBFE_MODCOD_RESERVED_2
-};
-
-enum tuner_param {
- DVBFE_TUNER_FREQUENCY = (1 << 0),
- DVBFE_TUNER_TUNERSTEP = (1 << 1),
- DVBFE_TUNER_IFFREQ = (1 << 2),
- DVBFE_TUNER_BANDWIDTH = (1 << 3),
- DVBFE_TUNER_REFCLOCK = (1 << 4),
- DVBFE_TUNER_IQSENSE = (1 << 5),
- DVBFE_TUNER_DUMMY = (1 << 31)
-};
-
-/*
- * ALGO_HW: (Hardware Algorithm)
- * ----------------------------------------------------------------
- * Devices that support this algorithm do everything in hardware
- * and no software support is needed to handle them.
- * Requesting these devices to LOCK is the only thing required,
- * device is supposed to do everything in the hardware.
- *
- * ALGO_SW: (Software Algorithm)
- * ----------------------------------------------------------------
- * These are dumb devices, that require software to do everything
- *
- * ALGO_CUSTOM: (Customizable Agorithm)
- * ----------------------------------------------------------------
- * Devices having this algorithm can be customized to have specific
- * algorithms in the frontend driver, rather than simply doing a
- * software zig-zag. In this case the zigzag maybe hardware assisted
- * or it maybe completely done in hardware. In all cases, usage of
- * this algorithm, in conjunction with the search and track
- * callbacks, utilizes the driver specific algorithm.
- *
- * ALGO_RECOVERY: (Recovery Algorithm)
- * ----------------------------------------------------------------
- * These devices have AUTO recovery capabilities from LOCK failure
- */
-enum dvbfe_algo {
- DVBFE_ALGO_HW = (1 << 0),
- DVBFE_ALGO_SW = (1 << 1),
- DVBFE_ALGO_CUSTOM = (1 << 2),
- DVBFE_ALGO_RECOVERY = (1 << 31)
-};
-
-struct tuner_state {
- u32 frequency;
- u32 tunerstep;
- u32 ifreq;
- u32 bandwidth;
- u32 iqsense;
- u32 refclock;
-};
-
-/*
- * search callback possible return status
- *
- * DVBFE_ALGO_SEARCH_SUCCESS
- * The frontend search algorithm completed and returned successfully
- *
- * DVBFE_ALGO_SEARCH_ASLEEP
- * The frontend search algorithm is sleeping
- *
- * DVBFE_ALGO_SEARCH_FAILED
- * The frontend search for a signal failed
- *
- * DVBFE_ALGO_SEARCH_INVALID
- * The frontend search algorith was probably supplied with invalid
- * parameters and the search is an invalid one
- *
- * DVBFE_ALGO_SEARCH_ERROR
- * The frontend search algorithm failed due to some error
- *
- * DVBFE_ALGO_SEARCH_AGAIN
- * The frontend search algorithm was requested to search again
- */
-enum dvbfe_search {
- DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
- DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
- DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
- DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
- DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
- DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
-};
-
-
-struct dvb_tuner_ops {
-
- struct dvb_tuner_info info;
-
- int (*release)(struct dvb_frontend *fe);
- int (*init)(struct dvb_frontend *fe);
- int (*sleep)(struct dvb_frontend *fe);
-
- /** This is for simple PLLs - set all parameters in one go. */
- 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, u8 *buf, int buf_len);
-
- /** This is to allow setting tuner-specific configs */
- int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-
- int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
- int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
- int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
-
-#define TUNER_STATUS_LOCKED 1
-#define TUNER_STATUS_STEREO 2
- int (*get_status)(struct dvb_frontend *fe, u32 *status);
- int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
- int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
-
- /** These are provided separately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter separately. */
- int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
- int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
-
- /*
- * These are provided separately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter separately.
- */
- int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
- int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-};
-
-struct analog_demod_info {
- char *name;
-};
-
-struct analog_demod_ops {
-
- struct analog_demod_info info;
-
- void (*set_params)(struct dvb_frontend *fe,
- struct analog_parameters *params);
- int (*has_signal)(struct dvb_frontend *fe);
- int (*get_afc)(struct dvb_frontend *fe);
- void (*tuner_status)(struct dvb_frontend *fe);
- void (*standby)(struct dvb_frontend *fe);
- void (*release)(struct dvb_frontend *fe);
- int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
-
- /** This is to allow setting tuner-specific configuration */
- 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);
-
- int (*init)(struct dvb_frontend* fe);
- int (*sleep)(struct dvb_frontend* fe);
-
- int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
-
- /* if this is set, it overrides the default swzigzag */
- int (*tune)(struct dvb_frontend* fe,
- bool re_tune,
- unsigned int mode_flags,
- unsigned int *delay,
- fe_status_t *status);
- /* get frontend tuning algorithm from the module */
- 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);
- int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
-
- 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);
- int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
- int (*read_snr)(struct dvb_frontend* fe, u16* snr);
- int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
-
- int (*diseqc_reset_overload)(struct dvb_frontend* fe);
- int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
- int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
- int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
- int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
- int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
- int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
- int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
- int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
- int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
-
- /* 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_tuner_ops tuner_ops;
- struct analog_demod_ops analog_ops;
-
- int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
- int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
-};
-
-#ifdef __DVB_CORE__
-#define MAX_EVENT 8
-
-struct dvb_fe_events {
- struct dvb_frontend_event events[MAX_EVENT];
- int eventw;
- int eventr;
- int overflow;
- wait_queue_head_t wait_queue;
- struct mutex mtx;
-};
-#endif
-
-struct dtv_frontend_properties {
-
- /* Cache State */
- u32 state;
-
- u32 frequency;
- fe_modulation_t modulation;
-
- fe_sec_voltage_t voltage;
- fe_sec_tone_mode_t sectone;
- fe_spectral_inversion_t inversion;
- fe_code_rate_t fec_inner;
- fe_transmit_mode_t transmission_mode;
- u32 bandwidth_hz; /* 0 = AUTO */
- fe_guard_interval_t guard_interval;
- fe_hierarchy_t hierarchy;
- u32 symbol_rate;
- fe_code_rate_t code_rate_HP;
- fe_code_rate_t code_rate_LP;
-
- fe_pilot_t pilot;
- fe_rolloff_t rolloff;
-
- fe_delivery_system_t delivery_system;
-
- /* ISDB-T specifics */
- u8 isdbt_partial_reception;
- u8 isdbt_sb_mode;
- u8 isdbt_sb_subchannel;
- u32 isdbt_sb_segment_idx;
- u32 isdbt_sb_segment_count;
- u8 isdbt_layer_enabled;
- struct {
- u8 segment_count;
- fe_code_rate_t fec;
- fe_modulation_t modulation;
- u8 interleaving;
- } layer[3];
-
- /* ISDB-T specifics */
- u32 isdbs_ts_id;
-
- /* DVB-T2 specifics */
- u32 dvbt2_plp_id;
-
- /* ATSC-MH specifics */
- u8 atscmh_fic_ver;
- u8 atscmh_parade_id;
- u8 atscmh_nog;
- u8 atscmh_tnog;
- u8 atscmh_sgn;
- u8 atscmh_prc;
-
- u8 atscmh_rs_frame_mode;
- u8 atscmh_rs_frame_ensemble;
- u8 atscmh_rs_code_mode_pri;
- u8 atscmh_rs_code_mode_sec;
- u8 atscmh_sccc_block_mode;
- u8 atscmh_sccc_code_mode_a;
- u8 atscmh_sccc_code_mode_b;
- u8 atscmh_sccc_code_mode_c;
- u8 atscmh_sccc_code_mode_d;
-};
-
-struct dvb_frontend {
- struct dvb_frontend_ops ops;
- struct dvb_adapter *dvb;
- void *demodulator_priv;
- void *tuner_priv;
- void *frontend_priv;
- void *sec_priv;
- 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;
-};
-
-extern int dvb_register_frontend(struct dvb_adapter *dvb,
- struct dvb_frontend *fe);
-
-extern int dvb_unregister_frontend(struct dvb_frontend *fe);
-
-extern void dvb_frontend_detach(struct dvb_frontend *fe);
-
-extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-
-extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
-extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
deleted file mode 100644
index fcc6ae98745e..000000000000
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * dvbdev.h
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- * for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- *
- */
-
-#ifndef _DVBDEV_H_
-#define _DVBDEV_H_
-
-#include <linux/types.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-
-#define DVB_MAJOR 212
-
-#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
- #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
-#else
- #define DVB_MAX_ADAPTERS 8
-#endif
-
-#define DVB_UNSET (-1)
-
-#define DVB_DEVICE_VIDEO 0
-#define DVB_DEVICE_AUDIO 1
-#define DVB_DEVICE_SEC 2
-#define DVB_DEVICE_FRONTEND 3
-#define DVB_DEVICE_DEMUX 4
-#define DVB_DEVICE_DVR 5
-#define DVB_DEVICE_CA 6
-#define DVB_DEVICE_NET 7
-#define DVB_DEVICE_OSD 8
-
-#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
- static short adapter_nr[] = \
- {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
- module_param_array(adapter_nr, short, NULL, 0444); \
- MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
-
-struct dvb_frontend;
-
-struct dvb_adapter {
- int num;
- struct list_head list_head;
- struct list_head device_list;
- const char *name;
- u8 proposed_mac [6];
- void* priv;
-
- struct device *device;
-
- struct module *module;
-
- int mfe_shared; /* indicates mutually exclusive frontends */
- struct dvb_device *mfe_dvbdev; /* frontend device in use */
- struct mutex mfe_lock; /* access lock for thread creation */
-
- /* Allow the adapter/bridge driver to perform an action before and/or
- * after the core handles an ioctl:
- *
- * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
- * DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
- *
- * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
- *
- * return 0 to allow dvb-core to handle the ioctl.
- * return a positive int to prevent dvb-core from handling the ioctl,
- * and exit without error.
- * return a negative int to prevent dvb-core from handling the ioctl,
- * and return that value as an error.
- *
- * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
- *
- * return 0 to allow the dvb_frontend ioctl handler to exit normally.
- * return a negative int to cause the dvb_frontend ioctl handler to
- * return that value as an error.
- */
-#define DVB_FE_IOCTL_PRE 0
-#define DVB_FE_IOCTL_POST 1
- int (*fe_ioctl_override)(struct dvb_frontend *fe,
- unsigned int cmd, void *parg,
- unsigned int stage);
-};
-
-
-struct dvb_device {
- struct list_head list_head;
- const struct file_operations *fops;
- struct dvb_adapter *adapter;
- int type;
- int minor;
- u32 id;
-
- /* in theory, 'users' can vanish now,
- but I don't want to change too much now... */
- int readers;
- int writers;
- int users;
-
- wait_queue_head_t wait_queue;
- /* don't really need those !? -- FIXME: use video_usercopy */
- int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
-
- void *priv;
-};
-
-
-extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
- struct module *module, struct device *device,
- short *adapter_nums);
-extern int dvb_unregister_adapter (struct dvb_adapter *adap);
-
-extern int dvb_register_device (struct dvb_adapter *adap,
- struct dvb_device **pdvbdev,
- const struct dvb_device *template,
- void *priv,
- int type);
-
-extern void dvb_unregister_device (struct dvb_device *dvbdev);
-
-extern int dvb_generic_open (struct inode *inode, struct file *file);
-extern int dvb_generic_release (struct inode *inode, struct file *file);
-extern long dvb_generic_ioctl (struct file *file,
- unsigned int cmd, unsigned long arg);
-
-/* we don't mess with video_usercopy() any more,
-we simply define out own dvb_usercopy(), which will hopefully become
-generic_usercopy() someday... */
-
-extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
- int (*func)(struct file *file, unsigned int cmd, void *arg));
-
-/** generic DVB attach function. */
-#ifdef CONFIG_MEDIA_ATTACH
-#define dvb_attach(FUNCTION, ARGS...) ({ \
- void *__r = NULL; \
- typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
- if (__a) { \
- __r = (void *) __a(ARGS); \
- if (__r == NULL) \
- symbol_put(FUNCTION); \
- } else { \
- printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
- } \
- __r; \
-})
-
-#else
-#define dvb_attach(FUNCTION, ARGS...) ({ \
- FUNCTION(ARGS); \
-})
-
-#endif
-
-#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
deleted file mode 100644
index c2161565023a..000000000000
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ /dev/null
@@ -1,440 +0,0 @@
-config DVB_USB
- tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB && I2C && RC_CORE
- help
- By enabling this you will be able to choose the various supported
- USB1.1 and USB2.0 DVB devices.
-
- Almost every USB device needs a firmware, please look into
- <file:Documentation/dvb/README.dvb-usb>.
-
- For a complete list of supported USB devices see the LinuxTV DVB Wiki:
- <http://www.linuxtv.org/wiki/index.php/DVB_USB>
-
- Say Y if you own a USB DVB device.
-
-config DVB_USB_DEBUG
- bool "Enable extended debug support for all DVB-USB devices"
- depends on DVB_USB
- help
- Say Y if you want to enable debugging. See modinfo dvb-usb (and the
- appropriate drivers) for debug levels.
-
-config DVB_USB_A800
- tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
- depends on DVB_USB
- select DVB_DIB3000MC
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
-
-config DVB_USB_DIBUSB_MB
- tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_DIB3000MB
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- help
- Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
- DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
-
- For an up-to-date list of devices supported by this driver, have a look
- on the Linux-DVB Wiki at www.linuxtv.org.
-
- Say Y if you own such a device and want to use it. You should build it as
- a module.
-
-config DVB_USB_DIBUSB_MB_FAULTY
- bool "Support faulty USB IDs"
- depends on DVB_USB_DIBUSB_MB
- help
- Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
-
-config DVB_USB_DIBUSB_MC
- tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
- depends on DVB_USB
- select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- help
- Support for USB2.0 DVB-T receivers based on reference designs made by
- DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
-
- For an up-to-date list of devices supported by this driver, have a look
- on the Linux-DVB Wiki at www.linuxtv.org.
-
- Say Y if you own such a device and want to use it. You should build it as
- a module.
-
-config DVB_USB_DIB0700
- tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
- depends on DVB_USB
- select DVB_DIB7000P if !DVB_FE_CUSTOMISE
- select DVB_DIB7000M if !DVB_FE_CUSTOMISE
- select DVB_DIB8000 if !DVB_FE_CUSTOMISE
- select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
- help
- Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
- USB bridge is also present in devices having the DiB7700 DVB-T-USB
- silicon. This chip can be found in devices offered by Hauppauge,
- Avermedia and other big and small companies.
-
- For an up-to-date list of devices supported by this driver, have a look
- on the LinuxTV Wiki at www.linuxtv.org.
-
- Say Y if you own such a device and want to use it. You should build it as
- a module.
-
-config DVB_USB_UMT_010
- tristate "HanfTek UMT-010 DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_DIB3000MC
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
-
-config DVB_USB_CXUSB
- tristate "Conexant USB2.0 hybrid reference design support"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_CX22702 if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_DIB7000P if !DVB_FE_CUSTOMISE
- select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
- select DVB_ATBM8830 if !DVB_FE_CUSTOMISE
- select DVB_LGS8GXX if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Conexant USB2.0 hybrid reference design.
- Currently, only DVB and ATSC modes are supported, analog mode
- shall be added in the future. Devices that require this module:
-
- Medion MD95700 hybrid USB2.0 device.
- DViCO FusionHDTV (Bluebird) USB2.0 devices
-
-config DVB_USB_M920X
- tristate "Uli m920x DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
- Currently, only devices with a product id of
- "DTV USB MINI" (in cold state) are supported.
- Firmware required.
-
-config DVB_USB_GL861
- tristate "Genesys Logic GL861 USB2.0 support"
- depends on DVB_USB
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
- receiver with USB ID 0db0:5581.
-
-config DVB_USB_AU6610
- tristate "Alcor Micro AU6610 USB2.0 support"
- depends on DVB_USB
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
-
-config DVB_USB_DIGITV
- tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_NXT6000 if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
-
-config DVB_USB_VP7045
- tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
- depends on DVB_USB
- help
- Say Y here to support the
-
- TwinhanDTV Alpha (stick) (VP-7045),
- TwinhanDTV MagicBox II (VP-7046),
- DigitalNow TinyUSB 2 DVB-t,
- DigitalRise USB 2.0 Ter (Beetle) and
- TYPHOON DVB-T USB DRIVE
-
- DVB-T USB2.0 receivers.
-
-config DVB_USB_VP702X
- tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
- depends on DVB_USB
- help
- Say Y here to support the
-
- TwinhanDTV StarBox,
- DigitalRise USB Starbox and
- TYPHOON DVB-S USB 2.0 BOX
-
- DVB-S USB2.0 receivers.
-
-config DVB_USB_GP8PSK
- tristate "GENPIX 8PSK->USB module support"
- depends on DVB_USB
- help
- Say Y here to support the
- GENPIX 8psk module
-
- DVB-S USB2.0 receivers.
-
-config DVB_USB_NOVA_T_USB2
- tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_DIB3000MC
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
-
-config DVB_USB_TTUSB2
- tristate "Pinnacle 400e DVB-S USB2.0 support"
- depends on DVB_USB
- select DVB_TDA10086 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_TDA826X if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
- firmware protocol used by this module is similar to the one used by the
- old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
-
-config DVB_USB_DTT200U
- tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
- depends on DVB_USB
- help
- Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
-
- The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
-
- The WT-220U and its clones are pen-sized.
-
-config DVB_USB_OPERA1
- tristate "Opera1 DVB-S USB2.0 receiver"
- depends on DVB_USB
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_PLL if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the Opera DVB-S USB2.0 receiver.
-
-config DVB_USB_AF9005
- tristate "Afatech AF9005 DVB-T USB1.1 support"
- depends on DVB_USB && EXPERIMENTAL
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
- and the TerraTec Cinergy T USB XE (Rev.1)
-
-config DVB_USB_AF9005_REMOTE
- tristate "Afatech AF9005 default remote control support"
- depends on DVB_USB_AF9005
- help
- Say Y here to support the default remote control decoding for the
- Afatech AF9005 based receiver.
-
-config DVB_USB_PCTV452E
- tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
- depends on DVB_USB
- select TTPCI_EEPROM
- select DVB_LNBP22 if !DVB_FE_CUSTOMISE
- select DVB_STB0899 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- help
- Support for external USB adapter designed by Pinnacle,
- shipped under the brand name 'PCTV HDTV Pro USB'.
- Also supports TT Connect S2-3600/3650 cards.
- Say Y if you own such a device and want to use it.
-
-config DVB_USB_DW2102
- tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_STV0288 if !DVB_FE_CUSTOMISE
- select DVB_STB6000 if !DVB_FE_CUSTOMISE
- select DVB_CX24116 if !DVB_FE_CUSTOMISE
- select DVB_SI21XX if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select DVB_MT312 if !DVB_FE_CUSTOMISE
- select DVB_ZL10039 if !DVB_FE_CUSTOMISE
- select DVB_DS3000 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- select DVB_STV6110 if !DVB_FE_CUSTOMISE
- select DVB_STV0900 if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
- receivers.
-
-config DVB_USB_CINERGY_T2
- tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
- depends on DVB_USB
- help
- Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
-
- Say Y if you own such a device and want to use it.
-
-config DVB_USB_ANYSEE
- tristate "Anysee DVB-T/C USB2.0 support"
- depends on DVB_USB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
- select DVB_CX24116 if !DVB_FE_CUSTOMISE
- 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.
-
-config DVB_USB_DTV5100
- tristate "AME DTV-5100 USB2.0 DVB-T support"
- depends on DVB_USB
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
-
-config DVB_USB_AF9015
- tristate "Afatech AF9015 DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_AF9013
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
-
-config DVB_USB_CE6230
- tristate "Intel CE6230 DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_ZL10353
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
-
-config DVB_USB_FRIIO
- tristate "Friio ISDB-T USB2.0 Receiver support"
- depends on DVB_USB
- help
- Say Y here to support the Japanese DTV receiver Friio.
-
-config DVB_USB_EC168
- tristate "E3C EC168 DVB-T USB2.0 support"
- 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
- select DVB_STB0899 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the AZ6027 device
-
-config DVB_USB_LME2510
- tristate "LME DM04/QQBOX DVB-S USB2.0 support"
- depends on DVB_USB
- select DVB_TDA10086 if !DVB_FE_CUSTOMISE
- select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_STV0288 if !DVB_FE_CUSTOMISE
- 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 .
-
-config DVB_USB_TECHNISAT_USB2
- tristate "Technisat DVB-S/S2 USB2.0 support"
- depends on DVB_USB
- select DVB_STV090x if !DVB_FE_CUSTOMISE
- select DVB_STV6110x if !DVB_FE_CUSTOMISE
- help
- Say Y here to support the Technisat USB2 DVB-S/S2 device
-
-config DVB_USB_IT913X
- tristate "it913x driver"
- depends on DVB_USB
- select DVB_IT913X_FE
- help
- Say Y here to support the it913x device
-
-config DVB_USB_MXL111SF
- tristate "MxL111SF DTV USB2.0 support"
- depends on DVB_USB
- select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
- select DVB_LG2160 if !DVB_FE_CUSTOMISE
- 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 DVB_RTL2832
- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Realtek RTL28xxU DVB USB receiver.
-
-config DVB_USB_AF9035
- tristate "Afatech AF9035 DVB-T USB2.0 support"
- depends on DVB_USB
- select DVB_AF9033
- select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
- help
- Say Y here to support the Afatech AF9035 based DVB USB receiver.
-
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
deleted file mode 100644
index b667ac39a4e3..000000000000
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ /dev/null
@@ -1,121 +0,0 @@
-dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
-obj-$(CONFIG_DVB_USB) += dvb-usb.o
-
-dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
-obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
-
-dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
-obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
-
-dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
-obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
-
-dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
-obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
-
-dvb-usb-dibusb-common-objs = dibusb-common.o
-
-dvb-usb-a800-objs = a800.o
-obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
-
-dvb-usb-dibusb-mb-objs = dibusb-mb.o
-obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
-
-dvb-usb-dibusb-mc-objs = dibusb-mc.o
-obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
-
-dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
-obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
-
-dvb-usb-umt-010-objs = umt-010.o
-obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
-
-dvb-usb-m920x-objs = m920x.o
-obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
-
-dvb-usb-gl861-objs = gl861.o
-obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
-
-dvb-usb-au6610-objs = au6610.o
-obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
-
-dvb-usb-digitv-objs = digitv.o
-obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
-
-dvb-usb-cxusb-objs = cxusb.o
-obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
-
-dvb-usb-ttusb2-objs = ttusb2.o
-obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
-
-dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
-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
-
-dvb-usb-af9005-remote-objs = af9005-remote.o
-obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
-
-dvb-usb-anysee-objs = anysee.o
-obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
-
-dvb-usb-pctv452e-objs = pctv452e.o
-obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
-
-dvb-usb-dw2102-objs = dw2102.o
-obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
-
-dvb-usb-dtv5100-objs = dtv5100.o
-obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
-
-dvb-usb-af9015-objs = af9015.o
-obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
-
-dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
-obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
-
-dvb-usb-ce6230-objs = ce6230.o
-obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
-
-dvb-usb-friio-objs = friio.o friio-fe.o
-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
-
-dvb-usb-lmedm04-objs = lmedm04.o
-obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
-
-dvb-usb-technisat-usb2-objs = technisat-usb2.o
-obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
-
-dvb-usb-it913x-objs := it913x.o
-obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
-
-dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
-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
-
-dvb-usb-rtl28xxu-objs = rtl28xxu.o
-obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
-
-dvb-usb-af9035-objs = af9035.o
-obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
-
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
-ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
-# due to tuner-xc3028
-ccflags-y += -I$(srctree)/drivers/media/common/tuners
-ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
-
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
deleted file mode 100644
index 677fed79b01e..000000000000
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ /dev/null
@@ -1,1952 +0,0 @@
-/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- * 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/hash.h>
-#include <linux/slab.h>
-
-#include "af9015.h"
-#include "af9013.h"
-#include "mt2060.h"
-#include "qt1010.h"
-#include "tda18271.h"
-#include "mxl5005s.h"
-#include "mc44s803.h"
-#include "tda18218.h"
-#include "mxl5007t.h"
-
-static int dvb_usb_af9015_debug;
-module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_af9015_remote;
-module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
-MODULE_PARM_DESC(remote, "select remote");
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static DEFINE_MUTEX(af9015_usb_mutex);
-
-static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[3];
-static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
-
-static struct af9013_config af9015_af9013_config[] = {
- {
- .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,
-
- }, {
- .ts_mode = AF9013_TS_SERIAL,
- .api_version = { 0, 1, 9, 0 },
- .gpio[0] = AF9013_GPIO_TUNER_ON,
- .gpio[1] = AF9013_GPIO_LO,
- }
-};
-
-static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
-{
-#define BUF_LEN 63
-#define REQ_HDR_LEN 8 /* send header size */
-#define ACK_HDR_LEN 2 /* rece header size */
- int act_len, ret;
- u8 buf[BUF_LEN];
- u8 write = 1;
- u8 msg_len = REQ_HDR_LEN;
- static u8 seq; /* packet sequence number */
-
- if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
- return -EAGAIN;
-
- buf[0] = req->cmd;
- buf[1] = seq++;
- buf[2] = req->i2c_addr;
- buf[3] = req->addr >> 8;
- buf[4] = req->addr & 0xff;
- buf[5] = req->mbox;
- buf[6] = req->addr_len;
- buf[7] = req->data_len;
-
- switch (req->cmd) {
- case GET_CONFIG:
- case READ_MEMORY:
- case RECONNECT_USB:
- write = 0;
- break;
- case READ_I2C:
- write = 0;
- buf[2] |= 0x01; /* set I2C direction */
- case WRITE_I2C:
- buf[0] = READ_WRITE_I2C;
- break;
- case WRITE_MEMORY:
- if (((req->addr & 0xff00) == 0xff00) ||
- ((req->addr & 0xff00) == 0xae00))
- buf[0] = WRITE_VIRTUAL_MEMORY;
- case WRITE_VIRTUAL_MEMORY:
- case COPY_FIRMWARE:
- case DOWNLOAD_FIRMWARE:
- case BOOT:
- break;
- default:
- err("unknown command:%d", req->cmd);
- ret = -1;
- goto error_unlock;
- }
-
- /* buffer overflow check */
- if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
- (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
- err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
- ret = -EINVAL;
- goto error_unlock;
- }
-
- /* write requested */
- if (write) {
- memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
- msg_len += req->data_len;
- }
-
- deb_xfer(">>> ");
- debug_dump(buf, msg_len, deb_xfer);
-
- /* send req */
- ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
- &act_len, AF9015_USB_TIMEOUT);
- if (ret)
- err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
- else
- if (act_len != msg_len)
- ret = -1; /* all data is not send */
- if (ret)
- goto error_unlock;
-
- /* no ack for those packets */
- if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
- goto exit_unlock;
-
- /* write receives seq + status = 2 bytes
- read receives seq + status + data = 2 + N bytes */
- msg_len = ACK_HDR_LEN;
- if (!write)
- msg_len += req->data_len;
-
- ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
- &act_len, AF9015_USB_TIMEOUT);
- if (ret) {
- err("recv bulk message failed:%d", ret);
- ret = -1;
- goto error_unlock;
- }
-
- deb_xfer("<<< ");
- debug_dump(buf, act_len, deb_xfer);
-
- /* check status */
- if (buf[1]) {
- err("command failed:%d", buf[1]);
- ret = -1;
- goto error_unlock;
- }
-
- /* read request, copy returned data to return buf */
- if (!write)
- memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
-
-error_unlock:
-exit_unlock:
- mutex_unlock(&af9015_usb_mutex);
-
- return ret;
-}
-
-static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
- return af9015_rw_udev(d->udev, req);
-}
-
-static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
- u8 len)
-{
- struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
- val};
- return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
-{
- return af9015_write_regs(d, addr, &val, 1);
-}
-
-static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
-{
- struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
- val};
- return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
-{
- return af9015_read_regs(d, addr, val, 1);
-}
-
-static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
- u8 val)
-{
- struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
-
- 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);
-}
-
-static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
- u8 *val)
-{
- struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
-
- 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);
-}
-
-static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0, i = 0;
- u16 addr;
- u8 uninitialized_var(mbox), addr_len;
- struct req_t req;
-
-/*
-The bus lock is needed because there is two tuners both using same I2C-address.
-Due to that the only way to select correct tuner is use demodulator I2C-gate.
-
-................................................
-. AF9015 includes integrated AF9013 demodulator.
-. ____________ ____________ . ____________
-.| uC | | demod | . | tuner |
-.|------------| |------------| . |------------|
-.| AF9015 | | AF9013/5 | . | MXL5003 |
-.| |--+----I2C-------|-----/ -----|-.-----I2C-------| |
-.| | | | addr 0x38 | . | addr 0xc6 |
-.|____________| | |____________| . |____________|
-.................|..............................
- | ____________ ____________
- | | demod | | tuner |
- | |------------| |------------|
- | | AF9013 | | MXL5003 |
- +----I2C-------|-----/ -----|-------I2C-------| |
- | addr 0x3a | | addr 0xc6 |
- |____________| |____________|
-*/
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- while (i < num) {
- 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];
- addr_len = 3;
- } else {
- addr = msg[i].buf[0];
- addr_len = 1;
- /* mbox is don't care in that case */
- }
-
- if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
- if (msg[i].len > 3 || msg[i+1].len > 61) {
- ret = -EOPNOTSUPP;
- goto error;
- }
- if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
- req.cmd = READ_MEMORY;
- else
- req.cmd = READ_I2C;
- req.i2c_addr = msg[i].addr;
- req.addr = addr;
- req.mbox = mbox;
- req.addr_len = addr_len;
- req.data_len = msg[i+1].len;
- req.data = &msg[i+1].buf[0];
- ret = af9015_ctrl_msg(d, &req);
- i += 2;
- } else if (msg[i].flags & I2C_M_RD) {
- if (msg[i].len > 61) {
- ret = -EOPNOTSUPP;
- goto error;
- }
- if (msg[i].addr ==
- af9015_af9013_config[0].i2c_addr) {
- ret = -EINVAL;
- goto error;
- }
- req.cmd = READ_I2C;
- req.i2c_addr = msg[i].addr;
- req.addr = addr;
- req.mbox = mbox;
- req.addr_len = addr_len;
- req.data_len = msg[i].len;
- req.data = &msg[i].buf[0];
- ret = af9015_ctrl_msg(d, &req);
- i += 1;
- } else {
- if (msg[i].len > 21) {
- ret = -EOPNOTSUPP;
- goto error;
- }
- if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
- req.cmd = WRITE_MEMORY;
- else
- req.cmd = WRITE_I2C;
- req.i2c_addr = msg[i].addr;
- req.addr = addr;
- req.mbox = mbox;
- req.addr_len = addr_len;
- req.data_len = msg[i].len-addr_len;
- req.data = &msg[i].buf[addr_len];
- ret = af9015_ctrl_msg(d, &req);
- i += 1;
- }
- if (ret)
- goto error;
-
- }
- ret = i;
-
-error:
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static u32 af9015_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9015_i2c_algo = {
- .master_xfer = af9015_i2c_xfer,
- .functionality = af9015_i2c_func,
-};
-
-static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
-{
- int ret;
- u8 val, mask = 0x01;
-
- ret = af9015_read_reg(d, addr, &val);
- if (ret)
- return ret;
-
- mask <<= bit;
- if (op) {
- /* set bit */
- val |= mask;
- } else {
- /* clear bit */
- mask ^= 0xff;
- val &= mask;
- }
-
- return af9015_write_reg(d, addr, val);
-}
-
-static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
- return af9015_do_reg_bit(d, addr, bit, 1);
-}
-
-static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
- return af9015_do_reg_bit(d, addr, bit, 0);
-}
-
-static int af9015_init_endpoint(struct dvb_usb_device *d)
-{
- int ret;
- u16 frame_size;
- u8 packet_size;
- deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
-
- /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
- We use smaller - about 1/4 from the original, 5 and 87. */
-#define TS_PACKET_SIZE 188
-
-#define TS_USB20_PACKET_COUNT 87
-#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
-
-#define TS_USB11_PACKET_COUNT 5
-#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
-
-#define TS_USB20_MAX_PACKET_SIZE 512
-#define TS_USB11_MAX_PACKET_SIZE 64
-
- if (d->udev->speed == USB_SPEED_FULL) {
- frame_size = TS_USB11_FRAME_SIZE/4;
- packet_size = TS_USB11_MAX_PACKET_SIZE/4;
- } else {
- frame_size = TS_USB20_FRAME_SIZE/4;
- packet_size = TS_USB20_MAX_PACKET_SIZE/4;
- }
-
- ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
- if (ret)
- goto error;
- ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
- if (ret)
- goto error;
- ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
- if (ret)
- goto error;
- if (af9015_config.dual_mode) {
- ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
- if (ret)
- goto error;
- }
- ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
- if (ret)
- goto error;
- if (af9015_config.dual_mode) {
- ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
- if (ret)
- goto error;
- }
- /* EP4 xfer length */
- ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
- if (ret)
- goto error;
- /* EP5 xfer length */
- ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
- if (ret)
- goto error;
- if (af9015_config.dual_mode) {
- ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
- if (ret)
- goto error;
- }
-
- /* enable / disable mp2if2 */
- if (af9015_config.dual_mode)
- ret = af9015_set_reg_bit(d, 0xd50b, 0);
- else
- ret = af9015_clear_reg_bit(d, 0xd50b, 0);
-
-error:
- if (ret)
- err("endpoint init failed:%d", ret);
- return ret;
-}
-
-static int af9015_copy_firmware(struct dvb_usb_device *d)
-{
- int ret;
- u8 fw_params[4];
- u8 val, i;
- struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
- fw_params };
- deb_info("%s:\n", __func__);
-
- fw_params[0] = af9015_config.firmware_size >> 8;
- fw_params[1] = af9015_config.firmware_size & 0xff;
- fw_params[2] = af9015_config.firmware_checksum >> 8;
- fw_params[3] = af9015_config.firmware_checksum & 0xff;
-
- /* wait 2nd demodulator ready */
- msleep(100);
-
- ret = af9015_read_reg_i2c(d,
- af9015_af9013_config[1].i2c_addr, 0x98be, &val);
- if (ret)
- goto error;
- else
- deb_info("%s: firmware status:%02x\n", __func__, val);
-
- if (val == 0x0c) /* fw is running, no need for download */
- goto exit;
-
- /* set I2C master clock to fast (to speed up firmware copy) */
- ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
- if (ret)
- goto error;
-
- msleep(50);
-
- /* copy firmware */
- ret = af9015_ctrl_msg(d, &req);
- if (ret)
- err("firmware copy cmd failed:%d", ret);
- deb_info("%s: firmware copy done\n", __func__);
-
- /* set I2C master clock back to normal */
- ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
- if (ret)
- goto error;
-
- /* request boot firmware */
- 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)
- goto error;
-
- for (i = 0; i < 15; i++) {
- msleep(100);
-
- /* check firmware status */
- ret = af9015_read_reg_i2c(d,
- 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)
- goto error;
-
- if (val == 0x0c || val == 0x04) /* success or fail */
- break;
- }
-
- if (val == 0x04) {
- err("firmware did not run");
- ret = -1;
- } else if (val != 0x0c) {
- err("firmware boot timeout");
- ret = -1;
- }
-
-error:
-exit:
- return ret;
-}
-
-/* hash (and dump) eeprom */
-static int af9015_eeprom_hash(struct usb_device *udev)
-{
- static const unsigned int eeprom_size = 256;
- unsigned int reg;
- int ret;
- u8 val, *eeprom;
- struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
- eeprom = kmalloc(eeprom_size, GFP_KERNEL);
- if (eeprom == NULL)
- return -ENOMEM;
-
- for (reg = 0; reg < eeprom_size; reg++) {
- req.addr = reg;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto free;
- eeprom[reg] = val;
- }
-
- if (dvb_usb_af9015_debug & 0x01)
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
- eeprom_size);
-
- BUG_ON(eeprom_size % 4);
-
- af9015_config.eeprom_sum = 0;
- for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
- af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
- af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
- }
-
- deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
-
- ret = 0;
-free:
- kfree(eeprom);
- return ret;
-}
-
-static int af9015_init(struct dvb_usb_device *d)
-{
- int ret;
- deb_info("%s:\n", __func__);
-
- /* init RC canary */
- ret = af9015_write_reg(d, 0x98e9, 0xff);
- if (ret)
- goto error;
-
- ret = af9015_init_endpoint(d);
- if (ret)
- goto error;
-
-error:
- return ret;
-}
-
-static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- int ret;
- deb_info("%s: onoff:%d\n", __func__, onoff);
-
- if (onoff)
- ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
- else
- ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
-
- return ret;
-}
-
-static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
- int onoff)
-{
- int ret;
- u8 idx;
-
- deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
- __func__, index, pid, onoff);
-
- ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
- if (ret)
- goto error;
-
- ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
- if (ret)
- goto error;
-
- idx = ((index & 0x1f) | (1 << 5));
- ret = af9015_write_reg(adap->dev, 0xd504, idx);
-
-error:
- return ret;
-}
-
-static int af9015_download_firmware(struct usb_device *udev,
- const struct firmware *fw)
-{
- int i, len, remaining, ret;
- struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
- u16 checksum = 0;
-
- deb_info("%s:\n", __func__);
-
- /* calc checksum */
- for (i = 0; i < fw->size; i++)
- checksum += fw->data[i];
-
- af9015_config.firmware_size = fw->size;
- af9015_config.firmware_checksum = checksum;
-
- #define FW_ADDR 0x5100 /* firmware start address */
- #define LEN_MAX 55 /* max packet size */
- for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
- len = remaining;
- if (len > LEN_MAX)
- len = LEN_MAX;
-
- req.data_len = len;
- req.data = (u8 *) &fw->data[fw->size - remaining];
- req.addr = FW_ADDR + fw->size - remaining;
-
- ret = af9015_rw_udev(udev, &req);
- if (ret) {
- err("firmware download failed:%d", ret);
- goto error;
- }
- }
-
- /* firmware loaded, request boot */
- req.cmd = BOOT;
- ret = af9015_rw_udev(udev, &req);
- if (ret) {
- err("firmware boot failed:%d", ret);
- goto error;
- }
-
-error:
- return ret;
-}
-
-struct af9015_rc_setup {
- unsigned int id;
- char *rc_codes;
-};
-
-static char *af9015_rc_setup_match(unsigned int id,
- const struct af9015_rc_setup *table)
-{
- for (; table->rc_codes; table++)
- if (table->id == id)
- return table->rc_codes;
- return NULL;
-}
-
-static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
- { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
- { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
- { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
- { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
- { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
- { }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
- { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
- { 0xa3703d00, RC_MAP_ALINK_DTU_M },
- { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
- { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
- { }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
- { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC,
- RC_MAP_TERRATEC_SLIM_2 },
- { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
- RC_MAP_TERRATEC_SLIM },
- { (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700,
- RC_MAP_AZUREWAVE_AD_TU700 },
- { (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN,
- RC_MAP_AZUREWAVE_AD_TU700 },
- { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III,
- RC_MAP_MSI_DIGIVOX_III },
- { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO,
- RC_MAP_MSI_DIGIVOX_III },
- { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD,
- RC_MAP_LEADTEK_Y04G0051 },
- { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS,
- RC_MAP_LEADTEK_Y04G0051 },
- { (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X,
- RC_MAP_AVERMEDIA_M135A },
- { (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT,
- RC_MAP_TREKSTOR },
- { (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2,
- RC_MAP_DIGITALNOW_TINYTWIN },
- { (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3,
- RC_MAP_DIGITALNOW_TINYTWIN },
- { (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22,
- RC_MAP_MSI_DIGIVOX_III },
- { }
-};
-
-static void af9015_set_remote_config(struct usb_device *udev,
- struct dvb_usb_device_properties *props)
-{
- u16 vid = le16_to_cpu(udev->descriptor.idVendor);
- u16 pid = le16_to_cpu(udev->descriptor.idProduct);
-
- /* try to load remote based module param */
- props->rc.core.rc_codes = af9015_rc_setup_match(
- dvb_usb_af9015_remote, af9015_rc_setup_modparam);
-
- /* try to load remote based eeprom hash */
- if (!props->rc.core.rc_codes)
- props->rc.core.rc_codes = af9015_rc_setup_match(
- af9015_config.eeprom_sum, af9015_rc_setup_hashes);
-
- /* try to load remote based USB ID */
- if (!props->rc.core.rc_codes)
- props->rc.core.rc_codes = af9015_rc_setup_match(
- (vid << 16) | pid, af9015_rc_setup_usbids);
-
- /* try to load remote based USB iManufacturer string */
- if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
- /* Check USB manufacturer and product strings and try
- to determine correct remote in case of chip vendor
- reference IDs are used.
- DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
- char manufacturer[10];
- memset(manufacturer, 0, sizeof(manufacturer));
- usb_string(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
- if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- props->rc.core.rc_codes = af9015_rc_setup_match(
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- af9015_rc_setup_modparam);
- }
- }
-
- /* finally load "empty" just for leaving IR receiver enabled */
- if (!props->rc.core.rc_codes)
- props->rc.core.rc_codes = RC_MAP_EMPTY;
-
- return;
-}
-
-static int af9015_read_config(struct usb_device *udev)
-{
- int ret;
- u8 val, i, offset = 0;
- struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
- /* IR remote controller */
- req.addr = AF9015_EEPROM_IR_MODE;
- /* first message will timeout often due to possible hw bug */
- for (i = 0; i < 4; i++) {
- ret = af9015_rw_udev(udev, &req);
- if (!ret)
- break;
- }
- if (ret)
- goto error;
-
- ret = af9015_eeprom_hash(udev);
- if (ret)
- goto error;
-
- 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;
- else
- af9015_set_remote_config(udev, &af9015_properties[i]);
- }
-
- /* TS mode - one or two receivers */
- req.addr = AF9015_EEPROM_TS_MODE;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- af9015_config.dual_mode = val;
- 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 */
- for (i = 0; i < af9015_properties_count; i++) {
- /* USB1.1 set smaller buffersize and disable 2nd adapter */
- if (udev->speed == USB_SPEED_FULL) {
- af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
- = TS_USB11_FRAME_SIZE;
- /* disable 2nd adapter because we don't have
- PID-filters */
- af9015_config.dual_mode = 0;
- } else {
- af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
- = TS_USB20_FRAME_SIZE;
- }
- }
-
- if (af9015_config.dual_mode) {
- /* read 2nd demodulator I2C address */
- req.addr = AF9015_EEPROM_DEMOD2_I2C;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- af9015_af9013_config[1].i2c_addr = val;
-
- /* enable 2nd adapter */
- for (i = 0; i < af9015_properties_count; i++)
- af9015_properties[i].num_adapters = 2;
-
- } else {
- /* disable 2nd adapter */
- for (i = 0; i < af9015_properties_count; i++)
- af9015_properties[i].num_adapters = 1;
- }
-
- for (i = 0; i < af9015_properties[0].num_adapters; i++) {
- if (i == 1)
- offset = AF9015_EEPROM_OFFSET;
- /* xtal */
- req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- switch (val) {
- case 0:
- af9015_af9013_config[i].clock = 28800000;
- break;
- case 1:
- af9015_af9013_config[i].clock = 20480000;
- break;
- case 2:
- af9015_af9013_config[i].clock = 28000000;
- break;
- case 3:
- af9015_af9013_config[i].clock = 25000000;
- break;
- };
- deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
- val, af9015_af9013_config[i].clock);
-
- /* IF frequency */
- req.addr = AF9015_EEPROM_IF1H + offset;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
-
- 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].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;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- af9015_config.mt2060_if1[i] = val << 8;
- req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- af9015_config.mt2060_if1[i] += val;
- deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
- af9015_config.mt2060_if1[i]);
-
- /* tuner */
- req.addr = AF9015_EEPROM_TUNER_ID1 + offset;
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- goto error;
- switch (val) {
- case AF9013_TUNER_ENV77H11D5:
- case AF9013_TUNER_MT2060:
- case AF9013_TUNER_QT1010:
- case AF9013_TUNER_UNKNOWN:
- case AF9013_TUNER_MT2060_2:
- case AF9013_TUNER_TDA18271:
- case AF9013_TUNER_QT1010A:
- case AF9013_TUNER_TDA18218:
- 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].spec_inv = 0;
- break;
- case AF9013_TUNER_MC44S803:
- af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
- af9015_af9013_config[i].spec_inv = 1;
- break;
- default:
- 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);
- }
-
-error:
- if (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
- AVerTV Red HD+ (A850T) device. */
- if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
- ((le16_to_cpu(udev->descriptor.idProduct) ==
- USB_PID_AVERMEDIA_A850) ||
- (le16_to_cpu(udev->descriptor.idProduct) ==
- USB_PID_AVERMEDIA_A850T))) {
- deb_info("%s: AverMedia A850: overriding config\n", __func__);
- /* disable dual mode */
- af9015_config.dual_mode = 0;
- /* disable 2nd adapter */
- for (i = 0; i < af9015_properties_count; i++)
- af9015_properties[i].num_adapters = 1;
-
- /* set correct IF */
- af9015_af9013_config[0].if_frequency = 4570000;
- }
-
- return ret;
-}
-
-static int af9015_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc,
- int *cold)
-{
- int ret;
- u8 reply;
- struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
-
- ret = af9015_rw_udev(udev, &req);
- if (ret)
- return ret;
-
- deb_info("%s: reply:%02x\n", __func__, reply);
- if (reply == 0x02)
- *cold = 0;
- else
- *cold = 1;
-
- return ret;
-}
-
-static int af9015_rc_query(struct dvb_usb_device *d)
-{
- struct af9015_state *priv = d->priv;
- int ret;
- u8 buf[17];
-
- /* read registers needed to detect remote controller code */
- ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
- if (ret)
- goto error;
-
- /* If any of these are non-zero, assume invalid data */
- if (buf[1] || buf[2] || buf[3])
- return ret;
-
- /* Check for repeat of previous code */
- if ((priv->rc_repeat != buf[6] || buf[0]) &&
- !memcmp(&buf[12], priv->rc_last, 4)) {
- deb_rc("%s: key repeated\n", __func__);
- rc_keydown(d->rc_dev, priv->rc_keycode, 0);
- priv->rc_repeat = buf[6];
- return ret;
- }
-
- /* Only process key if canary killed */
- if (buf[16] != 0xff && buf[0] != 0x01) {
- deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
- buf[12], buf[13], buf[14], buf[15]);
-
- /* Reset the canary */
- ret = af9015_write_reg(d, 0x98e9, 0xff);
- if (ret)
- goto error;
-
- /* Remember this key */
- memcpy(priv->rc_last, &buf[12], 4);
- if (buf[14] == (u8) ~buf[15]) {
- if (buf[12] == (u8) ~buf[13]) {
- /* NEC */
- priv->rc_keycode = buf[12] << 8 | buf[14];
- } else {
- /* NEC extended*/
- priv->rc_keycode = buf[12] << 16 |
- buf[13] << 8 | buf[14];
- }
- } else {
- /* 32 bit NEC */
- priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
- buf[14] << 8 | buf[15];
- }
- rc_keydown(d->rc_dev, priv->rc_keycode, 0);
- } else {
- deb_rc("%s: no key press\n", __func__);
- /* Invalidate last keypress */
- /* Not really needed, but helps with debug */
- priv->rc_last[2] = priv->rc_last[3];
- }
-
- priv->rc_repeat = buf[6];
-
-error:
- if (ret)
- err("%s: failed:%d", __func__, ret);
-
- 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 */
- if (af9015_config.dual_mode) {
- ret = af9015_copy_firmware(adap->dev);
- if (ret) {
- err("firmware copy to 2nd frontend " \
- "failed, will disable it");
- af9015_config.dual_mode = 0;
- return -ENODEV;
- }
- } else {
- return -ENODEV;
- }
- }
-
- /* attach demodulator */
- 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;
-}
-
-static struct mt2060_config af9015_mt2060_config = {
- .i2c_address = 0xc0,
- .clock_out = 0,
-};
-
-static struct qt1010_config af9015_qt1010_config = {
- .i2c_address = 0xc4,
-};
-
-static struct tda18271_config af9015_tda18271_config = {
- .gate = TDA18271_GATE_DIGITAL,
- .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
-};
-
-static struct mxl5005s_config af9015_mxl5003_config = {
- .i2c_address = 0xc6,
- .if_freq = IF_FREQ_4570000HZ,
- .xtal_freq = CRYSTAL_FREQ_16000000HZ,
- .agc_mode = MXL_SINGLE_AGC,
- .tracking_filter = MXL_TF_DEFAULT,
- .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 struct mxl5005s_config af9015_mxl5005_config = {
- .i2c_address = 0xc6,
- .if_freq = IF_FREQ_4570000HZ,
- .xtal_freq = CRYSTAL_FREQ_16000000HZ,
- .agc_mode = MXL_SINGLE_AGC,
- .tracking_filter = MXL_TF_OFF,
- .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 struct mc44s803_config af9015_mc44s803_config = {
- .i2c_address = 0xc0,
- .dig_out = 1,
-};
-
-static struct tda18218_config af9015_tda18218_config = {
- .i2c_address = 0xc0,
- .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
-};
-
-static struct mxl5007t_config af9015_mxl5007t_config = {
- .xtal_freq_hz = MxL_XTAL_24_MHZ,
- .if_freq_hz = MxL_IF_4_57_MHZ,
-};
-
-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) {
- case AF9013_TUNER_MT2060:
- case AF9013_TUNER_MT2060_2:
- ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &af9015_mt2060_config,
- af9015_config.mt2060_if1[adap->id])
- == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_QT1010:
- case AF9013_TUNER_QT1010A:
- ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- &af9015_qt1010_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_TDA18271:
- ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0,
- &adap->dev->i2c_adap,
- &af9015_tda18271_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_TDA18218:
- ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- &af9015_tda18218_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_MXL5003D:
- ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_MXL5005D:
- case AF9013_TUNER_MXL5005R:
- ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_ENV77H11D5:
- ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0,
- &adap->dev->i2c_adap,
- DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_MC44S803:
- ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_MXL5007T:
- ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap,
- 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
- break;
- case AF9013_TUNER_UNKNOWN:
- default:
- ret = -ENODEV;
- 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[] = {
- [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);
-
-#define AF9015_RC_INTERVAL 500
-static struct dvb_usb_device_properties af9015_properties[] = {
- {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = af9015_download_firmware,
- .firmware = "dvb-usb-af9015.fw",
- .no_reconnect = 1,
-
- .size_of_priv = sizeof(struct af9015_state),
-
- .num_adapters = 2,
- .adapter = {
- {
- .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 = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
- },
- }
- },
- },
- {
- .num_frontends = 1,
- .fe = {
- {
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize = TS_USB20_FRAME_SIZE,
- }
- }
- },
- }
- },
- }
- },
-
- .identify_state = af9015_identify_state,
-
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "af9015",
- .rc_query = af9015_rc_query,
- .rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
- },
-
- .i2c_algo = &af9015_i2c_algo,
-
- .num_device_descs = 12, /* check max from dvb-usb.h */
- .devices = {
- {
- .name = "Afatech AF9015 DVB-T USB2.0 stick",
- .cold_ids = {
- &af9015_usb_table[AFATECH_9015],
- &af9015_usb_table[AFATECH_9016],
- },
- }, {
- .name = "Leadtek WinFast DTV Dongle Gold",
- .cold_ids = {
- &af9015_usb_table[WINFAST_DTV_GOLD],
- },
- }, {
- .name = "Pinnacle PCTV 71e",
- .cold_ids = {
- &af9015_usb_table[PINNACLE_PCTV_71E],
- },
- }, {
- .name = "KWorld PlusTV Dual DVB-T Stick " \
- "(DVB-T 399U)",
- .cold_ids = {
- &af9015_usb_table[KWORLD_PLUSTV_399U],
- &af9015_usb_table[KWORLD_399U_2],
- },
- }, {
- .name = "DigitalNow TinyTwin DVB-T Receiver",
- .cold_ids = {
- &af9015_usb_table[TINYTWIN],
- &af9015_usb_table[TINYTWIN_2],
- &af9015_usb_table[TINYTWIN_3],
- },
- }, {
- .name = "TwinHan AzureWave AD-TU700(704J)",
- .cold_ids = {
- &af9015_usb_table[AZUREWAVE_TU700],
- },
- }, {
- .name = "TerraTec Cinergy T USB XE",
- .cold_ids = {
- &af9015_usb_table[TERRATEC_AF9015],
- },
- }, {
- .name = "KWorld PlusTV Dual DVB-T PCI " \
- "(DVB-T PC160-2T)",
- .cold_ids = {
- &af9015_usb_table[KWORLD_PLUSTV_PC160],
- },
- }, {
- .name = "AVerMedia AVerTV DVB-T Volar X",
- .cold_ids = {
- &af9015_usb_table[AVERTV_VOLAR_X],
- },
- }, {
- .name = "TerraTec Cinergy T Stick RC",
- .cold_ids = {
- &af9015_usb_table[CINERGY_T_STICK_RC],
- },
- }, {
- .name = "TerraTec Cinergy T Stick Dual RC",
- .cold_ids = {
- &af9015_usb_table[CINERGY_T_DUAL_RC],
- },
- }, {
- .name = "AverMedia AVerTV Red HD+ (A850T)",
- .cold_ids = {
- &af9015_usb_table[AVERTV_A850T],
- },
- },
- }
- }, {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = af9015_download_firmware,
- .firmware = "dvb-usb-af9015.fw",
- .no_reconnect = 1,
-
- .size_of_priv = sizeof(struct af9015_state),
-
- .num_adapters = 2,
- .adapter = {
- {
- .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 = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
- },
- }
- },
- },
- {
- .num_frontends = 1,
- .fe = {
- {
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize = TS_USB20_FRAME_SIZE,
- }
- }
- },
- }
- },
- }
- },
-
- .identify_state = af9015_identify_state,
-
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "af9015",
- .rc_query = af9015_rc_query,
- .rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
- },
-
- .i2c_algo = &af9015_i2c_algo,
-
- .num_device_descs = 10, /* check max from dvb-usb.h */
- .devices = {
- {
- .name = "Xtensions XD-380",
- .cold_ids = {
- &af9015_usb_table[XTENSIONS_380U],
- },
- }, {
- .name = "MSI DIGIVOX Duo",
- .cold_ids = {
- &af9015_usb_table[MSI_DIGIVOX_DUO],
- },
- }, {
- .name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
- .cold_ids = {
- &af9015_usb_table[AVERTV_VOLAR_X_REV2],
- },
- }, {
- .name = "Telestar Starstick 2",
- .cold_ids = {
- &af9015_usb_table[TELESTAR_STARSTICK_2],
- },
- }, {
- .name = "AVerMedia A309",
- .cold_ids = {
- &af9015_usb_table[AVERMEDIA_A309_USB],
- },
- }, {
- .name = "MSI Digi VOX mini III",
- .cold_ids = {
- &af9015_usb_table[MSI_DIGIVOX_MINI_III],
- },
- }, {
- .name = "KWorld USB DVB-T TV Stick II " \
- "(VS-DVB-T 395U)",
- .cold_ids = {
- &af9015_usb_table[KWORLD_E396],
- &af9015_usb_table[KWORLD_E39B],
- &af9015_usb_table[KWORLD_E395],
- &af9015_usb_table[KWORLD_E39A],
- },
- }, {
- .name = "TrekStor DVB-T USB Stick",
- .cold_ids = {
- &af9015_usb_table[TREKSTOR_DVBT],
- },
- }, {
- .name = "AverMedia AVerTV Volar Black HD " \
- "(A850)",
- .cold_ids = {
- &af9015_usb_table[AVERTV_A850],
- },
- }, {
- .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
- .cold_ids = {
- &af9015_usb_table[SVEON_STV22],
- },
- },
- }
- }, {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = af9015_download_firmware,
- .firmware = "dvb-usb-af9015.fw",
- .no_reconnect = 1,
-
- .size_of_priv = sizeof(struct af9015_state),
-
- .num_adapters = 2,
- .adapter = {
- {
- .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 = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
- },
- }
- },
- },
- {
- .num_frontends = 1,
- .fe = {
- {
- .frontend_attach = af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize = TS_USB20_FRAME_SIZE,
- }
- }
- },
- }
- },
- }
- },
-
- .identify_state = af9015_identify_state,
-
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "af9015",
- .rc_query = af9015_rc_query,
- .rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
- },
-
- .i2c_algo = &af9015_i2c_algo,
-
- .num_device_descs = 9, /* check max from dvb-usb.h */
- .devices = {
- {
- .name = "AverMedia AVerTV Volar GPS 805 (A805)",
- .cold_ids = {
- &af9015_usb_table[AVERTV_A805],
- },
- }, {
- .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
- "V3.0",
- .cold_ids = {
- &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
- },
- }, {
- .name = "KWorld Digial MC-810",
- .cold_ids = {
- &af9015_usb_table[KWORLD_MC810],
- },
- }, {
- .name = "Genius TVGo DVB-T03",
- .cold_ids = {
- &af9015_usb_table[GENIUS_TVGO_DVB_T03],
- },
- }, {
- .name = "KWorld PlusTV DVB-T PCI Pro Card " \
- "(DVB-T PC160-T)",
- .cold_ids = {
- &af9015_usb_table[KWORLD_PC160_T],
- },
- }, {
- .name = "Sveon STV20 Tuner USB DVB-T HDTV",
- .cold_ids = {
- &af9015_usb_table[SVEON_STV20],
- },
- }, {
- .name = "Leadtek WinFast DTV2000DS",
- .cold_ids = {
- &af9015_usb_table[WINFAST_DTV2000DS],
- },
- }, {
- .name = "KWorld USB DVB-T Stick Mobile " \
- "(UB383-T)",
- .cold_ids = {
- &af9015_usb_table[KWORLD_UB383_T],
- },
- }, {
- .name = "AverMedia AVerTV Volar M (A815Mac)",
- .cold_ids = {
- &af9015_usb_table[AVERMEDIA_A815M],
- },
- },
- }
- },
-};
-
-static int af9015_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int ret = 0;
- struct dvb_usb_device *d = NULL;
- struct usb_device *udev = interface_to_usbdev(intf);
- u8 i;
-
- deb_info("%s: interface:%d\n", __func__,
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- /* interface 0 is used by DVB-T receiver and
- interface 1 is for remote controller (HID) */
- if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
- ret = af9015_read_config(udev);
- if (ret)
- return ret;
-
- for (i = 0; i < af9015_properties_count; i++) {
- ret = dvb_usb_device_init(intf, &af9015_properties[i],
- THIS_MODULE, &d, adapter_nr);
- if (!ret)
- break;
- if (ret != -ENODEV)
- return ret;
- }
- if (ret)
- return ret;
-
- if (d)
- ret = af9015_init(d);
- }
-
- return ret;
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9015_usb_driver = {
- .name = "dvb_usb_af9015",
- .probe = af9015_usb_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = af9015_usb_table,
-};
-
-module_usb_driver(af9015_usb_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9015 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
deleted file mode 100644
index 2f68419e899b..000000000000
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- * 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 _DVB_USB_AF9015_H_
-#define _DVB_USB_AF9015_H_
-
-#define DVB_USB_LOG_PREFIX "af9015"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
-#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
-#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args)
-#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args)
-#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args)
-
-#define AF9015_I2C_EEPROM 0xa0
-#define AF9015_I2C_DEMOD 0x38
-#define AF9015_USB_TIMEOUT 2000
-
-/* EEPROM locations */
-#define AF9015_EEPROM_IR_MODE 0x18
-#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
-#define AF9015_EEPROM_TS_MODE 0x31
-#define AF9015_EEPROM_DEMOD2_I2C 0x32
-
-#define AF9015_EEPROM_SAW_BW1 0x35
-#define AF9015_EEPROM_XTAL_TYPE1 0x36
-#define AF9015_EEPROM_SPEC_INV1 0x37
-#define AF9015_EEPROM_IF1L 0x38
-#define AF9015_EEPROM_IF1H 0x39
-#define AF9015_EEPROM_MT2060_IF1L 0x3a
-#define AF9015_EEPROM_MT2060_IF1H 0x3b
-#define AF9015_EEPROM_TUNER_ID1 0x3c
-
-#define AF9015_EEPROM_SAW_BW2 0x45
-#define AF9015_EEPROM_XTAL_TYPE2 0x46
-#define AF9015_EEPROM_SPEC_INV2 0x47
-#define AF9015_EEPROM_IF2L 0x48
-#define AF9015_EEPROM_IF2H 0x49
-#define AF9015_EEPROM_MT2060_IF2L 0x4a
-#define AF9015_EEPROM_MT2060_IF2H 0x4b
-#define AF9015_EEPROM_TUNER_ID2 0x4c
-
-#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
-
-struct req_t {
- u8 cmd; /* [0] */
- /* seq */ /* [1] */
- u8 i2c_addr; /* [2] */
- u16 addr; /* [3|4] */
- u8 mbox; /* [5] */
- u8 addr_len; /* [6] */
- u8 data_len; /* [7] */
- u8 *data;
-};
-
-enum af9015_cmd {
- GET_CONFIG = 0x10,
- DOWNLOAD_FIRMWARE = 0x11,
- BOOT = 0x13,
- READ_MEMORY = 0x20,
- WRITE_MEMORY = 0x21,
- READ_WRITE_I2C = 0x22,
- COPY_FIRMWARE = 0x23,
- RECONNECT_USB = 0x5a,
- WRITE_VIRTUAL_MEMORY = 0x26,
- GET_IR_CODE = 0x27,
- READ_I2C,
- WRITE_I2C,
-};
-
-enum af9015_ir_mode {
- AF9015_IR_MODE_DISABLED = 0,
- AF9015_IR_MODE_HID,
- AF9015_IR_MODE_RLC,
- AF9015_IR_MODE_RC6,
- AF9015_IR_MODE_POLLING, /* just guess */
-};
-
-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 {
- u8 dual_mode:1;
- u16 mt2060_if1[2];
- u16 firmware_size;
- u16 firmware_checksum;
- u32 eeprom_sum;
-};
-
-enum af9015_remote {
- AF9015_REMOTE_NONE = 0,
-/* 1 */ AF9015_REMOTE_A_LINK_DTU_M,
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- AF9015_REMOTE_MYGICTV_U718,
- AF9015_REMOTE_DIGITTRADE_DVB_T,
-/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
deleted file mode 100644
index e83b39d3993c..000000000000
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- * Afatech AF9035 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 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 "af9035.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static DEFINE_MUTEX(af9035_usb_mutex);
-static struct dvb_usb_device_properties af9035_properties[2];
-static int af9035_properties_count = ARRAY_SIZE(af9035_properties);
-
-static u16 af9035_checksum(const u8 *buf, size_t len)
-{
- size_t i;
- u16 checksum = 0;
-
- for (i = 1; i < len; i++) {
- if (i % 2)
- checksum += buf[i] << 8;
- else
- checksum += buf[i];
- }
- checksum = ~checksum;
-
- return checksum;
-}
-
-static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
-{
-#define BUF_LEN 64
-#define REQ_HDR_LEN 4 /* send header size */
-#define ACK_HDR_LEN 3 /* rece header size */
-#define CHECKSUM_LEN 2
-#define USB_TIMEOUT 2000
-
- int ret, msg_len, act_len;
- u8 buf[BUF_LEN];
- static u8 seq; /* packet sequence number */
- u16 checksum, tmp_checksum;
-
- /* buffer overflow check */
- if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
- req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
- pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
- req->wlen, req->rlen);
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&af9035_usb_mutex) < 0)
- return -EAGAIN;
-
- buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
- buf[1] = req->mbox;
- buf[2] = req->cmd;
- buf[3] = seq++;
- if (req->wlen)
- memcpy(&buf[4], req->wbuf, req->wlen);
-
- /* calc and add checksum */
- checksum = af9035_checksum(buf, buf[0] - 1);
- buf[buf[0] - 1] = (checksum >> 8);
- buf[buf[0] - 0] = (checksum & 0xff);
-
- msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ;
-
- /* send req */
- ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
- &act_len, USB_TIMEOUT);
- if (ret < 0)
- err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len);
- else
- if (act_len != msg_len)
- ret = -EIO; /* all data is not send */
- if (ret < 0)
- goto err_mutex_unlock;
-
- /* no ack for those packets */
- if (req->cmd == CMD_FW_DL)
- goto exit_mutex_unlock;
-
- /* receive ack and data if read req */
- msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
- ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
- &act_len, USB_TIMEOUT);
- if (ret < 0) {
- err("recv bulk message failed=%d", ret);
- ret = -EIO;
- goto err_mutex_unlock;
- }
-
- if (act_len != msg_len) {
- err("recv bulk message truncated (%d != %d)", act_len, msg_len);
- ret = -EIO;
- goto err_mutex_unlock;
- }
-
- /* verify checksum */
- checksum = af9035_checksum(buf, act_len - 2);
- tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1];
- if (tmp_checksum != checksum) {
- err("%s: command=%02x checksum mismatch (%04x != %04x)",
- __func__, req->cmd, tmp_checksum, checksum);
- ret = -EIO;
- goto err_mutex_unlock;
- }
-
- /* check status */
- if (buf[2]) {
- pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
- req->cmd, buf[2]);
- ret = -EIO;
- goto err_mutex_unlock;
- }
-
- /* read request, copy returned data to return buf */
- if (req->rlen)
- memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
-
-err_mutex_unlock:
-exit_mutex_unlock:
- mutex_unlock(&af9035_usb_mutex);
-
- return ret;
-}
-
-/* write multiple registers */
-static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
-{
- u8 wbuf[6 + len];
- u8 mbox = (reg >> 16) & 0xff;
- struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
-
- wbuf[0] = len;
- wbuf[1] = 2;
- wbuf[2] = 0;
- wbuf[3] = 0;
- wbuf[4] = (reg >> 8) & 0xff;
- wbuf[5] = (reg >> 0) & 0xff;
- memcpy(&wbuf[6], val, len);
-
- return af9035_ctrl_msg(d->udev, &req);
-}
-
-/* read multiple registers */
-static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
-{
- u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
- u8 mbox = (reg >> 16) & 0xff;
- struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
-
- return af9035_ctrl_msg(d->udev, &req);
-}
-
-/* write single register */
-static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
-{
- return af9035_wr_regs(d, reg, &val, 1);
-}
-
-/* read single register */
-static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
-{
- return af9035_rd_regs(d, reg, val, 1);
-}
-
-/* write single register with mask */
-static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
- u8 mask)
-{
- int ret;
- u8 tmp;
-
- /* no need for read if whole reg is written */
- if (mask != 0xff) {
- ret = af9035_rd_regs(d, reg, &tmp, 1);
- if (ret)
- return ret;
-
- val &= mask;
- tmp &= ~mask;
- val |= tmp;
- }
-
- return af9035_wr_regs(d, reg, &val, 1);
-}
-
-static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
- struct i2c_msg msg[], int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct state *state = d->priv;
- int ret;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- /*
- * I2C sub header is 5 bytes long. Meaning of those bytes are:
- * 0: data len
- * 1: I2C addr << 1
- * 2: reg addr len
- * byte 3 and 4 can be used as reg addr
- * 3: reg addr MSB
- * used when reg addr len is set to 2
- * 4: reg addr LSB
- * used when reg addr len is set to 1 or 2
- *
- * For the simplify we do not use register addr at all.
- * NOTE: As a firmware knows tuner type there is very small possibility
- * there could be some tuner I2C hacks done by firmware and this may
- * lead problems if firmware expects those bytes are used.
- */
- if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
- (msg[1].flags & I2C_M_RD)) {
- if (msg[0].len > 40 || msg[1].len > 40) {
- /* TODO: correct limits > 40 */
- ret = -EOPNOTSUPP;
- } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
- /* integrated demod */
- u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
- msg[0].buf[2];
- ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
- msg[1].len);
- } else {
- /* I2C */
- u8 buf[5 + msg[0].len];
- struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
- buf, msg[1].len, msg[1].buf };
- buf[0] = msg[1].len;
- buf[1] = msg[0].addr << 1;
- buf[2] = 0x00; /* reg addr len */
- buf[3] = 0x00; /* reg addr MSB */
- buf[4] = 0x00; /* reg addr LSB */
- memcpy(&buf[5], msg[0].buf, msg[0].len);
- ret = af9035_ctrl_msg(d->udev, &req);
- }
- } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
- if (msg[0].len > 40) {
- /* TODO: correct limits > 40 */
- ret = -EOPNOTSUPP;
- } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
- /* integrated demod */
- u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
- msg[0].buf[2];
- ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
- msg[0].len - 3);
- } else {
- /* I2C */
- u8 buf[5 + msg[0].len];
- struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
- 0, NULL };
- buf[0] = msg[0].len;
- buf[1] = msg[0].addr << 1;
- buf[2] = 0x00; /* reg addr len */
- buf[3] = 0x00; /* reg addr MSB */
- buf[4] = 0x00; /* reg addr LSB */
- memcpy(&buf[5], msg[0].buf, msg[0].len);
- ret = af9035_ctrl_msg(d->udev, &req);
- }
- } else {
- /*
- * We support only two kind of I2C transactions:
- * 1) 1 x read + 1 x write
- * 2) 1 x write
- */
- ret = -EOPNOTSUPP;
- }
-
- mutex_unlock(&d->i2c_mutex);
-
- if (ret < 0)
- return ret;
- else
- return num;
-}
-
-static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9035_i2c_algo = {
- .master_xfer = af9035_i2c_master_xfer,
- .functionality = af9035_i2c_functionality,
-};
-
-#define AF9035_POLL 250
-static int af9035_rc_query(struct dvb_usb_device *d)
-{
- unsigned int key;
- unsigned char b[4];
- int ret;
- struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
-
- ret = af9035_ctrl_msg(d->udev, &req);
- if (ret < 0)
- goto err;
-
- if ((b[2] + b[3]) == 0xff) {
- if ((b[0] + b[1]) == 0xff) {
- /* NEC */
- key = b[0] << 8 | b[2];
- } else {
- /* ext. NEC */
- key = b[0] << 16 | b[1] << 8 | b[2];
- }
- } else {
- key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
- }
-
- rc_keydown(d->rc_dev, key, 0);
-
-err:
- /* ignore errors */
- return 0;
-}
-
-static int af9035_init(struct dvb_usb_device *d)
-{
- struct state *state = d->priv;
- int ret, i;
- u16 frame_size = 87 * 188 / 4;
- u8 packet_size = 512 / 4;
- struct reg_val_mask tab[] = {
- { 0x80f99d, 0x01, 0x01 },
- { 0x80f9a4, 0x01, 0x01 },
- { 0x00dd11, 0x00, 0x20 },
- { 0x00dd11, 0x00, 0x40 },
- { 0x00dd13, 0x00, 0x20 },
- { 0x00dd13, 0x00, 0x40 },
- { 0x00dd11, 0x20, 0x20 },
- { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
- { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
- { 0x00dd0c, packet_size, 0xff},
- { 0x00dd11, state->dual_mode << 6, 0x40 },
- { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
- { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
- { 0x00dd0d, packet_size, 0xff },
- { 0x80f9a3, 0x00, 0x01 },
- { 0x80f9cd, 0x00, 0x01 },
- { 0x80f99d, 0x00, 0x01 },
- { 0x80f9a4, 0x00, 0x01 },
- };
-
- pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
- __func__, d->udev->speed, frame_size, packet_size);
-
- /* init endpoints */
- for (i = 0; i < ARRAY_SIZE(tab); i++) {
- ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
- tab[i].mask);
- if (ret < 0)
- goto err;
- }
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc,
- int *cold)
-{
- int ret;
- u8 wbuf[1] = { 1 };
- u8 rbuf[4];
- struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
- sizeof(rbuf), rbuf };
-
- ret = af9035_ctrl_msg(udev, &req);
- if (ret < 0)
- goto err;
-
- pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__,
- rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
- if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
- *cold = 0;
- else
- *cold = 1;
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_download_firmware(struct usb_device *udev,
- const struct firmware *fw)
-{
- int ret, i, j, len;
- u8 wbuf[1];
- u8 rbuf[4];
- struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
- u8 hdr_core;
- u16 hdr_addr, hdr_data_len, hdr_checksum;
- #define MAX_DATA 58
- #define HDR_SIZE 7
-
- /*
- * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
- *
- * byte 0: MCS 51 core
- * There are two inside the AF9035 (1=Link and 2=OFDM) with separate
- * address spaces
- * byte 1-2: Big endian destination address
- * byte 3-4: Big endian number of data bytes following the header
- * byte 5-6: Big endian header checksum, apparently ignored by the chip
- * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
- */
-
- for (i = fw->size; i > HDR_SIZE;) {
- hdr_core = fw->data[fw->size - i + 0];
- hdr_addr = fw->data[fw->size - i + 1] << 8;
- hdr_addr |= fw->data[fw->size - i + 2] << 0;
- hdr_data_len = fw->data[fw->size - i + 3] << 8;
- hdr_data_len |= fw->data[fw->size - i + 4] << 0;
- hdr_checksum = fw->data[fw->size - i + 5] << 8;
- hdr_checksum |= fw->data[fw->size - i + 6] << 0;
-
- pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
- __func__, hdr_core, hdr_addr, hdr_data_len,
- hdr_checksum);
-
- if (((hdr_core != 1) && (hdr_core != 2)) ||
- (hdr_data_len > i)) {
- pr_debug("%s: bad firmware\n", __func__);
- break;
- }
-
- /* download begin packet */
- req.cmd = CMD_FW_DL_BEGIN;
- ret = af9035_ctrl_msg(udev, &req);
- if (ret < 0)
- goto err;
-
- /* download firmware packet(s) */
- for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
- len = j;
- if (len > MAX_DATA)
- len = MAX_DATA;
- req_fw_dl.wlen = len;
- req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
- HDR_SIZE + hdr_data_len - j];
- ret = af9035_ctrl_msg(udev, &req_fw_dl);
- if (ret < 0)
- goto err;
- }
-
- /* download end packet */
- req.cmd = CMD_FW_DL_END;
- ret = af9035_ctrl_msg(udev, &req);
- if (ret < 0)
- goto err;
-
- i -= hdr_data_len + HDR_SIZE;
-
- pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
- }
-
- /* firmware loaded, request boot */
- req.cmd = CMD_FW_BOOT;
- ret = af9035_ctrl_msg(udev, &req);
- if (ret < 0)
- goto err;
-
- /* ensure firmware starts */
- wbuf[0] = 1;
- ret = af9035_ctrl_msg(udev, &req_fw_ver);
- if (ret < 0)
- goto err;
-
- if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
- info("firmware did not run");
- ret = -ENODEV;
- goto err;
- }
-
- info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
- rbuf[3]);
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_download_firmware_it9135(struct usb_device *udev,
- const struct firmware *fw)
-{
- int ret, i, i_prev;
- u8 wbuf[1];
- u8 rbuf[4];
- struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
- #define HDR_SIZE 7
-
- /*
- * There seems to be following firmware header. Meaning of bytes 0-3
- * is unknown.
- *
- * 0: 3
- * 1: 0, 1
- * 2: 0
- * 3: 1, 2, 3
- * 4: addr MSB
- * 5: addr LSB
- * 6: count of data bytes ?
- */
-
- for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
- if (i == fw->size ||
- (fw->data[i + 0] == 0x03 &&
- (fw->data[i + 1] == 0x00 ||
- fw->data[i + 1] == 0x01) &&
- fw->data[i + 2] == 0x00)) {
- req_fw_dl.wlen = i - i_prev;
- req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
- i_prev = i;
- ret = af9035_ctrl_msg(udev, &req_fw_dl);
- if (ret < 0)
- goto err;
-
- pr_debug("%s: data uploaded=%d\n", __func__, i);
- }
- }
-
- /* firmware loaded, request boot */
- req.cmd = CMD_FW_BOOT;
- ret = af9035_ctrl_msg(udev, &req);
- if (ret < 0)
- goto err;
-
- /* ensure firmware starts */
- wbuf[0] = 1;
- ret = af9035_ctrl_msg(udev, &req_fw_ver);
- if (ret < 0)
- goto err;
-
- if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
- info("firmware did not run");
- ret = -ENODEV;
- goto err;
- }
-
- info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
- rbuf[3]);
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
- struct state *state = d->priv;
- int ret, i, eeprom_shift = 0;
- u8 tmp;
- u16 tmp16;
-
- /* check if there is dual tuners */
- ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
- if (ret < 0)
- goto err;
-
- state->dual_mode = tmp;
- pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
-
- for (i = 0; i < af9035_properties[0].num_adapters; i++) {
- /* tuner */
- ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
- if (ret < 0)
- goto err;
-
- state->af9033_config[i].tuner = tmp;
- pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
-
- switch (tmp) {
- case AF9033_TUNER_TUA9001:
- case AF9033_TUNER_FC0011:
- case AF9033_TUNER_MXL5007T:
- case AF9033_TUNER_TDA18218:
- state->af9033_config[i].spec_inv = 1;
- break;
- default:
- warn("tuner ID=%02x not supported, please report!",
- tmp);
- };
-
- /* tuner IF frequency */
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
- if (ret < 0)
- goto err;
-
- tmp16 = tmp;
-
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
- if (ret < 0)
- goto err;
-
- tmp16 |= tmp << 8;
-
- pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
-
- eeprom_shift = 0x10; /* shift for the 2nd tuner params */
- }
-
- /* get demod clock */
- ret = af9035_rd_reg(d, 0x00d800, &tmp);
- if (ret < 0)
- goto err;
-
- tmp = (tmp >> 0) & 0x0f;
-
- for (i = 0; i < af9035_properties[0].num_adapters; i++)
- state->af9033_config[i].clock = clock_lut[tmp];
-
- ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
- if (ret < 0)
- goto err;
- pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
-
- /* don't activate rc if in HID mode or if not available */
- if (tmp == 5) {
- ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
- if (ret < 0)
- goto err;
- pr_debug("%s: ir_type=%02x\n", __func__, tmp);
-
- switch (tmp) {
- case 0: /* NEC */
- default:
- d->props.rc.core.protocol = RC_TYPE_NEC;
- d->props.rc.core.allowed_protos = RC_TYPE_NEC;
- break;
- case 1: /* RC6 */
- d->props.rc.core.protocol = RC_TYPE_RC6;
- d->props.rc.core.allowed_protos = RC_TYPE_RC6;
- break;
- }
- d->props.rc.core.rc_query = af9035_rc_query;
- }
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
-{
- struct state *state = d->priv;
- int ret, i;
- u8 tmp;
-
- state->dual_mode = false;
-
- /* get demod clock */
- ret = af9035_rd_reg(d, 0x00d800, &tmp);
- if (ret < 0)
- goto err;
-
- tmp = (tmp >> 0) & 0x0f;
-
- for (i = 0; i < af9035_properties[0].num_adapters; i++)
- state->af9033_config[i].clock = clock_lut_it9135[tmp];
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
- int cmd, int arg)
-{
- int ret;
-
- switch (cmd) {
- case FC0011_FE_CALLBACK_POWER:
- /* Tuner enable */
- ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
- if (ret < 0)
- goto err;
-
- /* LED */
- ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
- if (ret < 0)
- goto err;
-
- usleep_range(10000, 50000);
- break;
- case FC0011_FE_CALLBACK_RESET:
- ret = af9035_wr_reg(d, 0xd8e9, 1);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0xd8e8, 1);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0xd8e7, 1);
- if (ret < 0)
- goto err;
-
- usleep_range(10000, 20000);
-
- ret = af9035_wr_reg(d, 0xd8e7, 0);
- if (ret < 0)
- goto err;
-
- usleep_range(10000, 20000);
- break;
- default:
- ret = -EINVAL;
- goto err;
- }
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
-{
- struct state *state = d->priv;
-
- switch (state->af9033_config[0].tuner) {
- case AF9033_TUNER_FC0011:
- return af9035_fc0011_tuner_callback(d, cmd, arg);
- default:
- break;
- }
-
- return -ENODEV;
-}
-
-static int af9035_frontend_callback(void *adapter_priv, int component,
- int cmd, int arg)
-{
- struct i2c_adapter *adap = adapter_priv;
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
- switch (component) {
- case DVB_FRONTEND_COMPONENT_TUNER:
- return af9035_tuner_callback(d, cmd, arg);
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct state *state = adap->dev->priv;
- int ret;
-
- if (!state->af9033_config[adap->id].tuner) {
- /* unsupported tuner */
- ret = -ENODEV;
- goto err;
- }
-
- if (adap->id == 0) {
- state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
- state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
-
- ret = af9035_wr_reg(adap->dev, 0x00417f,
- state->af9033_config[1].i2c_addr);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(adap->dev, 0x00d81a,
- state->dual_mode);
- if (ret < 0)
- goto err;
- }
-
- /* attach demodulator */
- adap->fe_adap[0].fe = dvb_attach(af9033_attach,
- &state->af9033_config[adap->id], &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL) {
- ret = -ENODEV;
- goto err;
- }
-
- /* disable I2C-gate */
- adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
- adap->fe_adap[0].fe->callback = af9035_frontend_callback;
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static struct tua9001_config af9035_tua9001_config = {
- .i2c_addr = 0x60,
-};
-
-static const struct fc0011_config af9035_fc0011_config = {
- .i2c_address = 0x60,
-};
-
-static struct mxl5007t_config af9035_mxl5007t_config = {
- .xtal_freq_hz = MxL_XTAL_24_MHZ,
- .if_freq_hz = MxL_IF_4_57_MHZ,
- .invert_if = 0,
- .loop_thru_enable = 0,
- .clk_out_enable = 0,
- .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
-};
-
-static struct tda18218_config af9035_tda18218_config = {
- .i2c_address = 0x60,
- .i2c_wr_max = 21,
-};
-
-static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
-{
- struct state *state = adap->dev->priv;
- int ret;
- struct dvb_frontend *fe;
-
- switch (state->af9033_config[adap->id].tuner) {
- case AF9033_TUNER_TUA9001:
- /* AF9035 gpiot3 = TUA9001 RESETN
- AF9035 gpiot2 = TUA9001 RXEN */
-
- /* configure gpiot2 and gpiot2 as output */
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- /* reset tuner */
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01);
- if (ret < 0)
- goto err;
-
- usleep_range(2000, 20000);
-
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- /* activate tuner RX */
- /* TODO: use callback for TUA9001 RXEN */
- ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- /* attach tuner */
- fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &af9035_tua9001_config);
- break;
- case AF9033_TUNER_FC0011:
- fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &af9035_fc0011_config);
- break;
- case AF9033_TUNER_MXL5007T:
- ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8df, 0);
- if (ret < 0)
- goto err;
-
- msleep(30);
-
- ret = af9035_wr_reg(adap->dev, 0x00d8df, 1);
- if (ret < 0)
- goto err;
-
- msleep(300);
-
- ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1);
- if (ret < 0)
- goto err;
-
- /* attach tuner */
- fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config);
- break;
- case AF9033_TUNER_TDA18218:
- /* attach tuner */
- fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &af9035_tda18218_config);
- break;
- default:
- fe = NULL;
- }
-
- if (fe == NULL) {
- ret = -ENODEV;
- goto err;
- }
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-enum af9035_id_entry {
- AF9035_15A4_9035,
- AF9035_15A4_1000,
- AF9035_15A4_1001,
- AF9035_15A4_1002,
- AF9035_15A4_1003,
- AF9035_0CCD_0093,
- AF9035_07CA_A835,
- AF9035_07CA_B835,
- AF9035_07CA_1867,
- AF9035_07CA_A867,
- AF9035_07CA_0825,
-};
-
-static struct usb_device_id af9035_id[] = {
- [AF9035_15A4_9035] = {
- USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)},
- [AF9035_15A4_1000] = {
- USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)},
- [AF9035_15A4_1001] = {
- USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)},
- [AF9035_15A4_1002] = {
- USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)},
- [AF9035_15A4_1003] = {
- USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)},
- [AF9035_0CCD_0093] = {
- USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)},
- [AF9035_07CA_A835] = {
- USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)},
- [AF9035_07CA_B835] = {
- USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)},
- [AF9035_07CA_1867] = {
- USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)},
- [AF9035_07CA_A867] = {
- USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)},
- [AF9035_07CA_0825] = {
- USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)},
- {},
-};
-
-MODULE_DEVICE_TABLE(usb, af9035_id);
-
-static struct dvb_usb_device_properties af9035_properties[] = {
- {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = af9035_download_firmware,
- .firmware = "dvb-usb-af9035-02.fw",
- .no_reconnect = 1,
-
- .size_of_priv = sizeof(struct state),
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {
- {
- .frontend_attach = af9035_frontend_attach,
- .tuner_attach = af9035_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
- .u = {
- .bulk = {
- .buffersize = (87 * 188),
- }
- }
- }
- }
- }
- }
- },
-
- .identify_state = af9035_identify_state,
- .read_mac_address = af9035_read_mac_address,
-
- .i2c_algo = &af9035_i2c_algo,
-
- .rc.core = {
- .protocol = RC_TYPE_UNKNOWN,
- .module_name = "af9035",
- .rc_query = NULL,
- .rc_interval = AF9035_POLL,
- .allowed_protos = RC_TYPE_UNKNOWN,
- .rc_codes = RC_MAP_EMPTY,
- },
- .num_device_descs = 5,
- .devices = {
- {
- .name = "Afatech AF9035 reference design",
- .cold_ids = {
- &af9035_id[AF9035_15A4_9035],
- &af9035_id[AF9035_15A4_1000],
- &af9035_id[AF9035_15A4_1001],
- &af9035_id[AF9035_15A4_1002],
- &af9035_id[AF9035_15A4_1003],
- },
- }, {
- .name = "TerraTec Cinergy T Stick",
- .cold_ids = {
- &af9035_id[AF9035_0CCD_0093],
- },
- }, {
- .name = "AVerMedia AVerTV Volar HD/PRO (A835)",
- .cold_ids = {
- &af9035_id[AF9035_07CA_A835],
- &af9035_id[AF9035_07CA_B835],
- },
- }, {
- .name = "AVerMedia HD Volar (A867)",
- .cold_ids = {
- &af9035_id[AF9035_07CA_1867],
- &af9035_id[AF9035_07CA_A867],
- },
- }, {
- .name = "AVerMedia Twinstar (A825)",
- .cold_ids = {
- &af9035_id[AF9035_07CA_0825],
- },
- },
- }
- },
- {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = af9035_download_firmware_it9135,
- .firmware = "dvb-usb-it9135-01.fw",
- .no_reconnect = 1,
-
- .size_of_priv = sizeof(struct state),
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {
- {
- .frontend_attach = af9035_frontend_attach,
- .tuner_attach = af9035_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
- .u = {
- .bulk = {
- .buffersize = (87 * 188),
- }
- }
- }
- }
- }
- }
- },
-
- .identify_state = af9035_identify_state,
- .read_mac_address = af9035_read_mac_address_it9135,
-
- .i2c_algo = &af9035_i2c_algo,
-
- .num_device_descs = 0, /* disabled as no support for IT9135 */
- .devices = {
- {
- .name = "ITE Tech. IT9135 reference design",
- },
- }
- },
-};
-
-static int af9035_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int ret, i;
- struct dvb_usb_device *d = NULL;
- struct usb_device *udev;
- bool found;
-
- pr_debug("%s: interface=%d\n", __func__,
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- /* interface 0 is used by DVB-T receiver and
- interface 1 is for remote controller (HID) */
- if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
- return 0;
-
- /* Dynamic USB ID support. Replaces first device ID with current one. */
- udev = interface_to_usbdev(intf);
-
- for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) {
- if (af9035_id[i].idVendor ==
- le16_to_cpu(udev->descriptor.idVendor) &&
- af9035_id[i].idProduct ==
- le16_to_cpu(udev->descriptor.idProduct)) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- pr_debug("%s: using dynamic ID %04x:%04x\n", __func__,
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
- af9035_properties[0].devices[0].cold_ids[0]->idVendor =
- le16_to_cpu(udev->descriptor.idVendor);
- af9035_properties[0].devices[0].cold_ids[0]->idProduct =
- le16_to_cpu(udev->descriptor.idProduct);
- }
-
-
- for (i = 0; i < af9035_properties_count; i++) {
- ret = dvb_usb_device_init(intf, &af9035_properties[i],
- THIS_MODULE, &d, adapter_nr);
-
- if (ret == -ENODEV)
- continue;
- else
- break;
- }
-
- if (ret < 0)
- goto err;
-
- if (d) {
- ret = af9035_init(d);
- if (ret < 0)
- goto err;
- }
-
- return 0;
-
-err:
- pr_debug("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9035_usb_driver = {
- .name = "dvb_usb_af9035",
- .probe = af9035_usb_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = af9035_id,
-};
-
-module_usb_driver(af9035_usb_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9035 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h
deleted file mode 100644
index 481a1a43dd2a..000000000000
--- a/drivers/media/dvb/dvb-usb/af9035.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Afatech AF9035 DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 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 AF9035_H
-#define AF9035_H
-
-/* prefix for dvb-usb log writings */
-#define DVB_USB_LOG_PREFIX "af9035"
-
-#include "dvb-usb.h"
-#include "af9033.h"
-#include "tua9001.h"
-#include "fc0011.h"
-#include "mxl5007t.h"
-#include "tda18218.h"
-
-struct reg_val {
- u32 reg;
- u8 val;
-};
-
-struct reg_val_mask {
- u32 reg;
- u8 val;
- u8 mask;
-};
-
-struct usb_req {
- u8 cmd;
- u8 mbox;
- u8 wlen;
- u8 *wbuf;
- u8 rlen;
- u8 *rbuf;
-};
-
-struct state {
- bool dual_mode;
-
- struct af9033_config af9033_config[2];
-};
-
-u32 clock_lut[] = {
- 20480000, /* FPGA */
- 16384000, /* 16.38 MHz */
- 20480000, /* 20.48 MHz */
- 36000000, /* 36.00 MHz */
- 30000000, /* 30.00 MHz */
- 26000000, /* 26.00 MHz */
- 28000000, /* 28.00 MHz */
- 32000000, /* 32.00 MHz */
- 34000000, /* 34.00 MHz */
- 24000000, /* 24.00 MHz */
- 22000000, /* 22.00 MHz */
- 12000000, /* 12.00 MHz */
-};
-
-u32 clock_lut_it9135[] = {
- 12000000, /* 12.00 MHz */
- 20480000, /* 20.48 MHz */
- 36000000, /* 36.00 MHz */
- 30000000, /* 30.00 MHz */
- 26000000, /* 26.00 MHz */
- 28000000, /* 28.00 MHz */
- 32000000, /* 32.00 MHz */
- 34000000, /* 34.00 MHz */
- 24000000, /* 24.00 MHz */
- 22000000, /* 22.00 MHz */
-};
-
-/* EEPROM locations */
-#define EEPROM_IR_MODE 0x430d
-#define EEPROM_DUAL_MODE 0x4326
-#define EEPROM_IR_TYPE 0x4329
-#define EEPROM_1_IFFREQ_L 0x432d
-#define EEPROM_1_IFFREQ_H 0x432e
-#define EEPROM_1_TUNER_ID 0x4331
-#define EEPROM_2_IFFREQ_L 0x433d
-#define EEPROM_2_IFFREQ_H 0x433e
-#define EEPROM_2_TUNER_ID 0x4341
-
-/* USB commands */
-#define CMD_MEM_RD 0x00
-#define CMD_MEM_WR 0x01
-#define CMD_I2C_RD 0x02
-#define CMD_I2C_WR 0x03
-#define CMD_IR_GET 0x18
-#define CMD_FW_DL 0x21
-#define CMD_FW_QUERYINFO 0x22
-#define CMD_FW_BOOT 0x23
-#define CMD_FW_DL_BEGIN 0x24
-#define CMD_FW_DL_END 0x25
-#define CMD_FW_SCATTER_WR 0x29
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
deleted file mode 100644
index 03c28655af1b..000000000000
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ /dev/null
@@ -1,1406 +0,0 @@
-/*
- * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 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.
- *
- * TODO:
- * - add smart card reader support for Conditional Access (CA)
- *
- * Card reader in Anysee is nothing more than ISO 7816 card reader.
- * There is no hardware CAM in any Anysee device sold.
- * In my understanding it should be implemented by making own module
- * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
- * module registers serial interface that can be used to communicate
- * with any ISO 7816 smart card.
- *
- * Any help according to implement serial smart card reader support
- * is highly welcome!
- */
-
-#include "anysee.h"
-#include "tda1002x.h"
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "zl10353.h"
-#include "tda18212.h"
-#include "cx24116.h"
-#include "stv0900.h"
-#include "stv6110.h"
-#include "isl6423.h"
-#include "cxd2820r.h"
-
-/* debug */
-static int dvb_usb_anysee_debug;
-module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_anysee_delsys;
-module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
-MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static DEFINE_MUTEX(anysee_usb_mutex);
-
-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, i;
- u8 buf[64];
-
- memcpy(&buf[0], sbuf, slen);
- buf[60] = state->seq++;
-
- 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
- */
-
- /* 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) {
- deb_info("%s: recv bulk message failed: %d",
- __func__, ret);
- } else {
- 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 (rbuf && rlen)
- memcpy(rbuf, buf, rlen);
-
-error_unlock:
- mutex_unlock(&anysee_usb_mutex);
-
- return ret;
-}
-
-static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
-{
- u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
- int ret;
- ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
- deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
- return ret;
-}
-
-static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
-{
- u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
- deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
- return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-/* write single register with mask */
-static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
- u8 mask)
-{
- int ret;
- u8 tmp;
-
- /* no need for read if whole reg is written */
- if (mask != 0xff) {
- ret = anysee_read_reg(d, reg, &tmp);
- if (ret)
- return ret;
-
- val &= mask;
- tmp &= ~mask;
- val |= tmp;
- }
-
- 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};
- return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
-}
-
-static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
- deb_info("%s: onoff:%02x\n", __func__, onoff);
- return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
-}
-
-static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
-{
- u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
- deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
- return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
-{
- u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
- deb_info("%s: onoff:%02x\n", __func__, onoff);
- return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
-}
-
-/* I2C */
-static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0, inc, i = 0;
- u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- while (i < num) {
- if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
- if (msg[i].len > 2 || msg[i+1].len > 60) {
- ret = -EOPNOTSUPP;
- break;
- }
- buf[0] = CMD_I2C_READ;
- buf[1] = (msg[i].addr << 1) | 0x01;
- buf[2] = msg[i].buf[0];
- buf[3] = msg[i].buf[1];
- buf[4] = msg[i].len-1;
- buf[5] = msg[i+1].len;
- ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
- msg[i+1].len);
- inc = 2;
- } else {
- if (msg[i].len > 48) {
- ret = -EOPNOTSUPP;
- break;
- }
- buf[0] = CMD_I2C_WRITE;
- buf[1] = (msg[i].addr << 1);
- buf[2] = msg[i].len;
- buf[3] = 0x01;
- memcpy(&buf[4], msg[i].buf, msg[i].len);
- ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0);
- inc = 1;
- }
- if (ret)
- break;
-
- i += inc;
- }
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret ? ret : i;
-}
-
-static u32 anysee_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm anysee_i2c_algo = {
- .master_xfer = anysee_master_xfer,
- .functionality = anysee_i2c_func,
-};
-
-static int anysee_mt352_demod_init(struct dvb_frontend *fe)
-{
- static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 };
- static u8 reset[] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 };
- static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
-
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
- return 0;
-}
-
-/* Callbacks for DVB USB */
-static struct tda10023_config anysee_tda10023_config = {
- .demod_address = (0x1a >> 1),
- .invert = 0,
- .xtal = 16000000,
- .pll_m = 11,
- .pll_p = 3,
- .pll_n = 1,
- .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
- .deltaf = 0xfeeb,
-};
-
-static struct mt352_config anysee_mt352_config = {
- .demod_address = (0x1e >> 1),
- .demod_init = anysee_mt352_demod_init,
-};
-
-static struct zl10353_config anysee_zl10353_config = {
- .demod_address = (0x1e >> 1),
- .parallel_ts = 1,
-};
-
-static struct zl10353_config anysee_zl10353_tda18212_config2 = {
- .demod_address = (0x1e >> 1),
- .parallel_ts = 1,
- .disable_i2c_gate_ctrl = 1,
- .no_tuner = 1,
- .if2 = 41500,
-};
-
-static struct zl10353_config anysee_zl10353_tda18212_config = {
- .demod_address = (0x18 >> 1),
- .parallel_ts = 1,
- .disable_i2c_gate_ctrl = 1,
- .no_tuner = 1,
- .if2 = 41500,
-};
-
-static struct tda10023_config anysee_tda10023_tda18212_config = {
- .demod_address = (0x1a >> 1),
- .xtal = 16000000,
- .pll_m = 12,
- .pll_p = 3,
- .pll_n = 1,
- .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
- .deltaf = 0xba02,
-};
-
-static struct tda18212_config anysee_tda18212_config = {
- .i2c_address = (0xc0 >> 1),
- .if_dvbt_6 = 4150,
- .if_dvbt_7 = 4150,
- .if_dvbt_8 = 4150,
- .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,
- .i2c_wr_max = 48,
-};
-
-static struct stv0900_config anysee_stv0900_config = {
- .demod_address = (0xd0 >> 1),
- .demod_mode = 0,
- .xtal = 8000000,
- .clkmode = 3,
- .diseqc_mode = 2,
- .tun1_maddress = 0,
- .tun1_adc = 1, /* 1 Vpp */
- .path1_mode = 3,
-};
-
-static struct stv6110_config anysee_stv6110_config = {
- .i2c_address = (0xc0 >> 1),
- .mclk = 16000000,
- .clk_div = 1,
-};
-
-static struct isl6423_config anysee_isl6423_config = {
- .current_max = SEC_CURRENT_800m,
- .curlim = SEC_CURRENT_LIM_OFF,
- .mod_extern = 1,
- .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
- *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
- * PCB: ?
- * parts: DNOS404ZH102A(MT352, DTT7579(?))
- *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
- * PCB: PCB 507T (rev1.61)
- * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
- * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
- * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
- *
- * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
- * PCB: 507CD (rev1.1)
- * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
- * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
- * IOD[0] ZL10353 1=enabled
- * IOA[7] TS 0=enabled
- * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
- *
- * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
- * PCB: 507DC (rev0.2)
- * parts: TDA10023, DTOS403IH102B TM, CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
- * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
- * IOD[0] TDA10023 1=enabled
- *
- * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
- * PCB: 507SI (rev2.1)
- * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
- * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
- * IOD[0] CX24116 1=enabled
- *
- * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
- * PCB: 507FA (rev0.4)
- * parts: TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
- * IOD[5] TDA10023 1=enabled
- * IOE[0] tuner 1=enabled
- *
- * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
- * PCB: 507FA (rev1.1)
- * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
- * DVB-C:
- * IOD[5] TDA10023 1=enabled
- * IOE[0] tuner 1=enabled
- * DVB-T:
- * IOD[0] ZL10353 1=enabled
- * IOE[0] tuner 0=enabled
- * tuner is behind ZL10353 I2C-gate
- *
- * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
- * PCB: 508TC (rev0.6)
- * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
- * 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[4] TDA18212 1=enabled
- * DVB-C:
- * IOD[6] ZL10353 0=disabled
- * IOD[5] TDA10023 1=enabled
- * IOE[0] IF 1=enabled
- * DVB-T:
- * IOD[5] TDA10023 0=disabled
- * IOD[6] ZL10353 1=enabled
- * IOE[0] IF 0=enabled
- *
- * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
- * PCB: 508S2 (rev0.7)
- * parts: DNBU10512IST(STV0903, STV6110), ISL6423
- * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
- * 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)
- * 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[4] TDA18212 1=enabled
- * DVB-C:
- * IOD[6] ZL10353 0=disabled
- * IOD[5] TDA10023 1=enabled
- * IOE[0] IF 1=enabled
- * DVB-T:
- * IOD[5] TDA10023 0=disabled
- * IOD[6] ZL10353 1=enabled
- * IOE[0] IF 0=enabled
- *
- * 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
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
- * IOA[7] TS 1=enabled
- * 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;
- struct anysee_state *state = adap->dev->priv;
- int ret;
-
- deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
-
- /* no frontend sleep control */
- if (onoff == 0)
- return 0;
-
- switch (state->hw) {
- case ANYSEE_HW_507FA: /* 15 */
- /* E30 Combo Plus */
- /* E30 C Plus */
-
- if ((fe->id ^ dvb_usb_anysee_delsys) == 0) {
- /* disable DVB-T demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
- 0x01);
- if (ret)
- goto error;
-
- /* enable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable DVB-C tuner on IOE[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
- 0x01);
- if (ret)
- goto error;
- } else {
- /* disable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable DVB-T demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
- 0x01);
- if (ret)
- goto error;
-
- /* enable DVB-T tuner on IOE[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
- 0x01);
- if (ret)
- goto error;
- }
-
- break;
- case ANYSEE_HW_508TC: /* 18 */
- case ANYSEE_HW_508PTC: /* 21 */
- /* E7 TC */
- /* E7 PTC */
-
- if ((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),
- 0x40);
- if (ret)
- goto error;
-
- /* enable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable IF route on IOE[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
- 0x01);
- if (ret)
- goto error;
- } else {
- /* disable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable DVB-T demod on IOD[6] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
- 0x40);
- if (ret)
- goto error;
-
- /* enable IF route on IOE[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
- 0x01);
- if (ret)
- goto error;
- }
-
- break;
- default:
- ret = 0;
- }
-
-error:
- return ret;
-}
-
-static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
-{
- int ret;
- struct anysee_state *state = adap->dev->priv;
- u8 hw_info[3];
- u8 tmp;
- struct i2c_msg msg[2] = {
- {
- .addr = anysee_tda18212_config.i2c_address,
- .flags = 0,
- .len = 1,
- .buf = "\x00",
- }, {
- .addr = anysee_tda18212_config.i2c_address,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = &tmp,
- }
- };
-
- /* 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/fw bug).
- */
- ret = anysee_get_hw_info(adap->dev, hw_info);
- if (ret)
- goto error;
-
- ret = anysee_get_hw_info(adap->dev, hw_info);
- if (ret)
- goto error;
-
- /* Meaning of these info bytes are guessed. */
- info("firmware version:%d.%d hardware id:%d",
- hw_info[1], hw_info[2], hw_info[0]);
-
- state->hw = hw_info[0];
- }
-
- /* set current frondend ID for devices having two frondends */
- if (adap->fe_adap[0].fe)
- state->fe_id++;
-
- switch (state->hw) {
- case ANYSEE_HW_507T: /* 2 */
- /* E30 */
-
- if (state->fe_id)
- break;
-
- /* attach demod */
- 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);
-
- break;
- case ANYSEE_HW_507CD: /* 6 */
- /* E30 Plus */
-
- if (state->fe_id)
- break;
-
- /* enable DVB-T demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
- if (ret)
- goto error;
-
- /* enable transport stream on IOA[7] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
- if (ret)
- goto error;
-
- /* attach demod */
- adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
- &anysee_zl10353_config, &adap->dev->i2c_adap);
-
- break;
- case ANYSEE_HW_507DC: /* 10 */
- /* E30 C Plus */
-
- if (state->fe_id)
- break;
-
- /* enable DVB-C demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
- if (ret)
- goto error;
-
- /* attach demod */
- adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
- &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
-
- break;
- case ANYSEE_HW_507SI: /* 11 */
- /* E30 S2 Plus */
-
- if (state->fe_id)
- break;
-
- /* enable DVB-S/S2 demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
- if (ret)
- goto error;
-
- /* attach demod */
- adap->fe_adap[0].fe = dvb_attach(cx24116_attach,
- &anysee_cx24116_config, &adap->dev->i2c_adap);
-
- break;
- case ANYSEE_HW_507FA: /* 15 */
- /* E30 Combo Plus */
- /* E30 C Plus */
-
- /* enable tuner on IOE[4] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
- if (ret)
- goto error;
-
- /* probe TDA18212 */
- tmp = 0;
- ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
- if (ret == 2 && tmp == 0xc7)
- deb_info("%s: TDA18212 found\n", __func__);
- else
- tmp = 0;
-
- /* disable tuner on IOE[4] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
- if (ret)
- goto error;
-
- if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) {
- /* disable DVB-T demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
- 0x01);
- if (ret)
- goto error;
-
- /* enable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* attach demod */
- if (tmp == 0xc7) {
- /* TDA18212 config */
- adap->fe_adap[state->fe_id].fe = dvb_attach(
- tda10023_attach,
- &anysee_tda10023_tda18212_config,
- &adap->dev->i2c_adap, 0x48);
- } else {
- /* PLL config */
- adap->fe_adap[state->fe_id].fe = dvb_attach(
- tda10023_attach,
- &anysee_tda10023_config,
- &adap->dev->i2c_adap, 0x48);
- }
- } else {
- /* disable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable DVB-T demod on IOD[0] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
- 0x01);
- if (ret)
- goto error;
-
- /* attach demod */
- if (tmp == 0xc7) {
- /* TDA18212 config */
- adap->fe_adap[state->fe_id].fe = dvb_attach(
- zl10353_attach,
- &anysee_zl10353_tda18212_config2,
- &adap->dev->i2c_adap);
- } else {
- /* PLL config */
- adap->fe_adap[state->fe_id].fe = dvb_attach(
- zl10353_attach,
- &anysee_zl10353_config,
- &adap->dev->i2c_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 */
-
- 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),
- 0x40);
- if (ret)
- goto error;
-
- /* enable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* attach demod */
- adap->fe_adap[state->fe_id].fe =
- dvb_attach(tda10023_attach,
- &anysee_tda10023_tda18212_config,
- &adap->dev->i2c_adap, 0x48);
- } else {
- /* disable DVB-C demod on IOD[5] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
- 0x20);
- if (ret)
- goto error;
-
- /* enable DVB-T demod on IOD[6] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
- 0x40);
- if (ret)
- goto error;
-
- /* attach demod */
- 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 */
- /* E7 S2 */
- /* E7 PS2 */
-
- if (state->fe_id)
- break;
-
- /* enable DVB-S/S2 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);
-
- 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[state->fe_id].fe = dvb_attach(cxd2820r_attach,
- &anysee_cxd2820r_config, &adap->dev->i2c_adap);
-
- state->has_ci = true;
-
- break;
- }
-
- if (!adap->fe_adap[0].fe) {
- /* we have no frontend :-( */
- ret = -ENODEV;
- err("Unsupported Anysee version. " \
- "Please report the <linux-media@vger.kernel.org>.");
- }
-error:
- return ret;
-}
-
-static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
-{
- struct anysee_state *state = adap->dev->priv;
- struct dvb_frontend *fe;
- int ret;
- deb_info("%s: fe=%d\n", __func__, state->fe_id);
-
- switch (state->hw) {
- case ANYSEE_HW_507T: /* 2 */
- /* E30 */
-
- /* attach tuner */
- 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);
-
- 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);
-
- break;
- case ANYSEE_HW_507SI: /* 11 */
- /* E30 S2 Plus */
-
- /* attach LNB controller */
- fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &anysee_isl6423_config);
-
- break;
- case ANYSEE_HW_507FA: /* 15 */
- /* E30 Combo Plus */
- /* E30 C Plus */
-
- /* Try first attach TDA18212 silicon tuner on IOE[4], if that
- * fails attach old simple PLL. */
-
- /* attach tuner */
- fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
- &adap->dev->i2c_adap, &anysee_tda18212_config);
- if (fe)
- break;
-
- /* attach tuner */
- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
- (0xc0 >> 1), &adap->dev->i2c_adap,
- DVB_PLL_SAMSUNG_DTOS403IH102A);
-
- break;
- case ANYSEE_HW_508TC: /* 18 */
- case ANYSEE_HW_508PTC: /* 21 */
- /* E7 TC */
- /* E7 PTC */
-
- /* attach tuner */
- fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
- &adap->dev->i2c_adap, &anysee_tda18212_config);
-
- break;
- case ANYSEE_HW_508S2: /* 19 */
- case ANYSEE_HW_508PS2: /* 22 */
- /* E7 S2 */
- /* E7 PS2 */
-
- /* attach tuner */
- fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe,
- &anysee_stv6110_config, &adap->dev->i2c_adap);
-
- if (fe) {
- /* attach LNB controller */
- fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, &anysee_isl6423_config);
- }
-
- 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;
- }
-
- if (fe)
- ret = 0;
- else
- ret = -ENODEV;
-
- return ret;
-}
-
-static int anysee_rc_query(struct dvb_usb_device *d)
-{
- u8 buf[] = {CMD_GET_IR_CODE};
- u8 ircode[2];
- int ret;
-
- /* Remote controller is basic NEC using address byte 0x08.
- Anysee device RC query returns only two bytes, status and code,
- address byte is dropped. Also it does not return any value for
- NEC RCs having address byte other than 0x08. Due to that, we
- cannot use that device as standard NEC receiver.
- It could be possible make hack which reads whole code directly
- from device memory... */
-
- ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
- if (ret)
- return ret;
-
- if (ircode[0]) {
- deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
- rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
- }
-
- 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;
-
-static int anysee_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
- int ret;
-
- /* There is one interface with two alternate settings.
- Alternate setting 0 is for bulk transfer.
- Alternate setting 1 is for isochronous transfer.
- We use bulk transfer (alternate setting 0). */
- if (intf->num_altsetting < 1)
- return -ENODEV;
-
- /*
- * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
- * firmware from eeprom). If dvb_usb_device_init() succeeds that
- * means d is a valid pointer.
- */
- ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
- adapter_nr);
- if (ret)
- return ret;
-
- alt = usb_altnum_to_altsetting(intf, 0);
- if (alt == NULL) {
- deb_info("%s: no alt found!\n", __func__);
- return -ENODEV;
- }
-
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- if (ret)
- return ret;
-
- 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) },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, anysee_table);
-
-static struct dvb_usb_device_properties anysee_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
-
- .size_of_priv = sizeof(struct anysee_state),
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 2,
- .frontend_ctrl = anysee_frontend_ctrl,
- .fe = { {
- .streaming_ctrl = anysee_streaming_ctrl,
- .frontend_attach = anysee_frontend_attach,
- .tuner_attach = anysee_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 8,
- .endpoint = 0x82,
- .u = {
- .bulk = {
- .buffersize = (16*512),
- }
- }
- },
- }, {
- .streaming_ctrl = anysee_streaming_ctrl,
- .frontend_attach = anysee_frontend_attach,
- .tuner_attach = anysee_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 8,
- .endpoint = 0x82,
- .u = {
- .bulk = {
- .buffersize = (16*512),
- }
- }
- },
- } },
- }
- },
-
- .rc.core = {
- .rc_codes = RC_MAP_ANYSEE,
- .protocol = RC_TYPE_OTHER,
- .module_name = "anysee",
- .rc_query = anysee_rc_query,
- .rc_interval = 250, /* windows driver uses 500ms */
- },
-
- .i2c_algo = &anysee_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 1,
-
- .num_device_descs = 1,
- .devices = {
- {
- .name = "Anysee DVB USB2.0",
- .cold_ids = {NULL},
- .warm_ids = {&anysee_table[0],
- &anysee_table[1], NULL},
- },
- }
-};
-
-static struct usb_driver anysee_driver = {
- .name = "dvb_usb_anysee",
- .probe = anysee_probe,
- .disconnect = anysee_disconnect,
- .id_table = anysee_table,
-};
-
-module_usb_driver(anysee_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
deleted file mode 100644
index 8ac879431540..000000000000
--- a/drivers/media/dvb/dvb-usb/anysee.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 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.
- *
- * TODO:
- * - add smart card reader support for Conditional Access (CA)
- *
- * Card reader in Anysee is nothing more than ISO 7816 card reader.
- * There is no hardware CAM in any Anysee device sold.
- * In my understanding it should be implemented by making own module
- * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
- * module registers serial interface that can be used to communicate
- * with any ISO 7816 smart card.
- *
- * Any help according to implement serial smart card reader support
- * is highly welcome!
- */
-
-#ifndef _DVB_USB_ANYSEE_H_
-#define _DVB_USB_ANYSEE_H_
-
-#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)
-#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args)
-#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args)
-#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args)
-#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args)
-
-enum cmd {
- CMD_I2C_READ = 0x33,
- CMD_I2C_WRITE = 0x31,
- CMD_REG_READ = 0xb0,
- CMD_REG_WRITE = 0xb1,
- CMD_STREAMING_CTRL = 0x12,
- CMD_LED_AND_IR_CTRL = 0x16,
- 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 */
-#define ANYSEE_HW_507CD 6 /* E30 Plus */
-#define ANYSEE_HW_507DC 10 /* E30 C Plus */
-#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
-#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 */
-
-#define REG_IOA 0x80 /* Port A (bit addressable) */
-#define REG_IOB 0x90 /* Port B (bit addressable) */
-#define REG_IOC 0xa0 /* Port C (bit addressable) */
-#define REG_IOD 0xb0 /* Port D (bit addressable) */
-#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */
-#define REG_OEA 0xb2 /* Port A Output Enable */
-#define REG_OEB 0xb3 /* Port B Output Enable */
-#define REG_OEC 0xb4 /* Port C Output Enable */
-#define REG_OED 0xb5 /* Port D Output Enable */
-#define REG_OEE 0xb6 /* Port E Output Enable */
-
-#endif
-
-/***************************************************************************
- * USB API description (reverse engineered)
- ***************************************************************************
-
-Transaction flow:
-=================
-BULK[00001] >>> REQUEST PACKET 64 bytes
-BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
-BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
-
-General reply packet(s) are always used if not own reply defined.
-
-============================================================================
-| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
-============================================================================
-| 00 | reply data (if any) from previous transaction
-| | Just same reply packet as returned during previous transaction.
-| | Needed only if reply is missed in previous transaction.
-| | Just skip normally.
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
-============================================================================
-| 00 | reply data (if any)
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | I2C WRITE REQUEST PACKET
-============================================================================
-| 00 | 0x31 I2C write command
-----------------------------------------------------------------------------
-| 01 | i2c address
-----------------------------------------------------------------------------
-| 02 | data length
-| | 0x02 (for typical I2C reg / val pair)
-----------------------------------------------------------------------------
-| 03 | 0x01
-----------------------------------------------------------------------------
-| 04- | data
-----------------------------------------------------------------------------
-| -59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | I2C READ REQUEST PACKET
-============================================================================
-| 00 | 0x33 I2C read command
-----------------------------------------------------------------------------
-| 01 | i2c address + 1
-----------------------------------------------------------------------------
-| 02 | register
-----------------------------------------------------------------------------
-| 03 | 0x00
-----------------------------------------------------------------------------
-| 04 | 0x00
-----------------------------------------------------------------------------
-| 05 | data length
-----------------------------------------------------------------------------
-| 06-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
-============================================================================
-| 00 | 0xb1 register write command
-----------------------------------------------------------------------------
-| 01-02 | register
-----------------------------------------------------------------------------
-| 03 | 0x01
-----------------------------------------------------------------------------
-| 04 | value
-----------------------------------------------------------------------------
-| 05-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
-============================================================================
-| 00 | 0xb0 register read command
-----------------------------------------------------------------------------
-| 01-02 | register
-----------------------------------------------------------------------------
-| 03 | 0x01
-----------------------------------------------------------------------------
-| 04-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | LED CONTROL REQUEST PACKET
-============================================================================
-| 00 | 0x16 LED and IR control command
-----------------------------------------------------------------------------
-| 01 | 0x01 (LED)
-----------------------------------------------------------------------------
-| 03 | 0x00 blink
-| | 0x01 lights continuously
-----------------------------------------------------------------------------
-| 04 | blink interval
-| | 0x00 fastest (looks like LED lights continuously)
-| | 0xff slowest
-----------------------------------------------------------------------------
-| 05-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | IR CONTROL REQUEST PACKET
-============================================================================
-| 00 | 0x16 LED and IR control command
-----------------------------------------------------------------------------
-| 01 | 0x02 (IR)
-----------------------------------------------------------------------------
-| 03 | 0x00 IR disabled
-| | 0x01 IR enabled
-----------------------------------------------------------------------------
-| 04-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | STREAMING CONTROL REQUEST PACKET
-============================================================================
-| 00 | 0x12 streaming control command
-----------------------------------------------------------------------------
-| 01 | 0x00 streaming disabled
-| | 0x01 streaming enabled
-----------------------------------------------------------------------------
-| 02 | 0x00
-----------------------------------------------------------------------------
-| 03-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | REMOTE CONTROL REQUEST PACKET
-============================================================================
-| 00 | 0x41 remote control command
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | REMOTE CONTROL REPLY PACKET
-============================================================================
-| 00 | 0x00 code not received
-| | 0x01 code received
-----------------------------------------------------------------------------
-| 01 | remote control code
-----------------------------------------------------------------------------
-| 02-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GET HARDWARE INFO REQUEST PACKET
-============================================================================
-| 00 | 0x19 get hardware info command
-----------------------------------------------------------------------------
-| 01-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | GET HARDWARE INFO REPLY PACKET
-============================================================================
-| 00 | hardware id
-----------------------------------------------------------------------------
-| 01-02 | firmware version
-----------------------------------------------------------------------------
-| 03-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-============================================================================
-| 00-63 | SMART CARD READER PACKET
-============================================================================
-| 00 | 0x34 smart card reader command
-----------------------------------------------------------------------------
-| xx |
-----------------------------------------------------------------------------
-| xx-59 | don't care
-----------------------------------------------------------------------------
-| 60 | packet sequence number
-----------------------------------------------------------------------------
-| 61-63 | don't care
-----------------------------------------------------------------------------
-
-*/
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
deleted file mode 100644
index 16210c060302..000000000000
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
- *
- * Copyright (C) 2006 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 "au6610.h"
-#include "zl10353.h"
-#include "qt1010.h"
-
-/* debug */
-static int dvb_usb_au6610_debug;
-module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
- u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
- int ret;
- u16 index;
- u8 *usb_buf;
-
- /*
- * allocate enough for all known requests,
- * read returns 5 and write 6 bytes
- */
- usb_buf = kmalloc(6, GFP_KERNEL);
- if (!usb_buf)
- return -ENOMEM;
-
- switch (wlen) {
- case 1:
- index = wbuf[0] << 8;
- break;
- case 2:
- index = wbuf[0] << 8;
- index += wbuf[1];
- break;
- default:
- warn("wlen = %x, aborting.", wlen);
- ret = -EINVAL;
- goto error;
- }
-
- ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
- USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
- usb_buf, 6, AU6610_USB_TIMEOUT);
- if (ret < 0)
- goto error;
-
- switch (operation) {
- case AU6610_REQ_I2C_READ:
- case AU6610_REQ_USB_READ:
- /* requested value is always 5th byte in buffer */
- rbuf[0] = usb_buf[4];
- }
-error:
- kfree(usb_buf);
- return ret;
-}
-
-static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
- u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
- u8 request;
- u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
-
- if (wo) {
- request = AU6610_REQ_I2C_WRITE;
- } else { /* rw */
- request = AU6610_REQ_I2C_READ;
- }
-
- return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
-}
-
-
-/* I2C */
-static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int i;
-
- if (num > 2)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- for (i = 0; i < num; i++) {
- /* write/read request */
- if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
- if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
- msg[i].len, msg[i+1].buf,
- msg[i+1].len) < 0)
- break;
- i++;
- } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
- msg[i].len, NULL, 0) < 0)
- break;
- }
-
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-
-static u32 au6610_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm au6610_i2c_algo = {
- .master_xfer = au6610_i2c_xfer,
- .functionality = au6610_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config au6610_zl10353_config = {
- .demod_address = 0x0f,
- .no_tuner = 1,
- .parallel_ts = 1,
-};
-
-static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
-{
- adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
- return -ENODEV;
-
- return 0;
-}
-
-static struct qt1010_config au6610_qt1010_config = {
- .i2c_address = 0x62
-};
-
-static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
-{
- return dvb_attach(qt1010_attach,
- adap->fe_adap[0].fe, &adap->dev->i2c_adap,
- &au6610_qt1010_config) == NULL ? -ENODEV : 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties au6610_properties;
-
-static int au6610_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
- int ret;
-
- if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
- return -ENODEV;
-
- ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d,
- adapter_nr);
- if (ret == 0) {
- alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
-
- if (alt == NULL) {
- deb_info("%s: no alt found!\n", __func__);
- return -ENODEV;
- }
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- }
-
- return ret;
-}
-
-static struct usb_device_id au6610_table [] = {
- { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, au6610_table);
-
-static struct dvb_usb_device_properties au6610_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
-
- .size_of_priv = 0,
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = au6610_zl10353_frontend_attach,
- .tuner_attach = au6610_qt1010_tuner_attach,
-
- .stream = {
- .type = USB_ISOC,
- .count = 5,
- .endpoint = 0x82,
- .u = {
- .isoc = {
- .framesperurb = 40,
- .framesize = 942,
- .interval = 1,
- }
- }
- },
- }},
- }
- },
-
- .i2c_algo = &au6610_i2c_algo,
-
- .num_device_descs = 1,
- .devices = {
- {
- .name = "Sigmatek DVB-110 DVB-T USB2.0",
- .cold_ids = {NULL},
- .warm_ids = {&au6610_table[0], NULL},
- },
- }
-};
-
-static struct usb_driver au6610_driver = {
- .name = "dvb_usb_au6610",
- .probe = au6610_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = au6610_table,
-};
-
-module_usb_driver(au6610_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
deleted file mode 100644
index 7849abe2c614..000000000000
--- a/drivers/media/dvb/dvb-usb/au6610.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
- *
- * Copyright (C) 2006 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 _DVB_USB_AU6610_H_
-#define _DVB_USB_AU6610_H_
-
-#define DVB_USB_LOG_PREFIX "au6610"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args)
-
-#define AU6610_REQ_I2C_WRITE 0x14
-#define AU6610_REQ_I2C_READ 0x13
-#define AU6610_REQ_USB_WRITE 0x16
-#define AU6610_REQ_USB_READ 0x15
-
-#define AU6610_USB_TIMEOUT 1000
-
-#define AU6610_ALTSETTING_COUNT 6
-#define AU6610_ALTSETTING 5
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
deleted file mode 100644
index 86861e6f86d2..000000000000
--- a/drivers/media/dvb/dvb-usb/az6007.c
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * 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, 6);
-
- if (ret > 0)
- deb_info("%s: mac is %pM\n", __func__, mac);
-
- 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/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c
deleted file mode 100644
index fa637255729c..000000000000
--- a/drivers/media/dvb/dvb-usb/ce6230.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2009 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 "ce6230.h"
-#include "zl10353.h"
-#include "mxl5005s.h"
-
-/* debug */
-static int dvb_usb_ce6230_debug;
-module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static struct zl10353_config ce6230_zl10353_config;
-
-static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
-{
- int ret;
- unsigned int pipe;
- u8 request;
- u8 requesttype;
- u16 value;
- u16 index;
- u8 *buf;
-
- request = req->cmd;
- value = req->value;
- index = req->index;
-
- switch (req->cmd) {
- case I2C_READ:
- case DEMOD_READ:
- case REG_READ:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
- break;
- case I2C_WRITE:
- case DEMOD_WRITE:
- case REG_WRITE:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
- break;
- default:
- err("unknown command:%02x", req->cmd);
- ret = -EPERM;
- goto error;
- }
-
- buf = kmalloc(req->data_len, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto error;
- }
-
- if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
- /* write */
- memcpy(buf, req->data, req->data_len);
- pipe = usb_sndctrlpipe(udev, 0);
- } else {
- /* read */
- pipe = usb_rcvctrlpipe(udev, 0);
- }
-
- msleep(1); /* avoid I2C errors */
-
- ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
- buf, req->data_len, CE6230_USB_TIMEOUT);
-
- ce6230_debug_dump(request, requesttype, value, index, buf,
- req->data_len, deb_xfer);
-
- if (ret < 0)
- deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
- else
- ret = 0;
-
- /* read request, copy returned data to return buf */
- if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
- memcpy(req->data, buf, req->data_len);
-
- kfree(buf);
-error:
- return ret;
-}
-
-static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
- return ce6230_rw_udev(d->udev, req);
-}
-
-/* I2C */
-static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int i = 0;
- struct req_t req;
- int ret = 0;
- memset(&req, 0, sizeof(req));
-
- if (num > 2)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- while (i < num) {
- if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
- if (msg[i].addr ==
- ce6230_zl10353_config.demod_address) {
- req.cmd = DEMOD_READ;
- req.value = msg[i].addr >> 1;
- req.index = msg[i].buf[0];
- req.data_len = msg[i+1].len;
- req.data = &msg[i+1].buf[0];
- ret = ce6230_ctrl_msg(d, &req);
- } else {
- err("i2c read not implemented");
- ret = -EPERM;
- }
- i += 2;
- } else {
- if (msg[i].addr ==
- ce6230_zl10353_config.demod_address) {
- req.cmd = DEMOD_WRITE;
- req.value = msg[i].addr >> 1;
- req.index = msg[i].buf[0];
- req.data_len = msg[i].len-1;
- req.data = &msg[i].buf[1];
- ret = ce6230_ctrl_msg(d, &req);
- } else {
- req.cmd = I2C_WRITE;
- req.value = 0x2000 + (msg[i].addr >> 1);
- req.index = 0x0000;
- req.data_len = msg[i].len;
- req.data = &msg[i].buf[0];
- ret = ce6230_ctrl_msg(d, &req);
- }
- i += 1;
- }
- if (ret)
- break;
- }
-
- mutex_unlock(&d->i2c_mutex);
- return ret ? ret : i;
-}
-
-static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm ce6230_i2c_algo = {
- .master_xfer = ce6230_i2c_xfer,
- .functionality = ce6230_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config ce6230_zl10353_config = {
- .demod_address = 0x1e,
- .adc_clock = 450000,
- .if2 = 45700,
- .no_tuner = 1,
- .parallel_ts = 1,
- .clock_ctl_1 = 0x34,
- .pll_0 = 0x0e,
-};
-
-static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
-{
- deb_info("%s:\n", __func__);
- adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
- return -ENODEV;
- return 0;
-}
-
-static struct mxl5005s_config ce6230_mxl5003s_config = {
- .i2c_address = 0xc6,
- .if_freq = IF_FREQ_4570000HZ,
- .xtal_freq = CRYSTAL_FREQ_16000000HZ,
- .agc_mode = MXL_SINGLE_AGC,
- .tracking_filter = MXL_TF_DEFAULT,
- .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 ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
- int ret;
- deb_info("%s:\n", __func__);
- ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
- &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
- return ret;
-}
-
-static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
- int ret;
- deb_info("%s: onoff:%d\n", __func__, onoff);
-
- /* InterfaceNumber 1 / AlternateSetting 0 idle
- InterfaceNumber 1 / AlternateSetting 1 streaming */
- ret = usb_set_interface(d->udev, 1, onoff);
- if (ret)
- err("usb_set_interface failed with error:%d", ret);
-
- return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ce6230_properties;
-
-static int ce6230_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int ret = 0;
- struct dvb_usb_device *d = NULL;
-
- deb_info("%s: interface:%d\n", __func__,
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
- ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
- &d, adapter_nr);
- if (ret)
- err("init failed with error:%d\n", ret);
- }
-
- return ret;
-}
-
-static struct usb_device_id ce6230_table[] = {
- { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, ce6230_table);
-
-static struct dvb_usb_device_properties ce6230_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .no_reconnect = 1,
-
- .size_of_priv = 0,
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = ce6230_zl10353_frontend_attach,
- .tuner_attach = ce6230_mxl5003s_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x82,
- .u = {
- .bulk = {
- .buffersize = (16*512),
- }
- }
- },
- }},
- }
- },
-
- .power_ctrl = ce6230_power_ctrl,
-
- .i2c_algo = &ce6230_i2c_algo,
-
- .num_device_descs = 2,
- .devices = {
- {
- .name = "Intel CE9500 reference design",
- .cold_ids = {NULL},
- .warm_ids = {&ce6230_table[0], NULL},
- },
- {
- .name = "AVerMedia A310 USB 2.0 DVB-T tuner",
- .cold_ids = {NULL},
- .warm_ids = {&ce6230_table[1], NULL},
- },
- }
-};
-
-static struct usb_driver ce6230_driver = {
- .name = "dvb_usb_ce6230",
- .probe = ce6230_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = ce6230_table,
-};
-
-module_usb_driver(ce6230_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h
deleted file mode 100644
index 97c42482ccb3..000000000000
--- a/drivers/media/dvb/dvb-usb/ce6230.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2009 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 _DVB_USB_CE6230_H_
-#define _DVB_USB_CE6230_H_
-
-#define DVB_USB_LOG_PREFIX "ce6230"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args)
-#define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args)
-#define deb_reg(args...) dprintk(dvb_usb_ce6230_debug, 0x08, args)
-#define deb_i2c(args...) dprintk(dvb_usb_ce6230_debug, 0x10, args)
-#define deb_fw(args...) dprintk(dvb_usb_ce6230_debug, 0x20, args)
-
-#define ce6230_debug_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");\
-}
-
-#define CE6230_USB_TIMEOUT 1000
-
-struct req_t {
- u8 cmd; /* [1] */
- u16 value; /* [2|3] */
- u16 index; /* [4|5] */
- u16 data_len; /* [6|7] */
- u8 *data;
-};
-
-enum ce6230_cmd {
- CONFIG_READ = 0xd0, /* rd 0 (unclear) */
- UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */
- I2C_READ = 0xd9, /* rd 9 (unclear) */
- I2C_WRITE = 0xca, /* wr a */
- DEMOD_READ = 0xdb, /* rd b */
- DEMOD_WRITE = 0xcc, /* wr c */
- REG_READ = 0xde, /* rd e */
- REG_WRITE = 0xcf, /* wr f */
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
deleted file mode 100644
index 7e9e00fae04e..000000000000
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
- *
- * 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.
- *
- * Copyright (C) 2005-6 DiBcom, SA
- */
-#include "dib0700.h"
-
-/* debug */
-int dvb_usb_dib0700_debug;
-module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
-
-static int nb_packet_buffer_size = 21;
-module_param(nb_packet_buffer_size, int, 0644);
-MODULE_PARM_DESC(nb_packet_buffer_size,
- "Set the dib0700 driver data buffer size. This parameter "
- "corresponds to the number of TS packets. The actual size of "
- "the data buffer corresponds to this parameter "
- "multiplied by 188 (default: 21)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-
-int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
- u32 *romversion, u32 *ramversion, u32 *fwtype)
-{
- struct dib0700_state *st = d->priv;
- int ret;
-
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
- REQUEST_GET_VERSION,
- USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- st->buf, 16, USB_CTRL_GET_TIMEOUT);
- if (hwversion != NULL)
- *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) |
- (st->buf[2] << 8) | st->buf[3];
- if (romversion != NULL)
- *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) |
- (st->buf[6] << 8) | st->buf[7];
- if (ramversion != NULL)
- *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) |
- (st->buf[10] << 8) | st->buf[11];
- if (fwtype != NULL)
- *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
- (st->buf[14] << 8) | st->buf[15];
- mutex_unlock(&d->usb_mutex);
- return ret;
-}
-
-/* expecting rx buffer: request data[0] data[1] ... data[2] */
-static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
-{
- int status;
-
- deb_data(">>> ");
- debug_dump(tx, txlen, deb_data);
-
- status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
- tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
- USB_CTRL_GET_TIMEOUT);
-
- if (status != txlen)
- deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
-
- return status < 0 ? status : 0;
-}
-
-/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
-{
- u16 index, value;
- int status;
-
- if (txlen < 2) {
- err("tx buffer length is smaller than 2. Makes no sense.");
- return -EINVAL;
- }
- if (txlen > 4) {
- err("tx buffer length is larger than 4. Not supported.");
- return -EINVAL;
- }
-
- deb_data(">>> ");
- debug_dump(tx,txlen,deb_data);
-
- value = ((txlen - 2) << 8) | tx[1];
- index = 0;
- if (txlen > 2)
- index |= (tx[2] << 8);
- if (txlen > 3)
- index |= tx[3];
-
- status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
- USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
- USB_CTRL_GET_TIMEOUT);
-
- if (status < 0)
- deb_info("ep 0 read error (status = %d)\n",status);
-
- deb_data("<<< ");
- debug_dump(rx, rxlen, deb_data);
-
- return status; /* length in case of success */
-}
-
-int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
-{
- struct dib0700_state *st = d->priv;
- int ret;
-
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_SET_GPIO;
- st->buf[1] = gpio;
- st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
-
- ret = dib0700_ctrl_wr(d, st->buf, 3);
-
- mutex_unlock(&d->usb_mutex);
- return ret;
-}
-
-static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
-{
- struct dib0700_state *st = d->priv;
- int ret;
-
- if (st->fw_version >= 0x10201) {
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_SET_USB_XFER_LEN;
- st->buf[1] = (nb_ts_packets >> 8) & 0xff;
- st->buf[2] = nb_ts_packets & 0xff;
-
- deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
-
- ret = dib0700_ctrl_wr(d, st->buf, 3);
- mutex_unlock(&d->usb_mutex);
- } else {
- deb_info("this firmware does not allow to change the USB xfer len\n");
- ret = -EIO;
- }
-
- return ret;
-}
-
-/*
- * I2C master xfer function (supported in 1.20 firmware)
- */
-static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
- int num)
-{
- /* The new i2c firmware messages are more reliable and in particular
- properly support i2c read calls not preceded by a write */
-
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct dib0700_state *st = d->priv;
- uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
- uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
- uint8_t en_start = 0;
- uint8_t en_stop = 0;
- int result, i;
-
- /* Ensure nobody else hits the i2c bus while we're sending our
- sequence of messages, (such as the remote control thread) */
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EINTR;
-
- for (i = 0; i < num; i++) {
- if (i == 0) {
- /* First message in the transaction */
- en_start = 1;
- } else if (!(msg[i].flags & I2C_M_NOSTART)) {
- /* Device supports repeated-start */
- en_start = 1;
- } else {
- /* Not the first packet and device doesn't support
- repeated start */
- en_start = 0;
- }
- if (i == (num - 1)) {
- /* Last message in the transaction */
- en_stop = 1;
- }
-
- if (msg[i].flags & I2C_M_RD) {
- /* Read request */
- u16 index, value;
- uint8_t i2c_dest;
-
- i2c_dest = (msg[i].addr << 1);
- value = ((en_start << 7) | (en_stop << 6) |
- (msg[i].len & 0x3F)) << 8 | i2c_dest;
- /* I2C ctrl + FE bus; */
- index = ((gen_mode << 6) & 0xC0) |
- ((bus_mode << 4) & 0x30);
-
- result = usb_control_msg(d->udev,
- usb_rcvctrlpipe(d->udev, 0),
- REQUEST_NEW_I2C_READ,
- USB_TYPE_VENDOR | USB_DIR_IN,
- value, index, msg[i].buf,
- msg[i].len,
- USB_CTRL_GET_TIMEOUT);
- if (result < 0) {
- deb_info("i2c read error (status = %d)\n", result);
- break;
- }
-
- deb_data("<<< ");
- debug_dump(msg[i].buf, msg[i].len, deb_data);
-
- } else {
- /* Write request */
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- mutex_unlock(&d->i2c_mutex);
- return -EINTR;
- }
- st->buf[0] = REQUEST_NEW_I2C_WRITE;
- st->buf[1] = msg[i].addr << 1;
- st->buf[2] = (en_start << 7) | (en_stop << 6) |
- (msg[i].len & 0x3F);
- /* I2C ctrl + FE bus; */
- st->buf[3] = ((gen_mode << 6) & 0xC0) |
- ((bus_mode << 4) & 0x30);
- /* The Actual i2c payload */
- memcpy(&st->buf[4], msg[i].buf, msg[i].len);
-
- deb_data(">>> ");
- debug_dump(st->buf, msg[i].len + 4, deb_data);
-
- result = usb_control_msg(d->udev,
- usb_sndctrlpipe(d->udev, 0),
- REQUEST_NEW_I2C_WRITE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- 0, 0, st->buf, msg[i].len + 4,
- USB_CTRL_GET_TIMEOUT);
- mutex_unlock(&d->usb_mutex);
- if (result < 0) {
- deb_info("i2c write error (status = %d)\n", result);
- break;
- }
- }
- }
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-/*
- * I2C master xfer function (pre-1.20 firmware)
- */
-static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
- struct i2c_msg *msg, int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct dib0700_state *st = d->priv;
- int i,len;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EINTR;
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- mutex_unlock(&d->i2c_mutex);
- return -EINTR;
- }
-
- for (i = 0; i < num; i++) {
- /* fill in the address */
- st->buf[1] = msg[i].addr << 1;
- /* fill the buffer */
- memcpy(&st->buf[2], msg[i].buf, msg[i].len);
-
- /* write/read request */
- if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
- st->buf[0] = REQUEST_I2C_READ;
- st->buf[1] |= 1;
-
- /* special thing in the current firmware: when length is zero the read-failed */
- len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
- msg[i+1].buf, msg[i+1].len);
- if (len <= 0) {
- deb_info("I2C read failed on address 0x%02x\n",
- msg[i].addr);
- break;
- }
-
- msg[i+1].len = len;
-
- i++;
- } else {
- st->buf[0] = REQUEST_I2C_WRITE;
- if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
- break;
- }
- }
- mutex_unlock(&d->usb_mutex);
- mutex_unlock(&d->i2c_mutex);
-
- return i;
-}
-
-static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct dib0700_state *st = d->priv;
-
- if (st->fw_use_new_i2c_api == 1) {
- /* User running at least fw 1.20 */
- return dib0700_i2c_xfer_new(adap, msg, num);
- } else {
- /* Use legacy calls */
- return dib0700_i2c_xfer_legacy(adap, msg, num);
- }
-}
-
-static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm dib0700_i2c_algo = {
- .master_xfer = dib0700_i2c_xfer,
- .functionality = dib0700_i2c_func,
-};
-
-int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc, int *cold)
-{
- s16 ret;
- u8 *b;
-
- b = kmalloc(16, GFP_KERNEL);
- if (!b)
- return -ENOMEM;
-
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
-
- deb_info("FW GET_VERSION length: %d\n",ret);
-
- *cold = ret <= 0;
- deb_info("cold: %d\n", *cold);
-
- kfree(b);
- return 0;
-}
-
-static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
- u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
- u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
-{
- struct dib0700_state *st = d->priv;
- int ret;
-
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_SET_CLOCK;
- st->buf[1] = (en_pll << 7) | (pll_src << 6) |
- (pll_range << 5) | (clock_gpio3 << 4);
- st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */
- st->buf[3] = pll_prediv & 0xff; /* LSB */
- st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
- st->buf[5] = pll_loopdiv & 0xff; /* LSB */
- st->buf[6] = (free_div >> 8) & 0xff; /* MSB */
- st->buf[7] = free_div & 0xff; /* LSB */
- st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */
- st->buf[9] = dsuScaler & 0xff; /* LSB */
-
- ret = dib0700_ctrl_wr(d, st->buf, 10);
- mutex_unlock(&d->usb_mutex);
-
- return ret;
-}
-
-int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
-{
- struct dib0700_state *st = d->priv;
- u16 divider;
- int ret;
-
- if (scl_kHz == 0)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_SET_I2C_PARAM;
- divider = (u16) (30000 / scl_kHz);
- st->buf[1] = 0;
- st->buf[2] = (u8) (divider >> 8);
- st->buf[3] = (u8) (divider & 0xff);
- divider = (u16) (72000 / scl_kHz);
- st->buf[4] = (u8) (divider >> 8);
- st->buf[5] = (u8) (divider & 0xff);
- divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
- st->buf[6] = (u8) (divider >> 8);
- st->buf[7] = (u8) (divider & 0xff);
-
- deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
- (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
- st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
-
- ret = dib0700_ctrl_wr(d, st->buf, 8);
- mutex_unlock(&d->usb_mutex);
-
- return ret;
-}
-
-
-int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
-{
- switch (clk_MHz) {
- case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
- default: return -EINVAL;
- }
- return 0;
-}
-
-static int dib0700_jumpram(struct usb_device *udev, u32 address)
-{
- int ret = 0, actlen;
- u8 *buf;
-
- buf = kmalloc(8, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- buf[0] = REQUEST_JUMPRAM;
- buf[1] = 0;
- buf[2] = 0;
- buf[3] = 0;
- buf[4] = (address >> 24) & 0xff;
- buf[5] = (address >> 16) & 0xff;
- buf[6] = (address >> 8) & 0xff;
- buf[7] = address & 0xff;
-
- if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
- deb_fw("jumpram to 0x%x failed\n",address);
- goto out;
- }
- if (actlen != 8) {
- deb_fw("jumpram to 0x%x failed\n",address);
- ret = -EIO;
- goto out;
- }
-out:
- kfree(buf);
- return ret;
-}
-
-int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
-{
- struct hexline hx;
- int pos = 0, ret, act_len, i, adap_num;
- u8 *buf;
- u32 fw_version;
-
- buf = kmalloc(260, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
- deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
- hx.addr, hx.len, hx.chk);
-
- buf[0] = hx.len;
- buf[1] = (hx.addr >> 8) & 0xff;
- buf[2] = hx.addr & 0xff;
- buf[3] = hx.type;
- memcpy(&buf[4],hx.data,hx.len);
- buf[4+hx.len] = hx.chk;
-
- ret = usb_bulk_msg(udev,
- usb_sndbulkpipe(udev, 0x01),
- buf,
- hx.len + 5,
- &act_len,
- 1000);
-
- if (ret < 0) {
- err("firmware download failed at %d with %d",pos,ret);
- goto out;
- }
- }
-
- if (ret == 0) {
- /* start the firmware */
- if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
- info("firmware started successfully.");
- msleep(500);
- }
- } else
- ret = -EIO;
-
- /* the number of ts packet has to be at least 1 */
- if (nb_packet_buffer_size < 1)
- nb_packet_buffer_size = 1;
-
- /* get the fimware version */
- usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- REQUEST_GET_VERSION,
- USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- buf, 16, USB_CTRL_GET_TIMEOUT);
- fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
-
- /* set the buffer size - DVB-USB is allocating URB buffers
- * only after the firwmare download was successful */
- for (i = 0; i < dib0700_device_count; i++) {
- for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
- adap_num++) {
- if (fw_version >= 0x10201) {
- dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
- } else {
- /* for fw version older than 1.20.1,
- * the buffersize has to be n times 512 */
- dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
- if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
- dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
- }
- }
- }
-out:
- kfree(buf);
- return ret;
-}
-
-int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dib0700_state *st = adap->dev->priv;
- int ret;
-
- if ((onoff != 0) && (st->fw_version >= 0x10201)) {
- /* for firmware later than 1.20.1,
- * the USB xfer length can be set */
- ret = dib0700_set_usb_xfer_len(adap->dev,
- st->nb_packet_buffer_size);
- if (ret < 0) {
- deb_info("can not set the USB xfer len\n");
- return ret;
- }
- }
-
- if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_ENABLE_VIDEO;
- /* this bit gives a kind of command,
- * rather than enabling something or not */
- st->buf[1] = (onoff << 4) | 0x00;
-
- if (st->disable_streaming_master_mode == 1)
- st->buf[2] = 0x00;
- else
- st->buf[2] = 0x01 << 4; /* Master mode */
-
- st->buf[3] = 0x00;
-
- deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
-
- st->channel_state &= ~0x3;
- if ((adap->fe_adap[0].stream.props.endpoint != 2)
- && (adap->fe_adap[0].stream.props.endpoint != 3)) {
- deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
- if (onoff)
- st->channel_state |= 1 << (adap->id);
- else
- st->channel_state |= 1 << ~(adap->id);
- } else {
- if (onoff)
- st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2);
- else
- st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint);
- }
-
- st->buf[2] |= st->channel_state;
-
- deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
-
- ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
- mutex_unlock(&adap->dev->usb_mutex);
-
- return ret;
-}
-
-int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
-{
- struct dvb_usb_device *d = rc->priv;
- struct dib0700_state *st = d->priv;
- int new_proto, ret;
-
- if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
-
- st->buf[0] = REQUEST_SET_RC;
- st->buf[1] = 0;
- st->buf[2] = 0;
-
- /* Set the IR mode */
- if (rc_type == RC_TYPE_RC5)
- new_proto = 1;
- else if (rc_type == RC_TYPE_NEC)
- new_proto = 0;
- else if (rc_type == RC_TYPE_RC6) {
- if (st->fw_version < 0x10200) {
- ret = -EINVAL;
- goto out;
- }
-
- new_proto = 2;
- } else {
- ret = -EINVAL;
- goto out;
- }
-
- st->buf[1] = new_proto;
-
- ret = dib0700_ctrl_wr(d, st->buf, 3);
- if (ret < 0) {
- err("ir protocol setup failed");
- goto out;
- }
-
- d->props.rc.core.protocol = rc_type;
-
-out:
- mutex_unlock(&d->usb_mutex);
- return ret;
-}
-
-/* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY_V1_20 10
-
-/* This is the structure of the RC response packet starting in firmware 1.20 */
-struct dib0700_rc_response {
- u8 report_id;
- u8 data_state;
- union {
- u16 system16;
- struct {
- u8 not_system;
- u8 system;
- };
- };
- u8 data;
- u8 not_data;
-};
-#define RC_MSG_SIZE_V1_20 6
-
-static void dib0700_rc_urb_completion(struct urb *purb)
-{
- struct dvb_usb_device *d = purb->context;
- struct dib0700_rc_response *poll_reply;
- u32 uninitialized_var(keycode);
- u8 toggle;
-
- deb_info("%s()\n", __func__);
- if (d->rc_dev == NULL) {
- /* This will occur if disable_rc_polling=1 */
- kfree(purb->transfer_buffer);
- usb_free_urb(purb);
- return;
- }
-
- poll_reply = purb->transfer_buffer;
-
- if (purb->status < 0) {
- deb_info("discontinuing polling\n");
- kfree(purb->transfer_buffer);
- usb_free_urb(purb);
- return;
- }
-
- if (purb->actual_length != RC_MSG_SIZE_V1_20) {
- deb_info("malformed rc msg size=%d\n", purb->actual_length);
- goto resubmit;
- }
-
- deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
- poll_reply->report_id, poll_reply->data_state,
- poll_reply->system, poll_reply->not_system,
- poll_reply->data, poll_reply->not_data,
- purb->actual_length);
-
- switch (d->props.rc.core.protocol) {
- case RC_TYPE_NEC:
- toggle = 0;
-
- /* NEC protocol sends repeat code as 0 0 0 FF */
- if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
- && (poll_reply->not_data == 0xff)) {
- poll_reply->data_state = 2;
- break;
- }
-
- if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
- deb_data("NEC extended protocol\n");
- /* NEC extended code - 24 bits */
- keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
- } else {
- deb_data("NEC normal protocol\n");
- /* normal NEC code - 16 bits */
- keycode = poll_reply->system << 8 | poll_reply->data;
- }
-
- break;
- default:
- deb_data("RC5 protocol\n");
- /* RC5 Protocol */
- toggle = poll_reply->report_id;
- keycode = poll_reply->system << 8 | poll_reply->data;
-
- break;
- }
-
- if ((poll_reply->data + poll_reply->not_data) != 0xff) {
- /* Key failed integrity check */
- err("key failed integrity check: %04x %02x %02x",
- poll_reply->system,
- poll_reply->data, poll_reply->not_data);
- goto resubmit;
- }
-
- rc_keydown(d->rc_dev, keycode, toggle);
-
-resubmit:
- /* Clean the buffer before we requeue */
- memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
-
- /* Requeue URB */
- usb_submit_urb(purb, GFP_ATOMIC);
-}
-
-int dib0700_rc_setup(struct dvb_usb_device *d)
-{
- struct dib0700_state *st = d->priv;
- struct urb *purb;
- int ret;
-
- /* Poll-based. Don't initialize bulk mode */
- if (st->fw_version < 0x10200)
- return 0;
-
- /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
- purb = usb_alloc_urb(0, GFP_KERNEL);
- if (purb == NULL) {
- err("rc usb alloc urb failed\n");
- return -ENOMEM;
- }
-
- purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
- if (purb->transfer_buffer == NULL) {
- err("rc kzalloc failed\n");
- usb_free_urb(purb);
- return -ENOMEM;
- }
-
- purb->status = -EINPROGRESS;
- usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
- purb->transfer_buffer, RC_MSG_SIZE_V1_20,
- dib0700_rc_urb_completion, d);
-
- ret = usb_submit_urb(purb, GFP_ATOMIC);
- if (ret) {
- err("rc submit urb failed\n");
- kfree(purb->transfer_buffer);
- usb_free_urb(purb);
- }
-
- return ret;
-}
-
-static int dib0700_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int i;
- struct dvb_usb_device *dev;
-
- for (i = 0; i < dib0700_device_count; i++)
- if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
- &dev, adapter_nr) == 0) {
- struct dib0700_state *st = dev->priv;
- u32 hwversion, romversion, fw_version, fwtype;
-
- dib0700_get_version(dev, &hwversion, &romversion,
- &fw_version, &fwtype);
-
- deb_info("Firmware version: %x, %d, 0x%x, %d\n",
- hwversion, romversion, fw_version, fwtype);
-
- st->fw_version = fw_version;
- st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
-
- /* Disable polling mode on newer firmwares */
- if (st->fw_version >= 0x10200)
- dev->props.rc.core.bulk_mode = true;
- else
- dev->props.rc.core.bulk_mode = false;
-
- dib0700_rc_setup(dev);
-
- return 0;
- }
-
- return -ENODEV;
-}
-
-static struct usb_driver dib0700_driver = {
- .name = "dvb_usb_dib0700",
- .probe = dib0700_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = dib0700_usb_id_table,
-};
-
-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");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
deleted file mode 100644
index ddf282f355b3..000000000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* dvb-usb-dvb.c is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * This file contains functions for initializing and handling the
- * linux-dvb API.
- */
-#include "dvb-usb-common.h"
-
-/* does the complete input transfer handling */
-static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
-{
- struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
- int newfeedcount, ret;
-
- if (adap == NULL)
- return -ENODEV;
-
- if ((adap->active_fe < 0) ||
- (adap->active_fe >= adap->num_frontends_initialized)) {
- return -EINVAL;
- }
-
- newfeedcount = adap->feedcount + (onoff ? 1 : -1);
-
- /* stop feed before setting a new pid if there will be no pid anymore */
- if (newfeedcount == 0) {
- deb_ts("stop feeding\n");
- usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
-
- if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
- ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
- if (ret < 0) {
- err("error while stopping stream.");
- return ret;
- }
- }
- }
-
- adap->feedcount = newfeedcount;
-
- /* activate the pid on the device specific pid_filter */
- deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
- adap->fe_adap[adap->active_fe].pid_filtering ?
- "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
- dvbdmxfeed->index, onoff ? "on" : "off");
- if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->fe_adap[adap->active_fe].pid_filtering &&
- adap->props.fe[adap->active_fe].pid_filter != NULL)
- adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
-
- /* start the feed if this was the first feed and there is still a feed
- * for reception.
- */
- if (adap->feedcount == onoff && adap->feedcount > 0) {
- deb_ts("submitting all URBs\n");
- usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
-
- deb_ts("controlling pid parser\n");
- if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->props.fe[adap->active_fe].caps &
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
- adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
- ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
- adap->fe_adap[adap->active_fe].pid_filtering);
- if (ret < 0) {
- err("could not handle pid_parser");
- return ret;
- }
- }
- deb_ts("start feeding\n");
- if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
- ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
- if (ret < 0) {
- err("error while enabling fifo.");
- return ret;
- }
- }
-
- }
- return 0;
-}
-
-static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
- return dvb_usb_ctrl_feed(dvbdmxfeed,1);
-}
-
-static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
- return dvb_usb_ctrl_feed(dvbdmxfeed,0);
-}
-
-int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
-{
- int i;
- int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
- adap->dev->owner, &adap->dev->udev->dev,
- adapter_nums);
-
- if (ret < 0) {
- deb_info("dvb_register_adapter failed: error %d", ret);
- goto err;
- }
- adap->dvb_adap.priv = adap;
- adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override;
-
- if (adap->dev->props.read_mac_address) {
- if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
- info("MAC address: %pM",adap->dvb_adap.proposed_mac);
- else
- err("MAC address reading failed.");
- }
-
-
- adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
- adap->demux.priv = adap;
-
- adap->demux.filternum = 0;
- for (i = 0; i < adap->props.num_frontends; i++) {
- if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
- adap->demux.filternum = adap->fe_adap[i].max_feed_count;
- }
- adap->demux.feednum = adap->demux.filternum;
- adap->demux.start_feed = dvb_usb_start_feed;
- adap->demux.stop_feed = dvb_usb_stop_feed;
- adap->demux.write_to_decoder = NULL;
- if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
- err("dvb_dmx_init failed: error %d",ret);
- goto err_dmx;
- }
-
- adap->dmxdev.filternum = adap->demux.filternum;
- adap->dmxdev.demux = &adap->demux.dmx;
- adap->dmxdev.capabilities = 0;
- if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
- err("dvb_dmxdev_init failed: error %d",ret);
- goto err_dmx_dev;
- }
-
- 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:
- dvb_unregister_adapter(&adap->dvb_adap);
-err:
- return ret;
-}
-
-int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
-{
- if (adap->state & DVB_USB_ADAP_STATE_DVB) {
- deb_info("unregistering DVB part\n");
- dvb_net_release(&adap->dvb_net);
- adap->demux.dmx.close(&adap->demux.dmx);
- dvb_dmxdev_release(&adap->dmxdev);
- dvb_dmx_release(&adap->demux);
- dvb_unregister_adapter(&adap->dvb_adap);
- adap->state &= ~DVB_USB_ADAP_STATE_DVB;
- }
- return 0;
-}
-
-static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- int ret = (adap->props.frontend_ctrl) ?
- adap->props.frontend_ctrl(fe, onoff) : 0;
-
- if (ret < 0) {
- err("frontend_ctrl request failed");
- return ret;
- }
- if (onoff)
- adap->active_fe = fe->id;
-
- return 0;
-}
-
-static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- dvb_usb_device_power_ctrl(adap->dev, 1);
-
- dvb_usb_set_active_fe(fe, 1);
-
- if (adap->fe_adap[fe->id].fe_init)
- adap->fe_adap[fe->id].fe_init(fe);
-
- return 0;
-}
-
-static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- if (adap->fe_adap[fe->id].fe_sleep)
- adap->fe_adap[fe->id].fe_sleep(fe);
-
- dvb_usb_set_active_fe(fe, 0);
-
- return dvb_usb_device_power_ctrl(adap->dev, 0);
-}
-
-int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
-{
- int ret, i;
-
- /* register all given adapter frontends */
- for (i = 0; i < adap->props.num_frontends; i++) {
-
- if (adap->props.fe[i].frontend_attach == NULL) {
- err("strange: '%s' #%d,%d "
- "doesn't want to attach a frontend.",
- adap->dev->desc->name, adap->id, i);
-
- return 0;
- }
-
- ret = adap->props.fe[i].frontend_attach(adap);
- if (ret || adap->fe_adap[i].fe == NULL) {
- /* only print error when there is no FE at all */
- if (i == 0)
- err("no frontend was attached by '%s'",
- adap->dev->desc->name);
-
- return 0;
- }
-
- adap->fe_adap[i].fe->id = i;
-
- /* re-assign sleep and wakeup functions */
- adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
- adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup;
- adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
- adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
-
- if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
- err("Frontend %d registration failed.", i);
- dvb_frontend_detach(adap->fe_adap[i].fe);
- adap->fe_adap[i].fe = NULL;
- /* In error case, do not try register more FEs,
- * still leaving already registered FEs alive. */
- if (i == 0)
- return -ENODEV;
- else
- return 0;
- }
-
- /* only attach the tuner if the demod is there */
- if (adap->props.fe[i].tuner_attach != NULL)
- adap->props.fe[i].tuner_attach(adap);
-
- adap->num_frontends_initialized++;
- }
-
- return 0;
-}
-
-int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
-{
- int i = adap->num_frontends_initialized - 1;
-
- /* unregister all given adapter frontends */
- for (; i >= 0; i--) {
- if (adap->fe_adap[i].fe != NULL) {
- dvb_unregister_frontend(adap->fe_adap[i].fe);
- dvb_frontend_detach(adap->fe_adap[i].fe);
- }
- }
- adap->num_frontends_initialized = 0;
-
- return 0;
-}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
deleted file mode 100644
index 99f94409efa1..000000000000
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ /dev/null
@@ -1,485 +0,0 @@
-/* dvb-usb.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
- * see dvb-usb-init.c for copyright information.
- *
- * the headerfile, all dvb-usb-drivers have to include.
- *
- * TODO: clean-up the structures for unused fields and update the comments
- */
-#ifndef __DVB_USB_H__
-#define __DVB_USB_H__
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-#include <linux/mutex.h>
-#include <media/rc-core.h>
-
-#include "dvb_frontend.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-#include "dmxdev.h"
-
-#include "dvb-pll.h"
-
-#include "dvb-usb-ids.h"
-
-/* debug */
-#ifdef CONFIG_DVB_USB_DEBUG
-#define dprintk(var,level,args...) \
- do { if ((var & level)) { printk(args); } } while (0)
-
-#define debug_dump(b,l,func) {\
- int loop_; \
- for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
- func("\n");\
-}
-#define DVB_USB_DEBUG_STATUS
-#else
-#define dprintk(args...)
-#define debug_dump(b,l,func)
-
-#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
-
-#endif
-
-/* generic log methods - taken from usb.h */
-#ifndef DVB_USB_LOG_PREFIX
- #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
-#endif
-
-#undef err
-#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
-
-/**
- * struct dvb_usb_device_description - name and its according USB IDs
- * @name: real name of the box, regardless which DVB USB device class is in use
- * @cold_ids: array of struct usb_device_id which describe the device in
- * pre-firmware state
- * @warm_ids: array of struct usb_device_id which describe the device in
- * post-firmware state
- *
- * Each DVB USB device class can have one or more actual devices, this struct
- * assigns a name to it.
- */
-struct dvb_usb_device_description {
- const char *name;
-
-#define DVB_USB_ID_MAX_NUM 15
- struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
- struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
-};
-
-static inline u8 rc5_custom(struct rc_map_table *key)
-{
- return (key->scancode >> 8) & 0xff;
-}
-
-static inline u8 rc5_data(struct rc_map_table *key)
-{
- return key->scancode & 0xff;
-}
-
-static inline u16 rc5_scan(struct rc_map_table *key)
-{
- return key->scancode & 0xffff;
-}
-
-struct dvb_usb_device;
-struct dvb_usb_adapter;
-struct usb_data_stream;
-
-/**
- * Properties of USB streaming - TODO this structure should be somewhere else
- * describes the kind of USB transfer used for data-streaming.
- * (BULK or ISOC)
- */
-struct usb_data_stream_properties {
-#define USB_BULK 1
-#define USB_ISOC 2
- int type;
- int count;
- int endpoint;
-
- union {
- struct {
- int buffersize; /* per URB */
- } bulk;
- struct {
- int framesperurb;
- int framesize;
- int interval;
- } isoc;
- } u;
-};
-
-/**
- * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
- * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
- * @caps: capabilities of the DVB USB device.
- * @pid_filter_count: number of PID filter position in the optional hardware
- * PID-filter.
- * @num_frontends: number of frontends of the DVB USB adapter.
- * @frontend_ctrl: called to power on/off active frontend.
- * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
- * device (not URB submitting/killing).
- * @pid_filter_ctrl: called to en/disable the PID filter, if any.
- * @pid_filter: called to set/unset a PID for filtering.
- * @frontend_attach: called to attach the possible frontends (fill fe-field
- * of struct dvb_usb_device).
- * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
- * pll_desc and pll_init_buf of struct dvb_usb_device).
- * @stream: configuration of the USB streaming
- */
-struct dvb_usb_adapter_fe_properties {
-#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
-#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
-#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
-#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
-#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10
- int caps;
- int pid_filter_count;
-
- int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
- int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
- int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
-
- int (*frontend_attach) (struct dvb_usb_adapter *);
- int (*tuner_attach) (struct dvb_usb_adapter *);
-
- struct usb_data_stream_properties stream;
-
- int size_of_priv;
-};
-
-#define MAX_NO_OF_FE_PER_ADAP 3
-struct dvb_usb_adapter_properties {
- int size_of_priv;
-
- int (*frontend_ctrl) (struct dvb_frontend *, int);
- int (*fe_ioctl_override) (struct dvb_frontend *,
- unsigned int, void *, unsigned int);
-
- int num_frontends;
- struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
-};
-
-/**
- * struct dvb_rc_legacy - old properties of remote controller
- * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
- * remote control handling).
- * @rc_map_size: number of items in @rc_map_table.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
- */
-struct dvb_rc_legacy {
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED 0x00
-#define REMOTE_KEY_PRESSED 0x01
-#define REMOTE_KEY_REPEAT 0x02
- struct rc_map_table *rc_map_table;
- int rc_map_size;
- int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
- int rc_interval;
-};
-
-/**
- * struct dvb_rc properties of remote controller, using rc-core
- * @rc_codes: name of rc codes table
- * @protocol: type of protocol(s) currently used by the driver
- * @allowed_protos: protocol(s) supported by the driver
- * @driver_type: Used to point if a device supports raw mode
- * @change_protocol: callback to change protocol
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
- * @bulk_mode: device supports bulk mode for RC (disable polling mode)
- */
-struct dvb_rc {
- char *rc_codes;
- u64 protocol;
- u64 allowed_protos;
- enum rc_driver_type driver_type;
- int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
- char *module_name;
- int (*rc_query) (struct dvb_usb_device *d);
- int rc_interval;
- bool bulk_mode; /* uses bulk mode */
-};
-
-/**
- * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
- * based on rc-core
- * This is initialized/used only inside dvb-usb-remote.c.
- * It shouldn't be set by the drivers.
- */
-enum dvb_usb_mode {
- DVB_RC_LEGACY,
- DVB_RC_CORE,
-};
-
-/**
- * struct dvb_usb_device_properties - properties of a dvb-usb-device
- * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
- * download.
- * @firmware: name of the firmware file.
- * @download_firmware: called to download the firmware when the usb_ctrl is
- * DEVICE_SPECIFIC.
- * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
- * so do the warm initialization right after it
- *
- * @size_of_priv: how many bytes shall be allocated for the private field
- * of struct dvb_usb_device.
- *
- * @power_ctrl: called to enable/disable power of the device.
- * @read_mac_address: called to read the MAC address of the device.
- * @identify_state: called to determine the state (cold or warm), when it
- * is not distinguishable by the USB IDs.
- *
- * @rc: remote controller properties
- *
- * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
- *
- * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
- * endpoint which received control messages with bulk transfers. When this
- * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
- * helper functions.
- *
- * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
- * endpoint for responses to control messages sent with bulk transfers via
- * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
- * instead of the generic_bulk_ctrl_endpoint when reading usb responses in
- * the dvb_usb_generic_rw helper function.
- *
- * @num_device_descs: number of struct dvb_usb_device_description in @devices
- * @devices: array of struct dvb_usb_device_description compatibles with these
- * properties.
- */
-#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
-struct dvb_usb_device_properties {
-
-#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
- int caps;
-
-#define DEVICE_SPECIFIC 0
-#define CYPRESS_AN2135 1
-#define CYPRESS_AN2235 2
-#define CYPRESS_FX2 3
- int usb_ctrl;
- int (*download_firmware) (struct usb_device *, const struct firmware *);
- const char *firmware;
- int no_reconnect;
-
- int size_of_priv;
-
- int num_adapters;
- struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
-
- int (*power_ctrl) (struct dvb_usb_device *, int);
- int (*read_mac_address) (struct dvb_usb_device *, u8 []);
- int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
- struct dvb_usb_device_description **, int *);
-
- struct {
- enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
- struct dvb_rc_legacy legacy;
- struct dvb_rc core;
- } rc;
-
- struct i2c_algorithm *i2c_algo;
-
- int generic_bulk_ctrl_endpoint;
- int generic_bulk_ctrl_endpoint_response;
-
- int num_device_descs;
- struct dvb_usb_device_description devices[12];
-};
-
-/**
- * struct usb_data_stream - generic object of an USB stream
- * @buf_num: number of buffer allocated.
- * @buf_size: size of each buffer in buf_list.
- * @buf_list: array containing all allocate buffers for streaming.
- * @dma_addr: list of dma_addr_t for each buffer in buf_list.
- *
- * @urbs_initialized: number of URBs initialized.
- * @urbs_submitted: number of URBs submitted.
- */
-#define MAX_NO_URBS_FOR_DATA_STREAM 10
-struct usb_data_stream {
- struct usb_device *udev;
- struct usb_data_stream_properties props;
-
-#define USB_STATE_INIT 0x00
-#define USB_STATE_URB_BUF 0x01
- int state;
-
- void (*complete) (struct usb_data_stream *, u8 *, size_t);
-
- struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
- int buf_num;
- unsigned long buf_size;
- u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
- dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
-
- int urbs_initialized;
- int urbs_submitted;
-
- void *user_priv;
-};
-
-/**
- * struct dvb_usb_adapter - a DVB adapter on a USB device
- * @id: index of this adapter (starting with 0).
- *
- * @feedcount: number of reqested feeds (used for streaming-activation)
- * @pid_filtering: is hardware pid_filtering used or not.
- *
- * @pll_addr: I2C address of the tuner for programming
- * @pll_init: array containing the initialization buffer
- * @pll_desc: pointer to the appropriate struct dvb_pll_desc
- * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
- *
- * @dvb_adap: device's dvb_adapter.
- * @dmxdev: device's dmxdev.
- * @demux: device's software demuxer.
- * @dvb_net: device's dvb_net interfaces.
- * @dvb_frontend: device's frontend.
- * @max_feed_count: how many feeds can be handled simultaneously by this
- * device
- *
- * @fe_init: rerouted frontend-init (wakeup) function.
- * @fe_sleep: rerouted frontend-sleep function.
- *
- * @stream: the usb data stream.
- */
-struct dvb_usb_fe_adapter {
- struct dvb_frontend *fe;
-
- int (*fe_init) (struct dvb_frontend *);
- int (*fe_sleep) (struct dvb_frontend *);
-
- struct usb_data_stream stream;
-
- int pid_filtering;
- int max_feed_count;
-
- void *priv;
-};
-
-struct dvb_usb_adapter {
- struct dvb_usb_device *dev;
- struct dvb_usb_adapter_properties props;
-
-#define DVB_USB_ADAP_STATE_INIT 0x000
-#define DVB_USB_ADAP_STATE_DVB 0x001
- int state;
-
- u8 id;
-
- int feedcount;
-
- /* dvb */
- struct dvb_adapter dvb_adap;
- struct dmxdev dmxdev;
- struct dvb_demux demux;
- struct dvb_net dvb_net;
-
- struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
- int active_fe;
- int num_frontends_initialized;
-
- void *priv;
-};
-
-/**
- * struct dvb_usb_device - object of a DVB USB device
- * @props: copy of the struct dvb_usb_properties this device belongs to.
- * @desc: pointer to the device's struct dvb_usb_device_description.
- * @state: initialization and runtime state of the device.
- *
- * @powered: indicated whether the device is power or not.
- * Powered is in/decremented for each call to modify the state.
- * @udev: pointer to the device's struct usb_device.
- *
- * @usb_mutex: semaphore of USB control messages (reading needs two messages)
- * @i2c_mutex: semaphore for i2c-transfers
- *
- * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
- *
- * @rc_dev: rc device for the remote control (rc-core mode)
- * @input_dev: input device for the remote control (legacy mode)
- * @rc_query_work: struct work_struct frequent rc queries
- * @last_event: last triggered event
- * @last_state: last state (no, pressed, repeat)
- * @owner: owner of the dvb_adapter
- * @priv: private data of the actual driver (allocate by dvb-usb, size defined
- * in size_of_priv of dvb_usb_properties).
- */
-struct dvb_usb_device {
- struct dvb_usb_device_properties props;
- struct dvb_usb_device_description *desc;
-
- struct usb_device *udev;
-
-#define DVB_USB_STATE_INIT 0x000
-#define DVB_USB_STATE_I2C 0x001
-#define DVB_USB_STATE_DVB 0x002
-#define DVB_USB_STATE_REMOTE 0x004
- int state;
-
- int powered;
-
- /* locking */
- struct mutex usb_mutex;
-
- /* i2c */
- struct mutex i2c_mutex;
- struct i2c_adapter i2c_adap;
-
- int num_adapters_initialized;
- struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
-
- /* remote control */
- struct rc_dev *rc_dev;
- struct input_dev *input_dev;
- char rc_phys[64];
- struct delayed_work rc_query_work;
- u32 last_event;
- int last_state;
-
- struct module *owner;
-
- void *priv;
-};
-
-extern int dvb_usb_device_init(struct usb_interface *,
- struct dvb_usb_device_properties *,
- struct module *, struct dvb_usb_device **,
- short *adapter_nums);
-extern void dvb_usb_device_exit(struct usb_interface *);
-
-/* the generic read/write method for device control */
-extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
-extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
-
-/* commonly used remote control parsing */
-extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
-
-/* commonly used firmware download types and function */
-struct hexline {
- u8 len;
- u32 addr;
- u8 type;
- u8 data[255];
- u8 chk;
-};
-extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
-extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c
deleted file mode 100644
index b4989ba8897d..000000000000
--- a/drivers/media/dvb/dvb-usb/ec168.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * E3C EC168 DVB USB driver
- *
- * Copyright (C) 2009 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 "ec168.h"
-#include "ec100.h"
-#include "mxl5005s.h"
-
-/* debug */
-static int dvb_usb_ec168_debug;
-module_param_named(debug, dvb_usb_ec168_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static struct ec100_config ec168_ec100_config;
-
-static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
-{
- int ret;
- unsigned int pipe;
- u8 request, requesttype;
- u8 *buf;
-
-
-
- switch (req->cmd) {
- case DOWNLOAD_FIRMWARE:
- case GPIO:
- case WRITE_I2C:
- case STREAMING_CTRL:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
- request = req->cmd;
- break;
- case READ_I2C:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
- request = req->cmd;
- break;
- case GET_CONFIG:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
- request = CONFIG;
- break;
- case SET_CONFIG:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
- request = CONFIG;
- break;
- case WRITE_DEMOD:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
- request = DEMOD_RW;
- break;
- case READ_DEMOD:
- requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
- request = DEMOD_RW;
- break;
- default:
- err("unknown command:%02x", req->cmd);
- ret = -EPERM;
- goto error;
- }
-
- buf = kmalloc(req->size, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto error;
- }
-
- if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
- /* write */
- memcpy(buf, req->data, req->size);
- pipe = usb_sndctrlpipe(udev, 0);
- } else {
- /* read */
- pipe = usb_rcvctrlpipe(udev, 0);
- }
-
- msleep(1); /* avoid I2C errors */
-
- ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
- req->index, buf, req->size, EC168_USB_TIMEOUT);
-
- ec168_debug_dump(request, requesttype, req->value, req->index, buf,
- req->size, deb_xfer);
-
- if (ret < 0)
- goto err_dealloc;
- else
- ret = 0;
-
- /* 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);
- return ret;
-
-err_dealloc:
- kfree(buf);
-error:
- deb_info("%s: failed:%d\n", __func__, ret);
- return ret;
-}
-
-static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
-{
- return ec168_rw_udev(d->udev, req);
-}
-
-/* I2C */
-static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct ec168_req req;
- int i = 0;
- int ret;
-
- if (num > 2)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- while (i < num) {
- if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
- if (msg[i].addr == ec168_ec100_config.demod_address) {
- req.cmd = READ_DEMOD;
- req.value = 0;
- req.index = 0xff00 + msg[i].buf[0]; /* reg */
- req.size = msg[i+1].len; /* bytes to read */
- req.data = &msg[i+1].buf[0];
- ret = ec168_ctrl_msg(d, &req);
- i += 2;
- } else {
- err("I2C read not implemented");
- ret = -ENOSYS;
- i += 2;
- }
- } else {
- if (msg[i].addr == ec168_ec100_config.demod_address) {
- req.cmd = WRITE_DEMOD;
- req.value = msg[i].buf[1]; /* val */
- req.index = 0xff00 + msg[i].buf[0]; /* reg */
- req.size = 0;
- req.data = NULL;
- ret = ec168_ctrl_msg(d, &req);
- i += 1;
- } else {
- req.cmd = WRITE_I2C;
- req.value = msg[i].buf[0]; /* val */
- req.index = 0x0100 + msg[i].addr; /* I2C addr */
- req.size = msg[i].len-1;
- req.data = &msg[i].buf[1];
- ret = ec168_ctrl_msg(d, &req);
- i += 1;
- }
- }
- if (ret)
- goto error;
-
- }
- ret = i;
-
-error:
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-
-static u32 ec168_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm ec168_i2c_algo = {
- .master_xfer = ec168_i2c_xfer,
- .functionality = ec168_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct ec100_config ec168_ec100_config = {
- .demod_address = 0xff, /* not real address, demod is integrated */
-};
-
-static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
-{
- deb_info("%s:\n", __func__);
- adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
- return -ENODEV;
-
- return 0;
-}
-
-static struct mxl5005s_config ec168_mxl5003s_config = {
- .i2c_address = 0xc6,
- .if_freq = IF_FREQ_4570000HZ,
- .xtal_freq = CRYSTAL_FREQ_16000000HZ,
- .agc_mode = MXL_SINGLE_AGC,
- .tracking_filter = MXL_TF_OFF,
- .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 ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
- deb_info("%s:\n", __func__);
- return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
- &ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
-}
-
-static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
- deb_info("%s: onoff:%d\n", __func__, onoff);
- if (onoff)
- req.index = 0x0102;
- return ec168_ctrl_msg(adap->dev, &req);
-}
-
-static int ec168_download_firmware(struct usb_device *udev,
- const struct firmware *fw)
-{
- int i, len, packets, remainder, ret;
- u16 addr = 0x0000; /* firmware start address */
- struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
- deb_info("%s:\n", __func__);
-
- #define FW_PACKET_MAX_DATA 2048
- packets = fw->size / FW_PACKET_MAX_DATA;
- remainder = fw->size % FW_PACKET_MAX_DATA;
- len = FW_PACKET_MAX_DATA;
- for (i = 0; i <= packets; i++) {
- if (i == packets) /* set size of the last packet */
- len = remainder;
-
- req.size = len;
- req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
- req.index = addr;
- addr += FW_PACKET_MAX_DATA;
-
- ret = ec168_rw_udev(udev, &req);
- if (ret) {
- err("firmware download failed:%d packet:%d", ret, i);
- goto error;
- }
- }
- req.size = 0;
-
- /* set "warm"? */
- req.cmd = SET_CONFIG;
- req.value = 0;
- req.index = 0x0001;
- ret = ec168_rw_udev(udev, &req);
- if (ret)
- goto error;
-
- /* really needed - no idea what does */
- req.cmd = GPIO;
- req.value = 0;
- req.index = 0x0206;
- ret = ec168_rw_udev(udev, &req);
- if (ret)
- goto error;
-
- /* activate tuner I2C? */
- req.cmd = WRITE_I2C;
- req.value = 0;
- req.index = 0x00c6;
- ret = ec168_rw_udev(udev, &req);
- if (ret)
- goto error;
-
- return ret;
-error:
- deb_info("%s: failed:%d\n", __func__, ret);
- return ret;
-}
-
-static int ec168_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc, int *cold)
-{
- int ret;
- u8 reply;
- struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
- deb_info("%s:\n", __func__);
-
- ret = ec168_rw_udev(udev, &req);
- if (ret)
- goto error;
-
- deb_info("%s: reply:%02x\n", __func__, reply);
-
- if (reply == 0x01)
- *cold = 0;
- else
- *cold = 1;
-
- return ret;
-error:
- deb_info("%s: failed:%d\n", __func__, ret);
- return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ec168_properties;
-
-static int ec168_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int ret;
- deb_info("%s: interface:%d\n", __func__,
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL,
- adapter_nr);
- if (ret)
- goto error;
-
- return ret;
-error:
- deb_info("%s: failed:%d\n", __func__, ret);
- return ret;
-}
-
-#define E3C_EC168_1689 0
-#define E3C_EC168_FFFA 1
-#define E3C_EC168_FFFB 2
-#define E3C_EC168_1001 3
-#define E3C_EC168_1002 4
-
-static struct usb_device_id ec168_id[] = {
- [E3C_EC168_1689] =
- {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)},
- [E3C_EC168_FFFA] =
- {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)},
- [E3C_EC168_FFFB] =
- {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)},
- [E3C_EC168_1001] =
- {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)},
- [E3C_EC168_1002] =
- {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)},
- {} /* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ec168_id);
-
-static struct dvb_usb_device_properties ec168_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = ec168_download_firmware,
- .firmware = "dvb-usb-ec168.fw",
- .no_reconnect = 1,
-
- .size_of_priv = 0,
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .streaming_ctrl = ec168_streaming_ctrl,
- .frontend_attach = ec168_ec100_frontend_attach,
- .tuner_attach = ec168_mxl5003s_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x82,
- .u = {
- .bulk = {
- .buffersize = (32*512),
- }
- }
- },
- }},
- }
- },
-
- .identify_state = ec168_identify_state,
-
- .i2c_algo = &ec168_i2c_algo,
-
- .num_device_descs = 1,
- .devices = {
- {
- .name = "E3C EC168 DVB-T USB2.0 reference design",
- .cold_ids = {
- &ec168_id[E3C_EC168_1689],
- &ec168_id[E3C_EC168_FFFA],
- &ec168_id[E3C_EC168_FFFB],
- &ec168_id[E3C_EC168_1001],
- &ec168_id[E3C_EC168_1002],
- NULL},
- .warm_ids = {NULL},
- },
- }
-};
-
-static struct usb_driver ec168_driver = {
- .name = "dvb_usb_ec168",
- .probe = ec168_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = ec168_id,
-};
-
-module_usb_driver(ec168_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h
deleted file mode 100644
index e7e0b831314e..000000000000
--- a/drivers/media/dvb/dvb-usb/ec168.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * E3C EC168 DVB USB driver
- *
- * Copyright (C) 2009 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 EC168_H
-#define EC168_H
-
-#define DVB_USB_LOG_PREFIX "ec168"
-#include "dvb-usb.h"
-
-#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args)
-#define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args)
-#define deb_reg(args...) dprintk(dvb_usb_ec168_debug, 0x08, args)
-#define deb_i2c(args...) dprintk(dvb_usb_ec168_debug, 0x10, args)
-#define deb_fw(args...) dprintk(dvb_usb_ec168_debug, 0x20, args)
-
-#define ec168_debug_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");\
-}
-
-#define EC168_USB_TIMEOUT 1000
-
-struct ec168_req {
- u8 cmd; /* [1] */
- u16 value; /* [2|3] */
- u16 index; /* [4|5] */
- u16 size; /* [6|7] */
- u8 *data;
-};
-
-enum ec168_cmd {
- DOWNLOAD_FIRMWARE = 0x00,
- CONFIG = 0x01,
- DEMOD_RW = 0x03,
- GPIO = 0x04,
- STREAMING_CTRL = 0x10,
- READ_I2C = 0x20,
- WRITE_I2C = 0x21,
- HID_DOWNLOAD = 0x30,
- GET_CONFIG,
- SET_CONFIG,
- READ_DEMOD,
- WRITE_DEMOD,
-};
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
deleted file mode 100644
index c1f5582e1cdf..000000000000
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* DVB USB compliant linux driver for GL861 USB2.0 devices.
- *
- * 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.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-#include "gl861.h"
-
-#include "zl10353.h"
-#include "qt1010.h"
-
-/* debug */
-static int dvb_usb_gl861_debug;
-module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
- DVB_USB_DEBUG_STATUS);
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
- u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
- u16 index;
- u16 value = addr << (8 + 1);
- int wo = (rbuf == NULL || rlen == 0); /* write-only */
- u8 req, type;
-
- if (wo) {
- req = GL861_REQ_I2C_WRITE;
- type = GL861_WRITE;
- } else { /* rw */
- req = GL861_REQ_I2C_READ;
- type = GL861_READ;
- }
-
- switch (wlen) {
- case 1:
- index = wbuf[0];
- break;
- case 2:
- index = wbuf[0];
- value = value + wbuf[1];
- break;
- default:
- warn("wlen = %x, aborting.", wlen);
- return -EINVAL;
- }
-
- msleep(1); /* avoid I2C errors */
-
- return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
- value, index, rbuf, rlen, 2000);
-}
-
-/* I2C */
-static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int i;
-
- if (num > 2)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- for (i = 0; i < num; i++) {
- /* write/read request */
- if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
- if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
- msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
- break;
- i++;
- } else
- if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
- msg[i].len, NULL, 0) < 0)
- break;
- }
-
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-static u32 gl861_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm gl861_i2c_algo = {
- .master_xfer = gl861_i2c_xfer,
- .functionality = gl861_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static struct zl10353_config gl861_zl10353_config = {
- .demod_address = 0x0f,
- .no_tuner = 1,
- .parallel_ts = 1,
-};
-
-static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
-{
-
- adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
- return -EIO;
-
- return 0;
-}
-
-static struct qt1010_config gl861_qt1010_config = {
- .i2c_address = 0x62
-};
-
-static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
-{
- return dvb_attach(qt1010_attach,
- adap->fe_adap[0].fe, &adap->dev->i2c_adap,
- &gl861_qt1010_config) == NULL ? -ENODEV : 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties gl861_properties;
-
-static int gl861_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
- int ret;
-
- if (intf->num_altsetting < 2)
- return -ENODEV;
-
- ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d,
- adapter_nr);
- if (ret == 0) {
- alt = usb_altnum_to_altsetting(intf, 0);
-
- if (alt == NULL) {
- deb_rc("not alt found!\n");
- return -ENODEV;
- }
-
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- }
-
- return ret;
-}
-
-static struct usb_device_id gl861_table [] = {
- { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
- { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, gl861_table);
-
-static struct dvb_usb_device_properties gl861_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
- .usb_ctrl = DEVICE_SPECIFIC,
-
- .size_of_priv = 0,
-
- .num_adapters = 1,
- .adapter = {{
- .num_frontends = 1,
- .fe = {{
-
- .frontend_attach = gl861_frontend_attach,
- .tuner_attach = gl861_tuner_attach,
-
- .stream = {
- .type = USB_BULK,
- .count = 7,
- .endpoint = 0x81,
- .u = {
- .bulk = {
- .buffersize = 512,
- }
- }
- },
- }},
- } },
- .i2c_algo = &gl861_i2c_algo,
-
- .num_device_descs = 2,
- .devices = {
- {
- .name = "MSI Mega Sky 55801 DVB-T USB2.0",
- .cold_ids = { NULL },
- .warm_ids = { &gl861_table[0], NULL },
- },
- {
- .name = "A-LINK DTU DVB-T USB2.0",
- .cold_ids = { NULL },
- .warm_ids = { &gl861_table[1], NULL },
- },
- }
-};
-
-static struct usb_driver gl861_driver = {
- .name = "dvb_usb_gl861",
- .probe = gl861_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = gl861_table,
-};
-
-module_usb_driver(gl861_driver);
-
-MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
-MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
deleted file mode 100644
index c54855e2c233..000000000000
--- a/drivers/media/dvb/dvb-usb/gl861.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _DVB_USB_GL861_H_
-#define _DVB_USB_GL861_H_
-
-#define DVB_USB_LOG_PREFIX "gl861"
-#include "dvb-usb.h"
-
-#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args)
-
-#define GL861_WRITE 0x40
-#define GL861_READ 0xc0
-
-#define GL861_REQ_I2C_WRITE 0x01
-#define GL861_REQ_I2C_READ 0x02
-
-#endif
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
deleted file mode 100644
index 6244fe9d1a3a..000000000000
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/* DVB USB compliant linux driver for IT9137
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9137 (C) ITE Tech 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.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- * see Documentation/dvb/it9137.txt for firmware information
- *
- */
-#define DVB_USB_LOG_PREFIX "it913x"
-
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb-usb.h"
-#include "it913x-fe.h"
-
-/* debug */
-static int dvb_usb_it913x_debug;
-#define l_dprintk(var, level, args...) do { \
- if ((var >= level)) \
- printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
-} while (0)
-
-#define deb_info(level, args...) l_dprintk(dvb_usb_it913x_debug, level, args)
-#define debug_data_snipet(level, name, p) \
- deb_info(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));
-
-
-module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
- DVB_USB_DEBUG_STATUS);
-
-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 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, 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 != -EBUSY && ret != -ETIMEDOUT)
- break;
- }
-
- if (len != actual_l && ret == 0)
- ret = -EAGAIN;
-
- return ret;
-}
-
-static int it913x_bulk_read(struct usb_device *dev,
- u8 *rev, int len, u8 pipe)
-{
- 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 != -EBUSY && ret != -ETIMEDOUT)
- break;
- }
-
- if (len != actual_l && ret == 0)
- ret = -EAGAIN;
-
- return ret;
-}
-
-static u16 check_sum(u8 *p, u8 len)
-{
- u16 sum = 0;
- u8 i = 1;
- while (i < len)
- sum += (i++ & 1) ? (*p++) << 8 : *p++;
- return ~sum;
-}
-
-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;
- u8 *buff;
- u8 rlen;
- u16 chk_sum;
-
- buff = kzalloc(256, GFP_KERNEL);
- if (!buff) {
- info("USB Buffer Failed");
- return -ENOMEM;
- }
-
- buff[buf_size++] = pro;
- buff[buf_size++] = cmd;
- buff[buf_size++] = cmd_counter;
-
- switch (mode) {
- case READ_LONG:
- case WRITE_LONG:
- buff[buf_size++] = len;
- buff[buf_size++] = 2;
- buff[buf_size++] = (reg >> 24);
- buff[buf_size++] = (reg >> 16) & 0xff;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_SHORT:
- buff[buf_size++] = addr;
- break;
- case WRITE_SHORT:
- buff[buf_size++] = len;
- buff[buf_size++] = addr;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_DATA:
- case WRITE_DATA:
- break;
- case WRITE_CMD:
- mode = 7;
- break;
- default:
- kfree(buff);
- return -EINVAL;
- }
-
- if (mode & 1) {
- for (i = 0; i < len ; i++)
- buff[buf_size++] = data[i];
- }
- chk_sum = check_sum(&buff[1], buf_size);
-
- buff[buf_size++] = chk_sum >> 8;
- buff[0] = buf_size;
- 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) ?
- 5 : len + 5 , 0x01);
- if (ret < 0)
- goto error;
-
- rlen = (mode & 0x1) ? 0x1 : len;
-
- if (mode & 1)
- ret = buff[2];
- else
- memcpy(data, &buff[3], rlen);
-
- cmd_counter++;
-
-error: kfree(buff);
-
- 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)
-{
- int ret;
- u8 b[1];
- b[0] = data;
- ret = it913x_io(udev, WRITE_LONG, pro,
- CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
-
- return ret;
-}
-
-static int it913x_read_reg(struct usb_device *udev, u32 reg)
-{
- int ret;
- u8 data[1];
-
- ret = it913x_io(udev, READ_LONG, DEV_0,
- CMD_DEMOD_READ, reg, 0, &data[0], 1);
-
- return (ret < 0) ? ret : data[0];
-}
-
-static u32 it913x_query(struct usb_device *udev, u8 pro)
-{
- int ret, i;
- u8 data[4];
- 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);
- }
-
- 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,
- it913x_config.chip_type);
-
- ret |= it913x_io(udev, READ_SHORT, pro,
- CMD_QUERYINFO, 0, 0x1, &data[0], 4);
-
- it913x_config.firmware = (data[0] << 24) + (data[1] << 16) +
- (data[2] << 8) + data[3];
-
- return (ret < 0) ? 0 : it913x_config.firmware;
-}
-
-static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- 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;
-
- mutex_lock(&adap->dev->i2c_mutex);
-
- deb_info(1, "PID_C (%02x)", onoff);
-
- ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff);
-
- mutex_unlock(&adap->dev->i2c_mutex);
- return ret;
-}
-
-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;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- mutex_lock(&adap->dev->i2c_mutex);
-
- deb_info(1, "PID_F (%02x)", onoff);
-
- 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_INX_EN, (u8)onoff);
-
- 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;
-}
-
-
-static int it913x_return_status(struct usb_device *udev)
-{
- u32 firm = 0;
-
- firm = it913x_query(udev, DEV_0);
- if (firm > 0)
- info("Firmware Version %d", firm);
-
- return (firm > 0) ? firm : 0;
-}
-
-static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- static u8 data[256];
- int ret;
- u32 reg;
- u8 pro;
-
- 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);
-
- pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0;
- pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
- memcpy(data, msg[0].buf, msg[0].len);
- reg = (data[0] << 24) + (data[1] << 16) +
- (data[2] << 8) + data[3];
- if (num == 2) {
- ret = it913x_io(d->udev, READ_LONG, pro,
- CMD_DEMOD_READ, reg, 0, data, msg[1].len);
- memcpy(msg[1].buf, data, msg[1].len);
- } else
- ret = it913x_io(d->udev, WRITE_LONG, pro, CMD_DEMOD_WRITE,
- reg, 0, &data[4], msg[0].len - 4);
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static u32 it913x_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm it913x_i2c_algo = {
- .master_xfer = it913x_i2c_xfer,
- .functionality = it913x_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-#define IT913X_POLL 250
-static int it913x_rc_query(struct dvb_usb_device *d)
-{
- u8 ibuf[4];
- int ret;
- u32 key;
- /* Avoid conflict with frontends*/
- 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] << 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;
-
- firm_no = it913x_return_status(udev);
-
- /* Read and select config */
- ret = it913x_select_config(udev, props);
- if (ret < 0)
- return ret;
-
- if (firm_no > 0) {
- *cold = 0;
- return 0;
- }
-
- if (it913x_config.dual_mode) {
- it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0);
- ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1);
- ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1);
- ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
- msleep(50);
- ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0);
- msleep(50);
- reg = it913x_read_reg(udev, GPIOH1_O);
- if (reg == 0) {
- ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
- ret |= it913x_return_status(udev);
- if (ret != 0)
- ret = it913x_wr_reg(udev, DEV_0,
- GPIOH1_O, 0x0);
- }
- }
-
- 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);
- 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);
- 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;
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-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;
-
- deb_info(1, "STM (%02x)", 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;
-
- }
-
- return ret;
-}
-
-static int it913x_download_firmware(struct usb_device *udev,
- const struct firmware *fw)
-{
- int ret = 0, i = 0, pos = 0;
- u8 packet_size, min_pkt;
- u8 *fw_data;
-
- ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100);
-
- info("FRM Starting Firmware Download");
-
- /* Multi firmware loader */
- /* This uses scatter write firmware headers */
- /* The firmware must start with 03 XX 00 */
- /* and be the extact firmware length */
-
- 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 (%d)" , ret);
- else
- info("FRM Firmware Download Completed - Resetting Device");
-
- 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);
-
- msleep(30);
-
- /* Tuner function */
- if (it913x_config.dual_mode)
- ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
- 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;
-}
-
-static int it913x_name(struct dvb_usb_adapter *adap)
-{
- const char *desc = adap->dev->desc->name;
- char *fe_name[] = {"_1", "_2", "_3", "_4"};
- char *name = adap->fe_adap[0].fe->ops.info.name;
-
- strlcpy(name, desc, 128);
- strlcat(name, fe_name[adap->id], 128);
-
- return 0;
-}
-
-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 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
- 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)
- 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, &st->it913x_config);
-
- if (adap->id == 0 && adap->fe_adap[0].fe) {
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
- ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f);
- ret = it913x_wr_reg(udev, DEV_0, EP0_TX_NAK, 0x1b);
- ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x2f);
- 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, 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, 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);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, TSIS_ENABLE, 0x1);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x0);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
- ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
- ret = it913x_wr_reg(udev, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
- ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
- } else
- return -ENODEV;
-
- ret = it913x_name(adap);
-
- return ret;
-}
-
-/* DVB USB Driver */
-static struct dvb_usb_device_properties it913x_properties;
-
-static int it913x_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- cmd_counter = 0;
- if (0 == dvb_usb_device_init(intf, &it913x_properties,
- THIS_MODULE, NULL, adapter_nr)) {
- info("DEV registering device driver");
- return 0;
- }
-
- info("DEV it913x Error");
- return -ENODEV;
-
-}
-
-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 */
-};
-
-MODULE_DEVICE_TABLE(usb, it913x_table);
-
-static struct dvb_usb_device_properties it913x_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
- .usb_ctrl = DEVICE_SPECIFIC,
- .download_firmware = it913x_download_firmware,
- .firmware = "dvb-usb-it9137-01.fw",
- .no_reconnect = 1,
- .size_of_priv = sizeof(struct it913x_state),
- .num_adapters = 2,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_NEED_PID_FILTERING|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .streaming_ctrl = it913x_streaming_ctrl,
- .pid_filter_count = 31,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .frontend_attach = it913x_frontend_attach,
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 10,
- .endpoint = 0x04,
- .u = {/* Keep Low if PID filter on */
- .bulk = {
- .buffersize =
- TS_BUFFER_SIZE_PID,
- }
- }
- }
- }},
- },
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_NEED_PID_FILTERING|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .streaming_ctrl = it913x_streaming_ctrl,
- .pid_filter_count = 31,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .frontend_attach = it913x_frontend_attach,
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 5,
- .endpoint = 0x05,
- .u = {
- .bulk = {
- .buffersize =
- TS_BUFFER_SIZE_PID,
- }
- }
- }
- }},
- }
- },
- .identify_state = it913x_identify_state,
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "it913x",
- .rc_query = it913x_rc_query,
- .rc_interval = IT913X_POLL,
- .allowed_protos = RC_TYPE_NEC,
- .rc_codes = RC_MAP_IT913X_V1,
- },
- .i2c_algo = &it913x_i2c_algo,
- .num_device_descs = 5,
- .devices = {
- { "Kworld UB499-2T T09(IT9137)",
- { &it913x_table[0], NULL },
- },
- { "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 },
- },
- }
-};
-
-static struct usb_driver it913x_driver = {
- .name = "it913x",
- .probe = it913x_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = it913x_table,
-};
-
-module_usb_driver(it913x_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("it913x USB 2 Driver");
-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
deleted file mode 100644
index 25d1031460f8..000000000000
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ /dev/null
@@ -1,1407 +0,0 @@
-/* DVB USB compliant linux driver for
- *
- * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
- * LME2510C + LG TDQY-P001F
- * LME2510C + BS2F7HZ0194
- * LME2510 + LG TDQY-P001F
- * LME2510 + BS2F7HZ0194
- *
- * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
- * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
- *
- * MV001F (LME2510+LGTDQY-P001F)
- * LG TDQY - P001F =(TDA8263 + TDA10086H)
- *
- * MVB0001F (LME2510C+LGTDQT-P001F)
- *
- * MV0194 (LME2510+SHARP:BS2F7HZ0194)
- * SHARP:BS2F7HZ0194 = (STV0299+IX2410)
- *
- * MVB0194 (LME2510C+SHARP0194)
- *
- * For firmware see Documentation/dvb/lmedm04.txt
- *
- * I2C addresses:
- * 0xd0 - STV0288 - Demodulator
- * 0xc0 - Sharp IX2505V - Tuner
- * --
- * 0x1c - TDA10086 - Demodulator
- * 0xc0 - TDA8263 - Tuner
- * --
- * 0xd0 - STV0299 - Demodulator
- * 0xc0 - IX2410 - Tuner
- *
- *
- * VID = 3344 PID LME2510=1122 LME2510C=1120
- *
- * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
- * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
- *
- * 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.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- *
- * Known Issues :
- * LME2510: Non Intel USB chipsets fail to maintain High Speed on
- * Boot or Hot Plug.
- *
- * QQbox suffers from noise on LNB voltage.
- *
- * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
- * with other tuners. After a cold reset streaming will not start.
- *
- */
-#define DVB_USB_LOG_PREFIX "LME2510(C)"
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb-usb.h"
-#include "lmedm04.h"
-#include "tda826x.h"
-#include "tda10086.h"
-#include "stv0288.h"
-#include "ix2505v.h"
-#include "stv0299.h"
-#include "dvb-pll.h"
-#include "z0194a.h"
-#include "m88rs2000.h"
-
-
-
-/* debug */
-static int dvb_usb_lme2510_debug;
-#define l_dprintk(var, level, args...) do { \
- if ((var >= level)) \
- printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
-} while (0)
-
-#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
-#define debug_data_snipet(level, name, p) \
- deb_info(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));
-
-
-module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
- DVB_USB_DEBUG_STATUS);
-
-static int dvb_usb_lme2510_firmware;
-module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
-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=default 1=off 2=on");
-
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define TUNER_DEFAULT 0x0
-#define TUNER_LG 0x1
-#define TUNER_S7395 0x2
-#define TUNER_S0194 0x3
-#define TUNER_RS2000 0x4
-
-struct lme2510_state {
- u8 id;
- u8 tuner_config;
- u8 signal_lock;
- 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;
- u8 i2c_tuner_gate_r;
- u8 i2c_tuner_addr;
- u8 stream_on;
- u8 pid_size;
- u8 pid_off;
- void *buffer;
- struct urb *lme_urb;
- void *usb_buffer;
-
-};
-
-static int lme2510_bulk_write(struct usb_device *dev,
- u8 *snd, int len, u8 pipe)
-{
- int ret, actual_l;
-
- ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
- snd, len , &actual_l, 100);
- return ret;
-}
-
-static int lme2510_bulk_read(struct usb_device *dev,
- u8 *rev, int len, u8 pipe)
-{
- int ret, actual_l;
-
- ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
- rev, len , &actual_l, 200);
- return ret;
-}
-
-static int lme2510_usb_talk(struct dvb_usb_device *d,
- u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
- struct lme2510_state *st = d->priv;
- u8 *buff;
- int ret = 0;
-
- if (st->usb_buffer == NULL) {
- st->usb_buffer = kmalloc(64, GFP_KERNEL);
- if (st->usb_buffer == NULL) {
- info("MEM Error no memory");
- return -ENOMEM;
- }
- }
- buff = st->usb_buffer;
-
- ret = mutex_lock_interruptible(&d->usb_mutex);
-
- if (ret < 0)
- return -EAGAIN;
-
- /* the read/write capped at 64 */
- memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
-
- ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
-
- ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
- rlen : 64 , 0x01);
-
- if (rlen > 0)
- memcpy(rbuf, buff, rlen);
-
- mutex_unlock(&d->usb_mutex);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int lme2510_stream_restart(struct dvb_usb_device *d)
-{
- struct lme2510_state *st = d->priv;
- u8 all_pids[] = LME_ALL_PIDS;
- u8 stream_on[] = LME_ST_ON_W;
- int ret;
- 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));
- return ret;
-}
-
-static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
-{
- struct lme2510_state *st = d->priv;
- static u8 pid_buff[] = LME_ZERO_PID;
- static u8 rbuf[1];
- u8 pid_no = index * 2;
- u8 pid_len = pid_no + 2;
- int ret = 0;
- deb_info(1, "PID Setting Pid %04x", pid_out);
-
- if (st->pid_size == 0)
- ret |= lme2510_stream_restart(d);
-
- pid_buff[2] = pid_no;
- pid_buff[3] = (u8)pid_out & 0xff;
- pid_buff[4] = pid_no + 1;
- pid_buff[5] = (u8)(pid_out >> 8);
-
- if (pid_len > st->pid_size)
- st->pid_size = pid_len;
- pid_buff[7] = 0x80 + st->pid_size;
-
- ret |= lme2510_usb_talk(d, pid_buff ,
- sizeof(pid_buff) , rbuf, sizeof(rbuf));
-
- if (st->stream_on)
- ret |= lme2510_stream_restart(d);
-
- return ret;
-}
-
-static void lme2510_int_response(struct urb *lme_urb)
-{
- struct dvb_usb_adapter *adap = lme_urb->context;
- struct lme2510_state *st = adap->dev->priv;
- static u8 *ibuf, *rbuf;
- int i = 0, offset;
- u32 key;
-
- switch (lme_urb->status) {
- case 0:
- case -ETIMEDOUT:
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- return;
- default:
- info("Error %x", lme_urb->status);
- break;
- }
-
- rbuf = (u8 *) lme_urb->transfer_buffer;
-
- offset = ((lme_urb->actual_length/8) > 4)
- ? 4 : (lme_urb->actual_length/8) ;
-
- for (i = 0; i < offset; ++i) {
- ibuf = (u8 *)&rbuf[i*8];
- deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
- offset, i, ibuf[0], ibuf[1]);
-
- switch (ibuf[0]) {
- case 0xaa:
- debug_data_snipet(1, "INT Remote data snipet", ibuf);
- if ((ibuf[4] + ibuf[5]) == 0xff) {
- key = ibuf[5];
- key += (ibuf[3] > 0)
- ? (ibuf[3] ^ 0xff) << 8 : 0;
- key += (ibuf[2] ^ 0xff) << 16;
- deb_info(1, "INT Key =%08x", key);
- if (adap->dev->rc_dev != NULL)
- rc_keydown(adap->dev->rc_dev, key, 0);
- }
- break;
- case 0xbb:
- switch (st->tuner_config) {
- case TUNER_LG:
- if (ibuf[2] > 0)
- st->signal_lock = ibuf[2];
- st->signal_level = ibuf[4];
- st->signal_sn = ibuf[3];
- st->time_key = ibuf[7];
- break;
- case TUNER_S7395:
- case TUNER_S0194:
- /* Tweak for earlier firmware*/
- if (ibuf[1] == 0x03) {
- if (ibuf[2] > 1)
- st->signal_lock = ibuf[2];
- st->signal_level = ibuf[3];
- st->signal_sn = ibuf[4];
- } else {
- st->signal_level = ibuf[4];
- st->signal_sn = ibuf[5];
- st->signal_lock =
- (st->signal_lock & 0xf7) +
- ((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;
- }
- debug_data_snipet(5, "INT Remote data snipet in", ibuf);
- break;
- case 0xcc:
- debug_data_snipet(1, "INT Control data snipet", ibuf);
- break;
- default:
- debug_data_snipet(1, "INT Unknown data snipet", ibuf);
- break;
- }
- }
- usb_submit_urb(lme_urb, GFP_ATOMIC);
-}
-
-static int lme2510_int_read(struct dvb_usb_adapter *adap)
-{
- struct lme2510_state *lme_int = adap->dev->priv;
-
- lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
-
- if (lme_int->lme_urb == NULL)
- return -ENOMEM;
-
- lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC,
- &lme_int->lme_urb->transfer_dma);
-
- if (lme_int->buffer == NULL)
- return -ENOMEM;
-
- usb_fill_int_urb(lme_int->lme_urb,
- adap->dev->udev,
- usb_rcvintpipe(adap->dev->udev, 0xa),
- lme_int->buffer,
- 128,
- lme2510_int_response,
- adap,
- 8);
-
- lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
- info("INT Interrupt Service Started");
-
- return 0;
-}
-
-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_ALL_PIDS;
- static u8 rbuf[1];
- int ret = 0;
-
- deb_info(1, "PID Clearing Filter");
-
- mutex_lock(&adap->dev->i2c_mutex);
-
- 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;
-
- mutex_unlock(&adap->dev->i2c_mutex);
-
- return 0;
-}
-
-static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
- int onoff)
-{
- int ret = 0;
-
- deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
- pid, index, onoff);
-
- if (onoff) {
- mutex_lock(&adap->dev->i2c_mutex);
- ret |= lme2510_enable_pid(adap->dev, index, pid);
- mutex_unlock(&adap->dev->i2c_mutex);
- }
-
-
- return ret;
-}
-
-
-static int lme2510_return_status(struct usb_device *dev)
-{
- int ret = 0;
- u8 *data;
-
- data = kzalloc(10, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
- info("Firmware Status: %x (%x)", ret , data[2]);
-
- ret = (ret < 0) ? -ENODEV : data[2];
- kfree(data);
- return ret;
-}
-
-static int lme2510_msg(struct dvb_usb_device *d,
- u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
- int ret = 0;
- struct lme2510_state *st = d->priv;
-
- if (st->i2c_talk_onoff == 1) {
-
- ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-
- switch (st->tuner_config) {
- case TUNER_LG:
- if (wbuf[2] == 0x1c) {
- if (wbuf[3] == 0x0e) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x10)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- msleep(80);
- }
- }
- break;
- case TUNER_S7395:
- if (wbuf[2] == 0xd0) {
- if (wbuf[3] == 0x24) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x8)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- }
- }
- break;
- case TUNER_S0194:
- if (wbuf[2] == 0xd0) {
- if (wbuf[3] == 0x1b) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x8)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- }
- }
- break;
- case TUNER_RS2000:
- default:
- break;
- }
- } else {
- /* TODO rewrite this section */
- switch (st->tuner_config) {
- case TUNER_LG:
- switch (wbuf[3]) {
- case 0x0e:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x43:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_level;
- break;
- case 0x1c:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x15:
- case 0x16:
- case 0x17:
- case 0x18:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- break;
- case TUNER_S7395:
- switch (wbuf[3]) {
- case 0x10:
- rbuf[0] = 0x55;
- rbuf[1] = (st->signal_level & 0x80)
- ? 0 : (st->signal_level * 2);
- break;
- case 0x2d:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x24:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x2e:
- case 0x26:
- case 0x27:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- break;
- case TUNER_S0194:
- switch (wbuf[3]) {
- case 0x18:
- rbuf[0] = 0x55;
- rbuf[1] = (st->signal_level & 0x80)
- ? 0 : (st->signal_level * 2);
- break;
- case 0x24:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x1b:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x19:
- case 0x25:
- case 0x1e:
- case 0x1d:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- 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;
- }
-
- deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)",
- wbuf[3], rbuf[1]);
-
- }
-
- return ret;
-}
-
-
-static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct lme2510_state *st = d->priv;
- static u8 obuf[64], ibuf[64];
- int i, read, read_o;
- u16 len;
- u8 gate = st->i2c_gate;
-
- mutex_lock(&d->i2c_mutex);
-
- if (gate == 0)
- gate = 5;
-
- if (num > 2)
- warn("more than 2 i2c messages"
- "at a time is not handled yet. TODO.");
-
- for (i = 0; i < num; i++) {
- read_o = 1 & (msg[i].flags & I2C_M_RD);
- read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
- read |= read_o;
- gate = (msg[i].addr == st->i2c_tuner_addr)
- ? (read) ? st->i2c_tuner_gate_r
- : st->i2c_tuner_gate_w
- : st->i2c_gate;
- obuf[0] = gate | (read << 7);
-
- if (gate == 5)
- obuf[1] = (read) ? 2 : msg[i].len + 1;
- else
- obuf[1] = msg[i].len + read + 1;
-
- obuf[2] = msg[i].addr;
- if (read) {
- if (read_o)
- len = 3;
- else {
- memcpy(&obuf[3], msg[i].buf, msg[i].len);
- obuf[msg[i].len+3] = msg[i+1].len;
- len = msg[i].len+4;
- }
- } else {
- memcpy(&obuf[3], msg[i].buf, msg[i].len);
- len = msg[i].len+3;
- }
-
- if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
- deb_info(1, "i2c transfer failed.");
- mutex_unlock(&d->i2c_mutex);
- return -EAGAIN;
- }
-
- if (read) {
- if (read_o)
- memcpy(msg[i].buf, &ibuf[1], msg[i].len);
- else {
- memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
- i++;
- }
- }
- }
-
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm lme2510_i2c_algo = {
- .master_xfer = lme2510_i2c_xfer,
- .functionality = lme2510_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-static int lme2510_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- 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;
-}
-
-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_ALL_PIDS;
- static u8 rbuf[1];
- int ret = 0, rlen = sizeof(rbuf);
-
- deb_info(1, "STM (%02x)", onoff);
-
- /* Streaming is started by FE_HAS_LOCK */
- if (onoff == 1)
- st->stream_on = 1;
- else {
- deb_info(1, "STM Steam Off");
- /* mutex is here only to avoid collision with I2C */
- mutex_lock(&adap->dev->i2c_mutex);
-
- ret = lme2510_usb_talk(adap->dev, clear_reg_3,
- sizeof(clear_reg_3), rbuf, rlen);
- st->stream_on = 0;
- st->i2c_talk_onoff = 1;
-
- mutex_unlock(&adap->dev->i2c_mutex);
- }
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static u8 check_sum(u8 *p, u8 len)
-{
- u8 sum = 0;
- while (len--)
- sum += *p++;
- return sum;
-}
-
-static int lme2510_download_firmware(struct usb_device *dev,
- const struct firmware *fw)
-{
- int ret = 0;
- u8 *data;
- u16 j, wlen, len_in, start, end;
- u8 packet_size, dlen, i;
- u8 *fw_data;
-
- packet_size = 0x31;
- len_in = 1;
-
- data = kzalloc(512, GFP_KERNEL);
- if (!data) {
- info("FRM Could not start Firmware Download (Buffer allocation failed)");
- return -ENOMEM;
- }
-
- info("FRM Starting Firmware Download");
-
- for (i = 1; i < 3; i++) {
- start = (i == 1) ? 0 : 512;
- end = (i == 1) ? 512 : fw->size;
- for (j = start; j < end; j += (packet_size+1)) {
- fw_data = (u8 *)(fw->data + j);
- if ((end - j) > packet_size) {
- data[0] = i;
- dlen = packet_size;
- } else {
- data[0] = i | 0x80;
- dlen = (u8)(end - j)-1;
- }
- data[1] = dlen;
- memcpy(&data[2], fw_data, dlen+1);
- wlen = (u8) dlen + 4;
- data[wlen-1] = check_sum(fw_data, dlen+1);
- deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
- data[dlen+2], data[dlen+3]);
- ret |= lme2510_bulk_write(dev, data, wlen, 1);
- ret |= lme2510_bulk_read(dev, data, len_in , 1);
- ret |= (data[0] == 0x88) ? 0 : -1;
- }
- }
-
- usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
-
-
- data[0] = 0x8a;
- len_in = 1;
- msleep(2000);
- ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
- ret |= lme2510_bulk_read(dev, data, len_in, 1);
- msleep(400);
-
- if (ret < 0)
- info("FRM Firmware Download Failed (%04x)" , ret);
- else
- info("FRM Firmware Download Completed - Resetting Device");
-
- kfree(data);
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static void lme_coldreset(struct usb_device *dev)
-{
- int ret = 0, len_in;
- u8 data[512] = {0};
-
- data[0] = 0x0a;
- len_in = 1;
- info("FRM Firmware Cold Reset");
- ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
- ret |= lme2510_bulk_read(dev, data, len_in, 1);
-
- return;
-}
-
-static int lme_firmware_switch(struct usb_device *udev, int cold)
-{
- const struct firmware *fw = NULL;
- 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 = 0, cold_fw;
-
- cold = (cold > 0) ? (cold & 1) : 0;
-
- cold_fw = !cold;
-
- switch (le16_to_cpu(udev->descriptor.idProduct)) {
- case 0x1122:
- switch (dvb_usb_lme2510_firmware) {
- default:
- dvb_usb_lme2510_firmware = TUNER_S0194;
- case TUNER_S0194:
- fw_lme = fw_s0194;
- ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0) {
- cold = 0;
- break;
- }
- dvb_usb_lme2510_firmware = TUNER_LG;
- case TUNER_LG:
- fw_lme = fw_lg;
- ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
- break;
- info("FRM No Firmware Found - please install");
- dvb_usb_lme2510_firmware = TUNER_DEFAULT;
- cold = 0;
- cold_fw = 0;
- break;
- }
- break;
- case 0x1120:
- switch (dvb_usb_lme2510_firmware) {
- default:
- dvb_usb_lme2510_firmware = TUNER_S7395;
- case TUNER_S7395:
- fw_lme = fw_c_s7395;
- ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0) {
- cold = 0;
- break;
- }
- dvb_usb_lme2510_firmware = TUNER_LG;
- case TUNER_LG:
- fw_lme = fw_c_lg;
- ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
- break;
- dvb_usb_lme2510_firmware = TUNER_S0194;
- case TUNER_S0194:
- fw_lme = fw_c_s0194;
- ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
- break;
- info("FRM No Firmware Found - please install");
- dvb_usb_lme2510_firmware = TUNER_DEFAULT;
- cold = 0;
- 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);
- }
-
- release_firmware(fw);
-
- if (cold) {
- info("FRM Changing to %s firmware", fw_lme);
- lme_coldreset(udev);
- return -ENODEV;
- }
-
- return ret;
-}
-
-static int lme2510_kill_urb(struct usb_data_stream *stream)
-{
- int i;
-
- for (i = 0; i < stream->urbs_submitted; i++) {
- deb_info(3, "killing URB no. %d.", i);
- /* stop the URB */
- usb_kill_urb(stream->urb_list[i]);
- }
- stream->urbs_submitted = 0;
-
- return 0;
-}
-
-static struct tda10086_config tda10086_config = {
- .demod_address = 0x1c,
- .invert = 0,
- .diseqc_tone = 1,
- .xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct stv0288_config lme_config = {
- .demod_address = 0xd0,
- .min_delay_ms = 15,
- .inittab = s7395_inittab,
-};
-
-static struct ix2505v_config lme_tuner = {
- .tuner_address = 0xc0,
- .min_delay_ms = 100,
- .tuner_gain = 0x0,
- .tuner_chargepump = 0x3,
-};
-
-static struct stv0299_config sharp_z0194_config = {
- .demod_address = 0xd0,
- .inittab = sharp_z0194a_inittab,
- .mclk = 88000000UL,
- .invert = 0,
- .skip_reinit = 0,
- .lock_output = STV0299_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .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)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- static u8 voltage_low[] = LME_VOLTAGE_L;
- static u8 voltage_high[] = LME_VOLTAGE_H;
- static u8 rbuf[1];
- int ret = 0, len = 3, rlen = 1;
-
- mutex_lock(&adap->dev->i2c_mutex);
-
- switch (voltage) {
- case SEC_VOLTAGE_18:
- ret |= lme2510_usb_talk(adap->dev,
- voltage_high, len, rbuf, rlen);
- break;
-
- case SEC_VOLTAGE_OFF:
- case SEC_VOLTAGE_13:
- default:
- ret |= lme2510_usb_talk(adap->dev,
- voltage_low, len, rbuf, rlen);
- break;
- }
-
- mutex_unlock(&adap->dev->i2c_mutex);
-
- 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", " RS2000"};
- char *name = adap->fe_adap[0].fe->ops.info.name;
-
- strlcpy(name, desc, 128);
- strlcat(name, fe_name[st->tuner_config], 128);
-
- return 0;
-}
-
-static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct lme2510_state *st = adap->dev->priv;
-
- 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(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;
- }
-
- 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);
- }
- break;
- }
- case 0x22f0:
- st->i2c_gate = 5;
- adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
- &m88rs2000_config, &adap->dev->i2c_adap);
-
- 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;
- }
- break;
- }
-
- if (adap->fe_adap[0].fe == NULL) {
- info("DM04/QQBOX Not Powered up or not Supported");
- return -ENODEV;
- }
-
- if (ret) {
- if (adap->fe_adap[0].fe) {
- dvb_frontend_detach(adap->fe_adap[0].fe);
- adap->fe_adap[0].fe = NULL;
- }
- adap->dev->props.rc.core.rc_codes = NULL;
- return -ENODEV;
- }
-
- adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage;
- ret = lme_name(adap);
- return 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", "RS2000"};
- int ret = 0;
-
- switch (st->tuner_config) {
- case TUNER_LG:
- if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0,
- &adap->dev->i2c_adap, 1))
- ret = st->tuner_config;
- break;
- case TUNER_S7395:
- if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner,
- &adap->dev->i2c_adap))
- ret = st->tuner_config;
- break;
- case TUNER_S0194:
- if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0,
- &adap->dev->i2c_adap, DVB_PLL_OPERA1))
- ret = st->tuner_config;
- break;
- case TUNER_RS2000:
- ret = st->tuner_config;
- break;
- default:
- break;
- }
-
- if (ret)
- info("TUN Found %s tuner", tun_msg[ret]);
- else {
- info("TUN No tuner found --- resetting device");
- lme_coldreset(adap->dev->udev);
- return -ENODEV;
- }
-
- /* Start the Interrupt*/
- ret = lme2510_int_read(adap);
- if (ret < 0) {
- info("INT Unable to start Interrupt Service");
- return -ENODEV;
- }
-
- return ret;
-}
-
-static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
-{
- struct lme2510_state *st = d->priv;
- static u8 lnb_on[] = LNB_ON;
- static u8 lnb_off[] = LNB_OFF;
- static u8 rbuf[1];
- int ret = 0, len = 3, rlen = 1;
-
- mutex_lock(&d->i2c_mutex);
-
- if (onoff)
- ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
- else
- ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
-
- st->i2c_talk_onoff = 1;
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties lme2510_properties;
-static struct dvb_usb_device_properties lme2510c_properties;
-
-static int lme2510_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
-
- usb_reset_configuration(udev);
-
- usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
-
- if (udev->speed != USB_SPEED_HIGH) {
- usb_reset_device(udev);
- info("DEV Failed to connect in HIGH SPEED mode");
- return -ENODEV;
- }
-
- if (lme2510_return_status(udev) == 0x44) {
- lme_firmware_switch(udev, 0);
- return -ENODEV;
- }
-
- if (0 == dvb_usb_device_init(intf, &lme2510_properties,
- THIS_MODULE, NULL, adapter_nr)) {
- info("DEV registering device driver");
- return 0;
- }
- if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
- THIS_MODULE, NULL, adapter_nr)) {
- info("DEV registering device driver");
- return 0;
- }
-
- info("DEV lme2510 Error");
- return -ENODEV;
-
-}
-
-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 */
-};
-
-MODULE_DEVICE_TABLE(usb, lme2510_table);
-
-static struct dvb_usb_device_properties lme2510_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
- .size_of_priv = sizeof(struct lme2510_state),
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_NEED_PID_FILTERING|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .streaming_ctrl = lme2510_streaming_ctrl,
- .pid_filter_count = 32,
- .pid_filter = lme2510_pid_filter,
- .pid_filter_ctrl = lme2510_pid_filter_ctrl,
- .frontend_attach = dm04_lme2510_frontend_attach,
- .tuner_attach = dm04_lme2510_tuner,
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 10,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
-
- }
- }
- }
- }},
- }
- },
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "LME2510 Remote Control",
- .allowed_protos = RC_TYPE_NEC,
- .rc_codes = RC_MAP_LME2510,
- },
- .power_ctrl = lme2510_powerup,
- .identify_state = lme2510_identify_state,
- .i2c_algo = &lme2510_i2c_algo,
- .generic_bulk_ctrl_endpoint = 0,
- .num_device_descs = 1,
- .devices = {
- { "DM04_LME2510_DVB-S",
- { &lme2510_table[0], NULL },
- },
-
- }
-};
-
-static struct dvb_usb_device_properties lme2510c_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
- .size_of_priv = sizeof(struct lme2510_state),
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_NEED_PID_FILTERING|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .streaming_ctrl = lme2510_streaming_ctrl,
- .pid_filter_count = 32,
- .pid_filter = lme2510_pid_filter,
- .pid_filter_ctrl = lme2510_pid_filter_ctrl,
- .frontend_attach = dm04_lme2510_frontend_attach,
- .tuner_attach = dm04_lme2510_tuner,
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 10,
- .endpoint = 0x8,
- .u = {
- .bulk = {
- .buffersize = 4096,
-
- }
- }
- }
- }},
- }
- },
- .rc.core = {
- .protocol = RC_TYPE_NEC,
- .module_name = "LME2510 Remote Control",
- .allowed_protos = RC_TYPE_NEC,
- .rc_codes = RC_MAP_LME2510,
- },
- .power_ctrl = lme2510_powerup,
- .identify_state = lme2510_identify_state,
- .i2c_algo = &lme2510_i2c_algo,
- .generic_bulk_ctrl_endpoint = 0,
- .num_device_descs = 2,
- .devices = {
- { "DM04_LME2510C_DVB-S",
- { &lme2510_table[1], NULL },
- },
- { "DM04_LME2510C_DVB-S RS2000",
- { &lme2510_table[2], NULL },
- },
- }
-};
-
-static void *lme2510_exit_int(struct dvb_usb_device *d)
-{
- struct lme2510_state *st = d->priv;
- struct dvb_usb_adapter *adap = &d->adapter[0];
- void *buffer = NULL;
-
- if (adap != NULL) {
- lme2510_kill_urb(&adap->fe_adap[0].stream);
- adap->feedcount = 0;
- }
-
- if (st->usb_buffer != NULL) {
- st->i2c_talk_onoff = 1;
- st->signal_lock = 0;
- st->signal_level = 0;
- st->signal_sn = 0;
- buffer = st->usb_buffer;
- }
-
- if (st->lme_urb != NULL) {
- usb_kill_urb(st->lme_urb);
- usb_free_coherent(d->udev, 128, st->buffer,
- st->lme_urb->transfer_dma);
- info("Interrupt Service Stopped");
- }
-
- return buffer;
-}
-
-static void lme2510_exit(struct usb_interface *intf)
-{
- struct dvb_usb_device *d = usb_get_intfdata(intf);
- void *usb_buffer;
-
- if (d != NULL) {
- usb_buffer = lme2510_exit_int(d);
- dvb_usb_device_exit(intf);
- if (usb_buffer != NULL)
- kfree(usb_buffer);
- }
-}
-
-static struct usb_driver lme2510_driver = {
- .name = "LME2510C_DVB-S",
- .probe = lme2510_probe,
- .disconnect = lme2510_exit,
- .id_table = lme2510_table,
-};
-
-module_usb_driver(lme2510_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.99");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
deleted file mode 100644
index 74da5bb1ce99..000000000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
- *
- * Copyright (C) 2010 Michael Krufky <mkrufky@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 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 "mxl111sf-tuner.h"
-#include "mxl111sf-phy.h"
-#include "mxl111sf-reg.h"
-
-/* debug */
-static int mxl111sf_tuner_debug;
-module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define mxl_dbg(fmt, arg...) \
- if (mxl111sf_tuner_debug) \
- mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-/* ------------------------------------------------------------------------ */
-
-struct mxl111sf_tuner_state {
- struct mxl111sf_state *mxl_state;
-
- struct mxl111sf_tuner_config *cfg;
-
- enum mxl_if_freq if_freq;
-
- u32 frequency;
- u32 bandwidth;
-};
-
-static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
- u8 addr, u8 *data)
-{
- return (state->cfg->read_reg) ?
- state->cfg->read_reg(state->mxl_state, addr, data) :
- -EINVAL;
-}
-
-static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
- u8 addr, u8 data)
-{
- return (state->cfg->write_reg) ?
- state->cfg->write_reg(state->mxl_state, addr, data) :
- -EINVAL;
-}
-
-static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
- struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
- return (state->cfg->program_regs) ?
- state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
- -EINVAL;
-}
-
-static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
- int onoff)
-{
- return (state->cfg->top_master_ctrl) ?
- state->cfg->top_master_ctrl(state->mxl_state, onoff) :
- -EINVAL;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
- {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
- DIG_MODEINDEX, _A, _CSF, */
- {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
- {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
- {0, 0, 0}
-};
-
-/* ------------------------------------------------------------------------ */
-
-static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
- u8 bw)
-{
- u8 filt_bw;
-
- /* set channel bandwidth */
- switch (bw) {
- case 0: /* ATSC */
- filt_bw = 25;
- break;
- case 1: /* QAM */
- filt_bw = 69;
- break;
- case 6:
- filt_bw = 21;
- break;
- case 7:
- filt_bw = 42;
- break;
- case 8:
- filt_bw = 63;
- break;
- default:
- err("%s: invalid bandwidth setting!", __func__);
- return NULL;
- }
-
- /* calculate RF channel */
- freq /= 1000000;
-
- freq *= 64;
-#if 0
- /* do round */
- freq += 0.5;
-#endif
- /* set bandwidth */
- mxl_phy_tune_rf[0].data = filt_bw;
-
- /* set RF */
- mxl_phy_tune_rf[1].data = (freq & 0xff);
- mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
-
- /* start tune */
- return mxl_phy_tune_rf;
-}
-
-static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
-{
- int ret;
- u8 ctrl;
-#if 0
- u16 iffcw;
- u32 if_freq;
-#endif
- mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
- state->cfg->invert_spectrum, state->cfg->if_freq);
-
- /* set IF polarity */
- ctrl = state->cfg->invert_spectrum;
-
- ctrl |= state->cfg->if_freq;
-
- ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
- if (mxl_fail(ret))
- goto fail;
-
-#if 0
- if_freq /= 1000000;
-
- /* do round */
- if_freq += 0.5;
-
- if (MXL_IF_LO == state->cfg->if_freq) {
- ctrl = 0x08;
- iffcw = (u16)(if_freq / (108 * 4096));
- } else if (MXL_IF_HI == state->cfg->if_freq) {
- ctrl = 0x08;
- iffcw = (u16)(if_freq / (216 * 4096));
- } else {
- ctrl = 0;
- iffcw = 0;
- }
-
- ctrl |= (iffcw >> 8);
-#endif
- ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
- if (mxl_fail(ret))
- goto fail;
-
- ctrl &= 0xf0;
- ctrl |= 0x90;
-
- ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
- if (mxl_fail(ret))
- goto fail;
-
-#if 0
- ctrl = iffcw & 0x00ff;
-#endif
- ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
- if (mxl_fail(ret))
- goto fail;
-
- state->if_freq = state->cfg->if_freq;
-fail:
- return ret;
-}
-
-static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
- int ret;
- u8 mxl_mode;
-
- mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
-
- /* stop tune */
- ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
- if (mxl_fail(ret))
- goto fail;
-
- /* check device mode */
- ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
- if (mxl_fail(ret))
- goto fail;
-
- /* Fill out registers for channel tune */
- reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
- if (!reg_ctrl_array)
- return -EINVAL;
-
- ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
- if (mxl_fail(ret))
- goto fail;
-
- if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
- /* IF tuner mode only */
- mxl1x1sf_tuner_top_master_ctrl(state, 0);
- mxl1x1sf_tuner_top_master_ctrl(state, 1);
- mxl1x1sf_tuner_set_if_output_freq(state);
- }
-
- ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
- if (mxl_fail(ret))
- goto fail;
-
- if (state->cfg->ant_hunt)
- state->cfg->ant_hunt(fe);
-fail:
- return ret;
-}
-
-static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
- int *rf_synth_lock,
- int *ref_synth_lock)
-{
- int ret;
- u8 data;
-
- *rf_synth_lock = 0;
- *ref_synth_lock = 0;
-
- ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
- if (mxl_fail(ret))
- goto fail;
-
- *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
- *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0;
-fail:
- return ret;
-}
-
-#if 0
-static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
- int onoff)
-{
- return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
- onoff ? 1 : 0);
-}
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-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("()");
-
- switch (delsys) {
- case SYS_ATSC:
- case SYS_ATSCMH:
- 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 7000000:
- bw = 7;
- break;
- case 8000000:
- bw = 8;
- break;
- default:
- err("%s: bandwidth not set!", __func__);
- return -EINVAL;
- }
- break;
- default:
- err("%s: modulation type not supported!", __func__);
- return -EINVAL;
- }
- ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
- if (mxl_fail(ret))
- goto fail;
-
- state->frequency = c->frequency;
- state->bandwidth = c->bandwidth_hz;
-fail:
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#if 0
-static int mxl111sf_tuner_init(struct dvb_frontend *fe)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- int ret;
-
- /* wake from standby handled by usb driver */
-
- return ret;
-}
-
-static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- int ret;
-
- /* enter standby mode handled by usb driver */
-
- return ret;
-}
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- int rf_locked, ref_locked, ret;
-
- *status = 0;
-
- ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
- if (mxl_fail(ret))
- goto fail;
- mxl_info("%s%s", rf_locked ? "rf locked " : "",
- ref_locked ? "ref locked" : "");
-
- if ((rf_locked) || (ref_locked))
- *status |= TUNER_STATUS_LOCKED;
-fail:
- return ret;
-}
-
-static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- u8 val1, val2;
- int ret;
-
- *strength = 0;
-
- ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
- if (mxl_fail(ret))
- goto fail;
-
- *strength = val1 | ((val2 & 0x07) << 8);
-fail:
- ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
- mxl_fail(ret);
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- *frequency = state->frequency;
- return 0;
-}
-
-static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
- struct mxl111sf_tuner_state *state = fe->tuner_priv;
- *bandwidth = state->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;
- mxl_dbg("()");
- kfree(state);
- fe->tuner_priv = NULL;
- return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
- .info = {
- .name = "MaxLinear MxL111SF",
-#if 0
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
-#endif
- },
-#if 0
- .init = mxl111sf_tuner_init,
- .sleep = mxl111sf_tuner_sleep,
-#endif
- .set_params = mxl111sf_tuner_set_params,
- .get_status = mxl111sf_tuner_get_status,
- .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,
-};
-
-struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
- struct mxl111sf_state *mxl_state,
- struct mxl111sf_tuner_config *cfg)
-{
- struct mxl111sf_tuner_state *state = NULL;
-
- mxl_dbg("()");
-
- state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
-
- state->mxl_state = mxl_state;
- state->cfg = cfg;
-
- memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- fe->tuner_priv = state;
- return fe;
-}
-EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
-
-MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
deleted file mode 100644
index cd842798f5af..000000000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#include <linux/vmalloc.h>
-#include <linux/i2c.h>
-
-#include "mxl111sf.h"
-#include "mxl111sf-reg.h"
-#include "mxl111sf-phy.h"
-#include "mxl111sf-i2c.h"
-#include "mxl111sf-gpio.h"
-
-#include "mxl111sf-demod.h"
-#include "mxl111sf-tuner.h"
-
-#include "lgdt3305.h"
-#include "lg2160.h"
-
-int dvb_usb_mxl111sf_debug;
-module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level "
- "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
-
-int dvb_usb_mxl111sf_isoc;
-module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
-MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
-
-int dvb_usb_mxl111sf_spi;
-module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
-MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
-
-#define ANT_PATH_AUTO 0
-#define ANT_PATH_EXTERNAL 1
-#define ANT_PATH_INTERNAL 2
-
-int dvb_usb_mxl111sf_rfswitch =
-#if 0
- ANT_PATH_AUTO;
-#else
- ANT_PATH_EXTERNAL;
-#endif
-
-module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
-MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
-#define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
-#define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
-
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
- u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
- int wo = (rbuf == NULL || rlen == 0); /* write-only */
- int ret;
- u8 sndbuf[1+wlen];
-
- deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
-
- memset(sndbuf, 0, 1+wlen);
-
- sndbuf[0] = cmd;
- memcpy(&sndbuf[1], wbuf, wlen);
-
- ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
- dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
- mxl_fail(ret);
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#define MXL_CMD_REG_READ 0xaa
-#define MXL_CMD_REG_WRITE 0x55
-
-int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
-{
- u8 buf[2];
- int ret;
-
- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
- if (mxl_fail(ret)) {
- mxl_debug("error reading reg: 0x%02x", addr);
- goto fail;
- }
-
- if (buf[0] == addr)
- *data = buf[1];
- else {
- err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
- addr, buf[0], buf[1]);
- ret = -EINVAL;
- }
-
- deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
-fail:
- return ret;
-}
-
-int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
-{
- u8 buf[] = { addr, data };
- int ret;
-
- deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
-
- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
- if (mxl_fail(ret))
- err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
- u8 addr, u8 mask, u8 data)
-{
- int ret;
- u8 val;
-
- if (mask != 0xff) {
- ret = mxl111sf_read_reg(state, addr, &val);
-#if 1
- /* dont know why this usually errors out on the first try */
- if (mxl_fail(ret))
- err("error writing addr: 0x%02x, mask: 0x%02x, "
- "data: 0x%02x, retrying...", addr, mask, data);
-
- ret = mxl111sf_read_reg(state, addr, &val);
-#endif
- if (mxl_fail(ret))
- goto fail;
- }
- val &= ~mask;
- val |= data;
-
- ret = mxl111sf_write_reg(state, addr, val);
- mxl_fail(ret);
-fail:
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
- struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
- int i, ret = 0;
-
- for (i = 0; ctrl_reg_info[i].addr |
- ctrl_reg_info[i].mask |
- ctrl_reg_info[i].data; i++) {
-
- ret = mxl111sf_write_reg_mask(state,
- ctrl_reg_info[i].addr,
- ctrl_reg_info[i].mask,
- ctrl_reg_info[i].data);
- if (mxl_fail(ret)) {
- err("failed on reg #%d (0x%02x)", i,
- ctrl_reg_info[i].addr);
- break;
- }
- }
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
-{
- int ret;
- u8 id, ver;
- char *mxl_chip, *mxl_rev;
-
- if ((state->chip_id) && (state->chip_ver))
- return 0;
-
- ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
- if (mxl_fail(ret))
- goto fail;
- state->chip_id = id;
-
- ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
- if (mxl_fail(ret))
- goto fail;
- state->chip_ver = ver;
-
- switch (id) {
- case 0x61:
- mxl_chip = "MxL101SF";
- break;
- case 0x63:
- mxl_chip = "MxL111SF";
- break;
- default:
- mxl_chip = "UNKNOWN MxL1X1";
- break;
- }
- switch (ver) {
- case 0x36:
- state->chip_rev = MXL111SF_V6;
- mxl_rev = "v6";
- break;
- case 0x08:
- state->chip_rev = MXL111SF_V8_100;
- mxl_rev = "v8_100";
- break;
- case 0x18:
- state->chip_rev = MXL111SF_V8_200;
- mxl_rev = "v8_200";
- break;
- default:
- state->chip_rev = 0;
- mxl_rev = "UNKNOWN REVISION";
- break;
- }
- info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
-fail:
- return ret;
-}
-
-#define get_chip_info(state) \
-({ \
- int ___ret; \
- ___ret = mxl1x1sf_get_chip_info(state); \
- if (mxl_fail(___ret)) { \
- mxl_debug("failed to get chip info" \
- " on first probe attempt"); \
- ___ret = mxl1x1sf_get_chip_info(state); \
- if (mxl_fail(___ret)) \
- err("failed to get chip info during probe"); \
- else \
- mxl_debug("probe needed a retry " \
- "in order to succeed."); \
- } \
- ___ret; \
-})
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
- /* power control depends on which adapter is being woken:
- * save this for init, instead, via mxl111sf_adap_fe_init */
- return 0;
-}
-
-static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
-
- int err;
-
- /* exit if we didnt initialize the driver yet */
- if (!state->chip_id) {
- mxl_debug("driver not yet initialized, exit.");
- goto fail;
- }
-
- deb_info("%s()\n", __func__);
-
- mutex_lock(&state->fe_lock);
-
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- err = mxl1x1sf_soft_reset(state);
- mxl_fail(err);
- err = mxl111sf_init_tuner_demod(state);
- mxl_fail(err);
- err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-
- mxl_fail(err);
- mxl111sf_enable_usb_output(state);
- mxl_fail(err);
- mxl1x1sf_top_master_ctrl(state, 1);
- mxl_fail(err);
-
- if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
- (state->chip_rev > MXL111SF_V6)) {
- mxl111sf_config_pin_mux_modes(state,
- PIN_MUX_TS_SPI_IN_MODE_1);
- mxl_fail(err);
- }
- err = mxl111sf_init_port_expander(state);
- if (!mxl_fail(err)) {
- state->gpio_mode = adap_state->gpio_mode;
- err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
- mxl_fail(err);
-#if 0
- err = fe->ops.init(fe);
-#endif
- msleep(100); /* add short delay after enabling
- * the demod before touching it */
- }
-
- return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
-fail:
- return -ENODEV;
-}
-
-static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
- int err;
-
- /* exit if we didnt initialize the driver yet */
- if (!state->chip_id) {
- mxl_debug("driver not yet initialized, exit.");
- goto fail;
- }
-
- deb_info("%s()\n", __func__);
-
- err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
-
- mutex_unlock(&state->fe_lock);
-
- return err;
-fail:
- return -ENODEV;
-}
-
-
-static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
- int ret = 0;
-
- deb_info("%s(%d)\n", __func__, onoff);
-
- if (onoff) {
- ret = mxl111sf_enable_usb_output(state);
- mxl_fail(ret);
- ret = mxl111sf_config_mpeg_in(state, 1, 1,
- adap_state->ep6_clockphase,
- 0, 0);
- mxl_fail(ret);
-#if 0
- } else {
- ret = mxl111sf_disable_656_port(state);
- mxl_fail(ret);
-#endif
- }
-
- return ret;
-}
-
-static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int ret = 0;
-
- deb_info("%s(%d)\n", __func__, onoff);
-
- if (onoff) {
- ret = mxl111sf_enable_usb_output(state);
- mxl_fail(ret);
-
- ret = mxl111sf_init_i2s_port(state, 200);
- mxl_fail(ret);
- ret = mxl111sf_config_i2s(state, 0, 15);
- mxl_fail(ret);
- } else {
- ret = mxl111sf_disable_i2s_port(state);
- mxl_fail(ret);
- }
- if (state->chip_rev > MXL111SF_V6)
- ret = mxl111sf_config_spi(state, onoff);
- mxl_fail(ret);
-
- return ret;
-}
-
-static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int ret = 0;
-
- deb_info("%s(%d)\n", __func__, onoff);
-
- if (onoff) {
- ret = mxl111sf_enable_usb_output(state);
- mxl_fail(ret);
- }
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static struct lgdt3305_config hauppauge_lgdt3305_config = {
- .i2c_addr = 0xb2 >> 1,
- .mpeg_mode = LGDT3305_MPEG_SERIAL,
- .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
- .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .qam_if_khz = 6000,
- .vsb_if_khz = 6000,
-};
-
-static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
- int ret;
-
- deb_adv("%s()\n", __func__);
-
- /* save a pointer to the dvb_usb_device in device state */
- state->d = d;
- adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
- adap_state->gpio_mode = state->gpio_mode;
- adap_state->device_mode = MXL_TUNER_MODE;
- adap_state->ep6_clockphase = 1;
-
- ret = mxl1x1sf_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_init_tuner_demod(state);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_enable_usb_output(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl1x1sf_top_master_ctrl(state, 1);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_init_port_expander(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
- if (mxl_fail(ret))
- goto fail;
-
- adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach,
- &hauppauge_lgdt3305_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[fe_id].fe) {
- adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
- adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
- adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
- adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
- return 0;
- }
- ret = -EIO;
-fail:
- return ret;
-}
-
-static struct lg2160_config hauppauge_lg2160_config = {
- .lg_chip = LG2160,
- .i2c_addr = 0x1c >> 1,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .if_khz = 6000,
-};
-
-static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
- int ret;
-
- deb_adv("%s()\n", __func__);
-
- /* save a pointer to the dvb_usb_device in device state */
- state->d = d;
- adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- state->gpio_mode = MXL111SF_GPIO_MOD_MH;
- adap_state->gpio_mode = state->gpio_mode;
- adap_state->device_mode = MXL_TUNER_MODE;
- adap_state->ep6_clockphase = 1;
-
- ret = mxl1x1sf_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_init_tuner_demod(state);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_enable_usb_output(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl1x1sf_top_master_ctrl(state, 1);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_init_port_expander(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = get_chip_info(state);
- if (mxl_fail(ret))
- goto fail;
-
- adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
- &hauppauge_lg2160_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[fe_id].fe) {
- adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
- adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
- adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
- adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
- return 0;
- }
- ret = -EIO;
-fail:
- return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_config = {
- .lg_chip = LG2161_1019,
- .i2c_addr = 0x1c >> 1,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .if_khz = 6000,
- .output_if = 2, /* LG2161_OIF_SPI_MAS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_config = {
- .lg_chip = LG2161_1040,
- .i2c_addr = 0x1c >> 1,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .if_khz = 6000,
- .output_if = 4, /* LG2161_OIF_SPI_MAS */
-};
-
-static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
- int ret;
-
- deb_adv("%s()\n", __func__);
-
- /* save a pointer to the dvb_usb_device in device state */
- state->d = d;
- adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- state->gpio_mode = MXL111SF_GPIO_MOD_MH;
- adap_state->gpio_mode = state->gpio_mode;
- adap_state->device_mode = MXL_TUNER_MODE;
- adap_state->ep6_clockphase = 1;
-
- ret = mxl1x1sf_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_init_tuner_demod(state);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_enable_usb_output(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl1x1sf_top_master_ctrl(state, 1);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_init_port_expander(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = get_chip_info(state);
- if (mxl_fail(ret))
- goto fail;
-
- adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
- (MXL111SF_V8_200 == state->chip_rev) ?
- &hauppauge_lg2161_1040_config :
- &hauppauge_lg2161_1019_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[fe_id].fe) {
- adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
- adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
- adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
- adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
- return 0;
- }
- ret = -EIO;
-fail:
- return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
- .lg_chip = LG2161_1019,
- .i2c_addr = 0x1c >> 1,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .if_khz = 6000,
- .output_if = 1, /* LG2161_OIF_SERIAL_TS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
- .lg_chip = LG2161_1040,
- .i2c_addr = 0x1c >> 1,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 0,
- .if_khz = 6000,
- .output_if = 7, /* LG2161_OIF_SERIAL_TS */
-};
-
-static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
- int ret;
-
- deb_adv("%s()\n", __func__);
-
- /* save a pointer to the dvb_usb_device in device state */
- state->d = d;
- adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- state->gpio_mode = MXL111SF_GPIO_MOD_MH;
- adap_state->gpio_mode = state->gpio_mode;
- adap_state->device_mode = MXL_TUNER_MODE;
- adap_state->ep6_clockphase = 0;
-
- ret = mxl1x1sf_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_init_tuner_demod(state);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_enable_usb_output(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl1x1sf_top_master_ctrl(state, 1);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_init_port_expander(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = get_chip_info(state);
- if (mxl_fail(ret))
- goto fail;
-
- adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
- (MXL111SF_V8_200 == state->chip_rev) ?
- &hauppauge_lg2161_1040_ep6_config :
- &hauppauge_lg2161_1019_ep6_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[fe_id].fe) {
- adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
- adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
- adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
- adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
- return 0;
- }
- ret = -EIO;
-fail:
- return ret;
-}
-
-static struct mxl111sf_demod_config mxl_demod_config = {
- .read_reg = mxl111sf_read_reg,
- .write_reg = mxl111sf_write_reg,
- .program_regs = mxl111sf_ctrl_program_regs,
-};
-
-static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
- struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
- int ret;
-
- deb_adv("%s()\n", __func__);
-
- /* save a pointer to the dvb_usb_device in device state */
- state->d = d;
- adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
- state->alt_mode = adap_state->alt_mode;
-
- if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
- err("set interface failed");
-
- state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
- adap_state->gpio_mode = state->gpio_mode;
- adap_state->device_mode = MXL_SOC_MODE;
- adap_state->ep6_clockphase = 1;
-
- ret = mxl1x1sf_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl111sf_init_tuner_demod(state);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
- if (mxl_fail(ret))
- goto fail;
-
- ret = mxl111sf_enable_usb_output(state);
- if (mxl_fail(ret))
- goto fail;
- ret = mxl1x1sf_top_master_ctrl(state, 1);
- if (mxl_fail(ret))
- goto fail;
-
- /* dont care if this fails */
- mxl111sf_init_port_expander(state);
-
- adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state,
- &mxl_demod_config);
- if (adap->fe_adap[fe_id].fe) {
- adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
- adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
- adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
- adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
- return 0;
- }
- ret = -EIO;
-fail:
- return ret;
-}
-
-static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
- int antpath)
-{
- return mxl111sf_idac_config(state, 1, 1,
- (antpath == ANT_PATH_INTERNAL) ?
- 0x3f : 0x00, 0);
-}
-
-#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
- err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
- __func__, __LINE__, \
- (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
- pwr0, pwr1, pwr2, pwr3)
-
-#define ANT_HUNT_SLEEP 90
-#define ANT_EXT_TWEAK 0
-
-static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
-
- int antctrl = dvb_usb_mxl111sf_rfswitch;
-
- u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
-
- /* FIXME: must force EXTERNAL for QAM - done elsewhere */
- mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
- ANT_PATH_EXTERNAL : antctrl);
-
- if (antctrl == ANT_PATH_AUTO) {
-#if 0
- msleep(ANT_HUNT_SLEEP);
-#endif
- fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
-
- mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
- msleep(ANT_HUNT_SLEEP);
- fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
-
- mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
- msleep(ANT_HUNT_SLEEP);
- fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
-
- mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
- msleep(ANT_HUNT_SLEEP);
- fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
-
- if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
- /* return with EXTERNAL enabled */
- mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
- DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
- rxPwr0, rxPwr1, rxPwr2);
- } else {
- /* return with INTERNAL enabled */
- DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
- rxPwr0, rxPwr1, rxPwr2);
- }
- }
- return 0;
-}
-
-static struct mxl111sf_tuner_config mxl_tuner_config = {
- .if_freq = MXL_IF_6_0, /* applies to external IF output, only */
- .invert_spectrum = 0,
- .read_reg = mxl111sf_read_reg,
- .write_reg = mxl111sf_write_reg,
- .program_regs = mxl111sf_ctrl_program_regs,
- .top_master_ctrl = mxl1x1sf_top_master_ctrl,
- .ant_hunt = mxl111sf_ant_hunt,
-};
-
-static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct mxl111sf_state *state = d->priv;
- int fe_id = adap->num_frontends_initialized;
-
- deb_adv("%s()\n", __func__);
-
- if (NULL != dvb_attach(mxl111sf_tuner_attach,
- adap->fe_adap[fe_id].fe, state,
- &mxl_tuner_config))
- return 0;
-
- return -EIO;
-}
-
-static int mxl111sf_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_READ_SIGNAL_STRENGTH:
- err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
- /* If no error occurs, prevent dvb-core from handling
- * this IOCTL, otherwise return the error */
- if (0 == err)
- err = 1;
- break;
- }
- break;
-
- case DVB_FE_IOCTL_POST:
- /* no post-ioctl handling required */
- break;
- }
- return err;
-};
-
-static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm mxl111sf_i2c_algo = {
- .master_xfer = mxl111sf_i2c_xfer,
- .functionality = mxl111sf_i2c_func,
-#ifdef NEED_ALGO_CONTROL
- .algo_control = dummy_algo_control,
-#endif
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties;
-
-static int mxl111sf_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct dvb_usb_device *d = NULL;
-
- deb_adv("%s()\n", __func__);
-
- if (((dvb_usb_mxl111sf_isoc) &&
- (0 == dvb_usb_device_init(intf,
- &mxl111sf_dvbt_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_atsc_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_atsc_mh_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mh_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- ((dvb_usb_mxl111sf_spi) &&
- (0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_spi_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_mh_spi_isoc_properties,
- THIS_MODULE, &d, adapter_nr))) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_tp_isoc_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_mh_tp_isoc_properties,
- THIS_MODULE, &d, adapter_nr))) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_dvbt_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_atsc_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_atsc_mh_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mh_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- ((dvb_usb_mxl111sf_spi) &&
- (0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_spi_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_mh_spi_bulk_properties,
- THIS_MODULE, &d, adapter_nr))) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_tp_bulk_properties,
- THIS_MODULE, &d, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &mxl111sf_mercury_mh_tp_bulk_properties,
- THIS_MODULE, &d, adapter_nr) || 0) {
-
- struct mxl111sf_state *state = d->priv;
- static u8 eeprom[256];
- struct i2c_client c;
- int ret;
-
- ret = get_chip_info(state);
- if (mxl_fail(ret))
- err("failed to get chip info during probe");
-
- mutex_init(&state->fe_lock);
-
- if (state->chip_rev > MXL111SF_V6)
- mxl111sf_config_pin_mux_modes(state,
- PIN_MUX_TS_SPI_IN_MODE_1);
-
- c.adapter = &d->i2c_adap;
- c.addr = 0xa0 >> 1;
-
- ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
- if (mxl_fail(ret))
- return 0;
- tveeprom_hauppauge_analog(&c, &state->tv,
- (0x84 == eeprom[0xa0]) ?
- eeprom + 0xa0 : eeprom + 0x80);
-#if 0
- switch (state->tv.model) {
- case 117001:
- case 126001:
- case 138001:
- break;
- default:
- printk(KERN_WARNING "%s: warning: "
- "unknown hauppauge model #%d\n",
- __func__, state->tv.model);
- }
-#endif
- return 0;
- }
- err("Your device is not yet supported by this driver. "
- "See kernellabs.com for more info");
- return -EINVAL;
-}
-
-static struct usb_device_id mxl111sf_table[] = {
-/* 0 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /* + */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+ */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT */
-/* 5 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /* + IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+ */
-/*10 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /* + sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw */
-/*15 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw */
-/*20 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT sw */
-/*25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT no */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+ */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /* + */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+ */
-/*30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /* + IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */
- { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */
- {} /* Terminating entry */
-};
-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, \
- .count = 5, \
- .endpoint = 0x04, \
- .u = { \
- .bulk = { \
- .buffersize = 8192, \
- } \
- } \
- }
-
-/* 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, \
- .count = 5, \
- .endpoint = 0x04, \
- .u = { \
- .isoc = { \
- .framesperurb = 96, \
- /* FIXME: v6 SILICON: */ \
- .framesize = 564, \
- .interval = 1, \
- } \
- } \
- }
-
-#define MXL111SF_EP5_BULK_STREAMING_CONFIG \
- .size_of_priv = sizeof(struct mxl111sf_adap_state), \
- .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \
- .stream = { \
- .type = USB_BULK, \
- .count = 5, \
- .endpoint = 0x05, \
- .u = { \
- .bulk = { \
- .buffersize = 8192, \
- } \
- } \
- }
-
-#define MXL111SF_EP5_ISOC_STREAMING_CONFIG \
- .size_of_priv = sizeof(struct mxl111sf_adap_state), \
- .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \
- .stream = { \
- .type = USB_ISOC, \
- .count = 5, \
- .endpoint = 0x05, \
- .u = { \
- .isoc = { \
- .framesperurb = 96, \
- .framesize = 200, \
- .interval = 1, \
- } \
- } \
- }
-
-#define MXL111SF_EP6_BULK_STREAMING_CONFIG \
- .size_of_priv = sizeof(struct mxl111sf_adap_state), \
- .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
- .stream = { \
- .type = USB_BULK, \
- .count = 5, \
- .endpoint = 0x06, \
- .u = { \
- .bulk = { \
- .buffersize = 8192, \
- } \
- } \
- }
-
-/* 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, \
- .count = 5, \
- .endpoint = 0x06, \
- .u = { \
- .isoc = { \
- .framesperurb = 24, \
- .framesize = 3072, \
- .interval = 1, \
- } \
- } \
- }
-
-#define MXL111SF_DEFAULT_DEVICE_PROPERTIES \
- .caps = DVB_USB_IS_AN_I2C_ADAPTER, \
- .usb_ctrl = DEVICE_SPECIFIC, \
- /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \
- EP6 BULK transfer (atsc/qam), \
- use usb alt setting 2 for EP4 BULK transfer (dvb-t), \
- EP6 ISOC transfer (atsc/qam), \
- */ \
- .power_ctrl = mxl111sf_power_ctrl, \
- .i2c_algo = &mxl111sf_i2c_algo, \
- .generic_bulk_ctrl_endpoint = MXL_EP2_REG_WRITE, \
- .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
- .size_of_priv = sizeof(struct mxl111sf_state)
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- } },
- },
- },
- .num_device_descs = 3,
- .devices = {
- { "Hauppauge 126xxx DVBT (bulk)",
- { NULL },
- { &mxl111sf_table[4], &mxl111sf_table[8],
- NULL },
- },
- { "Hauppauge 117xxx DVBT (bulk)",
- { NULL },
- { &mxl111sf_table[15], &mxl111sf_table[18],
- NULL },
- },
- { "Hauppauge 138xxx DVBT (bulk)",
- { NULL },
- { &mxl111sf_table[20], &mxl111sf_table[22],
- &mxl111sf_table[24], &mxl111sf_table[26],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- } },
- },
- },
- .num_device_descs = 3,
- .devices = {
- { "Hauppauge 126xxx DVBT (isoc)",
- { NULL },
- { &mxl111sf_table[4], &mxl111sf_table[8],
- NULL },
- },
- { "Hauppauge 117xxx DVBT (isoc)",
- { NULL },
- { &mxl111sf_table[15], &mxl111sf_table[18],
- NULL },
- },
- { "Hauppauge 138xxx DVBT (isoc)",
- { NULL },
- { &mxl111sf_table[20], &mxl111sf_table[22],
- &mxl111sf_table[24], &mxl111sf_table[26],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge 126xxx ATSC (bulk)",
- { NULL },
- { &mxl111sf_table[1], &mxl111sf_table[5],
- NULL },
- },
- { "Hauppauge 117xxx ATSC (bulk)",
- { NULL },
- { &mxl111sf_table[12],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge 126xxx ATSC (isoc)",
- { NULL },
- { &mxl111sf_table[1], &mxl111sf_table[5],
- NULL },
- },
- { "Hauppauge 117xxx ATSC (isoc)",
- { NULL },
- { &mxl111sf_table[12],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2160_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "HCW 126xxx (bulk)",
- { NULL },
- { &mxl111sf_table[2], &mxl111sf_table[6],
- NULL },
- },
- { "HCW 117xxx (bulk)",
- { NULL },
- { &mxl111sf_table[13],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2160_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "HCW 126xxx (isoc)",
- { NULL },
- { &mxl111sf_table[2], &mxl111sf_table[6],
- NULL },
- },
- { "HCW 117xxx (isoc)",
- { NULL },
- { &mxl111sf_table[13],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2160_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge 126xxx ATSC+ (bulk)",
- { NULL },
- { &mxl111sf_table[0], &mxl111sf_table[3],
- &mxl111sf_table[7], &mxl111sf_table[9],
- &mxl111sf_table[10], NULL },
- },
- { "Hauppauge 117xxx ATSC+ (bulk)",
- { NULL },
- { &mxl111sf_table[11], &mxl111sf_table[14],
- &mxl111sf_table[16], &mxl111sf_table[17],
- &mxl111sf_table[32], &mxl111sf_table[33],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2160_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge 126xxx ATSC+ (isoc)",
- { NULL },
- { &mxl111sf_table[0], &mxl111sf_table[3],
- &mxl111sf_table[7], &mxl111sf_table[9],
- &mxl111sf_table[10], NULL },
- },
- { "Hauppauge 117xxx ATSC+ (isoc)",
- { NULL },
- { &mxl111sf_table[11], &mxl111sf_table[14],
- &mxl111sf_table[16], &mxl111sf_table[17],
- &mxl111sf_table[32], &mxl111sf_table[33],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge Mercury (spi-bulk)",
- { NULL },
- { &mxl111sf_table[19], &mxl111sf_table[21],
- &mxl111sf_table[23], &mxl111sf_table[25],
- NULL },
- },
- { "Hauppauge WinTV-Aero-M (spi-bulk)",
- { NULL },
- { &mxl111sf_table[29], &mxl111sf_table[31],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge Mercury (spi-isoc)",
- { NULL },
- { &mxl111sf_table[19], &mxl111sf_table[21],
- &mxl111sf_table[23], &mxl111sf_table[25],
- NULL },
- },
- { "Hauppauge WinTV-Aero-M (spi-isoc)",
- { NULL },
- { &mxl111sf_table[29], &mxl111sf_table[31],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge Mercury (tp-bulk)",
- { NULL },
- { &mxl111sf_table[19], &mxl111sf_table[21],
- &mxl111sf_table[23], &mxl111sf_table[25],
- &mxl111sf_table[27], NULL },
- },
- { "Hauppauge WinTV-Aero-M",
- { NULL },
- { &mxl111sf_table[29], &mxl111sf_table[31],
- NULL },
- },
- }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 3,
- .fe = {{
- .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- },
- {
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 2,
- .devices = {
- { "Hauppauge Mercury (tp-isoc)",
- { NULL },
- { &mxl111sf_table[19], &mxl111sf_table[21],
- &mxl111sf_table[23], &mxl111sf_table[25],
- &mxl111sf_table[27], NULL },
- },
- { "Hauppauge WinTV-Aero-M (tp-isoc)",
- { NULL },
- { &mxl111sf_table[29], &mxl111sf_table[31],
- NULL },
- },
- }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 1,
- .devices = {
- { "Hauppauge 126xxx (tp-bulk)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
- }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP6_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 1,
- .devices = {
- { "Hauppauge 126xxx (tp-isoc)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
- }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_BULK_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 1,
- .devices = {
- { "Hauppauge 126xxx (spi-bulk)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
- }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = {
- MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
- .num_adapters = 1,
- .adapter = {
- {
- .fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
- .fe = {{
- .frontend_attach = mxl111sf_attach_demod,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP4_ISOC_STREAMING_CONFIG,
- },
- {
- .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
- .frontend_attach = mxl111sf_lg2161_frontend_attach,
- .tuner_attach = mxl111sf_attach_tuner,
-
- MXL111SF_EP5_ISOC_STREAMING_CONFIG,
- }},
- },
- },
- .num_device_descs = 1,
- .devices = {
- { "Hauppauge 126xxx (spi-isoc)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
- }
-};
-
-static struct usb_driver mxl111sf_driver = {
- .name = "dvb_usb_mxl111sf",
- .probe = mxl111sf_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = mxl111sf_table,
-};
-
-module_usb_driver(mxl111sf_driver);
-
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h
deleted file mode 100644
index 364d89f826bd..000000000000
--- a/drivers/media/dvb/dvb-usb/mxl111sf.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@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, version 2.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#ifndef _DVB_USB_MXL111SF_H_
-#define _DVB_USB_MXL111SF_H_
-
-#ifdef DVB_USB_LOG_PREFIX
-#undef DVB_USB_LOG_PREFIX
-#endif
-#define DVB_USB_LOG_PREFIX "mxl111sf"
-#include "dvb-usb.h"
-#include <media/tveeprom.h>
-
-#define MXL_EP1_REG_READ 1
-#define MXL_EP2_REG_WRITE 2
-#define MXL_EP3_INTERRUPT 3
-#define MXL_EP4_MPEG2 4
-#define MXL_EP5_I2S 5
-#define MXL_EP6_656 6
-#define MXL_EP6_MPEG2 6
-
-#ifdef USING_ENUM_mxl111sf_current_mode
-enum mxl111sf_current_mode {
- mxl_mode_dvbt = MXL_EP4_MPEG2,
- mxl_mode_mh = MXL_EP5_I2S,
- mxl_mode_atsc = MXL_EP6_MPEG2,
-};
-#endif
-
-enum mxl111sf_gpio_port_expander {
- mxl111sf_gpio_hw,
- mxl111sf_PCA9534,
-};
-
-struct mxl111sf_state {
- struct dvb_usb_device *d;
-
- enum mxl111sf_gpio_port_expander gpio_port_expander;
- u8 port_expander_addr;
-
- u8 chip_id;
- u8 chip_ver;
-#define MXL111SF_V6 1
-#define MXL111SF_V8_100 2
-#define MXL111SF_V8_200 3
- u8 chip_rev;
-
-#ifdef USING_ENUM_mxl111sf_current_mode
- enum mxl111sf_current_mode current_mode;
-#endif
-
-#define MXL_TUNER_MODE 0
-#define MXL_SOC_MODE 1
-#define MXL_DEV_MODE_MASK 0x01
-#if 1
- int device_mode;
-#endif
- /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
- EP5 BULK transfer (atsc-mh),
- EP6 BULK transfer (atsc/qam),
- use usb alt setting 2 for EP4 BULK transfer (dvb-t),
- EP5 ISOC transfer (atsc-mh),
- EP6 ISOC transfer (atsc/qam),
- */
- int alt_mode;
- int gpio_mode;
- struct tveeprom tv;
-
- struct mutex fe_lock;
-};
-
-struct mxl111sf_adap_state {
- int alt_mode;
- int gpio_mode;
- int device_mode;
- int ep6_clockphase;
- int (*fe_init)(struct dvb_frontend *);
- int (*fe_sleep)(struct dvb_frontend *);
-};
-
-int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
-int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
-
-struct mxl111sf_reg_ctrl_info {
- u8 addr;
- u8 mask;
- u8 data;
-};
-
-int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
- u8 addr, u8 mask, u8 data);
-int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
- struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
-
-/* needed for hardware i2c functions in mxl111sf-i2c.c:
- * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
- u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
-
-#define mxl_printk(kern, fmt, arg...) \
- printk(kern "%s: " fmt "\n", __func__, ##arg)
-
-#define mxl_info(fmt, arg...) \
- mxl_printk(KERN_INFO, fmt, ##arg)
-
-extern int dvb_usb_mxl111sf_debug;
-#define mxl_debug(fmt, arg...) \
- if (dvb_usb_mxl111sf_debug) \
- mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define MXL_I2C_DBG 0x04
-#define MXL_ADV_DBG 0x10
-#define mxl_debug_adv(fmt, arg...) \
- if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
- mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define mxl_i2c(fmt, arg...) \
- if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
- mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-#define mxl_i2c_adv(fmt, arg...) \
- if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
- (MXL_I2C_DBG | MXL_ADV_DBG)) \
- mxl_printk(KERN_DEBUG, fmt, ##arg)
-
-/* The following allows the mxl_fail() macro defined below to work
- * in externel modules, such as mxl111sf-tuner.ko, even though
- * dvb_usb_mxl111sf_debug is not defined within those modules */
-#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
-#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
-#else
-#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
-#endif
-
-#define mxl_fail(ret) \
-({ \
- int __ret; \
- __ret = (ret < 0); \
- if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \
- mxl_printk(KERN_ERR, "error %d on line %d", \
- ret, __LINE__); \
- __ret; \
-})
-
-#endif /* _DVB_USB_MXL111SF_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
deleted file mode 100644
index f526eb05cc7a..000000000000
--- a/drivers/media/dvb/dvb-usb/pctv452e.c
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * PCTV 452e DVB driver
- *
- * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
- *
- * TT connect S2-3650-CI Common Interface support, MAC readout
- * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
- *
- * 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.
- */
-
-/* dvb usb framework */
-#define DVB_USB_LOG_PREFIX "pctv452e"
-#include "dvb-usb.h"
-
-/* Demodulator */
-#include "stb0899_drv.h"
-#include "stb0899_reg.h"
-#include "stb0899_cfg.h"
-/* Tuner */
-#include "stb6100.h"
-#include "stb6100_cfg.h"
-/* FE Power */
-#include "lnbp22.h"
-
-#include "dvb_ca_en50221.h"
-#include "ttpci-eeprom.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define ISOC_INTERFACE_ALTERNATIVE 3
-
-#define SYNC_BYTE_OUT 0xaa
-#define SYNC_BYTE_IN 0x55
-
-/* guessed: (copied from ttusb-budget) */
-#define PCTV_CMD_RESET 0x15
-/* command to poll IR receiver */
-#define PCTV_CMD_IR 0x1b
-/* command to send I2C */
-#define PCTV_CMD_I2C 0x31
-
-#define I2C_ADDR_STB0899 (0xd0 >> 1)
-#define I2C_ADDR_STB6100 (0xc0 >> 1)
-#define I2C_ADDR_LNBP22 (0x10 >> 1)
-#define I2C_ADDR_24C16 (0xa0 >> 1)
-#define I2C_ADDR_24C64 (0xa2 >> 1)
-
-
-/* pctv452e sends us this amount of data for each issued usb-command */
-#define PCTV_ANSWER_LEN 64
-/* Wait up to 1000ms for device */
-#define PCTV_TIMEOUT 1000
-
-
-#define PCTV_LED_GPIO STB0899_GPIO01
-#define PCTV_LED_GREEN 0x82
-#define PCTV_LED_ORANGE 0x02
-
-#define ci_dbg(format, arg...) \
-do { \
- if (0) \
- printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
- ": " format "\n" , ## arg); \
-} while (0)
-
-enum {
- TT3650_CMD_CI_TEST = 0x40,
- TT3650_CMD_CI_RD_CTRL,
- TT3650_CMD_CI_WR_CTRL,
- TT3650_CMD_CI_RD_ATTR,
- TT3650_CMD_CI_WR_ATTR,
- TT3650_CMD_CI_RESET,
- TT3650_CMD_CI_SET_VIDEO_PORT
-};
-
-
-static struct stb0899_postproc pctv45e_postproc[] = {
- { PCTV_LED_GPIO, STB0899_GPIOPULLUP },
- { 0, 0 }
-};
-
-/*
- * stores all private variables for communication with the PCTV452e DVB-S2
- */
-struct pctv452e_state {
- struct dvb_ca_en50221 ca;
- struct mutex ca_mutex;
-
- u8 c; /* transaction counter, wraps around... */
- u8 initialized; /* set to 1 if 0x15 has been sent */
- u16 last_rc_key;
-};
-
-static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
- unsigned int write_len, unsigned int read_len)
-{
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 buf[64];
- u8 id;
- unsigned int rlen;
- int ret;
-
- BUG_ON(NULL == data && 0 != (write_len | read_len));
- BUG_ON(write_len > 64 - 4);
- BUG_ON(read_len > 64 - 4);
-
- id = state->c++;
-
- buf[0] = SYNC_BYTE_OUT;
- buf[1] = id;
- buf[2] = cmd;
- buf[3] = write_len;
-
- memcpy(buf + 4, data, write_len);
-
- rlen = (read_len > 0) ? 64 : 0;
- ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
- buf, rlen, /* delay_ms */ 0);
- if (0 != ret)
- goto failed;
-
- ret = -EIO;
- if (SYNC_BYTE_IN != buf[0] || id != buf[1])
- goto failed;
-
- memcpy(data, buf + 4, read_len);
-
- return 0;
-
-failed:
- err("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
- ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
-
- return ret;
-}
-
-static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
- u8 cmd, u8 *data, unsigned int write_len,
- unsigned int read_len)
-{
- struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- int ret;
-
- mutex_lock(&state->ca_mutex);
- ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
- mutex_unlock(&state->ca_mutex);
-
- return ret;
-}
-
-static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
- int slot, int address)
-{
- u8 buf[3];
- int ret;
-
- if (0 != slot)
- return -EINVAL;
-
- buf[0] = (address >> 8) & 0x0F;
- buf[1] = address;
-
- ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
-
- ci_dbg("%s %04x -> %d 0x%02x",
- __func__, address, ret, buf[2]);
-
- if (ret < 0)
- return ret;
-
- return buf[2];
-}
-
-static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
- int slot, int address, u8 value)
-{
- u8 buf[3];
-
- ci_dbg("%s %d 0x%04x 0x%02x",
- __func__, slot, address, value);
-
- if (0 != slot)
- return -EINVAL;
-
- buf[0] = (address >> 8) & 0x0F;
- buf[1] = address;
- buf[2] = value;
-
- return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
-}
-
-static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
- int slot,
- u8 address)
-{
- u8 buf[2];
- int ret;
-
- if (0 != slot)
- return -EINVAL;
-
- buf[0] = address & 3;
-
- ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
-
- ci_dbg("%s 0x%02x -> %d 0x%02x",
- __func__, address, ret, buf[1]);
-
- if (ret < 0)
- return ret;
-
- return buf[1];
-}
-
-static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
- int slot,
- u8 address,
- u8 value)
-{
- u8 buf[2];
-
- ci_dbg("%s %d 0x%02x 0x%02x",
- __func__, slot, address, value);
-
- if (0 != slot)
- return -EINVAL;
-
- buf[0] = address;
- buf[1] = value;
-
- return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
-}
-
-static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
- int slot,
- int enable)
-{
- u8 buf[1];
- int ret;
-
- ci_dbg("%s %d %d", __func__, slot, enable);
-
- if (0 != slot)
- return -EINVAL;
-
- enable = !!enable;
- buf[0] = enable;
-
- ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
- if (ret < 0)
- return ret;
-
- if (enable != buf[0]) {
- err("CI not %sabled.", enable ? "en" : "dis");
- return -EIO;
- }
-
- return 0;
-}
-
-static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
- return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
-}
-
-static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
- return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
-}
-
-static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
- struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 buf[1];
- int ret;
-
- ci_dbg("%s %d", __func__, slot);
-
- if (0 != slot)
- return -EINVAL;
-
- buf[0] = 0;
-
- mutex_lock(&state->ca_mutex);
-
- ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
- if (0 != ret)
- goto failed;
-
- msleep(500);
-
- buf[0] = 1;
-
- ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
- if (0 != ret)
- goto failed;
-
- msleep(500);
-
- buf[0] = 0; /* FTA */
-
- ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
-
- failed:
- mutex_unlock(&state->ca_mutex);
-
- return ret;
-}
-
-static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
- int slot,
- int open)
-{
- u8 buf[1];
- int ret;
-
- if (0 != slot)
- return -EINVAL;
-
- ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
- if (0 != ret)
- return ret;
-
- if (1 == buf[0])
- return DVB_CA_EN50221_POLL_CAM_PRESENT |
- DVB_CA_EN50221_POLL_CAM_READY;
-
- return 0;
-
-}
-
-static void tt3650_ci_uninit(struct dvb_usb_device *d)
-{
- struct pctv452e_state *state;
-
- ci_dbg("%s", __func__);
-
- if (NULL == d)
- return;
-
- state = (struct pctv452e_state *)d->priv;
- if (NULL == state)
- return;
-
- if (NULL == state->ca.data)
- return;
-
- /* Error ignored. */
- tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
-
- dvb_ca_en50221_release(&state->ca);
-
- memset(&state->ca, 0, sizeof(state->ca));
-}
-
-static int tt3650_ci_init(struct dvb_usb_adapter *a)
-{
- struct dvb_usb_device *d = a->dev;
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- int ret;
-
- ci_dbg("%s", __func__);
-
- mutex_init(&state->ca_mutex);
-
- state->ca.owner = THIS_MODULE;
- state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
- state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
- state->ca.read_cam_control = tt3650_ci_read_cam_control;
- state->ca.write_cam_control = tt3650_ci_write_cam_control;
- state->ca.slot_reset = tt3650_ci_slot_reset;
- state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
- state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
- state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
- state->ca.data = d;
-
- ret = dvb_ca_en50221_init(&a->dvb_adap,
- &state->ca,
- /* flags */ 0,
- /* n_slots */ 1);
- if (0 != ret) {
- err("Cannot initialize CI: Error %d.", ret);
- memset(&state->ca, 0, sizeof(state->ca));
- return ret;
- }
-
- info("CI initialized.");
-
- return 0;
-}
-
-#define CMD_BUFFER_SIZE 0x28
-static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
- const u8 *snd_buf, u8 snd_len,
- u8 *rcv_buf, u8 rcv_len)
-{
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 buf[64];
- u8 id;
- int ret;
-
- id = state->c++;
-
- ret = -EINVAL;
- if (snd_len > 64 - 7 || rcv_len > 64 - 7)
- goto failed;
-
- buf[0] = SYNC_BYTE_OUT;
- buf[1] = id;
- buf[2] = PCTV_CMD_I2C;
- buf[3] = snd_len + 3;
- buf[4] = addr << 1;
- buf[5] = snd_len;
- buf[6] = rcv_len;
-
- memcpy(buf + 7, snd_buf, snd_len);
-
- ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
- buf, /* rcv_len */ 64,
- /* delay_ms */ 0);
- if (ret < 0)
- goto failed;
-
- /* TT USB protocol error. */
- ret = -EIO;
- if (SYNC_BYTE_IN != buf[0] || id != buf[1])
- goto failed;
-
- /* I2C device didn't respond as expected. */
- ret = -EREMOTEIO;
- if (buf[5] < snd_len || buf[6] < rcv_len)
- goto failed;
-
- memcpy(rcv_buf, buf + 7, rcv_len);
-
- return rcv_len;
-
-failed:
- err("I2C error %d; %02X %02X %02X %02X %02X -> "
- "%02X %02X %02X %02X %02X.",
- ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
- buf[0], buf[1], buf[4], buf[5], buf[6]);
-
- return ret;
-}
-
-static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adapter);
- int i;
-
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
- for (i = 0; i < num; i++) {
- u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
- int ret;
-
- if (msg[i].flags & I2C_M_RD) {
- addr = msg[i].addr;
- snd_buf = NULL;
- snd_len = 0;
- rcv_buf = msg[i].buf;
- rcv_len = msg[i].len;
- } else {
- addr = msg[i].addr;
- snd_buf = msg[i].buf;
- snd_len = msg[i].len;
- rcv_buf = NULL;
- rcv_len = 0;
- }
-
- ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
- rcv_len);
- if (ret < rcv_len)
- break;
- }
-
- mutex_unlock(&d->i2c_mutex);
- return i;
-}
-
-static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
-{
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
- u8 rx[PCTV_ANSWER_LEN];
- int ret;
-
- info("%s: %d\n", __func__, i);
-
- if (!i)
- return 0;
-
- if (state->initialized)
- return 0;
-
- /* hmm where shoud this should go? */
- ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
- if (ret != 0)
- info("%s: Warning set interface returned: %d\n",
- __func__, ret);
-
- /* this is a one-time initialization, dont know where to put */
- b0[1] = state->c++;
- /* reset board */
- ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
- if (ret)
- return ret;
-
- b0[1] = state->c++;
- b0[4] = 1;
- /* reset board (again?) */
- ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
- if (ret)
- return ret;
-
- state->initialized = 1;
-
- return 0;
-}
-
-static int pctv452e_rc_query(struct dvb_usb_device *d)
-{
- struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 b[CMD_BUFFER_SIZE];
- u8 rx[PCTV_ANSWER_LEN];
- int ret, i;
- u8 id = state->c++;
-
- /* prepare command header */
- b[0] = SYNC_BYTE_OUT;
- b[1] = id;
- b[2] = PCTV_CMD_IR;
- b[3] = 0;
-
- /* send ir request */
- ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
- if (ret != 0)
- return ret;
-
- if (debug > 3) {
- info("%s: read: %2d: %02x %02x %02x: ", __func__,
- ret, rx[0], rx[1], rx[2]);
- for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
- info(" %02x", rx[i+3]);
-
- info("\n");
- }
-
- if ((rx[3] == 9) && (rx[12] & 0x01)) {
- /* got a "press" event */
- state->last_rc_key = (rx[7] << 8) | rx[6];
- if (debug > 2)
- info("%s: cmd=0x%02x sys=0x%02x\n",
- __func__, rx[6], rx[7]);
-
- rc_keydown(d->rc_dev, state->last_rc_key, 0);
- } else if (state->last_rc_key) {
- rc_keyup(d->rc_dev);
- state->last_rc_key = 0;
- }
-
- return 0;
-}
-
-static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
- const u8 mem_addr[] = { 0x1f, 0xcc };
- u8 encoded_mac[20];
- int ret;
-
- ret = -EAGAIN;
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- goto failed;
-
- ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
- mem_addr + 1, /* snd_len */ 1,
- encoded_mac, /* rcv_len */ 20);
- if (-EREMOTEIO == ret)
- /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
- byte write if /WC is low. */
- ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
- mem_addr, 2,
- encoded_mac, 20);
-
- mutex_unlock(&d->i2c_mutex);
-
- if (20 != ret)
- goto failed;
-
- ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
- if (0 != ret)
- goto failed;
-
- return 0;
-
-failed:
- memset(mac, 0, 6);
-
- return ret;
-}
-
-static const struct stb0899_s1_reg pctv452e_init_dev[] = {
- { STB0899_DISCNTRL1, 0x26 },
- { STB0899_DISCNTRL2, 0x80 },
- { STB0899_DISRX_ST0, 0x04 },
- { STB0899_DISRX_ST1, 0x20 },
- { STB0899_DISPARITY, 0x00 },
- { STB0899_DISFIFO, 0x00 },
- { STB0899_DISF22, 0x99 },
- { STB0899_DISF22RX, 0x85 }, /* 0xa8 */
- { STB0899_ACRPRESC, 0x11 },
- { STB0899_ACRDIV1, 0x0a },
- { STB0899_ACRDIV2, 0x05 },
- { STB0899_DACR1 , 0x00 },
- { STB0899_DACR2 , 0x00 },
- { STB0899_OUTCFG, 0x00 },
- { STB0899_MODECFG, 0x00 }, /* Inversion */
- { STB0899_IRQMSK_3, 0xf3 },
- { STB0899_IRQMSK_2, 0xfc },
- { STB0899_IRQMSK_1, 0xff },
- { STB0899_IRQMSK_0, 0xff },
- { STB0899_I2CCFG, 0x88 },
- { STB0899_I2CRPT, 0x58 },
- { STB0899_GPIO00CFG, 0x82 },
- { STB0899_GPIO01CFG, 0x82 }, /* LED: 0x02 green, 0x82 orange */
- { STB0899_GPIO02CFG, 0x82 },
- { STB0899_GPIO03CFG, 0x82 },
- { STB0899_GPIO04CFG, 0x82 },
- { STB0899_GPIO05CFG, 0x82 },
- { STB0899_GPIO06CFG, 0x82 },
- { STB0899_GPIO07CFG, 0x82 },
- { STB0899_GPIO08CFG, 0x82 },
- { STB0899_GPIO09CFG, 0x82 },
- { STB0899_GPIO10CFG, 0x82 },
- { STB0899_GPIO11CFG, 0x82 },
- { STB0899_GPIO12CFG, 0x82 },
- { STB0899_GPIO13CFG, 0x82 },
- { STB0899_GPIO14CFG, 0x82 },
- { STB0899_GPIO15CFG, 0x82 },
- { STB0899_GPIO16CFG, 0x82 },
- { STB0899_GPIO17CFG, 0x82 },
- { STB0899_GPIO18CFG, 0x82 },
- { STB0899_GPIO19CFG, 0x82 },
- { STB0899_GPIO20CFG, 0x82 },
- { STB0899_SDATCFG, 0xb8 },
- { STB0899_SCLTCFG, 0xba },
- { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
- { STB0899_GPIO22, 0x82 },
- { STB0899_GPIO21, 0x91 },
- { STB0899_DIRCLKCFG, 0x82 },
- { STB0899_CLKOUT27CFG, 0x7e },
- { STB0899_STDBYCFG, 0x82 },
- { STB0899_CS0CFG, 0x82 },
- { STB0899_CS1CFG, 0x82 },
- { STB0899_DISEQCOCFG, 0x20 },
- { STB0899_NCOARSE, 0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
- { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */
- { STB0899_FILTCTRL, 0x00 },
- { STB0899_SYSCTRL, 0x00 },
- { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */
- { STB0899_STOPCLK2, 0x00 },
- { STB0899_INTBUFCTRL, 0x0a },
- { STB0899_AGC2I1, 0x00 },
- { STB0899_AGC2I2, 0x00 },
- { STB0899_AGCIQIN, 0x00 },
- { STB0899_TSTRES, 0x40 }, /* rjkm */
- { 0xffff, 0xff },
-};
-
-static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
- { STB0899_DEMOD, 0x00 },
- { STB0899_RCOMPC, 0xc9 },
- { STB0899_AGC1CN, 0x01 },
- { STB0899_AGC1REF, 0x10 },
- { STB0899_RTC, 0x23 },
- { STB0899_TMGCFG, 0x4e },
- { STB0899_AGC2REF, 0x34 },
- { STB0899_TLSR, 0x84 },
- { STB0899_CFD, 0xf7 },
- { STB0899_ACLC, 0x87 },
- { STB0899_BCLC, 0x94 },
- { STB0899_EQON, 0x41 },
- { STB0899_LDT, 0xf1 },
- { STB0899_LDT2, 0xe3 },
- { STB0899_EQUALREF, 0xb4 },
- { STB0899_TMGRAMP, 0x10 },
- { STB0899_TMGTHD, 0x30 },
- { STB0899_IDCCOMP, 0xfd },
- { STB0899_QDCCOMP, 0xff },
- { STB0899_POWERI, 0x0c },
- { STB0899_POWERQ, 0x0f },
- { STB0899_RCOMP, 0x6c },
- { STB0899_AGCIQIN, 0x80 },
- { STB0899_AGC2I1, 0x06 },
- { STB0899_AGC2I2, 0x00 },
- { STB0899_TLIR, 0x30 },
- { STB0899_RTF, 0x7f },
- { STB0899_DSTATUS, 0x00 },
- { STB0899_LDI, 0xbc },
- { STB0899_CFRM, 0xea },
- { STB0899_CFRL, 0x31 },
- { STB0899_NIRM, 0x2b },
- { STB0899_NIRL, 0x80 },
- { STB0899_ISYMB, 0x1d },
- { STB0899_QSYMB, 0xa6 },
- { STB0899_SFRH, 0x2f },
- { STB0899_SFRM, 0x68 },
- { STB0899_SFRL, 0x40 },
- { STB0899_SFRUPH, 0x2f },
- { STB0899_SFRUPM, 0x68 },
- { STB0899_SFRUPL, 0x40 },
- { STB0899_EQUAI1, 0x02 },
- { STB0899_EQUAQ1, 0xff },
- { STB0899_EQUAI2, 0x04 },
- { STB0899_EQUAQ2, 0x05 },
- { STB0899_EQUAI3, 0x02 },
- { STB0899_EQUAQ3, 0xfd },
- { STB0899_EQUAI4, 0x03 },
- { STB0899_EQUAQ4, 0x07 },
- { STB0899_EQUAI5, 0x08 },
- { STB0899_EQUAQ5, 0xf5 },
- { STB0899_DSTATUS2, 0x00 },
- { STB0899_VSTATUS, 0x00 },
- { STB0899_VERROR, 0x86 },
- { STB0899_IQSWAP, 0x2a },
- { STB0899_ECNT1M, 0x00 },
- { STB0899_ECNT1L, 0x00 },
- { STB0899_ECNT2M, 0x00 },
- { STB0899_ECNT2L, 0x00 },
- { STB0899_ECNT3M, 0x0a },
- { STB0899_ECNT3L, 0xad },
- { STB0899_FECAUTO1, 0x06 },
- { STB0899_FECM, 0x01 },
- { STB0899_VTH12, 0xb0 },
- { STB0899_VTH23, 0x7a },
- { STB0899_VTH34, 0x58 },
- { STB0899_VTH56, 0x38 },
- { STB0899_VTH67, 0x34 },
- { STB0899_VTH78, 0x24 },
- { STB0899_PRVIT, 0xff },
- { STB0899_VITSYNC, 0x19 },
- { STB0899_RSULC, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
- { STB0899_TSULC, 0x42 },
- { STB0899_RSLLC, 0x41 },
- { STB0899_TSLPL, 0x12 },
- { STB0899_TSCFGH, 0x0c },
- { STB0899_TSCFGM, 0x00 },
- { STB0899_TSCFGL, 0x00 },
- { STB0899_TSOUT, 0x69 }, /* 0x0d for CAM */
- { STB0899_RSSYNCDEL, 0x00 },
- { STB0899_TSINHDELH, 0x02 },
- { STB0899_TSINHDELM, 0x00 },
- { STB0899_TSINHDELL, 0x00 },
- { STB0899_TSLLSTKM, 0x1b },
- { STB0899_TSLLSTKL, 0xb3 },
- { STB0899_TSULSTKM, 0x00 },
- { STB0899_TSULSTKL, 0x00 },
- { STB0899_PCKLENUL, 0xbc },
- { STB0899_PCKLENLL, 0xcc },
- { STB0899_RSPCKLEN, 0xbd },
- { STB0899_TSSTATUS, 0x90 },
- { STB0899_ERRCTRL1, 0xb6 },
- { STB0899_ERRCTRL2, 0x95 },
- { STB0899_ERRCTRL3, 0x8d },
- { STB0899_DMONMSK1, 0x27 },
- { STB0899_DMONMSK0, 0x03 },
- { STB0899_DEMAPVIT, 0x5c },
- { STB0899_PLPARM, 0x19 },
- { STB0899_PDELCTRL, 0x48 },
- { STB0899_PDELCTRL2, 0x00 },
- { STB0899_BBHCTRL1, 0x00 },
- { STB0899_BBHCTRL2, 0x00 },
- { STB0899_HYSTTHRESH, 0x77 },
- { STB0899_MATCSTM, 0x00 },
- { STB0899_MATCSTL, 0x00 },
- { STB0899_UPLCSTM, 0x00 },
- { STB0899_UPLCSTL, 0x00 },
- { STB0899_DFLCSTM, 0x00 },
- { STB0899_DFLCSTL, 0x00 },
- { STB0899_SYNCCST, 0x00 },
- { STB0899_SYNCDCSTM, 0x00 },
- { STB0899_SYNCDCSTL, 0x00 },
- { STB0899_ISI_ENTRY, 0x00 },
- { STB0899_ISI_BIT_EN, 0x00 },
- { STB0899_MATSTRM, 0xf0 },
- { STB0899_MATSTRL, 0x02 },
- { STB0899_UPLSTRM, 0x45 },
- { STB0899_UPLSTRL, 0x60 },
- { STB0899_DFLSTRM, 0xe3 },
- { STB0899_DFLSTRL, 0x00 },
- { STB0899_SYNCSTR, 0x47 },
- { STB0899_SYNCDSTRM, 0x05 },
- { STB0899_SYNCDSTRL, 0x18 },
- { STB0899_CFGPDELSTATUS1, 0x19 },
- { STB0899_CFGPDELSTATUS2, 0x2b },
- { STB0899_BBFERRORM, 0x00 },
- { STB0899_BBFERRORL, 0x01 },
- { STB0899_UPKTERRORM, 0x00 },
- { STB0899_UPKTERRORL, 0x00 },
- { 0xffff, 0xff },
-};
-
-static struct stb0899_config stb0899_config = {
- .init_dev = pctv452e_init_dev,
- .init_s2_demod = stb0899_s2_init_2,
- .init_s1_demod = pctv452e_init_s1_demod,
- .init_s2_fec = stb0899_s2_init_4,
- .init_tst = stb0899_s1_init_5,
-
- .demod_address = I2C_ADDR_STB0899, /* I2C Address */
- .block_sync_mode = STB0899_SYNC_FORCED, /* ? */
-
- .xtal_freq = 27000000, /* Assume Hz ? */
- .inversion = IQ_SWAP_ON, /* ? */
-
- .lo_clk = 76500000,
- .hi_clk = 99000000,
-
- .ts_output_mode = 0, /* Use parallel mode */
- .clock_polarity = 0,
- .data_clk_parity = 0,
- .fec_mode = 0,
-
- .esno_ave = STB0899_DVBS2_ESNO_AVE,
- .esno_quant = STB0899_DVBS2_ESNO_QUANT,
- .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
- .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
- .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
- .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
- .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
- .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
- .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
-
- .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
- .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
- .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
- .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
-
- .tuner_get_frequency = stb6100_get_frequency,
- .tuner_set_frequency = stb6100_set_frequency,
- .tuner_set_bandwidth = stb6100_set_bandwidth,
- .tuner_get_bandwidth = stb6100_get_bandwidth,
- .tuner_set_rfsiggain = NULL,
-
- /* helper for switching LED green/orange */
- .postproc = pctv45e_postproc
-};
-
-static struct stb6100_config stb6100_config = {
- .tuner_address = I2C_ADDR_STB6100,
- .refclock = 27000000
-};
-
-
-static struct i2c_algorithm pctv452e_i2c_algo = {
- .master_xfer = pctv452e_i2c_xfer,
- .functionality = pctv452e_i2c_func
-};
-
-static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
-{
- struct usb_device_id *id;
-
- a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
- &a->dev->i2c_adap);
- if (!a->fe_adap[0].fe)
- return -ENODEV;
- if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
- &a->dev->i2c_adap)) == 0)
- err("Cannot attach lnbp22\n");
-
- id = a->dev->desc->warm_ids[0];
- if (USB_VID_TECHNOTREND == id->idVendor
- && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
- /* Error ignored. */
- tt3650_ci_init(a);
-
- return 0;
-}
-
-static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
-{
- if (!a->fe_adap[0].fe)
- return -ENODEV;
- if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
- &a->dev->i2c_adap) == 0) {
- err("%s failed\n", __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static struct usb_device_id pctv452e_usb_table[] = {
- {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
- {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
- {USB_DEVICE(USB_VID_TECHNOTREND,
- USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
- {}
-};
-MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
-
-static struct dvb_usb_device_properties pctv452e_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
- .usb_ctrl = DEVICE_SPECIFIC,
-
- .size_of_priv = sizeof(struct pctv452e_state),
-
- .power_ctrl = pctv452e_power_ctrl,
-
- .rc.core = {
- .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .allowed_protos = RC_TYPE_UNKNOWN,
- .rc_query = pctv452e_rc_query,
- .rc_interval = 100,
- },
-
- .num_adapters = 1,
- .adapter = {{
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = pctv452e_frontend_attach,
- .tuner_attach = pctv452e_tuner_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_ISOC,
- .count = 4,
- .endpoint = 0x02,
- .u = {
- .isoc = {
- .framesperurb = 4,
- .framesize = 940,
- .interval = 1
- }
- }
- },
- } },
- } },
-
- .i2c_algo = &pctv452e_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
-
- .num_device_descs = 1,
- .devices = {
- { .name = "PCTV HDTV USB",
- .cold_ids = { NULL, NULL }, /* this is a warm only device */
- .warm_ids = { &pctv452e_usb_table[0], NULL }
- },
- { 0 },
- }
-};
-
-static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
- .usb_ctrl = DEVICE_SPECIFIC,
-
- .size_of_priv = sizeof(struct pctv452e_state),
-
- .power_ctrl = pctv452e_power_ctrl,
- .read_mac_address = pctv452e_read_mac_address,
-
- .rc.core = {
- .rc_codes = RC_MAP_TT_1500,
- .allowed_protos = RC_TYPE_UNKNOWN,
- .rc_query = pctv452e_rc_query,
- .rc_interval = 100,
- },
-
- .num_adapters = 1,
- .adapter = {{
- .num_frontends = 1,
- .fe = {{
- .frontend_attach = pctv452e_frontend_attach,
- .tuner_attach = pctv452e_tuner_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_ISOC,
- .count = 7,
- .endpoint = 0x02,
- .u = {
- .isoc = {
- .framesperurb = 4,
- .framesize = 940,
- .interval = 1
- }
- }
- },
-
- } },
- } },
-
- .i2c_algo = &pctv452e_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
-
- .num_device_descs = 2,
- .devices = {
- { .name = "Technotrend TT Connect S2-3600",
- .cold_ids = { NULL, NULL }, /* this is a warm only device */
- .warm_ids = { &pctv452e_usb_table[1], NULL }
- },
- { .name = "Technotrend TT Connect S2-3650-CI",
- .cold_ids = { NULL, NULL },
- .warm_ids = { &pctv452e_usb_table[2], NULL }
- },
- { 0 },
- }
-};
-
-static void pctv452e_usb_disconnect(struct usb_interface *intf)
-{
- struct dvb_usb_device *d = usb_get_intfdata(intf);
-
- tt3650_ci_uninit(d);
- dvb_usb_device_exit(intf);
-}
-
-static int pctv452e_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
- THIS_MODULE, NULL, adapter_nr))
- return 0;
-
- return -ENODEV;
-}
-
-static struct usb_driver pctv452e_usb_driver = {
- .name = "pctv452e",
- .probe = pctv452e_usb_probe,
- .disconnect = pctv452e_usb_disconnect,
- .id_table = pctv452e_usb_table,
-};
-
-module_usb_driver(pctv452e_usb_driver);
-
-MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
-MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
-MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
-MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
deleted file mode 100644
index 6bd0bd792437..000000000000
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ /dev/null
@@ -1,1428 +0,0 @@
-/*
- * Realtek RTL28xxU DVB USB driver
- *
- * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
- * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "rtl28xxu.h"
-
-#include "rtl2830.h"
-#include "rtl2832.h"
-
-#include "qt1010.h"
-#include "mt2060.h"
-#include "mxl5005s.h"
-#include "fc0012.h"
-#include "fc0013.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 rtl28xx_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 rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
-{
- return rtl28xx_wr_regs(d, reg, &val, 1);
-}
-
-static int rtl28xx_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 = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
- if (ret)
- goto err;
-
- /* enable as output GPIO0, GPIO2, GPIO4 */
- ret = rtl28xx_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.
- */
-
- /* demod needs some time to wake up */
- msleep(20);
-
- /* 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 struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
- .if_dvbt = 0,
- .tuner = TUNER_RTL2832_FC0012
-};
-
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
- .if_dvbt = 0,
- .tuner = TUNER_RTL2832_FC0013
-};
-
-static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
- int cmd, int arg)
-{
- int ret;
- u8 val;
-
- deb_info("%s cmd=%d arg=%d\n", __func__, cmd, arg);
- switch (cmd) {
- case FC_FE_CALLBACK_VHF_ENABLE:
- /* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
- if (ret)
- goto err;
-
- if (arg)
- val &= 0xbf; /* set GPIO6 low */
- else
- val |= 0x40; /* set GPIO6 high */
-
-
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
- if (ret)
- goto err;
- break;
- default:
- ret = -EINVAL;
- goto err;
- }
- return 0;
-
-err:
- err("%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-
-static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d,
- int cmd, int arg)
-{
- /* TODO implement*/
- return 0;
-}
-
-static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
-{
- struct rtl28xxu_priv *priv = d->priv;
-
- switch (priv->tuner) {
- case TUNER_RTL2832_FC0012:
- return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
-
- case TUNER_RTL2832_FC0013:
- return rtl2832u_fc0013_tuner_callback(d, cmd, arg);
- default:
- break;
- }
-
- return -ENODEV;
-}
-
-static int rtl2832u_frontend_callback(void *adapter_priv, int component,
- int cmd, int arg)
-{
- struct i2c_adapter *adap = adapter_priv;
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
-
- switch (component) {
- case DVB_FRONTEND_COMPONENT_TUNER:
- return rtl2832u_tuner_callback(d, cmd, arg);
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-
-
-
-static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
-{
- int ret;
- struct rtl28xxu_priv *priv = adap->dev->priv;
- struct rtl2832_config *rtl2832_config;
-
- u8 buf[2], val;
- /* 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 FC0012 tuner probe */
- struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
- /* for FC0013 tuner probe */
- struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
- /* for MT2266 tuner probe */
- struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
- /* for FC2580 tuner probe */
- struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
- /* for MT2063 tuner probe */
- struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
- /* for MAX3543 tuner probe */
- struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
- /* for TUA9001 tuner probe */
- struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
- /* for MXL5007T tuner probe */
- struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
- /* for E4000 tuner probe */
- struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
- /* for TDA18272 tuner probe */
- struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
-
- deb_info("%s:\n", __func__);
-
-
- ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_DIR, &val);
- if (ret)
- goto err;
-
- val &= 0xbf;
-
- ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, val);
- if (ret)
- goto err;
-
-
- /* enable as output GPIO3 and GPIO6*/
- ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_EN, &val);
- if (ret)
- goto err;
-
- val |= 0x48;
-
- ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, val);
- 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;
-
- priv->tuner = TUNER_NONE;
-
- /* check FC0012 ID register; reg=00 val=a1 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
- if (ret == 0 && buf[0] == 0xa1) {
- priv->tuner = TUNER_RTL2832_FC0012;
- rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
- info("%s: FC0012 tuner found", __func__);
- goto found;
- }
-
- /* check FC0013 ID register; reg=00 val=a3 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0013);
- if (ret == 0 && buf[0] == 0xa3) {
- priv->tuner = TUNER_RTL2832_FC0013;
- rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
- info("%s: FC0013 tuner found", __func__);
- goto found;
- }
-
- /* check MT2266 ID register; reg=00 val=85 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2266);
- if (ret == 0 && buf[0] == 0x85) {
- priv->tuner = TUNER_RTL2832_MT2266;
- /* TODO implement tuner */
- info("%s: MT2266 tuner found", __func__);
- goto unsupported;
- }
-
- /* 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;
- /* TODO implement tuner */
- info("%s: FC2580 tuner found", __func__);
- goto unsupported;
- }
-
- /* check MT2063 ID register; reg=00 val=9e || 9c */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2063);
- if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
- priv->tuner = TUNER_RTL2832_MT2063;
- /* TODO implement tuner */
- info("%s: MT2063 tuner found", __func__);
- goto unsupported;
- }
-
- /* check MAX3543 ID register; reg=00 val=38 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_max3543);
- if (ret == 0 && buf[0] == 0x38) {
- priv->tuner = TUNER_RTL2832_MAX3543;
- /* TODO implement tuner */
- info("%s: MAX3534 tuner found", __func__);
- goto unsupported;
- }
-
- /* check TUA9001 ID register; reg=7e val=2328 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_tua9001);
- if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
- priv->tuner = TUNER_RTL2832_TUA9001;
- /* TODO implement tuner */
- info("%s: TUA9001 tuner found", __func__);
- goto unsupported;
- }
-
- /* check MXL5007R ID register; reg=d9 val=14 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_mxl5007t);
- if (ret == 0 && buf[0] == 0x14) {
- priv->tuner = TUNER_RTL2832_MXL5007T;
- /* TODO implement tuner */
- info("%s: MXL5007T tuner found", __func__);
- goto unsupported;
- }
-
- /* check E4000 ID register; reg=02 val=40 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_e4000);
- if (ret == 0 && buf[0] == 0x40) {
- priv->tuner = TUNER_RTL2832_E4000;
- /* TODO implement tuner */
- info("%s: E4000 tuner found", __func__);
- goto unsupported;
- }
-
- /* check TDA18272 ID register; reg=00 val=c760 */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_tda18272);
- if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
- priv->tuner = TUNER_RTL2832_TDA18272;
- /* TODO implement tuner */
- info("%s: TDA18272 tuner found", __func__);
- goto unsupported;
- }
-
-unsupported:
- /* close demod I2C gate */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
- if (ret)
- goto err;
-
- /* tuner not found */
- deb_info("No compatible tuner found");
- ret = -ENODEV;
- return ret;
-
-found:
- /* close demod I2C gate */
- ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
- if (ret)
- goto err;
-
- /* attach demodulator */
- adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe == NULL) {
- ret = -ENODEV;
- goto err;
- }
-
- /* set fe callbacks */
- adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
-
- 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_FC0012:
- fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
-
- /* since fc0012 includs reading the signal strength delegate
- * that to the tuner driver */
- adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0].
- fe->ops.tuner_ops.get_rf_strength;
- return 0;
- break;
- case TUNER_RTL2832_FC0013:
- fe = dvb_attach(fc0013_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
-
- /* fc0013 also supports signal strength reading */
- adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0]
- .fe->ops.tuner_ops.get_rf_strength;
- return 0;
- 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 rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
-{
- int ret;
- u8 buf[2], gpio;
-
- deb_info("%s: onoff=%d\n", __func__, onoff);
-
- ret = rtl28xx_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 = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
- if (ret)
- goto err;
-
- ret = rtl28xx_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 rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
-{
- int ret;
- u8 buf[2];
-
- deb_info("%s: onoff=%d\n", __func__, onoff);
-
-
- if (onoff) {
- buf[0] = 0x00;
- buf[1] = 0x00;
- } else {
- buf[0] = 0x10; /* stall EPA */
- buf[1] = 0x02; /* reset EPA */
- }
-
- ret = rtl28xx_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 rtl2831u_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 = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
- if (ret)
- goto err;
-
- /* tuner power, read GPIOs */
- ret = rtl28xx_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 = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
- if (ret)
- goto err;
-
- /* tuner power, write GPIOs */
- ret = rtl28xx_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 rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
- int ret;
- u8 val;
-
- deb_info("%s: onoff=%d\n", __func__, onoff);
-
- if (onoff) {
- /* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
- if (ret)
- goto err;
-
- val |= 0x08;
- val &= 0xef;
-
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
- if (ret)
- goto err;
-
- /* demod_ctl_1 */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
- if (ret)
- goto err;
-
- val &= 0xef;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
- if (ret)
- goto err;
-
- /* demod control */
- /* PLL enable */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- /* bit 7 to 1 */
- val |= 0x80;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- if (ret)
- goto err;
-
- /* demod HW reset */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
- /* bit 5 to 0 */
- val &= 0xdf;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- if (ret)
- goto err;
-
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- val |= 0x20;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- if (ret)
- goto err;
-
- mdelay(5);
-
- /*enable ADC_Q and ADC_I */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- val |= 0x48;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- if (ret)
- goto err;
-
-
- } else {
- /* demod_ctl_1 */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
- if (ret)
- goto err;
-
- val |= 0x0c;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
- if (ret)
- goto err;
-
- /* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
- if (ret)
- goto err;
-
- val |= 0x10;
-
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
- if (ret)
- goto err;
-
- /* demod control */
- ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
- if (ret)
- goto err;
-
- val &= 0x37;
-
- ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
- 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 = rtl28xx_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 = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
- if (ret)
- goto err;
-
- /* repeated intentionally to avoid extra keypress */
- ret = rtl28xx_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 = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
- rc_nec_tab[i].val);
- if (ret)
- goto err;
- }
- priv->rc_active = true;
- }
-
- ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
- if (ret)
- goto err;
-
- if (buf[0] != 0x83)
- goto exit;
-
- ret = rtl28xx_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 = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
- ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
- ret = rtl28xx_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,
- RTL2832U_0CCD_00A9,
- RTL2832U_1F4D_B803,
- RTL2832U_0CCD_00B3,
-};
-
-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 */
- [RTL2832U_0CCD_00A9] = {
- USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1)},
- [RTL2832U_1F4D_B803] = {
- USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT)},
- [RTL2832U_0CCD_00B3] = {
- USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK)},
- {} /* 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 = rtl2831u_streaming_ctrl,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x81,
- .u = {
- .bulk = {
- .buffersize = 8*512,
- }
- }
- }
- }
- }
- }
- },
-
- .power_ctrl = rtl2831u_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 = rtl2832u_streaming_ctrl,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x81,
- .u = {
- .bulk = {
- .buffersize = 8*512,
- }
- }
- }
- }
- }
- }
- },
-
- .power_ctrl = rtl2832u_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 = 3,
- .devices = {
- {
- .name = "Terratec Cinergy T Stick Black",
- .warm_ids = {
- &rtl28xxu_table[RTL2832U_0CCD_00A9],
- },
- },
- {
- .name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T",
- .warm_ids = {
- &rtl28xxu_table[RTL2832U_1F4D_B803],
- },
- },
- {
- .name = "NOXON DAB/DAB+ USB dongle",
- .warm_ids = {
- &rtl28xxu_table[RTL2832U_0CCD_00B3],
- },
- },
- }
- },
-
-};
-
-static int rtl28xxu_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- int ret, i;
- u8 val;
- int properties_count = ARRAY_SIZE(rtl28xxu_properties);
- struct dvb_usb_device *d;
- struct usb_device *udev;
- bool found;
-
- deb_info("%s: interface=%d\n", __func__,
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
- return 0;
-
- /* Dynamic USB ID support. Replaces first device ID with current one .*/
- udev = interface_to_usbdev(intf);
-
- for (i = 0, found = false; i < ARRAY_SIZE(rtl28xxu_table) - 1; i++) {
- if (rtl28xxu_table[i].idVendor ==
- le16_to_cpu(udev->descriptor.idVendor) &&
- rtl28xxu_table[i].idProduct ==
- le16_to_cpu(udev->descriptor.idProduct)) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- deb_info("%s: using dynamic ID %04x:%04x\n", __func__,
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
- rtl28xxu_properties[0].devices[0].warm_ids[0]->idVendor =
- le16_to_cpu(udev->descriptor.idVendor);
- rtl28xxu_properties[0].devices[0].warm_ids[0]->idProduct =
- le16_to_cpu(udev->descriptor.idProduct);
- }
-
- 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 = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
- if (ret)
- goto err;
-
- /* enable DMA and Full Packet Mode*/
- val |= 0x09;
- ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
- if (ret)
- goto err;
-
- /* set EPA maximum packet size to 0x0200 */
- ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
- if (ret)
- goto err;
-
- /* change EPA FIFO length */
- ret = rtl28xx_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_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h
deleted file mode 100644
index 90f3bb4f4c0e..000000000000
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * 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/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
deleted file mode 100644
index 357b3aab186b..000000000000
--- a/drivers/media/dvb/firewire/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
-
-firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
-firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
deleted file mode 100644
index a08c2152d0ee..000000000000
--- a/drivers/media/dvb/frontends/Kconfig
+++ /dev/null
@@ -1,756 +0,0 @@
-config DVB_FE_CUSTOMISE
- bool "Customise the frontend modules to build"
- depends on DVB_CORE
- depends on EXPERT
- default y if EXPERT
- help
- This allows the user to select/deselect frontend drivers for their
- hardware from the build.
-
- Use this option with care as deselecting frontends which are in fact
- necessary will result in DVB devices which cannot be tuned due to lack
- of driver support.
-
- If unsure say N.
-
-menu "Customise DVB Frontends"
- visible if DVB_FE_CUSTOMISE
-
-comment "Multistandard (satellite) frontends"
- depends on DVB_CORE
-
-config DVB_STB0899
- tristate "STB0899 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
- to support this demodulator based frontends
-
-config DVB_STB6100
- tristate "STB6100 based tuners"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A Silicon tuner from ST used in conjunction with the STB0899
- demodulator. Say Y when you want to support this tuner.
-
-config DVB_STV090x
- tristate "STV0900/STV0903(A/B) based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
- Say Y when you want to support these frontends.
-
-config DVB_STV6110x
- tristate "STV6110/(A) based tuners"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A Silicon tuner that supports DVB-S and DVB-S2 modes
-
-comment "Multistandard (cable + terrestrial) frontends"
- depends on DVB_CORE
-
-config DVB_DRXK
- tristate "Micronas DRXK based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- Micronas DRX-K DVB-C/T demodulator.
-
- Say Y when you want to support this frontend.
-
-config DVB_TDA18271C2DD
- tristate "NXP TDA18271C2 silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- NXP TDA18271 silicon tuner.
-
- Say Y when you want to support this tuner.
-
-comment "DVB-S (satellite) frontends"
- depends on DVB_CORE
-
-config DVB_CX24110
- tristate "Conexant CX24110 based"
- 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.
-
-config DVB_CX24123
- tristate "Conexant CX24123 based"
- 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.
-
-config DVB_MT312
- tristate "Zarlink VP310/MT312/ZL10313 based"
- 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.
-
-config DVB_ZL10036
- tristate "Zarlink ZL10036 silicon 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.
-
-config DVB_ZL10039
- tristate "Zarlink ZL10039 silicon 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.
-
-config DVB_S5H1420
- tristate "Samsung S5H1420 based"
- 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.
-
-config DVB_STV0288
- tristate "ST STV0288 based"
- 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.
-
-config DVB_STB6000
- tristate "ST STB6000 silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_STV0299
- tristate "ST STV0299 based"
- 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.
-
-config DVB_STV6110
- tristate "ST STV6110 silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_STV0900
- tristate "ST STV0900 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
-
-config DVB_TDA8083
- tristate "Philips TDA8083 based"
- 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.
-
-config DVB_TDA10086
- tristate "Philips TDA10086 based"
- 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.
-
-config DVB_TDA8261
- tristate "Philips TDA8261 based"
- 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.
-
-config DVB_VES1X93
- tristate "VLSI VES1893 or VES1993 based"
- 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.
-
-config DVB_TUNER_ITD1000
- tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
- 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.
-
-config DVB_TUNER_CX24113
- tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
- 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.
-
-
-config DVB_TDA826X
- tristate "Philips TDA826X silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TUA6100
- tristate "Infineon TUA6100 PLL"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S PLL chip.
-
-config DVB_CX24116
- tristate "Conexant CX24116 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
-
-config DVB_SI21XX
- tristate "Silicon Labs SI21XX based"
- 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.
-
-config DVB_DS3000
- tristate "Montage Tehnology DS3000 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
-
-config DVB_MB86A16
- tristate "Fujitsu MB86A16 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S/DSS Direct Conversion reveiver.
- Say Y when you want to support this frontend.
-
-config DVB_TDA10071
- tristate "NXP TDA10071"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- Say Y when you want to support this frontend.
-
-comment "DVB-T (terrestrial) frontends"
- depends on DVB_CORE
-
-config DVB_SP8870
- tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
- This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_SP887X
- tristate "Spase sp887x based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
- This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_CX22700
- tristate "Conexant CX22700 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_CX22702
- tristate "Conexant cx22702 demodulator (OFDM)"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_S5H1432
- tristate "Samsung s5h1432 demodulator (OFDM)"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_DRXD
- tristate "Micronas DRXD driver"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
- Note: this driver was based on vendor driver reference code (released
- under the GPL) as opposed to the existing drx397xd driver, which
- was written via reverse engineering.
-
-config DVB_L64781
- tristate "LSI L64781"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA1004X
- tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
- This driver needs external firmware. Please use the commands
- "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
- "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- download/extract them, and then copy them to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_NXT6000
- tristate "NxtWave Communications NXT6000 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_MT352
- tristate "Zarlink MT352 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_ZL10353
- tristate "Zarlink ZL10353 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_DIB3000MB
- tristate "DiBcom 3000M-B"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Designed for mobile usage. Say Y when you want
- to support this frontend.
-
-config DVB_DIB3000MC
- tristate "DiBcom 3000P/M-C"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Designed for mobile usage. Say Y when you want
- to support this frontend.
-
-config DVB_DIB7000M
- tristate "DiBcom 7000MA/MB/PA/PB/MC"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Designed for mobile usage. Say Y when you want
- to support this frontend.
-
-config DVB_DIB7000P
- tristate "DiBcom 7000PC"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Designed for mobile usage. Say Y when you want
- to support this frontend.
-
-config DVB_DIB9000
- tristate "DiBcom 9000"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Designed for mobile usage. Say Y when you want
- to support this frontend.
-
-config DVB_TDA10048
- tristate "Philips TDA10048HN based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
-config DVB_AF9013
- tristate "Afatech AF9013 demodulator"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- Say Y when you want to support this frontend.
-
-config DVB_EC100
- tristate "E3C EC100"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- 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
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T/C tuner module. Say Y when you want to support this frontend.
-
-config DVB_CXD2820R
- tristate "Sony CXD2820R"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- 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.
-
-config DVB_RTL2832
- tristate "Realtek RTL2832 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
-
-config DVB_VES1820
- tristate "VLSI VES1820 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA10021
- tristate "Philips TDA10021 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA10023
- tristate "Philips TDA10023 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-C tuner module. Say Y when you want to support this frontend.
-
-config DVB_STV0297
- tristate "ST STV0297 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-C tuner module. Say Y when you want to support this frontend.
-
-comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
- depends on DVB_CORE
-
-config DVB_NXT200X
- tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
- This driver needs external firmware. Please use the commands
- "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
- "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
- download/extract them, and then copy them to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_OR51211
- tristate "Oren OR51211 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
-
- This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- download it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
-config DVB_OR51132
- tristate "Oren OR51132 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
- This driver needs external firmware. Please use the commands
- "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
- "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
- download firmwares for 8VSB and QAM64/256, respectively. Copy them to
- /usr/lib/hotplug/firmware or /lib/firmware (depending on
- configuration of firmware hotplug).
-
-config DVB_BCM3510
- tristate "Broadcom BCM3510"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
- support this frontend.
-
-config DVB_LGDT330X
- tristate "LG Electronics LGDT3302/LGDT3303 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
-config DVB_LGDT3305
- tristate "LG Electronics LGDT3304 and LGDT3305 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
-config DVB_LG2160
- tristate "LG Electronics LG216x based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC/MH demodulator module. Say Y when you want
- to support this frontend.
-
-config DVB_S5H1409
- tristate "Samsung S5H1409 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
-config DVB_AU8522
- depends on I2C
- tristate
-
-config DVB_AU8522_DTV
- tristate "Auvitek AU8522 based DTV demod"
- depends on DVB_CORE && I2C
- select DVB_AU8522
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
- you want to enable DTV demodulation support for this frontend.
-
-config DVB_AU8522_V4L
- tristate "Auvitek AU8522 based ATV demod"
- depends on VIDEO_V4L2 && I2C
- select DVB_AU8522
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
- you want to enable ATV demodulation support for this frontend.
-
-config DVB_S5H1411
- tristate "Samsung S5H1411 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
-comment "ISDB-T (terrestrial) frontends"
- depends on DVB_CORE
-
-config DVB_S921
- tristate "Sharp S921 frontend"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
- Say Y when you want to support this frontend.
-
-config DVB_DIB8000
- tristate "DiBcom 8000MB/MC"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
- Say Y when you want to support this frontend.
-
-config DVB_MB86A20S
- tristate "Fujitsu mb86a20s"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
- Say Y when you want to support this frontend.
-
-comment "Digital terrestrial only tuners/PLL"
- depends on DVB_CORE
-
-config DVB_PLL
- tristate "Generic I2C PLL based tuners"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- This module drives a number of tuners based on PLL chips with a
- common I2C interface. Say Y when you want to support these tuners.
-
-config DVB_TUNER_DIB0070
- tristate "DiBcom DiB0070 silicon base-band tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner DiB0070 from DiBcom.
- This device is only used inside a SiP called together with a
- demodulator for now.
-
-config DVB_TUNER_DIB0090
- tristate "DiBcom DiB0090 silicon base-band tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner DiB0090 from DiBcom.
- This device is only used inside a SiP called together with a
- demodulator for now.
-
-comment "SEC control devices for DVB-S"
- depends on DVB_CORE
-
-config DVB_LNBP21
- tristate "LNBP21/LNBH24 SEC controllers"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An SEC control chips.
-
-config DVB_LNBP22
- tristate "LNBP22 SEC controllers"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- LNB power supply and control voltage
- regulator chip with step-up converter
- and I2C interface.
- Say Y when you want to support this chip.
-
-config DVB_ISL6405
- tristate "ISL6405 SEC controller"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An SEC control chip.
-
-config DVB_ISL6421
- tristate "ISL6421 SEC controller"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An SEC control chip.
-
-config DVB_ISL6423
- tristate "ISL6423 SEC controller"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A SEC controller chip from Intersil
-
-config DVB_A8293
- tristate "Allegro A8293"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
-
-config DVB_LGS8GL5
- tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_LGS8GXX
- tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
- depends on DVB_CORE && I2C
- select FW_LOADER
- default m if DVB_FE_CUSTOMISE
- help
- A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_ATBM8830
- tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DMB-TH tuner module. Say Y when you want to support this frontend.
-
-config DVB_TDA665x
- tristate "TDA665x tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- Support for tuner modules based on Philips TDA6650/TDA6651 chips.
- Say Y when you want to support this chip.
-
- Currently supported tuners:
- * Panasonic ENV57H12D5 (ET-50DT)
-
-config DVB_IX2505V
- tristate "Sharp IX2505V silicon 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.
-
-config DVB_IT913X_FE
- tristate "it913x frontend and it9137 tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- 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.
-
-config DVB_AF9033
- tristate "Afatech AF9033 DVB-T demodulator"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
-
-comment "Tools to develop new frontends"
-
-config DVB_DUMMY_FE
- tristate "Dummy frontend driver"
- default n
-endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
deleted file mode 100644
index 185bb8b51952..000000000000
--- a/drivers/media/dvb/frontends/Makefile
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-# Makefile for the kernel DVB frontend device drivers.
-#
-
-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
-drxd-objs = drxd_firm.o drxd_hard.o
-cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
-drxk-objs := drxk_hard.o
-
-obj-$(CONFIG_DVB_PLL) += dvb-pll.o
-obj-$(CONFIG_DVB_STV0299) += stv0299.o
-obj-$(CONFIG_DVB_STB0899) += stb0899.o
-obj-$(CONFIG_DVB_STB6100) += stb6100.o
-obj-$(CONFIG_DVB_SP8870) += sp8870.o
-obj-$(CONFIG_DVB_CX22700) += cx22700.o
-obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
-obj-$(CONFIG_DVB_CX24110) += cx24110.o
-obj-$(CONFIG_DVB_TDA8083) += tda8083.o
-obj-$(CONFIG_DVB_L64781) += l64781.o
-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
-obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
-obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
-obj-$(CONFIG_DVB_MT312) += mt312.o
-obj-$(CONFIG_DVB_VES1820) += ves1820.o
-obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
-obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
-obj-$(CONFIG_DVB_SP887X) += sp887x.o
-obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
-obj-$(CONFIG_DVB_MT352) += mt352.o
-obj-$(CONFIG_DVB_ZL10036) += zl10036.o
-obj-$(CONFIG_DVB_ZL10039) += zl10039.o
-obj-$(CONFIG_DVB_ZL10353) += zl10353.o
-obj-$(CONFIG_DVB_CX22702) += cx22702.o
-obj-$(CONFIG_DVB_DRXD) += drxd.o
-obj-$(CONFIG_DVB_TDA10021) += tda10021.o
-obj-$(CONFIG_DVB_TDA10023) += tda10023.o
-obj-$(CONFIG_DVB_STV0297) += stv0297.o
-obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
-obj-$(CONFIG_DVB_OR51211) += or51211.o
-obj-$(CONFIG_DVB_OR51132) += or51132.o
-obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
-obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
-obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
-obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
-obj-$(CONFIG_DVB_LG2160) += lg2160.o
-obj-$(CONFIG_DVB_CX24123) += cx24123.o
-obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
-obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
-obj-$(CONFIG_DVB_ISL6405) += isl6405.o
-obj-$(CONFIG_DVB_ISL6421) += isl6421.o
-obj-$(CONFIG_DVB_TDA10086) += tda10086.o
-obj-$(CONFIG_DVB_TDA826X) += tda826x.o
-obj-$(CONFIG_DVB_TDA8261) += tda8261.o
-obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
-obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
-obj-$(CONFIG_DVB_TUA6100) += tua6100.o
-obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
-obj-$(CONFIG_DVB_AU8522) += au8522_common.o
-obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
-obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
-obj-$(CONFIG_DVB_TDA10048) += tda10048.o
-obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
-obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
-obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
-obj-$(CONFIG_DVB_TDA665x) += tda665x.o
-obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
-obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
-obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
-obj-$(CONFIG_DVB_AF9013) += af9013.o
-obj-$(CONFIG_DVB_CX24116) += cx24116.o
-obj-$(CONFIG_DVB_SI21XX) += si21xx.o
-obj-$(CONFIG_DVB_STV0288) += stv0288.o
-obj-$(CONFIG_DVB_STB6000) += stb6000.o
-obj-$(CONFIG_DVB_S921) += s921.o
-obj-$(CONFIG_DVB_STV6110) += stv6110.o
-obj-$(CONFIG_DVB_STV0900) += stv0900.o
-obj-$(CONFIG_DVB_STV090x) += stv090x.o
-obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
-obj-$(CONFIG_DVB_ISL6423) += isl6423.o
-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
-obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
-obj-$(CONFIG_DVB_STV0367) += stv0367.o
-obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
-obj-$(CONFIG_DVB_DRXK) += drxk.o
-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_RTL2832) += rtl2832.o
-obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
-obj-$(CONFIG_DVB_AF9033) += af9033.o
-
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
deleted file mode 100644
index a2261ea2cf82..000000000000
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
- * ATBM8830, ATBM8831
- *
- * Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <asm/div64.h>
-#include "dvb_frontend.h"
-
-#include "atbm8830.h"
-#include "atbm8830_priv.h"
-
-#define dprintk(args...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "atbm8830: " args); \
- } while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
-{
- int ret = 0;
- u8 dev_addr;
- u8 buf1[] = { reg >> 8, reg & 0xFF };
- u8 buf2[] = { data };
- struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
- struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
-
- dev_addr = priv->config->demod_address;
- msg1.addr = dev_addr;
- msg2.addr = dev_addr;
-
- if (debug >= 2)
- dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
-
- ret = i2c_transfer(priv->i2c, &msg1, 1);
- if (ret != 1)
- return -EIO;
-
- ret = i2c_transfer(priv->i2c, &msg2, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
-static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
-{
- int ret;
- u8 dev_addr;
-
- u8 buf1[] = { reg >> 8, reg & 0xFF };
- u8 buf2[] = { 0 };
- struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
- struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
-
- dev_addr = priv->config->demod_address;
- msg1.addr = dev_addr;
- msg2.addr = dev_addr;
-
- ret = i2c_transfer(priv->i2c, &msg1, 1);
- if (ret != 1) {
- dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
- return -EIO;
- }
-
- ret = i2c_transfer(priv->i2c, &msg2, 1);
- if (ret != 1)
- return -EIO;
-
- *p_data = buf2[0];
- if (debug >= 2)
- dprintk("%s: reg=0x%04X, data=0x%02X\n",
- __func__, reg, buf2[0]);
-
- return 0;
-}
-
-/* Lock register latch so that multi-register read is atomic */
-static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
-{
- return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
-}
-
-static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
-{
- u32 val;
- u64 t;
-
- /* 0x100000 * freq / 30.4MHz */
- t = (u64)0x100000 * freq;
- do_div(t, 30400);
- val = t;
-
- atbm8830_write_reg(priv, REG_OSC_CLK, val);
- atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
- atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
-
- return 0;
-}
-
-static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
-{
-
- u32 fs = priv->config->osc_clk_freq;
- u64 t;
- u32 val;
- u8 dat;
-
- if (freq != 0) {
- /* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
- t = (u64) 2 * 31416 * (freq - fs);
- t <<= 22;
- do_div(t, fs);
- do_div(t, 1000);
- val = t;
-
- atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
- atbm8830_write_reg(priv, REG_IF_FREQ, val);
- atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
- atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
-
- atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
- dat &= 0xFC;
- atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
- } else {
- /* Zero IF */
- atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
-
- atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
- dat &= 0xFC;
- dat |= 0x02;
- atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
-
- if (priv->config->zif_swap_iq)
- atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
- else
- atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
- }
-
- return 0;
-}
-
-static int is_locked(struct atbm_state *priv, u8 *locked)
-{
- u8 status;
-
- atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
-
- if (locked != NULL)
- *locked = (status == 1);
- return 0;
-}
-
-static int set_agc_config(struct atbm_state *priv,
- u8 min, u8 max, u8 hold_loop)
-{
- /* no effect if both min and max are zero */
- if (!min && !max)
- return 0;
-
- atbm8830_write_reg(priv, REG_AGC_MIN, min);
- atbm8830_write_reg(priv, REG_AGC_MAX, max);
- atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
-
- return 0;
-}
-
-static int set_static_channel_mode(struct atbm_state *priv)
-{
- int i;
-
- for (i = 0; i < 5; i++)
- atbm8830_write_reg(priv, 0x099B + i, 0x08);
-
- atbm8830_write_reg(priv, 0x095B, 0x7F);
- atbm8830_write_reg(priv, 0x09CB, 0x01);
- atbm8830_write_reg(priv, 0x09CC, 0x7F);
- atbm8830_write_reg(priv, 0x09CD, 0x7F);
- atbm8830_write_reg(priv, 0x0E01, 0x20);
-
- /* For single carrier */
- atbm8830_write_reg(priv, 0x0B03, 0x0A);
- atbm8830_write_reg(priv, 0x0935, 0x10);
- atbm8830_write_reg(priv, 0x0936, 0x08);
- atbm8830_write_reg(priv, 0x093E, 0x08);
- atbm8830_write_reg(priv, 0x096E, 0x06);
-
- /* frame_count_max0 */
- atbm8830_write_reg(priv, 0x0B09, 0x00);
- /* frame_count_max1 */
- atbm8830_write_reg(priv, 0x0B0A, 0x08);
-
- return 0;
-}
-
-static int set_ts_config(struct atbm_state *priv)
-{
- const struct atbm8830_config *cfg = priv->config;
-
- /*Set parallel/serial ts mode*/
- atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
- atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
- /*Set ts sampling edge*/
- atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
- cfg->ts_sampling_edge ? 1 : 0);
- /*Set ts clock freerun*/
- atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
- cfg->ts_clk_gated ? 0 : 1);
-
- return 0;
-}
-
-static int atbm8830_init(struct dvb_frontend *fe)
-{
- struct atbm_state *priv = fe->demodulator_priv;
- const struct atbm8830_config *cfg = priv->config;
-
- /*Set oscillator frequency*/
- set_osc_freq(priv, cfg->osc_clk_freq);
-
- /*Set IF frequency*/
- set_if_freq(priv, cfg->if_freq);
-
- /*Set AGC Config*/
- set_agc_config(priv, cfg->agc_min, cfg->agc_max,
- cfg->agc_hold_loop);
-
- /*Set static channel mode*/
- set_static_channel_mode(priv);
-
- set_ts_config(priv);
- /*Turn off DSP reset*/
- atbm8830_write_reg(priv, 0x000A, 0);
-
- /*SW version test*/
- atbm8830_write_reg(priv, 0x020C, 11);
-
- /* Run */
- atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
-
- return 0;
-}
-
-
-static void atbm8830_release(struct dvb_frontend *fe)
-{
- struct atbm_state *state = fe->demodulator_priv;
- dprintk("%s\n", __func__);
-
- kfree(state);
-}
-
-static int atbm8830_set_fe(struct dvb_frontend *fe)
-{
- struct atbm_state *priv = fe->demodulator_priv;
- int i;
- u8 locked = 0;
- dprintk("%s\n", __func__);
-
- /* set frequency */
- 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);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- /* start auto lock */
- for (i = 0; i < 10; i++) {
- mdelay(100);
- dprintk("Try %d\n", i);
- is_locked(priv, &locked);
- if (locked != 0) {
- dprintk("ATBM8830 locked!\n");
- break;
- }
- }
-
- return 0;
-}
-
-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 */
- c->inversion = INVERSION_OFF;
-
- /* bandwidth */
- c->bandwidth_hz = 8000000;
-
- c->code_rate_HP = FEC_AUTO;
- c->code_rate_LP = FEC_AUTO;
-
- c->modulation = QAM_AUTO;
-
- /* transmission mode */
- c->transmission_mode = TRANSMISSION_MODE_AUTO;
-
- /* guard interval */
- c->guard_interval = GUARD_INTERVAL_AUTO;
-
- /* hierarchy */
- c->hierarchy = HIERARCHY_NONE;
-
- return 0;
-}
-
-static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *fesettings)
-{
- fesettings->min_delay_ms = 0;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- return 0;
-}
-
-static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
-{
- struct atbm_state *priv = fe->demodulator_priv;
- u8 locked = 0;
- u8 agc_locked = 0;
-
- dprintk("%s\n", __func__);
- *fe_status = 0;
-
- is_locked(priv, &locked);
- if (locked) {
- *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- }
- dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
-
- atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
- dprintk("AGC Lock: %d\n", agc_locked);
-
- return 0;
-}
-
-static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct atbm_state *priv = fe->demodulator_priv;
- u32 frame_err;
- u8 t;
-
- dprintk("%s\n", __func__);
-
- atbm8830_reglatch_lock(priv, 1);
-
- atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
- frame_err = t & 0x7F;
- frame_err <<= 8;
- atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
- frame_err |= t;
-
- atbm8830_reglatch_lock(priv, 0);
-
- *ber = frame_err * 100 / 32767;
-
- dprintk("%s: ber=0x%x\n", __func__, *ber);
- return 0;
-}
-
-static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
-{
- struct atbm_state *priv = fe->demodulator_priv;
- u32 pwm;
- u8 t;
-
- dprintk("%s\n", __func__);
- atbm8830_reglatch_lock(priv, 1);
-
- atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
- pwm = t & 0x03;
- pwm <<= 8;
- atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
- pwm |= t;
-
- atbm8830_reglatch_lock(priv, 0);
-
- dprintk("AGC PWM = 0x%02X\n", pwm);
- pwm = 0x400 - pwm;
-
- *signal = pwm * 0x10000 / 0x400;
-
- return 0;
-}
-
-static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- dprintk("%s\n", __func__);
- *snr = 0;
- return 0;
-}
-
-static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- dprintk("%s\n", __func__);
- *ucblocks = 0;
- return 0;
-}
-
-static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct atbm_state *priv = fe->demodulator_priv;
-
- return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
-}
-
-static struct dvb_frontend_ops atbm8830_ops = {
- .delsys = { SYS_DMBTH },
- .info = {
- .name = "AltoBeam ATBM8830/8831 DMB-TH",
- .frequency_min = 474000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 10000,
- .caps =
- FE_CAN_FEC_AUTO |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO
- },
-
- .release = atbm8830_release,
-
- .init = atbm8830_init,
- .sleep = NULL,
- .write = NULL,
- .i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
-
- .set_frontend = atbm8830_set_fe,
- .get_frontend = atbm8830_get_fe,
- .get_tune_settings = atbm8830_get_tune_settings,
-
- .read_status = atbm8830_read_status,
- .read_ber = atbm8830_read_ber,
- .read_signal_strength = atbm8830_read_signal_strength,
- .read_snr = atbm8830_read_snr,
- .read_ucblocks = atbm8830_read_ucblocks,
-};
-
-struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
- struct i2c_adapter *i2c)
-{
- struct atbm_state *priv = NULL;
- u8 data = 0;
-
- dprintk("%s()\n", __func__);
-
- if (config == NULL || i2c == NULL)
- return NULL;
-
- priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
- if (priv == NULL)
- goto error_out;
-
- priv->config = config;
- priv->i2c = i2c;
-
- /* check if the demod is there */
- if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
- dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
- __func__, priv->config->demod_address);
- goto error_out;
- }
- dprintk("atbm8830 chip id: 0x%02X\n", data);
-
- memcpy(&priv->frontend.ops, &atbm8830_ops,
- sizeof(struct dvb_frontend_ops));
- priv->frontend.demodulator_priv = priv;
-
- atbm8830_init(&priv->frontend);
-
- atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
-
- return &priv->frontend;
-
-error_out:
- dprintk("%s() error_out\n", __func__);
- kfree(priv);
- return NULL;
-
-}
-EXPORT_SYMBOL(atbm8830_attach);
-
-MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
-MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c
deleted file mode 100644
index 5cfe151ee394..000000000000
--- a/drivers/media/dvb/frontends/au8522_common.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- Auvitek AU8522 QAM/8VSB demodulator driver
-
- Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
- Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
- Copyright (C) 2005-2008 Auvitek International, Ltd.
- Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
-
- 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/i2c.h>
-#include "dvb_frontend.h"
-#include "au8522_priv.h"
-
-MODULE_LICENSE("GPL");
-
-static int debug;
-
-#define dprintk(arg...)\
- do { if (debug)\
- printk(arg);\
- } while (0)
-
-/* Despite the name "hybrid_tuner", the framework works just as well for
- hybrid demodulators as well... */
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(au8522_list_mutex);
-
-/* 16 bit registers, 8 bit values */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
-{
- int ret;
- u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
-
- struct i2c_msg msg = { .addr = state->config->demod_address,
- .flags = 0, .buf = buf, .len = 3 };
-
- ret = i2c_transfer(state->i2c, &msg, 1);
-
- if (ret != 1)
- printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
- "ret == %i)\n", __func__, reg, data, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-EXPORT_SYMBOL(au8522_writereg);
-
-u8 au8522_readreg(struct au8522_state *state, u16 reg)
-{
- int ret;
- u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
- u8 b1[] = { 0 };
-
- struct i2c_msg msg[] = {
- { .addr = state->config->demod_address, .flags = 0,
- .buf = b0, .len = 2 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD,
- .buf = b1, .len = 1 } };
-
- ret = i2c_transfer(state->i2c, msg, 2);
-
- if (ret != 2)
- printk(KERN_ERR "%s: readreg error (ret == %i)\n",
- __func__, ret);
- return b1[0];
-}
-EXPORT_SYMBOL(au8522_readreg);
-
-int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct au8522_state *state = fe->demodulator_priv;
-
- dprintk("%s(%d)\n", __func__, enable);
-
- if (state->operational_mode == AU8522_ANALOG_MODE) {
- /* We're being asked to manage the gate even though we're
- not in digital mode. This can occur if we get switched
- over to analog mode before the dvb_frontend kernel thread
- has completely shutdown */
- return 0;
- }
-
- if (enable)
- return au8522_writereg(state, 0x106, 1);
- else
- return au8522_writereg(state, 0x106, 0);
-}
-EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
-
-/* Reset the demod hardware and reset all of the configuration registers
- to a default state. */
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
- u8 client_address)
-{
- int ret;
-
- mutex_lock(&au8522_list_mutex);
- ret = hybrid_tuner_request_state(struct au8522_state, (*state),
- hybrid_tuner_instance_list,
- i2c, client_address, "au8522");
- mutex_unlock(&au8522_list_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(au8522_get_state);
-
-void au8522_release_state(struct au8522_state *state)
-{
- mutex_lock(&au8522_list_mutex);
- if (state != NULL)
- hybrid_tuner_release_state(state);
- mutex_unlock(&au8522_list_mutex);
-}
-EXPORT_SYMBOL(au8522_release_state);
-
-static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
-{
- struct au8522_led_config *led_config = state->config->led_cfg;
- u8 val;
-
- /* bail out if we can't control an LED */
- if (!led_config || !led_config->gpio_output ||
- !led_config->gpio_output_enable || !led_config->gpio_output_disable)
- return 0;
-
- val = au8522_readreg(state, 0x4000 |
- (led_config->gpio_output & ~0xc000));
- if (onoff) {
- /* enable GPIO output */
- val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
- val |= (led_config->gpio_output_enable & 0xff);
- } else {
- /* disable GPIO output */
- val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
- val |= (led_config->gpio_output_disable & 0xff);
- }
- return au8522_writereg(state, 0x8000 |
- (led_config->gpio_output & ~0xc000), val);
-}
-
-/* led = 0 | off
- * led = 1 | signal ok
- * led = 2 | signal strong
- * led < 0 | only light led if leds are currently off
- */
-int au8522_led_ctrl(struct au8522_state *state, int led)
-{
- struct au8522_led_config *led_config = state->config->led_cfg;
- int i, ret = 0;
-
- /* bail out if we can't control an LED */
- if (!led_config || !led_config->gpio_leds ||
- !led_config->num_led_states || !led_config->led_states)
- return 0;
-
- if (led < 0) {
- /* if LED is already lit, then leave it as-is */
- if (state->led_state)
- return 0;
- else
- led *= -1;
- }
-
- /* toggle LED if changing state */
- if (state->led_state != led) {
- u8 val;
-
- dprintk("%s: %d\n", __func__, led);
-
- au8522_led_gpio_enable(state, 1);
-
- val = au8522_readreg(state, 0x4000 |
- (led_config->gpio_leds & ~0xc000));
-
- /* start with all leds off */
- for (i = 0; i < led_config->num_led_states; i++)
- val &= ~led_config->led_states[i];
-
- /* set selected LED state */
- if (led < led_config->num_led_states)
- val |= led_config->led_states[led];
- else if (led_config->num_led_states)
- val |=
- led_config->led_states[led_config->num_led_states - 1];
-
- ret = au8522_writereg(state, 0x8000 |
- (led_config->gpio_leds & ~0xc000), val);
- if (ret < 0)
- return ret;
-
- state->led_state = led;
-
- if (led == 0)
- au8522_led_gpio_enable(state, 0);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(au8522_led_ctrl);
-
-int au8522_init(struct dvb_frontend *fe)
-{
- struct au8522_state *state = fe->demodulator_priv;
- dprintk("%s()\n", __func__);
-
- state->operational_mode = AU8522_DIGITAL_MODE;
-
- /* Clear out any state associated with the digital side of the
- chip, so that when it gets powered back up it won't think
- that it is already tuned */
- state->current_frequency = 0;
-
- au8522_writereg(state, 0xa4, 1 << 5);
-
- au8522_i2c_gate_ctrl(fe, 1);
-
- return 0;
-}
-EXPORT_SYMBOL(au8522_init);
-
-int au8522_sleep(struct dvb_frontend *fe)
-{
- struct au8522_state *state = fe->demodulator_priv;
- dprintk("%s()\n", __func__);
-
- /* Only power down if the digital side is currently using the chip */
- if (state->operational_mode == AU8522_ANALOG_MODE) {
- /* We're not in one of the expected power modes, which means
- that the DVB thread is probably telling us to go to sleep
- even though the analog frontend has already started using
- the chip. So ignore the request */
- return 0;
- }
-
- /* turn off led */
- au8522_led_ctrl(state, 0);
-
- /* Power down the chip */
- au8522_writereg(state, 0xa4, 1 << 5);
-
- state->current_frequency = 0;
-
- return 0;
-}
-EXPORT_SYMBOL(au8522_sleep);
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
deleted file mode 100644
index 55b6390198e3..000000000000
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
- *
- * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
- * Copyright (C) 2005-2008 Auvitek International, Ltd.
- *
- * 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.
- */
-
-/* Developer notes:
- *
- * VBI support is not yet working
- * Enough is implemented here for CVBS and S-Video inputs, but the actual
- * analog demodulator code isn't implemented (not needed for xc5000 since it
- * has its own demodulator and outputs CVBS)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-device.h>
-#include "au8522.h"
-#include "au8522_priv.h"
-
-MODULE_AUTHOR("Devin Heitmueller");
-MODULE_LICENSE("GPL");
-
-static int au8522_analog_debug;
-
-
-module_param_named(analog_debug, au8522_analog_debug, int, 0644);
-
-MODULE_PARM_DESC(analog_debug,
- "Analog debugging messages [0=Off (default) 1=On]");
-
-struct au8522_register_config {
- u16 reg_name;
- u8 reg_val[8];
-};
-
-
-/* Video Decoder Filter Coefficients
- The values are as follows from left to right
- 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
-*/
-static const struct au8522_register_config filter_coef[] = {
- {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
- {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
- {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
- {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
- {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
- {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
- {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
- {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
- {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
- {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
- {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
- {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
- {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
- {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
- {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
- {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
- {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
- {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
- {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
- {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
- {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
- {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
-
-};
-#define NUM_FILTER_COEF (sizeof(filter_coef)\
- / sizeof(struct au8522_register_config))
-
-
-/* Registers 0x060b through 0x0652 are the LP Filter coefficients
- The values are as follows from left to right
- 0="SIF" 1="ATVRF/ATVRF13"
- Note: the "ATVRF/ATVRF13" mode has never been tested
-*/
-static const struct au8522_register_config lpfilter_coef[] = {
- {0x060b, {0x21, 0x0b} },
- {0x060c, {0xad, 0xad} },
- {0x060d, {0x70, 0xf0} },
- {0x060e, {0xea, 0xe9} },
- {0x060f, {0xdd, 0xdd} },
- {0x0610, {0x08, 0x64} },
- {0x0611, {0x60, 0x60} },
- {0x0612, {0xf8, 0xb2} },
- {0x0613, {0x01, 0x02} },
- {0x0614, {0xe4, 0xb4} },
- {0x0615, {0x19, 0x02} },
- {0x0616, {0xae, 0x2e} },
- {0x0617, {0xee, 0xc5} },
- {0x0618, {0x56, 0x56} },
- {0x0619, {0x30, 0x58} },
- {0x061a, {0xf9, 0xf8} },
- {0x061b, {0x24, 0x64} },
- {0x061c, {0x07, 0x07} },
- {0x061d, {0x30, 0x30} },
- {0x061e, {0xa9, 0xed} },
- {0x061f, {0x09, 0x0b} },
- {0x0620, {0x42, 0xc2} },
- {0x0621, {0x1d, 0x2a} },
- {0x0622, {0xd6, 0x56} },
- {0x0623, {0x95, 0x8b} },
- {0x0624, {0x2b, 0x2b} },
- {0x0625, {0x30, 0x24} },
- {0x0626, {0x3e, 0x3e} },
- {0x0627, {0x62, 0xe2} },
- {0x0628, {0xe9, 0xf5} },
- {0x0629, {0x99, 0x19} },
- {0x062a, {0xd4, 0x11} },
- {0x062b, {0x03, 0x04} },
- {0x062c, {0xb5, 0x85} },
- {0x062d, {0x1e, 0x20} },
- {0x062e, {0x2a, 0xea} },
- {0x062f, {0xd7, 0xd2} },
- {0x0630, {0x15, 0x15} },
- {0x0631, {0xa3, 0xa9} },
- {0x0632, {0x1f, 0x1f} },
- {0x0633, {0xf9, 0xd1} },
- {0x0634, {0xc0, 0xc3} },
- {0x0635, {0x4d, 0x8d} },
- {0x0636, {0x21, 0x31} },
- {0x0637, {0x83, 0x83} },
- {0x0638, {0x08, 0x8c} },
- {0x0639, {0x19, 0x19} },
- {0x063a, {0x45, 0xa5} },
- {0x063b, {0xef, 0xec} },
- {0x063c, {0x8a, 0x8a} },
- {0x063d, {0xf4, 0xf6} },
- {0x063e, {0x8f, 0x8f} },
- {0x063f, {0x44, 0x0c} },
- {0x0640, {0xef, 0xf0} },
- {0x0641, {0x66, 0x66} },
- {0x0642, {0xcc, 0xd2} },
- {0x0643, {0x41, 0x41} },
- {0x0644, {0x63, 0x93} },
- {0x0645, {0x8e, 0x8e} },
- {0x0646, {0xa2, 0x42} },
- {0x0647, {0x7b, 0x7b} },
- {0x0648, {0x04, 0x04} },
- {0x0649, {0x00, 0x00} },
- {0x064a, {0x40, 0x40} },
- {0x064b, {0x8c, 0x98} },
- {0x064c, {0x00, 0x00} },
- {0x064d, {0x63, 0xc3} },
- {0x064e, {0x04, 0x04} },
- {0x064f, {0x20, 0x20} },
- {0x0650, {0x00, 0x00} },
- {0x0651, {0x40, 0x40} },
- {0x0652, {0x01, 0x01} },
-};
-#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
- / sizeof(struct au8522_register_config))
-
-static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct au8522_state, sd);
-}
-
-static void setup_vbi(struct au8522_state *state, int aud_input)
-{
- int i;
-
- /* These are set to zero regardless of what mode we're in */
- au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
- 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
- 0x00);
- au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
- 0x00);
-
- /* Setup the VBI registers */
- for (i = 0x30; i < 0x60; i++)
- au8522_writereg(state, i, 0x40);
-
- /* For some reason, every register is 0x40 except register 0x44
- (confirmed via the HVR-950q USB capture) */
- au8522_writereg(state, 0x44, 0x60);
-
- /* Enable VBI (we always do this regardless of whether the user is
- viewing closed caption info) */
- au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
- AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
-
-}
-
-static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
-{
- int i;
- int filter_coef_type;
-
- /* Provide reasonable defaults for picture tuning values */
- au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
- au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
- state->brightness = 0xed - 128;
- au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
- state->contrast = 0x79;
- au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
- au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
- state->saturation = 0x80;
- au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
- au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
- state->hue = 0x00;
-
- /* Other decoder registers */
- au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
-
- if (input_mode == 0x23) {
- /* S-Video input mapping */
- au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
- } else {
- /* All other modes (CVBS/ATVRF etc.) */
- au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
- }
-
- au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
- AU8522_TVDEC_PGA_REG012H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
- AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
- au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
- AU8522_TVDED_DBG_MODE_REG060H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
- AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13);
- au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
- AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13);
- au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
- AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
- AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
- AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
- AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
- AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
- AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
- AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
- AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
- AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
- if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
- input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
- AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
- AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
- } else {
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
- AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
- AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
- }
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
- AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
- AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
- AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
- au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
- au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
- AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
- au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
- au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
- AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
- AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
- AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
- AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
- AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
- AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
- au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
- AU8522_TOREGAAGC_REG0E5H_CVBS);
- au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
-
- setup_vbi(state, 0);
-
- if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
- input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
- /* Despite what the table says, for the HVR-950q we still need
- to be in CVBS mode for the S-Video input (reason unknown). */
- /* filter_coef_type = 3; */
- filter_coef_type = 5;
- } else {
- filter_coef_type = 5;
- }
-
- /* Load the Video Decoder Filter Coefficients */
- for (i = 0; i < NUM_FILTER_COEF; i++) {
- au8522_writereg(state, filter_coef[i].reg_name,
- filter_coef[i].reg_val[filter_coef_type]);
- }
-
- /* It's not clear what these registers are for, but they are always
- set to the same value regardless of what mode we're in */
- au8522_writereg(state, AU8522_REG42EH, 0x87);
- au8522_writereg(state, AU8522_REG42FH, 0xa2);
- au8522_writereg(state, AU8522_REG430H, 0xbf);
- au8522_writereg(state, AU8522_REG431H, 0xcb);
- au8522_writereg(state, AU8522_REG432H, 0xa1);
- au8522_writereg(state, AU8522_REG433H, 0x41);
- au8522_writereg(state, AU8522_REG434H, 0x88);
- au8522_writereg(state, AU8522_REG435H, 0xc2);
- au8522_writereg(state, AU8522_REG436H, 0x3c);
-}
-
-static void au8522_setup_cvbs_mode(struct au8522_state *state)
-{
- /* here we're going to try the pre-programmed route */
- au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
- AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
-
- /* PGA in automatic mode */
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
- /* Enable clamping control */
- au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
-
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
-
- setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
-
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
-{
- /* here we're going to try the pre-programmed route */
- au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
- AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
-
- /* It's not clear why we have to have the PGA in automatic mode while
- enabling clamp control, but it's what Windows does */
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
- /* Enable clamping control */
- au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
-
- /* Disable automatic PGA (since the CVBS is coming from the tuner) */
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
-
- /* Set input mode to CVBS on channel 4 with SIF audio input enabled */
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
-
- setup_decoder_defaults(state,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
-
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-static void au8522_setup_svideo_mode(struct au8522_state *state)
-{
- au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
- AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
-
- /* Set input to Y on Channe1, C on Channel 3 */
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
-
- /* PGA in automatic mode */
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
-
- /* Enable clamping control */
- au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
-
- setup_decoder_defaults(state,
- AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
-
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void disable_audio_input(struct au8522_state *state)
-{
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
-
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
- au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
-
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
-}
-
-/* 0=disable, 1=SIF */
-static void set_audio_input(struct au8522_state *state, int aud_input)
-{
- int i;
-
- /* Note that this function needs to be used in conjunction with setting
- the input routing via register 0x81 */
-
- if (aud_input == AU8522_AUDIO_NONE) {
- disable_audio_input(state);
- return;
- }
-
- if (aud_input != AU8522_AUDIO_SIF) {
- /* The caller asked for a mode we don't currently support */
- printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
- aud_input);
- return;
- }
-
- /* Load the Audio Decoder Filter Coefficients */
- for (i = 0; i < NUM_LPFILTER_COEF; i++) {
- au8522_writereg(state, lpfilter_coef[i].reg_name,
- lpfilter_coef[i].reg_val[0]);
- }
-
- /* Setup audio */
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
- msleep(150);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
- msleep(1);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
- msleep(50);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
- msleep(80);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
- au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
- au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
- msleep(70);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
- au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
- au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct au8522_state *state = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- state->brightness = ctrl->value;
- au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
- ctrl->value - 128);
- break;
- case V4L2_CID_CONTRAST:
- state->contrast = ctrl->value;
- au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
- ctrl->value);
- break;
- case V4L2_CID_SATURATION:
- state->saturation = ctrl->value;
- au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
- ctrl->value);
- au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
- ctrl->value);
- break;
- case V4L2_CID_HUE:
- state->hue = ctrl->value;
- au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
- ctrl->value >> 8);
- au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
- ctrl->value & 0xFF);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- /* Not yet implemented */
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct au8522_state *state = to_state(sd);
-
- /* Note that we are using values cached in the state structure instead
- of reading the registers due to issues with i2c reads not working
- properly/consistently yet on the HVR-950q */
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = state->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = state->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = state->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = state->hue;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- /* Not yet supported */
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int au8522_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct au8522_state *state = to_state(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- reg->val = au8522_readreg(state, reg->reg & 0xffff);
- return 0;
-}
-
-static int au8522_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct au8522_state *state = to_state(sd);
-
- if (!v4l2_chip_match_i2c_client(client, &reg->match))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- au8522_writereg(state, reg->reg, reg->val & 0xff);
- return 0;
-}
-#endif
-
-static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct au8522_state *state = to_state(sd);
-
- if (enable) {
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- 0x01);
- msleep(1);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
- } else {
- /* This does not completely power down the device
- (it only reduces it from around 140ma to 80ma) */
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- 1 << 5);
- }
- return 0;
-}
-
-static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1,
- AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
- default:
- break;
- }
-
- qc->type = 0;
- return -EINVAL;
-}
-
-static int au8522_reset(struct v4l2_subdev *sd, u32 val)
-{
- struct au8522_state *state = to_state(sd);
-
- state->operational_mode = AU8522_ANALOG_MODE;
-
- /* Clear out any state associated with the digital side of the
- chip, so that when it gets powered back up it won't think
- that it is already tuned */
- state->current_frequency = 0;
-
- au8522_writereg(state, 0xa4, 1 << 5);
-
- return 0;
-}
-
-static int au8522_s_video_routing(struct v4l2_subdev *sd,
- u32 input, u32 output, u32 config)
-{
- struct au8522_state *state = to_state(sd);
-
- au8522_reset(sd, 0);
-
- /* Jam open the i2c gate to the tuner. We do this here to handle the
- case where the user went into digital mode (causing the gate to be
- closed), and then came back to analog mode */
- au8522_writereg(state, 0x106, 1);
-
- if (input == AU8522_COMPOSITE_CH1) {
- au8522_setup_cvbs_mode(state);
- } else if (input == AU8522_SVIDEO_CH13) {
- au8522_setup_svideo_mode(state);
- } else if (input == AU8522_COMPOSITE_CH4_SIF) {
- au8522_setup_cvbs_tuner_mode(state);
- } else {
- printk(KERN_ERR "au8522 mode not currently supported\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int au8522_s_audio_routing(struct v4l2_subdev *sd,
- u32 input, u32 output, u32 config)
-{
- struct au8522_state *state = to_state(sd);
- set_audio_input(state, input);
- return 0;
-}
-
-static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
-{
- int val = 0;
- struct au8522_state *state = to_state(sd);
- u8 lock_status;
-
- /* Interrogate the decoder to see if we are getting a real signal */
- lock_status = au8522_readreg(state, 0x00);
- if (lock_status == 0xa2)
- vt->signal = 0xffff;
- else
- vt->signal = 0x00;
-
- vt->capability |=
- V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-
- val = V4L2_TUNER_SUB_MONO;
- vt->rxsubchans = val;
- vt->audmode = V4L2_TUNER_MODE_STEREO;
- return 0;
-}
-
-static int au8522_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct au8522_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
-static int au8522_log_status(struct v4l2_subdev *sd)
-{
- /* FIXME: Add some status info here */
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops au8522_core_ops = {
- .log_status = au8522_log_status,
- .g_chip_ident = au8522_g_chip_ident,
- .g_ctrl = au8522_g_ctrl,
- .s_ctrl = au8522_s_ctrl,
- .queryctrl = au8522_queryctrl,
- .reset = au8522_reset,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = au8522_g_register,
- .s_register = au8522_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
- .g_tuner = au8522_g_tuner,
-};
-
-static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
- .s_routing = au8522_s_audio_routing,
-};
-
-static const struct v4l2_subdev_video_ops au8522_video_ops = {
- .s_routing = au8522_s_video_routing,
- .s_stream = au8522_s_stream,
-};
-
-static const struct v4l2_subdev_ops au8522_ops = {
- .core = &au8522_core_ops,
- .tuner = &au8522_tuner_ops,
- .audio = &au8522_audio_ops,
- .video = &au8522_video_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int au8522_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct au8522_state *state;
- struct v4l2_subdev *sd;
- int instance;
- struct au8522_config *demod_config;
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- return -EIO;
- }
-
- /* allocate memory for the internal state */
- instance = au8522_get_state(&state, client->adapter, client->addr);
- switch (instance) {
- case 0:
- printk(KERN_ERR "au8522_decoder allocation failed\n");
- return -EIO;
- case 1:
- /* new demod instance */
- printk(KERN_INFO "au8522_decoder creating new instance...\n");
- break;
- default:
- /* existing demod instance */
- printk(KERN_INFO "au8522_decoder attach existing instance.\n");
- break;
- }
-
- demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
- if (demod_config == NULL) {
- if (instance == 1)
- kfree(state);
- return -ENOMEM;
- }
- demod_config->demod_address = 0x8e >> 1;
-
- state->config = demod_config;
- state->i2c = client->adapter;
-
- sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &au8522_ops);
-
- state->c = client;
- state->vid_input = AU8522_COMPOSITE_CH1;
- state->aud_input = AU8522_AUDIO_NONE;
- state->id = 8522;
- state->rev = 0;
-
- /* Jam open the i2c gate to the tuner */
- au8522_writereg(state, 0x106, 1);
-
- return 0;
-}
-
-static int au8522_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- v4l2_device_unregister_subdev(sd);
- au8522_release_state(to_state(sd));
- return 0;
-}
-
-static const struct i2c_device_id au8522_id[] = {
- {"au8522", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, au8522_id);
-
-static struct i2c_driver au8522_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "au8522",
- },
- .probe = au8522_probe,
- .remove = au8522_remove,
- .id_table = au8522_id,
-};
-
-module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
deleted file mode 100644
index 5fc70d6cd04f..000000000000
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
- Auvitek AU8522 QAM/8VSB demodulator driver
-
- Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
-
- 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/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "au8522.h"
-#include "au8522_priv.h"
-
-static int debug;
-
-#define dprintk(arg...)\
- do { if (debug)\
- printk(arg);\
- } while (0)
-
-struct mse2snr_tab {
- u16 val;
- u16 data;
-};
-
-/* VSB SNR lookup table */
-static struct mse2snr_tab vsb_mse2snr_tab[] = {
- { 0, 270 },
- { 2, 250 },
- { 3, 240 },
- { 5, 230 },
- { 7, 220 },
- { 9, 210 },
- { 12, 200 },
- { 13, 195 },
- { 15, 190 },
- { 17, 185 },
- { 19, 180 },
- { 21, 175 },
- { 24, 170 },
- { 27, 165 },
- { 31, 160 },
- { 32, 158 },
- { 33, 156 },
- { 36, 152 },
- { 37, 150 },
- { 39, 148 },
- { 40, 146 },
- { 41, 144 },
- { 43, 142 },
- { 44, 140 },
- { 48, 135 },
- { 50, 130 },
- { 43, 142 },
- { 53, 125 },
- { 56, 120 },
- { 256, 115 },
-};
-
-/* QAM64 SNR lookup table */
-static struct mse2snr_tab qam64_mse2snr_tab[] = {
- { 15, 0 },
- { 16, 290 },
- { 17, 288 },
- { 18, 286 },
- { 19, 284 },
- { 20, 282 },
- { 21, 281 },
- { 22, 279 },
- { 23, 277 },
- { 24, 275 },
- { 25, 273 },
- { 26, 271 },
- { 27, 269 },
- { 28, 268 },
- { 29, 266 },
- { 30, 264 },
- { 31, 262 },
- { 32, 260 },
- { 33, 259 },
- { 34, 258 },
- { 35, 256 },
- { 36, 255 },
- { 37, 254 },
- { 38, 252 },
- { 39, 251 },
- { 40, 250 },
- { 41, 249 },
- { 42, 248 },
- { 43, 246 },
- { 44, 245 },
- { 45, 244 },
- { 46, 242 },
- { 47, 241 },
- { 48, 240 },
- { 50, 239 },
- { 51, 238 },
- { 53, 237 },
- { 54, 236 },
- { 56, 235 },
- { 57, 234 },
- { 59, 233 },
- { 60, 232 },
- { 62, 231 },
- { 63, 230 },
- { 65, 229 },
- { 67, 228 },
- { 68, 227 },
- { 70, 226 },
- { 71, 225 },
- { 73, 224 },
- { 74, 223 },
- { 76, 222 },
- { 78, 221 },
- { 80, 220 },
- { 82, 219 },
- { 85, 218 },
- { 88, 217 },
- { 90, 216 },
- { 92, 215 },
- { 93, 214 },
- { 94, 212 },
- { 95, 211 },
- { 97, 210 },
- { 99, 209 },
- { 101, 208 },
- { 102, 207 },
- { 104, 206 },
- { 107, 205 },
- { 111, 204 },
- { 114, 203 },
- { 118, 202 },
- { 122, 201 },
- { 125, 200 },
- { 128, 199 },
- { 130, 198 },
- { 132, 197 },
- { 256, 190 },
-};
-
-/* QAM256 SNR lookup table */
-static struct mse2snr_tab qam256_mse2snr_tab[] = {
- { 16, 0 },
- { 17, 400 },
- { 18, 398 },
- { 19, 396 },
- { 20, 394 },
- { 21, 392 },
- { 22, 390 },
- { 23, 388 },
- { 24, 386 },
- { 25, 384 },
- { 26, 382 },
- { 27, 380 },
- { 28, 379 },
- { 29, 378 },
- { 30, 377 },
- { 31, 376 },
- { 32, 375 },
- { 33, 374 },
- { 34, 373 },
- { 35, 372 },
- { 36, 371 },
- { 37, 370 },
- { 38, 362 },
- { 39, 354 },
- { 40, 346 },
- { 41, 338 },
- { 42, 330 },
- { 43, 328 },
- { 44, 326 },
- { 45, 324 },
- { 46, 322 },
- { 47, 320 },
- { 48, 319 },
- { 49, 318 },
- { 50, 317 },
- { 51, 316 },
- { 52, 315 },
- { 53, 314 },
- { 54, 313 },
- { 55, 312 },
- { 56, 311 },
- { 57, 310 },
- { 58, 308 },
- { 59, 306 },
- { 60, 304 },
- { 61, 302 },
- { 62, 300 },
- { 63, 298 },
- { 65, 295 },
- { 68, 294 },
- { 70, 293 },
- { 73, 292 },
- { 76, 291 },
- { 78, 290 },
- { 79, 289 },
- { 81, 288 },
- { 82, 287 },
- { 83, 286 },
- { 84, 285 },
- { 85, 284 },
- { 86, 283 },
- { 88, 282 },
- { 89, 281 },
- { 256, 280 },
-};
-
-static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
- u16 *snr)
-{
- int i, ret = -EINVAL;
- dprintk("%s()\n", __func__);
-
- for (i = 0; i < sz; i++) {
- if (mse < tab[i].val) {
- *snr = tab[i].data;
- ret = 0;
- break;
- }
- }
- dprintk("%s() snr=%d\n", __func__, *snr);
- return ret;
-}
-
-static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
-{
- struct au8522_state *state = fe->demodulator_priv;
- u8 r0b5, r0b6, r0b7;
- char *ifmhz;
-
- switch (if_freq) {
- case AU8522_IF_3_25MHZ:
- ifmhz = "3.25";
- r0b5 = 0x00;
- r0b6 = 0x3d;
- r0b7 = 0xa0;
- break;
- case AU8522_IF_4MHZ:
- ifmhz = "4.00";
- r0b5 = 0x00;
- r0b6 = 0x4b;
- r0b7 = 0xd9;
- break;
- case AU8522_IF_6MHZ:
- ifmhz = "6.00";
- r0b5 = 0xfb;
- r0b6 = 0x8e;
- r0b7 = 0x39;
- break;
- default:
- dprintk("%s() IF Frequency not supported\n", __func__);
- return -EINVAL;
- }
- dprintk("%s() %s MHz\n", __func__, ifmhz);
- au8522_writereg(state, 0x80b5, r0b5);
- au8522_writereg(state, 0x80b6, r0b6);
- au8522_writereg(state, 0x80b7, r0b7);
-
- return 0;
-}
-
-/* VSB Modulation table */
-static struct {
- u16 reg;
- u16 data;
-} VSB_mod_tab[] = {
- { 0x8090, 0x84 },
- { 0x4092, 0x11 },
- { 0x2005, 0x00 },
- { 0x8091, 0x80 },
- { 0x80a3, 0x0c },
- { 0x80a4, 0xe8 },
- { 0x8081, 0xc4 },
- { 0x80a5, 0x40 },
- { 0x80a7, 0x40 },
- { 0x80a6, 0x67 },
- { 0x8262, 0x20 },
- { 0x821c, 0x30 },
- { 0x80d8, 0x1a },
- { 0x8227, 0xa0 },
- { 0x8121, 0xff },
- { 0x80a8, 0xf0 },
- { 0x80a9, 0x05 },
- { 0x80aa, 0x77 },
- { 0x80ab, 0xf0 },
- { 0x80ac, 0x05 },
- { 0x80ad, 0x77 },
- { 0x80ae, 0x41 },
- { 0x80af, 0x66 },
- { 0x821b, 0xcc },
- { 0x821d, 0x80 },
- { 0x80a4, 0xe8 },
- { 0x8231, 0x13 },
-};
-
-/* QAM64 Modulation table */
-static struct {
- u16 reg;
- u16 data;
-} QAM64_mod_tab[] = {
- { 0x00a3, 0x09 },
- { 0x00a4, 0x00 },
- { 0x0081, 0xc4 },
- { 0x00a5, 0x40 },
- { 0x00aa, 0x77 },
- { 0x00ad, 0x77 },
- { 0x00a6, 0x67 },
- { 0x0262, 0x20 },
- { 0x021c, 0x30 },
- { 0x00b8, 0x3e },
- { 0x00b9, 0xf0 },
- { 0x00ba, 0x01 },
- { 0x00bb, 0x18 },
- { 0x00bc, 0x50 },
- { 0x00bd, 0x00 },
- { 0x00be, 0xea },
- { 0x00bf, 0xef },
- { 0x00c0, 0xfc },
- { 0x00c1, 0xbd },
- { 0x00c2, 0x1f },
- { 0x00c3, 0xfc },
- { 0x00c4, 0xdd },
- { 0x00c5, 0xaf },
- { 0x00c6, 0x00 },
- { 0x00c7, 0x38 },
- { 0x00c8, 0x30 },
- { 0x00c9, 0x05 },
- { 0x00ca, 0x4a },
- { 0x00cb, 0xd0 },
- { 0x00cc, 0x01 },
- { 0x00cd, 0xd9 },
- { 0x00ce, 0x6f },
- { 0x00cf, 0xf9 },
- { 0x00d0, 0x70 },
- { 0x00d1, 0xdf },
- { 0x00d2, 0xf7 },
- { 0x00d3, 0xc2 },
- { 0x00d4, 0xdf },
- { 0x00d5, 0x02 },
- { 0x00d6, 0x9a },
- { 0x00d7, 0xd0 },
- { 0x0250, 0x0d },
- { 0x0251, 0xcd },
- { 0x0252, 0xe0 },
- { 0x0253, 0x05 },
- { 0x0254, 0xa7 },
- { 0x0255, 0xff },
- { 0x0256, 0xed },
- { 0x0257, 0x5b },
- { 0x0258, 0xae },
- { 0x0259, 0xe6 },
- { 0x025a, 0x3d },
- { 0x025b, 0x0f },
- { 0x025c, 0x0d },
- { 0x025d, 0xea },
- { 0x025e, 0xf2 },
- { 0x025f, 0x51 },
- { 0x0260, 0xf5 },
- { 0x0261, 0x06 },
- { 0x021a, 0x00 },
- { 0x0546, 0x40 },
- { 0x0210, 0xc7 },
- { 0x0211, 0xaa },
- { 0x0212, 0xab },
- { 0x0213, 0x02 },
- { 0x0502, 0x00 },
- { 0x0121, 0x04 },
- { 0x0122, 0x04 },
- { 0x052e, 0x10 },
- { 0x00a4, 0xca },
- { 0x00a7, 0x40 },
- { 0x0526, 0x01 },
-};
-
-/* QAM256 Modulation table */
-static struct {
- u16 reg;
- u16 data;
-} QAM256_mod_tab[] = {
- { 0x80a3, 0x09 },
- { 0x80a4, 0x00 },
- { 0x8081, 0xc4 },
- { 0x80a5, 0x40 },
- { 0x80aa, 0x77 },
- { 0x80ad, 0x77 },
- { 0x80a6, 0x67 },
- { 0x8262, 0x20 },
- { 0x821c, 0x30 },
- { 0x80b8, 0x3e },
- { 0x80b9, 0xf0 },
- { 0x80ba, 0x01 },
- { 0x80bb, 0x18 },
- { 0x80bc, 0x50 },
- { 0x80bd, 0x00 },
- { 0x80be, 0xea },
- { 0x80bf, 0xef },
- { 0x80c0, 0xfc },
- { 0x80c1, 0xbd },
- { 0x80c2, 0x1f },
- { 0x80c3, 0xfc },
- { 0x80c4, 0xdd },
- { 0x80c5, 0xaf },
- { 0x80c6, 0x00 },
- { 0x80c7, 0x38 },
- { 0x80c8, 0x30 },
- { 0x80c9, 0x05 },
- { 0x80ca, 0x4a },
- { 0x80cb, 0xd0 },
- { 0x80cc, 0x01 },
- { 0x80cd, 0xd9 },
- { 0x80ce, 0x6f },
- { 0x80cf, 0xf9 },
- { 0x80d0, 0x70 },
- { 0x80d1, 0xdf },
- { 0x80d2, 0xf7 },
- { 0x80d3, 0xc2 },
- { 0x80d4, 0xdf },
- { 0x80d5, 0x02 },
- { 0x80d6, 0x9a },
- { 0x80d7, 0xd0 },
- { 0x8250, 0x0d },
- { 0x8251, 0xcd },
- { 0x8252, 0xe0 },
- { 0x8253, 0x05 },
- { 0x8254, 0xa7 },
- { 0x8255, 0xff },
- { 0x8256, 0xed },
- { 0x8257, 0x5b },
- { 0x8258, 0xae },
- { 0x8259, 0xe6 },
- { 0x825a, 0x3d },
- { 0x825b, 0x0f },
- { 0x825c, 0x0d },
- { 0x825d, 0xea },
- { 0x825e, 0xf2 },
- { 0x825f, 0x51 },
- { 0x8260, 0xf5 },
- { 0x8261, 0x06 },
- { 0x821a, 0x00 },
- { 0x8546, 0x40 },
- { 0x8210, 0x26 },
- { 0x8211, 0xf6 },
- { 0x8212, 0x84 },
- { 0x8213, 0x02 },
- { 0x8502, 0x01 },
- { 0x8121, 0x04 },
- { 0x8122, 0x04 },
- { 0x852e, 0x10 },
- { 0x80a4, 0xca },
- { 0x80a7, 0x40 },
- { 0x8526, 0x01 },
-};
-
-static int au8522_enable_modulation(struct dvb_frontend *fe,
- fe_modulation_t m)
-{
- struct au8522_state *state = fe->demodulator_priv;
- int i;
-
- dprintk("%s(0x%08x)\n", __func__, m);
-
- switch (m) {
- case VSB_8:
- dprintk("%s() VSB_8\n", __func__);
- for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
- au8522_writereg(state,
- VSB_mod_tab[i].reg,
- VSB_mod_tab[i].data);
- au8522_set_if(fe, state->config->vsb_if);
- break;
- case QAM_64:
- dprintk("%s() QAM 64\n", __func__);
- for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
- au8522_writereg(state,
- QAM64_mod_tab[i].reg,
- QAM64_mod_tab[i].data);
- au8522_set_if(fe, state->config->qam_if);
- break;
- case QAM_256:
- dprintk("%s() QAM 256\n", __func__);
- for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
- au8522_writereg(state,
- QAM256_mod_tab[i].reg,
- QAM256_mod_tab[i].data);
- au8522_set_if(fe, state->config->qam_if);
- break;
- default:
- dprintk("%s() Invalid modulation\n", __func__);
- return -EINVAL;
- }
-
- state->current_modulation = m;
-
- return 0;
-}
-
-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-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__, c->frequency);
-
- if ((state->current_frequency == c->frequency) &&
- (state->current_modulation == c->modulation))
- return 0;
-
- 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);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- if (ret < 0)
- return ret;
-
- /* Allow the tuner to settle */
- msleep(100);
-
- au8522_enable_modulation(fe, c->modulation);
-
- state->current_frequency = c->frequency;
-
- return 0;
-}
-
-static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct au8522_state *state = fe->demodulator_priv;
- u8 reg;
- u32 tuner_status = 0;
-
- *status = 0;
-
- if (state->current_modulation == VSB_8) {
- dprintk("%s() Checking VSB_8\n", __func__);
- reg = au8522_readreg(state, 0x4088);
- if ((reg & 0x03) == 0x03)
- *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
- } else {
- dprintk("%s() Checking QAM\n", __func__);
- reg = au8522_readreg(state, 0x4541);
- if (reg & 0x80)
- *status |= FE_HAS_VITERBI;
- if (reg & 0x20)
- *status |= FE_HAS_LOCK | FE_HAS_SYNC;
- }
-
- switch (state->config->status_mode) {
- case AU8522_DEMODLOCKING:
- dprintk("%s() DEMODLOCKING\n", __func__);
- if (*status & FE_HAS_VITERBI)
- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
- break;
- case AU8522_TUNERLOCKING:
- /* Get the tuner status */
- dprintk("%s() TUNERLOCKING\n", __func__);
- if (fe->ops.tuner_ops.get_status) {
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- fe->ops.tuner_ops.get_status(fe, &tuner_status);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- if (tuner_status)
- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
- break;
- }
- state->fe_status = *status;
-
- if (*status & FE_HAS_LOCK)
- /* turn on LED, if it isn't on already */
- au8522_led_ctrl(state, -1);
- else
- /* turn off LED */
- au8522_led_ctrl(state, 0);
-
- dprintk("%s() status 0x%08x\n", __func__, *status);
-
- return 0;
-}
-
-static int au8522_led_status(struct au8522_state *state, const u16 *snr)
-{
- struct au8522_led_config *led_config = state->config->led_cfg;
- int led;
- u16 strong;
-
- /* bail out if we can't control an LED */
- if (!led_config)
- return 0;
-
- if (0 == (state->fe_status & FE_HAS_LOCK))
- return au8522_led_ctrl(state, 0);
- else if (state->current_modulation == QAM_256)
- strong = led_config->qam256_strong;
- else if (state->current_modulation == QAM_64)
- strong = led_config->qam64_strong;
- else /* (state->current_modulation == VSB_8) */
- strong = led_config->vsb8_strong;
-
- if (*snr >= strong)
- led = 2;
- else
- led = 1;
-
- if ((state->led_state) &&
- (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
- /* snr didn't change enough to bother
- * changing the color of the led */
- return 0;
-
- return au8522_led_ctrl(state, led);
-}
-
-static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- struct au8522_state *state = fe->demodulator_priv;
- int ret = -EINVAL;
-
- dprintk("%s()\n", __func__);
-
- if (state->current_modulation == QAM_256)
- ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
- ARRAY_SIZE(qam256_mse2snr_tab),
- au8522_readreg(state, 0x4522),
- snr);
- else if (state->current_modulation == QAM_64)
- ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
- ARRAY_SIZE(qam64_mse2snr_tab),
- au8522_readreg(state, 0x4522),
- snr);
- else /* VSB_8 */
- ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
- ARRAY_SIZE(vsb_mse2snr_tab),
- au8522_readreg(state, 0x4311),
- snr);
-
- if (state->config->led_cfg)
- au8522_led_status(state, snr);
-
- return ret;
-}
-
-static int au8522_read_signal_strength(struct dvb_frontend *fe,
- u16 *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)
-{
- struct au8522_state *state = fe->demodulator_priv;
-
- if (state->current_modulation == VSB_8)
- *ucblocks = au8522_readreg(state, 0x4087);
- else
- *ucblocks = au8522_readreg(state, 0x4543);
-
- return 0;
-}
-
-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 dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct au8522_state *state = fe->demodulator_priv;
-
- c->frequency = state->current_frequency;
- c->modulation = state->current_modulation;
-
- return 0;
-}
-
-static int au8522_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *tune)
-{
- tune->min_delay_ms = 1000;
- return 0;
-}
-
-static struct dvb_frontend_ops au8522_ops;
-
-
-static void au8522_release(struct dvb_frontend *fe)
-{
- struct au8522_state *state = fe->demodulator_priv;
- au8522_release_state(state);
-}
-
-struct dvb_frontend *au8522_attach(const struct au8522_config *config,
- struct i2c_adapter *i2c)
-{
- struct au8522_state *state = NULL;
- int instance;
-
- /* allocate memory for the internal state */
- instance = au8522_get_state(&state, i2c, config->demod_address);
- switch (instance) {
- case 0:
- dprintk("%s state allocation failed\n", __func__);
- break;
- case 1:
- /* new demod instance */
- dprintk("%s using new instance\n", __func__);
- break;
- default:
- /* existing demod instance */
- dprintk("%s using existing instance\n", __func__);
- break;
- }
-
- /* setup the state */
- state->config = config;
- state->i2c = i2c;
- state->operational_mode = AU8522_DIGITAL_MODE;
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &au8522_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
-
- if (au8522_init(&state->frontend) != 0) {
- printk(KERN_ERR "%s: Failed to initialize correctly\n",
- __func__);
- goto error;
- }
-
- /* Note: Leaving the I2C gate open here. */
- au8522_i2c_gate_ctrl(&state->frontend, 1);
-
- return &state->frontend;
-
-error:
- au8522_release_state(state);
- return NULL;
-}
-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",
- .frequency_min = 54000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 62500,
- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
- },
-
- .init = au8522_init,
- .sleep = au8522_sleep,
- .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
- .set_frontend = au8522_set_frontend,
- .get_frontend = au8522_get_frontend,
- .get_tune_settings = au8522_get_tune_settings,
- .read_status = au8522_read_status,
- .read_ber = au8522_read_ber,
- .read_signal_strength = au8522_read_signal_strength,
- .read_snr = au8522_read_snr,
- .read_ucblocks = au8522_read_ucblocks,
- .release = au8522_release,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-
-MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
-MODULE_AUTHOR("Steven Toth");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
deleted file mode 100644
index 6e4a438732b5..000000000000
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- Auvitek AU8522 QAM/8VSB demodulator driver
-
- Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
- Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
- Copyright (C) 2005-2008 Auvitek International, Ltd.
-
- 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/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-#include "au8522.h"
-#include "tuner-i2c.h"
-
-#define AU8522_ANALOG_MODE 0
-#define AU8522_DIGITAL_MODE 1
-
-struct au8522_state {
- struct i2c_client *c;
- struct i2c_adapter *i2c;
-
- u8 operational_mode;
-
- /* Used for sharing of the state between analog and digital mode */
- struct tuner_i2c_props i2c_props;
- struct list_head hybrid_tuner_instance_list;
-
- /* configuration settings */
- const struct au8522_config *config;
-
- struct dvb_frontend frontend;
-
- u32 current_frequency;
- fe_modulation_t current_modulation;
-
- u32 fe_status;
- unsigned int led_state;
-
- /* Analog settings */
- struct v4l2_subdev sd;
- v4l2_std_id std;
- int vid_input;
- int aud_input;
- u32 id;
- u32 rev;
- u8 brightness;
- u8 contrast;
- u8 saturation;
- s16 hue;
-};
-
-/* These are routines shared by both the VSB/QAM demodulator and the analog
- decoder */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
-u8 au8522_readreg(struct au8522_state *state, u16 reg);
-int au8522_init(struct dvb_frontend *fe);
-int au8522_sleep(struct dvb_frontend *fe);
-
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
- u8 client_address);
-void au8522_release_state(struct au8522_state *state);
-int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
-int au8522_led_ctrl(struct au8522_state *state, int led);
-
-/* REGISTERS */
-#define AU8522_INPUT_CONTROL_REG081H 0x081
-#define AU8522_PGA_CONTROL_REG082H 0x082
-#define AU8522_CLAMPING_CONTROL_REG083H 0x083
-
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5
-#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6
-#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7
-#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8
-#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9
-#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA
-#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB
-#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC
-#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD
-#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE
-#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF
-
-/* Receiver registers */
-#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0
-#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1
-#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2
-#define AU8522_TOREGAGC1_REG0B3H 0x0B3
-#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4
-#define AU8522_FRMREGBBH_REG0B5H 0x0B5
-#define AU8522_FRMREGBBM_REG0B6H 0x0B6
-#define AU8522_FRMREGBBL_REG0B7H 0x0B7
-/* 0xB8 TO 0xD7 are the filter coefficients */
-#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8
-#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9
-#define AU8522_TOREGAGC2_REG0DAH 0x0DA
-#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB
-#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC
-#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD
-#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE
-#define AU8522_TOREGFREQ_REG0DFH 0x0DF
-
-#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB
-#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC
-#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED
-
-#define AU8522_CHIP_MODE_REG0FEH 0x0FE
-
-/* I2C bus control registers */
-#define AU8522_I2C_CONTROL_REG0_REG090H 0x090
-#define AU8522_I2C_CONTROL_REG1_REG091H 0x091
-#define AU8522_I2C_STATUS_REG092H 0x092
-#define AU8522_I2C_WR_DATA0_REG093H 0x093
-#define AU8522_I2C_WR_DATA1_REG094H 0x094
-#define AU8522_I2C_WR_DATA2_REG095H 0x095
-#define AU8522_I2C_WR_DATA3_REG096H 0x096
-#define AU8522_I2C_WR_DATA4_REG097H 0x097
-#define AU8522_I2C_WR_DATA5_REG098H 0x098
-#define AU8522_I2C_WR_DATA6_REG099H 0x099
-#define AU8522_I2C_WR_DATA7_REG09AH 0x09A
-#define AU8522_I2C_RD_DATA0_REG09BH 0x09B
-#define AU8522_I2C_RD_DATA1_REG09CH 0x09C
-#define AU8522_I2C_RD_DATA2_REG09DH 0x09D
-#define AU8522_I2C_RD_DATA3_REG09EH 0x09E
-#define AU8522_I2C_RD_DATA4_REG09FH 0x09F
-#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0
-#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1
-#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2
-
-#define AU8522_ENA_USB_REG101H 0x101
-
-#define AU8522_I2S_CTRL_0_REG110H 0x110
-#define AU8522_I2S_CTRL_1_REG111H 0x111
-#define AU8522_I2S_CTRL_2_REG112H 0x112
-
-#define AU8522_FRMREGFFECONTROL_REG121H 0x121
-#define AU8522_FRMREGDFECONTROL_REG122H 0x122
-
-#define AU8522_CARRFREQOFFSET0_REG201H 0x201
-#define AU8522_CARRFREQOFFSET1_REG202H 0x202
-
-#define AU8522_DECIMATION_GAIN_REG21AH 0x21A
-#define AU8522_FRMREGIFSLP_REG21BH 0x21B
-#define AU8522_FRMREGTHRDL2_REG21CH 0x21C
-#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D
-#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E
-#define AU8522_FRMREGPLLMODE_REG21FH 0x21F
-#define AU8522_FRMREGCSTHRD_REG220H 0x220
-#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221
-#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222
-#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223
-#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224
-#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225
-#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226
-#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227
-#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228
-
-/* Analog TV Decoder */
-#define AU8522_TVDEC_STATUS_REG000H 0x000
-#define AU8522_TVDEC_INT_STATUS_REG001H 0x001
-#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002
-#define AU8522_TVDEC_SHARPNESSREG009H 0x009
-#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A
-#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B
-#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C
-#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D
-#define AU8522_TVDEC_HUE_H_REG00EH 0x00E
-#define AU8522_TVDEC_HUE_L_REG00FH 0x00F
-#define AU8522_TVDEC_INT_MASK_REG010H 0x010
-#define AU8522_VIDEO_MODE_REG011H 0x011
-#define AU8522_TVDEC_PGA_REG012H 0x012
-#define AU8522_TVDEC_COMB_MODE_REG015H 0x015
-#define AU8522_REG016H 0x016
-#define AU8522_TVDED_DBG_MODE_REG060H 0x060
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061
-#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062
-#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063
-#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064
-#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065
-#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066
-#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067
-#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068
-#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069
-#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A
-#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D
-#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E
-#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F
-#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070
-#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073
-#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077
-#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078
-#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079
-#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A
-#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B
-#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E
-#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F
-
-#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4
-#define AU8522_TOREGAAGC_REG0E5H 0x0E5
-
-#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401
-#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402
-#define AU8522_FILTER_COEF_R410 0x410
-#define AU8522_FILTER_COEF_R411 0x411
-#define AU8522_FILTER_COEF_R412 0x412
-#define AU8522_FILTER_COEF_R413 0x413
-#define AU8522_FILTER_COEF_R414 0x414
-#define AU8522_FILTER_COEF_R415 0x415
-#define AU8522_FILTER_COEF_R416 0x416
-#define AU8522_FILTER_COEF_R417 0x417
-#define AU8522_FILTER_COEF_R418 0x418
-#define AU8522_FILTER_COEF_R419 0x419
-#define AU8522_FILTER_COEF_R41A 0x41A
-#define AU8522_FILTER_COEF_R41B 0x41B
-#define AU8522_FILTER_COEF_R41C 0x41C
-#define AU8522_FILTER_COEF_R41D 0x41D
-#define AU8522_FILTER_COEF_R41E 0x41E
-#define AU8522_FILTER_COEF_R41F 0x41F
-#define AU8522_FILTER_COEF_R420 0x420
-#define AU8522_FILTER_COEF_R421 0x421
-#define AU8522_FILTER_COEF_R422 0x422
-#define AU8522_FILTER_COEF_R423 0x423
-#define AU8522_FILTER_COEF_R424 0x424
-#define AU8522_FILTER_COEF_R425 0x425
-#define AU8522_FILTER_COEF_R426 0x426
-#define AU8522_FILTER_COEF_R427 0x427
-#define AU8522_FILTER_COEF_R428 0x428
-#define AU8522_FILTER_COEF_R429 0x429
-#define AU8522_FILTER_COEF_R42A 0x42A
-#define AU8522_FILTER_COEF_R42B 0x42B
-#define AU8522_FILTER_COEF_R42C 0x42C
-#define AU8522_FILTER_COEF_R42D 0x42D
-
-/* VBI Control Registers */
-#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004
-#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005
-#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006
-#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007
-#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017
-#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018
-#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019
-#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A
-#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B
-#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F
-#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022
-#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023
-
-#define AU8522_REG071H 0x071
-#define AU8522_REG072H 0x072
-#define AU8522_REG074H 0x074
-#define AU8522_REG075H 0x075
-
-/* Digital Demodulator Registers */
-#define AU8522_FRAME_COUNT0_REG084H 0x084
-#define AU8522_RS_STATUS_G0_REG085H 0x085
-#define AU8522_RS_STATUS_B0_REG086H 0x086
-#define AU8522_RS_STATUS_E_REG087H 0x087
-#define AU8522_DEMODULATION_STATUS_REG088H 0x088
-#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6
-#define AU8522_TSPORT_CONTROL_REG10BH 0x10B
-#define AU8522_TSTHES_REG10CH 0x10C
-#define AU8522_FRMREGDFEKEEP_REG301H 0x301
-#define AU8522_DFE_AVERAGE_REG302H 0x302
-#define AU8522_FRMREGEQLERRWIN_REG303H 0x303
-#define AU8522_FRMREGFFEKEEP_REG304H 0x304
-#define AU8522_FRMREGDFECONTROL1_REG305H 0x305
-#define AU8522_FRMREGEQLERRLOW_REG306H 0x306
-
-#define AU8522_REG42EH 0x42E
-#define AU8522_REG42FH 0x42F
-#define AU8522_REG430H 0x430
-#define AU8522_REG431H 0x431
-#define AU8522_REG432H 0x432
-#define AU8522_REG433H 0x433
-#define AU8522_REG434H 0x434
-#define AU8522_REG435H 0x435
-#define AU8522_REG436H 0x436
-
-/* GPIO Registers */
-#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0
-#define AU8522_GPIO_STATUS_REG0E1H 0x0E1
-#define AU8522_GPIO_DATA_REG0E2H 0x0E2
-
-/* Audio Control Registers */
-#define AU8522_AUDIOAGC_REG0EEH 0x0EE
-#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0
-#define AU8522_AUDIO_MODE_REG0F1H 0x0F1
-#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2
-#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3
-#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4
-#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7
-#define AU8522_REG0F9H 0x0F9
-
-#define AU8522_AUDIOAGC2_REG605H 0x605
-#define AU8522_AUDIOFREQ_REG606H 0x606
-
-
-/**************************************************************/
-
-#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4
-#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4
-#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4
-#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4
-#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4
-#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68
-#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28
-/* CH1 AS Y,CH3 AS C */
-#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23
-/* CH2 AS Y,CH4 AS C */
-#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A
-#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02
-
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD
-#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD
-
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01
-#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01
-
-/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
-#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79
-#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80
-#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80
-#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00
-#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00
-#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F
-#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00
-#define AU8522_REG016H_CVBS 0x00
-#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS 0x0B
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13 0x03
-#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13 0x00
-#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19
-#define AU8522_REG0F9H_AUDIO 0x20
-#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7
-#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A
-#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32
-#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19
-#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23
-#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41
-#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
-#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
-#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
-#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15
-#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
-#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
-#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
-#define AU8522_REG071H_CVBS 0x18
-#define AU8522_REG072H_CVBS 0x30
-#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0
-#define AU8522_REG074H_CVBS 0x80
-#define AU8522_REG075H_CVBS 0xF0
-#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB
-#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04
-#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00
-#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00
-#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE
-#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE
-#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00
-#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40
-
-/* Enables Closed captioning */
-#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
deleted file mode 100644
index 1a026239cdcc..000000000000
--- a/drivers/media/dvb/frontends/cxd2820r_t.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Sony CXD2820R demodulator driver
- *
- * Copyright (C) 2010 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 "cxd2820r_priv.h"
-
-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, bw_i;
- u32 if_freq, if_ctl;
- u64 num;
- u8 buf[3], bw_param;
- u8 bw_params1[][5] = {
- { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
- { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
- { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
- };
- u8 bw_params2[][2] = {
- { 0x1f, 0xdc }, /* 6 MHz */
- { 0x12, 0xf8 }, /* 7 MHz */
- { 0x01, 0xe0 }, /* 8 MHz */
- };
- struct reg_val_mask tab[] = {
- { 0x00080, 0x00, 0xff },
- { 0x00081, 0x03, 0xff },
- { 0x00085, 0x07, 0xff },
- { 0x00088, 0x01, 0xff },
-
- { 0x00070, priv->cfg.ts_mode, 0xff },
- { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
- { 0x000a5, 0x00, 0x01 },
- { 0x00082, 0x20, 0x60 },
- { 0x000c2, 0xc3, 0xff },
- { 0x0016a, 0x50, 0xff },
- { 0x00427, 0x41, 0xff },
- };
-
- 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)
- goto error;
-
- /* program tuner */
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe);
-
- if (priv->delivery_system != SYS_DVBT) {
- for (i = 0; i < ARRAY_SIZE(tab); i++) {
- ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
- tab[i].val, tab[i].mask);
- if (ret)
- goto error;
- }
- }
-
- priv->delivery_system = SYS_DVBT;
- priv->ber_running = 0; /* tune stops BER counter */
-
- /* 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 *= 0x1000000;
- if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
- buf[0] = ((if_ctl >> 16) & 0xff);
- buf[1] = ((if_ctl >> 8) & 0xff);
- buf[2] = ((if_ctl >> 0) & 0xff);
-
- ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
- if (ret)
- goto error;
-
- ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
- if (ret)
- goto error;
-
- ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
- if (ret)
- goto error;
-
- ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
- if (ret)
- goto error;
-
- ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
- if (ret)
- goto error;
-
- ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
- if (ret)
- goto error;
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-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;
- int ret;
- u8 buf[2];
-
- ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
- if (ret)
- goto error;
-
- switch ((buf[0] >> 6) & 0x03) {
- case 0:
- c->modulation = QPSK;
- break;
- case 1:
- c->modulation = QAM_16;
- break;
- case 2:
- c->modulation = QAM_64;
- break;
- }
-
- switch ((buf[1] >> 1) & 0x03) {
- case 0:
- c->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 1:
- c->transmission_mode = TRANSMISSION_MODE_8K;
- break;
- }
-
- switch ((buf[1] >> 3) & 0x03) {
- case 0:
- c->guard_interval = GUARD_INTERVAL_1_32;
- break;
- case 1:
- c->guard_interval = GUARD_INTERVAL_1_16;
- break;
- case 2:
- c->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 3:
- c->guard_interval = GUARD_INTERVAL_1_4;
- break;
- }
-
- switch ((buf[0] >> 3) & 0x07) {
- case 0:
- c->hierarchy = HIERARCHY_NONE;
- break;
- case 1:
- c->hierarchy = HIERARCHY_1;
- break;
- case 2:
- c->hierarchy = HIERARCHY_2;
- break;
- case 3:
- c->hierarchy = HIERARCHY_4;
- break;
- }
-
- switch ((buf[0] >> 0) & 0x07) {
- case 0:
- c->code_rate_HP = FEC_1_2;
- break;
- case 1:
- c->code_rate_HP = FEC_2_3;
- break;
- case 2:
- c->code_rate_HP = FEC_3_4;
- break;
- case 3:
- c->code_rate_HP = FEC_5_6;
- break;
- case 4:
- c->code_rate_HP = FEC_7_8;
- break;
- }
-
- switch ((buf[1] >> 5) & 0x07) {
- case 0:
- c->code_rate_LP = FEC_1_2;
- break;
- case 1:
- c->code_rate_LP = FEC_2_3;
- break;
- case 2:
- c->code_rate_LP = FEC_3_4;
- break;
- case 3:
- c->code_rate_LP = FEC_5_6;
- break;
- case 4:
- c->code_rate_LP = FEC_7_8;
- break;
- }
-
- ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
- if (ret)
- goto error;
-
- switch ((buf[0] >> 0) & 0x01) {
- case 0:
- c->inversion = INVERSION_OFF;
- break;
- case 1:
- c->inversion = INVERSION_ON;
- break;
- }
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[3], start_ber = 0;
- *ber = 0;
-
- if (priv->ber_running) {
- ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
- if (ret)
- goto error;
-
- if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
- *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
- start_ber = 1;
- }
- } else {
- priv->ber_running = 1;
- start_ber = 1;
- }
-
- if (start_ber) {
- /* (re)start BER */
- ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
- if (ret)
- goto error;
- }
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
- u16 *strength)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[2];
- u16 tmp;
-
- ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
- if (ret)
- goto error;
-
- tmp = (buf[0] & 0x0f) << 8 | buf[1];
- tmp = ~tmp & 0x0fff;
-
- /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
- *strength = tmp * 0xffff / 0x0fff;
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[2];
- u16 tmp;
- /* report SNR in dB * 10 */
-
- ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
- if (ret)
- goto error;
-
- tmp = (buf[0] & 0x1f) << 8 | buf[1];
- #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
- if (tmp)
- *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
- / 100);
- else
- *snr = 0;
-
- dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
-{
- *ucblocks = 0;
- /* no way to read ? */
- return 0;
-}
-
-int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[4];
- *status = 0;
-
- ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
- if (ret)
- goto error;
-
- if ((buf[0] & 0x07) == 6) {
- ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
- if (ret)
- goto error;
-
- if (((buf[1] >> 3) & 0x01) == 1) {
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- } else {
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI | FE_HAS_SYNC;
- }
- } else {
- ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
- if (ret)
- goto error;
-
- if ((buf[2] & 0x0f) >= 4) {
- ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
- if (ret)
- goto error;
-
- if (((buf[3] >> 4) & 0x01) == 1)
- *status |= FE_HAS_SIGNAL;
- }
- }
-
- dbg("%s: lock=%02x %02x %02x %02x", __func__,
- buf[0], buf[1], buf[2], buf[3]);
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_init_t(struct dvb_frontend *fe)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
-
- ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
- if (ret)
- goto error;
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_sleep_t(struct dvb_frontend *fe)
-{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret, i;
- struct reg_val_mask tab[] = {
- { 0x000ff, 0x1f, 0xff },
- { 0x00085, 0x00, 0xff },
- { 0x00088, 0x01, 0xff },
- { 0x00081, 0x00, 0xff },
- { 0x00080, 0x00, 0xff },
- };
-
- dbg("%s", __func__);
-
- priv->delivery_system = SYS_UNDEFINED;
-
- for (i = 0; i < ARRAY_SIZE(tab); i++) {
- ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
- tab[i].mask);
- if (ret)
- goto error;
- }
-
- return ret;
-error:
- dbg("%s: failed:%d", __func__, ret);
- return ret;
-}
-
-int cxd2820r_get_tune_settings_t(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;
-}
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
deleted file mode 100644
index 1ab34838221c..000000000000
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * descriptions + helper functions for simple dvb plls.
- *
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * 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/slab.h>
-#include <linux/module.h>
-#include <linux/dvb/frontend.h>
-#include <asm/types.h>
-
-#include "dvb-pll.h"
-
-struct dvb_pll_priv {
- /* pll number */
- int nr;
-
- /* i2c details */
- int pll_i2c_address;
- struct i2c_adapter *i2c;
-
- /* the PLL descriptor */
- struct dvb_pll_desc *pll_desc;
-
- /* cached frequency/bandwidth */
- u32 frequency;
- u32 bandwidth;
-};
-
-#define DVB_PLL_MAX 64
-
-static unsigned int dvb_pll_devcount;
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static unsigned int id[DVB_PLL_MAX] =
- { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
-module_param_array(id, int, NULL, 0644);
-MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
-
-/* ----------------------------------------------------------- */
-
-struct dvb_pll_desc {
- char *name;
- u32 min;
- u32 max;
- u32 iffreq;
- void (*set)(struct dvb_frontend *fe, u8 *buf);
- u8 *initdata;
- u8 *initdata2;
- u8 *sleepdata;
- int count;
- struct {
- u32 limit;
- u32 stepsize;
- u8 config;
- u8 cb;
- } entries[12];
-};
-
-/* ----------------------------------------------------------- */
-/* descriptions */
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
- .name = "Thomson dtt7579",
- .min = 177000000,
- .max = 858000000,
- .iffreq= 36166667,
- .sleepdata = (u8[]){ 2, 0xb4, 0x03 },
- .count = 4,
- .entries = {
- { 443250000, 166667, 0xb4, 0x02 },
- { 542000000, 166667, 0xb4, 0x08 },
- { 771000000, 166667, 0xbc, 0x08 },
- { 999999999, 166667, 0xf4, 0x08 },
- },
-};
-
-static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
-{
- u32 bw = fe->dtv_property_cache.bandwidth_hz;
- if (bw == 7000000)
- buf[3] |= 0x10;
-}
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
- .name = "Thomson dtt759x",
- .min = 177000000,
- .max = 896000000,
- .set = thomson_dtt759x_bw,
- .iffreq= 36166667,
- .sleepdata = (u8[]){ 2, 0x84, 0x03 },
- .count = 5,
- .entries = {
- { 264000000, 166667, 0xb4, 0x02 },
- { 470000000, 166667, 0xbc, 0x02 },
- { 735000000, 166667, 0xbc, 0x08 },
- { 835000000, 166667, 0xf4, 0x08 },
- { 999999999, 166667, 0xfc, 0x08 },
- },
-};
-
-static struct dvb_pll_desc dvb_pll_lg_z201 = {
- .name = "LG z201",
- .min = 174000000,
- .max = 862000000,
- .iffreq= 36166667,
- .sleepdata = (u8[]){ 2, 0xbc, 0x03 },
- .count = 5,
- .entries = {
- { 157500000, 166667, 0xbc, 0x01 },
- { 443250000, 166667, 0xbc, 0x02 },
- { 542000000, 166667, 0xbc, 0x04 },
- { 830000000, 166667, 0xf4, 0x04 },
- { 999999999, 166667, 0xfc, 0x04 },
- },
-};
-
-static struct dvb_pll_desc dvb_pll_unknown_1 = {
- .name = "unknown 1", /* used by dntv live dvb-t */
- .min = 174000000,
- .max = 862000000,
- .iffreq= 36166667,
- .count = 9,
- .entries = {
- { 150000000, 166667, 0xb4, 0x01 },
- { 173000000, 166667, 0xbc, 0x01 },
- { 250000000, 166667, 0xb4, 0x02 },
- { 400000000, 166667, 0xbc, 0x02 },
- { 420000000, 166667, 0xf4, 0x02 },
- { 470000000, 166667, 0xfc, 0x02 },
- { 600000000, 166667, 0xbc, 0x08 },
- { 730000000, 166667, 0xf4, 0x08 },
- { 999999999, 166667, 0xfc, 0x08 },
- },
-};
-
-/* Infineon TUA6010XS
- * used in Thomson Cable Tuner
- */
-static struct dvb_pll_desc dvb_pll_tua6010xs = {
- .name = "Infineon TUA6010XS",
- .min = 44250000,
- .max = 858000000,
- .iffreq= 36125000,
- .count = 3,
- .entries = {
- { 115750000, 62500, 0x8e, 0x03 },
- { 403250000, 62500, 0x8e, 0x06 },
- { 999999999, 62500, 0x8e, 0x85 },
- },
-};
-
-/* Panasonic env57h1xd5 (some Philips PLL ?) */
-static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
- .name = "Panasonic ENV57H1XD5",
- .min = 44250000,
- .max = 858000000,
- .iffreq= 36125000,
- .count = 4,
- .entries = {
- { 153000000, 166667, 0xc2, 0x41 },
- { 470000000, 166667, 0xc2, 0x42 },
- { 526000000, 166667, 0xc2, 0x84 },
- { 999999999, 166667, 0xc2, 0xa4 },
- },
-};
-
-/* Philips TDA6650/TDA6651
- * used in Panasonic ENV77H11D5
- */
-static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
-{
- u32 bw = fe->dtv_property_cache.bandwidth_hz;
- if (bw == 8000000)
- buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_tda665x = {
- .name = "Philips TDA6650/TDA6651",
- .min = 44250000,
- .max = 858000000,
- .set = tda665x_bw,
- .iffreq= 36166667,
- .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
- .count = 12,
- .entries = {
- { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
- { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
- { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
- { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
- { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
- { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
- { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
- { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
- { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
- { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
- { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
- { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
- }
-};
-
-/* Infineon TUA6034
- * used in LG TDTP E102P
- */
-static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
-{
- u32 bw = fe->dtv_property_cache.bandwidth_hz;
- if (bw == 7000000)
- buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_tua6034 = {
- .name = "Infineon TUA6034",
- .min = 44250000,
- .max = 858000000,
- .iffreq= 36166667,
- .count = 3,
- .set = tua6034_bw,
- .entries = {
- { 174500000, 62500, 0xce, 0x01 },
- { 230000000, 62500, 0xce, 0x02 },
- { 999999999, 62500, 0xce, 0x04 },
- },
-};
-
-/* ALPS TDED4
- * used in Nebula-Cards and USB boxes
- */
-static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
-{
- u32 bw = fe->dtv_property_cache.bandwidth_hz;
- if (bw == 8000000)
- buf[3] |= 0x04;
-}
-
-static struct dvb_pll_desc dvb_pll_tded4 = {
- .name = "ALPS TDED4",
- .min = 47000000,
- .max = 863000000,
- .iffreq= 36166667,
- .set = tded4_bw,
- .count = 4,
- .entries = {
- { 153000000, 166667, 0x85, 0x01 },
- { 470000000, 166667, 0x85, 0x02 },
- { 823000000, 166667, 0x85, 0x08 },
- { 999999999, 166667, 0x85, 0x88 },
- }
-};
-
-/* ALPS TDHU2
- * used in AverTVHD MCE A180
- */
-static struct dvb_pll_desc dvb_pll_tdhu2 = {
- .name = "ALPS TDHU2",
- .min = 54000000,
- .max = 864000000,
- .iffreq= 44000000,
- .count = 4,
- .entries = {
- { 162000000, 62500, 0x85, 0x01 },
- { 426000000, 62500, 0x85, 0x02 },
- { 782000000, 62500, 0x85, 0x08 },
- { 999999999, 62500, 0x85, 0x88 },
- }
-};
-
-/* Samsung TBMV30111IN / TBMV30712IN1
- * used in Air2PC ATSC - 2nd generation (nxt2002)
- */
-static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
- .name = "Samsung TBMV30111IN / TBMV30712IN1",
- .min = 54000000,
- .max = 860000000,
- .iffreq= 44000000,
- .count = 6,
- .entries = {
- { 172000000, 166667, 0xb4, 0x01 },
- { 214000000, 166667, 0xb4, 0x02 },
- { 467000000, 166667, 0xbc, 0x02 },
- { 721000000, 166667, 0xbc, 0x08 },
- { 841000000, 166667, 0xf4, 0x08 },
- { 999999999, 166667, 0xfc, 0x02 },
- }
-};
-
-/*
- * Philips SD1878 Tuner.
- */
-static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
- .name = "Philips SD1878",
- .min = 950000,
- .max = 2150000,
- .iffreq= 249, /* zero-IF, offset 249 is to round up */
- .count = 4,
- .entries = {
- { 1250000, 500, 0xc4, 0x00},
- { 1450000, 500, 0xc4, 0x40},
- { 2050000, 500, 0xc4, 0x80},
- { 2150000, 500, 0xc4, 0xc0},
- },
-};
-
-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 = (c->symbol_rate * 27) / 32000;
- struct i2c_msg msg = {
- .addr = priv->pll_i2c_address,
- .flags = 0,
- .buf = buf,
- .len = 4
- };
- int result;
- u8 lpf;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- result = i2c_transfer(priv->i2c, &msg, 1);
- if (result != 1)
- printk(KERN_ERR "%s: i2c_transfer failed:%d",
- __func__, result);
-
- if (b_w <= 10000)
- lpf = 0xc;
- else if (b_w <= 12000)
- lpf = 0x2;
- else if (b_w <= 14000)
- lpf = 0xa;
- else if (b_w <= 16000)
- lpf = 0x6;
- else if (b_w <= 18000)
- lpf = 0xe;
- else if (b_w <= 20000)
- lpf = 0x1;
- else if (b_w <= 22000)
- lpf = 0x9;
- else if (b_w <= 24000)
- lpf = 0x5;
- else if (b_w <= 26000)
- lpf = 0xd;
- else if (b_w <= 28000)
- lpf = 0x3;
- else
- lpf = 0xb;
- buf[2] ^= 0x1c; /* Flip bits 3-5 */
- /* Set lpf */
- buf[2] |= ((lpf >> 2) & 0x3) << 3;
- buf[3] |= (lpf & 0x3) << 2;
-
- return;
-}
-
-static struct dvb_pll_desc dvb_pll_opera1 = {
- .name = "Opera Tuner",
- .min = 900000,
- .max = 2250000,
- .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 },
- .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 },
- .iffreq= 0,
- .set = opera1_bw,
- .count = 8,
- .entries = {
- { 1064000, 500, 0xf9, 0xc2 },
- { 1169000, 500, 0xf9, 0xe2 },
- { 1299000, 500, 0xf9, 0x20 },
- { 1444000, 500, 0xf9, 0x40 },
- { 1606000, 500, 0xf9, 0x60 },
- { 1777000, 500, 0xf9, 0x80 },
- { 1941000, 500, 0xf9, 0xa0 },
- { 2250000, 500, 0xf9, 0xc0 },
- }
-};
-
-static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
- struct i2c_msg msg = {
- .addr = priv->pll_i2c_address,
- .flags = 0,
- .buf = buf,
- .len = 4
- };
- int result;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- result = i2c_transfer(priv->i2c, &msg, 1);
- if (result != 1)
- printk(KERN_ERR "%s: i2c_transfer failed:%d",
- __func__, result);
-
- buf[2] = 0x9e;
- buf[3] = 0x90;
-
- return;
-}
-
-/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
-static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
- .name = "Samsung DTOS403IH102A",
- .min = 44250000,
- .max = 858000000,
- .iffreq = 36125000,
- .count = 8,
- .set = samsung_dtos403ih102a_set,
- .entries = {
- { 135000000, 62500, 0xbe, 0x01 },
- { 177000000, 62500, 0xf6, 0x01 },
- { 370000000, 62500, 0xbe, 0x02 },
- { 450000000, 62500, 0xf6, 0x02 },
- { 466000000, 62500, 0xfe, 0x02 },
- { 538000000, 62500, 0xbe, 0x08 },
- { 826000000, 62500, 0xf6, 0x08 },
- { 999999999, 62500, 0xfe, 0x08 },
- }
-};
-
-/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
-static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
- .name = "Samsung TDTC9251DH0",
- .min = 48000000,
- .max = 863000000,
- .iffreq = 36166667,
- .count = 3,
- .entries = {
- { 157500000, 166667, 0xcc, 0x09 },
- { 443000000, 166667, 0xcc, 0x0a },
- { 863000000, 166667, 0xcc, 0x08 },
- }
-};
-
-/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
-static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
- .name = "Samsung TBDU18132",
- .min = 950000,
- .max = 2150000, /* guesses */
- .iffreq = 0,
- .count = 2,
- .entries = {
- { 1550000, 125, 0x84, 0x82 },
- { 4095937, 125, 0x84, 0x80 },
- }
- /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
- * by this driver. The two extra bits are 0x60 in the third byte. 15
- * bits is enough for over 4 GHz, which is enough to cover the range
- * of this tuner. We could use the additional divisor bits by adding
- * more entries, e.g.
- { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
- { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
- { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
-};
-
-/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
-static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
- .name = "Samsung TBMU24112",
- .min = 950000,
- .max = 2150000, /* guesses */
- .iffreq = 0,
- .count = 2,
- .entries = {
- { 1500000, 125, 0x84, 0x18 },
- { 9999999, 125, 0x84, 0x08 },
- }
-};
-
-/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
-/* byte 4 : 1 * * AGD R3 R2 R1 R0
- * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
- * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
- * Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
- * 47 - 153 0 * 0 0 0 0 0 1 0x01
- * 153 - 430 0 * 0 0 0 0 1 0 0x02
- * 430 - 822 0 * 0 0 1 0 0 0 0x08
- * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
-static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
- .name = "ALPS TDEE4",
- .min = 47000000,
- .max = 862000000,
- .iffreq = 36125000,
- .count = 4,
- .entries = {
- { 153000000, 62500, 0x95, 0x01 },
- { 430000000, 62500, 0x95, 0x02 },
- { 822000000, 62500, 0x95, 0x08 },
- { 999999999, 62500, 0x95, 0x88 },
- }
-};
-
-/* ----------------------------------------------------------- */
-
-static struct dvb_pll_desc *pll_list[] = {
- [DVB_PLL_UNDEFINED] = NULL,
- [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
- [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
- [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
- [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
- [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
- [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
- [DVB_PLL_TUA6034] = &dvb_pll_tua6034,
- [DVB_PLL_TDA665X] = &dvb_pll_tda665x,
- [DVB_PLL_TDED4] = &dvb_pll_tded4,
- [DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4,
- [DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
- [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
- [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
- [DVB_PLL_OPERA1] = &dvb_pll_opera1,
- [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
- [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0,
- [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132,
- [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112,
-};
-
-/* ----------------------------------------------------------- */
-/* code */
-
-static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
- const u32 frequency)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
- struct dvb_pll_desc *desc = priv->pll_desc;
- u32 div;
- int i;
-
- if (frequency && (frequency < desc->min || frequency > desc->max))
- return -EINVAL;
-
- for (i = 0; i < desc->count; i++) {
- if (frequency > desc->entries[i].limit)
- continue;
- break;
- }
-
- if (debug)
- printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
- frequency, i, desc->count);
- if (i == desc->count)
- return -EINVAL;
-
- div = (frequency + desc->iffreq +
- desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
- buf[0] = div >> 8;
- buf[1] = div & 0xff;
- buf[2] = desc->entries[i].config;
- buf[3] = desc->entries[i].cb;
-
- if (desc->set)
- desc->set(fe, buf);
-
- if (debug)
- printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
- desc->name, div, buf[0], buf[1], buf[2], buf[3]);
-
- // calculate the frequency we set it to
- return (div * desc->entries[i].stepsize) - desc->iffreq;
-}
-
-static int dvb_pll_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
- return 0;
-}
-
-static int dvb_pll_sleep(struct dvb_frontend *fe)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
-
- if (priv->i2c == NULL)
- return -EINVAL;
-
- if (priv->pll_desc->sleepdata) {
- struct i2c_msg msg = { .flags = 0,
- .addr = priv->pll_i2c_address,
- .buf = priv->pll_desc->sleepdata + 1,
- .len = priv->pll_desc->sleepdata[0] };
-
- int result;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
- return result;
- }
- return 0;
- }
- /* Shouldn't be called when initdata is NULL, maybe BUG()? */
- return -EINVAL;
-}
-
-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 =
- { .addr = priv->pll_i2c_address, .flags = 0,
- .buf = buf, .len = sizeof(buf) };
- int result;
- u32 frequency = 0;
-
- if (priv->i2c == NULL)
- return -EINVAL;
-
- result = dvb_pll_configure(fe, buf, c->frequency);
- if (result < 0)
- return result;
- else
- frequency = result;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
- return result;
- }
-
- priv->frequency = frequency;
- priv->bandwidth = c->bandwidth_hz;
-
- return 0;
-}
-
-static int dvb_pll_calc_regs(struct dvb_frontend *fe,
- 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;
-
- if (buf_len < 5)
- return -EINVAL;
-
- result = dvb_pll_configure(fe, buf + 1, c->frequency);
- if (result < 0)
- return result;
- else
- frequency = result;
-
- buf[0] = priv->pll_i2c_address;
-
- priv->frequency = frequency;
- priv->bandwidth = c->bandwidth_hz;
-
- return 5;
-}
-
-static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
- return 0;
-}
-
-static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
- *bandwidth = priv->bandwidth;
- return 0;
-}
-
-static int dvb_pll_init(struct dvb_frontend *fe)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
-
- if (priv->i2c == NULL)
- return -EINVAL;
-
- if (priv->pll_desc->initdata) {
- struct i2c_msg msg = { .flags = 0,
- .addr = priv->pll_i2c_address,
- .buf = priv->pll_desc->initdata + 1,
- .len = priv->pll_desc->initdata[0] };
-
- int result;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- result = i2c_transfer(priv->i2c, &msg, 1);
- if (result != 1)
- return result;
- if (priv->pll_desc->initdata2) {
- msg.buf = priv->pll_desc->initdata2 + 1;
- msg.len = priv->pll_desc->initdata2[0];
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- result = i2c_transfer(priv->i2c, &msg, 1);
- if (result != 1)
- return result;
- }
- return 0;
- }
- /* Shouldn't be called when initdata is NULL, maybe BUG()? */
- return -EINVAL;
-}
-
-static struct dvb_tuner_ops dvb_pll_tuner_ops = {
- .release = dvb_pll_release,
- .sleep = dvb_pll_sleep,
- .init = dvb_pll_init,
- .set_params = dvb_pll_set_params,
- .calc_regs = dvb_pll_calc_regs,
- .get_frequency = dvb_pll_get_frequency,
- .get_bandwidth = dvb_pll_get_bandwidth,
-};
-
-struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
- struct i2c_adapter *i2c,
- unsigned int pll_desc_id)
-{
- u8 b1 [] = { 0 };
- struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
- .buf = b1, .len = 1 };
- struct dvb_pll_priv *priv = NULL;
- int ret;
- struct dvb_pll_desc *desc;
-
- if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
- (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
- pll_desc_id = id[dvb_pll_devcount];
-
- BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
-
- desc = pll_list[pll_desc_id];
-
- if (i2c != NULL) {
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- ret = i2c_transfer (i2c, &msg, 1);
- if (ret != 1)
- return NULL;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
-
- priv->pll_i2c_address = pll_addr;
- priv->i2c = i2c;
- priv->pll_desc = desc;
- priv->nr = dvb_pll_devcount++;
-
- memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- strncpy(fe->ops.tuner_ops.info.name, desc->name,
- sizeof(fe->ops.tuner_ops.info.name));
- fe->ops.tuner_ops.info.frequency_min = desc->min;
- fe->ops.tuner_ops.info.frequency_max = desc->max;
- if (!desc->initdata)
- fe->ops.tuner_ops.init = NULL;
- if (!desc->sleepdata)
- fe->ops.tuner_ops.sleep = NULL;
-
- fe->tuner_priv = priv;
-
- if ((debug) || (id[priv->nr] == pll_desc_id)) {
- printk("dvb-pll[%d]", priv->nr);
- if (i2c != NULL)
- printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
- printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
- id[priv->nr] == pll_desc_id ?
- "insmod option" : "autodetected");
- }
-
- return fe;
-}
-EXPORT_SYMBOL(dvb_pll_attach);
-
-MODULE_DESCRIPTION("dvb pll library");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
deleted file mode 100644
index 086964344c38..000000000000
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * descriptions + helper functions for simple dvb plls.
- */
-
-#ifndef __DVB_PLL_H__
-#define __DVB_PLL_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#define DVB_PLL_UNDEFINED 0
-#define DVB_PLL_THOMSON_DTT7579 1
-#define DVB_PLL_THOMSON_DTT759X 2
-#define DVB_PLL_LG_Z201 3
-#define DVB_PLL_UNKNOWN_1 4
-#define DVB_PLL_TUA6010XS 5
-#define DVB_PLL_ENV57H1XD5 6
-#define DVB_PLL_TUA6034 7
-#define DVB_PLL_TDA665X 8
-#define DVB_PLL_TDED4 9
-#define DVB_PLL_TDHU2 10
-#define DVB_PLL_SAMSUNG_TBMV 11
-#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
-#define DVB_PLL_OPERA1 13
-#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
-#define DVB_PLL_SAMSUNG_TDTC9251DH0 15
-#define DVB_PLL_SAMSUNG_TBDU18132 16
-#define DVB_PLL_SAMSUNG_TBMU24112 17
-#define DVB_PLL_TDEE4 18
-
-/**
- * Attach a dvb-pll to the supplied frontend structure.
- *
- * @param fe Frontend to attach to.
- * @param pll_addr i2c address of the PLL (if used).
- * @param i2c i2c adapter to use (set to NULL if not used).
- * @param pll_desc_id dvb_pll_desc to use.
- * @return Frontend pointer on success, NULL on failure
- */
-#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
-extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
- int pll_addr,
- struct i2c_adapter *i2c,
- unsigned int pll_desc_id);
-#else
-static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
- int pll_addr,
- struct i2c_adapter *i2c,
- unsigned int pll_desc_id)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
deleted file mode 100644
index 708cbf197913..000000000000
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Driver for it913x-fe Frontend
- *
- * with support for on chip it9137 integral tuner
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9137 Copyright (C) ITE Tech Inc.
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "dvb_frontend.h"
-#include "it913x-fe.h"
-#include "it913x-fe-priv.h"
-
-static int it913x_debug;
-
-module_param_named(debug, it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-#define dprintk(level, args...) do { \
- if (level & it913x_debug) \
- printk(KERN_DEBUG "it913x-fe: " args); \
-} while (0)
-
-#define deb_info(args...) dprintk(0x01, args)
-#define debug_data_snipet(level, name, p) \
- 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;
- fe_modulation_t constellation;
- fe_transmit_mode_t transmission_mode;
- u8 priority;
- u32 crystalFrequency;
- u32 adcFrequency;
- u8 tuner_type;
- struct adctable *table;
- fe_status_t it913x_status;
- u16 tun_xtal;
- u8 tun_fdiv;
- u8 tun_clk_mode;
- u32 tun_fn_min;
- u32 ucblocks;
-};
-
-static int it913x_read_reg(struct it913x_fe_state *state,
- u32 reg, u8 *data, u8 count)
-{
- int ret;
- u8 pro = PRO_DMOD; /* All reads from demodulator */
- u8 b[4];
- struct i2c_msg msg[2] = {
- { .addr = state->i2c_addr + (pro << 1), .flags = 0,
- .buf = b, .len = sizeof(b) },
- { .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD,
- .buf = data, .len = count }
- };
- b[0] = (u8) reg >> 24;
- b[1] = (u8)(reg >> 16) & 0xff;
- b[2] = (u8)(reg >> 8) & 0xff;
- b[3] = (u8) reg & 0xff;
-
- ret = i2c_transfer(state->i2c_adap, msg, 2);
-
- return ret;
-}
-
-static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg)
-{
- int ret;
- u8 b[1];
- ret = it913x_read_reg(state, reg, &b[0], sizeof(b));
- return (ret < 0) ? -ENODEV : b[0];
-}
-
-static int it913x_write(struct it913x_fe_state *state,
- u8 pro, u32 reg, u8 buf[], u8 count)
-{
- u8 b[256];
- struct i2c_msg msg[1] = {
- { .addr = state->i2c_addr + (pro << 1), .flags = 0,
- .buf = b, .len = count + 4 }
- };
- int ret;
-
- b[0] = (u8) reg >> 24;
- b[1] = (u8)(reg >> 16) & 0xff;
- b[2] = (u8)(reg >> 8) & 0xff;
- b[3] = (u8) reg & 0xff;
- memcpy(&b[4], buf, count);
-
- ret = i2c_transfer(state->i2c_adap, msg, 1);
-
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-static int it913x_write_reg(struct it913x_fe_state *state,
- u8 pro, u32 reg, u32 data)
-{
- int ret;
- u8 b[4];
- u8 s;
-
- b[0] = data >> 24;
- b[1] = (data >> 16) & 0xff;
- b[2] = (data >> 8) & 0xff;
- b[3] = data & 0xff;
- /* expand write as needed */
- if (data < 0x100)
- s = 3;
- else if (data < 0x1000)
- s = 2;
- else if (data < 0x100000)
- s = 1;
- else
- s = 0;
-
- ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s);
-
- return ret;
-}
-
-static int it913x_fe_script_loader(struct it913x_fe_state *state,
- struct it913xset *loadscript)
-{
- int ret, i;
- if (loadscript == NULL)
- return -EINVAL;
-
- for (i = 0; i < 1000; ++i) {
- if (loadscript[i].pro == 0xff)
- break;
- ret = it913x_write(state, loadscript[i].pro,
- loadscript[i].address,
- loadscript[i].reg, loadscript[i].count);
- if (ret < 0)
- return -ENODEV;
- }
- return 0;
-}
-
-static int it913x_init_tuner(struct it913x_fe_state *state)
-{
- int ret, i, reg;
- u8 val, nv_val;
- u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
- u8 b[2];
-
- reg = it913x_read_reg_u8(state, 0xec86);
- switch (reg) {
- case 0:
- state->tun_clk_mode = reg;
- state->tun_xtal = 2000;
- state->tun_fdiv = 3;
- val = 16;
- break;
- case -ENODEV:
- return -ENODEV;
- case 1:
- default:
- state->tun_clk_mode = reg;
- state->tun_xtal = 640;
- state->tun_fdiv = 1;
- val = 6;
- break;
- }
-
- reg = it913x_read_reg_u8(state, 0xed03);
-
- if (reg < 0)
- return -ENODEV;
- else if (reg < sizeof(nv))
- nv_val = nv[reg];
- else
- nv_val = 2;
-
- for (i = 0; i < 50; i++) {
- ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b));
- reg = (b[1] << 8) + b[0];
- if (reg > 0)
- break;
- if (ret < 0)
- return -ENODEV;
- udelay(2000);
- }
- state->tun_fn_min = state->tun_xtal * reg;
- state->tun_fn_min /= (state->tun_fdiv * nv_val);
- deb_info("Tuner fn_min %d", state->tun_fn_min);
-
- 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,
- u32 bandwidth, u32 frequency_m)
-{
- struct it913xset *set_tuner = set_it9137_template;
- int ret, reg;
- u32 frequency = frequency_m / 1000;
- u32 freq, temp_f, tmp;
- u16 iqik_m_cal;
- u16 n_div;
- u8 n;
- u8 l_band;
- 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) {
- l_band = 0;
- lna_band = 0;
- } else if (frequency > 440000 && frequency <= 484000) {
- l_band = 1;
- lna_band = 1;
- } else if (frequency > 484000 && frequency <= 533000) {
- l_band = 1;
- lna_band = 2;
- } else if (frequency > 533000 && frequency <= 587000) {
- l_band = 1;
- lna_band = 3;
- } else if (frequency > 587000 && frequency <= 645000) {
- l_band = 1;
- lna_band = 4;
- } else if (frequency > 645000 && frequency <= 710000) {
- l_band = 1;
- lna_band = 5;
- } else if (frequency > 710000 && frequency <= 782000) {
- l_band = 1;
- lna_band = 6;
- } else if (frequency > 782000 && frequency <= 860000) {
- l_band = 1;
- lna_band = 7;
- } else if (frequency > 1450000 && frequency <= 1492000) {
- l_band = 1;
- lna_band = 0;
- } else if (frequency > 1660000 && frequency <= 1685000) {
- l_band = 1;
- lna_band = 1;
- } else
- return -EINVAL;
- set_tuner[0].reg[0] = lna_band;
-
- switch (bandwidth) {
- case 5000000:
- bw = 0;
- break;
- case 6000000:
- bw = 2;
- break;
- case 7000000:
- bw = 4;
- break;
- default:
- case 8000000:
- bw = 6;
- break;
- }
-
- set_tuner[1].reg[0] = bw;
- set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
-
- if (frequency > 53000 && frequency <= 74000) {
- n_div = 48;
- n = 0;
- } else if (frequency > 74000 && frequency <= 111000) {
- n_div = 32;
- n = 1;
- } else if (frequency > 111000 && frequency <= 148000) {
- n_div = 24;
- n = 2;
- } else if (frequency > 148000 && frequency <= 222000) {
- n_div = 16;
- n = 3;
- } else if (frequency > 222000 && frequency <= 296000) {
- n_div = 12;
- n = 4;
- } else if (frequency > 296000 && frequency <= 445000) {
- n_div = 8;
- n = 5;
- } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
- n_div = 6;
- n = 6;
- } else if (frequency > state->tun_fn_min && frequency <= 950000) {
- n_div = 4;
- n = 7;
- } else if (frequency > 1450000 && frequency <= 1680000) {
- n_div = 2;
- n = 0;
- } else
- return -EINVAL;
-
- reg = it913x_read_reg_u8(state, 0xed81);
- iqik_m_cal = (u16)reg * n_div;
-
- if (reg < 0x20) {
- if (state->tun_clk_mode == 0)
- iqik_m_cal = (iqik_m_cal * 9) >> 5;
- else
- iqik_m_cal >>= 1;
- } else {
- iqik_m_cal = 0x40 - iqik_m_cal;
- if (state->tun_clk_mode == 0)
- iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
- else
- iqik_m_cal = ~(iqik_m_cal >> 1);
- }
-
- temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
- freq = temp_f / state->tun_xtal;
- tmp = freq * state->tun_xtal;
-
- if ((temp_f - tmp) >= (state->tun_xtal >> 1))
- freq++;
-
- freq += (u32) n << 13;
- /* Frequency OMEGA_IQIK_M_CAL_MID*/
- temp_f = freq + (u32)iqik_m_cal;
-
- set_tuner[3].reg[0] = temp_f & 0xff;
- set_tuner[4].reg[0] = (temp_f >> 8) & 0xff;
-
- deb_info("High Frequency = %04x", temp_f);
-
- /* Lower frequency */
- set_tuner[5].reg[0] = freq & 0xff;
- set_tuner[6].reg[0] = (freq >> 8) & 0xff;
-
- deb_info("low Frequency = %04x", freq);
-
- ret = it913x_fe_script_loader(state, set_tuner);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_select_bw(struct it913x_fe_state *state,
- u32 bandwidth, u32 adcFrequency)
-{
- int ret, i;
- u8 buffer[256];
- u32 coeff[8];
- u16 bfsfcw_fftinx_ratio;
- u16 fftinx_bfsfcw_ratio;
- u8 count;
- u8 bw;
- u8 adcmultiplier;
-
- deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
-
- switch (bandwidth) {
- case 5000000:
- bw = 3;
- break;
- case 6000000:
- bw = 0;
- break;
- case 7000000:
- bw = 1;
- break;
- default:
- case 8000000:
- bw = 2;
- break;
- }
- ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
-
- if (state->table == NULL)
- return -EINVAL;
-
- /* In write order */
- coeff[0] = state->table[bw].coeff_1_2048;
- coeff[1] = state->table[bw].coeff_2_2k;
- coeff[2] = state->table[bw].coeff_1_8191;
- coeff[3] = state->table[bw].coeff_1_8192;
- coeff[4] = state->table[bw].coeff_1_8193;
- coeff[5] = state->table[bw].coeff_2_8k;
- coeff[6] = state->table[bw].coeff_1_4096;
- coeff[7] = state->table[bw].coeff_2_4k;
- bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio;
- fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio;
-
- /* ADC multiplier */
- ret = it913x_read_reg_u8(state, ADC_X_2);
- if (ret < 0)
- return -EINVAL;
-
- adcmultiplier = ret;
-
- count = 0;
-
- /* Build Buffer for COEFF Registers */
- for (i = 0; i < 8; i++) {
- if (adcmultiplier == 1)
- coeff[i] /= 2;
- buffer[count++] = (coeff[i] >> 24) & 0x3;
- buffer[count++] = (coeff[i] >> 16) & 0xff;
- buffer[count++] = (coeff[i] >> 8) & 0xff;
- buffer[count++] = coeff[i] & 0xff;
- }
-
- /* bfsfcw_fftinx_ratio register 0x21-0x22 */
- buffer[count++] = bfsfcw_fftinx_ratio & 0xff;
- buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff;
- /* fftinx_bfsfcw_ratio register 0x23-0x24 */
- buffer[count++] = fftinx_bfsfcw_ratio & 0xff;
- buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff;
- /* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/
- ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count);
-
- for (i = 0; i < 42; i += 8)
- debug_data_snipet(0x1, "Buffer", &buffer[i]);
-
- return ret;
-}
-
-
-
-static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret, i;
- fe_status_t old_status = state->it913x_status;
- *status = 0;
-
- if (state->it913x_status == 0) {
- ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
- if (ret == 0x1) {
- *status |= FE_HAS_SIGNAL;
- for (i = 0; i < 40; i++) {
- ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK);
- if (ret == 0x1)
- break;
- msleep(25);
- }
- if (ret == 0x1)
- *status |= FE_HAS_CARRIER
- | FE_HAS_VITERBI
- | FE_HAS_SYNC;
- state->it913x_status = *status;
- }
- }
-
- if (state->it913x_status & FE_HAS_SYNC) {
- ret = it913x_read_reg_u8(state, TPSD_LOCK);
- if (ret == 0x1)
- *status |= FE_HAS_LOCK
- | state->it913x_status;
- else
- state->it913x_status = 0;
- if (old_status != state->it913x_status)
- ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret);
- }
-
- 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 = 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)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- 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)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- u8 reg[5];
- /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
- 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)
-{
- 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 dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct it913x_fe_state *state = fe->demodulator_priv;
- u8 reg[8];
-
- it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
-
- if (reg[3] < 3)
- p->modulation = fe_con[reg[3]];
-
- if (reg[0] < 3)
- p->transmission_mode = fe_mode[reg[0]];
-
- if (reg[1] < 4)
- p->guard_interval = fe_gi[reg[1]];
-
- if (reg[2] < 4)
- p->hierarchy = fe_hi[reg[2]];
-
- state->priority = reg[5];
-
- 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 dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct it913x_fe_state *state = fe->demodulator_priv;
- int i;
- u8 empty_ch, last_ch;
-
- state->it913x_status = 0;
-
- /* Set bw*/
- it913x_fe_select_bw(state, p->bandwidth_hz,
- state->adcFrequency);
-
- /* Training Mode Off */
- it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
-
- /* Clear Empty Channel */
- it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
-
- /* Clear bits */
- it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
- /* LED on */
- it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
- /* Select Band*/
- if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
- i = 0;
- else if ((p->frequency >= 350000000) && (p->frequency <= 900000000))
- i = 1;
- else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
- i = 2;
- else
- return -EOPNOTSUPP;
-
- it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
-
- deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
- switch (state->tuner_type) {
- case IT9135_38:
- case IT9135_51:
- case IT9135_52:
- case IT9135_60:
- case IT9135_61:
- case IT9135_62:
- it9137_set_tuner(state,
- p->bandwidth_hz, p->frequency);
- break;
- default:
- if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- break;
- }
- /* LED off */
- it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
- /* Trigger ofsm */
- it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
- last_ch = 2;
- for (i = 0; i < 40; ++i) {
- empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
- if (last_ch == 1 && empty_ch == 1)
- break;
- if (last_ch == 2 && empty_ch == 2)
- return 0;
- last_ch = empty_ch;
- msleep(25);
- }
- for (i = 0; i < 40; ++i) {
- if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1)
- break;
- msleep(25);
- }
-
- state->frequency = p->frequency;
- return 0;
-}
-
-static int it913x_fe_suspend(struct it913x_fe_state *state)
-{
- int ret, i;
- u8 b;
-
- ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1);
-
- ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
-
- for (i = 0; i < 128; i++) {
- ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1);
- if (ret < 0)
- return -ENODEV;
- if (b == 0)
- break;
-
- }
-
- ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8);
- /* Turn LED off */
- ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
-
- ret |= it913x_fe_script_loader(state, it9137_tuner_off);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-/* Power sequence */
-/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */
-/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */
-
-static int it913x_fe_sleep(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- return it913x_fe_suspend(state);
-}
-
-static u32 compute_div(u32 a, u32 b, u32 x)
-{
- u32 res = 0;
- u32 c = 0;
- u32 i = 0;
-
- if (a > b) {
- c = a / b;
- a = a - c * b;
- }
-
- for (i = 0; i < x; i++) {
- if (a >= b) {
- res += 1;
- a -= b;
- }
- a <<= 1;
- res <<= 1;
- }
-
- res = (c << x) + res;
-
- return res;
-}
-
-static int it913x_fe_start(struct it913x_fe_state *state)
-{
- struct it913xset *set_lna;
- struct it913xset *set_mode;
- int ret;
- u8 adf = (state->config->adf & 0xf);
- u32 adc, xtal;
- u8 b[4];
-
- if (state->config->chip_ver == 1)
- ret = it913x_init_tuner(state);
-
- info("ADF table value :%02x", adf);
-
- if (adf < 10) {
- state->crystalFrequency = fe_clockTable[adf].xtal ;
- state->table = fe_clockTable[adf].table;
- state->adcFrequency = state->table->adcFrequency;
-
- adc = compute_div(state->adcFrequency, 1000000ul, 19ul);
- xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul);
-
- } else
- return -EINVAL;
-
- /* 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);
- ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
-
- ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type);
- ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01);
- ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01);
-
- b[0] = xtal & 0xff;
- b[1] = (xtal >> 8) & 0xff;
- b[2] = (xtal >> 16) & 0xff;
- b[3] = (xtal >> 24);
- ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4);
-
- b[0] = adc & 0xff;
- b[1] = (adc >> 8) & 0xff;
- 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 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:
- 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;
-
- /* Always solo frontend */
- set_mode = set_solo_fe;
- ret |= it913x_fe_script_loader(state, set_mode);
-
- ret |= it913x_fe_suspend(state);
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_fe_init(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- int ret = 0;
- /* Power Up Tuner - common all versions */
- ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
-
- ret |= it913x_fe_script_loader(state, init_1);
-
- ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
-
- ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static void it913x_fe_release(struct dvb_frontend *fe)
-{
- struct it913x_fe_state *state = fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops;
-
-struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
- 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->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)
- goto error;
-
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
-
- return &state->frontend;
-error:
- kfree(state);
- return NULL;
-}
-EXPORT_SYMBOL(it913x_fe_attach);
-
-static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
- .delsys = { SYS_DVBT },
- .info = {
- .name = "it913x-fe DVB-T",
- .frequency_min = 51000000,
- .frequency_max = 1680000000,
- .frequency_stepsize = 62500,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
- FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | 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,
- },
-
- .release = it913x_fe_release,
-
- .init = it913x_fe_init,
- .sleep = it913x_fe_sleep,
-
- .set_frontend = it913x_fe_set_frontend,
- .get_frontend = it913x_fe_get_frontend,
-
- .read_status = it913x_fe_read_status,
- .read_signal_strength = it913x_fe_read_signal_strength,
- .read_snr = it913x_fe_read_snr,
- .read_ber = it913x_fe_read_ber,
- .read_ucblocks = it913x_fe_read_ucblocks,
-};
-
-MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
-MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.15");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c
deleted file mode 100644
index 2cec8041a106..000000000000
--- a/drivers/media/dvb/frontends/lgs8gl5.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
-
- Copyright (C) 2008 Sirius International (Hong Kong) Limited
- Timothy Lee <timothy.lee@siriushk.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "dvb_frontend.h"
-#include "lgs8gl5.h"
-
-
-#define REG_RESET 0x02
-#define REG_RESET_OFF 0x01
-#define REG_03 0x03
-#define REG_04 0x04
-#define REG_07 0x07
-#define REG_09 0x09
-#define REG_0A 0x0a
-#define REG_0B 0x0b
-#define REG_0C 0x0c
-#define REG_37 0x37
-#define REG_STRENGTH 0x4b
-#define REG_STRENGTH_MASK 0x7f
-#define REG_STRENGTH_CARRIER 0x80
-#define REG_INVERSION 0x7c
-#define REG_INVERSION_ON 0x80
-#define REG_7D 0x7d
-#define REG_7E 0x7e
-#define REG_A2 0xa2
-#define REG_STATUS 0xa4
-#define REG_STATUS_SYNC 0x04
-#define REG_STATUS_LOCK 0x01
-
-
-struct lgs8gl5_state {
- struct i2c_adapter *i2c;
- const struct lgs8gl5_config *config;
- struct dvb_frontend frontend;
-};
-
-
-static int debug;
-#define dprintk(args...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "lgs8gl5: " args); \
- } while (0)
-
-
-/* Writes into demod's register */
-static int
-lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
- int ret;
- u8 buf[] = {reg, data};
- struct i2c_msg msg = {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = buf,
- .len = 2
- };
-
- ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
- dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
- __func__, reg, data, ret);
- return (ret != 1) ? -1 : 0;
-}
-
-
-/* Reads from demod's register */
-static int
-lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
-{
- int ret;
- u8 b0[] = {reg};
- u8 b1[] = {0};
- struct i2c_msg msg[2] = {
- {
- .addr = state->config->demod_address,
- .flags = 0,
- .buf = b0,
- .len = 1
- },
- {
- .addr = state->config->demod_address,
- .flags = I2C_M_RD,
- .buf = b1,
- .len = 1
- }
- };
-
- ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- return -EIO;
-
- return b1[0];
-}
-
-
-static int
-lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
- lgs8gl5_read_reg(state, reg);
- lgs8gl5_write_reg(state, reg, data);
- return 0;
-}
-
-
-/* Writes into alternate device's register */
-/* TODO: Find out what that device is for! */
-static int
-lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
-{
- int ret;
- u8 b0[] = {reg};
- u8 b1[] = {0};
- u8 b2[] = {reg, data};
- struct i2c_msg msg[3] = {
- {
- .addr = state->config->demod_address + 2,
- .flags = 0,
- .buf = b0,
- .len = 1
- },
- {
- .addr = state->config->demod_address + 2,
- .flags = I2C_M_RD,
- .buf = b1,
- .len = 1
- },
- {
- .addr = state->config->demod_address + 2,
- .flags = 0,
- .buf = b2,
- .len = 2
- },
- };
-
- ret = i2c_transfer(state->i2c, msg, 3);
- return (ret != 3) ? -1 : 0;
-}
-
-
-static void
-lgs8gl5_soft_reset(struct lgs8gl5_state *state)
-{
- u8 val;
-
- dprintk("%s\n", __func__);
-
- val = lgs8gl5_read_reg(state, REG_RESET);
- lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
- lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
- msleep(5);
-}
-
-
-/* Starts demodulation */
-static void
-lgs8gl5_start_demod(struct lgs8gl5_state *state)
-{
- u8 val;
- int n;
-
- dprintk("%s\n", __func__);
-
- lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
- lgs8gl5_soft_reset(state);
- lgs8gl5_update_reg(state, REG_07, 0x10);
- lgs8gl5_update_reg(state, REG_07, 0x10);
- lgs8gl5_write_reg(state, REG_09, 0x0e);
- lgs8gl5_write_reg(state, REG_0A, 0xe5);
- lgs8gl5_write_reg(state, REG_0B, 0x35);
- lgs8gl5_write_reg(state, REG_0C, 0x30);
-
- lgs8gl5_update_reg(state, REG_03, 0x00);
- lgs8gl5_update_reg(state, REG_7E, 0x01);
- lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
- lgs8gl5_update_reg(state, REG_04, 0x02);
- lgs8gl5_update_reg(state, REG_37, 0x01);
- lgs8gl5_soft_reset(state);
-
- /* Wait for carrier */
- for (n = 0; n < 10; n++) {
- val = lgs8gl5_read_reg(state, REG_STRENGTH);
- dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
- if (val & REG_STRENGTH_CARRIER)
- break;
- msleep(4);
- }
- if (!(val & REG_STRENGTH_CARRIER))
- return;
-
- /* Wait for lock */
- for (n = 0; n < 20; n++) {
- val = lgs8gl5_read_reg(state, REG_STATUS);
- dprintk("Wait for lock[%d] 0x%02X\n", n, val);
- if (val & REG_STATUS_LOCK)
- break;
- msleep(12);
- }
- if (!(val & REG_STATUS_LOCK))
- return;
-
- lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
- lgs8gl5_soft_reset(state);
-}
-
-
-static int
-lgs8gl5_init(struct dvb_frontend *fe)
-{
- struct lgs8gl5_state *state = fe->demodulator_priv;
-
- dprintk("%s\n", __func__);
-
- lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
- lgs8gl5_soft_reset(state);
- lgs8gl5_update_reg(state, REG_07, 0x10);
- lgs8gl5_update_reg(state, REG_07, 0x10);
- lgs8gl5_write_reg(state, REG_09, 0x0e);
- lgs8gl5_write_reg(state, REG_0A, 0xe5);
- lgs8gl5_write_reg(state, REG_0B, 0x35);
- lgs8gl5_write_reg(state, REG_0C, 0x30);
-
- return 0;
-}
-
-
-static int
-lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct lgs8gl5_state *state = fe->demodulator_priv;
- u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
- u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
-
- *status = 0;
-
- if ((level & REG_STRENGTH_MASK) > 0)
- *status |= FE_HAS_SIGNAL;
- if (level & REG_STRENGTH_CARRIER)
- *status |= FE_HAS_CARRIER;
- if (flags & REG_STATUS_SYNC)
- *status |= FE_HAS_SYNC;
- if (flags & REG_STATUS_LOCK)
- *status |= FE_HAS_LOCK;
-
- return 0;
-}
-
-
-static int
-lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- *ber = 0;
-
- return 0;
-}
-
-
-static int
-lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
-{
- struct lgs8gl5_state *state = fe->demodulator_priv;
- u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
- *signal_strength = (level & REG_STRENGTH_MASK) << 8;
-
- return 0;
-}
-
-
-static int
-lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- struct lgs8gl5_state *state = fe->demodulator_priv;
- u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
- *snr = (level & REG_STRENGTH_MASK) << 8;
-
- return 0;
-}
-
-
-static int
-lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- *ucblocks = 0;
-
- return 0;
-}
-
-
-static int
-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->bandwidth_hz != 8000000)
- return -EINVAL;
-
- if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- /* lgs8gl5_set_inversion(state, p->inversion); */
-
- lgs8gl5_start_demod(state);
-
- return 0;
-}
-
-
-static int
-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);
-
- p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
-
- 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;
-}
-
-
-static int
-lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *fesettings)
-{
- fesettings->min_delay_ms = 240;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- return 0;
-}
-
-
-static void
-lgs8gl5_release(struct dvb_frontend *fe)
-{
- struct lgs8gl5_state *state = fe->demodulator_priv;
- kfree(state);
-}
-
-
-static struct dvb_frontend_ops lgs8gl5_ops;
-
-
-struct dvb_frontend*
-lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
-{
- struct lgs8gl5_state *state = NULL;
-
- dprintk("%s\n", __func__);
-
- /* Allocate memory for the internal state */
- state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
- if (state == NULL)
- goto error;
-
- /* Setup the state */
- state->config = config;
- state->i2c = i2c;
-
- /* Check if the demod is there */
- if (lgs8gl5_read_reg(state, REG_RESET) < 0)
- goto error;
-
- /* Create dvb_frontend */
- memcpy(&state->frontend.ops, &lgs8gl5_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-
-error:
- kfree(state);
- return NULL;
-}
-EXPORT_SYMBOL(lgs8gl5_attach);
-
-
-static struct dvb_frontend_ops lgs8gl5_ops = {
- .delsys = { SYS_DMBTH },
- .info = {
- .name = "Legend Silicon LGS-8GL5 DMB-TH",
- .frequency_min = 474000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 10000,
- .frequency_tolerance = 0,
- .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 = lgs8gl5_release,
-
- .init = lgs8gl5_init,
-
- .set_frontend = lgs8gl5_set_frontend,
- .get_frontend = lgs8gl5_get_frontend,
- .get_tune_settings = lgs8gl5_get_tune_settings,
-
- .read_status = lgs8gl5_read_status,
- .read_ber = lgs8gl5_read_ber,
- .read_signal_strength = lgs8gl5_read_signal_strength,
- .read_snr = lgs8gl5_read_snr,
- .read_ucblocks = lgs8gl5_read_ucblocks,
-};
-
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
-MODULE_AUTHOR("Timothy Lee");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
deleted file mode 100644
index c2ea2749ebed..000000000000
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
- * LGS8913, LGS8GL5, LGS8G75
- * experimental support LGS8G42, LGS8G52
- *
- * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
- * Copyright (C) 2008 Sirius International (Hong Kong) Limited
- * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
- *
- * 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 <asm/div64.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
-
-#include "lgs8gxx.h"
-#include "lgs8gxx_priv.h"
-
-#define dprintk(args...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "lgs8gxx: " args); \
- } while (0)
-
-static int debug;
-static int fake_signal_str = 1;
-
-#define LGS8GXX_FIRMWARE "lgs8g75.fw"
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-module_param(fake_signal_str, int, 0644);
-MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:on).");
-
-/* LGS8GXX internal helper functions */
-
-static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
-{
- int ret;
- u8 buf[] = { reg, data };
- struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
-
- msg.addr = priv->config->demod_address;
- if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
- msg.addr += 0x02;
-
- if (debug >= 2)
- dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
-
- ret = i2c_transfer(priv->i2c, &msg, 1);
-
- if (ret != 1)
- dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
- __func__, reg, data, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
-{
- int ret;
- u8 dev_addr;
-
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
- struct i2c_msg msg[] = {
- { .flags = 0, .buf = b0, .len = 1 },
- { .flags = I2C_M_RD, .buf = b1, .len = 1 },
- };
-
- dev_addr = priv->config->demod_address;
- if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
- dev_addr += 0x02;
- msg[1].addr = msg[0].addr = dev_addr;
-
- ret = i2c_transfer(priv->i2c, msg, 2);
- if (ret != 2) {
- dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
- return -1;
- }
-
- *p_data = b1[0];
- if (debug >= 2)
- dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
- return 0;
-}
-
-static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
-{
- lgs8gxx_write_reg(priv, 0x02, 0x00);
- msleep(1);
- lgs8gxx_write_reg(priv, 0x02, 0x01);
- msleep(100);
-
- return 0;
-}
-
-static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
- u8 val, u8 delay, u8 tries)
-{
- u8 t;
- int i;
-
- for (i = 0; i < tries; i++) {
- lgs8gxx_read_reg(priv, reg, &t);
-
- if ((t & mask) == val)
- return 0;
- msleep(delay);
- }
-
- return 1;
-}
-
-static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
-{
- const struct lgs8gxx_config *config = priv->config;
- u8 if_conf;
-
- if_conf = 0x10; /* AGC output on, RF_AGC output off; */
-
- if_conf |=
- ((config->ext_adc) ? 0x80 : 0x00) |
- ((config->if_neg_center) ? 0x04 : 0x00) |
- ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
- ((config->adc_signed) ? 0x02 : 0x00) |
- ((config->if_neg_edge) ? 0x01 : 0x00);
-
- if (config->ext_adc &&
- (config->prod == LGS8GXX_PROD_LGS8G52)) {
- lgs8gxx_write_reg(priv, 0xBA, 0x40);
- }
-
- lgs8gxx_write_reg(priv, 0x07, if_conf);
-
- return 0;
-}
-
-static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
-{
- u64 val;
- u32 v32;
- u32 if_clk;
-
- if_clk = priv->config->if_clk_freq;
-
- val = freq;
- if (freq != 0) {
- val <<= 32;
- if (if_clk != 0)
- do_div(val, if_clk);
- v32 = val & 0xFFFFFFFF;
- dprintk("Set IF Freq to %dkHz\n", freq);
- } else {
- v32 = 0;
- dprintk("Set IF Freq to baseband\n");
- }
- dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
- lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
- lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
- lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
- } else {
- lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
- lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
- lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
- lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
- }
-
- return 0;
-}
-
-static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
-{
- u64 val;
- u32 v32 = 0;
- u8 reg_addr, t;
- int i;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
- reg_addr = 0x23;
- else
- reg_addr = 0x48;
-
- for (i = 0; i < 4; i++) {
- lgs8gxx_read_reg(priv, reg_addr, &t);
- v32 <<= 8;
- v32 |= t;
- reg_addr--;
- }
-
- val = v32;
- val *= priv->config->if_clk_freq;
- val >>= 32;
- dprintk("AFC = %u kHz\n", (u32)val);
- return 0;
-}
-
-static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
-{
- u8 t;
- u8 prod = priv->config->prod;
-
- if (prod == LGS8GXX_PROD_LGS8913)
- lgs8gxx_write_reg(priv, 0xC6, 0x01);
-
- if (prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_read_reg(priv, 0x0C, &t);
- t &= (~0x04);
- lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
- lgs8gxx_write_reg(priv, 0x39, 0x00);
- lgs8gxx_write_reg(priv, 0x3D, 0x04);
- } else if (prod == LGS8GXX_PROD_LGS8913 ||
- prod == LGS8GXX_PROD_LGS8GL5 ||
- prod == LGS8GXX_PROD_LGS8G42 ||
- prod == LGS8GXX_PROD_LGS8G52 ||
- prod == LGS8GXX_PROD_LGS8G54) {
- lgs8gxx_read_reg(priv, 0x7E, &t);
- lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
-
- /* clear FEC self reset */
- lgs8gxx_read_reg(priv, 0xC5, &t);
- lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
- }
-
- if (prod == LGS8GXX_PROD_LGS8913) {
- /* FEC auto detect */
- lgs8gxx_write_reg(priv, 0xC1, 0x03);
-
- lgs8gxx_read_reg(priv, 0x7C, &t);
- t = (t & 0x8C) | 0x03;
- lgs8gxx_write_reg(priv, 0x7C, t);
-
- /* BER test mode */
- lgs8gxx_read_reg(priv, 0xC3, &t);
- t = (t & 0xEF) | 0x10;
- lgs8gxx_write_reg(priv, 0xC3, t);
- }
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G52)
- lgs8gxx_write_reg(priv, 0xD9, 0x40);
-
- return 0;
-}
-
-static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
-{
- u8 t;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- u8 t2;
- lgs8gxx_read_reg(priv, 0x0C, &t);
- t &= (~0x80);
- lgs8gxx_write_reg(priv, 0x0C, t);
-
- lgs8gxx_read_reg(priv, 0x0C, &t);
- lgs8gxx_read_reg(priv, 0x19, &t2);
-
- if (((t&0x03) == 0x01) && (t2&0x01)) {
- lgs8gxx_write_reg(priv, 0x6E, 0x05);
- lgs8gxx_write_reg(priv, 0x39, 0x02);
- lgs8gxx_write_reg(priv, 0x39, 0x03);
- lgs8gxx_write_reg(priv, 0x3D, 0x05);
- lgs8gxx_write_reg(priv, 0x3E, 0x28);
- lgs8gxx_write_reg(priv, 0x53, 0x80);
- } else {
- lgs8gxx_write_reg(priv, 0x6E, 0x3F);
- lgs8gxx_write_reg(priv, 0x39, 0x00);
- lgs8gxx_write_reg(priv, 0x3D, 0x04);
- }
-
- lgs8gxx_soft_reset(priv);
- return 0;
- }
-
- /* turn off auto-detect; manual settings */
- lgs8gxx_write_reg(priv, 0x7E, 0);
- if (priv->config->prod == LGS8GXX_PROD_LGS8913)
- lgs8gxx_write_reg(priv, 0xC1, 0);
-
- lgs8gxx_read_reg(priv, 0xC5, &t);
- t = (t & 0xE0) | 0x06;
- lgs8gxx_write_reg(priv, 0xC5, t);
-
- lgs8gxx_soft_reset(priv);
-
- return 0;
-}
-
-static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
-{
- int ret = 0;
- u8 t;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
- ret = lgs8gxx_read_reg(priv, 0x13, &t);
- else
- ret = lgs8gxx_read_reg(priv, 0x4B, &t);
- if (ret != 0)
- return ret;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
- *locked = ((t & 0x80) == 0x80) ? 1 : 0;
- else
- *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
- return 0;
-}
-
-/* Wait for Code Acquisition Lock */
-static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
-{
- int ret = 0;
- u8 reg, mask, val;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- reg = 0x13;
- mask = 0x80;
- val = 0x80;
- } else {
- reg = 0x4B;
- mask = 0xC0;
- val = 0xC0;
- }
-
- ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
- *locked = (ret == 0) ? 1 : 0;
-
- return 0;
-}
-
-static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
- u8 *finished)
-{
- int ret = 0;
- u8 reg, mask, val;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- reg = 0x1f;
- mask = 0xC0;
- val = 0x80;
- } else {
- reg = 0xA4;
- mask = 0x03;
- val = 0x01;
- }
-
- ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
- *finished = (ret == 0) ? 1 : 0;
-
- return 0;
-}
-
-static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
- u8 *locked)
-{
- int err = 0;
- u8 ad_fini = 0;
- u8 t1, t2;
-
- if (gi == GI_945)
- dprintk("try GI 945\n");
- else if (gi == GI_595)
- dprintk("try GI 595\n");
- else if (gi == GI_420)
- dprintk("try GI 420\n");
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_read_reg(priv, 0x0C, &t1);
- lgs8gxx_read_reg(priv, 0x18, &t2);
- t1 &= ~(GI_MASK);
- t1 |= gi;
- t2 &= 0xFE;
- t2 |= cpn ? 0x01 : 0x00;
- lgs8gxx_write_reg(priv, 0x0C, t1);
- lgs8gxx_write_reg(priv, 0x18, t2);
- } else {
- lgs8gxx_write_reg(priv, 0x04, gi);
- }
- lgs8gxx_soft_reset(priv);
- err = lgs8gxx_wait_ca_lock(priv, locked);
- if (err || !(*locked))
- return err;
- err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
- if (err != 0)
- return err;
- if (ad_fini) {
- dprintk("auto detect finished\n");
- } else
- *locked = 0;
-
- return 0;
-}
-
-static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
- u8 *detected_param, u8 *gi)
-{
- int i, j;
- int err = 0;
- u8 locked = 0, tmp_gi;
-
- dprintk("%s\n", __func__);
-
- lgs8gxx_set_mode_auto(priv);
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_write_reg(priv, 0x67, 0xAA);
- lgs8gxx_write_reg(priv, 0x6E, 0x3F);
- } else {
- /* Guard Interval */
- lgs8gxx_write_reg(priv, 0x03, 00);
- }
-
- for (i = 0; i < 2; i++) {
- for (j = 0; j < 2; j++) {
- tmp_gi = GI_945;
- err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
- if (err)
- goto out;
- if (locked)
- goto locked;
- }
- for (j = 0; j < 2; j++) {
- tmp_gi = GI_420;
- err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
- if (err)
- goto out;
- if (locked)
- goto locked;
- }
- tmp_gi = GI_595;
- err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
- if (err)
- goto out;
- if (locked)
- goto locked;
- }
-
-locked:
- if ((err == 0) && (locked == 1)) {
- u8 t;
-
- if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_read_reg(priv, 0xA2, &t);
- *detected_param = t;
- } else {
- lgs8gxx_read_reg(priv, 0x1F, &t);
- *detected_param = t & 0x3F;
- }
-
- if (tmp_gi == GI_945)
- dprintk("GI 945 locked\n");
- else if (tmp_gi == GI_595)
- dprintk("GI 595 locked\n");
- else if (tmp_gi == GI_420)
- dprintk("GI 420 locked\n");
- *gi = tmp_gi;
- }
- if (!locked)
- err = -1;
-
-out:
- return err;
-}
-
-static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
-{
- s8 err;
- u8 gi = 0x2;
- u8 detected_param = 0;
-
- err = lgs8gxx_auto_detect(priv, &detected_param, &gi);
-
- if (err != 0) {
- dprintk("lgs8gxx_auto_detect failed\n");
- } else
- dprintk("detected param = 0x%02X\n", detected_param);
-
- /* Apply detected parameters */
- if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
- u8 inter_leave_len = detected_param & TIM_MASK ;
- /* Fix 8913 time interleaver detection bug */
- inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
- detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
- detected_param |= inter_leave_len;
- }
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- u8 t;
- lgs8gxx_read_reg(priv, 0x19, &t);
- t &= 0x81;
- t |= detected_param << 1;
- lgs8gxx_write_reg(priv, 0x19, t);
- } else {
- lgs8gxx_write_reg(priv, 0x7D, detected_param);
- if (priv->config->prod == LGS8GXX_PROD_LGS8913)
- lgs8gxx_write_reg(priv, 0xC0, detected_param);
- }
- /* lgs8gxx_soft_reset(priv); */
-
- /* Enter manual mode */
- lgs8gxx_set_mode_manual(priv);
-
- switch (gi) {
- case GI_945:
- priv->curr_gi = 945; break;
- case GI_595:
- priv->curr_gi = 595; break;
- case GI_420:
- priv->curr_gi = 420; break;
- default:
- priv->curr_gi = 945; break;
- }
-}
-
-static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
- u8 serial, u8 clk_pol, u8 clk_gated)
-{
- int ret = 0;
- u8 t, reg_addr;
-
- reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
- ret = lgs8gxx_read_reg(priv, reg_addr, &t);
- if (ret != 0)
- return ret;
-
- t &= 0xF8;
- t |= serial ? TS_SERIAL : TS_PARALLEL;
- t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
- t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
-
- ret = lgs8gxx_write_reg(priv, reg_addr, t);
- if (ret != 0)
- return ret;
-
- return 0;
-}
-
-/* A/D input peak-to-peak voltage range */
-static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
- u8 sel)
-{
- u8 r26 = 0x73, r27 = 0x90;
-
- if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
- return 0;
-
- r26 |= (sel & 0x01) << 7;
- r27 |= (sel & 0x02) >> 1;
- lgs8gxx_write_reg(priv, 0x26, r26);
- lgs8gxx_write_reg(priv, 0x27, r27);
-
- return 0;
-}
-
-/* LGS8913 demod frontend functions */
-
-static int lgs8913_init(struct lgs8gxx_state *priv)
-{
- u8 t;
-
- /* LGS8913 specific */
- lgs8gxx_write_reg(priv, 0xc1, 0x3);
-
- lgs8gxx_read_reg(priv, 0x7c, &t);
- lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);
-
- /* LGS8913 specific */
- lgs8gxx_read_reg(priv, 0xc3, &t);
- lgs8gxx_write_reg(priv, 0xc3, t&0x10);
-
-
- return 0;
-}
-
-static int lgs8g75_init_data(struct lgs8gxx_state *priv)
-{
- const struct firmware *fw;
- int rc;
- int i;
-
- rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev);
- if (rc)
- return rc;
-
- lgs8gxx_write_reg(priv, 0xC6, 0x40);
-
- lgs8gxx_write_reg(priv, 0x3D, 0x04);
- lgs8gxx_write_reg(priv, 0x39, 0x00);
-
- lgs8gxx_write_reg(priv, 0x3A, 0x00);
- lgs8gxx_write_reg(priv, 0x38, 0x00);
- lgs8gxx_write_reg(priv, 0x3B, 0x00);
- lgs8gxx_write_reg(priv, 0x38, 0x00);
-
- for (i = 0; i < fw->size; i++) {
- lgs8gxx_write_reg(priv, 0x38, 0x00);
- lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
- lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
- lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
- }
-
- lgs8gxx_write_reg(priv, 0x38, 0x00);
-
- release_firmware(fw);
- return 0;
-}
-
-static int lgs8gxx_init(struct dvb_frontend *fe)
-{
- struct lgs8gxx_state *priv =
- (struct lgs8gxx_state *)fe->demodulator_priv;
- const struct lgs8gxx_config *config = priv->config;
- u8 data = 0;
- s8 err;
- dprintk("%s\n", __func__);
-
- lgs8gxx_read_reg(priv, 0, &data);
- dprintk("reg 0 = 0x%02X\n", data);
-
- if (config->prod == LGS8GXX_PROD_LGS8G75)
- lgs8g75_set_adc_vpp(priv, config->adc_vpp);
-
- /* Setup MPEG output format */
- err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
- config->ts_clk_pol,
- config->ts_clk_gated);
- if (err != 0)
- return -EIO;
-
- if (config->prod == LGS8GXX_PROD_LGS8913)
- lgs8913_init(priv);
- lgs8gxx_set_if_freq(priv, priv->config->if_freq);
- lgs8gxx_set_ad_mode(priv);
-
- return 0;
-}
-
-static void lgs8gxx_release(struct dvb_frontend *fe)
-{
- struct lgs8gxx_state *state = fe->demodulator_priv;
- dprintk("%s\n", __func__);
-
- kfree(state);
-}
-
-
-static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
-
- if (len != 2)
- return -EINVAL;
-
- return lgs8gxx_write_reg(priv, buf[0], buf[1]);
-}
-
-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);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- /* start auto lock */
- lgs8gxx_auto_lock(priv);
-
- msleep(10);
-
- return 0;
-}
-
-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 */
- /* inversion status */
- fe_params->inversion = INVERSION_OFF;
-
- /* bandwidth */
- fe_params->bandwidth_hz = 8000000;
-
- fe_params->code_rate_HP = FEC_AUTO;
- fe_params->code_rate_LP = FEC_AUTO;
-
- fe_params->modulation = QAM_AUTO;
-
- /* transmission mode */
- fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
-
- /* guard interval */
- fe_params->guard_interval = GUARD_INTERVAL_AUTO;
-
- /* hierarchy */
- fe_params->hierarchy = HIERARCHY_NONE;
-
- return 0;
-}
-
-static
-int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *fesettings)
-{
- /* FIXME: copy from tda1004x.c */
- fesettings->min_delay_ms = 800;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- return 0;
-}
-
-static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
- s8 ret;
- u8 t, locked = 0;
-
- dprintk("%s\n", __func__);
- *fe_status = 0;
-
- lgs8gxx_get_afc_phase(priv);
- lgs8gxx_is_locked(priv, &locked);
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- if (locked)
- *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- return 0;
- }
-
- ret = lgs8gxx_read_reg(priv, 0x4B, &t);
- if (ret != 0)
- return -EIO;
-
- dprintk("Reg 0x4B: 0x%02X\n", t);
-
- *fe_status = 0;
- if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
- if ((t & 0x40) == 0x40)
- *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
- if ((t & 0x80) == 0x80)
- *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |
- FE_HAS_LOCK;
- } else {
- if ((t & 0x80) == 0x80)
- *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- }
-
- /* success */
- dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
- return 0;
-}
-
-static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
-{
- u16 v;
- u8 agc_lvl[2], cat;
-
- dprintk("%s()\n", __func__);
- lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);
- lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);
-
- v = agc_lvl[0];
- v <<= 8;
- v |= agc_lvl[1];
-
- dprintk("agc_lvl: 0x%04X\n", v);
-
- if (v < 0x100)
- cat = 0;
- else if (v < 0x190)
- cat = 5;
- else if (v < 0x2A8)
- cat = 4;
- else if (v < 0x381)
- cat = 3;
- else if (v < 0x400)
- cat = 2;
- else if (v == 0x400)
- cat = 1;
- else
- cat = 0;
-
- *signal = cat * 65535 / 5;
-
- return 0;
-}
-
-static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
-{
- u8 t; s8 ret;
- s16 max_strength = 0;
- u8 str;
- u16 i, gi = priv->curr_gi;
-
- dprintk("%s\n", __func__);
-
- ret = lgs8gxx_read_reg(priv, 0x4B, &t);
- if (ret != 0)
- return -EIO;
-
- if (fake_signal_str) {
- if ((t & 0xC0) == 0xC0) {
- dprintk("Fake signal strength\n");
- *signal = 0x7FFF;
- } else
- *signal = 0;
- return 0;
- }
-
- dprintk("gi = %d\n", gi);
- for (i = 0; i < gi; i++) {
-
- if ((i & 0xFF) == 0)
- lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));
- lgs8gxx_write_reg(priv, 0x83, i & 0xFF);
-
- lgs8gxx_read_reg(priv, 0x94, &str);
- if (max_strength < str)
- max_strength = str;
- }
-
- *signal = max_strength;
- dprintk("%s: signal=0x%02X\n", __func__, *signal);
-
- lgs8gxx_read_reg(priv, 0x95, &t);
- dprintk("%s: AVG Noise=0x%02X\n", __func__, t);
-
- return 0;
-}
-
-static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
-{
- u8 t;
- s16 v = 0;
-
- dprintk("%s\n", __func__);
-
- lgs8gxx_read_reg(priv, 0xB1, &t);
- v |= t;
- v <<= 8;
- lgs8gxx_read_reg(priv, 0xB0, &t);
- v |= t;
-
- *signal = v;
- dprintk("%s: signal=0x%02X\n", __func__, *signal);
-
- return 0;
-}
-
-static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8913)
- return lgs8913_read_signal_strength(priv, signal);
- else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
- return lgs8g75_read_signal_strength(priv, signal);
- else
- return lgs8gxx_read_signal_agc(priv, signal);
-}
-
-static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
- u8 t;
- *snr = 0;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
- lgs8gxx_read_reg(priv, 0x34, &t);
- else
- lgs8gxx_read_reg(priv, 0x95, &t);
- dprintk("AVG Noise=0x%02X\n", t);
- *snr = 256 - t;
- *snr <<= 8;
- dprintk("snr=0x%x\n", *snr);
-
- return 0;
-}
-
-static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- *ucblocks = 0;
- dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
- return 0;
-}
-
-static void packet_counter_start(struct lgs8gxx_state *priv)
-{
- u8 orig, t;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_read_reg(priv, 0x30, &orig);
- orig &= 0xE7;
- t = orig | 0x10;
- lgs8gxx_write_reg(priv, 0x30, t);
- t = orig | 0x18;
- lgs8gxx_write_reg(priv, 0x30, t);
- t = orig | 0x10;
- lgs8gxx_write_reg(priv, 0x30, t);
- } else {
- lgs8gxx_write_reg(priv, 0xC6, 0x01);
- lgs8gxx_write_reg(priv, 0xC6, 0x41);
- lgs8gxx_write_reg(priv, 0xC6, 0x01);
- }
-}
-
-static void packet_counter_stop(struct lgs8gxx_state *priv)
-{
- u8 t;
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- lgs8gxx_read_reg(priv, 0x30, &t);
- t &= 0xE7;
- lgs8gxx_write_reg(priv, 0x30, t);
- } else {
- lgs8gxx_write_reg(priv, 0xC6, 0x81);
- }
-}
-
-static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
- u8 reg_err, reg_total, t;
- u32 total_cnt = 0, err_cnt = 0;
- int i;
-
- dprintk("%s\n", __func__);
-
- packet_counter_start(priv);
- msleep(200);
- packet_counter_stop(priv);
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
- reg_total = 0x28; reg_err = 0x2C;
- } else {
- reg_total = 0xD0; reg_err = 0xD4;
- }
-
- for (i = 0; i < 4; i++) {
- total_cnt <<= 8;
- lgs8gxx_read_reg(priv, reg_total+3-i, &t);
- total_cnt |= t;
- }
- for (i = 0; i < 4; i++) {
- err_cnt <<= 8;
- lgs8gxx_read_reg(priv, reg_err+3-i, &t);
- err_cnt |= t;
- }
- dprintk("error=%d total=%d\n", err_cnt, total_cnt);
-
- if (total_cnt == 0)
- *ber = 0;
- else
- *ber = err_cnt * 100 / total_cnt;
-
- dprintk("%s: ber=0x%x\n", __func__, *ber);
- return 0;
-}
-
-static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
-
- if (priv->config->tuner_address == 0)
- return 0;
- if (enable) {
- u8 v = 0x80 | priv->config->tuner_address;
- return lgs8gxx_write_reg(priv, 0x01, v);
- }
- return lgs8gxx_write_reg(priv, 0x01, 0);
-}
-
-static struct dvb_frontend_ops lgs8gxx_ops = {
- .delsys = { SYS_DMBTH },
- .info = {
- .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
- .frequency_min = 474000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 10000,
- .caps =
- FE_CAN_FEC_AUTO |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO
- },
-
- .release = lgs8gxx_release,
-
- .init = lgs8gxx_init,
- .write = lgs8gxx_write,
- .i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,
-
- .set_frontend = lgs8gxx_set_fe,
- .get_frontend = lgs8gxx_get_fe,
- .get_tune_settings = lgs8gxx_get_tune_settings,
-
- .read_status = lgs8gxx_read_status,
- .read_ber = lgs8gxx_read_ber,
- .read_signal_strength = lgs8gxx_read_signal_strength,
- .read_snr = lgs8gxx_read_snr,
- .read_ucblocks = lgs8gxx_read_ucblocks,
-};
-
-struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
- struct i2c_adapter *i2c)
-{
- struct lgs8gxx_state *priv = NULL;
- u8 data = 0;
-
- dprintk("%s()\n", __func__);
-
- if (config == NULL || i2c == NULL)
- return NULL;
-
- priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);
- if (priv == NULL)
- goto error_out;
-
- priv->config = config;
- priv->i2c = i2c;
-
- /* check if the demod is there */
- if (lgs8gxx_read_reg(priv, 0, &data) != 0) {
- dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",
- __func__, priv->config->demod_address);
- goto error_out;
- }
-
- lgs8gxx_read_reg(priv, 1, &data);
-
- memcpy(&priv->frontend.ops, &lgs8gxx_ops,
- sizeof(struct dvb_frontend_ops));
- priv->frontend.demodulator_priv = priv;
-
- if (config->prod == LGS8GXX_PROD_LGS8G75)
- lgs8g75_init_data(priv);
-
- return &priv->frontend;
-
-error_out:
- dprintk("%s() error_out\n", __func__);
- kfree(priv);
- return NULL;
-
-}
-EXPORT_SYMBOL(lgs8gxx_attach);
-
-MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
-MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(LGS8GXX_FIRMWARE);
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
deleted file mode 100644
index 312588e84dae..000000000000
--- a/drivers/media/dvb/frontends/m88rs2000.c
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- 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)
-{
- struct m88rs2000_state *state = fe->demodulator_priv;
- u8 data;
-
- data = m88rs2000_demod_read(state, 0xb2);
- data |= 0x03; /* bit0 V/H, bit1 off/on */
-
- switch (volt) {
- case SEC_VOLTAGE_18:
- data &= ~0x03;
- break;
- case SEC_VOLTAGE_13:
- data &= ~0x03;
- data |= 0x01;
- break;
- case SEC_VOLTAGE_OFF:
- break;
- }
-
- m88rs2000_demod_write(state, 0xb2, data);
-
- 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)
-{
- 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;
- }
- 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++) {
- 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/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
deleted file mode 100644
index 49ca78d883b1..000000000000
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * Support for NXT2002 and NXT2004 - VSB/QAM
- *
- * Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com>
- * Copyright (C) 2006 Michael Krufky <mkrufky@m1k.net>
- * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
- * and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
-*/
-
-/*
- * NOTES ABOUT THIS DRIVER
- *
- * This Linux driver supports:
- * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
- * AverTVHD MCE A180 (NXT2004)
- * ATI HDTV Wonder (NXT2004)
- *
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
- * download/extract the appropriate firmware, and then copy it to
- * /usr/lib/hotplug/firmware/ or /lib/firmware/
- * (depending on configuration of firmware hotplug).
- */
-#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
-#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
-#define CRC_CCIT_MASK 0x1021
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include "dvb_frontend.h"
-#include "nxt200x.h"
-
-struct nxt200x_state {
-
- struct i2c_adapter* i2c;
- const struct nxt200x_config* config;
- struct dvb_frontend frontend;
-
- /* demodulator private data */
- nxt_chip_type demod_chip;
- u8 initialised:1;
-};
-
-static int debug;
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG "nxt200x: " args); \
- } while (0)
-
-static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
-{
- int err;
- struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
-
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
- __func__, addr, err);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
-{
- int err;
- struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
-
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
- __func__, addr, err);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
- const u8 *buf, u8 len)
-{
- u8 buf2 [len+1];
- int err;
- struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
-
- buf2[0] = reg;
- memcpy(&buf2[1], buf, len);
-
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
- __func__, state->config->demod_address, err);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
-{
- u8 reg2 [] = { reg };
-
- struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
-
- int err;
-
- if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
- printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
- __func__, state->config->demod_address, err);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static u16 nxt200x_crc(u16 crc, u8 c)
-{
- u8 i;
- u16 input = (u16) c & 0xFF;
-
- input<<=8;
- for(i=0; i<8; i++) {
- if((crc^input) & 0x8000)
- crc=(crc<<1)^CRC_CCIT_MASK;
- else
- crc<<=1;
- input<<=1;
- }
- return crc;
-}
-
-static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
-{
- u8 attr, len2, buf;
- dprintk("%s\n", __func__);
-
- /* set mutli register register */
- nxt200x_writebytes(state, 0x35, &reg, 1);
-
- /* send the actual data */
- nxt200x_writebytes(state, 0x36, data, len);
-
- switch (state->demod_chip) {
- case NXT2002:
- len2 = len;
- buf = 0x02;
- break;
- case NXT2004:
- /* probably not right, but gives correct values */
- attr = 0x02;
- if (reg & 0x80) {
- attr = attr << 1;
- if (reg & 0x04)
- attr = attr >> 1;
- }
- /* set write bit */
- len2 = ((attr << 4) | 0x10) | len;
- buf = 0x80;
- break;
- default:
- return -EINVAL;
- break;
- }
-
- /* set multi register length */
- nxt200x_writebytes(state, 0x34, &len2, 1);
-
- /* toggle the multireg write bit */
- nxt200x_writebytes(state, 0x21, &buf, 1);
-
- nxt200x_readbytes(state, 0x21, &buf, 1);
-
- switch (state->demod_chip) {
- case NXT2002:
- if ((buf & 0x02) == 0)
- return 0;
- break;
- case NXT2004:
- if (buf == 0)
- return 0;
- break;
- default:
- return -EINVAL;
- break;
- }
-
- printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
-
- return 0;
-}
-
-static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
-{
- int i;
- u8 buf, len2, attr;
- dprintk("%s\n", __func__);
-
- /* set mutli register register */
- nxt200x_writebytes(state, 0x35, &reg, 1);
-
- switch (state->demod_chip) {
- case NXT2002:
- /* set multi register length */
- len2 = len & 0x80;
- nxt200x_writebytes(state, 0x34, &len2, 1);
-
- /* read the actual data */
- nxt200x_readbytes(state, reg, data, len);
- return 0;
- break;
- case NXT2004:
- /* probably not right, but gives correct values */
- attr = 0x02;
- if (reg & 0x80) {
- attr = attr << 1;
- if (reg & 0x04)
- attr = attr >> 1;
- }
-
- /* set multi register length */
- len2 = (attr << 4) | len;
- nxt200x_writebytes(state, 0x34, &len2, 1);
-
- /* toggle the multireg bit*/
- buf = 0x80;
- nxt200x_writebytes(state, 0x21, &buf, 1);
-
- /* read the actual data */
- for(i = 0; i < len; i++) {
- nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
- }
- return 0;
- break;
- default:
- return -EINVAL;
- break;
- }
-}
-
-static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
-{
- u8 buf, stopval, counter = 0;
- dprintk("%s\n", __func__);
-
- /* set correct stop value */
- switch (state->demod_chip) {
- case NXT2002:
- stopval = 0x40;
- break;
- case NXT2004:
- stopval = 0x10;
- break;
- default:
- stopval = 0;
- break;
- }
-
- buf = 0x80;
- nxt200x_writebytes(state, 0x22, &buf, 1);
-
- while (counter < 20) {
- nxt200x_readbytes(state, 0x31, &buf, 1);
- if (buf & stopval)
- return;
- msleep(10);
- counter++;
- }
-
- printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
- return;
-}
-
-static void nxt200x_microcontroller_start (struct nxt200x_state* state)
-{
- u8 buf;
- dprintk("%s\n", __func__);
-
- buf = 0x00;
- nxt200x_writebytes(state, 0x22, &buf, 1);
-}
-
-static void nxt2004_microcontroller_init (struct nxt200x_state* state)
-{
- u8 buf[9];
- u8 counter = 0;
- dprintk("%s\n", __func__);
-
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x2b, buf, 1);
- buf[0] = 0x70;
- nxt200x_writebytes(state, 0x34, buf, 1);
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x35, buf, 1);
- buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
- buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
- nxt200x_writebytes(state, 0x36, buf, 9);
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x21, buf, 1);
-
- while (counter < 20) {
- nxt200x_readbytes(state, 0x21, buf, 1);
- if (buf[0] == 0)
- return;
- msleep(10);
- counter++;
- }
-
- printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
-
- return;
-}
-
-static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
-{
- u8 buf, count = 0;
-
- dprintk("%s\n", __func__);
-
- dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
-
- /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
- * direct write is required for Philips TUV1236D and ALPS TDHU2 */
- switch (state->demod_chip) {
- case NXT2004:
- if (i2c_writebytes(state, data[0], data+1, 4))
- printk(KERN_WARNING "nxt200x: error writing to tuner\n");
- /* wait until we have a lock */
- while (count < 20) {
- i2c_readbytes(state, data[0], &buf, 1);
- if (buf & 0x40)
- return 0;
- msleep(100);
- count++;
- }
- printk("nxt2004: timeout waiting for tuner lock\n");
- break;
- case NXT2002:
- /* set the i2c transfer speed to the tuner */
- buf = 0x03;
- nxt200x_writebytes(state, 0x20, &buf, 1);
-
- /* setup to transfer 4 bytes via i2c */
- buf = 0x04;
- nxt200x_writebytes(state, 0x34, &buf, 1);
-
- /* write actual tuner bytes */
- nxt200x_writebytes(state, 0x36, data+1, 4);
-
- /* set tuner i2c address */
- buf = data[0] << 1;
- nxt200x_writebytes(state, 0x35, &buf, 1);
-
- /* write UC Opmode to begin transfer */
- buf = 0x80;
- nxt200x_writebytes(state, 0x21, &buf, 1);
-
- while (count < 20) {
- nxt200x_readbytes(state, 0x21, &buf, 1);
- if ((buf & 0x80)== 0x00)
- return 0;
- msleep(100);
- count++;
- }
- printk("nxt2002: timeout error writing tuner\n");
- break;
- default:
- return -EINVAL;
- break;
- }
- return 0;
-}
-
-static void nxt200x_agc_reset(struct nxt200x_state* state)
-{
- u8 buf;
- dprintk("%s\n", __func__);
-
- switch (state->demod_chip) {
- case NXT2002:
- buf = 0x08;
- nxt200x_writebytes(state, 0x08, &buf, 1);
- buf = 0x00;
- nxt200x_writebytes(state, 0x08, &buf, 1);
- break;
- case NXT2004:
- nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
- buf = 0x08;
- nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
- buf = 0x00;
- nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
- break;
- default:
- break;
- }
- return;
-}
-
-static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
-{
-
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 buf[3], written = 0, chunkpos = 0;
- u16 rambase, position, crc = 0;
-
- dprintk("%s\n", __func__);
- dprintk("Firmware is %zu bytes\n", fw->size);
-
- /* Get the RAM base for this nxt2002 */
- nxt200x_readbytes(state, 0x10, buf, 1);
-
- if (buf[0] & 0x10)
- rambase = 0x1000;
- else
- rambase = 0x0000;
-
- dprintk("rambase on this nxt2002 is %04X\n", rambase);
-
- /* Hold the micro in reset while loading firmware */
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x2B, buf, 1);
-
- for (position = 0; position < fw->size; position++) {
- if (written == 0) {
- crc = 0;
- chunkpos = 0x28;
- buf[0] = ((rambase + position) >> 8);
- buf[1] = (rambase + position) & 0xFF;
- buf[2] = 0x81;
- /* write starting address */
- nxt200x_writebytes(state, 0x29, buf, 3);
- }
- written++;
- chunkpos++;
-
- if ((written % 4) == 0)
- nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
-
- crc = nxt200x_crc(crc, fw->data[position]);
-
- if ((written == 255) || (position+1 == fw->size)) {
- /* write remaining bytes of firmware */
- nxt200x_writebytes(state, chunkpos+4-(written %4),
- &fw->data[position-(written %4) + 1],
- written %4);
- buf[0] = crc << 8;
- buf[1] = crc & 0xFF;
-
- /* write crc */
- nxt200x_writebytes(state, 0x2C, buf, 2);
-
- /* do a read to stop things */
- nxt200x_readbytes(state, 0x2A, buf, 1);
-
- /* set transfer mode to complete */
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x2B, buf, 1);
-
- written = 0;
- }
- }
-
- return 0;
-};
-
-static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
-{
-
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 buf[3];
- u16 rambase, position, crc=0;
-
- dprintk("%s\n", __func__);
- dprintk("Firmware is %zu bytes\n", fw->size);
-
- /* set rambase */
- rambase = 0x1000;
-
- /* hold the micro in reset while loading firmware */
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x2B, buf,1);
-
- /* calculate firmware CRC */
- for (position = 0; position < fw->size; position++) {
- crc = nxt200x_crc(crc, fw->data[position]);
- }
-
- buf[0] = rambase >> 8;
- buf[1] = rambase & 0xFF;
- buf[2] = 0x81;
- /* write starting address */
- nxt200x_writebytes(state,0x29,buf,3);
-
- for (position = 0; position < fw->size;) {
- nxt200x_writebytes(state, 0x2C, &fw->data[position],
- fw->size-position > 255 ? 255 : fw->size-position);
- position += (fw->size-position > 255 ? 255 : fw->size-position);
- }
- buf[0] = crc >> 8;
- buf[1] = crc & 0xFF;
-
- dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
-
- /* write crc */
- nxt200x_writebytes(state, 0x2C, buf,2);
-
- /* do a read to stop things */
- nxt200x_readbytes(state, 0x2C, buf, 1);
-
- /* set transfer mode to complete */
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x2B, buf,1);
-
- return 0;
-};
-
-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];
-
- /* stop the micro first */
- nxt200x_microcontroller_stop(state);
-
- if (state->demod_chip == NXT2004) {
- /* make sure demod is set to digital */
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x14, buf, 1);
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x17, buf, 1);
- }
-
- /* set additional params */
- switch (p->modulation) {
- case QAM_64:
- case QAM_256:
- /* Set punctured clock for QAM */
- /* This is just a guess since I am unable to test it */
- if (state->config->set_ts_params)
- state->config->set_ts_params(fe, 1);
- break;
- case VSB_8:
- /* Set non-punctured clock for VSB */
- if (state->config->set_ts_params)
- state->config->set_ts_params(fe, 0);
- break;
- default:
- return -EINVAL;
- break;
- }
-
- if (fe->ops.tuner_ops.calc_regs) {
- /* get tuning information */
- fe->ops.tuner_ops.calc_regs(fe, buf, 5);
-
- /* write frequency information */
- nxt200x_writetuner(state, buf);
- }
-
- /* reset the agc now that tuning has been completed */
- nxt200x_agc_reset(state);
-
- /* set target power level */
- switch (p->modulation) {
- case QAM_64:
- case QAM_256:
- buf[0] = 0x74;
- break;
- case VSB_8:
- buf[0] = 0x70;
- break;
- default:
- return -EINVAL;
- break;
- }
- nxt200x_writebytes(state, 0x42, buf, 1);
-
- /* configure sdm */
- switch (state->demod_chip) {
- case NXT2002:
- buf[0] = 0x87;
- break;
- case NXT2004:
- buf[0] = 0x07;
- break;
- default:
- return -EINVAL;
- break;
- }
- nxt200x_writebytes(state, 0x57, buf, 1);
-
- /* write sdm1 input */
- buf[0] = 0x10;
- buf[1] = 0x00;
- switch (state->demod_chip) {
- case NXT2002:
- nxt200x_writereg_multibyte(state, 0x58, buf, 2);
- break;
- case NXT2004:
- nxt200x_writebytes(state, 0x58, buf, 2);
- break;
- default:
- return -EINVAL;
- break;
- }
-
- /* write sdmx input */
- switch (p->modulation) {
- case QAM_64:
- buf[0] = 0x68;
- break;
- case QAM_256:
- buf[0] = 0x64;
- break;
- case VSB_8:
- buf[0] = 0x60;
- break;
- default:
- return -EINVAL;
- break;
- }
- buf[1] = 0x00;
- switch (state->demod_chip) {
- case NXT2002:
- nxt200x_writereg_multibyte(state, 0x5C, buf, 2);
- break;
- case NXT2004:
- nxt200x_writebytes(state, 0x5C, buf, 2);
- break;
- default:
- return -EINVAL;
- break;
- }
-
- /* write adc power lpf fc */
- buf[0] = 0x05;
- nxt200x_writebytes(state, 0x43, buf, 1);
-
- if (state->demod_chip == NXT2004) {
- /* write ??? */
- buf[0] = 0x00;
- buf[1] = 0x00;
- nxt200x_writebytes(state, 0x46, buf, 2);
- }
-
- /* write accumulator2 input */
- buf[0] = 0x80;
- buf[1] = 0x00;
- switch (state->demod_chip) {
- case NXT2002:
- nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
- break;
- case NXT2004:
- nxt200x_writebytes(state, 0x4B, buf, 2);
- break;
- default:
- return -EINVAL;
- break;
- }
-
- /* write kg1 */
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x4D, buf, 1);
-
- /* write sdm12 lpf fc */
- buf[0] = 0x44;
- nxt200x_writebytes(state, 0x55, buf, 1);
-
- /* write agc control reg */
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x41, buf, 1);
-
- if (state->demod_chip == NXT2004) {
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x24;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- /* soft reset? */
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x10;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x04;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x81, buf, 1);
- buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
- nxt200x_writereg_multibyte(state, 0x82, buf, 3);
- nxt200x_readreg_multibyte(state, 0x88, buf, 1);
- buf[0] = 0x11;
- nxt200x_writereg_multibyte(state, 0x88, buf, 1);
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x44;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
- }
-
- /* write agc ucgp0 */
- switch (p->modulation) {
- case QAM_64:
- buf[0] = 0x02;
- break;
- case QAM_256:
- buf[0] = 0x03;
- break;
- case VSB_8:
- buf[0] = 0x00;
- break;
- default:
- return -EINVAL;
- break;
- }
- nxt200x_writebytes(state, 0x30, buf, 1);
-
- /* write agc control reg */
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x41, buf, 1);
-
- /* write accumulator2 input */
- buf[0] = 0x80;
- buf[1] = 0x00;
- switch (state->demod_chip) {
- case NXT2002:
- nxt200x_writereg_multibyte(state, 0x49, buf, 2);
- nxt200x_writereg_multibyte(state, 0x4B, buf, 2);
- break;
- case NXT2004:
- nxt200x_writebytes(state, 0x49, buf, 2);
- nxt200x_writebytes(state, 0x4B, buf, 2);
- break;
- default:
- return -EINVAL;
- break;
- }
-
- /* write agc control reg */
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x41, buf, 1);
-
- nxt200x_microcontroller_start(state);
-
- if (state->demod_chip == NXT2004) {
- nxt2004_microcontroller_init(state);
-
- /* ???? */
- buf[0] = 0xF0;
- buf[1] = 0x00;
- nxt200x_writebytes(state, 0x5C, buf, 2);
- }
-
- /* adjacent channel detection should be done here, but I don't
- have any stations with this need so I cannot test it */
-
- return 0;
-}
-
-static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 lock;
- nxt200x_readbytes(state, 0x31, &lock, 1);
-
- *status = 0;
- if (lock & 0x20) {
- *status |= FE_HAS_SIGNAL;
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_LOCK;
- }
- return 0;
-}
-
-static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 b[3];
-
- nxt200x_readreg_multibyte(state, 0xE6, b, 3);
-
- *ber = ((b[0] << 8) + b[1]) * 8;
-
- return 0;
-}
-
-static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 b[2];
- u16 temp = 0;
-
- /* setup to read cluster variance */
- b[0] = 0x00;
- nxt200x_writebytes(state, 0xA1, b, 1);
-
- /* get multreg val */
- nxt200x_readreg_multibyte(state, 0xA6, b, 2);
-
- temp = (b[0] << 8) | b[1];
- *strength = ((0x7FFF - temp) & 0x0FFF) * 16;
-
- return 0;
-}
-
-static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 b[2];
- u16 temp = 0, temp2;
- u32 snrdb = 0;
-
- /* setup to read cluster variance */
- b[0] = 0x00;
- nxt200x_writebytes(state, 0xA1, b, 1);
-
- /* get multreg val from 0xA6 */
- nxt200x_readreg_multibyte(state, 0xA6, b, 2);
-
- temp = (b[0] << 8) | b[1];
- temp2 = 0x7FFF - temp;
-
- /* snr will be in db */
- if (temp2 > 0x7F00)
- snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
- else if (temp2 > 0x7EC0)
- snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
- else if (temp2 > 0x7C00)
- snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
- else
- snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
-
- /* the value reported back from the frontend will be FFFF=32db 0000=0db */
- *snr = snrdb * (0xFFFF/32000);
-
- return 0;
-}
-
-static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- u8 b[3];
-
- nxt200x_readreg_multibyte(state, 0xE6, b, 3);
- *ucblocks = b[2];
-
- return 0;
-}
-
-static int nxt200x_sleep(struct dvb_frontend* fe)
-{
- return 0;
-}
-
-static int nxt2002_init(struct dvb_frontend* fe)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- const struct firmware *fw;
- int ret;
- u8 buf[2];
-
- /* request the firmware, this will block until someone uploads it */
- printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
- state->i2c->dev.parent);
- printk("nxt2002: Waiting for firmware upload(2)...\n");
- if (ret) {
- printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
- return ret;
- }
-
- ret = nxt2002_load_firmware(fe, fw);
- release_firmware(fw);
- if (ret) {
- printk("nxt2002: Writing firmware to device failed\n");
- return ret;
- }
- printk("nxt2002: Firmware upload complete\n");
-
- /* Put the micro into reset */
- nxt200x_microcontroller_stop(state);
-
- /* ensure transfer is complete */
- buf[0]=0x00;
- nxt200x_writebytes(state, 0x2B, buf, 1);
-
- /* Put the micro into reset for real this time */
- nxt200x_microcontroller_stop(state);
-
- /* soft reset everything (agc,frontend,eq,fec)*/
- buf[0] = 0x0F;
- nxt200x_writebytes(state, 0x08, buf, 1);
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x08, buf, 1);
-
- /* write agc sdm configure */
- buf[0] = 0xF1;
- nxt200x_writebytes(state, 0x57, buf, 1);
-
- /* write mod output format */
- buf[0] = 0x20;
- nxt200x_writebytes(state, 0x09, buf, 1);
-
- /* write fec mpeg mode */
- buf[0] = 0x7E;
- buf[1] = 0x00;
- nxt200x_writebytes(state, 0xE9, buf, 2);
-
- /* write mux selection */
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0xCC, buf, 1);
-
- return 0;
-}
-
-static int nxt2004_init(struct dvb_frontend* fe)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- const struct firmware *fw;
- int ret;
- u8 buf[3];
-
- /* ??? */
- buf[0]=0x00;
- nxt200x_writebytes(state, 0x1E, buf, 1);
-
- /* request the firmware, this will block until someone uploads it */
- printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
- state->i2c->dev.parent);
- printk("nxt2004: Waiting for firmware upload(2)...\n");
- if (ret) {
- printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
- return ret;
- }
-
- ret = nxt2004_load_firmware(fe, fw);
- release_firmware(fw);
- if (ret) {
- printk("nxt2004: Writing firmware to device failed\n");
- return ret;
- }
- printk("nxt2004: Firmware upload complete\n");
-
- /* ensure transfer is complete */
- buf[0] = 0x01;
- nxt200x_writebytes(state, 0x19, buf, 1);
-
- nxt2004_microcontroller_init(state);
- nxt200x_microcontroller_stop(state);
- nxt200x_microcontroller_stop(state);
- nxt2004_microcontroller_init(state);
- nxt200x_microcontroller_stop(state);
-
- /* soft reset everything (agc,frontend,eq,fec)*/
- buf[0] = 0xFF;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
- /* write agc sdm configure */
- buf[0] = 0xD7;
- nxt200x_writebytes(state, 0x57, buf, 1);
-
- /* ???*/
- buf[0] = 0x07;
- buf[1] = 0xfe;
- nxt200x_writebytes(state, 0x35, buf, 2);
- buf[0] = 0x12;
- nxt200x_writebytes(state, 0x34, buf, 1);
- buf[0] = 0x80;
- nxt200x_writebytes(state, 0x21, buf, 1);
-
- /* ???*/
- buf[0] = 0x21;
- nxt200x_writebytes(state, 0x0A, buf, 1);
-
- /* ???*/
- buf[0] = 0x01;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- /* write fec mpeg mode */
- buf[0] = 0x7E;
- buf[1] = 0x00;
- nxt200x_writebytes(state, 0xE9, buf, 2);
-
- /* write mux selection */
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0xCC, buf, 1);
-
- /* ???*/
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- /* soft reset? */
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x10;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
- /* ???*/
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x01;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x70;
- nxt200x_writereg_multibyte(state, 0x81, buf, 1);
- buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
- nxt200x_writereg_multibyte(state, 0x82, buf, 3);
-
- nxt200x_readreg_multibyte(state, 0x88, buf, 1);
- buf[0] = 0x11;
- nxt200x_writereg_multibyte(state, 0x88, buf, 1);
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x40;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- nxt200x_readbytes(state, 0x10, buf, 1);
- buf[0] = 0x10;
- nxt200x_writebytes(state, 0x10, buf, 1);
- nxt200x_readbytes(state, 0x0A, buf, 1);
- buf[0] = 0x21;
- nxt200x_writebytes(state, 0x0A, buf, 1);
-
- nxt2004_microcontroller_init(state);
-
- buf[0] = 0x21;
- nxt200x_writebytes(state, 0x0A, buf, 1);
- buf[0] = 0x7E;
- nxt200x_writebytes(state, 0xE9, buf, 1);
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0xEA, buf, 1);
-
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- /* soft reset? */
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x10;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
- nxt200x_readreg_multibyte(state, 0x08, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x08, buf, 1);
-
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x04;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x00;
- nxt200x_writereg_multibyte(state, 0x81, buf, 1);
- buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
- nxt200x_writereg_multibyte(state, 0x82, buf, 3);
-
- nxt200x_readreg_multibyte(state, 0x88, buf, 1);
- buf[0] = 0x11;
- nxt200x_writereg_multibyte(state, 0x88, buf, 1);
-
- nxt200x_readreg_multibyte(state, 0x80, buf, 1);
- buf[0] = 0x44;
- nxt200x_writereg_multibyte(state, 0x80, buf, 1);
-
- /* initialize tuner */
- nxt200x_readbytes(state, 0x10, buf, 1);
- buf[0] = 0x12;
- nxt200x_writebytes(state, 0x10, buf, 1);
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x13, buf, 1);
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x16, buf, 1);
- buf[0] = 0x04;
- nxt200x_writebytes(state, 0x14, buf, 1);
- buf[0] = 0x00;
- nxt200x_writebytes(state, 0x14, buf, 1);
- nxt200x_writebytes(state, 0x17, buf, 1);
- nxt200x_writebytes(state, 0x14, buf, 1);
- nxt200x_writebytes(state, 0x17, buf, 1);
-
- return 0;
-}
-
-static int nxt200x_init(struct dvb_frontend* fe)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- int ret = 0;
-
- if (!state->initialised) {
- switch (state->demod_chip) {
- case NXT2002:
- ret = nxt2002_init(fe);
- break;
- case NXT2004:
- ret = nxt2004_init(fe);
- break;
- default:
- return -EINVAL;
- break;
- }
- state->initialised = 1;
- }
- return ret;
-}
-
-static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-{
- fesettings->min_delay_ms = 500;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- return 0;
-}
-
-static void nxt200x_release(struct dvb_frontend* fe)
-{
- struct nxt200x_state* state = fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops nxt200x_ops;
-
-struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
- struct i2c_adapter* i2c)
-{
- struct nxt200x_state* state = NULL;
- u8 buf [] = {0,0,0,0,0};
-
- /* allocate memory for the internal state */
- state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
- if (state == NULL)
- goto error;
-
- /* setup the state */
- state->config = config;
- state->i2c = i2c;
- state->initialised = 0;
-
- /* read card id */
- nxt200x_readbytes(state, 0x00, buf, 5);
- dprintk("NXT info: %02X %02X %02X %02X %02X\n",
- buf[0], buf[1], buf[2], buf[3], buf[4]);
-
- /* set demod chip */
- switch (buf[0]) {
- case 0x04:
- state->demod_chip = NXT2002;
- printk("nxt200x: NXT2002 Detected\n");
- break;
- case 0x05:
- state->demod_chip = NXT2004;
- printk("nxt200x: NXT2004 Detected\n");
- break;
- default:
- goto error;
- }
-
- /* make sure demod chip is supported */
- switch (state->demod_chip) {
- case NXT2002:
- if (buf[0] != 0x04) goto error; /* device id */
- if (buf[1] != 0x02) goto error; /* fab id */
- if (buf[2] != 0x11) goto error; /* month */
- if (buf[3] != 0x20) goto error; /* year msb */
- if (buf[4] != 0x00) goto error; /* year lsb */
- break;
- case NXT2004:
- if (buf[0] != 0x05) goto error; /* device id */
- break;
- default:
- goto error;
- }
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-
-error:
- kfree(state);
- printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n",
- buf[0], buf[1], buf[2], buf[3], buf[4]);
- return NULL;
-}
-
-static struct dvb_frontend_ops nxt200x_ops = {
- .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
- .info = {
- .name = "Nextwave NXT200X VSB/QAM frontend",
- .frequency_min = 54000000,
- .frequency_max = 860000000,
- .frequency_stepsize = 166666, /* stepsize is just a guess */
- .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_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
- },
-
- .release = nxt200x_release,
-
- .init = nxt200x_init,
- .sleep = nxt200x_sleep,
-
- .set_frontend = nxt200x_setup_frontend_parameters,
- .get_tune_settings = nxt200x_get_tune_settings,
-
- .read_status = nxt200x_read_status,
- .read_ber = nxt200x_read_ber,
- .read_signal_strength = nxt200x_read_signal_strength,
- .read_snr = nxt200x_read_snr,
- .read_ucblocks = nxt200x_read_ucblocks,
-};
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
-MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(nxt200x_attach);
-
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
deleted file mode 100644
index 93612ebac519..000000000000
--- a/drivers/media/dvb/frontends/rtl2830.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * 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_get_frontend(struct dvb_frontend *fe)
-{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret;
- u8 buf[3];
-
- if (priv->sleeping)
- return 0;
-
- ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
- if (ret)
- goto err;
-
- ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
- if (ret)
- goto err;
-
- dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]);
-
- switch ((buf[0] >> 2) & 3) {
- case 0:
- c->modulation = QPSK;
- break;
- case 1:
- c->modulation = QAM_16;
- break;
- case 2:
- c->modulation = QAM_64;
- break;
- }
-
- switch ((buf[2] >> 2) & 1) {
- case 0:
- c->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 1:
- c->transmission_mode = TRANSMISSION_MODE_8K;
- }
-
- switch ((buf[2] >> 0) & 3) {
- case 0:
- c->guard_interval = GUARD_INTERVAL_1_32;
- break;
- case 1:
- c->guard_interval = GUARD_INTERVAL_1_16;
- break;
- case 2:
- c->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 3:
- c->guard_interval = GUARD_INTERVAL_1_4;
- break;
- }
-
- switch ((buf[0] >> 4) & 7) {
- case 0:
- c->hierarchy = HIERARCHY_NONE;
- break;
- case 1:
- c->hierarchy = HIERARCHY_1;
- break;
- case 2:
- c->hierarchy = HIERARCHY_2;
- break;
- case 3:
- c->hierarchy = HIERARCHY_4;
- break;
- }
-
- switch ((buf[1] >> 3) & 7) {
- case 0:
- c->code_rate_HP = FEC_1_2;
- break;
- case 1:
- c->code_rate_HP = FEC_2_3;
- break;
- case 2:
- c->code_rate_HP = FEC_3_4;
- break;
- case 3:
- c->code_rate_HP = FEC_5_6;
- break;
- case 4:
- c->code_rate_HP = FEC_7_8;
- break;
- }
-
- switch ((buf[1] >> 0) & 7) {
- case 0:
- c->code_rate_LP = FEC_1_2;
- break;
- case 1:
- c->code_rate_LP = FEC_2_3;
- break;
- case 2:
- c->code_rate_LP = FEC_3_4;
- break;
- case 3:
- c->code_rate_LP = FEC_5_6;
- break;
- case 4:
- c->code_rate_LP = FEC_7_8;
- break;
- }
-
- return 0;
-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)
-{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- int ret, hierarchy, constellation;
- u8 buf[2], tmp;
- u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
- static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
- { 70705899, 70705899, 70705899, 70705899 },
- { 82433173, 82433173, 87483115, 94445660 },
- { 92888734, 92888734, 95487525, 99770748 },
- };
-
- if (priv->sleeping)
- return 0;
-
- /* reports SNR in resolution of 0.1 dB */
-
- ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
- if (ret)
- goto err;
-
- constellation = (tmp >> 2) & 0x03; /* [3:2] */
- if (constellation > CONSTELLATION_NUM - 1)
- goto err;
-
- hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
- if (hierarchy > HIERARCHY_NUM - 1)
- goto err;
-
- ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
- if (ret)
- goto err;
-
- tmp16 = buf[0] << 8 | buf[1];
-
- if (tmp16)
- *snr = (snr_constant[constellation][hierarchy] -
- intlog10(tmp16)) / ((1 << 24) / 100);
- else
- *snr = 0;
-
- return 0;
-err:
- dbg("%s: failed=%d", __func__, ret);
- return ret;
-}
-
-static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[2];
-
- if (priv->sleeping)
- return 0;
-
- ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
- if (ret)
- goto err;
-
- *ber = buf[0] << 8 | buf[1];
-
- return 0;
-err:
- dbg("%s: failed=%d", __func__, ret);
- return ret;
-}
-
-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)
-{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- int ret;
- u8 buf[2];
- u16 if_agc_raw, if_agc;
-
- if (priv->sleeping)
- return 0;
-
- ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
- if (ret)
- goto err;
-
- if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
-
- if (if_agc_raw & (1 << 9))
- if_agc = -(~(if_agc_raw - 1) & 0x1ff);
- else
- if_agc = if_agc_raw;
-
- *strength = (u8) (55 - if_agc / 182);
- *strength |= *strength << 8;
-
- return 0;
-err:
- dbg("%s: failed=%d", __func__, ret);
- return ret;
-}
-
-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,
- .get_frontend = rtl2830_get_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/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
deleted file mode 100644
index a13a50503134..000000000000
--- a/drivers/media/dvb/mantis/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-config MANTIS_CORE
- tristate "Mantis/Hopper PCI bridge based devices"
- depends on PCI && I2C && INPUT && RC_CORE
-
- help
- Support for PCI cards based on the Mantis and Hopper PCi bridge.
-
- Say Y if you own such a device and want to use it.
-
-config DVB_MANTIS
- tristate "MANTIS based cards"
- depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_MB86A16 if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_STB0899 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- select DVB_TDA665x if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select DVB_PLL
- help
- Support for PCI cards based on the Mantis PCI bridge.
- Say Y when you have a Mantis based DVB card and want to use it.
-
- If unsure say N.
-
-config DVB_HOPPER
- tristate "HOPPER based cards"
- depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_PLL
- help
- Support for PCI cards based on the Hopper PCI bridge.
- Say Y when you have a Hopper based DVB card and want to use it.
-
- If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
deleted file mode 100644
index ec8116dcb368..000000000000
--- a/drivers/media/dvb/mantis/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-mantis_core-objs := mantis_ioc.o \
- mantis_uart.o \
- mantis_dma.o \
- mantis_pci.o \
- mantis_i2c.o \
- mantis_dvb.o \
- mantis_evm.o \
- mantis_hif.o \
- mantis_ca.o \
- mantis_pcmcia.o \
- mantis_input.o
-
-mantis-objs := mantis_cards.o \
- mantis_vp1033.o \
- mantis_vp1034.o \
- mantis_vp1041.o \
- mantis_vp2033.o \
- mantis_vp2040.o \
- mantis_vp3030.o
-
-hopper-objs := hopper_cards.o \
- hopper_vp3028.o
-
-obj-$(CONFIG_MANTIS_CORE) += mantis_core.o
-obj-$(CONFIG_DVB_MANTIS) += mantis.o
-obj-$(CONFIG_DVB_HOPPER) += hopper.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
deleted file mode 100644
index 095cf3a994e2..000000000000
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- Mantis PCI bridge driver
-
- Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <asm/irq.h>
-#include <linux/interrupt.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-
-#include "mantis_vp1033.h"
-#include "mantis_vp1034.h"
-#include "mantis_vp1041.h"
-#include "mantis_vp2033.h"
-#include "mantis_vp2040.h"
-#include "mantis_vp3030.h"
-
-#include "mantis_dma.h"
-#include "mantis_ca.h"
-#include "mantis_dvb.h"
-#include "mantis_uart.h"
-#include "mantis_ioc.h"
-#include "mantis_pci.h"
-#include "mantis_i2c.h"
-#include "mantis_reg.h"
-
-static unsigned int verbose;
-module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
-
-static int devs;
-
-#define DRIVER_NAME "Mantis"
-
-static char *label[10] = {
- "DMA",
- "IRQ-0",
- "IRQ-1",
- "OCERR",
- "PABRT",
- "RIPRR",
- "PPERR",
- "FTRGT",
- "RISCI",
- "RACK"
-};
-
-static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
-{
- u32 stat = 0, mask = 0;
- u32 rst_stat = 0, rst_mask = 0;
-
- struct mantis_pci *mantis;
- struct mantis_ca *ca;
-
- mantis = (struct mantis_pci *) dev_id;
- if (unlikely(mantis == NULL)) {
- dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
- return IRQ_NONE;
- }
- ca = mantis->mantis_ca;
-
- stat = mmread(MANTIS_INT_STAT);
- mask = mmread(MANTIS_INT_MASK);
- if (!(stat & mask))
- return IRQ_NONE;
-
- rst_mask = MANTIS_GPIF_WRACK |
- MANTIS_GPIF_OTHERR |
- MANTIS_SBUF_WSTO |
- MANTIS_GPIF_EXTIRQ;
-
- rst_stat = mmread(MANTIS_GPIF_STATUS);
- rst_stat &= rst_mask;
- mmwrite(rst_stat, MANTIS_GPIF_STATUS);
-
- mantis->mantis_int_stat = stat;
- mantis->mantis_int_mask = mask;
- dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
- if (stat & MANTIS_INT_RISCEN) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
- }
- if (stat & MANTIS_INT_IRQ0) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
- mantis->gpif_status = rst_stat;
- wake_up(&ca->hif_write_wq);
- schedule_work(&ca->hif_evm_work);
- }
- if (stat & MANTIS_INT_IRQ1) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
- schedule_work(&mantis->uart_work);
- }
- if (stat & MANTIS_INT_OCERR) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
- }
- if (stat & MANTIS_INT_PABORT) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
- }
- if (stat & MANTIS_INT_RIPERR) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
- }
- if (stat & MANTIS_INT_PPERR) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
- }
- if (stat & MANTIS_INT_FTRGT) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
- }
- if (stat & MANTIS_INT_RISCI) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
- mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
- tasklet_schedule(&mantis->tasklet);
- }
- if (stat & MANTIS_INT_I2CDONE) {
- dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
- wake_up(&mantis->i2c_wq);
- }
- mmwrite(stat, MANTIS_INT_STAT);
- stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
- MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
- MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
- MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
- MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
- MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
- MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
- MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
- MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
- MANTIS_INT_RISCI);
-
- if (stat)
- dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
-
- dprintk(MANTIS_DEBUG, 0, "\n");
- return IRQ_HANDLED;
-}
-
-static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
- struct mantis_pci *mantis;
- struct mantis_hwconfig *config;
- int err = 0;
-
- mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
- if (mantis == NULL) {
- printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
- err = -ENOMEM;
- goto fail0;
- }
-
- mantis->num = devs;
- mantis->verbose = verbose;
- mantis->pdev = pdev;
- config = (struct mantis_hwconfig *) pci_id->driver_data;
- config->irq_handler = &mantis_irq_handler;
- mantis->hwconfig = config;
-
- err = mantis_pci_init(mantis);
- if (err) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
- goto fail1;
- }
-
- err = mantis_stream_control(mantis, STREAM_TO_HIF);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
- goto fail1;
- }
-
- err = mantis_i2c_init(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
- goto fail2;
- }
-
- err = mantis_get_mac(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
- goto fail2;
- }
-
- err = mantis_dma_init(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
- goto fail3;
- }
-
- err = mantis_dvb_init(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
- goto fail4;
- }
- err = mantis_uart_init(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
- goto fail6;
- }
-
- devs++;
-
- return err;
-
-
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
- mantis_uart_exit(mantis);
-
-fail6:
-fail4:
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
- mantis_dma_exit(mantis);
-
-fail3:
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
- mantis_i2c_exit(mantis);
-
-fail2:
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
- mantis_pci_exit(mantis);
-
-fail1:
- dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
- kfree(mantis);
-
-fail0:
- return err;
-}
-
-static void __devexit mantis_pci_remove(struct pci_dev *pdev)
-{
- struct mantis_pci *mantis = pci_get_drvdata(pdev);
-
- if (mantis) {
-
- mantis_uart_exit(mantis);
- mantis_dvb_exit(mantis);
- mantis_dma_exit(mantis);
- mantis_i2c_exit(mantis);
- mantis_pci_exit(mantis);
- kfree(mantis);
- }
- return;
-}
-
-static struct pci_device_id mantis_pci_table[] = {
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
- MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
- MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
- MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
- MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
- MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
- MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
- { }
-};
-
-MODULE_DEVICE_TABLE(pci, mantis_pci_table);
-
-static struct pci_driver mantis_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = mantis_pci_table,
- .probe = mantis_pci_probe,
- .remove = mantis_pci_remove,
-};
-
-static int __devinit mantis_init(void)
-{
- return pci_register_driver(&mantis_pci_driver);
-}
-
-static void __devexit mantis_exit(void)
-{
- return pci_unregister_driver(&mantis_pci_driver);
-}
-
-module_init(mantis_init);
-module_exit(mantis_exit);
-
-MODULE_DESCRIPTION("MANTIS driver");
-MODULE_AUTHOR("Manu Abraham");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
deleted file mode 100644
index 22524a8e6f61..000000000000
--- a/drivers/media/dvb/mantis/mantis_core.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- Mantis PCI bridge driver
-
- Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "mantis_common.h"
-#include "mantis_core.h"
-#include "mantis_vp1033.h"
-#include "mantis_vp1034.h"
-#include "mantis_vp1041.h"
-#include "mantis_vp2033.h"
-#include "mantis_vp2040.h"
-#include "mantis_vp3030.h"
-
-static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
-{
- int err;
- struct i2c_msg msg[] = {
- {
- .addr = 0x50,
- .flags = 0,
- .buf = data,
- .len = 1
- }, {
- .addr = 0x50,
- .flags = I2C_M_RD,
- .buf = data,
- .len = length
- },
- };
-
- err = i2c_transfer(&mantis->adapter, msg, 2);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1,
- "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
- err, data[0], data[1]);
-
- return err;
- }
-
- return 0;
-}
-
-static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
-{
- int err;
-
- struct i2c_msg msg = {
- .addr = 0x50,
- .flags = 0,
- .buf = data,
- .len = length
- };
-
- err = i2c_transfer(&mantis->adapter, &msg, 1);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1,
- "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
- err, length, data[0], data[1]);
-
- return err;
- }
-
- return 0;
-}
-
-static int get_mac_address(struct mantis_pci *mantis)
-{
- int err;
-
- mantis->mac_address[0] = 0x08;
- err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
-
- return err;
- }
- dprintk(verbose, MANTIS_ERROR, 0,
- " MAC Address=[%pM]\n", mantis->mac_address);
-
- return 0;
-}
-
-#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
-#define MANTIS_DEV_UNKNOWN "UNKNOWN"
-
-struct mantis_hwconfig unknown_device = {
- .model_name = MANTIS_MODEL_UNKNOWN,
- .dev_type = MANTIS_DEV_UNKNOWN,
-};
-
-static void mantis_load_config(struct mantis_pci *mantis)
-{
- switch (mantis->subsystem_device) {
- case MANTIS_VP_1033_DVB_S: /* VP-1033 */
- mantis->hwconfig = &vp1033_mantis_config;
- break;
- case MANTIS_VP_1034_DVB_S: /* VP-1034 */
- mantis->hwconfig = &vp1034_mantis_config;
- break;
- case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
- case TECHNISAT_SKYSTAR_HD2:
- mantis->hwconfig = &vp1041_mantis_config;
- break;
- case MANTIS_VP_2033_DVB_C: /* VP-2033 */
- mantis->hwconfig = &vp2033_mantis_config;
- break;
- case MANTIS_VP_2040_DVB_C: /* VP-2040 */
- case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */
- case TECHNISAT_CABLESTAR_HD2:
- mantis->hwconfig = &vp2040_mantis_config;
- break;
- case MANTIS_VP_3030_DVB_T: /* VP-3030 */
- mantis->hwconfig = &vp3030_mantis_config;
- break;
- default:
- mantis->hwconfig = &unknown_device;
- break;
- }
-}
-
-int mantis_core_init(struct mantis_pci *mantis)
-{
- int err = 0;
-
- mantis_load_config(mantis);
- dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
- mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
- mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
- dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
- mantis->revision,
- mantis->subsystem_vendor, mantis->subsystem_device);
- dprintk(verbose, MANTIS_ERROR, 0,
- "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
- mantis->pdev->irq, mantis->latency,
- mantis->mantis_addr, mantis->mantis_mmio);
-
- err = mantis_i2c_init(mantis);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
- return err;
- }
- err = get_mac_address(mantis);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
- return err;
- }
- err = mantis_dma_init(mantis);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
- return err;
- }
- err = mantis_dvb_init(mantis);
- if (err < 0) {
- dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
- return err;
- }
- err = mantis_uart_init(mantis);
- if (err < 0) {
- dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
- return err;
- }
-
- return 0;
-}
-
-int mantis_core_exit(struct mantis_pci *mantis)
-{
- mantis_dma_stop(mantis);
- dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
-
- mantis_uart_exit(mantis);
- dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
-
- if (mantis_dma_exit(mantis) < 0)
- dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
- if (mantis_dvb_exit(mantis) < 0)
- dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
- if (mantis_i2c_exit(mantis) < 0)
- dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
-
- return 0;
-}
-
-/* Turn the given bit on or off. */
-void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
-{
- u32 cur;
-
- cur = mmread(MANTIS_GPIF_ADDR);
- if (value)
- mantis->gpio_status = cur | (1 << bitpos);
- else
- mantis->gpio_status = cur & (~(1 << bitpos));
-
- mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
- mmwrite(0x00, MANTIS_GPIF_DOUT);
- udelay(100);
-}
-
-/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
-void mantis_set_direction(struct mantis_pci *mantis, int direction)
-{
- u32 reg;
-
- reg = mmread(0x28);
- dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
- if (direction == 0x01) {
- /* to CI */
- reg |= 0x04;
- mmwrite(reg, 0x28);
- reg &= 0xff - 0x04;
- mmwrite(reg, 0x28);
- } else {
- reg &= 0xff - 0x04;
- mmwrite(reg, 0x28);
- reg |= 0x04;
- mmwrite(reg, 0x28);
- }
-}
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
deleted file mode 100644
index e5180e45d310..000000000000
--- a/drivers/media/dvb/mantis/mantis_dvb.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- Mantis PCI bridge driver
- Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-
-#include "mantis_common.h"
-#include "mantis_dma.h"
-#include "mantis_ca.h"
-#include "mantis_ioc.h"
-#include "mantis_dvb.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
-{
- struct mantis_hwconfig *config = mantis->hwconfig;
-
- switch (power) {
- case POWER_ON:
- dprintk(MANTIS_DEBUG, 1, "Power ON");
- mantis_gpio_set_bits(mantis, config->power, POWER_ON);
- msleep(100);
- mantis_gpio_set_bits(mantis, config->power, POWER_ON);
- msleep(100);
- break;
-
- case POWER_OFF:
- dprintk(MANTIS_DEBUG, 1, "Power OFF");
- mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
- msleep(100);
- break;
-
- default:
- dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
- return -1;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_frontend_power);
-
-void mantis_frontend_soft_reset(struct mantis_pci *mantis)
-{
- struct mantis_hwconfig *config = mantis->hwconfig;
-
- dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
- mantis_gpio_set_bits(mantis, config->reset, 0);
- msleep(100);
- mantis_gpio_set_bits(mantis, config->reset, 0);
- msleep(100);
- mantis_gpio_set_bits(mantis, config->reset, 1);
- msleep(100);
- mantis_gpio_set_bits(mantis, config->reset, 1);
- msleep(100);
-
- return;
-}
-EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
-
-static int mantis_frontend_shutdown(struct mantis_pci *mantis)
-{
- int err;
-
- mantis_frontend_soft_reset(mantis);
- err = mantis_frontend_power(mantis, POWER_OFF);
- if (err != 0) {
- dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
- return 1;
- }
-
- return 0;
-}
-
-static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct mantis_pci *mantis = dvbdmx->priv;
-
- dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
- if (!dvbdmx->dmx.frontend) {
- dprintk(MANTIS_DEBUG, 1, "no frontend ?");
- return -EINVAL;
- }
-
- mantis->feeds++;
- dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
-
- if (mantis->feeds == 1) {
- dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
- mantis_dma_start(mantis);
- tasklet_enable(&mantis->tasklet);
- }
-
- return mantis->feeds;
-}
-
-static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct mantis_pci *mantis = dvbdmx->priv;
-
- dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
- if (!dvbdmx->dmx.frontend) {
- dprintk(MANTIS_DEBUG, 1, "no frontend ?");
- return -EINVAL;
- }
-
- mantis->feeds--;
- if (mantis->feeds == 0) {
- dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
- tasklet_disable(&mantis->tasklet);
- mantis_dma_stop(mantis);
- }
-
- return 0;
-}
-
-int __devinit mantis_dvb_init(struct mantis_pci *mantis)
-{
- struct mantis_hwconfig *config = mantis->hwconfig;
- int result = -1;
-
- dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
-
- result = dvb_register_adapter(&mantis->dvb_adapter,
- "Mantis DVB adapter",
- THIS_MODULE,
- &mantis->pdev->dev,
- adapter_nr);
-
- if (result < 0) {
-
- dprintk(MANTIS_ERROR, 1, "Error registering adapter");
- return -ENODEV;
- }
-
- mantis->dvb_adapter.priv = mantis;
- mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
- DMX_SECTION_FILTERING |
- DMX_MEMORY_BASED_FILTERING;
-
- mantis->demux.priv = mantis;
- mantis->demux.filternum = 256;
- mantis->demux.feednum = 256;
- mantis->demux.start_feed = mantis_dvb_start_feed;
- mantis->demux.stop_feed = mantis_dvb_stop_feed;
- mantis->demux.write_to_decoder = NULL;
-
- dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
- result = dvb_dmx_init(&mantis->demux);
- if (result < 0) {
- dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
-
- goto err0;
- }
-
- mantis->dmxdev.filternum = 256;
- mantis->dmxdev.demux = &mantis->demux.dmx;
- mantis->dmxdev.capabilities = 0;
- dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
-
- result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
- if (result < 0) {
-
- dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
- goto err1;
- }
-
- mantis->fe_hw.source = DMX_FRONTEND_0;
- result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
- if (result < 0) {
-
- dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
- goto err2;
- }
-
- mantis->fe_mem.source = DMX_MEMORY_FE;
- result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
- if (result < 0) {
- dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
- goto err3;
- }
-
- result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
- if (result < 0) {
- dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
- goto err4;
- }
-
- dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
- tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
- tasklet_disable(&mantis->tasklet);
- if (mantis->hwconfig) {
- result = config->frontend_init(mantis, mantis->fe);
- if (result < 0) {
- dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
- goto err5;
- } else {
- if (mantis->fe == NULL) {
- dprintk(MANTIS_ERROR, 1, "FE <NULL>");
- goto err5;
- }
-
- if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
- dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
-
- if (mantis->fe->ops.release)
- mantis->fe->ops.release(mantis->fe);
-
- mantis->fe = NULL;
- goto err5;
- }
- }
- }
-
- return 0;
-
- /* Error conditions .. */
-err5:
- tasklet_kill(&mantis->tasklet);
- dvb_net_release(&mantis->dvbnet);
- dvb_unregister_frontend(mantis->fe);
- dvb_frontend_detach(mantis->fe);
-err4:
- mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
-
-err3:
- mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-
-err2:
- dvb_dmxdev_release(&mantis->dmxdev);
-
-err1:
- dvb_dmx_release(&mantis->demux);
-
-err0:
- dvb_unregister_adapter(&mantis->dvb_adapter);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(mantis_dvb_init);
-
-int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
-{
- int err;
-
- if (mantis->fe) {
- /* mantis_ca_exit(mantis); */
- err = mantis_frontend_shutdown(mantis);
- if (err != 0)
- dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
- dvb_unregister_frontend(mantis->fe);
- dvb_frontend_detach(mantis->fe);
- }
-
- tasklet_kill(&mantis->tasklet);
- dvb_net_release(&mantis->dvbnet);
-
- mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
- mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
-
- dvb_dmxdev_release(&mantis->dmxdev);
- dvb_dmx_release(&mantis->demux);
-
- dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
- dvb_unregister_adapter(&mantis->dvb_adapter);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig
deleted file mode 100644
index 64c84702ba5c..000000000000
--- a/drivers/media/dvb/ngene/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config DVB_NGENE
- tristate "Micronas nGene support"
- depends on DVB_CORE && PCI && I2C
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_STV6110x if !DVB_FE_CUSTOMISE
- select DVB_STV090x if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_DRXK if !DVB_FE_CUSTOMISE
- select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
- ---help---
- Support for Micronas PCI express cards with nGene bridge.
-
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile
deleted file mode 100644
index 13ebeffb705f..000000000000
--- a/drivers/media/dvb/ngene/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the nGene device driver
-#
-
-ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
-
-obj-$(CONFIG_DVB_NGENE) += ngene.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
deleted file mode 100644
index 72ee8de02260..000000000000
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * ngene-cards.c: nGene PCIe bridge driver - card specific info
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- * Modifications for new nGene firmware,
- * support for EEPROM-copying,
- * support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, 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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-#include "ngene.h"
-
-/* demods/tuners */
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "lnbh24.h"
-#include "lgdt330x.h"
-#include "mt2131.h"
-#include "tda18271c2dd.h"
-#include "drxk.h"
-
-
-/****************************************************************************/
-/* Demod/tuner attachment ***************************************************/
-/****************************************************************************/
-
-static int tuner_attach_stv6110(struct ngene_channel *chan)
-{
- struct i2c_adapter *i2c;
- struct stv090x_config *feconf = (struct stv090x_config *)
- chan->dev->card_info->fe_config[chan->number];
- struct stv6110x_config *tunerconf = (struct stv6110x_config *)
- chan->dev->card_info->tuner_config[chan->number];
- struct stv6110x_devctl *ctl;
-
- /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
- if (chan->number < 2)
- i2c = &chan->dev->channel[0].i2c_adapter;
- else
- i2c = &chan->dev->channel[1].i2c_adapter;
-
- ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
- if (ctl == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");
- return -ENODEV;
- }
-
- feconf->tuner_init = ctl->tuner_init;
- feconf->tuner_sleep = ctl->tuner_sleep;
- feconf->tuner_set_mode = ctl->tuner_set_mode;
- feconf->tuner_set_frequency = ctl->tuner_set_frequency;
- feconf->tuner_get_frequency = ctl->tuner_get_frequency;
- feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
- feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
- feconf->tuner_set_bbgain = ctl->tuner_set_bbgain;
- feconf->tuner_get_bbgain = ctl->tuner_get_bbgain;
- feconf->tuner_set_refclk = ctl->tuner_set_refclk;
- feconf->tuner_get_status = ctl->tuner_get_status;
-
- return 0;
-}
-
-
-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct ngene_channel *chan = fe->sec_priv;
- int status;
-
- if (enable) {
- down(&chan->dev->pll_mutex);
- status = chan->gate_ctrl(fe, 1);
- } else {
- status = chan->gate_ctrl(fe, 0);
- up(&chan->dev->pll_mutex);
- }
- return status;
-}
-
-static int tuner_attach_tda18271(struct ngene_channel *chan)
-{
- struct i2c_adapter *i2c;
- struct dvb_frontend *fe;
-
- i2c = &chan->dev->channel[0].i2c_adapter;
- if (chan->fe->ops.i2c_gate_ctrl)
- chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
- fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
- if (chan->fe->ops.i2c_gate_ctrl)
- chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
- if (!fe) {
- printk(KERN_ERR "No TDA18271 found!\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int tuner_attach_probe(struct ngene_channel *chan)
-{
- if (chan->demod_type == 0)
- return tuner_attach_stv6110(chan);
- if (chan->demod_type == 1)
- return tuner_attach_tda18271(chan);
- return -EINVAL;
-}
-
-static int demod_attach_stv0900(struct ngene_channel *chan)
-{
- struct i2c_adapter *i2c;
- struct stv090x_config *feconf = (struct stv090x_config *)
- chan->dev->card_info->fe_config[chan->number];
-
- /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
- /* Note: Both adapters share the same i2c bus, but the demod */
- /* driver requires that each demod has its own i2c adapter */
- if (chan->number < 2)
- i2c = &chan->dev->channel[0].i2c_adapter;
- else
- i2c = &chan->dev->channel[1].i2c_adapter;
-
- chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
- (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
- : STV090x_DEMODULATOR_1);
- if (chan->fe == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");
- return -ENODEV;
- }
-
- /* store channel info */
- if (feconf->tuner_i2c_lock)
- chan->fe->analog_demod_priv = chan;
-
- if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
- 0, chan->dev->card_info->lnb[chan->number])) {
- printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
- dvb_frontend_detach(chan->fe);
- chan->fe = NULL;
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
-{
- struct ngene_channel *chan = fe->analog_demod_priv;
-
- if (lock)
- down(&chan->dev->pll_mutex);
- else
- up(&chan->dev->pll_mutex);
-}
-
-static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
-{
- struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
- .buf = val, .len = 1 } };
- return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
-}
-
-static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
- u16 reg, u8 *val)
-{
- u8 msg[2] = {reg>>8, reg&0xff};
- struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
- .buf = msg, .len = 2},
- {.addr = adr, .flags = I2C_M_RD,
- .buf = val, .len = 1} };
- return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
-}
-
-static int port_has_stv0900(struct i2c_adapter *i2c, int port)
-{
- u8 val;
- if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
- return 0;
- return 1;
-}
-
-static int port_has_drxk(struct i2c_adapter *i2c, int port)
-{
- u8 val;
-
- if (i2c_read(i2c, 0x29+port, &val) < 0)
- return 0;
- return 1;
-}
-
-static int demod_attach_drxk(struct ngene_channel *chan,
- struct i2c_adapter *i2c)
-{
- struct drxk_config config;
-
- memset(&config, 0, sizeof(config));
- config.microcode_name = "drxk_a3.mc";
- config.qam_demod_parameter_count = 4;
- config.adr = 0x29 + (chan->number ^ 2);
-
- chan->fe = dvb_attach(drxk_attach, &config, i2c);
- if (!chan->fe) {
- printk(KERN_ERR "No DRXK found!\n");
- return -ENODEV;
- }
- chan->fe->sec_priv = chan;
- chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
- chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
- return 0;
-}
-
-static int cineS2_probe(struct ngene_channel *chan)
-{
- struct i2c_adapter *i2c;
- struct stv090x_config *fe_conf;
- u8 buf[3];
- struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
- int rc;
-
- /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
- if (chan->number < 2)
- i2c = &chan->dev->channel[0].i2c_adapter;
- else
- i2c = &chan->dev->channel[1].i2c_adapter;
-
- if (port_has_stv0900(i2c, chan->number)) {
- chan->demod_type = 0;
- fe_conf = chan->dev->card_info->fe_config[chan->number];
- /* demod found, attach it */
- rc = demod_attach_stv0900(chan);
- if (rc < 0 || chan->number < 2)
- return rc;
-
- /* demod #2: reprogram outputs DPN1 & DPN2 */
- i2c_msg.addr = fe_conf->address;
- i2c_msg.len = 3;
- buf[0] = 0xf1;
- switch (chan->number) {
- case 2:
- buf[1] = 0x5c;
- buf[2] = 0xc2;
- break;
- case 3:
- buf[1] = 0x61;
- buf[2] = 0xcc;
- break;
- default:
- return -ENODEV;
- }
- rc = i2c_transfer(i2c, &i2c_msg, 1);
- if (rc != 1) {
- printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
- return -EIO;
- }
- } else if (port_has_drxk(i2c, chan->number^2)) {
- chan->demod_type = 1;
- demod_attach_drxk(chan, i2c);
- } else {
- printk(KERN_ERR "No demod found on chan %d\n", chan->number);
- return -ENODEV;
- }
- return 0;
-}
-
-
-static struct lgdt330x_config aver_m780 = {
- .demod_address = 0xb2 >> 1,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x00, /* PARALLEL */
- .clock_polarity_flip = 1,
-};
-
-static struct mt2131_config m780_tunerconfig = {
- 0xc0 >> 1
-};
-
-/* A single func to attach the demo and tuner, rather than
- * use two sep funcs like the current design mandates.
- */
-static int demod_attach_lg330x(struct ngene_channel *chan)
-{
- chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
- if (chan->fe == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n");
- return -ENODEV;
- }
-
- dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
- &m780_tunerconfig, 0);
-
- return (chan->fe) ? 0 : -ENODEV;
-}
-
-/****************************************************************************/
-/* Switch control (I2C gates, etc.) *****************************************/
-/****************************************************************************/
-
-
-static struct stv090x_config fe_cineS2 = {
- .device = STV0900,
- .demod_mode = STV090x_DUAL,
- .clk_mode = STV090x_CLK_EXT,
-
- .xtal = 27000000,
- .address = 0x68,
-
- .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
- .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
-
- .repeater_level = STV090x_RPTLEVEL_16,
-
- .adc1_range = STV090x_ADC_1Vpp,
- .adc2_range = STV090x_ADC_1Vpp,
-
- .diseqc_envelope_mode = true,
-
- .tuner_i2c_lock = cineS2_tuner_i2c_lock,
-};
-
-static struct stv090x_config fe_cineS2_2 = {
- .device = STV0900,
- .demod_mode = STV090x_DUAL,
- .clk_mode = STV090x_CLK_EXT,
-
- .xtal = 27000000,
- .address = 0x69,
-
- .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
- .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
-
- .repeater_level = STV090x_RPTLEVEL_16,
-
- .adc1_range = STV090x_ADC_1Vpp,
- .adc2_range = STV090x_ADC_1Vpp,
-
- .diseqc_envelope_mode = true,
-
- .tuner_i2c_lock = cineS2_tuner_i2c_lock,
-};
-
-static struct stv6110x_config tuner_cineS2_0 = {
- .addr = 0x60,
- .refclk = 27000000,
- .clk_div = 1,
-};
-
-static struct stv6110x_config tuner_cineS2_1 = {
- .addr = 0x63,
- .refclk = 27000000,
- .clk_div = 1,
-};
-
-static struct ngene_info ngene_info_cineS2 = {
- .type = NGENE_SIDEWINDER,
- .name = "Linux4Media cineS2 DVB-S2 Twin Tuner",
- .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
- .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
- .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
- .fe_config = {&fe_cineS2, &fe_cineS2},
- .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
- .lnb = {0x0b, 0x08},
- .tsf = {3, 3},
- .fw_version = 18,
- .msi_supported = true,
-};
-
-static struct ngene_info ngene_info_satixS2 = {
- .type = NGENE_SIDEWINDER,
- .name = "Mystique SaTiX-S2 Dual",
- .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
- .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
- .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
- .fe_config = {&fe_cineS2, &fe_cineS2},
- .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
- .lnb = {0x0b, 0x08},
- .tsf = {3, 3},
- .fw_version = 18,
- .msi_supported = true,
-};
-
-static struct ngene_info ngene_info_satixS2v2 = {
- .type = NGENE_SIDEWINDER,
- .name = "Mystique SaTiX-S2 Dual (v2)",
- .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
- NGENE_IO_TSOUT},
- .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
- .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
- .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
- .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
- .lnb = {0x0a, 0x08, 0x0b, 0x09},
- .tsf = {3, 3},
- .fw_version = 18,
- .msi_supported = true,
-};
-
-static struct ngene_info ngene_info_cineS2v5 = {
- .type = NGENE_SIDEWINDER,
- .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
- .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
- NGENE_IO_TSOUT},
- .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
- .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
- .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
- .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
- .lnb = {0x0a, 0x08, 0x0b, 0x09},
- .tsf = {3, 3},
- .fw_version = 18,
- .msi_supported = true,
-};
-
-
-static struct ngene_info ngene_info_duoFlex = {
- .type = NGENE_SIDEWINDER,
- .name = "Digital Devices DuoFlex PCIe or miniPCIe",
- .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
- NGENE_IO_TSOUT},
- .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
- .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
- .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
- .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
- .lnb = {0x0a, 0x08, 0x0b, 0x09},
- .tsf = {3, 3},
- .fw_version = 18,
- .msi_supported = true,
-};
-
-static struct ngene_info ngene_info_m780 = {
- .type = NGENE_APP,
- .name = "Aver M780 ATSC/QAM-B",
-
- /* Channel 0 is analog, which is currently unsupported */
- .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN },
- .demod_attach = { NULL, demod_attach_lg330x },
-
- /* Ensure these are NULL else the frame will call them (as funcs) */
- .tuner_attach = { 0, 0, 0, 0 },
- .fe_config = { NULL, &aver_m780 },
- .avf = { 0 },
-
- /* A custom electrical interface config for the demod to bridge */
- .tsf = { 4, 4 },
- .fw_version = 15,
-};
-
-/****************************************************************************/
-
-
-
-/****************************************************************************/
-/* PCI Subsystem ID *********************************************************/
-/****************************************************************************/
-
-#define NGENE_ID(_subvend, _subdev, _driverdata) { \
- .vendor = NGENE_VID, .device = NGENE_PID, \
- .subvendor = _subvend, .subdevice = _subdev, \
- .driver_data = (unsigned long) &_driverdata }
-
-/****************************************************************************/
-
-static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
- NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
- NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
- NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
- NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
- NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
- NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
- NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
- NGENE_ID(0x1461, 0x062e, ngene_info_m780),
- {0}
-};
-MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
-
-/****************************************************************************/
-/* Init/Exit ****************************************************************/
-/****************************************************************************/
-
-static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
- enum pci_channel_state state)
-{
- printk(KERN_ERR DEVICE_NAME ": PCI error\n");
- if (state == pci_channel_io_perm_failure)
- return PCI_ERS_RESULT_DISCONNECT;
- if (state == pci_channel_io_frozen)
- return PCI_ERS_RESULT_NEED_RESET;
- return PCI_ERS_RESULT_CAN_RECOVER;
-}
-
-static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
-{
- printk(KERN_INFO DEVICE_NAME ": link reset\n");
- return 0;
-}
-
-static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
-{
- printk(KERN_INFO DEVICE_NAME ": slot reset\n");
- return 0;
-}
-
-static void ngene_resume(struct pci_dev *dev)
-{
- printk(KERN_INFO DEVICE_NAME ": resume\n");
-}
-
-static struct pci_error_handlers ngene_errors = {
- .error_detected = ngene_error_detected,
- .link_reset = ngene_link_reset,
- .slot_reset = ngene_slot_reset,
- .resume = ngene_resume,
-};
-
-static struct pci_driver ngene_pci_driver = {
- .name = "ngene",
- .id_table = ngene_id_tbl,
- .probe = ngene_probe,
- .remove = __devexit_p(ngene_remove),
- .err_handler = &ngene_errors,
- .shutdown = ngene_shutdown,
-};
-
-static __init int module_init_ngene(void)
-{
- printk(KERN_INFO
- "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
- return pci_register_driver(&ngene_pci_driver);
-}
-
-static __exit void module_exit_ngene(void)
-{
- pci_unregister_driver(&ngene_pci_driver);
-}
-
-module_init(module_init_ngene);
-module_exit(module_exit_ngene);
-
-MODULE_DESCRIPTION("nGene");
-MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
deleted file mode 100644
index 39857384af10..000000000000
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ /dev/null
@@ -1,1713 +0,0 @@
-/*
- * ngene.c: nGene PCIe bridge driver
- *
- * Copyright (C) 2005-2007 Micronas
- *
- * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
- * Modifications for new nGene firmware,
- * support for EEPROM-copying,
- * support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, 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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/byteorder/generic.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-
-#include "ngene.h"
-
-static int one_adapter;
-module_param(one_adapter, int, 0444);
-MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
-
-static int shutdown_workaround;
-module_param(shutdown_workaround, int, 0644);
-MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
-
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Print debugging information.");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk if (debug) printk
-
-#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngreadl(adr) readl(dev->iomem + (adr))
-#define ngreadb(adr) readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count) memcpy_toio((char *) \
- (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
- (dev->iomem + (adr)), (count))
-
-/****************************************************************************/
-/* nGene interrupt handler **************************************************/
-/****************************************************************************/
-
-static void event_tasklet(unsigned long data)
-{
- struct ngene *dev = (struct ngene *)data;
-
- while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
- struct EVENT_BUFFER Event =
- dev->EventQueue[dev->EventQueueReadIndex];
- dev->EventQueueReadIndex =
- (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
-
- if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
- dev->TxEventNotify(dev, Event.TimeStamp);
- if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
- dev->RxEventNotify(dev, Event.TimeStamp,
- Event.RXCharacter);
- }
-}
-
-static void demux_tasklet(unsigned long data)
-{
- struct ngene_channel *chan = (struct ngene_channel *)data;
- struct SBufferHeader *Cur = chan->nextBuffer;
-
- spin_lock_irq(&chan->state_lock);
-
- while (Cur->ngeneBuffer.SR.Flags & 0x80) {
- if (chan->mode & NGENE_IO_TSOUT) {
- u32 Flags = chan->DataFormatFlags;
- if (Cur->ngeneBuffer.SR.Flags & 0x20)
- Flags |= BEF_OVERFLOW;
- if (chan->pBufferExchange) {
- if (!chan->pBufferExchange(chan,
- Cur->Buffer1,
- chan->Capture1Length,
- Cur->ngeneBuffer.SR.
- Clock, Flags)) {
- /*
- We didn't get data
- Clear in service flag to make sure we
- get called on next interrupt again.
- leave fill/empty (0x80) flag alone
- to avoid hardware running out of
- buffers during startup, we hold only
- in run state ( the source may be late
- delivering data )
- */
-
- if (chan->HWState == HWSTATE_RUN) {
- Cur->ngeneBuffer.SR.Flags &=
- ~0x40;
- break;
- /* Stop processing stream */
- }
- } else {
- /* We got a valid buffer,
- so switch to run state */
- chan->HWState = HWSTATE_RUN;
- }
- } else {
- printk(KERN_ERR DEVICE_NAME ": OOPS\n");
- if (chan->HWState == HWSTATE_RUN) {
- Cur->ngeneBuffer.SR.Flags &= ~0x40;
- break; /* Stop processing stream */
- }
- }
- if (chan->AudioDTOUpdated) {
- printk(KERN_INFO DEVICE_NAME
- ": Update AudioDTO = %d\n",
- chan->AudioDTOValue);
- Cur->ngeneBuffer.SR.DTOUpdate =
- chan->AudioDTOValue;
- chan->AudioDTOUpdated = 0;
- }
- } else {
- if (chan->HWState == HWSTATE_RUN) {
- u32 Flags = chan->DataFormatFlags;
- IBufferExchange *exch1 = chan->pBufferExchange;
- IBufferExchange *exch2 = chan->pBufferExchange2;
- if (Cur->ngeneBuffer.SR.Flags & 0x01)
- Flags |= BEF_EVEN_FIELD;
- if (Cur->ngeneBuffer.SR.Flags & 0x20)
- Flags |= BEF_OVERFLOW;
- spin_unlock_irq(&chan->state_lock);
- if (exch1)
- exch1(chan, Cur->Buffer1,
- chan->Capture1Length,
- Cur->ngeneBuffer.SR.Clock,
- Flags);
- if (exch2)
- exch2(chan, Cur->Buffer2,
- chan->Capture2Length,
- Cur->ngeneBuffer.SR.Clock,
- Flags);
- spin_lock_irq(&chan->state_lock);
- } else if (chan->HWState != HWSTATE_STOP)
- chan->HWState = HWSTATE_RUN;
- }
- Cur->ngeneBuffer.SR.Flags = 0x00;
- Cur = Cur->Next;
- }
- chan->nextBuffer = Cur;
-
- spin_unlock_irq(&chan->state_lock);
-}
-
-static irqreturn_t irq_handler(int irq, void *dev_id)
-{
- struct ngene *dev = (struct ngene *)dev_id;
- u32 icounts = 0;
- irqreturn_t rc = IRQ_NONE;
- u32 i = MAX_STREAM;
- u8 *tmpCmdDoneByte;
-
- if (dev->BootFirmware) {
- icounts = ngreadl(NGENE_INT_COUNTS);
- if (icounts != dev->icounts) {
- ngwritel(0, FORCE_NMI);
- dev->cmd_done = 1;
- wake_up(&dev->cmd_wq);
- dev->icounts = icounts;
- rc = IRQ_HANDLED;
- }
- return rc;
- }
-
- ngwritel(0, FORCE_NMI);
-
- spin_lock(&dev->cmd_lock);
- tmpCmdDoneByte = dev->CmdDoneByte;
- if (tmpCmdDoneByte &&
- (*tmpCmdDoneByte ||
- (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
- dev->CmdDoneByte = NULL;
- dev->cmd_done = 1;
- wake_up(&dev->cmd_wq);
- rc = IRQ_HANDLED;
- }
- spin_unlock(&dev->cmd_lock);
-
- if (dev->EventBuffer->EventStatus & 0x80) {
- u8 nextWriteIndex =
- (dev->EventQueueWriteIndex + 1) &
- (EVENT_QUEUE_SIZE - 1);
- if (nextWriteIndex != dev->EventQueueReadIndex) {
- dev->EventQueue[dev->EventQueueWriteIndex] =
- *(dev->EventBuffer);
- dev->EventQueueWriteIndex = nextWriteIndex;
- } else {
- printk(KERN_ERR DEVICE_NAME ": event overflow\n");
- dev->EventQueueOverflowCount += 1;
- dev->EventQueueOverflowFlag = 1;
- }
- dev->EventBuffer->EventStatus &= ~0x80;
- tasklet_schedule(&dev->event_tasklet);
- rc = IRQ_HANDLED;
- }
-
- while (i > 0) {
- i--;
- spin_lock(&dev->channel[i].state_lock);
- /* if (dev->channel[i].State>=KSSTATE_RUN) { */
- if (dev->channel[i].nextBuffer) {
- if ((dev->channel[i].nextBuffer->
- ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
- dev->channel[i].nextBuffer->
- ngeneBuffer.SR.Flags |= 0x40;
- tasklet_schedule(
- &dev->channel[i].demux_tasklet);
- rc = IRQ_HANDLED;
- }
- }
- spin_unlock(&dev->channel[i].state_lock);
- }
-
- /* Request might have been processed by a previous call. */
- return IRQ_HANDLED;
-}
-
-/****************************************************************************/
-/* nGene command interface **************************************************/
-/****************************************************************************/
-
-static void dump_command_io(struct ngene *dev)
-{
- u8 buf[8], *b;
-
- ngcpyfrom(buf, HOST_TO_NGENE, 8);
- printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
- HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7]);
-
- ngcpyfrom(buf, NGENE_TO_HOST, 8);
- printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
- NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7]);
-
- b = dev->hosttongene;
- printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
- b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
-
- b = dev->ngenetohost;
- printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
- b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
-}
-
-static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
-{
- int ret;
- u8 *tmpCmdDoneByte;
-
- dev->cmd_done = 0;
-
- if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
- dev->BootFirmware = 1;
- dev->icounts = ngreadl(NGENE_INT_COUNTS);
- ngwritel(0, NGENE_COMMAND);
- ngwritel(0, NGENE_COMMAND_HI);
- ngwritel(0, NGENE_STATUS);
- ngwritel(0, NGENE_STATUS_HI);
- ngwritel(0, NGENE_EVENT);
- ngwritel(0, NGENE_EVENT_HI);
- } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
- u64 fwio = dev->PAFWInterfaceBuffer;
-
- ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
- ngwritel(fwio >> 32, NGENE_COMMAND_HI);
- ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
- ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
- ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
- ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
- }
-
- memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
-
- if (dev->BootFirmware)
- ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
-
- spin_lock_irq(&dev->cmd_lock);
- tmpCmdDoneByte = dev->ngenetohost + com->out_len;
- if (!com->out_len)
- tmpCmdDoneByte++;
- *tmpCmdDoneByte = 0;
- dev->ngenetohost[0] = 0;
- dev->ngenetohost[1] = 0;
- dev->CmdDoneByte = tmpCmdDoneByte;
- spin_unlock_irq(&dev->cmd_lock);
-
- /* Notify 8051. */
- ngwritel(1, FORCE_INT);
-
- ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
- if (!ret) {
- /*ngwritel(0, FORCE_NMI);*/
-
- printk(KERN_ERR DEVICE_NAME
- ": Command timeout cmd=%02x prev=%02x\n",
- com->cmd.hdr.Opcode, dev->prev_cmd);
- dump_command_io(dev);
- return -1;
- }
- if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
- dev->BootFirmware = 0;
-
- dev->prev_cmd = com->cmd.hdr.Opcode;
-
- if (!com->out_len)
- return 0;
-
- memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
-
- return 0;
-}
-
-int ngene_command(struct ngene *dev, struct ngene_command *com)
-{
- int result;
-
- down(&dev->cmd_mutex);
- result = ngene_command_mutex(dev, com);
- up(&dev->cmd_mutex);
- return result;
-}
-
-
-static int ngene_command_load_firmware(struct ngene *dev,
- u8 *ngene_fw, u32 size)
-{
-#define FIRSTCHUNK (1024)
- u32 cleft;
- struct ngene_command com;
-
- com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
- com.cmd.hdr.Length = 0;
- com.in_len = 0;
- com.out_len = 0;
-
- ngene_command(dev, &com);
-
- cleft = (size + 3) & ~3;
- if (cleft > FIRSTCHUNK) {
- ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
- cleft - FIRSTCHUNK);
- cleft = FIRSTCHUNK;
- }
- ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
-
- memset(&com, 0, sizeof(struct ngene_command));
- com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
- com.cmd.hdr.Length = 4;
- com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
- com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
- com.in_len = 4;
- com.out_len = 0;
-
- return ngene_command(dev, &com);
-}
-
-
-static int ngene_command_config_buf(struct ngene *dev, u8 config)
-{
- struct ngene_command com;
-
- com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
- com.cmd.hdr.Length = 1;
- com.cmd.ConfigureBuffers.config = config;
- com.in_len = 1;
- com.out_len = 0;
-
- if (ngene_command(dev, &com) < 0)
- return -EIO;
- return 0;
-}
-
-static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
-{
- struct ngene_command com;
-
- com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
- com.cmd.hdr.Length = 6;
- memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
- com.in_len = 6;
- com.out_len = 0;
-
- if (ngene_command(dev, &com) < 0)
- return -EIO;
-
- return 0;
-}
-
-int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
-{
- struct ngene_command com;
-
- com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
- com.cmd.hdr.Length = 1;
- com.cmd.SetGpioPin.select = select | (level << 7);
- com.in_len = 1;
- com.out_len = 0;
-
- return ngene_command(dev, &com);
-}
-
-
-/*
- 02000640 is sample on rising edge.
- 02000740 is sample on falling edge.
- 02000040 is ignore "valid" signal
-
- 0: FD_CTL1 Bit 7,6 must be 0,1
- 7 disable(fw controlled)
- 6 0-AUX,1-TS
- 5 0-par,1-ser
- 4 0-lsb/1-msb
- 3,2 reserved
- 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
- 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
- 2: FD_STA is read-only. 0-sync
- 3: FD_INSYNC is number of 47s to trigger "in sync".
- 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
- 5: FD_MAXBYTE1 is low-order of bytes per packet.
- 6: FD_MAXBYTE2 is high-order of bytes per packet.
- 7: Top byte is unused.
-*/
-
-/****************************************************************************/
-
-static u8 TSFeatureDecoderSetup[8 * 5] = {
- 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
- 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
- 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
- 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
- 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
-};
-
-/* Set NGENE I2S Config to 16 bit packed */
-static u8 I2SConfiguration[] = {
- 0x00, 0x10, 0x00, 0x00,
- 0x80, 0x10, 0x00, 0x00,
-};
-
-static u8 SPDIFConfiguration[10] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/* Set NGENE I2S Config to transport stream compatible mode */
-
-static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
-
-static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
-
-static u8 ITUDecoderSetup[4][16] = {
- {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */
- 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
- {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
- {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */
- 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
- {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */
- 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
-};
-
-/*
- * 50 48 60 gleich
- * 27p50 9f 00 22 80 42 69 18 ...
- * 27p60 93 00 22 80 82 69 1c ...
- */
-
-/* Maxbyte to 1144 (for raw data) */
-static u8 ITUFeatureDecoderSetup[8] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
-};
-
-void FillTSBuffer(void *Buffer, int Length, u32 Flags)
-{
- u32 *ptr = Buffer;
-
- memset(Buffer, TS_FILLER, Length);
- while (Length > 0) {
- if (Flags & DF_SWAP32)
- *ptr = 0x471FFF10;
- else
- *ptr = 0x10FF1F47;
- ptr += (188 / 4);
- Length -= 188;
- }
-}
-
-
-static void flush_buffers(struct ngene_channel *chan)
-{
- u8 val;
-
- do {
- msleep(1);
- spin_lock_irq(&chan->state_lock);
- val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
- spin_unlock_irq(&chan->state_lock);
- } while (val);
-}
-
-static void clear_buffers(struct ngene_channel *chan)
-{
- struct SBufferHeader *Cur = chan->nextBuffer;
-
- do {
- memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
- if (chan->mode & NGENE_IO_TSOUT)
- FillTSBuffer(Cur->Buffer1,
- chan->Capture1Length,
- chan->DataFormatFlags);
- Cur = Cur->Next;
- } while (Cur != chan->nextBuffer);
-
- if (chan->mode & NGENE_IO_TSOUT) {
- chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
- chan->AudioDTOValue;
- chan->AudioDTOUpdated = 0;
-
- Cur = chan->TSIdleBuffer.Head;
-
- do {
- memset(&Cur->ngeneBuffer.SR, 0,
- sizeof(Cur->ngeneBuffer.SR));
- FillTSBuffer(Cur->Buffer1,
- chan->Capture1Length,
- chan->DataFormatFlags);
- Cur = Cur->Next;
- } while (Cur != chan->TSIdleBuffer.Head);
- }
-}
-
-static int ngene_command_stream_control(struct ngene *dev, u8 stream,
- u8 control, u8 mode, u8 flags)
-{
- struct ngene_channel *chan = &dev->channel[stream];
- struct ngene_command com;
- u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
- u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
- u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
- u16 BsSDO = 0x9B00;
-
- down(&dev->stream_mutex);
- memset(&com, 0, sizeof(com));
- com.cmd.hdr.Opcode = CMD_CONTROL;
- com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
- com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
- if (chan->mode & NGENE_IO_TSOUT)
- com.cmd.StreamControl.Stream |= 0x07;
- com.cmd.StreamControl.Control = control |
- (flags & SFLAG_ORDER_LUMA_CHROMA);
- com.cmd.StreamControl.Mode = mode;
- com.in_len = sizeof(struct FW_STREAM_CONTROL);
- com.out_len = 0;
-
- dprintk(KERN_INFO DEVICE_NAME
- ": Stream=%02x, Control=%02x, Mode=%02x\n",
- com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
- com.cmd.StreamControl.Mode);
-
- chan->Mode = mode;
-
- if (!(control & 0x80)) {
- spin_lock_irq(&chan->state_lock);
- if (chan->State == KSSTATE_RUN) {
- chan->State = KSSTATE_ACQUIRE;
- chan->HWState = HWSTATE_STOP;
- spin_unlock_irq(&chan->state_lock);
- if (ngene_command(dev, &com) < 0) {
- up(&dev->stream_mutex);
- return -1;
- }
- /* clear_buffers(chan); */
- flush_buffers(chan);
- up(&dev->stream_mutex);
- return 0;
- }
- spin_unlock_irq(&chan->state_lock);
- up(&dev->stream_mutex);
- return 0;
- }
-
- if (mode & SMODE_AUDIO_CAPTURE) {
- com.cmd.StreamControl.CaptureBlockCount =
- chan->Capture1Length / AUDIO_BLOCK_SIZE;
- com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
- } else if (mode & SMODE_TRANSPORT_STREAM) {
- com.cmd.StreamControl.CaptureBlockCount =
- chan->Capture1Length / TS_BLOCK_SIZE;
- com.cmd.StreamControl.MaxLinesPerField =
- chan->Capture1Length / TS_BLOCK_SIZE;
- com.cmd.StreamControl.Buffer_Address =
- chan->TSRingBuffer.PAHead;
- if (chan->mode & NGENE_IO_TSOUT) {
- com.cmd.StreamControl.BytesPerVBILine =
- chan->Capture1Length / TS_BLOCK_SIZE;
- com.cmd.StreamControl.Stream |= 0x07;
- }
- } else {
- com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
- com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
- com.cmd.StreamControl.MinLinesPerField = 100;
- com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
-
- if (mode & SMODE_VBI_CAPTURE) {
- com.cmd.StreamControl.MaxVBILinesPerField =
- chan->nVBILines;
- com.cmd.StreamControl.MinVBILinesPerField = 0;
- com.cmd.StreamControl.BytesPerVBILine =
- chan->nBytesPerVBILine;
- }
- if (flags & SFLAG_COLORBAR)
- com.cmd.StreamControl.Stream |= 0x04;
- }
-
- spin_lock_irq(&chan->state_lock);
- if (mode & SMODE_AUDIO_CAPTURE) {
- chan->nextBuffer = chan->RingBuffer.Head;
- if (mode & SMODE_AUDIO_SPDIF) {
- com.cmd.StreamControl.SetupDataLen =
- sizeof(SPDIFConfiguration);
- com.cmd.StreamControl.SetupDataAddr = BsSPI;
- memcpy(com.cmd.StreamControl.SetupData,
- SPDIFConfiguration, sizeof(SPDIFConfiguration));
- } else {
- com.cmd.StreamControl.SetupDataLen = 4;
- com.cmd.StreamControl.SetupDataAddr = BsSDI;
- memcpy(com.cmd.StreamControl.SetupData,
- I2SConfiguration +
- 4 * dev->card_info->i2s[stream], 4);
- }
- } else if (mode & SMODE_TRANSPORT_STREAM) {
- chan->nextBuffer = chan->TSRingBuffer.Head;
- if (stream >= STREAM_AUDIOIN1) {
- if (chan->mode & NGENE_IO_TSOUT) {
- com.cmd.StreamControl.SetupDataLen =
- sizeof(TS_I2SOutConfiguration);
- com.cmd.StreamControl.SetupDataAddr = BsSDO;
- memcpy(com.cmd.StreamControl.SetupData,
- TS_I2SOutConfiguration,
- sizeof(TS_I2SOutConfiguration));
- } else {
- com.cmd.StreamControl.SetupDataLen =
- sizeof(TS_I2SConfiguration);
- com.cmd.StreamControl.SetupDataAddr = BsSDI;
- memcpy(com.cmd.StreamControl.SetupData,
- TS_I2SConfiguration,
- sizeof(TS_I2SConfiguration));
- }
- } else {
- com.cmd.StreamControl.SetupDataLen = 8;
- com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
- memcpy(com.cmd.StreamControl.SetupData,
- TSFeatureDecoderSetup +
- 8 * dev->card_info->tsf[stream], 8);
- }
- } else {
- chan->nextBuffer = chan->RingBuffer.Head;
- com.cmd.StreamControl.SetupDataLen =
- 16 + sizeof(ITUFeatureDecoderSetup);
- com.cmd.StreamControl.SetupDataAddr = BsUVI;
- memcpy(com.cmd.StreamControl.SetupData,
- ITUDecoderSetup[chan->itumode], 16);
- memcpy(com.cmd.StreamControl.SetupData + 16,
- ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
- }
- clear_buffers(chan);
- chan->State = KSSTATE_RUN;
- if (mode & SMODE_TRANSPORT_STREAM)
- chan->HWState = HWSTATE_RUN;
- else
- chan->HWState = HWSTATE_STARTUP;
- spin_unlock_irq(&chan->state_lock);
-
- if (ngene_command(dev, &com) < 0) {
- up(&dev->stream_mutex);
- return -1;
- }
- up(&dev->stream_mutex);
- return 0;
-}
-
-void set_transfer(struct ngene_channel *chan, int state)
-{
- u8 control = 0, mode = 0, flags = 0;
- struct ngene *dev = chan->dev;
- int ret;
-
- /*
- printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
- msleep(100);
- */
-
- if (state) {
- if (chan->running) {
- printk(KERN_INFO DEVICE_NAME ": already running\n");
- return;
- }
- } else {
- if (!chan->running) {
- printk(KERN_INFO DEVICE_NAME ": already stopped\n");
- return;
- }
- }
-
- if (dev->card_info->switch_ctrl)
- dev->card_info->switch_ctrl(chan, 1, state ^ 1);
-
- if (state) {
- spin_lock_irq(&chan->state_lock);
-
- /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
- ngreadl(0x9310)); */
- dvb_ringbuffer_flush(&dev->tsout_rbuf);
- control = 0x80;
- if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
- chan->Capture1Length = 512 * 188;
- mode = SMODE_TRANSPORT_STREAM;
- }
- if (chan->mode & NGENE_IO_TSOUT) {
- chan->pBufferExchange = tsout_exchange;
- /* 0x66666666 = 50MHz *2^33 /250MHz */
- chan->AudioDTOValue = 0x80000000;
- chan->AudioDTOUpdated = 1;
- }
- if (chan->mode & NGENE_IO_TSIN)
- chan->pBufferExchange = tsin_exchange;
- spin_unlock_irq(&chan->state_lock);
- } else
- ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
- ngreadl(0x9310)); */
-
- ret = ngene_command_stream_control(dev, chan->number,
- control, mode, flags);
- if (!ret)
- chan->running = state;
- else
- printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
- state);
- if (!state) {
- spin_lock_irq(&chan->state_lock);
- chan->pBufferExchange = NULL;
- dvb_ringbuffer_flush(&dev->tsout_rbuf);
- spin_unlock_irq(&chan->state_lock);
- }
-}
-
-
-/****************************************************************************/
-/* nGene hardware init and release functions ********************************/
-/****************************************************************************/
-
-static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
-{
- struct SBufferHeader *Cur = rb->Head;
- u32 j;
-
- if (!Cur)
- return;
-
- for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
- if (Cur->Buffer1)
- pci_free_consistent(dev->pci_dev,
- rb->Buffer1Length,
- Cur->Buffer1,
- Cur->scList1->Address);
-
- if (Cur->Buffer2)
- pci_free_consistent(dev->pci_dev,
- rb->Buffer2Length,
- Cur->Buffer2,
- Cur->scList2->Address);
- }
-
- if (rb->SCListMem)
- pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
- rb->SCListMem, rb->PASCListMem);
-
- pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
-}
-
-static void free_idlebuffer(struct ngene *dev,
- struct SRingBufferDescriptor *rb,
- struct SRingBufferDescriptor *tb)
-{
- int j;
- struct SBufferHeader *Cur = tb->Head;
-
- if (!rb->Head)
- return;
- free_ringbuffer(dev, rb);
- for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
- Cur->Buffer2 = NULL;
- Cur->scList2 = NULL;
- Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
- Cur->ngeneBuffer.Number_of_entries_2 = 0;
- }
-}
-
-static void free_common_buffers(struct ngene *dev)
-{
- u32 i;
- struct ngene_channel *chan;
-
- for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
- chan = &dev->channel[i];
- free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
- free_ringbuffer(dev, &chan->RingBuffer);
- free_ringbuffer(dev, &chan->TSRingBuffer);
- }
-
- if (dev->OverflowBuffer)
- pci_free_consistent(dev->pci_dev,
- OVERFLOW_BUFFER_SIZE,
- dev->OverflowBuffer, dev->PAOverflowBuffer);
-
- if (dev->FWInterfaceBuffer)
- pci_free_consistent(dev->pci_dev,
- 4096,
- dev->FWInterfaceBuffer,
- dev->PAFWInterfaceBuffer);
-}
-
-/****************************************************************************/
-/* Ring buffer handling *****************************************************/
-/****************************************************************************/
-
-static int create_ring_buffer(struct pci_dev *pci_dev,
- struct SRingBufferDescriptor *descr, u32 NumBuffers)
-{
- dma_addr_t tmp;
- struct SBufferHeader *Head;
- u32 i;
- u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
- u64 PARingBufferHead;
- u64 PARingBufferCur;
- u64 PARingBufferNext;
- struct SBufferHeader *Cur, *Next;
-
- descr->Head = NULL;
- descr->MemSize = 0;
- descr->PAHead = 0;
- descr->NumBuffers = 0;
-
- if (MemSize < 4096)
- MemSize = 4096;
-
- Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
- PARingBufferHead = tmp;
-
- if (!Head)
- return -ENOMEM;
-
- memset(Head, 0, MemSize);
-
- PARingBufferCur = PARingBufferHead;
- Cur = Head;
-
- for (i = 0; i < NumBuffers - 1; i++) {
- Next = (struct SBufferHeader *)
- (((u8 *) Cur) + SIZEOF_SBufferHeader);
- PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
- Cur->Next = Next;
- Cur->ngeneBuffer.Next = PARingBufferNext;
- Cur = Next;
- PARingBufferCur = PARingBufferNext;
- }
- /* Last Buffer points back to first one */
- Cur->Next = Head;
- Cur->ngeneBuffer.Next = PARingBufferHead;
-
- descr->Head = Head;
- descr->MemSize = MemSize;
- descr->PAHead = PARingBufferHead;
- descr->NumBuffers = NumBuffers;
-
- return 0;
-}
-
-static int AllocateRingBuffers(struct pci_dev *pci_dev,
- dma_addr_t of,
- struct SRingBufferDescriptor *pRingBuffer,
- u32 Buffer1Length, u32 Buffer2Length)
-{
- dma_addr_t tmp;
- u32 i, j;
- int status = 0;
- u32 SCListMemSize = pRingBuffer->NumBuffers
- * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
- NUM_SCATTER_GATHER_ENTRIES)
- * sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
- u64 PASCListMem;
- struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
- u64 PASCListEntry;
- struct SBufferHeader *Cur;
- void *SCListMem;
-
- if (SCListMemSize < 4096)
- SCListMemSize = 4096;
-
- SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
-
- PASCListMem = tmp;
- if (SCListMem == NULL)
- return -ENOMEM;
-
- memset(SCListMem, 0, SCListMemSize);
-
- pRingBuffer->SCListMem = SCListMem;
- pRingBuffer->PASCListMem = PASCListMem;
- pRingBuffer->SCListMemSize = SCListMemSize;
- pRingBuffer->Buffer1Length = Buffer1Length;
- pRingBuffer->Buffer2Length = Buffer2Length;
-
- SCListEntry = SCListMem;
- PASCListEntry = PASCListMem;
- Cur = pRingBuffer->Head;
-
- for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
- u64 PABuffer;
-
- void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
- &tmp);
- PABuffer = tmp;
-
- if (Buffer == NULL)
- return -ENOMEM;
-
- Cur->Buffer1 = Buffer;
-
- SCListEntry->Address = PABuffer;
- SCListEntry->Length = Buffer1Length;
-
- Cur->scList1 = SCListEntry;
- Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
- Cur->ngeneBuffer.Number_of_entries_1 =
- NUM_SCATTER_GATHER_ENTRIES;
-
- SCListEntry += 1;
- PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
-#if NUM_SCATTER_GATHER_ENTRIES > 1
- for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
- SCListEntry->Address = of;
- SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
- SCListEntry += 1;
- PASCListEntry +=
- sizeof(struct HW_SCATTER_GATHER_ELEMENT);
- }
-#endif
-
- if (!Buffer2Length)
- continue;
-
- Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
- PABuffer = tmp;
-
- if (Buffer == NULL)
- return -ENOMEM;
-
- Cur->Buffer2 = Buffer;
-
- SCListEntry->Address = PABuffer;
- SCListEntry->Length = Buffer2Length;
-
- Cur->scList2 = SCListEntry;
- Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
- Cur->ngeneBuffer.Number_of_entries_2 =
- NUM_SCATTER_GATHER_ENTRIES;
-
- SCListEntry += 1;
- PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
-
-#if NUM_SCATTER_GATHER_ENTRIES > 1
- for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
- SCListEntry->Address = of;
- SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
- SCListEntry += 1;
- PASCListEntry +=
- sizeof(struct HW_SCATTER_GATHER_ELEMENT);
- }
-#endif
-
- }
-
- return status;
-}
-
-static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
- struct SRingBufferDescriptor *pRingBuffer)
-{
- int status = 0;
-
- /* Copy pointer to scatter gather list in TSRingbuffer
- structure for buffer 2
- Load number of buffer
- */
- u32 n = pRingBuffer->NumBuffers;
-
- /* Point to first buffer entry */
- struct SBufferHeader *Cur = pRingBuffer->Head;
- int i;
- /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
- for (i = 0; i < n; i++) {
- Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
- Cur->scList2 = pIdleBuffer->Head->scList1;
- Cur->ngeneBuffer.Address_of_first_entry_2 =
- pIdleBuffer->Head->ngeneBuffer.
- Address_of_first_entry_1;
- Cur->ngeneBuffer.Number_of_entries_2 =
- pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
- Cur = Cur->Next;
- }
- return status;
-}
-
-static u32 RingBufferSizes[MAX_STREAM] = {
- RING_SIZE_VIDEO,
- RING_SIZE_VIDEO,
- RING_SIZE_AUDIO,
- RING_SIZE_AUDIO,
- RING_SIZE_AUDIO,
-};
-
-static u32 Buffer1Sizes[MAX_STREAM] = {
- MAX_VIDEO_BUFFER_SIZE,
- MAX_VIDEO_BUFFER_SIZE,
- MAX_AUDIO_BUFFER_SIZE,
- MAX_AUDIO_BUFFER_SIZE,
- MAX_AUDIO_BUFFER_SIZE
-};
-
-static u32 Buffer2Sizes[MAX_STREAM] = {
- MAX_VBI_BUFFER_SIZE,
- MAX_VBI_BUFFER_SIZE,
- 0,
- 0,
- 0
-};
-
-
-static int AllocCommonBuffers(struct ngene *dev)
-{
- int status = 0, i;
-
- dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
- &dev->PAFWInterfaceBuffer);
- if (!dev->FWInterfaceBuffer)
- return -ENOMEM;
- dev->hosttongene = dev->FWInterfaceBuffer;
- dev->ngenetohost = dev->FWInterfaceBuffer + 256;
- dev->EventBuffer = dev->FWInterfaceBuffer + 512;
-
- dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
- OVERFLOW_BUFFER_SIZE,
- &dev->PAOverflowBuffer);
- if (!dev->OverflowBuffer)
- return -ENOMEM;
- memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
-
- for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
- int type = dev->card_info->io_type[i];
-
- dev->channel[i].State = KSSTATE_STOP;
-
- if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
- status = create_ring_buffer(dev->pci_dev,
- &dev->channel[i].RingBuffer,
- RingBufferSizes[i]);
- if (status < 0)
- break;
-
- if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
- status = AllocateRingBuffers(dev->pci_dev,
- dev->
- PAOverflowBuffer,
- &dev->channel[i].
- RingBuffer,
- Buffer1Sizes[i],
- Buffer2Sizes[i]);
- if (status < 0)
- break;
- } else if (type & NGENE_IO_HDTV) {
- status = AllocateRingBuffers(dev->pci_dev,
- dev->
- PAOverflowBuffer,
- &dev->channel[i].
- RingBuffer,
- MAX_HDTV_BUFFER_SIZE,
- 0);
- if (status < 0)
- break;
- }
- }
-
- if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
-
- status = create_ring_buffer(dev->pci_dev,
- &dev->channel[i].
- TSRingBuffer, RING_SIZE_TS);
- if (status < 0)
- break;
-
- status = AllocateRingBuffers(dev->pci_dev,
- dev->PAOverflowBuffer,
- &dev->channel[i].
- TSRingBuffer,
- MAX_TS_BUFFER_SIZE, 0);
- if (status)
- break;
- }
-
- if (type & NGENE_IO_TSOUT) {
- status = create_ring_buffer(dev->pci_dev,
- &dev->channel[i].
- TSIdleBuffer, 1);
- if (status < 0)
- break;
- status = AllocateRingBuffers(dev->pci_dev,
- dev->PAOverflowBuffer,
- &dev->channel[i].
- TSIdleBuffer,
- MAX_TS_BUFFER_SIZE, 0);
- if (status)
- break;
- FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
- &dev->channel[i].TSRingBuffer);
- }
- }
- return status;
-}
-
-static void ngene_release_buffers(struct ngene *dev)
-{
- if (dev->iomem)
- iounmap(dev->iomem);
- free_common_buffers(dev);
- vfree(dev->tsout_buf);
- vfree(dev->tsin_buf);
- vfree(dev->ain_buf);
- vfree(dev->vin_buf);
- vfree(dev);
-}
-
-static int ngene_get_buffers(struct ngene *dev)
-{
- if (AllocCommonBuffers(dev))
- return -ENOMEM;
- if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
- dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
- if (!dev->tsout_buf)
- return -ENOMEM;
- dvb_ringbuffer_init(&dev->tsout_rbuf,
- dev->tsout_buf, TSOUT_BUF_SIZE);
- }
- if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
- dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
- if (!dev->tsin_buf)
- return -ENOMEM;
- dvb_ringbuffer_init(&dev->tsin_rbuf,
- dev->tsin_buf, TSIN_BUF_SIZE);
- }
- if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
- dev->ain_buf = vmalloc(AIN_BUF_SIZE);
- if (!dev->ain_buf)
- return -ENOMEM;
- dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
- }
- if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
- dev->vin_buf = vmalloc(VIN_BUF_SIZE);
- if (!dev->vin_buf)
- return -ENOMEM;
- dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
- }
- dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
- pci_resource_len(dev->pci_dev, 0));
- if (!dev->iomem)
- return -ENOMEM;
-
- return 0;
-}
-
-static void ngene_init(struct ngene *dev)
-{
- int i;
-
- tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
-
- memset_io(dev->iomem + 0xc000, 0x00, 0x220);
- memset_io(dev->iomem + 0xc400, 0x00, 0x100);
-
- for (i = 0; i < MAX_STREAM; i++) {
- dev->channel[i].dev = dev;
- dev->channel[i].number = i;
- }
-
- dev->fw_interface_version = 0;
-
- ngwritel(0, NGENE_INT_ENABLE);
-
- dev->icounts = ngreadl(NGENE_INT_COUNTS);
-
- dev->device_version = ngreadl(DEV_VER) & 0x0f;
- printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
- dev->device_version);
-}
-
-static int ngene_load_firm(struct ngene *dev)
-{
- u32 size;
- const struct firmware *fw = NULL;
- u8 *ngene_fw;
- char *fw_name;
- int err, version;
-
- version = dev->card_info->fw_version;
-
- switch (version) {
- default:
- case 15:
- version = 15;
- size = 23466;
- fw_name = "ngene_15.fw";
- dev->cmd_timeout_workaround = true;
- break;
- case 16:
- size = 23498;
- fw_name = "ngene_16.fw";
- dev->cmd_timeout_workaround = true;
- break;
- case 17:
- size = 24446;
- fw_name = "ngene_17.fw";
- dev->cmd_timeout_workaround = true;
- break;
- case 18:
- size = 0;
- fw_name = "ngene_18.fw";
- break;
- }
-
- if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
- printk(KERN_ERR DEVICE_NAME
- ": Could not load firmware file %s.\n", fw_name);
- printk(KERN_INFO DEVICE_NAME
- ": Copy %s to your hotplug directory!\n", fw_name);
- return -1;
- }
- if (size == 0)
- size = fw->size;
- if (size != fw->size) {
- printk(KERN_ERR DEVICE_NAME
- ": Firmware %s has invalid size!", fw_name);
- err = -1;
- } else {
- printk(KERN_INFO DEVICE_NAME
- ": Loading firmware file %s.\n", fw_name);
- ngene_fw = (u8 *) fw->data;
- err = ngene_command_load_firmware(dev, ngene_fw, size);
- }
-
- release_firmware(fw);
-
- return err;
-}
-
-static void ngene_stop(struct ngene *dev)
-{
- down(&dev->cmd_mutex);
- i2c_del_adapter(&(dev->channel[0].i2c_adapter));
- i2c_del_adapter(&(dev->channel[1].i2c_adapter));
- ngwritel(0, NGENE_INT_ENABLE);
- ngwritel(0, NGENE_COMMAND);
- ngwritel(0, NGENE_COMMAND_HI);
- ngwritel(0, NGENE_STATUS);
- ngwritel(0, NGENE_STATUS_HI);
- ngwritel(0, NGENE_EVENT);
- ngwritel(0, NGENE_EVENT_HI);
- free_irq(dev->pci_dev->irq, dev);
-#ifdef CONFIG_PCI_MSI
- if (dev->msi_enabled)
- pci_disable_msi(dev->pci_dev);
-#endif
-}
-
-static int ngene_buffer_config(struct ngene *dev)
-{
- int stat;
-
- if (dev->card_info->fw_version >= 17) {
- u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
- u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
- u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
- u8 *bconf = tsin12_config;
-
- if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
- dev->card_info->io_type[3]&NGENE_IO_TSIN) {
- bconf = tsin1234_config;
- if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
- dev->ci.en)
- bconf = tsio1235_config;
- }
- stat = ngene_command_config_free_buf(dev, bconf);
- } else {
- int bconf = BUFFER_CONFIG_4422;
-
- if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
- bconf = BUFFER_CONFIG_3333;
- stat = ngene_command_config_buf(dev, bconf);
- }
- return stat;
-}
-
-
-static int ngene_start(struct ngene *dev)
-{
- int stat;
- int i;
-
- pci_set_master(dev->pci_dev);
- ngene_init(dev);
-
- stat = request_irq(dev->pci_dev->irq, irq_handler,
- IRQF_SHARED, "nGene",
- (void *)dev);
- if (stat < 0)
- return stat;
-
- init_waitqueue_head(&dev->cmd_wq);
- init_waitqueue_head(&dev->tx_wq);
- init_waitqueue_head(&dev->rx_wq);
- sema_init(&dev->cmd_mutex, 1);
- sema_init(&dev->stream_mutex, 1);
- sema_init(&dev->pll_mutex, 1);
- sema_init(&dev->i2c_switch_mutex, 1);
- spin_lock_init(&dev->cmd_lock);
- for (i = 0; i < MAX_STREAM; i++)
- spin_lock_init(&dev->channel[i].state_lock);
- ngwritel(1, TIMESTAMPS);
-
- ngwritel(1, NGENE_INT_ENABLE);
-
- stat = ngene_load_firm(dev);
- if (stat < 0)
- goto fail;
-
-#ifdef CONFIG_PCI_MSI
- /* enable MSI if kernel and card support it */
- if (pci_msi_enabled() && dev->card_info->msi_supported) {
- unsigned long flags;
-
- ngwritel(0, NGENE_INT_ENABLE);
- free_irq(dev->pci_dev->irq, dev);
- stat = pci_enable_msi(dev->pci_dev);
- if (stat) {
- printk(KERN_INFO DEVICE_NAME
- ": MSI not available\n");
- flags = IRQF_SHARED;
- } else {
- flags = 0;
- dev->msi_enabled = true;
- }
- stat = request_irq(dev->pci_dev->irq, irq_handler,
- flags, "nGene", dev);
- if (stat < 0)
- goto fail2;
- ngwritel(1, NGENE_INT_ENABLE);
- }
-#endif
-
- stat = ngene_i2c_init(dev, 0);
- if (stat < 0)
- goto fail;
-
- stat = ngene_i2c_init(dev, 1);
- if (stat < 0)
- goto fail;
-
- return 0;
-
-fail:
- ngwritel(0, NGENE_INT_ENABLE);
- free_irq(dev->pci_dev->irq, dev);
-#ifdef CONFIG_PCI_MSI
-fail2:
- if (dev->msi_enabled)
- pci_disable_msi(dev->pci_dev);
-#endif
- return stat;
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static void release_channel(struct ngene_channel *chan)
-{
- struct dvb_demux *dvbdemux = &chan->demux;
- struct ngene *dev = chan->dev;
-
- if (chan->running)
- set_transfer(chan, 0);
-
- tasklet_kill(&chan->demux_tasklet);
-
- if (chan->ci_dev) {
- dvb_unregister_device(chan->ci_dev);
- chan->ci_dev = NULL;
- }
-
- if (chan->fe2)
- dvb_unregister_frontend(chan->fe2);
-
- if (chan->fe) {
- dvb_unregister_frontend(chan->fe);
- dvb_frontend_detach(chan->fe);
- chan->fe = NULL;
- }
-
- if (chan->has_demux) {
- dvb_net_release(&chan->dvbnet);
- dvbdemux->dmx.close(&dvbdemux->dmx);
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
- &chan->hw_frontend);
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
- &chan->mem_frontend);
- dvb_dmxdev_release(&chan->dmxdev);
- dvb_dmx_release(&chan->demux);
- chan->has_demux = false;
- }
-
- if (chan->has_adapter) {
- dvb_unregister_adapter(&dev->adapter[chan->number]);
- chan->has_adapter = false;
- }
-}
-
-static int init_channel(struct ngene_channel *chan)
-{
- int ret = 0, nr = chan->number;
- struct dvb_adapter *adapter = NULL;
- struct dvb_demux *dvbdemux = &chan->demux;
- struct ngene *dev = chan->dev;
- struct ngene_info *ni = dev->card_info;
- int io = ni->io_type[nr];
-
- tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
- chan->users = 0;
- chan->type = io;
- chan->mode = chan->type; /* for now only one mode */
-
- if (io & NGENE_IO_TSIN) {
- chan->fe = NULL;
- if (ni->demod_attach[nr]) {
- ret = ni->demod_attach[nr](chan);
- if (ret < 0)
- goto err;
- }
- if (chan->fe && ni->tuner_attach[nr]) {
- ret = ni->tuner_attach[nr](chan);
- if (ret < 0)
- goto err;
- }
- }
-
- if (!dev->ci.en && (io & NGENE_IO_TSOUT))
- return 0;
-
- if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
- if (nr >= STREAM_AUDIOIN1)
- chan->DataFormatFlags = DF_SWAP32;
-
- if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
- adapter = &dev->adapter[nr];
- ret = dvb_register_adapter(adapter, "nGene",
- THIS_MODULE,
- &chan->dev->pci_dev->dev,
- adapter_nr);
- if (ret < 0)
- goto err;
- if (dev->first_adapter == NULL)
- dev->first_adapter = adapter;
- chan->has_adapter = true;
- } else
- adapter = dev->first_adapter;
- }
-
- if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
- dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
- set_transfer(chan, 1);
- chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
- set_transfer(&chan->dev->channel[2], 1);
- dvb_register_device(adapter, &chan->ci_dev,
- &ngene_dvbdev_ci, (void *) chan,
- DVB_DEVICE_SEC);
- if (!chan->ci_dev)
- goto err;
- }
-
- if (chan->fe) {
- if (dvb_register_frontend(adapter, chan->fe) < 0)
- goto err;
- chan->has_demux = true;
- }
- if (chan->fe2) {
- if (dvb_register_frontend(adapter, chan->fe2) < 0)
- goto err;
- chan->fe2->tuner_priv = chan->fe->tuner_priv;
- memcpy(&chan->fe2->ops.tuner_ops,
- &chan->fe->ops.tuner_ops,
- sizeof(struct dvb_tuner_ops));
- }
-
- if (chan->has_demux) {
- ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
- ngene_start_feed,
- ngene_stop_feed, chan);
- ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
- &chan->hw_frontend,
- &chan->mem_frontend, adapter);
- ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
- }
-
- return ret;
-
-err:
- if (chan->fe) {
- dvb_frontend_detach(chan->fe);
- chan->fe = NULL;
- }
- release_channel(chan);
- return 0;
-}
-
-static int init_channels(struct ngene *dev)
-{
- int i, j;
-
- for (i = 0; i < MAX_STREAM; i++) {
- dev->channel[i].number = i;
- if (init_channel(&dev->channel[i]) < 0) {
- for (j = i - 1; j >= 0; j--)
- release_channel(&dev->channel[j]);
- return -1;
- }
- }
- return 0;
-}
-
-static struct cxd2099_cfg cxd_cfg = {
- .bitrate = 62000,
- .adr = 0x40,
- .polarity = 0,
- .clock_mode = 0,
-};
-
-static void cxd_attach(struct ngene *dev)
-{
- struct ngene_ci *ci = &dev->ci;
-
- ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
- ci->dev = dev;
- return;
-}
-
-static void cxd_detach(struct ngene *dev)
-{
- struct ngene_ci *ci = &dev->ci;
-
- dvb_ca_en50221_release(ci->en);
- kfree(ci->en);
- ci->en = 0;
-}
-
-/***********************************/
-/* workaround for shutdown failure */
-/***********************************/
-
-static void ngene_unlink(struct ngene *dev)
-{
- struct ngene_command com;
-
- com.cmd.hdr.Opcode = CMD_MEM_WRITE;
- com.cmd.hdr.Length = 3;
- com.cmd.MemoryWrite.address = 0x910c;
- com.cmd.MemoryWrite.data = 0xff;
- com.in_len = 3;
- com.out_len = 1;
-
- down(&dev->cmd_mutex);
- ngwritel(0, NGENE_INT_ENABLE);
- ngene_command_mutex(dev, &com);
- up(&dev->cmd_mutex);
-}
-
-void ngene_shutdown(struct pci_dev *pdev)
-{
- struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
-
- if (!dev || !shutdown_workaround)
- return;
-
- printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
- ngene_unlink(dev);
- pci_disable_device(pdev);
-}
-
-/****************************************************************************/
-/* device probe/remove calls ************************************************/
-/****************************************************************************/
-
-void __devexit ngene_remove(struct pci_dev *pdev)
-{
- struct ngene *dev = pci_get_drvdata(pdev);
- int i;
-
- tasklet_kill(&dev->event_tasklet);
- for (i = MAX_STREAM - 1; i >= 0; i--)
- release_channel(&dev->channel[i]);
- if (dev->ci.en)
- cxd_detach(dev);
- ngene_stop(dev);
- ngene_release_buffers(dev);
- pci_set_drvdata(pdev, NULL);
- pci_disable_device(pdev);
-}
-
-int __devinit ngene_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *id)
-{
- struct ngene *dev;
- int stat = 0;
-
- if (pci_enable_device(pci_dev) < 0)
- return -ENODEV;
-
- dev = vzalloc(sizeof(struct ngene));
- if (dev == NULL) {
- stat = -ENOMEM;
- goto fail0;
- }
-
- dev->pci_dev = pci_dev;
- dev->card_info = (struct ngene_info *)id->driver_data;
- printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
-
- pci_set_drvdata(pci_dev, dev);
-
- /* Alloc buffers and start nGene */
- stat = ngene_get_buffers(dev);
- if (stat < 0)
- goto fail1;
- stat = ngene_start(dev);
- if (stat < 0)
- goto fail1;
-
- cxd_attach(dev);
-
- stat = ngene_buffer_config(dev);
- if (stat < 0)
- goto fail1;
-
-
- dev->i2c_current_bus = -1;
-
- /* Register DVB adapters and devices for both channels */
- if (init_channels(dev) < 0)
- goto fail2;
-
- return 0;
-
-fail2:
- ngene_stop(dev);
-fail1:
- ngene_release_buffers(dev);
-fail0:
- pci_disable_device(pci_dev);
- pci_set_drvdata(pci_dev, NULL);
- return stat;
-}
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
deleted file mode 100644
index 700822350ec5..000000000000
--- a/drivers/media/dvb/pluto2/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile
deleted file mode 100644
index d80d8e8e7c57..000000000000
--- a/drivers/media/dvb/pt1/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
-
-obj-$(CONFIG_DVB_PT1) += earth-pt1.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
deleted file mode 100644
index bc6456eb2c4f..000000000000
--- a/drivers/media/dvb/siano/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Siano Mobile Silicon Digital TV device configuration
-#
-
-config SMS_SIANO_MDTV
- tristate "Siano SMS1xxx based MDTV receiver"
- depends on DVB_CORE && RC_CORE && HAS_DMA
- ---help---
- Choose Y or M here if you have MDTV receiver with a Siano chipset.
-
- To compile this driver as a module, choose M here
- (The module will be called smsmdtv).
-
- Further documentation on this driver can be found on the WWW
- at http://www.siano-ms.com/
-
-if SMS_SIANO_MDTV
-menu "Siano module components"
-
-# Hardware interfaces support
-
-config SMS_USB_DRV
- tristate "USB interface support"
- depends on DVB_CORE && USB
- ---help---
- Choose if you would like to have Siano's support for USB interface
-
-config SMS_SDIO_DRV
- tristate "SDIO interface support"
- depends on DVB_CORE && MMC
- ---help---
- Choose if you would like to have Siano's support for SDIO interface
-endmenu
-endif # SMS_SIANO_MDTV
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
deleted file mode 100644
index f233b57c86fb..000000000000
--- a/drivers/media/dvb/siano/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-
-smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
-
-obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
-obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
-obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
-
-ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
-
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
deleted file mode 100644
index 9d83ced69dd6..000000000000
--- a/drivers/media/dvb/ttpci/Kconfig
+++ /dev/null
@@ -1,159 +0,0 @@
-config TTPCI_EEPROM
- tristate
- depends on I2C
- default n
-
-config DVB_AV7110
- tristate "AV7110 cards"
- depends on DVB_CORE && PCI && I2C
- select TTPCI_EEPROM
- select VIDEO_SAA7146_VV
- depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
- select DVB_VES1820 if !DVB_FE_CUSTOMISE
- select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- select DVB_SP8870 if !DVB_FE_CUSTOMISE
- select DVB_STV0297 if !DVB_FE_CUSTOMISE
- select DVB_L64781 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- help
- Support for SAA7146 and AV7110 based DVB cards as produced
- by Fujitsu-Siemens, Technotrend, Hauppauge and others.
-
- This driver only supports the fullfeatured cards with
- onboard MPEG2 decoder.
-
- This driver needs an external firmware. Please use the script
- "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
- Alternatively, you can download the file and use the kernel's
- EXTRA_FIRMWARE configuration option to build it into your
- kernel image by adding the filename to the EXTRA_FIRMWARE
- configuration option string.
-
- Say Y if you own such a card and want to use it.
-
-config DVB_AV7110_OSD
- bool "AV7110 OSD support"
- depends on DVB_AV7110
- default y if DVB_AV7110=y || DVB_AV7110=m
- help
- The AV7110 firmware provides some code to generate an OnScreenDisplay
- on the video output. This is kind of nonstandard and not guaranteed to
- be maintained.
-
- Anyway, some popular DVB software like VDR uses this OSD to render
- its menus, so say Y if you want to use this software.
-
- All other people say N.
-
-config DVB_BUDGET_CORE
- tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
- depends on DVB_CORE && PCI && I2C
- select VIDEO_SAA7146
- select TTPCI_EEPROM
- help
- Support for simple SAA7146 based DVB cards
- (so called Budget- or Nova-PCI cards) without onboard
- MPEG2 decoder.
-
-config DVB_BUDGET
- tristate "Budget cards"
- depends on DVB_BUDGET_CORE && I2C
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- select DVB_VES1820 if !DVB_FE_CUSTOMISE
- select DVB_L64781 if !DVB_FE_CUSTOMISE
- select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- select DVB_S5H1420 if !DVB_FE_CUSTOMISE
- select DVB_TDA10086 if !DVB_FE_CUSTOMISE
- select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select DVB_ISL6423 if !DVB_FE_CUSTOMISE
- select DVB_STV090x if !DVB_FE_CUSTOMISE
- select DVB_STV6110x if !DVB_FE_CUSTOMISE
- help
- Support for simple SAA7146 based DVB cards (so called Budget-
- or Nova-PCI cards) without onboard MPEG2 decoder, and without
- analog inputs or an onboard Common Interface connector.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget.
-
-config DVB_BUDGET_CI
- tristate "Budget cards with onboard CI connector"
- depends on DVB_BUDGET_CORE && I2C
- select DVB_STV0297 if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select DVB_STB0899 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_STV0288 if !DVB_FE_CUSTOMISE
- select DVB_STB6000 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
- depends on RC_CORE
- help
- Support for simple SAA7146 based DVB cards
- (so called Budget- or Nova-PCI cards) without onboard
- MPEG2 decoder, but with onboard Common Interface connector.
-
- Note: The Common Interface is not yet supported by this driver
- due to lack of information from the vendor.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget-ci.
-
-config DVB_BUDGET_AV
- tristate "Budget cards with analog video inputs"
- depends on DVB_BUDGET_CORE && I2C
- select VIDEO_SAA7146_VV
- depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select DVB_STB0899 if !DVB_FE_CUSTOMISE
- select DVB_TDA8261 if !DVB_FE_CUSTOMISE
- select DVB_TUA6100 if !DVB_FE_CUSTOMISE
- help
- Support for simple SAA7146 based DVB cards
- (so called Budget- or Nova-PCI cards) without onboard
- MPEG2 decoder, but with one or more analog video inputs.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget-av.
-
-config DVB_BUDGET_PATCH
- tristate "AV7110 cards with Budget Patch"
- depends on DVB_BUDGET_CORE && I2C
- depends on DVB_AV7110
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- help
- Support for Budget Patch (full TS) modification on
- SAA7146+AV7110 based cards (DVB-S cards). This
- driver doesn't use onboard MPEG2 decoder. The
- card is driven in Budget-only mode. Card is
- required to have loaded firmware to tune properly.
- Firmware can be loaded by insertion and removal of
- standard AV7110 driver prior to loading this
- driver.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget-patch.
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
deleted file mode 100644
index f6e869372e30..000000000000
--- a/drivers/media/dvb/ttpci/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Makefile for the kernel SAA7146 FULL TS DVB device driver
-# and the AV7110 DVB device driver
-#
-
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
-
-ifdef CONFIG_INPUT_EVDEV
-dvb-ttpci-objs += av7110_ir.o
-endif
-
-obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
-obj-$(CONFIG_DVB_BUDGET) += budget.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
deleted file mode 100644
index b21bcce66708..000000000000
--- a/drivers/media/dvb/ttpci/budget.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * budget.c: driver for the SAA7146 based Budget DVB cards
- *
- * Compiled from various sources by Michael Hunold <michael@mihu.de>
- *
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * Copyright (C) 1999-2002 Ralph Metzler
- * & Marcus Metzler for convergence integrated media GmbH
- *
- * 26feb2004 Support for FS Activy Card (Grundig tuner) by
- * Michael Dreher <michael@5dot1.de>,
- * Oliver Endriss <o.endriss@gmx.de> and
- * Andreas 'randy' Weinberger
- *
- * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- *
- * the project's page is at http://www.linuxtv.org/
- */
-
-#include "budget.h"
-#include "stv0299.h"
-#include "ves1x93.h"
-#include "ves1820.h"
-#include "l64781.h"
-#include "tda8083.h"
-#include "s5h1420.h"
-#include "tda10086.h"
-#include "tda826x.h"
-#include "lnbp21.h"
-#include "bsru6.h"
-#include "bsbe1.h"
-#include "tdhd1.h"
-#include "stv6110x.h"
-#include "stv090x.h"
-#include "isl6423.h"
-
-static int diseqc_method;
-module_param(diseqc_method, int, 0444);
-MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static void Set22K (struct budget *budget, int state)
-{
- struct saa7146_dev *dev=budget->dev;
- dprintk(2, "budget: %p\n", budget);
- saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
-}
-
-/* Diseqc functions only for TT Budget card */
-/* taken from the Skyvision DVB driver by
- Ralph Metzler <rjkm@metzlerbros.de> */
-
-static void DiseqcSendBit (struct budget *budget, int data)
-{
- struct saa7146_dev *dev=budget->dev;
- dprintk(2, "budget: %p\n", budget);
-
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(data ? 500 : 1000);
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- udelay(data ? 1000 : 500);
-}
-
-static void DiseqcSendByte (struct budget *budget, int data)
-{
- int i, par=1, d;
-
- dprintk(2, "budget: %p\n", budget);
-
- for (i=7; i>=0; i--) {
- d = (data>>i)&1;
- par ^= d;
- DiseqcSendBit(budget, d);
- }
-
- DiseqcSendBit(budget, par);
-}
-
-static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
-{
- struct saa7146_dev *dev=budget->dev;
- int i;
-
- dprintk(2, "budget: %p\n", budget);
-
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- mdelay(16);
-
- for (i=0; i<len; i++)
- DiseqcSendByte(budget, msg[i]);
-
- mdelay(16);
-
- if (burst!=-1) {
- if (burst)
- DiseqcSendByte(budget, 0xff);
- else {
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- mdelay(12);
- udelay(500);
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- }
- msleep(20);
- }
-
- return 0;
-}
-
-/*
- * Routines for the Fujitsu Siemens Activy budget card
- * 22 kHz tone and DiSEqC are handled by the frontend.
- * Voltage must be set here.
- * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
- */
-static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
-{
- struct saa7146_dev *dev=budget->dev;
-
- dprintk(2, "budget: %p\n", budget);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
- saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
- break;
- case SEC_VOLTAGE_18:
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
- saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
- break;
- case SEC_VOLTAGE_OFF:
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- return SetVoltage_Activy (budget, voltage);
-}
-
-static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- switch (tone) {
- case SEC_TONE_ON:
- Set22K (budget, 1);
- break;
-
- case SEC_TONE_OFF:
- Set22K (budget, 0);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-
- return 0;
-}
-
-static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- SendDiSEqCMsg (budget, 0, NULL, minicmd);
-
- return 0;
-}
-
-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 = (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;
- buf[1] = div & 0xff;
- buf[2] = ((div & 0x18000) >> 10) | 0x95;
- buf[3] = (pwr << 6) | 0x30;
-
- // NOTE: since we're using a prescaler of 2, we set the
- // divisor frequency to 62.5kHz and divide by 125 above
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct ves1x93_config alps_bsrv2_config =
-{
- .demod_address = 0x08,
- .xin = 90100000UL,
- .invert_pwm = 0,
-};
-
-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 = (c->frequency + 35937500 + 31250) / 62500;
-
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x85 | ((div >> 10) & 0x60);
- data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct ves1820_config alps_tdbe2_config = {
- .demod_address = 0x09,
- .xin = 57840000UL,
- .invert = 1,
- .selagc = VES1820_SELAGC_SIGNAMPERR,
-};
-
-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;
- u8 cfg, cpump, band_select;
- u8 data[4];
- struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };
-
- if (tuner_addr)
- msg.addr = *tuner_addr;
- else
- msg.addr = 0x61;
-
- div = (36125000 + c->frequency) / 166666;
-
- cfg = 0x88;
-
- 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 (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;
- data[2] = ((div >> 10) & 0x60) | cfg;
- data[3] = (cpump << 6) | band_select;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct l64781_config grundig_29504_401_config = {
- .demod_address = 0x55,
-};
-
-static struct l64781_config grundig_29504_401_config_activy = {
- .demod_address = 0x54,
-};
-
-static u8 tuner_address_grundig_29504_401_activy = 0x60;
-
-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 = c->frequency / 125;
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x8e;
- data[3] = 0x00;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct tda8083_config grundig_29504_451_config = {
- .demod_address = 0x68,
-};
-
-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 = c->frequency / 1000;
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0xc2;
-
- if (div < 1450)
- data[3] = 0x00;
- else if (div < 1850)
- data[3] = 0x40;
- else if (div < 2000)
- data[3] = 0x80;
- else
- data[3] = 0xc0;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
- return 0;
-}
-
-static struct s5h1420_config s5h1420_config = {
- .demod_address = 0x53,
- .invert = 1,
- .cdclk_polarity = 1,
-};
-
-static struct tda10086_config tda10086_config = {
- .demod_address = 0x0e,
- .invert = 0,
- .diseqc_tone = 1,
- .xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct stv0299_config alps_bsru6_config_activy = {
- .demod_address = 0x68,
- .inittab = alps_bsru6_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .op0_off = 1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
-};
-
-static struct stv0299_config alps_bsbe1_config_activy = {
- .demod_address = 0x68,
- .inittab = alps_bsbe1_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .op0_off = 1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsbe1_set_symbol_rate,
-};
-
-static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
-{
- struct budget *budget = (struct budget *)fe->dvb->priv;
-
- return request_firmware(fw, name, &budget->dev->pci->dev);
-}
-
-
-static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
-{
- u8 val;
- struct i2c_msg msg[] = {
- { .addr = adr, .flags = 0, .buf = &reg, .len = 1 },
- { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
- };
-
- return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;
-}
-
-static u8 read_pwm(struct budget* budget)
-{
- u8 b = 0xff;
- u8 pwm;
- struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
- { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
-
- if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
- pwm = 0x48;
-
- return pwm;
-}
-
-static struct stv090x_config tt1600_stv090x_config = {
- .device = STV0903,
- .demod_mode = STV090x_SINGLE,
- .clk_mode = STV090x_CLK_EXT,
-
- .xtal = 13500000,
- .address = 0x68,
-
- .ts1_mode = STV090x_TSMODE_DVBCI,
- .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
-
- .repeater_level = STV090x_RPTLEVEL_16,
-
- .tuner_init = NULL,
- .tuner_sleep = NULL,
- .tuner_set_mode = NULL,
- .tuner_set_frequency = NULL,
- .tuner_get_frequency = NULL,
- .tuner_set_bandwidth = NULL,
- .tuner_get_bandwidth = NULL,
- .tuner_set_bbgain = NULL,
- .tuner_get_bbgain = NULL,
- .tuner_set_refclk = NULL,
- .tuner_get_status = NULL,
-};
-
-static struct stv6110x_config tt1600_stv6110x_config = {
- .addr = 0x60,
- .refclk = 27000000,
- .clk_div = 2,
-};
-
-static struct isl6423_config tt1600_isl6423_config = {
- .current_max = SEC_CURRENT_515m,
- .curlim = SEC_CURRENT_LIM_ON,
- .mod_extern = 1,
- .addr = 0x08,
-};
-
-static void frontend_init(struct budget *budget)
-{
- (void)alps_bsbe1_config; /* avoid warning */
-
- switch(budget->dev->pci->subsystem_device) {
- case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
- case 0x1013:
- // try the ALPS BSRV2 first of all
- budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_set_tone;
- break;
- }
-
- // try the ALPS BSRU6 now
- budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
- budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
- if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_set_tone;
- }
- break;
- }
- break;
-
- case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
-
- budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
- break;
- }
- break;
-
- case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
-
- budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
- budget->dvb_frontend->tuner_priv = NULL;
- break;
- }
- break;
-
- case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
- {
- int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
-
- if (subtype < 0)
- break;
- /* fixme: find a better way to identify the card */
- if (subtype < 0x36) {
- /* assume ALPS BSRU6 */
- budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
- budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
- budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
- break;
- }
- } else {
- /* assume ALPS BSBE1 */
- /* reset tuner */
- saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);
- msleep(50);
- saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);
- msleep(250);
- budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
- budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
- budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
- break;
- }
- }
- break;
- }
-
- case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
- budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
- budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
- }
- break;
-
- case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
- budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
- budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
- }
- break;
-
- case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
- budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;
- budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
- }
- break;
-
- case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
- budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
- if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
- printk("%s: No LNBP21 found!\n", __func__);
- goto error_out;
- }
- break;
- }
-
- case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
- // gpio2 is connected to CLB - reset it + leave it high
- saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
- msleep(1);
- saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
- msleep(1);
-
- budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
- printk("%s: No tda826x found!\n", __func__);
- if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
- printk("%s: No LNBP21 found!\n", __func__);
- goto error_out;
- }
- break;
- }
-
- case 0x101c: { /* TT S2-1600 */
- struct stv6110x_devctl *ctl;
- saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
- msleep(50);
- saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
- msleep(250);
-
- budget->dvb_frontend = dvb_attach(stv090x_attach,
- &tt1600_stv090x_config,
- &budget->i2c_adap,
- STV090x_DEMODULATOR_0);
-
- if (budget->dvb_frontend) {
-
- ctl = dvb_attach(stv6110x_attach,
- budget->dvb_frontend,
- &tt1600_stv6110x_config,
- &budget->i2c_adap);
-
- if (ctl) {
- tt1600_stv090x_config.tuner_init = ctl->tuner_init;
- tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep;
- tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
- tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
- tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
- tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
- tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
- tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
- tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
- tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
- tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status;
-
- /* call the init function once to initialize
- tuner's clock output divider and demod's
- master clock */
- if (budget->dvb_frontend->ops.init)
- budget->dvb_frontend->ops.init(budget->dvb_frontend);
-
- if (dvb_attach(isl6423_attach,
- budget->dvb_frontend,
- &budget->i2c_adap,
- &tt1600_isl6423_config) == NULL) {
- printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);
- goto error_out;
- }
- } else {
- printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
- goto error_out;
- }
- }
- }
- break;
- }
-
- if (budget->dvb_frontend == NULL) {
- printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
- budget->dev->pci->vendor,
- budget->dev->pci->device,
- budget->dev->pci->subsystem_vendor,
- budget->dev->pci->subsystem_device);
- } else {
- if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
- goto error_out;
- }
- return;
-
-error_out:
- printk("budget: Frontend registration failed!\n");
- dvb_frontend_detach(budget->dvb_frontend);
- budget->dvb_frontend = NULL;
- return;
-}
-
-static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
- struct budget *budget = NULL;
- int err;
-
- budget = kmalloc(sizeof(struct budget), GFP_KERNEL);
- if( NULL == budget ) {
- return -ENOMEM;
- }
-
- dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
-
- dev->ext_priv = budget;
-
- err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
- if (err) {
- printk("==> failed\n");
- kfree (budget);
- return err;
- }
-
- budget->dvb_adapter.priv = budget;
- frontend_init(budget);
-
- ttpci_budget_init_hooks(budget);
-
- return 0;
-}
-
-static int budget_detach (struct saa7146_dev* dev)
-{
- struct budget *budget = (struct budget*) dev->ext_priv;
- int err;
-
- if (budget->dvb_frontend) {
- dvb_unregister_frontend(budget->dvb_frontend);
- dvb_frontend_detach(budget->dvb_frontend);
- }
-
- err = ttpci_budget_deinit (budget);
-
- kfree (budget);
- dev->ext_priv = NULL;
-
- return err;
-}
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
-MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
-MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
-
-static struct pci_device_id pci_tbl[] = {
- MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
- MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
- MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
- MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
- MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
- MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
- MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
- MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
- MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
- MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
- MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
- {
- .vendor = 0,
- }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_extension budget_extension = {
- .name = "budget dvb",
- .flags = SAA7146_USE_I2C_IRQ,
-
- .module = THIS_MODULE,
- .pci_tbl = pci_tbl,
- .attach = budget_attach,
- .detach = budget_detach,
-
- .irq_mask = MASK_10,
- .irq_func = ttpci_budget_irq10_handler,
-};
-
-static int __init budget_init(void)
-{
- return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_exit(void)
-{
- saa7146_unregister_extension(&budget_extension);
-}
-
-module_init(budget_init);
-module_exit(budget_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
-MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
- "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
deleted file mode 100644
index 2663ae39b886..000000000000
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config DVB_TTUSB_BUDGET
- tristate "Technotrend/Hauppauge Nova-USB devices"
- depends on DVB_CORE && USB && I2C && PCI
- select DVB_CX22700 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select DVB_VES1820 if !DVB_FE_CUSTOMISE
- select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_STV0297 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- help
- Support for external USB adapters designed by Technotrend and
- produced by Hauppauge, shipped under the brand name 'Nova-USB'.
-
- These devices don't have a MPEG decoder built in, so you need
- an external software decoder to watch TV.
-
- Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
deleted file mode 100644
index 8d6c4acb7f1d..000000000000
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
deleted file mode 100644
index ed28b5384d20..000000000000
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/firewire/Kconfig
index f3e9448c3955..f3e9448c3955 100644
--- a/drivers/media/dvb/firewire/Kconfig
+++ b/drivers/media/firewire/Kconfig
diff --git a/drivers/media/firewire/Makefile b/drivers/media/firewire/Makefile
new file mode 100644
index 000000000000..239481344d7c
--- /dev/null
+++ b/drivers/media/firewire/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
+
+firedtv-y += firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
+firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
+
+ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c
index d1a1a1324ef8..d1a1a1324ef8 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/firewire/firedtv-avc.c
diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c
index e5ebdbfe8c19..e5ebdbfe8c19 100644
--- a/drivers/media/dvb/firewire/firedtv-ci.c
+++ b/drivers/media/firewire/firedtv-ci.c
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/firewire/firedtv-dvb.c
index eb7496eab130..eb7496eab130 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/firewire/firedtv-dvb.c
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/firewire/firedtv-fe.c
index 6fe9793b98b3..6fe9793b98b3 100644
--- a/drivers/media/dvb/firewire/firedtv-fe.c
+++ b/drivers/media/firewire/firedtv-fe.c
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/firewire/firedtv-fw.c
index e24ec539a5fd..e24ec539a5fd 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/firewire/firedtv-fw.c
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/firewire/firedtv-rc.c
index f82d4a93feb3..f82d4a93feb3 100644
--- a/drivers/media/dvb/firewire/firedtv-rc.c
+++ b/drivers/media/firewire/firedtv-rc.c
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/firewire/firedtv.h
index 4fdcd8cb7530..4fdcd8cb7530 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/firewire/firedtv.h
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
new file mode 100644
index 000000000000..9a5a059c1bde
--- /dev/null
+++ b/drivers/media/i2c/Kconfig
@@ -0,0 +1,561 @@
+#
+# Generic video config states
+#
+
+config VIDEO_BTCX
+ depends on PCI
+ tristate
+
+config VIDEO_TVEEPROM
+ tristate
+ depends on I2C
+
+#
+# Multimedia Video device configuration
+#
+
+if VIDEO_V4L2
+
+config VIDEO_IR_I2C
+ tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT
+ depends on I2C && RC_CORE
+ default y
+ ---help---
+ Most boards have an IR chip directly connected via GPIO. However,
+ some video boards have the IR connected via I2C bus.
+
+ If your board doesn't have an I2C IR chip, you may disable this
+ option.
+
+ In doubt, say Y.
+
+#
+# Encoder / Decoder module configuration
+#
+
+menu "Encoders, decoders, sensors and other helper chips"
+ visible if !MEDIA_SUBDRV_AUTOSELECT
+
+comment "Audio decoders, processors and mixers"
+
+config VIDEO_TVAUDIO
+ tristate "Simple audio decoder chips"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for several audio decoder chips found on some bt8xx boards:
+ Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
+ tea6320, tea6420, tda8425, ta8874z.
+ Microchip: pic16c54 based design on ProVideo PV951 board.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvaudio.
+
+config VIDEO_TDA7432
+ tristate "Philips TDA7432 audio processor"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for tda7432 audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda7432.
+
+config VIDEO_TDA9840
+ tristate "Philips TDA9840 audio processor"
+ depends on I2C
+ ---help---
+ Support for tda9840 audio decoder chip found on some Zoran boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda9840.
+
+config VIDEO_TEA6415C
+ tristate "Philips TEA6415C audio processor"
+ depends on I2C
+ ---help---
+ Support for tea6415c audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tea6415c.
+
+config VIDEO_TEA6420
+ tristate "Philips TEA6420 audio processor"
+ depends on I2C
+ ---help---
+ Support for tea6420 audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tea6420.
+
+config VIDEO_MSP3400
+ tristate "Micronas MSP34xx audio decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Micronas MSP34xx series of audio decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called msp3400.
+
+config VIDEO_CS5345
+ tristate "Cirrus Logic CS5345 audio ADC"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Cirrus Logic CS5345 24-bit, 192 kHz
+ stereo A/D converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs5345.
+
+config VIDEO_CS53L32A
+ tristate "Cirrus Logic CS53L32A audio ADC"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Cirrus Logic CS53L32A low voltage
+ stereo A/D converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs53l32a.
+
+config VIDEO_TLV320AIC23B
+ tristate "Texas Instruments TLV320AIC23B audio codec"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Texas Instruments TLV320AIC23B audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tlv320aic23b.
+
+config VIDEO_WM8775
+ tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Wolfson Microelectronics WM8775 high
+ performance stereo A/D Converter with a 4 channel input mixer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm8775.
+
+config VIDEO_WM8739
+ tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Wolfson Microelectronics WM8739
+ stereo A/D Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm8739.
+
+config VIDEO_VP27SMPX
+ tristate "Panasonic VP27s internal MPX"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the internal MPX of the Panasonic VP27s tuner.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vp27smpx.
+
+comment "RDS decoders"
+
+config VIDEO_SAA6588
+ tristate "SAA6588 Radio Chip RDS decoder support"
+ depends on VIDEO_V4L2 && I2C
+
+ help
+ Support for this Radio Data System (RDS) decoder. This allows
+ seeing radio station identification transmitted using this
+ standard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa6588.
+
+comment "Video decoders"
+
+config VIDEO_ADV7180
+ tristate "Analog Devices ADV7180 decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Analog Devices ADV7180 video decoder.
+
+ 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
+ ---help---
+ Support for BT819A video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt819.
+
+config VIDEO_BT856
+ tristate "BT856 VideoStream decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for BT856 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt856.
+
+config VIDEO_BT866
+ tristate "BT866 VideoStream decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for BT866 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt866.
+
+config VIDEO_KS0127
+ tristate "KS0127 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for KS0127 video decoder.
+
+ This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ks0127.
+
+config VIDEO_SAA7110
+ tristate "Philips SAA7110 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7110 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7110.
+
+config VIDEO_SAA711X
+ tristate "Philips SAA7111/3/4/5 video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7111/3/4/5 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7115.
+
+config VIDEO_SAA7191
+ tristate "Philips SAA7191 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7191 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7191.
+
+config VIDEO_TVP514X
+ tristate "Texas Instruments TVP514x video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
+ decoder. It is currently working with the TI OMAP3 camera
+ controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp514x.
+
+config VIDEO_TVP5150
+ tristate "Texas Instruments TVP5150 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Texas Instruments TVP5150 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp5150.
+
+config VIDEO_TVP7002
+ tristate "Texas Instruments TVP7002 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Texas Instruments TVP7002 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp7002.
+
+config VIDEO_VPX3220
+ tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for VPX322x video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpx3220.
+
+comment "Video and audio decoders"
+
+config VIDEO_SAA717X
+ tristate "Philips SAA7171/3/4 audio/video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7171/3/4 audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa717x.
+
+source "drivers/media/i2c/cx25840/Kconfig"
+
+comment "MPEG video encoders"
+
+config VIDEO_CX2341X
+ tristate "Conexant CX2341x MPEG encoders"
+ depends on VIDEO_V4L2
+ ---help---
+ Support for the Conexant CX23416 MPEG encoders
+ and CX23415 MPEG encoder/decoders.
+
+ This module currently supports the encoding functions only.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx2341x.
+
+comment "Video encoders"
+
+config VIDEO_SAA7127
+ tristate "Philips SAA7127/9 digital video encoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7127/9 digital video encoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7127.
+
+config VIDEO_SAA7185
+ tristate "Philips SAA7185 video encoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7185 video encoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7185.
+
+config VIDEO_ADV7170
+ tristate "Analog Devices ADV7170 video encoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Analog Devices ADV7170 video encoder driver
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7170.
+
+config VIDEO_ADV7175
+ tristate "Analog Devices ADV7175 video encoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Analog Devices ADV7175 video encoder driver
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7175.
+
+config VIDEO_ADV7343
+ tristate "ADV7343 video encoder"
+ depends on I2C
+ help
+ Support for Analog Devices I2C bus based ADV7343 encoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7343.
+
+config VIDEO_ADV7393
+ tristate "ADV7393 video encoder"
+ depends on I2C
+ help
+ Support for Analog Devices I2C bus based ADV7393 encoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7393.
+
+config VIDEO_AK881X
+ tristate "AK8813/AK8814 video encoders"
+ depends on I2C
+ help
+ Video output driver for AKM AK8813 and AK8814 TV encoders
+
+comment "Camera sensor devices"
+
+config VIDEO_APTINA_PLL
+ tristate
+
+config VIDEO_SMIAPP_PLL
+ tristate
+
+config VIDEO_OV7670
+ tristate "OmniVision OV7670 sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV7670 VGA camera. It currently only works with the M88ALP01
+ controller.
+
+config VIDEO_VS6624
+ tristate "ST VS6624 sensor support"
+ depends on VIDEO_V4L2 && I2C
+ depends on MEDIA_CAMERA_SUPPORT
+ ---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 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ 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
+ depends on MEDIA_CAMERA_SUPPORT
+ select VIDEO_APTINA_PLL
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Aptina
+ (Micron) mt9p031 5 Mpixel camera.
+
+config VIDEO_MT9T001
+ tristate "Aptina MT9T001 support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Aptina
+ (Micron) mt0t001 3 Mpixel camera.
+
+config VIDEO_MT9V011
+ tristate "Micron mt9v011 sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ mt0v011 1.3 Mpixel camera. It currently only works with the
+ em28xx driver.
+
+config VIDEO_MT9V032
+ tristate "Micron MT9V032 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ MT9V032 752x480 CMOS sensor.
+
+config VIDEO_TCM825X
+ tristate "TCM825x camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a driver for the Toshiba TCM825x VGA camera sensor.
+ It is used for example in Nokia N800.
+
+config VIDEO_SR030PC30
+ tristate "Siliconfile SR030PC30 sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_NOON010PC30
+ tristate "Siliconfile NOON010PC30 sensor support"
+ depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This driver supports NOON010PC30 CIF camera from Siliconfile
+
+source "drivers/media/i2c/m5mols/Kconfig"
+
+config VIDEO_S5K6AA
+ tristate "Samsung S5K6AAFX sensor support"
+ depends on MEDIA_CAMERA_SUPPORT
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
+ camera sensor with an embedded SoC image signal processor.
+
+source "drivers/media/i2c/smiapp/Kconfig"
+
+comment "Flash devices"
+
+config VIDEO_ADP1653
+ tristate "ADP1653 flash support"
+ depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ 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
+ depends on MEDIA_CAMERA_SUPPORT
+ ---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
+ tristate "NEC Electronics uPD64031A Ghost Reduction"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the NEC Electronics uPD64031A Ghost Reduction
+ video chip. It is most often found in NTSC TV cards made for
+ Japan and is used to reduce the 'ghosting' effect that can
+ be present in analog TV broadcasts.
+
+ To compile this driver as a module, choose M here: the
+ module will be called upd64031a.
+
+config VIDEO_UPD64083
+ tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+ separation video chip. It is used to improve the quality of
+ the colors of a composite signal.
+
+ To compile this driver as a module, choose M here: the
+ module will be called upd64083.
+
+comment "Miscelaneous helper chips"
+
+config VIDEO_THS7303
+ tristate "THS7303 Video Amplifier"
+ depends on I2C
+ help
+ Support for TI THS7303 video amplifier
+
+ To compile this driver as a module, choose M here: the
+ module will be called ths7303.
+
+config VIDEO_M52790
+ tristate "Mitsubishi M52790 A/V switch"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Mitsubishi M52790 A/V switch.
+
+ To compile this driver as a module, choose M here: the
+ module will be called m52790.
+endmenu
+
+menu "Sensors used on soc_camera driver"
+
+if SOC_CAMERA
+ source "drivers/media/i2c/soc_camera/Kconfig"
+endif
+
+endmenu
+
+endif
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
new file mode 100644
index 000000000000..088a46015605
--- /dev/null
+++ b/drivers/media/i2c/Makefile
@@ -0,0 +1,64 @@
+msp3400-objs := msp3400-driver.o msp3400-kthreads.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+
+obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
+obj-y += soc_camera/
+
+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
+obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
+obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
+obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
+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_ADV7393) += adv7393.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
+obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
+obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
+obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
+obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
+obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
+obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
+obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
+obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
+obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
+obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
+obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
+obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
new file mode 100644
index 000000000000..18a38b38fcb8
--- /dev/null
+++ b/drivers/media/i2c/adp1653.c
@@ -0,0 +1,487 @@
+/*
+ * drivers/media/i2c/adp1653.c
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ * Tuukka Toivonen <tuukkat76@gmail.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:
+ * - fault interrupt handling
+ * - hardware strobe
+ * - power doesn't need to be ON if all lights are off
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/adp1653.h>
+#include <media/v4l2-device.h>
+
+#define TIMEOUT_MAX 820000
+#define TIMEOUT_STEP 54600
+#define TIMEOUT_MIN (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \
+ * TIMEOUT_STEP)
+#define TIMEOUT_US_TO_CODE(t) ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \
+ / TIMEOUT_STEP)
+#define TIMEOUT_CODE_TO_US(c) (TIMEOUT_MAX - (c) * TIMEOUT_STEP)
+
+/* Write values into ADP1653 registers. */
+static int adp1653_update_hw(struct adp1653_flash *flash)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ u8 out_sel;
+ u8 config = 0;
+ int rval;
+
+ out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+ flash->indicator_intensity->val)
+ << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+
+ switch (flash->led_mode->val) {
+ case V4L2_FLASH_LED_MODE_NONE:
+ break;
+ case V4L2_FLASH_LED_MODE_FLASH:
+ /* Flash mode, light on with strobe, duration from timer */
+ config = ADP1653_REG_CONFIG_TMR_CFG;
+ config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val)
+ << ADP1653_REG_CONFIG_TMR_SET_SHIFT;
+ break;
+ case V4L2_FLASH_LED_MODE_TORCH:
+ /* Torch mode, light immediately on, duration indefinite */
+ out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+ flash->torch_intensity->val)
+ << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+ break;
+ }
+
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+ if (rval < 0)
+ return rval;
+
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config);
+ if (rval < 0)
+ return rval;
+
+ return 0;
+}
+
+static int adp1653_get_fault(struct adp1653_flash *flash)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int fault;
+ int rval;
+
+ fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
+ if (IS_ERR_VALUE(fault))
+ return fault;
+
+ flash->fault |= fault;
+
+ if (!flash->fault)
+ return 0;
+
+ /* Clear faults. */
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+ if (IS_ERR_VALUE(rval))
+ return rval;
+
+ flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
+
+ rval = adp1653_update_hw(flash);
+ if (IS_ERR_VALUE(rval))
+ return rval;
+
+ return flash->fault;
+}
+
+static int adp1653_strobe(struct adp1653_flash *flash, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+ flash->indicator_intensity->val)
+ << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+ int rval;
+
+ if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH)
+ return -EBUSY;
+
+ if (!enable)
+ return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL,
+ out_sel);
+
+ out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+ flash->flash_intensity->val)
+ << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+ if (rval)
+ return rval;
+
+ /* Software strobe using i2c */
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE,
+ ADP1653_REG_SW_STROBE_SW_STROBE);
+ if (rval)
+ return rval;
+ return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct adp1653_flash *flash =
+ container_of(ctrl->handler, struct adp1653_flash, ctrls);
+ int rval;
+
+ rval = adp1653_get_fault(flash);
+ if (IS_ERR_VALUE(rval))
+ return rval;
+
+ ctrl->cur.val = 0;
+
+ if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+ if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+ if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+ if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+
+ flash->fault = 0;
+
+ return 0;
+}
+
+static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct adp1653_flash *flash =
+ container_of(ctrl->handler, struct adp1653_flash, ctrls);
+ int rval;
+
+ rval = adp1653_get_fault(flash);
+ if (IS_ERR_VALUE(rval))
+ return rval;
+ if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
+ ADP1653_REG_FAULT_FLT_OT |
+ ADP1653_REG_FAULT_FLT_OV)) &&
+ (ctrl->id == V4L2_CID_FLASH_STROBE ||
+ ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY ||
+ ctrl->id == V4L2_CID_FLASH_LED_MODE))
+ return -EBUSY;
+
+ switch (ctrl->id) {
+ case V4L2_CID_FLASH_STROBE:
+ return adp1653_strobe(flash, 1);
+ case V4L2_CID_FLASH_STROBE_STOP:
+ return adp1653_strobe(flash, 0);
+ }
+
+ return adp1653_update_hw(flash);
+}
+
+static const struct v4l2_ctrl_ops adp1653_ctrl_ops = {
+ .g_volatile_ctrl = adp1653_get_ctrl,
+ .s_ctrl = adp1653_set_ctrl,
+};
+
+static int adp1653_init_controls(struct adp1653_flash *flash)
+{
+ struct v4l2_ctrl *fault;
+
+ v4l2_ctrl_handler_init(&flash->ctrls, 9);
+
+ flash->led_mode =
+ v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_LED_MODE,
+ V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0);
+ v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_STROBE_SOURCE,
+ V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0);
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+ flash->flash_timeout =
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN,
+ flash->platform_data->max_flash_timeout,
+ TIMEOUT_STEP,
+ flash->platform_data->max_flash_timeout);
+ flash->flash_intensity =
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_INTENSITY,
+ ADP1653_FLASH_INTENSITY_MIN,
+ flash->platform_data->max_flash_intensity,
+ 1, flash->platform_data->max_flash_intensity);
+ flash->torch_intensity =
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_TORCH_INTENSITY,
+ ADP1653_TORCH_INTENSITY_MIN,
+ flash->platform_data->max_torch_intensity,
+ ADP1653_FLASH_INTENSITY_STEP,
+ flash->platform_data->max_torch_intensity);
+ flash->indicator_intensity =
+ v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_INDICATOR_INTENSITY,
+ ADP1653_INDICATOR_INTENSITY_MIN,
+ flash->platform_data->max_indicator_intensity,
+ ADP1653_INDICATOR_INTENSITY_STEP,
+ ADP1653_INDICATOR_INTENSITY_MIN);
+ fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+ V4L2_CID_FLASH_FAULT, 0,
+ V4L2_FLASH_FAULT_OVER_VOLTAGE
+ | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+ | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+
+ if (flash->ctrls.error)
+ return flash->ctrls.error;
+
+ fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ flash->subdev.ctrl_handler = &flash->ctrls;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static int
+adp1653_init_device(struct adp1653_flash *flash)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int rval;
+
+ /* Clear FAULT register by writing zero to OUT_SEL */
+ rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+ if (rval < 0) {
+ dev_err(&client->dev, "failed writing fault register\n");
+ return -EIO;
+ }
+
+ mutex_lock(flash->ctrls.lock);
+ /* Reset faults before reading new ones. */
+ flash->fault = 0;
+ rval = adp1653_get_fault(flash);
+ mutex_unlock(flash->ctrls.lock);
+ if (rval > 0) {
+ dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
+ return -EIO;
+ }
+
+ mutex_lock(flash->ctrls.lock);
+ rval = adp1653_update_hw(flash);
+ mutex_unlock(flash->ctrls.lock);
+ if (rval) {
+ dev_err(&client->dev,
+ "adp1653_update_hw failed at %s\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+__adp1653_set_power(struct adp1653_flash *flash, int on)
+{
+ int ret;
+
+ ret = flash->platform_data->power(&flash->subdev, on);
+ if (ret < 0)
+ return ret;
+
+ if (!on)
+ return 0;
+
+ ret = adp1653_init_device(flash);
+ if (ret < 0)
+ flash->platform_data->power(&flash->subdev, 0);
+
+ return ret;
+}
+
+static int
+adp1653_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct adp1653_flash *flash = to_adp1653_flash(subdev);
+ int ret = 0;
+
+ mutex_lock(&flash->power_lock);
+
+ /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (flash->power_count == !on) {
+ ret = __adp1653_set_power(flash, !!on);
+ if (ret < 0)
+ goto done;
+ }
+
+ /* Update the power count. */
+ flash->power_count += on ? 1 : -1;
+ WARN_ON(flash->power_count < 0);
+
+done:
+ mutex_unlock(&flash->power_lock);
+ return ret;
+}
+
+static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return adp1653_set_power(sd, 1);
+}
+
+static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return adp1653_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops adp1653_core_ops = {
+ .s_power = adp1653_set_power,
+};
+
+static const struct v4l2_subdev_ops adp1653_ops = {
+ .core = &adp1653_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops adp1653_internal_ops = {
+ .open = adp1653_open,
+ .close = adp1653_close,
+};
+
+/* --------------------------------------------------------------------------
+ * I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int adp1653_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+ if (!flash->power_count)
+ return 0;
+
+ return __adp1653_set_power(flash, 0);
+}
+
+static int adp1653_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+ if (!flash->power_count)
+ return 0;
+
+ return __adp1653_set_power(flash, 1);
+}
+
+#else
+
+#define adp1653_suspend NULL
+#define adp1653_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int adp1653_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct adp1653_flash *flash;
+ int ret;
+
+ /* we couldn't work without platform data */
+ if (client->dev.platform_data == NULL)
+ return -ENODEV;
+
+ flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+ if (flash == NULL)
+ return -ENOMEM;
+
+ flash->platform_data = client->dev.platform_data;
+
+ mutex_init(&flash->power_lock);
+
+ v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops);
+ flash->subdev.internal_ops = &adp1653_internal_ops;
+ flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ ret = adp1653_init_controls(flash);
+ if (ret)
+ goto free_and_quit;
+
+ ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+ if (ret < 0)
+ goto free_and_quit;
+
+ flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+ return 0;
+
+free_and_quit:
+ v4l2_ctrl_handler_free(&flash->ctrls);
+ kfree(flash);
+ return ret;
+}
+
+static int __exit adp1653_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+ v4l2_device_unregister_subdev(&flash->subdev);
+ v4l2_ctrl_handler_free(&flash->ctrls);
+ media_entity_cleanup(&flash->subdev.entity);
+ kfree(flash);
+ return 0;
+}
+
+static const struct i2c_device_id adp1653_id_table[] = {
+ { ADP1653_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adp1653_id_table);
+
+static struct dev_pm_ops adp1653_pm_ops = {
+ .suspend = adp1653_suspend,
+ .resume = adp1653_resume,
+};
+
+static struct i2c_driver adp1653_i2c_driver = {
+ .driver = {
+ .name = ADP1653_NAME,
+ .pm = &adp1653_pm_ops,
+ },
+ .probe = adp1653_probe,
+ .remove = __exit_p(adp1653_remove),
+ .id_table = adp1653_id_table,
+};
+
+module_i2c_driver(adp1653_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/adv7170.c b/drivers/media/i2c/adv7170.c
index 6bc01fb98ff8..6bc01fb98ff8 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/i2c/adv7170.c
diff --git a/drivers/media/video/adv7175.c b/drivers/media/i2c/adv7175.c
index c7640fab5730..c7640fab5730 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/i2c/adv7175.c
diff --git a/drivers/media/video/adv7180.c b/drivers/media/i2c/adv7180.c
index 45ecf8db1eae..45ecf8db1eae 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
diff --git a/drivers/media/video/adv7183.c b/drivers/media/i2c/adv7183.c
index e1d4c89d7140..e1d4c89d7140 100644
--- a/drivers/media/video/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
diff --git a/drivers/media/video/adv7183_regs.h b/drivers/media/i2c/adv7183_regs.h
index 4a5b7d211d2f..4a5b7d211d2f 100644
--- a/drivers/media/video/adv7183_regs.h
+++ b/drivers/media/i2c/adv7183_regs.h
diff --git a/drivers/media/video/adv7343.c b/drivers/media/i2c/adv7343.c
index 2b5aa676a84e..2b5aa676a84e 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
diff --git a/drivers/media/video/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h
index 446606764346..446606764346 100644
--- a/drivers/media/video/adv7343_regs.h
+++ b/drivers/media/i2c/adv7343_regs.h
diff --git a/drivers/media/video/adv7393.c b/drivers/media/i2c/adv7393.c
index 3dc6098c7267..3dc6098c7267 100644
--- a/drivers/media/video/adv7393.c
+++ b/drivers/media/i2c/adv7393.c
diff --git a/drivers/media/video/adv7393_regs.h b/drivers/media/i2c/adv7393_regs.h
index 78968330f0be..78968330f0be 100644
--- a/drivers/media/video/adv7393_regs.h
+++ b/drivers/media/i2c/adv7393_regs.h
diff --git a/drivers/media/video/ak881x.c b/drivers/media/i2c/ak881x.c
index ba674656b10d..ba674656b10d 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/i2c/aptina-pll.c
index 8153a449846b..8153a449846b 100644
--- a/drivers/media/video/aptina-pll.c
+++ b/drivers/media/i2c/aptina-pll.c
diff --git a/drivers/media/video/aptina-pll.h b/drivers/media/i2c/aptina-pll.h
index b370e341e75d..b370e341e75d 100644
--- a/drivers/media/video/aptina-pll.h
+++ b/drivers/media/i2c/aptina-pll.h
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
new file mode 100644
index 000000000000..3bfdbf9d9bf1
--- /dev/null
+++ b/drivers/media/i2c/as3645a.c
@@ -0,0 +1,888 @@
+/*
+ * drivers/media/i2c/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 __devinit 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 __devinit 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 __devexit 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 = __devexit_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/bt819.c b/drivers/media/i2c/bt819.c
index 377bf05b1efd..377bf05b1efd 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/i2c/bt819.c
diff --git a/drivers/media/video/bt856.c b/drivers/media/i2c/bt856.c
index 7e5bd365c239..7e5bd365c239 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/i2c/bt856.c
diff --git a/drivers/media/video/bt866.c b/drivers/media/i2c/bt866.c
index 905320b67a1c..905320b67a1c 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/i2c/bt866.c
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/i2c/btcx-risc.c
index ac1b2687a20d..ac1b2687a20d 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/i2c/btcx-risc.c
diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/i2c/btcx-risc.h
index f8bc6e8e7b51..f8bc6e8e7b51 100644
--- a/drivers/media/video/btcx-risc.h
+++ b/drivers/media/i2c/btcx-risc.h
diff --git a/drivers/media/video/cs5345.c b/drivers/media/i2c/cs5345.c
index c8581e26fa9c..c8581e26fa9c 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/i2c/cs5345.c
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/i2c/cs53l32a.c
index b293912206eb..b293912206eb 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/i2c/cs53l32a.c
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/i2c/cx2341x.c
index 103ef6bad2e2..103ef6bad2e2 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/i2c/cx2341x.c
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/i2c/cx25840/Kconfig
index 451133ad41ff..451133ad41ff 100644
--- a/drivers/media/video/cx25840/Kconfig
+++ b/drivers/media/i2c/cx25840/Kconfig
diff --git a/drivers/media/i2c/cx25840/Makefile b/drivers/media/i2c/cx25840/Makefile
new file mode 100644
index 000000000000..898eb13340ae
--- /dev/null
+++ b/drivers/media/i2c/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+ cx25840-vbi.o cx25840-ir.o
+
+obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/i2c/cx25840/cx25840-audio.c
index 34b96c7cfd62..34b96c7cfd62 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/i2c/cx25840/cx25840-audio.c
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index d8eac3e30a7e..d8eac3e30a7e 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
index bd4ada28b490..bd4ada28b490 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
diff --git a/drivers/media/i2c/cx25840/cx25840-firmware.c b/drivers/media/i2c/cx25840/cx25840-firmware.c
new file mode 100644
index 000000000000..b3169f94ece8
--- /dev/null
+++ b/drivers/media/i2c/cx25840/cx25840-firmware.c
@@ -0,0 +1,175 @@
+/* cx25840 firmware functions
+ *
+ * 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 <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx25840.h>
+
+#include "cx25840-core.h"
+
+/*
+ * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
+ * size of the firmware chunks sent down the I2C bus to the chip.
+ * Previously this had been set to 1024 but unfortunately some I2C
+ * implementations can't transfer data in such big gulps.
+ * Specifically, the pvrusb2 driver has a hard limit of around 60
+ * bytes, due to the encapsulation there of I2C traffic into USB
+ * messages. So we have to significantly reduce this parameter.
+ */
+#define FWSEND 48
+
+#define FWDEV(x) &((x)->dev)
+
+static char *firmware = "";
+
+module_param(firmware, charp, 0444);
+
+MODULE_PARM_DESC(firmware, "Firmware image to load");
+
+static void start_fw_load(struct i2c_client *client)
+{
+ /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
+ cx25840_write(client, 0x800, 0x00);
+ cx25840_write(client, 0x801, 0x00);
+ // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
+ cx25840_write(client, 0x803, 0x0b);
+ /* AUTO_INC_DIS=1 */
+ cx25840_write(client, 0x000, 0x20);
+}
+
+static void end_fw_load(struct i2c_client *client)
+{
+ /* AUTO_INC_DIS=0 */
+ cx25840_write(client, 0x000, 0x00);
+ /* DL_ENABLE=0 */
+ cx25840_write(client, 0x803, 0x03);
+}
+
+#define CX2388x_FIRMWARE "v4l-cx23885-avcore-01.fw"
+#define CX231xx_FIRMWARE "v4l-cx231xx-avcore-01.fw"
+#define CX25840_FIRMWARE "v4l-cx25840.fw"
+
+static const char *get_fw_name(struct i2c_client *client)
+{
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+ if (firmware[0])
+ return firmware;
+ if (is_cx2388x(state))
+ return CX2388x_FIRMWARE;
+ if (is_cx231xx(state))
+ return CX231xx_FIRMWARE;
+ return CX25840_FIRMWARE;
+}
+
+static int check_fw_load(struct i2c_client *client, int size)
+{
+ /* DL_ADDR_HB DL_ADDR_LB */
+ int s = cx25840_read(client, 0x801) << 8;
+ s |= cx25840_read(client, 0x800);
+
+ if (size != s) {
+ v4l_err(client, "firmware %s load failed\n",
+ get_fw_name(client));
+ return -EINVAL;
+ }
+
+ v4l_info(client, "loaded %s firmware (%d bytes)\n",
+ get_fw_name(client), size);
+ return 0;
+}
+
+static int fw_write(struct i2c_client *client, const u8 *data, int size)
+{
+ if (i2c_master_send(client, data, size) < size) {
+ v4l_err(client, "firmware load i2c failure\n");
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+int cx25840_loadfw(struct i2c_client *client)
+{
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+ const struct firmware *fw = NULL;
+ u8 buffer[FWSEND];
+ const u8 *ptr;
+ const char *fwname = get_fw_name(client);
+ int size, retval;
+ int MAX_BUF_SIZE = FWSEND;
+ u32 gpio_oe = 0, gpio_da = 0;
+
+ if (is_cx2388x(state)) {
+ /* Preserve the GPIO OE and output bits */
+ gpio_oe = cx25840_read(client, 0x160);
+ gpio_da = cx25840_read(client, 0x164);
+ }
+
+ if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
+ v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
+ MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
+ }
+
+ if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
+ v4l_err(client, "unable to open firmware %s\n", fwname);
+ return -EINVAL;
+ }
+
+ start_fw_load(client);
+
+ buffer[0] = 0x08;
+ buffer[1] = 0x02;
+
+ size = fw->size;
+ ptr = fw->data;
+ while (size > 0) {
+ int len = min(MAX_BUF_SIZE - 2, size);
+
+ memcpy(buffer + 2, ptr, len);
+
+ retval = fw_write(client, buffer, len + 2);
+
+ if (retval < 0) {
+ release_firmware(fw);
+ return retval;
+ }
+
+ size -= len;
+ ptr += len;
+ }
+
+ end_fw_load(client);
+
+ size = fw->size;
+ release_firmware(fw);
+
+ if (is_cx2388x(state)) {
+ /* Restore GPIO configuration after f/w load */
+ cx25840_write(client, 0x160, gpio_oe);
+ cx25840_write(client, 0x164, gpio_da);
+ }
+
+ return check_fw_load(client, size);
+}
+
+MODULE_FIRMWARE(CX2388x_FIRMWARE);
+MODULE_FIRMWARE(CX231xx_FIRMWARE);
+MODULE_FIRMWARE(CX25840_FIRMWARE);
+
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 38ce76ed1924..38ce76ed1924 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c
index 64a4004f8a97..64a4004f8a97 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/i2c/cx25840/cx25840-vbi.c
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 04f192a0398a..04f192a0398a 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
diff --git a/drivers/media/video/ks0127.c b/drivers/media/i2c/ks0127.c
index ee7ca2dcca2f..ee7ca2dcca2f 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
diff --git a/drivers/media/video/ks0127.h b/drivers/media/i2c/ks0127.h
index cb8abd5403b3..cb8abd5403b3 100644
--- a/drivers/media/video/ks0127.h
+++ b/drivers/media/i2c/ks0127.h
diff --git a/drivers/media/video/m52790.c b/drivers/media/i2c/m52790.c
index 0991576f4c82..0991576f4c82 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/i2c/m52790.c
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig
index dc8c2505907e..dc8c2505907e 100644
--- a/drivers/media/video/m5mols/Kconfig
+++ b/drivers/media/i2c/m5mols/Kconfig
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/i2c/m5mols/Makefile
index 0a44e028edc7..0a44e028edc7 100644
--- a/drivers/media/video/m5mols/Makefile
+++ b/drivers/media/i2c/m5mols/Makefile
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h
index bb589917b65b..bb589917b65b 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/i2c/m5mols/m5mols.h
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
index cb243bd278ce..cb243bd278ce 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/i2c/m5mols/m5mols_capture.c
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c
index fdbc205a2969..fdbc205a2969 100644
--- a/drivers/media/video/m5mols/m5mols_controls.c
+++ b/drivers/media/i2c/m5mols/m5mols_controls.c
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index ac7d28b6ddf2..ac7d28b6ddf2 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h
index 14d4be72aeff..14d4be72aeff 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/i2c/m5mols/m5mols_reg.h
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index aeb22be7dcbd..aeb22be7dcbd 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h
index fbe5e0715f93..fbe5e0715f93 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/i2c/msp3400-driver.h
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c
index f8b51714f2f9..f8b51714f2f9 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/i2c/msp3400-kthreads.c
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 445359c96113..445359c96113 100644
--- a/drivers/media/video/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 3be537ef22d2..3be537ef22d2 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/i2c/mt9t001.c
index 6d343adf891d..6d343adf891d 100644
--- a/drivers/media/video/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 6bf01ad62765..6bf01ad62765 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 4ba4884c016e..4ba4884c016e 100644
--- a/drivers/media/video/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 440c12962bae..440c12962bae 100644
--- a/drivers/media/video/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
diff --git a/drivers/media/video/ov7670.c b/drivers/media/i2c/ov7670.c
index e7c82b297514..e7c82b297514 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
new file mode 100644
index 000000000000..045ca7f4f6ca
--- /dev/null
+++ b/drivers/media/i2c/s5k6aa.c
@@ -0,0 +1,1667 @@
+/*
+ * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
+ * with embedded SoC ISP.
+ *
+ * Copyright (C) 2011, Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Based on a driver authored by Dongsoo Nathaniel Kim.
+ * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5k6aa.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define DRIVER_NAME "S5K6AA"
+
+/* The token to indicate array termination */
+#define S5K6AA_TERM 0xffff
+#define S5K6AA_OUT_WIDTH_DEF 640
+#define S5K6AA_OUT_HEIGHT_DEF 480
+#define S5K6AA_WIN_WIDTH_MAX 1280
+#define S5K6AA_WIN_HEIGHT_MAX 1024
+#define S5K6AA_WIN_WIDTH_MIN 8
+#define S5K6AA_WIN_HEIGHT_MIN 8
+
+/*
+ * H/W register Interface (0xD0000000 - 0xD0000FFF)
+ */
+#define AHB_MSB_ADDR_PTR 0xfcfc
+#define GEN_REG_OFFSH 0xd000
+#define REG_CMDWR_ADDRH 0x0028
+#define REG_CMDWR_ADDRL 0x002a
+#define REG_CMDRD_ADDRH 0x002c
+#define REG_CMDRD_ADDRL 0x002e
+#define REG_CMDBUF0_ADDR 0x0f12
+#define REG_CMDBUF1_ADDR 0x0f10
+
+/*
+ * Host S/W Register interface (0x70000000 - 0x70002000)
+ * The value of the two most significant address bytes is 0x7000,
+ * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
+ */
+#define HOST_SWIF_OFFSH 0x7000
+
+/* Initialization parameters */
+/* Master clock frequency in KHz */
+#define REG_I_INCLK_FREQ_L 0x01b8
+#define REG_I_INCLK_FREQ_H 0x01ba
+#define MIN_MCLK_FREQ_KHZ 6000U
+#define MAX_MCLK_FREQ_KHZ 27000U
+#define REG_I_USE_NPVI_CLOCKS 0x01c6
+#define REG_I_USE_NMIPI_CLOCKS 0x01c8
+
+/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
+#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc)
+#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce)
+#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0)
+#define SYS_PLL_OUT_FREQ (48000000 / 4000)
+#define PCLK_FREQ_MIN (24000000 / 4000)
+#define PCLK_FREQ_MAX (48000000 / 4000)
+#define REG_I_INIT_PARAMS_UPDATED 0x01e0
+#define REG_I_ERROR_INFO 0x01e2
+
+/* General purpose parameters */
+#define REG_USER_BRIGHTNESS 0x01e4
+#define REG_USER_CONTRAST 0x01e6
+#define REG_USER_SATURATION 0x01e8
+#define REG_USER_SHARPBLUR 0x01ea
+
+#define REG_G_SPEC_EFFECTS 0x01ee
+#define REG_G_ENABLE_PREV 0x01f0
+#define REG_G_ENABLE_PREV_CHG 0x01f2
+#define REG_G_NEW_CFG_SYNC 0x01f8
+#define REG_G_PREVZOOM_IN_WIDTH 0x020a
+#define REG_G_PREVZOOM_IN_HEIGHT 0x020c
+#define REG_G_PREVZOOM_IN_XOFFS 0x020e
+#define REG_G_PREVZOOM_IN_YOFFS 0x0210
+#define REG_G_INPUTS_CHANGE_REQ 0x021a
+#define REG_G_ACTIVE_PREV_CFG 0x021c
+#define REG_G_PREV_CFG_CHG 0x021e
+#define REG_G_PREV_OPEN_AFTER_CH 0x0220
+#define REG_G_PREV_CFG_ERROR 0x0222
+
+/* Preview control section. n = 0...4. */
+#define PREG(n, x) ((n) * 0x26 + x)
+#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242)
+#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244)
+#define REG_P_FMT(n) PREG(n, 0x0246)
+#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248)
+#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a)
+#define REG_P_PVI_MASK(n) PREG(n, 0x024c)
+#define REG_P_CLK_INDEX(n) PREG(n, 0x024e)
+#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250)
+#define FR_RATE_DYNAMIC 0
+#define FR_RATE_FIXED 1
+#define FR_RATE_FIXED_ACCURATE 2
+#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252)
+#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */
+#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */
+/* Frame period in 0.1 ms units */
+#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254)
+#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256)
+/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
+#define US_TO_FR_TIME(__t) ((__t) / 100)
+#define S5K6AA_MIN_FR_TIME 33300 /* us */
+#define S5K6AA_MAX_FR_TIME 650000 /* us */
+#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */
+/* The below 5 registers are for "device correction" values */
+#define REG_P_COLORTEMP(n) PREG(n, 0x025e)
+#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262)
+
+/* Extended image property controls */
+/* Exposure time in 10 us units */
+#define REG_SF_USR_EXPOSURE_L 0x03c6
+#define REG_SF_USR_EXPOSURE_H 0x03c8
+#define REG_SF_USR_EXPOSURE_CHG 0x03ca
+#define REG_SF_USR_TOT_GAIN 0x03cc
+#define REG_SF_USR_TOT_GAIN_CHG 0x03ce
+#define REG_SF_RGAIN 0x03d0
+#define REG_SF_RGAIN_CHG 0x03d2
+#define REG_SF_GGAIN 0x03d4
+#define REG_SF_GGAIN_CHG 0x03d6
+#define REG_SF_BGAIN 0x03d8
+#define REG_SF_BGAIN_CHG 0x03da
+#define REG_SF_FLICKER_QUANT 0x03dc
+#define REG_SF_FLICKER_QUANT_CHG 0x03de
+
+/* Output interface (parallel/MIPI) setup */
+#define REG_OIF_EN_MIPI_LANES 0x03fa
+#define REG_OIF_EN_PACKETS 0x03fc
+#define REG_OIF_CFG_CHG 0x03fe
+
+/* Auto-algorithms enable mask */
+#define REG_DBG_AUTOALG_EN 0x0400
+#define AALG_ALL_EN_MASK (1 << 0)
+#define AALG_AE_EN_MASK (1 << 1)
+#define AALG_DIVLEI_EN_MASK (1 << 2)
+#define AALG_WB_EN_MASK (1 << 3)
+#define AALG_FLICKER_EN_MASK (1 << 5)
+#define AALG_FIT_EN_MASK (1 << 6)
+#define AALG_WRHW_EN_MASK (1 << 7)
+
+/* Firmware revision information */
+#define REG_FW_APIVER 0x012e
+#define S5K6AAFX_FW_APIVER 0x0001
+#define REG_FW_REVISION 0x0130
+
+/* For now we use only one user configuration register set */
+#define S5K6AA_MAX_PRESETS 1
+
+static const char * const s5k6aa_supply_names[] = {
+ "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */
+ "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */
+ "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V)
+ or 2.8V (2.6V to 3.0) */
+ "vddio", /* I/O supply 1.8V (1.65V to 1.95V)
+ or 2.8V (2.5V to 3.1V) */
+};
+#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
+
+enum s5k6aa_gpio_id {
+ STBY,
+ RST,
+ GPIO_NUM,
+};
+
+struct s5k6aa_regval {
+ u16 addr;
+ u16 val;
+};
+
+struct s5k6aa_pixfmt {
+ enum v4l2_mbus_pixelcode code;
+ u32 colorspace;
+ /* REG_P_FMT(x) register value */
+ u16 reg_p_fmt;
+};
+
+struct s5k6aa_preset {
+ /* output pixel format and resolution */
+ struct v4l2_mbus_framefmt mbus_fmt;
+ u8 clk_id;
+ u8 index;
+};
+
+struct s5k6aa_ctrls {
+ struct v4l2_ctrl_handler handler;
+ /* Auto / manual white balance cluster */
+ struct v4l2_ctrl *awb;
+ struct v4l2_ctrl *gain_red;
+ struct v4l2_ctrl *gain_blue;
+ struct v4l2_ctrl *gain_green;
+ /* Mirror cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ /* Auto exposure / manual exposure and gain cluster */
+ struct v4l2_ctrl *auto_exp;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+};
+
+struct s5k6aa_interval {
+ u16 reg_fr_time;
+ struct v4l2_fract interval;
+ /* Maximum rectangle for the interval */
+ struct v4l2_frmsize_discrete size;
+};
+
+struct s5k6aa {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ enum v4l2_mbus_type bus_type;
+ u8 mipi_lanes;
+
+ int (*s_power)(int enable);
+ struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
+ struct s5k6aa_gpio gpio[GPIO_NUM];
+
+ /* external master clock frequency */
+ unsigned long mclk_frequency;
+ /* ISP internal master clock frequency */
+ u16 clk_fop;
+ /* output pixel clock frequency range */
+ u16 pclk_fmin;
+ u16 pclk_fmax;
+
+ unsigned int inv_hflip:1;
+ unsigned int inv_vflip:1;
+
+ /* protects the struct members below */
+ struct mutex lock;
+
+ /* sensor matrix scan window */
+ struct v4l2_rect ccd_rect;
+
+ struct s5k6aa_ctrls ctrls;
+ struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
+ struct s5k6aa_preset *preset;
+ const struct s5k6aa_interval *fiv;
+
+ unsigned int streaming:1;
+ unsigned int apply_cfg:1;
+ unsigned int apply_crop:1;
+ unsigned int power;
+};
+
+static struct s5k6aa_regval s5k6aa_analog_config[] = {
+ /* Analog settings */
+ { 0x112a, 0x0000 }, { 0x1132, 0x0000 },
+ { 0x113e, 0x0000 }, { 0x115c, 0x0000 },
+ { 0x1164, 0x0000 }, { 0x1174, 0x0000 },
+ { 0x1178, 0x0000 }, { 0x077a, 0x0000 },
+ { 0x077c, 0x0000 }, { 0x077e, 0x0000 },
+ { 0x0780, 0x0000 }, { 0x0782, 0x0000 },
+ { 0x0784, 0x0000 }, { 0x0786, 0x0000 },
+ { 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
+ { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
+ { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
+ { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
+ { 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
+ { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
+};
+
+/* TODO: Add RGB888 and Bayer format */
+static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
+ { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
+ /* range 16-240 */
+ { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
+ { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
+};
+
+static const struct s5k6aa_interval s5k6aa_intervals[] = {
+ { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
+ { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */
+ { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */
+ { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */
+ { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */
+};
+
+#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
+}
+
+static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct s5k6aa, sd);
+}
+
+/* Set initial values for all preview presets */
+static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
+{
+ struct s5k6aa_preset *preset = &s5k6aa->presets[0];
+ int i;
+
+ for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
+ preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF;
+ preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF;
+ preset->mbus_fmt.code = s5k6aa_formats[0].code;
+ preset->index = i;
+ preset->clk_id = 0;
+ preset++;
+ }
+
+ s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
+ s5k6aa->preset = &s5k6aa->presets[0];
+}
+
+static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
+{
+ u8 wbuf[2] = {addr >> 8, addr & 0xFF};
+ struct i2c_msg msg[2];
+ u8 rbuf[2];
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = wbuf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = rbuf;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ *val = be16_to_cpu(*((u16 *)rbuf));
+
+ v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
+
+ return ret == 2 ? 0 : ret;
+}
+
+static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
+{
+ u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
+
+ int ret = i2c_master_send(client, buf, 4);
+ v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
+
+ return ret == 4 ? 0 : ret;
+}
+
+/* The command register write, assumes Command_Wr_addH = 0x7000. */
+static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
+{
+ int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
+ if (ret)
+ return ret;
+ return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
+}
+
+/* The command register read, assumes Command_Rd_addH = 0x7000. */
+static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
+{
+ int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
+ if (ret)
+ return ret;
+ return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
+}
+
+static int s5k6aa_write_array(struct v4l2_subdev *sd,
+ const struct s5k6aa_regval *msg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 addr_incr = 0;
+ int ret = 0;
+
+ while (msg->addr != S5K6AA_TERM) {
+ if (addr_incr != 2)
+ ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
+ msg->addr);
+ if (ret)
+ break;
+ ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
+ if (ret)
+ break;
+ /* Assume that msg->addr is always less than 0xfffc */
+ addr_incr = (msg + 1)->addr - msg->addr;
+ msg++;
+ }
+
+ return ret;
+}
+
+/* Configure the AHB high address bytes for GTG registers access */
+static int s5k6aa_set_ahb_address(struct i2c_client *client)
+{
+ int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
+ if (ret)
+ return ret;
+ ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
+ if (ret)
+ return ret;
+ return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
+}
+
+/**
+ * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
+ *
+ * Configure the internal ISP PLL for the required output frequency.
+ * Locking: called with s5k6aa.lock mutex held.
+ */
+static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+ unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
+ u16 status;
+ int ret;
+
+ if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
+ "Invalid clock frequency: %ld\n", fmclk))
+ return -EINVAL;
+
+ s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
+ s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
+ s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
+
+ /* External input clock frequency in kHz */
+ ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
+ /* Internal PLL frequency */
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
+ s5k6aa->pclk_fmin);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
+ s5k6aa->pclk_fmax);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
+ if (!ret)
+ ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
+
+ return ret ? ret : (status ? -EINVAL : 0);
+}
+
+/* Set horizontal and vertical image flipping */
+static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ int index = s5k6aa->preset->index;
+
+ unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
+ unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
+
+ return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
+}
+
+/* Configure auto/manual white balance and R/G/B gains */
+static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+ struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
+ u16 reg;
+
+ int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &reg);
+
+ if (!ret && !awb) {
+ ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
+ if (ret)
+ return ret;
+
+ ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
+ if (ret)
+ return ret;
+
+ ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
+ }
+ if (!ret) {
+ reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
+ ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
+ }
+
+ return ret;
+}
+
+/* Program FW with exposure time, 'exposure' in us units */
+static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
+{
+ unsigned int time = exposure / 10;
+
+ int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
+ if (ret)
+ return ret;
+ return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
+}
+
+static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
+{
+ int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
+ if (ret)
+ return ret;
+ return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
+}
+
+/* Set auto/manual exposure and total gain */
+static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+ unsigned int exp_time = s5k6aa->ctrls.exposure->val;
+ u16 auto_alg;
+
+ int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
+ if (ret)
+ return ret;
+
+ v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
+ exp_time, value, auto_alg);
+
+ if (value == V4L2_EXPOSURE_AUTO) {
+ auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
+ } else {
+ ret = s5k6aa_set_user_exposure(c, exp_time);
+ if (ret)
+ return ret;
+ ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
+ if (ret)
+ return ret;
+ auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
+ }
+
+ return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
+}
+
+static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ u16 auto_alg;
+ int ret;
+
+ ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
+ if (ret)
+ return ret;
+
+ if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
+ auto_alg |= AALG_FLICKER_EN_MASK;
+ } else {
+ auto_alg &= ~AALG_FLICKER_EN_MASK;
+ /* The V4L2_CID_LINE_FREQUENCY control values match
+ * the register values */
+ ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
+ if (ret)
+ return ret;
+ ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
+ if (ret)
+ return ret;
+ }
+
+ return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
+}
+
+static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ static const struct v4l2_control colorfx[] = {
+ { V4L2_COLORFX_NONE, 0 },
+ { V4L2_COLORFX_BW, 1 },
+ { V4L2_COLORFX_NEGATIVE, 2 },
+ { V4L2_COLORFX_SEPIA, 3 },
+ { V4L2_COLORFX_SKY_BLUE, 4 },
+ { V4L2_COLORFX_SKETCH, 5 },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
+ if (colorfx[i].id == val)
+ return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
+ colorfx[i].value);
+ }
+ return -EINVAL;
+}
+
+static int s5k6aa_preview_config_status(struct i2c_client *client)
+{
+ u16 error = 0;
+ int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
+
+ v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
+ return ret ? ret : (error ? -EINVAL : 0);
+}
+
+static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
+ struct v4l2_mbus_framefmt *mf)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
+ if (mf->colorspace == s5k6aa_formats[i].colorspace &&
+ mf->code == s5k6aa_formats[i].code)
+ return i;
+ return 0;
+}
+
+static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
+ struct s5k6aa_preset *preset)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
+ int ret;
+
+ ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
+ preset->mbus_fmt.width);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
+ preset->mbus_fmt.height);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_FMT(preset->index),
+ s5k6aa_formats[fmt_index].reg_p_fmt);
+ return ret;
+}
+
+static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
+ struct v4l2_rect *r = &s5k6aa->ccd_rect;
+ int ret;
+
+ ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
+ if (!ret)
+ ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
+ if (!ret)
+ s5k6aa->apply_crop = 0;
+
+ return ret;
+}
+
+/**
+ * s5k6aa_configure_video_bus - configure the video output interface
+ * @bus_type: video bus type: parallel or MIPI-CSI
+ * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
+ *
+ * Note: Only parallel bus operation has been tested.
+ */
+static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
+ enum v4l2_mbus_type bus_type, int nlanes)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ u16 cfg = 0;
+ int ret;
+
+ /*
+ * TODO: The sensor is supposed to support BT.601 and BT.656
+ * but there is nothing indicating how to switch between both
+ * in the datasheet. For now default BT.601 interface is assumed.
+ */
+ if (bus_type == V4L2_MBUS_CSI2)
+ cfg = nlanes;
+ else if (bus_type != V4L2_MBUS_PARALLEL)
+ return -EINVAL;
+
+ ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
+ if (ret)
+ return ret;
+ return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
+}
+
+/* This function should be called when switching to new user configuration set*/
+static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
+ int cid)
+{
+ unsigned long end = jiffies + msecs_to_jiffies(timeout);
+ u16 reg = 1;
+ int ret;
+
+ ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
+ if (timeout == 0)
+ return ret;
+
+ while (ret >= 0 && time_is_after_jiffies(end)) {
+ ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, &reg);
+ if (!reg)
+ return 0;
+ usleep_range(1000, 5000);
+ }
+ return ret ? ret : -ETIMEDOUT;
+}
+
+/**
+ * s5k6aa_set_prev_config - write user preview register set
+ *
+ * Configure output resolution and color fromat, pixel clock
+ * frequency range, device frame rate type and frame period range.
+ */
+static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
+ struct s5k6aa_preset *preset)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ int idx = preset->index;
+ u16 frame_rate_q;
+ int ret;
+
+ if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
+ frame_rate_q = FR_RATE_Q_BEST_FRRATE;
+ else
+ frame_rate_q = FR_RATE_Q_BEST_QUALITY;
+
+ ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
+ s5k6aa->pclk_fmax);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
+ s5k6aa->pclk_fmin);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
+ preset->clk_id);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
+ FR_RATE_DYNAMIC);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
+ frame_rate_q);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
+ s5k6aa->fiv->reg_fr_time + 33);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
+ s5k6aa->fiv->reg_fr_time - 33);
+ if (!ret)
+ ret = s5k6aa_new_config_sync(client, 250, idx);
+ if (!ret)
+ ret = s5k6aa_preview_config_status(client);
+ if (!ret)
+ s5k6aa->apply_cfg = 0;
+
+ v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
+ s5k6aa->fiv->reg_fr_time, ret);
+ return ret;
+}
+
+/**
+ * s5k6aa_initialize_isp - basic ISP MCU initialization
+ *
+ * Configure AHB addresses for registers read/write; configure PLLs for
+ * required output pixel clock. The ISP power supply needs to be already
+ * enabled, with an optional H/W reset.
+ * Locking: called with s5k6aa.lock mutex held.
+ */
+static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int ret;
+
+ s5k6aa->apply_crop = 1;
+ s5k6aa->apply_cfg = 1;
+ msleep(100);
+
+ ret = s5k6aa_set_ahb_address(client);
+ if (ret)
+ return ret;
+ ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
+ s5k6aa->mipi_lanes);
+ if (ret)
+ return ret;
+ ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
+ if (ret)
+ return ret;
+ msleep(20);
+
+ return s5k6aa_configure_pixel_clocks(s5k6aa);
+}
+
+static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
+{
+ if (!gpio_is_valid(priv->gpio[id].gpio))
+ return 0;
+ gpio_set_value(priv->gpio[id].gpio, !!val);
+ return 1;
+}
+
+static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
+{
+ return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
+}
+
+static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
+{
+ return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
+}
+
+static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+ if (ret)
+ return ret;
+ if (s5k6aa_gpio_deassert(s5k6aa, STBY))
+ usleep_range(150, 200);
+
+ if (s5k6aa->s_power)
+ ret = s5k6aa->s_power(1);
+ usleep_range(4000, 4000);
+
+ if (s5k6aa_gpio_deassert(s5k6aa, RST))
+ msleep(20);
+
+ return ret;
+}
+
+static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
+{
+ int ret;
+
+ if (s5k6aa_gpio_assert(s5k6aa, RST))
+ usleep_range(100, 150);
+
+ if (s5k6aa->s_power) {
+ ret = s5k6aa->s_power(0);
+ if (ret)
+ return ret;
+ }
+ if (s5k6aa_gpio_assert(s5k6aa, STBY))
+ usleep_range(50, 100);
+ s5k6aa->streaming = 0;
+
+ return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+}
+
+/*
+ * V4L2 subdev core and video operations
+ */
+static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int ret = 0;
+
+ mutex_lock(&s5k6aa->lock);
+
+ if (!on == s5k6aa->power) {
+ if (on) {
+ ret = __s5k6aa_power_on(s5k6aa);
+ if (!ret)
+ ret = s5k6aa_initialize_isp(sd);
+ } else {
+ ret = __s5k6aa_power_off(s5k6aa);
+ }
+
+ if (!ret)
+ s5k6aa->power += on ? 1 : -1;
+ }
+
+ mutex_unlock(&s5k6aa->lock);
+
+ if (!on || ret || s5k6aa->power != 1)
+ return ret;
+
+ return v4l2_ctrl_handler_setup(sd->ctrl_handler);
+}
+
+static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ int ret = 0;
+
+ ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
+ if (!ret)
+ ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
+ if (!ret)
+ s5k6aa->streaming = enable;
+
+ return ret;
+}
+
+static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int ret = 0;
+
+ mutex_lock(&s5k6aa->lock);
+
+ if (s5k6aa->streaming == !on) {
+ if (!ret && s5k6aa->apply_cfg)
+ ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
+ if (s5k6aa->apply_crop)
+ ret = s5k6aa_set_input_params(s5k6aa);
+ if (!ret)
+ ret = __s5k6aa_stream(s5k6aa, !!on);
+ }
+ mutex_unlock(&s5k6aa->lock);
+
+ return ret;
+}
+
+static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+
+ mutex_lock(&s5k6aa->lock);
+ fi->interval = s5k6aa->fiv->interval;
+ mutex_unlock(&s5k6aa->lock);
+
+ return 0;
+}
+
+static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
+ const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
+ unsigned int err, min_err = UINT_MAX;
+ unsigned int i, fr_time;
+
+ if (fi->interval.denominator == 0)
+ return -EINVAL;
+
+ fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
+
+ for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
+ const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
+
+ if (mbus_fmt->width > iv->size.width ||
+ mbus_fmt->height > iv->size.height)
+ continue;
+
+ err = abs(iv->reg_fr_time - fr_time);
+ if (err < min_err) {
+ fiv = iv;
+ min_err = err;
+ }
+ }
+ s5k6aa->fiv = fiv;
+
+ v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
+ fiv->reg_fr_time * 100);
+ return 0;
+}
+
+static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int ret;
+
+ v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
+ fi->interval.numerator, fi->interval.denominator);
+
+ mutex_lock(&s5k6aa->lock);
+ ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
+ s5k6aa->apply_cfg = 1;
+
+ mutex_unlock(&s5k6aa->lock);
+ return ret;
+}
+
+/*
+ * V4L2 subdev pad level and video operations
+ */
+static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ const struct s5k6aa_interval *fi;
+ int ret = 0;
+
+ if (fie->index > ARRAY_SIZE(s5k6aa_intervals))
+ return -EINVAL;
+
+ v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
+ S5K6AA_WIN_WIDTH_MAX, 1,
+ &fie->height, S5K6AA_WIN_HEIGHT_MIN,
+ S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+ mutex_lock(&s5k6aa->lock);
+ fi = &s5k6aa_intervals[fie->index];
+ if (fie->width > fi->size.width || fie->height > fi->size.height)
+ ret = -EINVAL;
+ else
+ fie->interval = fi->interval;
+ mutex_unlock(&s5k6aa->lock);
+
+ return ret;
+}
+
+static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(s5k6aa_formats))
+ return -EINVAL;
+
+ code->code = s5k6aa_formats[code->index].code;
+ return 0;
+}
+
+static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int i = ARRAY_SIZE(s5k6aa_formats);
+
+ if (fse->index > 0)
+ return -EINVAL;
+
+ while (--i)
+ if (fse->code == s5k6aa_formats[i].code)
+ break;
+
+ fse->code = s5k6aa_formats[i].code;
+ fse->min_width = S5K6AA_WIN_WIDTH_MIN;
+ fse->max_width = S5K6AA_WIN_WIDTH_MAX;
+ fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
+ fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
+
+ return 0;
+}
+
+static struct v4l2_rect *
+__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return &s5k6aa->ccd_rect;
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, 0);
+
+ return NULL;
+}
+
+static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
+ struct v4l2_mbus_framefmt *mf)
+{
+ unsigned int index;
+
+ v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
+ S5K6AA_WIN_WIDTH_MAX, 1,
+ &mf->height, S5K6AA_WIN_HEIGHT_MIN,
+ S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+ if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
+ mf->colorspace != V4L2_COLORSPACE_REC709)
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
+
+ mf->colorspace = s5k6aa_formats[index].colorspace;
+ mf->code = s5k6aa_formats[index].code;
+ mf->field = V4L2_FIELD_NONE;
+}
+
+static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ memset(fmt->reserved, 0, sizeof(fmt->reserved));
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, 0);
+ fmt->format = *mf;
+ return 0;
+ }
+
+ mutex_lock(&s5k6aa->lock);
+ fmt->format = s5k6aa->preset->mbus_fmt;
+ mutex_unlock(&s5k6aa->lock);
+
+ return 0;
+}
+
+static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ struct s5k6aa_preset *preset = s5k6aa->preset;
+ struct v4l2_mbus_framefmt *mf;
+ struct v4l2_rect *crop;
+ int ret = 0;
+
+ mutex_lock(&s5k6aa->lock);
+ s5k6aa_try_format(s5k6aa, &fmt->format);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ crop = v4l2_subdev_get_try_crop(fh, 0);
+ } else {
+ if (s5k6aa->streaming) {
+ ret = -EBUSY;
+ } else {
+ mf = &preset->mbus_fmt;
+ crop = &s5k6aa->ccd_rect;
+ s5k6aa->apply_cfg = 1;
+ }
+ }
+
+ if (ret == 0) {
+ struct v4l2_subdev_frame_interval fiv = {
+ .interval = {0, 1}
+ };
+
+ *mf = fmt->format;
+ /*
+ * Make sure the crop window is valid, i.e. its size is
+ * greater than the output window, as the ISP supports
+ * only down-scaling.
+ */
+ crop->width = clamp_t(unsigned int, crop->width, mf->width,
+ S5K6AA_WIN_WIDTH_MAX);
+ crop->height = clamp_t(unsigned int, crop->height, mf->height,
+ S5K6AA_WIN_HEIGHT_MAX);
+ crop->left = clamp_t(unsigned int, crop->left, 0,
+ S5K6AA_WIN_WIDTH_MAX - crop->width);
+ crop->top = clamp_t(unsigned int, crop->top, 0,
+ S5K6AA_WIN_HEIGHT_MAX - crop->height);
+
+ /* Reset to minimum possible frame interval */
+ ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
+ }
+ mutex_unlock(&s5k6aa->lock);
+
+ return ret;
+}
+
+static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ struct v4l2_rect *rect;
+
+ memset(crop->reserved, 0, sizeof(crop->reserved));
+ mutex_lock(&s5k6aa->lock);
+
+ rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+ if (rect)
+ crop->rect = *rect;
+
+ mutex_unlock(&s5k6aa->lock);
+
+ v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
+ rect->left, rect->top, rect->width, rect->height);
+
+ return 0;
+}
+
+static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ struct v4l2_mbus_framefmt *mf;
+ unsigned int max_x, max_y;
+ struct v4l2_rect *crop_r;
+
+ mutex_lock(&s5k6aa->lock);
+ crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ mf = &s5k6aa->preset->mbus_fmt;
+ s5k6aa->apply_crop = 1;
+ } else {
+ mf = v4l2_subdev_get_try_format(fh, 0);
+ }
+ v4l_bound_align_image(&crop->rect.width, mf->width,
+ S5K6AA_WIN_WIDTH_MAX, 1,
+ &crop->rect.height, mf->height,
+ S5K6AA_WIN_HEIGHT_MAX, 1, 0);
+
+ max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1;
+ max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1;
+
+ crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x);
+ crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y);
+
+ *crop_r = crop->rect;
+
+ mutex_unlock(&s5k6aa->lock);
+
+ v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
+ crop_r->left, crop_r->top, crop_r->width, crop_r->height);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
+ .enum_mbus_code = s5k6aa_enum_mbus_code,
+ .enum_frame_size = s5k6aa_enum_frame_size,
+ .enum_frame_interval = s5k6aa_enum_frame_interval,
+ .get_fmt = s5k6aa_get_fmt,
+ .set_fmt = s5k6aa_set_fmt,
+ .get_crop = s5k6aa_get_crop,
+ .set_crop = s5k6aa_set_crop,
+};
+
+static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
+ .g_frame_interval = s5k6aa_g_frame_interval,
+ .s_frame_interval = s5k6aa_s_frame_interval,
+ .s_stream = s5k6aa_s_stream,
+};
+
+/*
+ * V4L2 subdev controls
+ */
+
+static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int idx, err = 0;
+
+ v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
+
+ mutex_lock(&s5k6aa->lock);
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any controls to H/W at this time. Instead
+ * the controls will be restored right after power-up.
+ */
+ if (s5k6aa->power == 0)
+ goto unlock;
+ idx = s5k6aa->preset->index;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = s5k6aa_set_awb(s5k6aa, ctrl->val);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
+ break;
+
+ case V4L2_CID_COLORFX:
+ err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
+ break;
+
+ case V4L2_CID_HFLIP:
+ err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
+ if (err)
+ break;
+ err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+ break;
+
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
+ break;
+
+ case V4L2_CID_SATURATION:
+ err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
+ break;
+
+ case V4L2_CID_SHARPNESS:
+ err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
+ break;
+
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
+ if (err)
+ break;
+ err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
+ break;
+ }
+unlock:
+ mutex_unlock(&s5k6aa->lock);
+ return err;
+}
+
+static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
+ .s_ctrl = s5k6aa_s_ctrl,
+};
+
+static int s5k6aa_log_status(struct v4l2_subdev *sd)
+{
+ v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+ return 0;
+}
+
+#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001)
+#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002)
+#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003)
+
+static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
+ {
+ .ops = &s5k6aa_ctrl_ops,
+ .id = V4L2_CID_RED_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain, Red",
+ .min = 0,
+ .max = 256,
+ .def = 127,
+ .step = 1,
+ }, {
+ .ops = &s5k6aa_ctrl_ops,
+ .id = V4L2_CID_GREEN_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain, Green",
+ .min = 0,
+ .max = 256,
+ .def = 127,
+ .step = 1,
+ }, {
+ .ops = &s5k6aa_ctrl_ops,
+ .id = V4L2_CID_BLUE_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain, Blue",
+ .min = 0,
+ .max = 256,
+ .def = 127,
+ .step = 1,
+ },
+};
+
+static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
+{
+ const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
+ struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ int ret = v4l2_ctrl_handler_init(hdl, 16);
+ if (ret)
+ return ret;
+ /* Auto white balance cluster */
+ ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
+ ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
+ ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
+ v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
+
+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &ctrls->hflip);
+
+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_EXPOSURE_AUTO,
+ V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+ /* Exposure time: x 1 us */
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+ 0, 6000000U, 1, 100000U);
+ /* Total gain: 256 <=> 1x */
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+ 0, 256, 1, 256);
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
+
+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+
+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
+ V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ 0, 256, 1, 0);
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ s5k6aa->sd.ctrl_handler = hdl;
+ return 0;
+}
+
+/*
+ * V4L2 subdev internal operations
+ */
+static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
+
+ format->colorspace = s5k6aa_formats[0].colorspace;
+ format->code = s5k6aa_formats[0].code;
+ format->width = S5K6AA_OUT_WIDTH_DEF;
+ format->height = S5K6AA_OUT_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+
+ crop->width = S5K6AA_WIN_WIDTH_MAX;
+ crop->height = S5K6AA_WIN_HEIGHT_MAX;
+ crop->left = 0;
+ crop->top = 0;
+
+ return 0;
+}
+
+static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+ u16 api_ver = 0, fw_rev = 0;
+
+ int ret = s5k6aa_set_ahb_address(client);
+
+ if (!ret)
+ ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
+ if (!ret)
+ ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
+ if (ret) {
+ v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
+ return ret;
+ }
+
+ v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
+ api_ver, fw_rev);
+
+ return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
+}
+
+static int s5k6aa_registered(struct v4l2_subdev *sd)
+{
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+ int ret;
+
+ mutex_lock(&s5k6aa->lock);
+ ret = __s5k6aa_power_on(s5k6aa);
+ if (!ret) {
+ msleep(100);
+ ret = s5k6aa_check_fw_revision(s5k6aa);
+ __s5k6aa_power_off(s5k6aa);
+ }
+ mutex_unlock(&s5k6aa->lock);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
+ .registered = s5k6aa_registered,
+ .open = s5k6aa_open,
+};
+
+static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
+ .s_power = s5k6aa_set_power,
+ .log_status = s5k6aa_log_status,
+};
+
+static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
+ .core = &s5k6aa_core_ops,
+ .pad = &s5k6aa_pad_ops,
+ .video = &s5k6aa_video_ops,
+};
+
+/*
+ * GPIO setup
+ */
+static int s5k6aa_configure_gpio(int nr, int val, const char *name)
+{
+ unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ int ret;
+
+ if (!gpio_is_valid(nr))
+ return 0;
+ ret = gpio_request_one(nr, flags, name);
+ if (!ret)
+ gpio_export(nr, 0);
+ return ret;
+}
+
+static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) {
+ if (!gpio_is_valid(s5k6aa->gpio[i].gpio))
+ continue;
+ gpio_free(s5k6aa->gpio[i].gpio);
+ s5k6aa->gpio[i].gpio = -EINVAL;
+ }
+}
+
+static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
+ const struct s5k6aa_platform_data *pdata)
+{
+ const struct s5k6aa_gpio *gpio = &pdata->gpio_stby;
+ int ret;
+
+ s5k6aa->gpio[STBY].gpio = -EINVAL;
+ s5k6aa->gpio[RST].gpio = -EINVAL;
+
+ ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY");
+ if (ret) {
+ s5k6aa_free_gpios(s5k6aa);
+ return ret;
+ }
+ s5k6aa->gpio[STBY] = *gpio;
+ if (gpio_is_valid(gpio->gpio))
+ gpio_set_value(gpio->gpio, 0);
+
+ gpio = &pdata->gpio_reset;
+ ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST");
+ if (ret) {
+ s5k6aa_free_gpios(s5k6aa);
+ return ret;
+ }
+ s5k6aa->gpio[RST] = *gpio;
+ if (gpio_is_valid(gpio->gpio))
+ gpio_set_value(gpio->gpio, 0);
+
+ return 0;
+}
+
+static int s5k6aa_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
+ struct v4l2_subdev *sd;
+ struct s5k6aa *s5k6aa;
+ int i, ret;
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "Platform data not specified\n");
+ return -EINVAL;
+ }
+
+ if (pdata->mclk_frequency == 0) {
+ dev_err(&client->dev, "MCLK frequency not specified\n");
+ return -EINVAL;
+ }
+
+ s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL);
+ if (!s5k6aa)
+ return -ENOMEM;
+
+ mutex_init(&s5k6aa->lock);
+
+ s5k6aa->mclk_frequency = pdata->mclk_frequency;
+ s5k6aa->bus_type = pdata->bus_type;
+ s5k6aa->mipi_lanes = pdata->nlanes;
+ s5k6aa->s_power = pdata->set_power;
+ s5k6aa->inv_hflip = pdata->horiz_flip;
+ s5k6aa->inv_vflip = pdata->vert_flip;
+
+ sd = &s5k6aa->sd;
+ 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;
+
+ s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0);
+ if (ret)
+ return ret;
+
+ ret = s5k6aa_configure_gpios(s5k6aa, pdata);
+ if (ret)
+ goto out_err2;
+
+ for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
+ s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
+
+ ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
+ s5k6aa->supplies);
+ if (ret) {
+ dev_err(&client->dev, "Failed to get regulators\n");
+ goto out_err3;
+ }
+
+ ret = s5k6aa_initialize_ctrls(s5k6aa);
+ if (ret)
+ goto out_err4;
+
+ s5k6aa_presets_data_init(s5k6aa);
+
+ s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
+ s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX;
+ s5k6aa->ccd_rect.left = 0;
+ s5k6aa->ccd_rect.top = 0;
+
+ return 0;
+
+out_err4:
+ regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+out_err3:
+ s5k6aa_free_gpios(s5k6aa);
+out_err2:
+ media_entity_cleanup(&s5k6aa->sd.entity);
+ return ret;
+}
+
+static int s5k6aa_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct s5k6aa *s5k6aa = to_s5k6aa(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ media_entity_cleanup(&sd->entity);
+ regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
+ s5k6aa_free_gpios(s5k6aa);
+
+ return 0;
+}
+
+static const struct i2c_device_id s5k6aa_id[] = {
+ { DRIVER_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
+
+
+static struct i2c_driver s5k6aa_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME
+ },
+ .probe = s5k6aa_probe,
+ .remove = s5k6aa_remove,
+ .id_table = s5k6aa_id,
+};
+
+module_i2c_driver(s5k6aa_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/saa6588.c b/drivers/media/i2c/saa6588.c
index 0caac50d7cf4..0caac50d7cf4 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
diff --git a/drivers/media/video/saa7110.c b/drivers/media/i2c/saa7110.c
index 51cd4c8f0520..51cd4c8f0520 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
diff --git a/drivers/media/video/saa7115.c b/drivers/media/i2c/saa7115.c
index 2107336cd836..2107336cd836 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
diff --git a/drivers/media/video/saa711x_regs.h b/drivers/media/i2c/saa711x_regs.h
index 4e5f2eb0a2c1..4e5f2eb0a2c1 100644
--- a/drivers/media/video/saa711x_regs.h
+++ b/drivers/media/i2c/saa711x_regs.h
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
new file mode 100644
index 000000000000..8ecb6564a315
--- /dev/null
+++ b/drivers/media/i2c/saa7127.c
@@ -0,0 +1,852 @@
+/*
+ * saa7127 - Philips SAA7127/SAA7129 video encoder driver
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * from the ivtv Project
+ *
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * Dual output support:
+ * Copyright (C) 2004 Eric Varsanyi
+ *
+ * NTSC Tuning and 7.5 IRE Setup
+ * Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ *
+ * VBI additions & cleanup:
+ * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: the saa7126 is identical to the saa7127, and the saa7128 is
+ * identical to the saa7129, except that the saa7126 and saa7128 have
+ * macrovision anti-taping support. This driver will almost certainly
+ * work fine for those chips, except of course for the missing anti-taping
+ * support.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/saa7127.h>
+
+static int debug;
+static int test_image;
+
+MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0644);
+module_param(test_image, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+MODULE_PARM_DESC(test_image, "test_image (0-1)");
+
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS 0x00
+#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
+#define SAA7127_REG_BURST_START 0x28
+#define SAA7127_REG_BURST_END 0x29
+#define SAA7127_REG_COPYGEN_0 0x2a
+#define SAA7127_REG_COPYGEN_1 0x2b
+#define SAA7127_REG_COPYGEN_2 0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
+#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
+#define SAA7129_REG_FADE_KEY_COL2 0x4f
+#define SAA7127_REG_CHROMA_PHASE 0x5a
+#define SAA7127_REG_GAINU 0x5b
+#define SAA7127_REG_GAINV 0x5c
+#define SAA7127_REG_BLACK_LEVEL 0x5d
+#define SAA7127_REG_BLANKING_LEVEL 0x5e
+#define SAA7127_REG_VBI_BLANKING 0x5f
+#define SAA7127_REG_DAC_CONTROL 0x61
+#define SAA7127_REG_BURST_AMP 0x62
+#define SAA7127_REG_SUBC3 0x63
+#define SAA7127_REG_SUBC2 0x64
+#define SAA7127_REG_SUBC1 0x65
+#define SAA7127_REG_SUBC0 0x66
+#define SAA7127_REG_LINE_21_ODD_0 0x67
+#define SAA7127_REG_LINE_21_ODD_1 0x68
+#define SAA7127_REG_LINE_21_EVEN_0 0x69
+#define SAA7127_REG_LINE_21_EVEN_1 0x6a
+#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
+#define SAA7127_REG_VTRIG 0x6c
+#define SAA7127_REG_HTRIG_HI 0x6d
+#define SAA7127_REG_MULTI 0x6e
+#define SAA7127_REG_CLOSED_CAPTION 0x6f
+#define SAA7127_REG_RCV2_OUTPUT_START 0x70
+#define SAA7127_REG_RCV2_OUTPUT_END 0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START 0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
+#define SAA7127_REG_FIRST_ACTIVE 0x7a
+#define SAA7127_REG_LAST_ACTIVE 0x7b
+#define SAA7127_REG_MSB_VERTICAL 0x7c
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
+
+/*
+ **********************************************************************
+ *
+ * Arrays with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value {
+ unsigned char reg;
+ unsigned char value;
+};
+
+static const struct i2c_reg_value saa7129_init_config_extra[] = {
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
+ { SAA7127_REG_VTRIG, 0xfa },
+ { 0, 0 }
+};
+
+static const struct i2c_reg_value saa7127_init_config_common[] = {
+ { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
+ { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
+ { SAA7127_REG_COPYGEN_0, 0x77 },
+ { SAA7127_REG_COPYGEN_1, 0x41 },
+ { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf },
+ { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
+ { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
+ { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */
+ { SAA7127_REG_LINE_21_ODD_0, 0x77 },
+ { SAA7127_REG_LINE_21_ODD_1, 0x41 },
+ { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
+ { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
+ { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
+ { SAA7127_REG_VTRIG, 0xf9 },
+ { SAA7127_REG_HTRIG_HI, 0x00 },
+ { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
+ { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
+ { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
+ { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
+ { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
+ { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_FIRST_ACTIVE, 0x1a },
+ { SAA7127_REG_LAST_ACTIVE, 0x01 },
+ { SAA7127_REG_MSB_VERTICAL, 0xc0 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
+ { 0, 0 }
+};
+
+#define SAA7127_60HZ_DAC_CONTROL 0x15
+static const struct i2c_reg_value saa7127_init_config_60hz[] = {
+ { SAA7127_REG_BURST_START, 0x19 },
+ /* BURST_END is also used as a chip ID in saa7127_probe */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0xa3 },
+ { SAA7127_REG_GAINU, 0x98 },
+ { SAA7127_REG_GAINV, 0xd3 },
+ { SAA7127_REG_BLACK_LEVEL, 0x39 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x2e },
+ { SAA7127_REG_VBI_BLANKING, 0x2e },
+ { SAA7127_REG_DAC_CONTROL, 0x15 },
+ { SAA7127_REG_BURST_AMP, 0x4d },
+ { SAA7127_REG_SUBC3, 0x1f },
+ { SAA7127_REG_SUBC2, 0x7c },
+ { SAA7127_REG_SUBC1, 0xf0 },
+ { SAA7127_REG_SUBC0, 0x21 },
+ { SAA7127_REG_MULTI, 0x90 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x11 },
+ { 0, 0 }
+};
+
+#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
+static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
+ { SAA7127_REG_BURST_START, 0x21 },
+ /* BURST_END is also used as a chip ID in saa7127_probe */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0x3f },
+ { SAA7127_REG_GAINU, 0x7d },
+ { SAA7127_REG_GAINV, 0xaf },
+ { SAA7127_REG_BLACK_LEVEL, 0x33 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x35 },
+ { SAA7127_REG_VBI_BLANKING, 0x35 },
+ { SAA7127_REG_DAC_CONTROL, 0x02 },
+ { SAA7127_REG_BURST_AMP, 0x2f },
+ { SAA7127_REG_SUBC3, 0xcb },
+ { SAA7127_REG_SUBC2, 0x8a },
+ { SAA7127_REG_SUBC1, 0x09 },
+ { SAA7127_REG_SUBC0, 0x2a },
+ { SAA7127_REG_MULTI, 0xa0 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x00 },
+ { 0, 0 }
+};
+
+#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
+static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
+ { SAA7127_REG_BURST_START, 0x21 },
+ /* BURST_END is also used as a chip ID in saa7127_probe */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0x3f },
+ { SAA7127_REG_GAINU, 0x6a },
+ { SAA7127_REG_GAINV, 0x81 },
+ { SAA7127_REG_BLACK_LEVEL, 0x33 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x35 },
+ { SAA7127_REG_VBI_BLANKING, 0x35 },
+ { SAA7127_REG_DAC_CONTROL, 0x08 },
+ { SAA7127_REG_BURST_AMP, 0x2f },
+ { SAA7127_REG_SUBC3, 0xb2 },
+ { SAA7127_REG_SUBC2, 0x3b },
+ { SAA7127_REG_SUBC1, 0xa3 },
+ { SAA7127_REG_SUBC0, 0x28 },
+ { SAA7127_REG_MULTI, 0x90 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x00 },
+ { 0, 0 }
+};
+
+/*
+ **********************************************************************
+ *
+ * Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127_state {
+ struct v4l2_subdev sd;
+ v4l2_std_id std;
+ u32 ident;
+ enum saa7127_input_type input_type;
+ enum saa7127_output_type output_type;
+ int video_enable;
+ int wss_enable;
+ u16 wss_mode;
+ int cc_enable;
+ u16 cc_data;
+ int xds_enable;
+ u16 xds_data;
+ int vps_enable;
+ u8 vps_data[5];
+ u8 reg_2d;
+ u8 reg_3a;
+ u8 reg_3a_cb; /* colorbar bit */
+ u8 reg_61;
+};
+
+static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7127_state, sd);
+}
+
+static const char * const output_strs[] =
+{
+ "S-Video + Composite",
+ "Composite",
+ "S-Video",
+ "RGB",
+ "YUV C",
+ "YUV V"
+};
+
+static const char * const wss_strs[] = {
+ "invalid",
+ "letterbox 14:9 center",
+ "letterbox 14:9 top",
+ "invalid",
+ "letterbox 16:9 top",
+ "invalid",
+ "invalid",
+ "16:9 full format anamorphic",
+ "4:3 full format",
+ "invalid",
+ "invalid",
+ "letterbox 16:9 center",
+ "invalid",
+ "letterbox >16:9 center",
+ "14:9 full format center",
+ "invalid",
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, reg, val) == 0)
+ return 0;
+ }
+ v4l2_err(sd, "I2C Write Problem\n");
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct v4l2_subdev *sd,
+ const struct i2c_reg_value *regs)
+{
+ while (regs->reg != 0) {
+ saa7127_write(sd, regs->reg, regs->value);
+ regs++;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = to_state(sd);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 16))
+ return -EINVAL;
+ if (state->vps_enable != enable) {
+ v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
+ saa7127_write(sd, 0x54, enable << 7);
+ state->vps_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ state->vps_data[0] = data->data[2];
+ state->vps_data[1] = data->data[8];
+ state->vps_data[2] = data->data[9];
+ state->vps_data[3] = data->data[10];
+ state->vps_data[4] = data->data[11];
+ v4l2_dbg(1, debug, sd, "Set VPS data %*ph\n", 5, state->vps_data);
+ saa7127_write(sd, 0x55, state->vps_data[0]);
+ saa7127_write(sd, 0x56, state->vps_data[1]);
+ saa7127_write(sd, 0x57, state->vps_data[2]);
+ saa7127_write(sd, 0x58, state->vps_data[3]);
+ saa7127_write(sd, 0x59, state->vps_data[4]);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = to_state(sd);
+ u16 cc = data->data[1] << 8 | data->data[0];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 21))
+ return -EINVAL;
+ if (state->cc_enable != enable) {
+ v4l2_dbg(1, debug, sd,
+ "Turn CC %s\n", enable ? "on" : "off");
+ saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
+ (state->xds_enable << 7) | (enable << 6) | 0x11);
+ state->cc_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
+ saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+ saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+ state->cc_data = cc;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = to_state(sd);
+ u16 xds = data->data[1] << 8 | data->data[0];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 1 || data->line != 21))
+ return -EINVAL;
+ if (state->xds_enable != enable) {
+ v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
+ saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
+ (enable << 7) | (state->cc_enable << 6) | 0x11);
+ state->xds_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
+ saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+ saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+ state->xds_data = xds;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = to_state(sd);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 23))
+ return -EINVAL;
+ if (state->wss_enable != enable) {
+ v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
+ saa7127_write(sd, 0x27, enable << 7);
+ state->wss_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_write(sd, 0x26, data->data[0]);
+ saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
+ v4l2_dbg(1, debug, sd,
+ "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+ state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ if (enable) {
+ v4l2_dbg(1, debug, sd, "Enable Video Output\n");
+ saa7127_write(sd, 0x2d, state->reg_2d);
+ saa7127_write(sd, 0x61, state->reg_61);
+ } else {
+ v4l2_dbg(1, debug, sd, "Disable Video Output\n");
+ saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
+ saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
+ }
+ state->video_enable = enable;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct saa7127_state *state = to_state(sd);
+ const struct i2c_reg_value *inittab;
+
+ if (std & V4L2_STD_525_60) {
+ v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
+ inittab = saa7127_init_config_60hz;
+ state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+
+ } else if (state->ident == V4L2_IDENT_SAA7129 &&
+ (std & V4L2_STD_SECAM) &&
+ !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
+
+ /* If and only if SECAM, with a SAA712[89] */
+ v4l2_dbg(1, debug, sd,
+ "Selecting 50 Hz SECAM video Standard\n");
+ inittab = saa7127_init_config_50hz_secam;
+ state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
+
+ } else {
+ v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
+ inittab = saa7127_init_config_50hz_pal;
+ state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
+ }
+
+ /* Write Table */
+ saa7127_write_inittab(sd, inittab);
+ state->std = std;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ switch (output) {
+ case SAA7127_OUTPUT_TYPE_RGB:
+ state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_COMPOSITE:
+ if (state->ident == V4L2_IDENT_SAA7129)
+ state->reg_2d = 0x20; /* CVBS only */
+ else
+ state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_SVIDEO:
+ if (state->ident == V4L2_IDENT_SAA7129)
+ state->reg_2d = 0x18; /* Y + C */
+ else
+ state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_V:
+ state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_C:
+ state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_BOTH:
+ if (state->ident == V4L2_IDENT_SAA7129)
+ state->reg_2d = 0x38;
+ else
+ state->reg_2d = 0xbf;
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ v4l2_dbg(1, debug, sd,
+ "Selecting %s output type\n", output_strs[output]);
+
+ /* Configure Encoder */
+ saa7127_write(sd, 0x2d, state->reg_2d);
+ saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->output_type = output;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ switch (input) {
+ case SAA7127_INPUT_TYPE_NORMAL: /* avia */
+ v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
+ state->reg_3a_cb = 0;
+ break;
+
+ case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
+ v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
+ state->reg_3a_cb = 0x80;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->input_type = input;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ if (state->std == std)
+ return 0;
+ return saa7127_set_std(sd, std);
+}
+
+static int saa7127_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ struct saa7127_state *state = to_state(sd);
+ int rc = 0;
+
+ if (state->input_type != input)
+ rc = saa7127_set_input_type(sd, input);
+ if (rc == 0 && state->output_type != output)
+ rc = saa7127_set_output_type(sd, output);
+ return rc;
+}
+
+static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ if (state->video_enable == enable)
+ return 0;
+ return saa7127_set_video_enable(sd, enable);
+}
+
+static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ memset(fmt, 0, sizeof(*fmt));
+ if (state->vps_enable)
+ fmt->service_lines[0][16] = V4L2_SLICED_VPS;
+ if (state->wss_enable)
+ fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+ if (state->cc_enable) {
+ fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+ }
+ fmt->service_set =
+ (state->vps_enable ? V4L2_SLICED_VPS : 0) |
+ (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+ (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+ return 0;
+}
+
+static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ return saa7127_set_wss(sd, data);
+ case V4L2_SLICED_VPS:
+ return saa7127_set_vps(sd, data);
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0)
+ return saa7127_set_cc(sd, data);
+ return saa7127_set_xds(sd, data);
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa7127_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 = saa7127_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
+
+static int saa7127_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;
+ saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct saa7127_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
+
+static int saa7127_log_status(struct v4l2_subdev *sd)
+{
+ struct saa7127_state *state = to_state(sd);
+
+ v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+ v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal");
+ v4l2_info(sd, "Output: %s\n", state->video_enable ?
+ output_strs[state->output_type] : "disabled");
+ v4l2_info(sd, "WSS: %s\n", state->wss_enable ?
+ wss_strs[state->wss_mode] : "disabled");
+ v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
+ v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7127_core_ops = {
+ .log_status = saa7127_log_status,
+ .g_chip_ident = saa7127_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = saa7127_g_register,
+ .s_register = saa7127_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops saa7127_video_ops = {
+ .s_std_output = saa7127_s_std_output,
+ .s_routing = saa7127_s_routing,
+ .s_stream = saa7127_s_stream,
+};
+
+static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
+ .s_vbi_data = saa7127_s_vbi_data,
+ .g_sliced_fmt = saa7127_g_sliced_fmt,
+};
+
+static const struct v4l2_subdev_ops saa7127_ops = {
+ .core = &saa7127_core_ops,
+ .video = &saa7127_video_ops,
+ .vbi = &saa7127_vbi_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct saa7127_state *state;
+ struct v4l2_subdev *sd;
+ struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
+ client->addr << 1);
+
+ state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+ if (state == NULL)
+ return -ENOMEM;
+
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
+
+ /* First test register 0: Bits 5-7 are a version ID (should be 0),
+ and bit 2 should also be 0.
+ This is rather general, so the second test is more specific and
+ looks at the 'ending point of burst in clock cycles' which is
+ 0x1d after a reset and not expected to ever change. */
+ if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
+ (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
+ v4l2_dbg(1, debug, sd, "saa7127 not found\n");
+ kfree(state);
+ return -ENODEV;
+ }
+
+ if (id->driver_data) { /* Chip type is already known */
+ state->ident = id->driver_data;
+ } else { /* Needs detection */
+ int read_result;
+
+ /* Detect if it's an saa7129 */
+ read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
+ saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+ if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+ saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
+ read_result);
+ state->ident = V4L2_IDENT_SAA7129;
+ strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
+ } else {
+ state->ident = V4L2_IDENT_SAA7127;
+ strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
+ }
+ }
+
+ v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+ client->addr << 1, client->adapter->name);
+
+ v4l2_dbg(1, debug, sd, "Configuring encoder\n");
+ saa7127_write_inittab(sd, saa7127_init_config_common);
+ saa7127_set_std(sd, V4L2_STD_NTSC);
+ saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
+ saa7127_set_vps(sd, &vbi);
+ saa7127_set_wss(sd, &vbi);
+ saa7127_set_cc(sd, &vbi);
+ saa7127_set_xds(sd, &vbi);
+ if (test_image == 1)
+ /* The Encoder has an internal Colorbar generator */
+ /* This can be used for debugging */
+ saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
+ else
+ saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
+ saa7127_set_video_enable(sd, 1);
+
+ if (state->ident == V4L2_IDENT_SAA7129)
+ saa7127_write_inittab(sd, saa7129_init_config_extra);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ /* Turn off TV output */
+ saa7127_set_video_enable(sd, 0);
+ kfree(to_state(sd));
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_device_id saa7127_id[] = {
+ { "saa7127_auto", 0 }, /* auto-detection */
+ { "saa7126", V4L2_IDENT_SAA7127 },
+ { "saa7127", V4L2_IDENT_SAA7127 },
+ { "saa7128", V4L2_IDENT_SAA7129 },
+ { "saa7129", V4L2_IDENT_SAA7129 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
+static struct i2c_driver saa7127_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7127",
+ },
+ .probe = saa7127_probe,
+ .remove = saa7127_remove,
+ .id_table = saa7127_id,
+};
+
+module_i2c_driver(saa7127_driver);
diff --git a/drivers/media/video/saa717x.c b/drivers/media/i2c/saa717x.c
index 1e84466515aa..1e84466515aa 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
diff --git a/drivers/media/video/saa7185.c b/drivers/media/i2c/saa7185.c
index 2c6b65c76e2b..2c6b65c76e2b 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/i2c/saa7185.c
diff --git a/drivers/media/video/saa7191.c b/drivers/media/i2c/saa7191.c
index d7d1670e0ca3..d7d1670e0ca3 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/i2c/saa7191.c
diff --git a/drivers/media/video/saa7191.h b/drivers/media/i2c/saa7191.h
index 803c74d6066f..803c74d6066f 100644
--- a/drivers/media/video/saa7191.h
+++ b/drivers/media/i2c/saa7191.h
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
new file mode 100644
index 000000000000..a577614bd84f
--- /dev/null
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -0,0 +1,418 @@
+/*
+ * drivers/media/i2c/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/gcd.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "smiapp-pll.h"
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+ return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+ if (a == 1)
+ return 1;
+ return (a + 1) & ~1;
+}
+
+static inline uint32_t is_one_or_even(uint32_t a)
+{
+ if (a == 1)
+ return 1;
+ if (a & 1)
+ return 0;
+
+ return 1;
+}
+
+static int bounds_check(struct device *dev, uint32_t val,
+ uint32_t min, uint32_t max, char *str)
+{
+ if (val >= min && val <= max)
+ return 0;
+
+ dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+
+ return -EINVAL;
+}
+
+static void print_pll(struct device *dev, struct smiapp_pll *pll)
+{
+ dev_dbg(dev, "pre_pll_clk_div\t%d\n", pll->pre_pll_clk_div);
+ dev_dbg(dev, "pll_multiplier \t%d\n", pll->pll_multiplier);
+ if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
+ dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
+ }
+ dev_dbg(dev, "vt_sys_clk_div \t%d\n", pll->vt_sys_clk_div);
+ dev_dbg(dev, "vt_pix_clk_div \t%d\n", pll->vt_pix_clk_div);
+
+ dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
+ dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
+ dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
+ if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
+ pll->op_sys_clk_freq_hz);
+ dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
+ pll->op_pix_clk_freq_hz);
+ }
+ dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
+ dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
+}
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+ struct smiapp_pll *pll)
+{
+ uint32_t sys_div;
+ uint32_t best_pix_div = INT_MAX >> 1;
+ uint32_t vt_op_binning_div;
+ uint32_t lane_op_clock_ratio;
+ uint32_t mul, div;
+ uint32_t more_mul_min, more_mul_max;
+ uint32_t more_mul_factor;
+ uint32_t min_vt_div, max_vt_div, vt_div;
+ uint32_t min_sys_div, max_sys_div;
+ unsigned int i;
+ int rval;
+
+ if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
+ lane_op_clock_ratio = pll->lanes;
+ else
+ lane_op_clock_ratio = 1;
+ dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+
+ dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
+ pll->binning_vertical);
+
+ /* CSI transfers 2 bits per clock per lane; thus times 2 */
+ pll->pll_op_clk_freq_hz = pll->link_freq * 2
+ * (pll->lanes / lane_op_clock_ratio);
+
+ /* Figure out limits for pre-pll divider based on extclk */
+ dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+ limits->max_pre_pll_clk_div =
+ min_t(uint16_t, limits->max_pre_pll_clk_div,
+ clk_div_even(pll->ext_clk_freq_hz /
+ limits->min_pll_ip_freq_hz));
+ limits->min_pre_pll_clk_div =
+ max_t(uint16_t, limits->min_pre_pll_clk_div,
+ clk_div_even_up(
+ DIV_ROUND_UP(pll->ext_clk_freq_hz,
+ limits->max_pll_ip_freq_hz)));
+ dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+ i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
+ mul = div_u64(pll->pll_op_clk_freq_hz, i);
+ div = pll->ext_clk_freq_hz / i;
+ dev_dbg(dev, "mul %d / div %d\n", mul, div);
+
+ limits->min_pre_pll_clk_div =
+ max_t(uint16_t, limits->min_pre_pll_clk_div,
+ clk_div_even_up(
+ DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+ limits->max_pll_op_freq_hz)));
+ dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+ if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
+ dev_err(dev, "unable to compute pre_pll divisor\n");
+ return -EINVAL;
+ }
+
+ pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
+
+ /*
+ * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+ * too high.
+ */
+ dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+
+ /* Don't go above max pll multiplier. */
+ more_mul_max = limits->max_pll_multiplier / mul;
+ dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
+ more_mul_max);
+ /* Don't go above max pll op frequency. */
+ more_mul_max =
+ min_t(int,
+ more_mul_max,
+ limits->max_pll_op_freq_hz
+ / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+ dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+ more_mul_max);
+ /* Don't go above the division capability of op sys clock divider. */
+ more_mul_max = min(more_mul_max,
+ limits->max_op_sys_clk_div * pll->pre_pll_clk_div
+ / div);
+ dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+ more_mul_max);
+ /* Ensure we won't go above min_pll_multiplier. */
+ more_mul_max = min(more_mul_max,
+ DIV_ROUND_UP(limits->max_pll_multiplier, mul));
+ dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
+ more_mul_max);
+
+ /* Ensure we won't go below min_pll_op_freq_hz. */
+ more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
+ pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+ * mul);
+ dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+ more_mul_min);
+ /* Ensure we won't go below min_pll_multiplier. */
+ more_mul_min = max(more_mul_min,
+ DIV_ROUND_UP(limits->min_pll_multiplier, mul));
+ dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
+ more_mul_min);
+
+ if (more_mul_min > more_mul_max) {
+ dev_warn(dev,
+ "unable to compute more_mul_min and more_mul_max");
+ return -EINVAL;
+ }
+
+ more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+ dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
+ more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div);
+ dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+ more_mul_factor);
+ i = roundup(more_mul_min, more_mul_factor);
+ if (!is_one_or_even(i))
+ i <<= 1;
+
+ dev_dbg(dev, "final more_mul: %d\n", i);
+ if (i > more_mul_max) {
+ dev_warn(dev, "final more_mul is bad, max %d", more_mul_max);
+ return -EINVAL;
+ }
+
+ pll->pll_multiplier = mul * i;
+ pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
+ dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+
+ pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+ / pll->pre_pll_clk_div;
+
+ pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+ * pll->pll_multiplier;
+
+ /* Derive pll_op_clk_freq_hz. */
+ pll->op_sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+
+ pll->op_pix_clk_div = pll->bits_per_pixel;
+ dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+
+ pll->op_pix_clk_freq_hz =
+ pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+
+ /*
+ * Some sensors perform analogue binning and some do this
+ * digitally. The ones doing this digitally can be roughly be
+ * found out using this formula. The ones doing this digitally
+ * should run at higher clock rate, so smaller divisor is used
+ * on video timing side.
+ */
+ if (limits->min_line_length_pck_bin > limits->min_line_length_pck
+ / pll->binning_horizontal)
+ vt_op_binning_div = pll->binning_horizontal;
+ else
+ vt_op_binning_div = 1;
+ dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+
+ /*
+ * Profile 2 supports vt_pix_clk_div E [4, 10]
+ *
+ * Horizontal binning can be used as a base for difference in
+ * divisors. One must make sure that horizontal blanking is
+ * enough to accommodate the CSI-2 sync codes.
+ *
+ * Take scaling factor into account as well.
+ *
+ * Find absolute limits for the factor of vt divider.
+ */
+ dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
+ min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+ * pll->scale_n,
+ lane_op_clock_ratio * vt_op_binning_div
+ * pll->scale_m);
+
+ /* Find smallest and biggest allowed vt divisor. */
+ dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
+ min_vt_div = max(min_vt_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->max_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+ min_vt_div);
+ min_vt_div = max_t(uint32_t, min_vt_div,
+ limits->min_vt_pix_clk_div
+ * limits->min_vt_sys_clk_div);
+ dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
+
+ max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div;
+ dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
+ max_vt_div = min(max_vt_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
+ max_vt_div);
+
+ /*
+ * Find limitsits for sys_clk_div. Not all values are possible
+ * with all values of pix_clk_div.
+ */
+ min_sys_div = limits->min_vt_sys_clk_div;
+ dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
+ min_sys_div = max(min_sys_div,
+ DIV_ROUND_UP(min_vt_div,
+ limits->max_vt_pix_clk_div));
+ dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
+ min_sys_div = max(min_sys_div,
+ pll->pll_op_clk_freq_hz
+ / limits->max_vt_sys_clk_freq_hz);
+ dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
+ min_sys_div = clk_div_even_up(min_sys_div);
+ dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
+
+ max_sys_div = limits->max_vt_sys_clk_div;
+ dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
+ max_sys_div = min(max_sys_div,
+ DIV_ROUND_UP(max_vt_div,
+ limits->min_vt_pix_clk_div));
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
+ max_sys_div = min(max_sys_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
+
+ /*
+ * Find pix_div such that a legal pix_div * sys_div results
+ * into a value which is not smaller than div, the desired
+ * divisor.
+ */
+ for (vt_div = min_vt_div; vt_div <= max_vt_div;
+ vt_div += 2 - (vt_div & 1)) {
+ for (sys_div = min_sys_div;
+ sys_div <= max_sys_div;
+ sys_div += 2 - (sys_div & 1)) {
+ int pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+ if (pix_div < limits->min_vt_pix_clk_div
+ || pix_div > limits->max_vt_pix_clk_div) {
+ dev_dbg(dev,
+ "pix_div %d too small or too big (%d--%d)\n",
+ pix_div,
+ limits->min_vt_pix_clk_div,
+ limits->max_vt_pix_clk_div);
+ continue;
+ }
+
+ /* Check if this one is better. */
+ if (pix_div * sys_div
+ <= roundup(min_vt_div, best_pix_div))
+ best_pix_div = pix_div;
+ }
+ if (best_pix_div < INT_MAX >> 1)
+ break;
+ }
+
+ pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+ pll->vt_pix_clk_div = best_pix_div;
+
+ pll->vt_sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
+ pll->vt_pix_clk_freq_hz =
+ pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+
+ pll->pixel_rate_csi =
+ pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
+
+ print_pll(dev, pll);
+
+ rval = bounds_check(dev, pll->pre_pll_clk_div,
+ limits->min_pre_pll_clk_div,
+ limits->max_pre_pll_clk_div, "pre_pll_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_ip_clk_freq_hz,
+ limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz,
+ "pll_ip_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_multiplier,
+ limits->min_pll_multiplier, limits->max_pll_multiplier,
+ "pll_multiplier");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_op_clk_freq_hz,
+ limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+ "pll_op_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_sys_clk_div,
+ limits->min_op_sys_clk_div, limits->max_op_sys_clk_div,
+ "op_sys_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_pix_clk_div,
+ limits->min_op_pix_clk_div, limits->max_op_pix_clk_div,
+ "op_pix_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_sys_clk_freq_hz,
+ limits->min_op_sys_clk_freq_hz,
+ limits->max_op_sys_clk_freq_hz,
+ "op_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_pix_clk_freq_hz,
+ limits->min_op_pix_clk_freq_hz,
+ limits->max_op_pix_clk_freq_hz,
+ "op_pix_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt_sys_clk_freq_hz,
+ limits->min_vt_sys_clk_freq_hz,
+ limits->max_vt_sys_clk_freq_hz,
+ "vt_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt_pix_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz,
+ limits->max_vt_pix_clk_freq_hz,
+ "vt_pix_clk_freq_hz");
+
+ return rval;
+}
+EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
new file mode 100644
index 000000000000..cb2d2db5d02d
--- /dev/null
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -0,0 +1,103 @@
+/*
+ * drivers/media/i2c/smiapp-pll.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 SMIAPP_PLL_H
+#define SMIAPP_PLL_H
+
+#include <linux/device.h>
+
+struct smiapp_pll {
+ uint8_t lanes;
+ uint8_t binning_horizontal;
+ uint8_t binning_vertical;
+ uint8_t scale_m;
+ uint8_t scale_n;
+ uint8_t bits_per_pixel;
+ uint16_t flags;
+ uint32_t link_freq;
+
+ uint16_t pre_pll_clk_div;
+ uint16_t pll_multiplier;
+ uint16_t op_sys_clk_div;
+ uint16_t op_pix_clk_div;
+ uint16_t vt_sys_clk_div;
+ uint16_t vt_pix_clk_div;
+
+ uint32_t ext_clk_freq_hz;
+ uint32_t pll_ip_clk_freq_hz;
+ uint32_t pll_op_clk_freq_hz;
+ uint32_t op_sys_clk_freq_hz;
+ uint32_t op_pix_clk_freq_hz;
+ uint32_t vt_sys_clk_freq_hz;
+ uint32_t vt_pix_clk_freq_hz;
+
+ uint32_t pixel_rate_csi;
+};
+
+struct smiapp_pll_limits {
+ /* Strict PLL limits */
+ uint32_t min_ext_clk_freq_hz;
+ uint32_t max_ext_clk_freq_hz;
+ uint16_t min_pre_pll_clk_div;
+ uint16_t max_pre_pll_clk_div;
+ uint32_t min_pll_ip_freq_hz;
+ uint32_t max_pll_ip_freq_hz;
+ uint16_t min_pll_multiplier;
+ uint16_t max_pll_multiplier;
+ uint32_t min_pll_op_freq_hz;
+ uint32_t max_pll_op_freq_hz;
+
+ uint16_t min_vt_sys_clk_div;
+ uint16_t max_vt_sys_clk_div;
+ uint32_t min_vt_sys_clk_freq_hz;
+ uint32_t max_vt_sys_clk_freq_hz;
+ uint16_t min_vt_pix_clk_div;
+ uint16_t max_vt_pix_clk_div;
+ uint32_t min_vt_pix_clk_freq_hz;
+ uint32_t max_vt_pix_clk_freq_hz;
+
+ uint16_t min_op_sys_clk_div;
+ uint16_t max_op_sys_clk_div;
+ uint32_t min_op_sys_clk_freq_hz;
+ uint32_t max_op_sys_clk_freq_hz;
+ uint16_t min_op_pix_clk_div;
+ uint16_t max_op_pix_clk_div;
+ uint32_t min_op_pix_clk_freq_hz;
+ uint32_t max_op_pix_clk_freq_hz;
+
+ /* Other relevant limits */
+ uint32_t min_line_length_pck_bin;
+ uint32_t min_line_length_pck;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
+#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1)
+
+struct device;
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+ struct smiapp_pll *pll);
+
+#endif /* SMIAPP_PLL_H */
diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig
index 3149cda1d0db..3149cda1d0db 100644
--- a/drivers/media/video/smiapp/Kconfig
+++ b/drivers/media/i2c/smiapp/Kconfig
diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile
new file mode 100644
index 000000000000..f45a003cbe7e
--- /dev/null
+++ b/drivers/media/i2c/smiapp/Makefile
@@ -0,0 +1,5 @@
+smiapp-objs += smiapp-core.o smiapp-regs.o \
+ smiapp-quirk.o smiapp-limits.o
+obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
new file mode 100644
index 000000000000..1cf914d11345
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -0,0 +1,2895 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-core.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on smiapp driver by Vimarsh Zutshi
+ * Based on jt8ev1.c by Vimarsh Zutshi
+ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+
+#include "smiapp.h"
+
+#define SMIAPP_ALIGN_DIM(dim, flags) \
+ ((flags) & V4L2_SEL_FLAG_GE \
+ ? ALIGN((dim), 2) \
+ : (dim) & ~1)
+
+/*
+ * smiapp_module_idents - supported camera modules
+ */
+static const struct smiapp_module_ident smiapp_module_idents[] = {
+ SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
+ SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
+ SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
+ SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
+ SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
+ SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
+ SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
+ SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
+ SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
+ SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
+ SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
+};
+
+/*
+ *
+ * Dynamic Capability Identification
+ *
+ */
+
+static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
+ unsigned int i;
+ int rval;
+ int line_count = 0;
+ int embedded_start = -1, embedded_end = -1;
+ int image_start = 0;
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
+ &fmt_model_type);
+ if (rval)
+ return rval;
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
+ &fmt_model_subtype);
+ if (rval)
+ return rval;
+
+ ncol_desc = (fmt_model_subtype
+ & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
+ >> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
+ nrow_desc = fmt_model_subtype
+ & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK;
+
+ dev_dbg(&client->dev, "format_model_type %s\n",
+ fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
+ ? "2 byte" :
+ fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
+ ? "4 byte" : "is simply bad");
+
+ for (i = 0; i < ncol_desc + nrow_desc; i++) {
+ u32 desc;
+ u32 pixelcode;
+ u32 pixels;
+ char *which;
+ char *what;
+
+ if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
+ &desc);
+ if (rval)
+ return rval;
+
+ pixelcode =
+ (desc
+ & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
+ >> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
+ pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
+ } else if (fmt_model_type
+ == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
+ &desc);
+ if (rval)
+ return rval;
+
+ pixelcode =
+ (desc
+ & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
+ >> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
+ pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
+ } else {
+ dev_dbg(&client->dev,
+ "invalid frame format model type %d\n",
+ fmt_model_type);
+ return -EINVAL;
+ }
+
+ if (i < ncol_desc)
+ which = "columns";
+ else
+ which = "rows";
+
+ switch (pixelcode) {
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+ what = "embedded";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
+ what = "dummy";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
+ what = "black";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
+ what = "dark";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+ what = "visible";
+ break;
+ default:
+ what = "invalid";
+ dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
+ break;
+ }
+
+ dev_dbg(&client->dev, "%s pixels: %d %s\n",
+ what, pixels, which);
+
+ if (i < ncol_desc)
+ continue;
+
+ /* Handle row descriptors */
+ if (pixelcode
+ == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
+ embedded_start = line_count;
+ } else {
+ if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
+ || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
+ image_start = line_count;
+ if (embedded_start != -1 && embedded_end == -1)
+ embedded_end = line_count;
+ }
+ line_count += pixels;
+ }
+
+ if (embedded_start == -1 || embedded_end == -1) {
+ embedded_start = 0;
+ embedded_end = 0;
+ }
+
+ dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
+ embedded_start, embedded_end);
+ dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+
+ return 0;
+}
+
+static int smiapp_pll_configure(struct smiapp_sensor *sensor)
+{
+ struct smiapp_pll *pll = &sensor->pll;
+ int rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
+ if (rval < 0)
+ return rval;
+
+ /* Lane op clock ratio does not apply here. */
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
+ DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+ if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+ if (rval < 0)
+ return rval;
+
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+}
+
+static int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct smiapp_pll_limits lim = {
+ .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+ .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+ .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
+ .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
+ .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
+ .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
+ .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
+ .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
+
+ .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
+ .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
+ .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
+ .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
+ .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
+ .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
+ .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
+ .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
+
+ .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
+ .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
+ .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
+ .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
+ .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
+ .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
+ .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
+ .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
+
+ .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
+ .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
+ };
+ struct smiapp_pll *pll = &sensor->pll;
+ int rval;
+
+ memset(&sensor->pll, 0, sizeof(sensor->pll));
+
+ pll->lanes = sensor->platform_data->lanes;
+ pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+
+ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
+ /*
+ * Fill in operational clock divisors limits from the
+ * video timing ones. On profile 0 sensors the
+ * requirements regarding them are essentially the
+ * same as on VT ones.
+ */
+ lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
+ lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
+ lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
+ lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
+ lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
+ lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
+ lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
+ lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
+ /* Profile 0 sensors have no separate OP clock branch. */
+ pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+ }
+
+ if (smiapp_needs_quirk(sensor,
+ SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
+ pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+
+ pll->binning_horizontal = sensor->binning_horizontal;
+ pll->binning_vertical = sensor->binning_vertical;
+ pll->link_freq =
+ sensor->link_freq->qmenu_int[sensor->link_freq->val];
+ pll->scale_m = sensor->scale_m;
+ pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ pll->bits_per_pixel = sensor->csi_format->compressed;
+
+ rval = smiapp_pll_calculate(&client->dev, &lim, pll);
+ if (rval < 0)
+ return rval;
+
+ sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
+ sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+
+ return 0;
+}
+
+
+/*
+ *
+ * V4L2 Controls handling
+ *
+ */
+
+static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
+{
+ struct v4l2_ctrl *ctrl = sensor->exposure;
+ int max;
+
+ max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + sensor->vblank->val
+ - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+
+ ctrl->maximum = max;
+ if (ctrl->default_value > max)
+ ctrl->default_value = max;
+ if (ctrl->val > max)
+ ctrl->val = max;
+ if (ctrl->cur.val > max)
+ ctrl->cur.val = max;
+}
+
+/*
+ * Order matters.
+ *
+ * 1. Bits-per-pixel, descending.
+ * 2. Bits-per-pixel compressed, descending.
+ * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
+ * orders must be defined.
+ */
+static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
+ { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+};
+
+const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+
+#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \
+ - (unsigned long)smiapp_csi_data_formats) \
+ / sizeof(*smiapp_csi_data_formats))
+
+static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int flip = 0;
+
+ if (sensor->hflip) {
+ if (sensor->hflip->val)
+ flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+ if (sensor->vflip->val)
+ flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+ }
+
+ flip ^= sensor->hvflip_inv_mask;
+
+ dev_dbg(&client->dev, "flip %d\n", flip);
+ return sensor->default_pixel_order ^ flip;
+}
+
+static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int csi_format_idx =
+ to_csi_format_idx(sensor->csi_format) & ~3;
+ unsigned int internal_csi_format_idx =
+ to_csi_format_idx(sensor->internal_csi_format) & ~3;
+ unsigned int pixel_order = smiapp_pixel_order(sensor);
+
+ sensor->mbus_frame_fmts =
+ sensor->default_mbus_frame_fmts << pixel_order;
+ sensor->csi_format =
+ &smiapp_csi_data_formats[csi_format_idx + pixel_order];
+ sensor->internal_csi_format =
+ &smiapp_csi_data_formats[internal_csi_format_idx
+ + pixel_order];
+
+ BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
+ >= ARRAY_SIZE(smiapp_csi_data_formats));
+ BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
+
+ dev_dbg(&client->dev, "new pixel order %s\n",
+ pixel_order_str[pixel_order]);
+}
+
+static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct smiapp_sensor *sensor =
+ container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
+ ->sensor;
+ u32 orient = 0;
+ int exposure;
+ int rval;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ return smiapp_write(
+ sensor,
+ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
+
+ case V4L2_CID_EXPOSURE:
+ return smiapp_write(
+ sensor,
+ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ if (sensor->streaming)
+ return -EBUSY;
+
+ if (sensor->hflip->val)
+ orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+ if (sensor->vflip->val)
+ orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+ orient ^= sensor->hvflip_inv_mask;
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_IMAGE_ORIENTATION,
+ orient);
+ if (rval < 0)
+ return rval;
+
+ smiapp_update_mbus_formats(sensor);
+
+ return 0;
+
+ case V4L2_CID_VBLANK:
+ exposure = sensor->exposure->val;
+
+ __smiapp_update_exposure_limits(sensor);
+
+ if (exposure > sensor->exposure->maximum) {
+ sensor->exposure->val =
+ sensor->exposure->maximum;
+ rval = smiapp_set_ctrl(
+ sensor->exposure);
+ if (rval < 0)
+ return rval;
+ }
+
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + ctrl->val);
+
+ case V4L2_CID_HBLANK:
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+ + ctrl->val);
+
+ case V4L2_CID_LINK_FREQ:
+ if (sensor->streaming)
+ return -EBUSY;
+
+ return smiapp_pll_update(sensor);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
+ .s_ctrl = smiapp_set_ctrl,
+};
+
+static int smiapp_init_controls(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int max;
+ int rval;
+
+ rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+ if (rval)
+ return rval;
+ sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
+
+ sensor->analog_gain = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN,
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
+ max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+
+ /* Exposure limits will be updated soon, use just something here. */
+ sensor->exposure = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 0, 1, 0);
+
+ sensor->hflip = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sensor->vflip = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ sensor->vblank = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_VBLANK, 0, 1, 1, 0);
+
+ if (sensor->vblank)
+ sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+ sensor->hblank = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_HBLANK, 0, 1, 1, 0);
+
+ if (sensor->hblank)
+ sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+ sensor->pixel_rate_parray = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+ if (sensor->pixel_array->ctrl_handler.error) {
+ dev_err(&client->dev,
+ "pixel array controls initialization failed (%d)\n",
+ sensor->pixel_array->ctrl_handler.error);
+ rval = sensor->pixel_array->ctrl_handler.error;
+ goto error;
+ }
+
+ sensor->pixel_array->sd.ctrl_handler =
+ &sensor->pixel_array->ctrl_handler;
+
+ v4l2_ctrl_cluster(2, &sensor->hflip);
+
+ rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
+ if (rval)
+ goto error;
+ sensor->src->ctrl_handler.lock = &sensor->mutex;
+
+ for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+ sensor->link_freq = v4l2_ctrl_new_int_menu(
+ &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_LINK_FREQ, max, 0,
+ sensor->platform_data->op_sys_clock);
+
+ sensor->pixel_rate_csi = v4l2_ctrl_new_std(
+ &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+ if (sensor->src->ctrl_handler.error) {
+ dev_err(&client->dev,
+ "src controls initialization failed (%d)\n",
+ sensor->src->ctrl_handler.error);
+ rval = sensor->src->ctrl_handler.error;
+ goto error;
+ }
+
+ sensor->src->sd.ctrl_handler =
+ &sensor->src->ctrl_handler;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
+ v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+
+ return rval;
+}
+
+static void smiapp_free_controls(struct smiapp_sensor *sensor)
+{
+ unsigned int i;
+
+ for (i = 0; i < sensor->ssds_used; i++)
+ v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
+}
+
+static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
+ unsigned int n)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int i;
+ u32 val;
+ int rval;
+
+ for (i = 0; i < n; i++) {
+ rval = smiapp_read(
+ sensor, smiapp_reg_limits[limit[i]].addr, &val);
+ if (rval)
+ return rval;
+ sensor->limits[limit[i]] = val;
+ dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limit[i]].addr,
+ smiapp_reg_limits[limit[i]].what, val, val);
+ }
+
+ return 0;
+}
+
+static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
+{
+ unsigned int i;
+ int rval;
+
+ for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+ rval = smiapp_get_limits(sensor, &i, 1);
+ if (rval < 0)
+ return rval;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+ return 0;
+}
+
+static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ static u32 const limits[] = {
+ SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
+ SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
+ SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
+ SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
+ };
+ static u32 const limits_replace[] = {
+ SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
+ SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
+ SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
+ SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
+ };
+ unsigned int i;
+ int rval;
+
+ if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
+ SMIAPP_BINNING_CAPABILITY_NO) {
+ for (i = 0; i < ARRAY_SIZE(limits); i++)
+ sensor->limits[limits[i]] =
+ sensor->limits[limits_replace[i]];
+
+ return 0;
+ }
+
+ rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
+ if (rval < 0)
+ return rval;
+
+ /*
+ * Sanity check whether the binning limits are valid. If not,
+ * use the non-binning ones.
+ */
+ if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]
+ && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]
+ && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN])
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(limits); i++) {
+ dev_dbg(&client->dev,
+ "replace limit 0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limits[i]].addr,
+ smiapp_reg_limits[limits[i]].what,
+ sensor->limits[limits_replace[i]],
+ sensor->limits[limits_replace[i]]);
+ sensor->limits[limits[i]] =
+ sensor->limits[limits_replace[i]];
+ }
+
+ return 0;
+}
+
+static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int type, n;
+ unsigned int i, pixel_order;
+ int rval;
+
+ rval = smiapp_read(
+ sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
+ if (rval)
+ return rval;
+
+ dev_dbg(&client->dev, "data_format_model_type %d\n", type);
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER,
+ &pixel_order);
+ if (rval)
+ return rval;
+
+ if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
+ dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
+ return -EINVAL;
+ }
+
+ dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
+ pixel_order_str[pixel_order]);
+
+ switch (type) {
+ case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
+ n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
+ break;
+ case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
+ n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sensor->default_pixel_order = pixel_order;
+ sensor->mbus_frame_fmts = 0;
+
+ for (i = 0; i < n; i++) {
+ unsigned int fmt, j;
+
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
+ if (rval)
+ return rval;
+
+ dev_dbg(&client->dev, "bpp %d, compressed %d\n",
+ fmt >> 8, (u8)fmt);
+
+ for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
+ const struct smiapp_csi_data_format *f =
+ &smiapp_csi_data_formats[j];
+
+ if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
+ continue;
+
+ if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
+ continue;
+
+ dev_dbg(&client->dev, "jolly good! %d\n", j);
+
+ sensor->default_mbus_frame_fmts |= 1 << j;
+ if (!sensor->csi_format) {
+ sensor->csi_format = f;
+ sensor->internal_csi_format = f;
+ }
+ }
+ }
+
+ if (!sensor->csi_format) {
+ dev_err(&client->dev, "no supported mbus code found\n");
+ return -EINVAL;
+ }
+
+ smiapp_update_mbus_formats(sensor);
+
+ return 0;
+}
+
+static void smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+ struct v4l2_ctrl *vblank = sensor->vblank;
+ struct v4l2_ctrl *hblank = sensor->hblank;
+
+ vblank->minimum =
+ max_t(int,
+ sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+ sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+ vblank->maximum =
+ sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
+
+ vblank->val = clamp_t(int, vblank->val,
+ vblank->minimum, vblank->maximum);
+ vblank->default_value = vblank->minimum;
+ vblank->val = vblank->val;
+ vblank->cur.val = vblank->val;
+
+ hblank->minimum =
+ max_t(int,
+ sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+ sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+ hblank->maximum =
+ sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
+
+ hblank->val = clamp_t(int, hblank->val,
+ hblank->minimum, hblank->maximum);
+ hblank->default_value = hblank->minimum;
+ hblank->val = hblank->val;
+ hblank->cur.val = hblank->val;
+
+ __smiapp_update_exposure_limits(sensor);
+}
+
+static int smiapp_update_mode(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int binning_mode;
+ int rval;
+
+ dev_dbg(&client->dev, "frame size: %dx%d\n",
+ sensor->src->crop[SMIAPP_PAD_SRC].width,
+ sensor->src->crop[SMIAPP_PAD_SRC].height);
+ dev_dbg(&client->dev, "csi format width: %d\n",
+ sensor->csi_format->width);
+
+ /* Binning has to be set up here; it affects limits */
+ if (sensor->binning_horizontal == 1 &&
+ sensor->binning_vertical == 1) {
+ binning_mode = 0;
+ } else {
+ u8 binning_type =
+ (sensor->binning_horizontal << 4)
+ | sensor->binning_vertical;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
+ if (rval < 0)
+ return rval;
+
+ binning_mode = 1;
+ }
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
+ if (rval < 0)
+ return rval;
+
+ /* Get updated limits due to binning */
+ rval = smiapp_get_limits_binning(sensor);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_pll_update(sensor);
+ if (rval < 0)
+ return rval;
+
+ /* Output from pixel array, including blanking */
+ smiapp_update_blanking(sensor);
+
+ dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
+ dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
+
+ dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
+ sensor->pll.vt_pix_clk_freq_hz /
+ ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+ + sensor->hblank->val) *
+ (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + sensor->vblank->val) / 100));
+
+ return 0;
+}
+
+/*
+ *
+ * SMIA++ NVM handling
+ *
+ */
+static int smiapp_read_nvm(struct smiapp_sensor *sensor,
+ unsigned char *nvm)
+{
+ u32 i, s, p, np, v;
+ int rval = 0, rval2;
+
+ np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
+ for (p = 0; p < np; p++) {
+ rval = smiapp_write(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
+ if (rval)
+ goto out;
+
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
+ SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
+ SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
+ if (rval)
+ goto out;
+
+ for (i = 0; i < 1000; i++) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
+
+ if (rval)
+ goto out;
+
+ if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
+ break;
+
+ if (--i == 0) {
+ rval = -ETIMEDOUT;
+ goto out;
+ }
+
+ }
+
+ for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
+ &v);
+ if (rval)
+ goto out;
+
+ *nvm++ = v;
+ }
+ }
+
+out:
+ rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
+ if (rval < 0)
+ return rval;
+ else
+ return rval2;
+}
+
+/*
+ *
+ * SMIA++ CCI address control
+ *
+ */
+static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+ u32 val;
+
+ client->addr = sensor->platform_data->i2c_addr_dfl;
+
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
+ sensor->platform_data->i2c_addr_alt << 1);
+ if (rval)
+ return rval;
+
+ client->addr = sensor->platform_data->i2c_addr_alt;
+
+ /* verify addr change went ok */
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
+ if (rval)
+ return rval;
+
+ if (val != sensor->platform_data->i2c_addr_alt << 1)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ *
+ * SMIA++ Mode Control
+ *
+ */
+static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
+{
+ struct smiapp_flash_strobe_parms *strobe_setup;
+ unsigned int ext_freq = sensor->platform_data->ext_clk;
+ u32 tmp;
+ u32 strobe_adjustment;
+ u32 strobe_width_high_rs;
+ int rval;
+
+ strobe_setup = sensor->platform_data->strobe_setup;
+
+ /*
+ * How to calculate registers related to strobe length. Please
+ * do not change, or if you do at least know what you're
+ * doing. :-)
+ *
+ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
+ *
+ * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
+ * / EXTCLK freq [Hz]) * flash_strobe_adjustment
+ *
+ * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
+ * flash_strobe_adjustment E N, [1 - 0xff]
+ *
+ * The formula above is written as below to keep it on one
+ * line:
+ *
+ * l / 10^6 = w / e * a
+ *
+ * Let's mark w * a by x:
+ *
+ * x = w * a
+ *
+ * Thus, we get:
+ *
+ * x = l * e / 10^6
+ *
+ * The strobe width must be at least as long as requested,
+ * thus rounding upwards is needed.
+ *
+ * x = (l * e + 10^6 - 1) / 10^6
+ * -----------------------------
+ *
+ * Maximum possible accuracy is wanted at all times. Thus keep
+ * a as small as possible.
+ *
+ * Calculate a, assuming maximum w, with rounding upwards:
+ *
+ * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
+ * -------------------------------------
+ *
+ * Thus, we also get w, with that a, with rounding upwards:
+ *
+ * w = (x + a - 1) / a
+ * -------------------
+ *
+ * To get limits:
+ *
+ * x E [1, (2^16 - 1) * (2^8 - 1)]
+ *
+ * Substituting maximum x to the original formula (with rounding),
+ * the maximum l is thus
+ *
+ * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
+ *
+ * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
+ * --------------------------------------------------
+ *
+ * flash_strobe_length must be clamped between 1 and
+ * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
+ *
+ * Then,
+ *
+ * flash_strobe_adjustment = ((flash_strobe_length *
+ * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
+ *
+ * tFlash_strobe_width_ctrl = ((flash_strobe_length *
+ * EXTCLK freq + 10^6 - 1) / 10^6 +
+ * flash_strobe_adjustment - 1) / flash_strobe_adjustment
+ */
+ tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
+ 1000000 + 1, ext_freq);
+ strobe_setup->strobe_width_high_us =
+ clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
+
+ tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
+ 1000000 - 1), 1000000ULL);
+ strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
+ strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
+ strobe_adjustment;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS,
+ strobe_setup->mode);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
+ strobe_adjustment);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
+ strobe_width_high_rs);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
+ strobe_setup->strobe_delay);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
+ strobe_setup->stobe_start_point);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
+ strobe_setup->trigger);
+
+out:
+ sensor->platform_data->strobe_setup->trigger = 0;
+
+ return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int smiapp_power_on(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int sleep;
+ int rval;
+
+ rval = regulator_enable(sensor->vana);
+ if (rval) {
+ dev_err(&client->dev, "failed to enable vana regulator\n");
+ return rval;
+ }
+ usleep_range(1000, 1000);
+
+ if (sensor->platform_data->set_xclk)
+ rval = sensor->platform_data->set_xclk(
+ &sensor->src->sd, sensor->platform_data->ext_clk);
+ else
+ rval = clk_enable(sensor->ext_clk);
+ if (rval < 0) {
+ dev_dbg(&client->dev, "failed to set xclk\n");
+ goto out_xclk_fail;
+ }
+ usleep_range(1000, 1000);
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 1);
+
+ sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
+ usleep_range(sleep, sleep);
+
+ /*
+ * Failures to respond to the address change command have been noticed.
+ * Those failures seem to be caused by the sensor requiring a longer
+ * boot time than advertised. An additional 10ms delay seems to work
+ * around the issue, but the SMIA++ I2C write retry hack makes the delay
+ * unnecessary. The failures need to be investigated to find a proper
+ * fix, and a delay will likely need to be added here if the I2C write
+ * retry hack is reverted before the root cause of the boot time issue
+ * is found.
+ */
+
+ if (sensor->platform_data->i2c_addr_alt) {
+ rval = smiapp_change_cci_addr(sensor);
+ if (rval) {
+ dev_err(&client->dev, "cci address change error\n");
+ goto out_cci_addr_fail;
+ }
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET,
+ SMIAPP_SOFTWARE_RESET);
+ if (rval < 0) {
+ dev_err(&client->dev, "software reset failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ if (sensor->platform_data->i2c_addr_alt) {
+ rval = smiapp_change_cci_addr(sensor);
+ if (rval) {
+ dev_err(&client->dev, "cci address change error\n");
+ goto out_cci_addr_fail;
+ }
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE,
+ SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
+ if (rval) {
+ dev_err(&client->dev, "compression mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
+ sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
+ if (rval) {
+ dev_err(&client->dev, "extclk frequency set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE,
+ sensor->platform_data->lanes - 1);
+ if (rval) {
+ dev_err(&client->dev, "csi lane mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
+ SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
+ if (rval) {
+ dev_err(&client->dev, "fast standby set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
+ sensor->platform_data->csi_signalling_mode);
+ if (rval) {
+ dev_err(&client->dev, "csi signalling mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ /* DPHY control done by sensor based on requested link rate */
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
+ SMIAPP_DPHY_CTRL_UI);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_call_quirk(sensor, post_poweron);
+ if (rval) {
+ dev_err(&client->dev, "post_poweron quirks failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ /* Are we still initialising...? If yes, return here. */
+ if (!sensor->pixel_array)
+ return 0;
+
+ rval = v4l2_ctrl_handler_setup(
+ &sensor->pixel_array->ctrl_handler);
+ if (rval)
+ goto out_cci_addr_fail;
+
+ rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+ if (rval)
+ goto out_cci_addr_fail;
+
+ mutex_lock(&sensor->mutex);
+ rval = smiapp_update_mode(sensor);
+ mutex_unlock(&sensor->mutex);
+ if (rval < 0)
+ goto out_cci_addr_fail;
+
+ return 0;
+
+out_cci_addr_fail:
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+
+out_xclk_fail:
+ regulator_disable(sensor->vana);
+ return rval;
+}
+
+static void smiapp_power_off(struct smiapp_sensor *sensor)
+{
+ /*
+ * Currently power/clock to lens are enable/disabled separately
+ * but they are essentially the same signals. So if the sensor is
+ * powered off while the lens is powered on the sensor does not
+ * really see a power off and next time the cci address change
+ * will fail. So do a soft reset explicitly here.
+ */
+ if (sensor->platform_data->i2c_addr_alt)
+ smiapp_write(sensor,
+ SMIAPP_REG_U8_SOFTWARE_RESET,
+ SMIAPP_SOFTWARE_RESET);
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+ usleep_range(5000, 5000);
+ regulator_disable(sensor->vana);
+ sensor->streaming = 0;
+}
+
+static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int ret = 0;
+
+ mutex_lock(&sensor->power_mutex);
+
+ /*
+ * If the power count is modified from 0 to != 0 or from != 0
+ * to 0, update the power state.
+ */
+ if (!sensor->power_count == !on)
+ goto out;
+
+ if (on) {
+ /* Power on and perform initialisation. */
+ ret = smiapp_power_on(sensor);
+ if (ret < 0)
+ goto out;
+ } else {
+ smiapp_power_off(sensor);
+ }
+
+ /* Update the power count. */
+ sensor->power_count += on ? 1 : -1;
+ WARN_ON(sensor->power_count < 0);
+
+out:
+ mutex_unlock(&sensor->power_mutex);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video stream management
+ */
+
+static int smiapp_start_streaming(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT,
+ (sensor->csi_format->width << 8) |
+ sensor->csi_format->compressed);
+ if (rval)
+ goto out;
+
+ rval = smiapp_pll_configure(sensor);
+ if (rval)
+ goto out;
+
+ /* Analog crop start coordinates */
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
+ if (rval < 0)
+ goto out;
+
+ /* Analog crop end coordinates */
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_X_ADDR_END,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
+ + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_Y_ADDR_END,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
+ + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
+ if (rval < 0)
+ goto out;
+
+ /*
+ * Output from pixel array, including blanking, is set using
+ * controls below. No need to set here.
+ */
+
+ /* Digital crop */
+ if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].left);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].top);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].width);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].height);
+ if (rval < 0)
+ goto out;
+ }
+
+ /* Scaling */
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE) {
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
+ sensor->scaling_mode);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M,
+ sensor->scale_m);
+ if (rval < 0)
+ goto out;
+ }
+
+ /* Output size from sensor */
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE,
+ sensor->src->crop[SMIAPP_PAD_SRC].width);
+ if (rval < 0)
+ goto out;
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
+ sensor->src->crop[SMIAPP_PAD_SRC].height);
+ if (rval < 0)
+ goto out;
+
+ if ((sensor->flash_capability &
+ (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
+ SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
+ sensor->platform_data->strobe_setup != NULL &&
+ sensor->platform_data->strobe_setup->trigger != 0) {
+ rval = smiapp_setup_flash_strobe(sensor);
+ if (rval)
+ goto out;
+ }
+
+ rval = smiapp_call_quirk(sensor, pre_streamon);
+ if (rval) {
+ dev_err(&client->dev, "pre_streamon quirks failed\n");
+ goto out;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+ SMIAPP_MODE_SELECT_STREAMING);
+
+out:
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+ SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
+ if (rval)
+ goto out;
+
+ rval = smiapp_call_quirk(sensor, post_streamoff);
+ if (rval)
+ dev_err(&client->dev, "post_streamoff quirks failed\n");
+
+out:
+ mutex_unlock(&sensor->mutex);
+ return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ if (sensor->streaming == enable)
+ return 0;
+
+ if (enable) {
+ sensor->streaming = 1;
+ rval = smiapp_start_streaming(sensor);
+ if (rval < 0)
+ sensor->streaming = 0;
+ } else {
+ rval = smiapp_stop_streaming(sensor);
+ sensor->streaming = 0;
+ }
+
+ return rval;
+}
+
+static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+ int idx = -1;
+ int rval = -EINVAL;
+
+ mutex_lock(&sensor->mutex);
+
+ dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
+ subdev->name, code->pad, code->index);
+
+ if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
+ if (code->index)
+ goto out;
+
+ code->code = sensor->internal_csi_format->code;
+ rval = 0;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ if (sensor->mbus_frame_fmts & (1 << i))
+ idx++;
+
+ if (idx == code->index) {
+ code->code = smiapp_csi_data_formats[i].code;
+ dev_err(&client->dev, "found index %d, i %d, code %x\n",
+ code->index, i, code->code);
+ rval = 0;
+ break;
+ }
+ }
+
+out:
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
+ unsigned int pad)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+ if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
+ return sensor->csi_format->code;
+ else
+ return sensor->internal_csi_format->code;
+}
+
+static int __smiapp_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ } else {
+ struct v4l2_rect *r;
+
+ if (fmt->pad == ssd->source_pad)
+ r = &ssd->crop[ssd->source_pad];
+ else
+ r = &ssd->sink_fmt;
+
+ fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+ fmt->format.width = r->width;
+ fmt->format.height = r->height;
+ }
+
+ return 0;
+}
+
+static int smiapp_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = __smiapp_get_format(subdev, fh, fmt);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_rect **crops,
+ struct v4l2_rect **comps, int which)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ unsigned int i;
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (crops)
+ for (i = 0; i < subdev->entity.num_pads; i++)
+ crops[i] = &ssd->crop[i];
+ if (comps)
+ *comps = &ssd->compose;
+ } else {
+ if (crops) {
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ crops[i] = v4l2_subdev_get_try_crop(fh, i);
+ BUG_ON(!crops[i]);
+ }
+ }
+ if (comps) {
+ *comps = v4l2_subdev_get_try_compose(fh,
+ SMIAPP_PAD_SINK);
+ BUG_ON(!*comps);
+ }
+ }
+}
+
+/* Changes require propagation only on sink pad. */
+static void smiapp_propagate(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh, int which,
+ int target)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
+
+ switch (target) {
+ case V4L2_SEL_TGT_CROP:
+ comp->width = crops[SMIAPP_PAD_SINK]->width;
+ comp->height = crops[SMIAPP_PAD_SINK]->height;
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (ssd == sensor->scaler) {
+ sensor->scale_m =
+ sensor->limits[
+ SMIAPP_LIMIT_SCALER_N_MIN];
+ sensor->scaling_mode =
+ SMIAPP_SCALING_MODE_NONE;
+ } else if (ssd == sensor->binner) {
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+ }
+ }
+ /* Fall through */
+ case V4L2_SEL_TGT_COMPOSE:
+ *crops[SMIAPP_PAD_SRC] = *comp;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static const struct smiapp_csi_data_format
+*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
+{
+ const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ if (sensor->mbus_frame_fmts & (1 << i)
+ && smiapp_csi_data_formats[i].code == code)
+ return &smiapp_csi_data_formats[i];
+ }
+
+ return csi_format;
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *crops[SMIAPP_PADS];
+
+ mutex_lock(&sensor->mutex);
+
+ /*
+ * Media bus code is changeable on src subdev's source pad. On
+ * other source pads we just get format here.
+ */
+ if (fmt->pad == ssd->source_pad) {
+ u32 code = fmt->format.code;
+ int rval = __smiapp_get_format(subdev, fh, fmt);
+
+ if (!rval && subdev == &sensor->src->sd) {
+ const struct smiapp_csi_data_format *csi_format =
+ smiapp_validate_csi_data_format(sensor, code);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ sensor->csi_format = csi_format;
+ fmt->format.code = csi_format->code;
+ }
+
+ mutex_unlock(&sensor->mutex);
+ return rval;
+ }
+
+ /* Sink pad. Width and height are changeable here. */
+ fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+ fmt->format.width &= ~1;
+ fmt->format.height &= ~1;
+
+ fmt->format.width =
+ clamp(fmt->format.width,
+ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+ sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
+ fmt->format.height =
+ clamp(fmt->format.height,
+ sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+ sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
+
+ smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
+
+ crops[ssd->sink_pad]->left = 0;
+ crops[ssd->sink_pad]->top = 0;
+ crops[ssd->sink_pad]->width = fmt->format.width;
+ crops[ssd->sink_pad]->height = fmt->format.height;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ ssd->sink_fmt = *crops[ssd->sink_pad];
+ smiapp_propagate(subdev, fh, fmt->which,
+ V4L2_SEL_TGT_CROP);
+
+ mutex_unlock(&sensor->mutex);
+
+ return 0;
+}
+
+/*
+ * Calculate goodness of scaled image size compared to expected image
+ * size and flags provided.
+ */
+#define SCALING_GOODNESS 100000
+#define SCALING_GOODNESS_EXTREME 100000000
+static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
+ int h, int ask_h, u32 flags)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ int val = 0;
+
+ w &= ~1;
+ ask_w &= ~1;
+ h &= ~1;
+ ask_h &= ~1;
+
+ if (flags & V4L2_SEL_FLAG_GE) {
+ if (w < ask_w)
+ val -= SCALING_GOODNESS;
+ if (h < ask_h)
+ val -= SCALING_GOODNESS;
+ }
+
+ if (flags & V4L2_SEL_FLAG_LE) {
+ if (w > ask_w)
+ val -= SCALING_GOODNESS;
+ if (h > ask_h)
+ val -= SCALING_GOODNESS;
+ }
+
+ val -= abs(w - ask_w);
+ val -= abs(h - ask_h);
+
+ if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+ val -= SCALING_GOODNESS_EXTREME;
+
+ dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
+ w, ask_h, h, ask_h, val);
+
+ return val;
+}
+
+static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel,
+ struct v4l2_rect **crops,
+ struct v4l2_rect *comp)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+ unsigned int binh = 1, binv = 1;
+ unsigned int best = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width, sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
+
+ for (i = 0; i < sensor->nbinning_subtypes; i++) {
+ int this = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width
+ / sensor->binning_subtypes[i].horizontal,
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height
+ / sensor->binning_subtypes[i].vertical,
+ sel->r.height, sel->flags);
+
+ if (this > best) {
+ binh = sensor->binning_subtypes[i].horizontal;
+ binv = sensor->binning_subtypes[i].vertical;
+ best = this;
+ }
+ }
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sensor->binning_vertical = binv;
+ sensor->binning_horizontal = binh;
+ }
+
+ sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
+ sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
+}
+
+/*
+ * Calculate best scaling ratio and mode for given output resolution.
+ *
+ * Try all of these: horizontal ratio, vertical ratio and smallest
+ * size possible (horizontally).
+ *
+ * Also try whether horizontal scaler or full scaler gives a better
+ * result.
+ */
+static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel,
+ struct v4l2_rect **crops,
+ struct v4l2_rect *comp)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ u32 min, max, a, b, max_m;
+ u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+ u32 try[4];
+ u32 ntry = 0;
+ unsigned int i;
+ int best = INT_MIN;
+
+ sel->r.width = min_t(unsigned int, sel->r.width,
+ crops[SMIAPP_PAD_SINK]->width);
+ sel->r.height = min_t(unsigned int, sel->r.height,
+ crops[SMIAPP_PAD_SINK]->height);
+
+ a = crops[SMIAPP_PAD_SINK]->width
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
+ b = crops[SMIAPP_PAD_SINK]->height
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
+ max_m = crops[SMIAPP_PAD_SINK]->width
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+ / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+
+ a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+ b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+ max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+
+ dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
+
+ min = min(max_m, min(a, b));
+ max = min(max_m, max(a, b));
+
+ try[ntry] = min;
+ ntry++;
+ if (min != max) {
+ try[ntry] = max;
+ ntry++;
+ }
+ if (max != max_m) {
+ try[ntry] = min + 1;
+ ntry++;
+ if (min != max) {
+ try[ntry] = max + 1;
+ ntry++;
+ }
+ }
+
+ for (i = 0; i < ntry; i++) {
+ int this = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height,
+ sel->r.height,
+ sel->flags);
+
+ dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
+
+ if (this > best) {
+ scale_m = try[i];
+ mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+ best = this;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+ continue;
+
+ this = scaling_goodness(
+ subdev, crops[SMIAPP_PAD_SINK]->width
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.height,
+ sel->flags);
+
+ if (this > best) {
+ scale_m = try[i];
+ mode = SMIAPP_SCALING_MODE_BOTH;
+ best = this;
+ }
+ }
+
+ sel->r.width =
+ (crops[SMIAPP_PAD_SINK]->width
+ / scale_m
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+ if (mode == SMIAPP_SCALING_MODE_BOTH)
+ sel->r.height =
+ (crops[SMIAPP_PAD_SINK]->height
+ / scale_m
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+ & ~1;
+ else
+ sel->r.height = crops[SMIAPP_PAD_SINK]->height;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sensor->scale_m = scale_m;
+ sensor->scaling_mode = mode;
+ }
+}
+/* We're only called on source pads. This function sets scaling. */
+static int smiapp_set_compose(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+ sel->r.top = 0;
+ sel->r.left = 0;
+
+ if (ssd == sensor->binner)
+ smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
+ else
+ smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
+
+ *comp = sel->r;
+ smiapp_propagate(subdev, fh, sel->which,
+ V4L2_SEL_TGT_COMPOSE);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return smiapp_update_mode(sensor);
+
+ return 0;
+}
+
+static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+ /* We only implement crop in three places. */
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (ssd == sensor->pixel_array
+ && sel->pad == SMIAPP_PA_PAD_SRC)
+ return 0;
+ if (ssd == sensor->src
+ && sel->pad == SMIAPP_PAD_SRC)
+ return 0;
+ if (ssd == sensor->scaler
+ && sel->pad == SMIAPP_PAD_SINK
+ && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
+ return 0;
+ return -EINVAL;
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ if (sel->pad == ssd->source_pad)
+ return -EINVAL;
+ if (ssd == sensor->binner)
+ return 0;
+ if (ssd == sensor->scaler
+ && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE)
+ return 0;
+ /* Fall through */
+ default:
+ return -EINVAL;
+ }
+}
+
+static int smiapp_set_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
+ struct v4l2_rect _r;
+
+ smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (sel->pad == ssd->sink_pad)
+ src_size = &ssd->sink_fmt;
+ else
+ src_size = &ssd->compose;
+ } else {
+ if (sel->pad == ssd->sink_pad) {
+ _r.left = 0;
+ _r.top = 0;
+ _r.width = v4l2_subdev_get_try_format(fh, sel->pad)
+ ->width;
+ _r.height = v4l2_subdev_get_try_format(fh, sel->pad)
+ ->height;
+ src_size = &_r;
+ } else {
+ src_size =
+ v4l2_subdev_get_try_compose(
+ fh, ssd->sink_pad);
+ }
+ }
+
+ if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
+ sel->r.left = 0;
+ sel->r.top = 0;
+ }
+
+ sel->r.width = min(sel->r.width, src_size->width);
+ sel->r.height = min(sel->r.height, src_size->height);
+
+ sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
+ sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
+
+ *crops[sel->pad] = sel->r;
+
+ if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
+ smiapp_propagate(subdev, fh, sel->which,
+ V4L2_SEL_TGT_CROP);
+
+ return 0;
+}
+
+static int __smiapp_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+ struct v4l2_rect sink_fmt;
+ int ret;
+
+ ret = __smiapp_sel_supported(subdev, sel);
+ if (ret)
+ return ret;
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sink_fmt = ssd->sink_fmt;
+ } else {
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_get_try_format(fh, ssd->sink_pad);
+
+ sink_fmt.left = 0;
+ sink_fmt.top = 0;
+ sink_fmt.width = fmt->width;
+ sink_fmt.height = fmt->height;
+ }
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (ssd == sensor->pixel_array) {
+ sel->r.width =
+ sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ sel->r.height =
+ sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ } else if (sel->pad == ssd->sink_pad) {
+ sel->r = sink_fmt;
+ } else {
+ sel->r = *comp;
+ }
+ break;
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ sel->r = *crops[sel->pad];
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ sel->r = *comp;
+ break;
+ }
+
+ return 0;
+}
+
+static int smiapp_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = __smiapp_get_selection(subdev, fh, sel);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+static int smiapp_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int ret;
+
+ ret = __smiapp_sel_supported(subdev, sel);
+ if (ret)
+ return ret;
+
+ mutex_lock(&sensor->mutex);
+
+ sel->r.left = max(0, sel->r.left & ~1);
+ sel->r.top = max(0, sel->r.top & ~1);
+ sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
+ sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
+
+ sel->r.width = max_t(unsigned int,
+ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+ sel->r.width);
+ sel->r.height = max_t(unsigned int,
+ sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+ sel->r.height);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ ret = smiapp_set_crop(subdev, fh, sel);
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ ret = smiapp_set_compose(subdev, fh, sel);
+ break;
+ default:
+ BUG();
+ }
+
+ mutex_unlock(&sensor->mutex);
+ return ret;
+}
+
+static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+ *frames = sensor->frame_skip;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * sysfs attributes
+ */
+
+static ssize_t
+smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int nbytes;
+
+ if (!sensor->dev_init_done)
+ return -EBUSY;
+
+ if (!sensor->nvm_size) {
+ /* NVM not read yet - read it now */
+ sensor->nvm_size = sensor->platform_data->nvm_size;
+ if (smiapp_set_power(subdev, 1) < 0)
+ return -ENODEV;
+ if (smiapp_read_nvm(sensor, sensor->nvm)) {
+ dev_err(&client->dev, "nvm read failed\n");
+ return -ENODEV;
+ }
+ smiapp_set_power(subdev, 0);
+ }
+ /*
+ * NVM is still way below a PAGE_SIZE, so we can safely
+ * assume this for now.
+ */
+ nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
+ memcpy(buf, sensor->nvm, nbytes);
+
+ return nbytes;
+}
+static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int smiapp_identify_module(struct v4l2_subdev *subdev)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_module_info *minfo = &sensor->minfo;
+ unsigned int i;
+ int rval = 0;
+
+ minfo->name = SMIAPP_NAME;
+
+ /* Module info */
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
+ &minfo->manufacturer_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID,
+ &minfo->model_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
+ &minfo->revision_number_major);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
+ &minfo->revision_number_minor);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_MODULE_DATE_YEAR,
+ &minfo->module_year);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_MODULE_DATE_MONTH,
+ &minfo->module_month);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY,
+ &minfo->module_day);
+
+ /* Sensor info */
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
+ &minfo->sensor_manufacturer_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U16_SENSOR_MODEL_ID,
+ &minfo->sensor_model_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
+ &minfo->sensor_revision_number);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
+ &minfo->sensor_firmware_version);
+
+ /* SMIA */
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
+ &minfo->smia_version);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
+ &minfo->smiapp_version);
+
+ if (rval) {
+ dev_err(&client->dev, "sensor detection failed\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
+ minfo->manufacturer_id, minfo->model_id);
+
+ dev_dbg(&client->dev,
+ "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
+ minfo->revision_number_major, minfo->revision_number_minor,
+ minfo->module_year, minfo->module_month, minfo->module_day);
+
+ dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
+ minfo->sensor_manufacturer_id, minfo->sensor_model_id);
+
+ dev_dbg(&client->dev,
+ "sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+ minfo->sensor_revision_number, minfo->sensor_firmware_version);
+
+ dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
+ minfo->smia_version, minfo->smiapp_version);
+
+ /*
+ * Some modules have bad data in the lvalues below. Hope the
+ * rvalues have better stuff. The lvalues are module
+ * parameters whereas the rvalues are sensor parameters.
+ */
+ if (!minfo->manufacturer_id && !minfo->model_id) {
+ minfo->manufacturer_id = minfo->sensor_manufacturer_id;
+ minfo->model_id = minfo->sensor_model_id;
+ minfo->revision_number_major = minfo->sensor_revision_number;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
+ if (smiapp_module_idents[i].manufacturer_id
+ != minfo->manufacturer_id)
+ continue;
+ if (smiapp_module_idents[i].model_id != minfo->model_id)
+ continue;
+ if (smiapp_module_idents[i].flags
+ & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
+ if (smiapp_module_idents[i].revision_number_major
+ < minfo->revision_number_major)
+ continue;
+ } else {
+ if (smiapp_module_idents[i].revision_number_major
+ != minfo->revision_number_major)
+ continue;
+ }
+
+ minfo->name = smiapp_module_idents[i].name;
+ minfo->quirk = smiapp_module_idents[i].quirk;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(smiapp_module_idents))
+ dev_warn(&client->dev,
+ "no quirks for this module; let's hope it's fully compliant\n");
+
+ dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
+ minfo->name, minfo->manufacturer_id, minfo->model_id,
+ minfo->revision_number_major);
+
+ strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
+
+ return 0;
+}
+
+static const struct v4l2_subdev_ops smiapp_ops;
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
+static const struct media_entity_operations smiapp_entity_ops;
+
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_subdev *last = NULL;
+ u32 tmp;
+ unsigned int i;
+ int rval;
+
+ sensor->vana = regulator_get(&client->dev, "VANA");
+ if (IS_ERR(sensor->vana)) {
+ dev_err(&client->dev, "could not get regulator for vana\n");
+ return -ENODEV;
+ }
+
+ if (!sensor->platform_data->set_xclk) {
+ sensor->ext_clk = clk_get(&client->dev,
+ sensor->platform_data->ext_clk_name);
+ if (IS_ERR(sensor->ext_clk)) {
+ dev_err(&client->dev, "could not get clock %s\n",
+ sensor->platform_data->ext_clk_name);
+ rval = -ENODEV;
+ goto out_clk_get;
+ }
+
+ rval = clk_set_rate(sensor->ext_clk,
+ sensor->platform_data->ext_clk);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "unable to set clock %s freq to %u\n",
+ sensor->platform_data->ext_clk_name,
+ sensor->platform_data->ext_clk);
+ rval = -ENODEV;
+ goto out_clk_set_rate;
+ }
+ }
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
+ if (gpio_request_one(sensor->platform_data->xshutdown, 0,
+ "SMIA++ xshutdown") != 0) {
+ dev_err(&client->dev,
+ "unable to acquire reset gpio %d\n",
+ sensor->platform_data->xshutdown);
+ rval = -ENODEV;
+ goto out_clk_set_rate;
+ }
+ }
+
+ rval = smiapp_power_on(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_smiapp_power_on;
+ }
+
+ rval = smiapp_identify_module(subdev);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ rval = smiapp_get_all_limits(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ /*
+ * Handle Sensor Module orientation on the board.
+ *
+ * The application of H-FLIP and V-FLIP on the sensor is modified by
+ * the sensor orientation on the board.
+ *
+ * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+ * both H-FLIP and V-FLIP for normal operation which also implies
+ * that a set/unset operation for user space HFLIP and VFLIP v4l2
+ * controls will need to be internally inverted.
+ *
+ * Rotation also changes the bayer pattern.
+ */
+ if (sensor->platform_data->module_board_orient ==
+ SMIAPP_MODULE_BOARD_ORIENT_180)
+ sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+ SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+ rval = smiapp_get_mbus_formats(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+ u32 val;
+
+ rval = smiapp_read(sensor,
+ SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->nbinning_subtypes = min_t(u8, val,
+ SMIAPP_BINNING_SUBTYPES);
+
+ for (i = 0; i < sensor->nbinning_subtypes; i++) {
+ rval = smiapp_read(
+ sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->binning_subtypes[i] =
+ *(struct smiapp_binning_subtype *)&val;
+
+ dev_dbg(&client->dev, "binning %xx%x\n",
+ sensor->binning_subtypes[i].horizontal,
+ sensor->binning_subtypes[i].vertical);
+ }
+ }
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+
+ /* SMIA++ NVM initialization - it will be read from the sensor
+ * when it is first requested by userspace.
+ */
+ if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
+ sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
+ GFP_KERNEL);
+ if (sensor->nvm == NULL) {
+ dev_err(&client->dev, "nvm buf allocation failed\n");
+ rval = -ENOMEM;
+ goto out_power_off;
+ }
+
+ if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+ dev_err(&client->dev, "sysfs nvm entry failed\n");
+ rval = -EBUSY;
+ goto out_power_off;
+ }
+ }
+
+ rval = smiapp_call_quirk(sensor, limits);
+ if (rval) {
+ dev_err(&client->dev, "limits quirks failed\n");
+ goto out_nvm_release;
+ }
+
+ /* We consider this as profile 0 sensor if any of these are zero. */
+ if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+ } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE) {
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+ else
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ }
+ sensor->binner = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+
+ sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+ for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+ struct {
+ struct smiapp_subdev *ssd;
+ char *name;
+ } const __this[] = {
+ { sensor->scaler, "scaler", },
+ { sensor->binner, "binner", },
+ { sensor->pixel_array, "pixel array", },
+ }, *_this = &__this[i];
+ struct smiapp_subdev *this = _this->ssd;
+
+ if (!this)
+ continue;
+
+ if (this != sensor->src)
+ v4l2_subdev_init(&this->sd, &smiapp_ops);
+
+ this->sensor = sensor;
+
+ if (this == sensor->pixel_array) {
+ this->npads = 1;
+ } else {
+ this->npads = 2;
+ this->source_pad = 1;
+ }
+
+ snprintf(this->sd.name,
+ sizeof(this->sd.name), "%s %s",
+ sensor->minfo.name, _this->name);
+
+ this->sink_fmt.width =
+ sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ this->sink_fmt.height =
+ sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ this->compose.width = this->sink_fmt.width;
+ this->compose.height = this->sink_fmt.height;
+ this->crop[this->source_pad] = this->compose;
+ this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+ if (this != sensor->pixel_array) {
+ this->crop[this->sink_pad] = this->compose;
+ this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
+ }
+
+ this->sd.entity.ops = &smiapp_entity_ops;
+
+ if (last == NULL) {
+ last = this;
+ continue;
+ }
+
+ this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ this->sd.internal_ops = &smiapp_internal_ops;
+ this->sd.owner = NULL;
+ v4l2_set_subdevdata(&this->sd, client);
+
+ rval = media_entity_init(&this->sd.entity,
+ this->npads, this->pads, 0);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_init failed\n");
+ goto out_nvm_release;
+ }
+
+ rval = media_entity_create_link(&this->sd.entity,
+ this->source_pad,
+ &last->sd.entity,
+ last->sink_pad,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_create_link failed\n");
+ goto out_nvm_release;
+ }
+
+ rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+ &this->sd);
+ if (rval) {
+ dev_err(&client->dev,
+ "v4l2_device_register_subdev failed\n");
+ goto out_nvm_release;
+ }
+
+ last = this;
+ }
+
+ dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+ sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+ /* final steps */
+ smiapp_read_frame_fmt(sensor);
+ rval = smiapp_init_controls(sensor);
+ if (rval < 0)
+ goto out_nvm_release;
+
+ rval = smiapp_update_mode(sensor);
+ if (rval) {
+ dev_err(&client->dev, "update mode failed\n");
+ goto out_nvm_release;
+ }
+
+ sensor->streaming = false;
+ sensor->dev_init_done = true;
+
+ /* check flash capability */
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
+ sensor->flash_capability = tmp;
+ if (rval)
+ goto out_nvm_release;
+
+ smiapp_power_off(sensor);
+
+ return 0;
+
+out_nvm_release:
+ device_remove_file(&client->dev, &dev_attr_nvm);
+
+out_power_off:
+ kfree(sensor->nvm);
+ sensor->nvm = NULL;
+ smiapp_power_off(sensor);
+
+out_smiapp_power_on:
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_free(sensor->platform_data->xshutdown);
+
+out_clk_set_rate:
+ clk_put(sensor->ext_clk);
+ sensor->ext_clk = NULL;
+
+out_clk_get:
+ regulator_put(sensor->vana);
+ sensor->vana = NULL;
+ return rval;
+}
+
+static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
+ struct smiapp_sensor *sensor = ssd->sensor;
+ u32 mbus_code =
+ smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
+ unsigned int i;
+
+ mutex_lock(&sensor->mutex);
+
+ for (i = 0; i < ssd->npads; i++) {
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(fh, i);
+ struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
+ struct v4l2_rect *try_comp;
+
+ try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ try_fmt->code = mbus_code;
+
+ try_crop->top = 0;
+ try_crop->left = 0;
+ try_crop->width = try_fmt->width;
+ try_crop->height = try_fmt->height;
+
+ if (ssd != sensor->pixel_array)
+ continue;
+
+ try_comp = v4l2_subdev_get_try_compose(fh, i);
+ *try_comp = *try_crop;
+ }
+
+ mutex_unlock(&sensor->mutex);
+
+ return smiapp_set_power(sd, 1);
+}
+
+static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return smiapp_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_video_ops smiapp_video_ops = {
+ .s_stream = smiapp_set_stream,
+};
+
+static const struct v4l2_subdev_core_ops smiapp_core_ops = {
+ .s_power = smiapp_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
+ .enum_mbus_code = smiapp_enum_mbus_code,
+ .get_fmt = smiapp_get_format,
+ .set_fmt = smiapp_set_format,
+ .get_selection = smiapp_get_selection,
+ .set_selection = smiapp_set_selection,
+};
+
+static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
+ .g_skip_frames = smiapp_get_skip_frames,
+};
+
+static const struct v4l2_subdev_ops smiapp_ops = {
+ .core = &smiapp_core_ops,
+ .video = &smiapp_video_ops,
+ .pad = &smiapp_pad_ops,
+ .sensor = &smiapp_sensor_ops,
+};
+
+static const struct media_entity_operations smiapp_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
+ .registered = smiapp_registered,
+ .open = smiapp_open,
+ .close = smiapp_close,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
+ .open = smiapp_open,
+ .close = smiapp_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver
+ */
+
+#ifdef CONFIG_PM
+
+static int smiapp_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ bool streaming;
+
+ BUG_ON(mutex_is_locked(&sensor->mutex));
+
+ if (sensor->power_count == 0)
+ return 0;
+
+ if (sensor->streaming)
+ smiapp_stop_streaming(sensor);
+
+ streaming = sensor->streaming;
+
+ smiapp_power_off(sensor);
+
+ /* save state for resume */
+ sensor->streaming = streaming;
+
+ return 0;
+}
+
+static int smiapp_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ if (sensor->power_count == 0)
+ return 0;
+
+ rval = smiapp_power_on(sensor);
+ if (rval)
+ return rval;
+
+ if (sensor->streaming)
+ rval = smiapp_start_streaming(sensor);
+
+ return rval;
+}
+
+#else
+
+#define smiapp_suspend NULL
+#define smiapp_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int smiapp_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct smiapp_sensor *sensor;
+ int rval;
+
+ if (client->dev.platform_data == NULL)
+ return -ENODEV;
+
+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ sensor->platform_data = client->dev.platform_data;
+ mutex_init(&sensor->mutex);
+ mutex_init(&sensor->power_mutex);
+ sensor->src = &sensor->ssds[sensor->ssds_used];
+
+ v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
+ sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+ sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->src->sensor = sensor;
+
+ sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+ rval = media_entity_init(&sensor->src->sd.entity, 2,
+ sensor->src->pads, 0);
+ if (rval < 0)
+ kfree(sensor);
+
+ return rval;
+}
+
+static int __exit smiapp_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+
+ if (sensor->power_count) {
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+ sensor->power_count = 0;
+ }
+
+ if (sensor->nvm) {
+ device_remove_file(&client->dev, &dev_attr_nvm);
+ kfree(sensor->nvm);
+ }
+
+ for (i = 0; i < sensor->ssds_used; i++) {
+ media_entity_cleanup(&sensor->ssds[i].sd.entity);
+ v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+ }
+ smiapp_free_controls(sensor);
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_free(sensor->platform_data->xshutdown);
+ if (sensor->ext_clk)
+ clk_put(sensor->ext_clk);
+ if (sensor->vana)
+ regulator_put(sensor->vana);
+
+ kfree(sensor);
+
+ return 0;
+}
+
+static const struct i2c_device_id smiapp_id_table[] = {
+ { SMIAPP_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
+
+static const struct dev_pm_ops smiapp_pm_ops = {
+ .suspend = smiapp_suspend,
+ .resume = smiapp_resume,
+};
+
+static struct i2c_driver smiapp_i2c_driver = {
+ .driver = {
+ .name = SMIAPP_NAME,
+ .pm = &smiapp_pm_ops,
+ },
+ .probe = smiapp_probe,
+ .remove = __exit_p(smiapp_remove),
+ .id_table = smiapp_id_table,
+};
+
+module_i2c_driver(smiapp_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c
new file mode 100644
index 000000000000..fb2f81ad8c3b
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-limits.c
@@ -0,0 +1,132 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-limits.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 "smiapp.h"
+
+struct smiapp_reg_limits smiapp_reg_limits[] = {
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
+ { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
+ { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
+ { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
+ { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
+ { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
+ { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
+ { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
+ { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
+ { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
+ { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
+ { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
+ { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
+ { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
+ { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
+ { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
+ { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
+ { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
+ { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
+ { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
+ { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
+ { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
+ { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
+ { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
+ { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
+ { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
+ { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
+ { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
+ { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
+ { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
+ { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
+ { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
+ { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
+ { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
+ { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
+ { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
+ { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
+ { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
+ { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
+ { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
+ { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
+ { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
+ { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
+ { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
+ { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
+ { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
+ { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
+ { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
+ { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
+ { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
+ { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
+ { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
+ { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
+ { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
+ { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
+ { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
+ { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
+ { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
+ { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
+ { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
+ { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
+ { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
+ { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
+ { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
+ { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
+ { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
+ { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
+ { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
+ { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
+ { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
+ { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
+ { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
+ { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
+ { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
+ { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
+ { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
+ { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
+ { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
+ { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
+ { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
+ { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
+ { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
+ { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
+ { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
+ { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
+ { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
+ { 0, NULL },
+};
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h
new file mode 100644
index 000000000000..9ae765e23ea5
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-limits.h
@@ -0,0 +1,128 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-limits.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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
+ *
+ */
+
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN 1
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX 2
+#define SMIAPP_LIMIT_THS_ZERO_MIN 3
+#define SMIAPP_LIMIT_TCLK_TRAIL_MIN 4
+#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY 5
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN 6
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN 7
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN 8
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN 9
+#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY 10
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN 11
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX 12
+#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ 13
+#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ 14
+#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV 15
+#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV 16
+#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ 17
+#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ 18
+#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER 19
+#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER 20
+#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ 21
+#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ 22
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV 23
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV 24
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ 25
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ 26
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ 27
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ 28
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV 29
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV 30
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES 31
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES 32
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK 33
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK 34
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK 35
+#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES 36
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE 37
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV 38
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV 39
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ 40
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ 41
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV 42
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV 43
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ 44
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ 45
+#define SMIAPP_LIMIT_X_ADDR_MIN 46
+#define SMIAPP_LIMIT_Y_ADDR_MIN 47
+#define SMIAPP_LIMIT_X_ADDR_MAX 48
+#define SMIAPP_LIMIT_Y_ADDR_MAX 49
+#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE 50
+#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE 51
+#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE 52
+#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE 53
+#define SMIAPP_LIMIT_MIN_EVEN_INC 54
+#define SMIAPP_LIMIT_MAX_EVEN_INC 55
+#define SMIAPP_LIMIT_MIN_ODD_INC 56
+#define SMIAPP_LIMIT_MAX_ODD_INC 57
+#define SMIAPP_LIMIT_SCALING_CAPABILITY 58
+#define SMIAPP_LIMIT_SCALER_M_MIN 59
+#define SMIAPP_LIMIT_SCALER_M_MAX 60
+#define SMIAPP_LIMIT_SCALER_N_MIN 61
+#define SMIAPP_LIMIT_SCALER_N_MAX 62
+#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY 63
+#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY 64
+#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY 65
+#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY 66
+#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY 67
+#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY 68
+#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY 69
+#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY 70
+#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY 71
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS 72
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS 73
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS 74
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS 75
+#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY 76
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN 77
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN 78
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN 79
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN 80
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN 81
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN 82
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 83
+#define SMIAPP_LIMIT_BINNING_CAPABILITY 84
+#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY 85
+#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY 86
+#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY 87
+#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY 88
+#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY 89
+#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY 90
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY 91
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2 92
+#define SMIAPP_LIMIT_EDOF_CAPABILITY 93
+#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY 94
+#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY 95
+#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY 96
+#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN 97
+#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY 98
+#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY 99
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1 100
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2 101
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP 102
+#define SMIAPP_LIMIT_LAST 103
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
new file mode 100644
index 000000000000..cf048128367c
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -0,0 +1,306 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-quirk.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/delay.h>
+
+#include "smiapp.h"
+
+static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
+{
+ return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+}
+
+static int smiapp_write_8s(struct smiapp_sensor *sensor,
+ struct smiapp_reg_8 *regs, int len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ for (; len > 0; len--, regs++) {
+ rval = smiapp_write_8(sensor, regs->reg, regs->val);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "error %d writing reg 0x%4.4x, val 0x%2.2x",
+ rval, regs->reg, regs->val);
+ return rval;
+ }
+ }
+
+ return 0;
+}
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+ u32 limit, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+ dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limit].addr,
+ smiapp_reg_limits[limit].what, val, val);
+ sensor->limits[limit] = val;
+}
+
+int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
+ u32 reg, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int i;
+
+ for (i = 0; smiapp_reg_limits[i].addr; i++) {
+ if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
+ continue;
+
+ smiapp_replace_limit(sensor, i, val);
+
+ return 0;
+ }
+
+ dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
+
+ return -EINVAL;
+}
+
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+ u32 reg, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ const struct smia_reg *sreg;
+
+ if (!sensor->minfo.quirk)
+ return false;
+
+ sreg = sensor->minfo.quirk->regs;
+
+ if (!sreg)
+ return false;
+
+ while (sreg->type) {
+ u16 type = reg >> 16;
+ u16 reg16 = reg;
+
+ if (sreg->type != type || sreg->reg != reg16) {
+ sreg++;
+ continue;
+ }
+
+ switch ((u8)type) {
+ case SMIA_REG_8BIT:
+ dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
+ reg, sreg->val);
+ break;
+ case SMIA_REG_16BIT:
+ dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
+ reg, sreg->val);
+ break;
+ case SMIA_REG_32BIT:
+ dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
+ reg, sreg->val);
+ break;
+ }
+
+ *val = sreg->val;
+
+ return true;
+ }
+
+ return false;
+}
+
+static int jt8ew9_limits(struct smiapp_sensor *sensor)
+{
+ if (sensor->minfo.revision_number_major < 0x03)
+ sensor->frame_skip = 1;
+
+ /* Below 24 gain doesn't have effect at all, */
+ /* but ~59 is needed for full dynamic range */
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
+ smiapp_replace_limit(
+ sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
+
+ return 0;
+}
+
+static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
+{
+ struct smiapp_reg_8 regs[] = {
+ { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
+ { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+ { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+ { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
+ { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ /* Taken from v03. No idea what the rest are. */
+ { 0x32e0, 0x05 },
+ { 0x32e1, 0x05 },
+ { 0x32e2, 0x04 },
+ { 0x32e5, 0x04 },
+ { 0x32e6, 0x04 },
+
+ };
+
+ return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_jt8ew9_quirk = {
+ .limits = jt8ew9_limits,
+ .post_poweron = jt8ew9_post_poweron,
+};
+
+static int imx125es_post_poweron(struct smiapp_sensor *sensor)
+{
+ /* Taken from v02. No idea what the other two are. */
+ struct smiapp_reg_8 regs[] = {
+ /*
+ * 0x3302: clk during frame blanking:
+ * 0x00 - HS mode, 0x01 - LP11
+ */
+ { 0x3302, 0x01 },
+ { 0x302d, 0x00 },
+ { 0x3b08, 0x8c },
+ };
+
+ return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_imx125es_quirk = {
+ .post_poweron = imx125es_post_poweron,
+};
+
+static int jt8ev1_limits(struct smiapp_sensor *sensor)
+{
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
+ smiapp_replace_limit(sensor,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
+
+ return 0;
+}
+
+static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ struct smiapp_reg_8 regs[] = {
+ { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
+ { 0x30a3, 0xd0 }, /* FLASH STROBE enable */
+ { 0x3237, 0x00 }, /* For control of pulse timing for ADC */
+ { 0x3238, 0x43 },
+ { 0x3301, 0x06 }, /* For analog bias for sensor */
+ { 0x3302, 0x06 },
+ { 0x3304, 0x00 },
+ { 0x3305, 0x88 },
+ { 0x332a, 0x14 },
+ { 0x332c, 0x6b },
+ { 0x3336, 0x01 },
+ { 0x333f, 0x1f },
+ { 0x3355, 0x00 },
+ { 0x3356, 0x20 },
+ { 0x33bf, 0x20 }, /* Adjust the FBC speed */
+ { 0x33c9, 0x20 },
+ { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
+ { 0x33cf, 0xec }, /* For Black sun */
+ { 0x3328, 0x80 }, /* Ugh. No idea what's this. */
+ };
+
+ struct smiapp_reg_8 regs_96[] = {
+ { 0x30ae, 0x00 }, /* For control of ADC clock */
+ { 0x30af, 0xd0 },
+ { 0x30b0, 0x01 },
+ };
+
+ rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+ if (rval < 0)
+ return rval;
+
+ switch (sensor->platform_data->ext_clk) {
+ case 9600000:
+ return smiapp_write_8s(sensor, regs_96,
+ ARRAY_SIZE(regs_96));
+ default:
+ dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
+ sensor->platform_data->ext_clk);
+ return 0;
+ }
+}
+
+static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
+{
+ return smiapp_write_8(sensor, 0x3328, 0x00);
+}
+
+static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
+{
+ int rval;
+
+ /* Workaround: allows fast standby to work properly */
+ rval = smiapp_write_8(sensor, 0x3205, 0x04);
+ if (rval < 0)
+ return rval;
+
+ /* Wait for 1 ms + one line => 2 ms is likely enough */
+ usleep_range(2000, 2000);
+
+ /* Restore it */
+ rval = smiapp_write_8(sensor, 0x3205, 0x00);
+ if (rval < 0)
+ return rval;
+
+ return smiapp_write_8(sensor, 0x3328, 0x80);
+}
+
+const struct smiapp_quirk smiapp_jt8ev1_quirk = {
+ .limits = jt8ev1_limits,
+ .post_poweron = jt8ev1_post_poweron,
+ .pre_streamon = jt8ev1_pre_streamon,
+ .post_streamoff = jt8ev1_post_streamoff,
+ .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+};
+
+static int tcm8500md_limits(struct smiapp_sensor *sensor)
+{
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
+
+ return 0;
+}
+
+const struct smiapp_quirk smiapp_tcm8500md_quirk = {
+ .limits = tcm8500md_limits,
+};
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h
new file mode 100644
index 000000000000..86fd3e8bfb0f
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.h
@@ -0,0 +1,83 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-quirk.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_QUIRK__
+#define __SMIAPP_QUIRK__
+
+struct smiapp_sensor;
+
+/**
+ * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
+ *
+ * @limits: Replace sensor->limits with values which can't be read from
+ * sensor registers. Called the first time the sensor is powered up.
+ * @post_poweron: Called always after the sensor has been fully powered on.
+ * @pre_streamon: Called just before streaming is enabled.
+ * @post_streamon: Called right after stopping streaming.
+ */
+struct smiapp_quirk {
+ int (*limits)(struct smiapp_sensor *sensor);
+ int (*post_poweron)(struct smiapp_sensor *sensor);
+ int (*pre_streamon)(struct smiapp_sensor *sensor);
+ int (*post_streamoff)(struct smiapp_sensor *sensor);
+ const struct smia_reg *regs;
+ unsigned long flags;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
+#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 1)
+
+struct smiapp_reg_8 {
+ u16 reg;
+ u8 val;
+};
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+ u32 limit, u32 val);
+bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
+ u32 reg, u32 *val);
+
+#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
+ { \
+ .type = (_reg >> 16), \
+ .reg = (u16)_reg, \
+ .val = _val, \
+ }
+
+#define smiapp_call_quirk(_sensor, _quirk, ...) \
+ (_sensor->minfo.quirk && \
+ _sensor->minfo.quirk->_quirk ? \
+ _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+
+#define smiapp_needs_quirk(_sensor, _quirk) \
+ (_sensor->minfo.quirk ? \
+ _sensor->minfo.quirk->flags & _quirk : 0)
+
+extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
+extern const struct smiapp_quirk smiapp_imx125es_quirk;
+extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
+extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
+
+#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
new file mode 100644
index 000000000000..defa7c5adebf
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
@@ -0,0 +1,503 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-reg-defs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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
+ *
+ */
+#define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r))
+#define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r))
+#define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r))
+
+#define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002)
+#define SMIAPP_REG_U8_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION SMIAPP_REG_MK_U8(0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT SMIAPP_REG_MK_U8(0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER SMIAPP_REG_MK_U8(0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL SMIAPP_REG_MK_U16(0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH SMIAPP_REG_MK_U8(0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR SMIAPP_REG_MK_U8(0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION SMIAPP_REG_MK_U8(0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR SMIAPP_REG_MK_U8(0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH SMIAPP_REG_MK_U8(0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY SMIAPP_REG_MK_U8(0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE SMIAPP_REG_MK_U8(0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID SMIAPP_REG_MK_U16(0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER SMIAPP_REG_MK_U8(0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION SMIAPP_REG_MK_U8(0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER SMIAPP_REG_MK_U32(0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN SMIAPP_REG_MK_U16(0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX SMIAPP_REG_MK_U16(0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP SMIAPP_REG_MK_U16(0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE SMIAPP_REG_MK_U16(0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 SMIAPP_REG_MK_U16(0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 SMIAPP_REG_MK_U16(0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 SMIAPP_REG_MK_U16(0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 SMIAPP_REG_MK_U16(0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1))
+#define SMIAPP_REG_U8_MODE_SELECT SMIAPP_REG_MK_U8(0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION SMIAPP_REG_MK_U8(0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET SMIAPP_REG_MK_U8(0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD SMIAPP_REG_MK_U8(0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES SMIAPP_REG_MK_U8(0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL SMIAPP_REG_MK_U8(0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL SMIAPP_REG_MK_U8(0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER SMIAPP_REG_MK_U8(0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE SMIAPP_REG_MK_U8(0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT SMIAPP_REG_MK_U16(0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE SMIAPP_REG_MK_U8(0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT SMIAPP_REG_MK_U8(0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT SMIAPP_REG_MK_U8(0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT SMIAPP_REG_MK_U8(0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT SMIAPP_REG_MK_U8(0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT SMIAPP_REG_MK_U8(0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT SMIAPP_REG_MK_U8(0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT SMIAPP_REG_MK_U8(0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT SMIAPP_REG_MK_U8(0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT SMIAPP_REG_MK_U8(0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT SMIAPP_REG_MK_U8(0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE SMIAPP_REG_MK_U8(0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE SMIAPP_REG_MK_U16(0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE SMIAPP_REG_MK_U16(0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE SMIAPP_REG_MK_U16(0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ SMIAPP_REG_MK_U16(0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL SMIAPP_REG_MK_U8(0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE SMIAPP_REG_MK_U8(0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT SMIAPP_REG_MK_U8(0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL SMIAPP_REG_MK_U16(0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR SMIAPP_REG_MK_U16(0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED SMIAPP_REG_MK_U16(0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE SMIAPP_REG_MK_U16(0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB SMIAPP_REG_MK_U16(0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR SMIAPP_REG_MK_U16(0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED SMIAPP_REG_MK_U16(0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE SMIAPP_REG_MK_U16(0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB SMIAPP_REG_MK_U16(0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START SMIAPP_REG_MK_U16(0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START SMIAPP_REG_MK_U16(0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END SMIAPP_REG_MK_U16(0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END SMIAPP_REG_MK_U16(0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC SMIAPP_REG_MK_U16(0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC SMIAPP_REG_MK_U16(0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC SMIAPP_REG_MK_U16(0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC SMIAPP_REG_MK_U16(0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE SMIAPP_REG_MK_U16(0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING SMIAPP_REG_MK_U16(0x0402)
+#define SMIAPP_REG_U16_SCALE_M SMIAPP_REG_MK_U16(0x0404)
+#define SMIAPP_REG_U16_SCALE_N SMIAPP_REG_MK_U16(0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET SMIAPP_REG_MK_U16(0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET SMIAPP_REG_MK_U16(0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH SMIAPP_REG_MK_U16(0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT SMIAPP_REG_MK_U16(0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE SMIAPP_REG_MK_U16(0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE SMIAPP_REG_MK_U16(0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED SMIAPP_REG_MK_U16(0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR SMIAPP_REG_MK_U16(0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE SMIAPP_REG_MK_U16(0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB SMIAPP_REG_MK_U16(0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS SMIAPP_REG_MK_U16(0x0700)
+#define SMIAPP_REG_U8_TCLK_POST SMIAPP_REG_MK_U8(0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE SMIAPP_REG_MK_U8(0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN SMIAPP_REG_MK_U8(0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL SMIAPP_REG_MK_U8(0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN SMIAPP_REG_MK_U8(0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE SMIAPP_REG_MK_U8(0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO SMIAPP_REG_MK_U8(0x0806)
+#define SMIAPP_REG_U8_TLPX SMIAPP_REG_MK_U8(0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL SMIAPP_REG_MK_U8(0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS SMIAPP_REG_MK_U32(0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE SMIAPP_REG_MK_U8(0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE SMIAPP_REG_MK_U8(0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING SMIAPP_REG_MK_U8(0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL SMIAPP_REG_MK_U8(0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS SMIAPP_REG_MK_U8(0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 SMIAPP_REG_MK_U8(0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 SMIAPP_REG_MK_U8(0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 SMIAPP_REG_MK_U8(0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 SMIAPP_REG_MK_U8(0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 SMIAPP_REG_MK_U8(0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 SMIAPP_REG_MK_U8(0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 SMIAPP_REG_MK_U8(0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 SMIAPP_REG_MK_U8(0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 SMIAPP_REG_MK_U8(0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 SMIAPP_REG_MK_U8(0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 SMIAPP_REG_MK_U8(0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 SMIAPP_REG_MK_U8(0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 SMIAPP_REG_MK_U8(0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 SMIAPP_REG_MK_U8(0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 SMIAPP_REG_MK_U8(0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 SMIAPP_REG_MK_U8(0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 SMIAPP_REG_MK_U8(0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 SMIAPP_REG_MK_U8(0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 SMIAPP_REG_MK_U8(0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 SMIAPP_REG_MK_U8(0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 SMIAPP_REG_MK_U8(0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 SMIAPP_REG_MK_U8(0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 SMIAPP_REG_MK_U8(0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 SMIAPP_REG_MK_U8(0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 SMIAPP_REG_MK_U8(0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 SMIAPP_REG_MK_U8(0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 SMIAPP_REG_MK_U8(0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 SMIAPP_REG_MK_U8(0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 SMIAPP_REG_MK_U8(0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 SMIAPP_REG_MK_U8(0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 SMIAPP_REG_MK_U8(0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 SMIAPP_REG_MK_U8(0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 SMIAPP_REG_MK_U8(0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 SMIAPP_REG_MK_U8(0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 SMIAPP_REG_MK_U8(0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 SMIAPP_REG_MK_U8(0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 SMIAPP_REG_MK_U8(0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 SMIAPP_REG_MK_U8(0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 SMIAPP_REG_MK_U8(0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 SMIAPP_REG_MK_U8(0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 SMIAPP_REG_MK_U8(0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 SMIAPP_REG_MK_U8(0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 SMIAPP_REG_MK_U8(0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 SMIAPP_REG_MK_U8(0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 SMIAPP_REG_MK_U8(0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 SMIAPP_REG_MK_U8(0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 SMIAPP_REG_MK_U8(0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 SMIAPP_REG_MK_U8(0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 SMIAPP_REG_MK_U8(0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 SMIAPP_REG_MK_U8(0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 SMIAPP_REG_MK_U8(0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 SMIAPP_REG_MK_U8(0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 SMIAPP_REG_MK_U8(0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 SMIAPP_REG_MK_U8(0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 SMIAPP_REG_MK_U8(0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 SMIAPP_REG_MK_U8(0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 SMIAPP_REG_MK_U8(0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 SMIAPP_REG_MK_U8(0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL SMIAPP_REG_MK_U8(0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS SMIAPP_REG_MK_U8(0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 SMIAPP_REG_MK_U8(0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 SMIAPP_REG_MK_U8(0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 SMIAPP_REG_MK_U8(0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 SMIAPP_REG_MK_U8(0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 SMIAPP_REG_MK_U8(0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 SMIAPP_REG_MK_U8(0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 SMIAPP_REG_MK_U8(0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 SMIAPP_REG_MK_U8(0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 SMIAPP_REG_MK_U8(0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 SMIAPP_REG_MK_U8(0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 SMIAPP_REG_MK_U8(0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 SMIAPP_REG_MK_U8(0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 SMIAPP_REG_MK_U8(0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 SMIAPP_REG_MK_U8(0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 SMIAPP_REG_MK_U8(0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 SMIAPP_REG_MK_U8(0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 SMIAPP_REG_MK_U8(0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 SMIAPP_REG_MK_U8(0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 SMIAPP_REG_MK_U8(0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 SMIAPP_REG_MK_U8(0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 SMIAPP_REG_MK_U8(0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 SMIAPP_REG_MK_U8(0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 SMIAPP_REG_MK_U8(0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 SMIAPP_REG_MK_U8(0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 SMIAPP_REG_MK_U8(0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 SMIAPP_REG_MK_U8(0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 SMIAPP_REG_MK_U8(0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 SMIAPP_REG_MK_U8(0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 SMIAPP_REG_MK_U8(0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 SMIAPP_REG_MK_U8(0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 SMIAPP_REG_MK_U8(0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 SMIAPP_REG_MK_U8(0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 SMIAPP_REG_MK_U8(0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 SMIAPP_REG_MK_U8(0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 SMIAPP_REG_MK_U8(0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 SMIAPP_REG_MK_U8(0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 SMIAPP_REG_MK_U8(0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 SMIAPP_REG_MK_U8(0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 SMIAPP_REG_MK_U8(0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 SMIAPP_REG_MK_U8(0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 SMIAPP_REG_MK_U8(0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 SMIAPP_REG_MK_U8(0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 SMIAPP_REG_MK_U8(0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 SMIAPP_REG_MK_U8(0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 SMIAPP_REG_MK_U8(0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 SMIAPP_REG_MK_U8(0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 SMIAPP_REG_MK_U8(0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 SMIAPP_REG_MK_U8(0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 SMIAPP_REG_MK_U8(0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 SMIAPP_REG_MK_U8(0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 SMIAPP_REG_MK_U8(0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 SMIAPP_REG_MK_U8(0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 SMIAPP_REG_MK_U8(0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 SMIAPP_REG_MK_U8(0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 SMIAPP_REG_MK_U8(0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 SMIAPP_REG_MK_U8(0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 SMIAPP_REG_MK_U8(0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 SMIAPP_REG_MK_U8(0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 SMIAPP_REG_MK_U8(0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 SMIAPP_REG_MK_U8(0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 SMIAPP_REG_MK_U8(0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 SMIAPP_REG_MK_U8(0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 SMIAPP_REG_MK_U8(0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 SMIAPP_REG_MK_U8(0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL SMIAPP_REG_MK_U8(0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE SMIAPP_REG_MK_U8(0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT SMIAPP_REG_MK_U8(0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT SMIAPP_REG_MK_U8(0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE SMIAPP_REG_MK_U8(0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS SMIAPP_REG_MK_U8(0x0b83)
+#define SMIAPP_REG_U8_DENOISING SMIAPP_REG_MK_U8(0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC SMIAPP_REG_MK_U8(0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL SMIAPP_REG_MK_U8(0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE SMIAPP_REG_MK_U16(0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR SMIAPP_REG_MK_U16(0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED SMIAPP_REG_MK_U16(0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE SMIAPP_REG_MK_U16(0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB SMIAPP_REG_MK_U16(0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE SMIAPP_REG_MK_U8(0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING SMIAPP_REG_MK_U16(0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START SMIAPP_REG_MK_U16(0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START SMIAPP_REG_MK_U16(0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH SMIAPP_REG_MK_U16(0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT SMIAPP_REG_MK_U16(0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 SMIAPP_REG_MK_U8(0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 SMIAPP_REG_MK_U8(0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 SMIAPP_REG_MK_U8(0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 SMIAPP_REG_MK_U8(0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL SMIAPP_REG_MK_U16(0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL SMIAPP_REG_MK_U16(0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL SMIAPP_REG_MK_U16(0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT SMIAPP_REG_MK_U8(0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL SMIAPP_REG_MK_U16(0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS SMIAPP_REG_MK_U8(0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS SMIAPP_REG_MK_U8(0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS SMIAPP_REG_MK_U8(0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE SMIAPP_REG_MK_U8(0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER SMIAPP_REG_MK_U8(0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS SMIAPP_REG_MK_U8(0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL SMIAPP_REG_MK_U16(0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL SMIAPP_REG_MK_U8(0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL SMIAPP_REG_MK_U8(0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL SMIAPP_REG_MK_U16(0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL SMIAPP_REG_MK_U8(0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT SMIAPP_REG_MK_U16(0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL SMIAPP_REG_MK_U8(0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE SMIAPP_REG_MK_U8(0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1 SMIAPP_REG_MK_U8(0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2 SMIAPP_REG_MK_U8(0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE SMIAPP_REG_MK_U16(0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL SMIAPP_REG_MK_U16(0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 SMIAPP_REG_MK_U16(0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 SMIAPP_REG_MK_U16(0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 SMIAPP_REG_MK_U8(0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 SMIAPP_REG_MK_U8(0x0d89)
+#define SMIAPP_REG_U8_POSITION SMIAPP_REG_MK_U8(0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL SMIAPP_REG_MK_U8(0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE SMIAPP_REG_MK_U8(0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL SMIAPP_REG_MK_U8(0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START SMIAPP_REG_MK_U8(0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END SMIAPP_REG_MK_U8(0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY SMIAPP_REG_MK_U16(0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN SMIAPP_REG_MK_U16(0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX SMIAPP_REG_MK_U16(0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE SMIAPP_REG_MK_U16(0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1100)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1104)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x110c)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x1110)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x1118)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x111c)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1124)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1128)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x112c)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1130)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK SMIAPP_REG_MK_U16(0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES SMIAPP_REG_MK_U16(0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE SMIAPP_REG_MK_U8(0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1164)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1168)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1170)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1174)
+#define SMIAPP_REG_U16_X_ADDR_MIN SMIAPP_REG_MK_U16(0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN SMIAPP_REG_MK_U16(0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX SMIAPP_REG_MK_U16(0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX SMIAPP_REG_MK_U16(0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC SMIAPP_REG_MK_U16(0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC SMIAPP_REG_MK_U16(0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC SMIAPP_REG_MK_U16(0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC SMIAPP_REG_MK_U16(0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY SMIAPP_REG_MK_U16(0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN SMIAPP_REG_MK_U16(0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX SMIAPP_REG_MK_U16(0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN SMIAPP_REG_MK_U16(0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX SMIAPP_REG_MK_U16(0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY SMIAPP_REG_MK_U16(0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY SMIAPP_REG_MK_U8(0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY SMIAPP_REG_MK_U16(0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED SMIAPP_REG_MK_U16(0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED SMIAPP_REG_MK_U16(0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED SMIAPP_REG_MK_U16(0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN SMIAPP_REG_MK_U16(0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN SMIAPP_REG_MK_U16(0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN SMIAPP_REG_MK_U16(0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE SMIAPP_REG_MK_U16(0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE SMIAPP_REG_MK_U16(0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE SMIAPP_REG_MK_U16(0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS SMIAPP_REG_MK_U16(0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY SMIAPP_REG_MK_U8(0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY SMIAPP_REG_MK_U8(0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY SMIAPP_REG_MK_U8(0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY SMIAPP_REG_MK_U8(0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY SMIAPP_REG_MK_U8(0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN SMIAPP_REG_MK_U16(0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN SMIAPP_REG_MK_U16(0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN SMIAPP_REG_MK_U16(0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY SMIAPP_REG_MK_U8(0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY SMIAPP_REG_MK_U8(0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES SMIAPP_REG_MK_U8(0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_n(n) SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY SMIAPP_REG_MK_U8(0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY SMIAPP_REG_MK_U8(0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY SMIAPP_REG_MK_U8(0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY SMIAPP_REG_MK_U16(0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 SMIAPP_REG_MK_U16(0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY SMIAPP_REG_MK_U8(0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES SMIAPP_REG_MK_U8(0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ SMIAPP_REG_MK_U8(0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ SMIAPP_REG_MK_U8(0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ SMIAPP_REG_MK_U8(0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ SMIAPP_REG_MK_U8(0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ SMIAPP_REG_MK_U8(0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY SMIAPP_REG_MK_U8(0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM SMIAPP_REG_MK_U8(0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY SMIAPP_REG_MK_U8(0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN SMIAPP_REG_MK_U16(0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR SMIAPP_REG_MK_U16(0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY SMIAPP_REG_MK_U8(0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE SMIAPP_REG_MK_U16(0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS SMIAPP_REG_MK_U8(0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS SMIAPP_REG_MK_U16(0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 SMIAPP_REG_MK_U8(0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 SMIAPP_REG_MK_U8(0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE SMIAPP_REG_MK_U8(0x1c02)
diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h
new file mode 100644
index 000000000000..54568ca2fe6d
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-reg.h
@@ -0,0 +1,122 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-reg.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_REG_H_
+#define __SMIAPP_REG_H_
+
+#include "smiapp-reg-defs.h"
+
+/* Bits for above register */
+#define SMIAPP_IMAGE_ORIENTATION_HFLIP (1 << 0)
+#define SMIAPP_IMAGE_ORIENTATION_VFLIP (1 << 1)
+
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN (1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN (0 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN (1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR (1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY (1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY (1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA (1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE (1 << 3)
+
+#define SMIAPP_SOFTWARE_RESET (1 << 0)
+
+#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE (1 << 0)
+#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE (1 << 1)
+
+#define SMIAPP_DPHY_CTRL_AUTOMATIC 0
+/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
+#define SMIAPP_DPHY_CTRL_UI 1
+#define SMIAPP_DPHY_CTRL_REGISTER 2
+
+#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1
+#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2
+
+#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0
+#define SMIAPP_MODE_SELECT_STREAMING 1
+
+#define SMIAPP_SCALING_MODE_NONE 0
+#define SMIAPP_SCALING_MODE_HORIZONTAL 1
+#define SMIAPP_SCALING_MODE_BOTH 2
+
+#define SMIAPP_SCALING_CAPABILITY_NONE 0
+#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1
+#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */
+
+/* digital crop right before scaler */
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1
+
+#define SMIAPP_BINNING_CAPABILITY_NO 0
+#define SMIAPP_BINNING_CAPABILITY_YES 1
+
+/* Maximum number of binning subtypes */
+#define SMIAPP_BINNING_SUBTYPES 253
+
+#define SMIAPP_PIXEL_ORDER_GRBG 0
+#define SMIAPP_PIXEL_ORDER_RGGB 1
+#define SMIAPP_PIXEL_ORDER_BGGR 2
+#define SMIAPP_PIXEL_ORDER_GBRG 3
+
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16
+
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4
+
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff
+
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff
+
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5
+
+#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0
+#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1
+
+/* Scaling N factor */
+#define SMIAPP_SCALE_N 16
+
+/* Image statistics registers */
+/* Registers 0x2000 to 0x2fff are reserved for future
+ * use for statistics features.
+ */
+
+/* Manufacturer Specific Registers: 0x3000 to 0x3fff
+ * The manufacturer specifies these as a black box.
+ */
+
+#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c
new file mode 100644
index 000000000000..70e0d8db0130
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp-regs.c
@@ -0,0 +1,273 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp-regs.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/delay.h>
+#include <linux/i2c.h>
+
+#include "smiapp.h"
+#include "smiapp-regs.h"
+
+static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
+ uint32_t phloat)
+{
+ int32_t exp;
+ uint64_t man;
+
+ if (phloat >= 0x80000000) {
+ dev_err(&client->dev, "this is a negative number\n");
+ return 0;
+ }
+
+ if (phloat == 0x7f800000)
+ return ~0; /* Inf. */
+
+ if ((phloat & 0x7f800000) == 0x7f800000) {
+ dev_err(&client->dev, "NaN or other special number\n");
+ return 0;
+ }
+
+ /* Valid cases begin here */
+ if (phloat == 0)
+ return 0; /* Valid zero */
+
+ if (phloat > 0x4f800000)
+ return ~0; /* larger than 4294967295 */
+
+ /*
+ * Unbias exponent (note how phloat is now guaranteed to
+ * have 0 in the high bit)
+ */
+ exp = ((int32_t)phloat >> 23) - 127;
+
+ /* Extract mantissa, add missing '1' bit and it's in MHz */
+ man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
+
+ if (exp < 0)
+ man >>= -exp;
+ else
+ man <<= exp;
+
+ man >>= 23; /* Remove mantissa bias */
+
+ return man & 0xffffffff;
+}
+
+
+/*
+ * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
+ u16 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct i2c_msg msg;
+ unsigned char data[4];
+ u16 offset = reg;
+ int r;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (offset >> 8);
+ data[1] = (u8) offset;
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ if (r >= 0)
+ r = -EBUSY;
+ goto err;
+ }
+
+ msg.len = len;
+ msg.flags = I2C_M_RD;
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ if (r >= 0)
+ r = -EBUSY;
+ goto err;
+ }
+
+ *val = 0;
+ /* high byte comes first */
+ switch (len) {
+ case SMIA_REG_32BIT:
+ *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+ data[3];
+ break;
+ case SMIA_REG_16BIT:
+ *val = (data[0] << 8) + data[1];
+ break;
+ case SMIA_REG_8BIT:
+ *val = data[0];
+ break;
+ default:
+ BUG();
+ }
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+
+ return r;
+}
+
+/* Read a register using 8-bit access only. */
+static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg,
+ u16 len, u32 *val)
+{
+ unsigned int i;
+ int rval;
+
+ *val = 0;
+
+ for (i = 0; i < len; i++) {
+ u32 val8;
+
+ rval = ____smiapp_read(sensor, reg + i, 1, &val8);
+ if (rval < 0)
+ return rval;
+ *val |= val8 << ((len - i - 1) << 3);
+ }
+
+ return 0;
+}
+
+/*
+ * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
+ bool only8)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int len = (u8)(reg >> 16);
+ int rval;
+
+ if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
+ && len != SMIA_REG_32BIT)
+ return -EINVAL;
+
+ if (smiapp_quirk_reg(sensor, reg, val))
+ goto found_quirk;
+
+ if (len == SMIA_REG_8BIT && !only8)
+ rval = ____smiapp_read(sensor, (u16)reg, len, val);
+ else
+ rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
+ if (rval < 0)
+ return rval;
+
+found_quirk:
+ if (reg & SMIA_REG_FLAG_FLOAT)
+ *val = float_to_u32_mul_1000000(client, *val);
+
+ return 0;
+}
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+ return __smiapp_read(
+ sensor, reg, val,
+ smiapp_needs_quirk(sensor,
+ SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
+}
+
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+ return __smiapp_read(sensor, reg, val, true);
+}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct i2c_msg msg;
+ unsigned char data[6];
+ unsigned int retries;
+ unsigned int flags = reg >> 24;
+ unsigned int len = (u8)(reg >> 16);
+ u16 offset = reg;
+ int r;
+
+ if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
+ len != SMIA_REG_32BIT) || flags)
+ return -EINVAL;
+
+ msg.addr = client->addr;
+ msg.flags = 0; /* Write */
+ msg.len = 2 + len;
+ msg.buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (reg >> 8);
+ data[1] = (u8) (reg & 0xff);
+
+ switch (len) {
+ case SMIA_REG_8BIT:
+ data[2] = val;
+ break;
+ case SMIA_REG_16BIT:
+ data[2] = val >> 8;
+ data[3] = val;
+ break;
+ case SMIA_REG_32BIT:
+ data[2] = val >> 24;
+ data[3] = val >> 16;
+ data[4] = val >> 8;
+ data[5] = val;
+ break;
+ default:
+ BUG();
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ /*
+ * Due to unknown reason sensor stops responding. This
+ * loop is a temporaty solution until the root cause
+ * is found.
+ */
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r == 1) {
+ if (retries)
+ dev_err(&client->dev,
+ "sensor i2c stall encountered. "
+ "retries: %d\n", retries);
+ return 0;
+ }
+
+ usleep_range(2000, 2000);
+ }
+
+ dev_err(&client->dev,
+ "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+
+ return r;
+}
diff --git a/drivers/media/video/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h
index 7f9013b47971..7f9013b47971 100644
--- a/drivers/media/video/smiapp/smiapp-regs.h
+++ b/drivers/media/i2c/smiapp/smiapp-regs.h
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
new file mode 100644
index 000000000000..4182a695ab53
--- /dev/null
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -0,0 +1,252 @@
+/*
+ * drivers/media/i2c/smiapp/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_PRIV_H_
+#define __SMIAPP_PRIV_H_
+
+#include <linux/mutex.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/smiapp.h>
+
+#include "smiapp-pll.h"
+#include "smiapp-reg.h"
+#include "smiapp-regs.h"
+#include "smiapp-quirk.h"
+
+/*
+ * Standard SMIA++ constants
+ */
+#define SMIA_VERSION_1 10
+#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */
+#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */
+#define SMIAPP_VERSION_1 10
+
+#define SMIAPP_PROFILE_0 0
+#define SMIAPP_PROFILE_1 1
+#define SMIAPP_PROFILE_2 2
+
+#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */
+
+#define SMIAPP_RESET_DELAY_CLOCKS 2400
+#define SMIAPP_RESET_DELAY(clk) \
+ (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \
+ + (clk) / 1000 - 1) / ((clk) / 1000))
+
+#include "smiapp-limits.h"
+
+struct smiapp_quirk;
+
+#define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0)
+
+struct smiapp_module_ident {
+ u8 manufacturer_id;
+ u16 model_id;
+ u8 revision_number_major;
+
+ u8 flags;
+
+ char *name;
+ const struct smiapp_quirk *quirk;
+};
+
+struct smiapp_module_info {
+ u32 manufacturer_id;
+ u32 model_id;
+ u32 revision_number_major;
+ u32 revision_number_minor;
+
+ u32 module_year;
+ u32 module_month;
+ u32 module_day;
+
+ u32 sensor_manufacturer_id;
+ u32 sensor_model_id;
+ u32 sensor_revision_number;
+ u32 sensor_firmware_version;
+
+ u32 smia_version;
+ u32 smiapp_version;
+
+ u32 smiapp_profile;
+
+ char *name;
+ const struct smiapp_quirk *quirk;
+};
+
+#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = fl, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
+ .name = _name, }
+
+#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = 0, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT(manufacturer, model, rev, _name) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = 0, \
+ .name = _name, }
+
+struct smiapp_reg_limits {
+ u32 addr;
+ char *what;
+};
+
+extern struct smiapp_reg_limits smiapp_reg_limits[];
+
+struct smiapp_csi_data_format {
+ u32 code;
+ u8 width;
+ u8 compressed;
+ u8 pixel_order;
+};
+
+#define SMIAPP_SUBDEVS 3
+
+#define SMIAPP_PA_PAD_SRC 0
+#define SMIAPP_PAD_SINK 0
+#define SMIAPP_PAD_SRC 1
+#define SMIAPP_PADS 2
+
+struct smiapp_binning_subtype {
+ u8 horizontal:4;
+ u8 vertical:4;
+} __packed;
+
+struct smiapp_subdev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[2];
+ struct v4l2_rect sink_fmt;
+ struct v4l2_rect crop[2];
+ struct v4l2_rect compose; /* compose on sink */
+ unsigned short sink_pad;
+ unsigned short source_pad;
+ int npads;
+ struct smiapp_sensor *sensor;
+ struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct smiapp_sensor - Main device structure
+ */
+struct smiapp_sensor {
+ /*
+ * "mutex" is used to serialise access to all fields here
+ * except v4l2_ctrls at the end of the struct. "mutex" is also
+ * used to serialise access to file handle specific
+ * information. The exception to this rule is the power_mutex
+ * below.
+ */
+ struct mutex mutex;
+ /*
+ * power_mutex is used to serialise power management related
+ * activities. Acquiring "mutex" at that time isn't necessary
+ * since there are no other users anyway.
+ */
+ struct mutex power_mutex;
+ struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
+ u32 ssds_used;
+ struct smiapp_subdev *src;
+ struct smiapp_subdev *binner;
+ struct smiapp_subdev *scaler;
+ struct smiapp_subdev *pixel_array;
+ struct smiapp_platform_data *platform_data;
+ struct regulator *vana;
+ struct clk *ext_clk;
+ u32 limits[SMIAPP_LIMIT_LAST];
+ u8 nbinning_subtypes;
+ struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
+ u32 mbus_frame_fmts;
+ const struct smiapp_csi_data_format *csi_format;
+ const struct smiapp_csi_data_format *internal_csi_format;
+ u32 default_mbus_frame_fmts;
+ int default_pixel_order;
+
+ u8 binning_horizontal;
+ u8 binning_vertical;
+
+ u8 scale_m;
+ u8 scaling_mode;
+
+ u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
+ u8 flash_capability;
+ u8 frame_skip;
+
+ int power_count;
+
+ bool streaming;
+ bool dev_init_done;
+
+ u8 *nvm; /* nvm memory buffer */
+ unsigned int nvm_size; /* bytes */
+
+ struct smiapp_module_info minfo;
+
+ struct smiapp_pll pll;
+
+ /* Pixel array controls */
+ struct v4l2_ctrl *analog_gain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *pixel_rate_parray;
+ /* src controls */
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate_csi;
+};
+
+#define to_smiapp_subdev(_sd) \
+ container_of(_sd, struct smiapp_subdev, sd)
+
+#define to_smiapp_sensor(_sd) \
+ (to_smiapp_subdev(_sd)->sensor)
+
+#endif /* __SMIAPP_PRIV_H_ */
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
new file mode 100644
index 000000000000..6dff2b7ad520
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/Kconfig
@@ -0,0 +1,89 @@
+comment "soc_camera sensor drivers"
+
+config SOC_CAMERA_IMX074
+ tristate "imx074 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports IMX074 cameras from Sony
+
+config SOC_CAMERA_MT9M001
+ tristate "mt9m001 support"
+ depends on SOC_CAMERA && I2C
+ select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+ help
+ This driver supports MT9M001 cameras from Micron, monochrome
+ and colour models.
+
+config SOC_CAMERA_MT9M111
+ tristate "mt9m111, mt9m112 and mt9m131 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9M111, MT9M112 and MT9M131 cameras from
+ Micron/Aptina
+
+config SOC_CAMERA_MT9T031
+ tristate "mt9t031 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9T031 cameras from Micron.
+
+config SOC_CAMERA_MT9T112
+ tristate "mt9t112 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9T112 cameras from Aptina.
+
+config SOC_CAMERA_MT9V022
+ tristate "mt9v022 and mt9v024 support"
+ depends on SOC_CAMERA && I2C
+ select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+ help
+ This driver supports MT9V022 cameras from Micron
+
+config SOC_CAMERA_OV2640
+ tristate "ov2640 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov2640 camera driver
+
+config SOC_CAMERA_OV5642
+ tristate "ov5642 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a V4L2 camera driver for the OmniVision OV5642 sensor
+
+config SOC_CAMERA_OV6650
+ tristate "ov6650 sensor support"
+ depends on SOC_CAMERA && I2C
+ ---help---
+ This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
+
+config SOC_CAMERA_OV772X
+ tristate "ov772x camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov772x camera driver
+
+config SOC_CAMERA_OV9640
+ tristate "ov9640 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov9640 camera driver
+
+config SOC_CAMERA_OV9740
+ tristate "ov9740 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov9740 camera driver
+
+config SOC_CAMERA_RJ54N1
+ tristate "rj54n1cb0c support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a rj54n1cb0c video driver
+
+config SOC_CAMERA_TW9910
+ tristate "tw9910 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a tw9910 video driver
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
new file mode 100644
index 000000000000..d0421feaa796
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o
+obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o
+obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
+obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
+obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
+obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
+obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
+obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
new file mode 100644
index 000000000000..f8534eec9de9
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -0,0 +1,495 @@
+/*
+ * Driver for IMX074 CMOS Image Sensor from Sony
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Partially inspired by the IMX074 driver from the Android / MSM tree
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+/* IMX074 registers */
+
+#define MODE_SELECT 0x0100
+#define IMAGE_ORIENTATION 0x0101
+#define GROUPED_PARAMETER_HOLD 0x0104
+
+/* Integration Time */
+#define COARSE_INTEGRATION_TIME_HI 0x0202
+#define COARSE_INTEGRATION_TIME_LO 0x0203
+/* Gain */
+#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204
+#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205
+
+/* PLL registers */
+#define PRE_PLL_CLK_DIV 0x0305
+#define PLL_MULTIPLIER 0x0307
+#define PLSTATIM 0x302b
+#define VNDMY_ABLMGSHLMT 0x300a
+#define Y_OPBADDR_START_DI 0x3014
+/* mode setting */
+#define FRAME_LENGTH_LINES_HI 0x0340
+#define FRAME_LENGTH_LINES_LO 0x0341
+#define LINE_LENGTH_PCK_HI 0x0342
+#define LINE_LENGTH_PCK_LO 0x0343
+#define YADDR_START 0x0347
+#define YADDR_END 0x034b
+#define X_OUTPUT_SIZE_MSB 0x034c
+#define X_OUTPUT_SIZE_LSB 0x034d
+#define Y_OUTPUT_SIZE_MSB 0x034e
+#define Y_OUTPUT_SIZE_LSB 0x034f
+#define X_EVEN_INC 0x0381
+#define X_ODD_INC 0x0383
+#define Y_EVEN_INC 0x0385
+#define Y_ODD_INC 0x0387
+
+#define HMODEADD 0x3001
+#define VMODEADD 0x3016
+#define VAPPLINE_START 0x3069
+#define VAPPLINE_END 0x306b
+#define SHUTTER 0x3086
+#define HADDAVE 0x30e8
+#define LANESEL 0x3301
+
+/* IMX074 supported geometry */
+#define IMX074_WIDTH 1052
+#define IMX074_HEIGHT 780
+
+/* IMX074 has only one fixed colorspace per pixelcode */
+struct imx074_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct imx074 {
+ struct v4l2_subdev subdev;
+ const struct imx074_datafmt *fmt;
+};
+
+static const struct imx074_datafmt imx074_colour_fmts[] = {
+ {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static struct imx074 *to_imx074(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct imx074, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++)
+ if (imx074_colour_fmts[i].code == code)
+ return imx074_colour_fmts + i;
+
+ return NULL;
+}
+
+static int reg_write(struct i2c_client *client, const u16 addr, const u8 data)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+ unsigned char tx[3];
+ int ret;
+
+ msg.addr = client->addr;
+ msg.buf = tx;
+ msg.len = 3;
+ msg.flags = 0;
+
+ tx[0] = addr >> 8;
+ tx[1] = addr & 0xff;
+ tx[2] = data;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ mdelay(2);
+
+ return ret == 1 ? 0 : -EIO;
+}
+
+static int reg_read(struct i2c_client *client, const u16 addr)
+{
+ u8 buf[2] = {addr >> 8, addr & 0xff};
+ int ret;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buf,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 2,
+ .buf = buf,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0) {
+ dev_warn(&client->dev, "Reading register %x from %x failed\n",
+ addr, client->addr);
+ return ret;
+ }
+
+ return buf[0] & 0xff; /* no sign-extension */
+}
+
+static int imx074_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code);
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+ if (!fmt) {
+ mf->code = imx074_colour_fmts[0].code;
+ mf->colorspace = imx074_colour_fmts[0].colorspace;
+ }
+
+ mf->width = IMX074_WIDTH;
+ mf->height = IMX074_HEIGHT;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int imx074_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx074 *priv = to_imx074(client);
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+ /* MIPI CSI could have changed the format, double-check */
+ if (!imx074_find_datafmt(mf->code))
+ return -EINVAL;
+
+ imx074_try_fmt(sd, mf);
+
+ priv->fmt = imx074_find_datafmt(mf->code);
+
+ return 0;
+}
+
+static int imx074_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx074 *priv = to_imx074(client);
+
+ const struct imx074_datafmt *fmt = priv->fmt;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->width = IMX074_WIDTH;
+ mf->height = IMX074_HEIGHT;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct v4l2_rect *rect = &a->c;
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rect->top = 0;
+ rect->left = 0;
+ rect->width = IMX074_WIDTH;
+ rect->height = IMX074_HEIGHT;
+
+ return 0;
+}
+
+static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = IMX074_WIDTH;
+ a->bounds.height = IMX074_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
+ return -EINVAL;
+
+ *code = imx074_colour_fmts[index].code;
+ return 0;
+}
+
+static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* MODE_SELECT: stream or standby */
+ return reg_write(client, MODE_SELECT, !!enable);
+}
+
+static int imx074_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = V4L2_IDENT_IMX074;
+ id->revision = 0;
+
+ return 0;
+}
+
+static int imx074_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int imx074_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ cfg->type = V4L2_MBUS_CSI2;
+ cfg->flags = V4L2_MBUS_CSI2_2_LANE |
+ V4L2_MBUS_CSI2_CHANNEL_0 |
+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
+ .s_stream = imx074_s_stream,
+ .s_mbus_fmt = imx074_s_fmt,
+ .g_mbus_fmt = imx074_g_fmt,
+ .try_mbus_fmt = imx074_try_fmt,
+ .enum_mbus_fmt = imx074_enum_fmt,
+ .g_crop = imx074_g_crop,
+ .cropcap = imx074_cropcap,
+ .g_mbus_config = imx074_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+ .g_chip_ident = imx074_g_chip_ident,
+ .s_power = imx074_s_power,
+};
+
+static struct v4l2_subdev_ops imx074_subdev_ops = {
+ .core = &imx074_subdev_core_ops,
+ .video = &imx074_subdev_video_ops,
+};
+
+static int imx074_video_probe(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ int ret;
+ u16 id;
+
+ ret = imx074_s_power(subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Read sensor Model ID */
+ ret = reg_read(client, 0);
+ if (ret < 0)
+ goto done;
+
+ id = ret << 8;
+
+ ret = reg_read(client, 1);
+ if (ret < 0)
+ goto done;
+
+ id |= ret;
+
+ dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+ if (id != 0x74) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ /* PLL Setting EXTCLK=24MHz, 22.5times */
+ reg_write(client, PLL_MULTIPLIER, 0x2D);
+ reg_write(client, PRE_PLL_CLK_DIV, 0x02);
+ reg_write(client, PLSTATIM, 0x4B);
+
+ /* 2-lane mode */
+ reg_write(client, 0x3024, 0x00);
+
+ reg_write(client, IMAGE_ORIENTATION, 0x00);
+
+ /* select RAW mode:
+ * 0x08+0x08 = top 8 bits
+ * 0x0a+0x08 = compressed 8-bits
+ * 0x0a+0x0a = 10 bits
+ */
+ reg_write(client, 0x0112, 0x08);
+ reg_write(client, 0x0113, 0x08);
+
+ /* Base setting for High frame mode */
+ reg_write(client, VNDMY_ABLMGSHLMT, 0x80);
+ reg_write(client, Y_OPBADDR_START_DI, 0x08);
+ reg_write(client, 0x3015, 0x37);
+ reg_write(client, 0x301C, 0x01);
+ reg_write(client, 0x302C, 0x05);
+ reg_write(client, 0x3031, 0x26);
+ reg_write(client, 0x3041, 0x60);
+ reg_write(client, 0x3051, 0x24);
+ reg_write(client, 0x3053, 0x34);
+ reg_write(client, 0x3057, 0xC0);
+ reg_write(client, 0x305C, 0x09);
+ reg_write(client, 0x305D, 0x07);
+ reg_write(client, 0x3060, 0x30);
+ reg_write(client, 0x3065, 0x00);
+ reg_write(client, 0x30AA, 0x08);
+ reg_write(client, 0x30AB, 0x1C);
+ reg_write(client, 0x30B0, 0x32);
+ reg_write(client, 0x30B2, 0x83);
+ reg_write(client, 0x30D3, 0x04);
+ reg_write(client, 0x3106, 0x78);
+ reg_write(client, 0x310C, 0x82);
+ reg_write(client, 0x3304, 0x05);
+ reg_write(client, 0x3305, 0x04);
+ reg_write(client, 0x3306, 0x11);
+ reg_write(client, 0x3307, 0x02);
+ reg_write(client, 0x3308, 0x0C);
+ reg_write(client, 0x3309, 0x06);
+ reg_write(client, 0x330A, 0x08);
+ reg_write(client, 0x330B, 0x04);
+ reg_write(client, 0x330C, 0x08);
+ reg_write(client, 0x330D, 0x06);
+ reg_write(client, 0x330E, 0x01);
+ reg_write(client, 0x3381, 0x00);
+
+ /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */
+ /* 1608 = 1560 + 48 (black lines) */
+ reg_write(client, FRAME_LENGTH_LINES_HI, 0x06);
+ reg_write(client, FRAME_LENGTH_LINES_LO, 0x48);
+ reg_write(client, YADDR_START, 0x00);
+ reg_write(client, YADDR_END, 0x2F);
+ /* 0x838 == 2104 */
+ reg_write(client, X_OUTPUT_SIZE_MSB, 0x08);
+ reg_write(client, X_OUTPUT_SIZE_LSB, 0x38);
+ /* 0x618 == 1560 */
+ reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06);
+ reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18);
+ reg_write(client, X_EVEN_INC, 0x01);
+ reg_write(client, X_ODD_INC, 0x03);
+ reg_write(client, Y_EVEN_INC, 0x01);
+ reg_write(client, Y_ODD_INC, 0x03);
+ reg_write(client, HMODEADD, 0x00);
+ reg_write(client, VMODEADD, 0x16);
+ reg_write(client, VAPPLINE_START, 0x24);
+ reg_write(client, VAPPLINE_END, 0x53);
+ reg_write(client, SHUTTER, 0x00);
+ reg_write(client, HADDAVE, 0x80);
+
+ reg_write(client, LANESEL, 0x00);
+
+ reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */
+
+ ret = 0;
+
+done:
+ imx074_s_power(subdev, 0);
+ return ret;
+}
+
+static int imx074_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct imx074 *priv;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "IMX074: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+
+ priv->fmt = &imx074_colour_fmts[0];
+
+ ret = imx074_video_probe(client);
+ if (ret < 0) {
+ kfree(priv);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int imx074_remove(struct i2c_client *client)
+{
+ struct imx074 *priv = to_imx074(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ if (icl->free_bus)
+ icl->free_bus(icl);
+ kfree(priv);
+
+ return 0;
+}
+
+static const struct i2c_device_id imx074_id[] = {
+ { "imx074", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, imx074_id);
+
+static struct i2c_driver imx074_i2c_driver = {
+ .driver = {
+ .name = "imx074",
+ },
+ .probe = imx074_probe,
+ .remove = imx074_remove,
+ .id_table = imx074_id,
+};
+
+module_i2c_driver(imx074_i2c_driver);
+
+MODULE_DESCRIPTION("Sony IMX074 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
new file mode 100644
index 000000000000..d85be41ffa1d
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -0,0 +1,757 @@
+/*
+ * Driver for MT9M001 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9m001 i2c address 0x5d
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_link
+ */
+
+/* mt9m001 selected register addresses */
+#define MT9M001_CHIP_VERSION 0x00
+#define MT9M001_ROW_START 0x01
+#define MT9M001_COLUMN_START 0x02
+#define MT9M001_WINDOW_HEIGHT 0x03
+#define MT9M001_WINDOW_WIDTH 0x04
+#define MT9M001_HORIZONTAL_BLANKING 0x05
+#define MT9M001_VERTICAL_BLANKING 0x06
+#define MT9M001_OUTPUT_CONTROL 0x07
+#define MT9M001_SHUTTER_WIDTH 0x09
+#define MT9M001_FRAME_RESTART 0x0b
+#define MT9M001_SHUTTER_DELAY 0x0c
+#define MT9M001_RESET 0x0d
+#define MT9M001_READ_OPTIONS1 0x1e
+#define MT9M001_READ_OPTIONS2 0x20
+#define MT9M001_GLOBAL_GAIN 0x35
+#define MT9M001_CHIP_ENABLE 0xF1
+
+#define MT9M001_MAX_WIDTH 1280
+#define MT9M001_MAX_HEIGHT 1024
+#define MT9M001_MIN_WIDTH 48
+#define MT9M001_MIN_HEIGHT 32
+#define MT9M001_COLUMN_SKIP 20
+#define MT9M001_ROW_SKIP 12
+
+/* MT9M001 has only one fixed colorspace per pixelcode */
+struct mt9m001_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9m001_datafmt *mt9m001_find_datafmt(
+ enum v4l2_mbus_pixelcode code, const struct mt9m001_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 mt9m001_datafmt mt9m001_colour_fmts[] = {
+ /*
+ * Order important: first natively supported,
+ * second supported with a GPIO extender
+ */
+ {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
+ /* Order important - see above */
+ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+struct mt9m001 {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* exposure/auto-exposure cluster */
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct v4l2_rect rect; /* Sensor window */
+ const struct mt9m001_datafmt *fmt;
+ const struct mt9m001_datafmt *fmts;
+ int num_fmts;
+ int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ unsigned int total_h;
+ unsigned short y_skip_top; /* Lines to skip at the top */
+};
+
+static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+ 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_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9m001_init(struct i2c_client *client)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ /*
+ * We don't know, whether platform provides reset, issue a soft reset
+ * too. This returns all registers to their default values.
+ */
+ ret = reg_write(client, MT9M001_RESET, 1);
+ if (!ret)
+ ret = reg_write(client, MT9M001_RESET, 0);
+
+ /* Disable chip, synchronous option update */
+ if (!ret)
+ ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
+
+ return ret;
+}
+
+static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* Switch to master "normal" mode or stop sensor readout */
+ if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_rect rect = a->c;
+ int ret;
+ const u16 hblank = 9, vblank = 25;
+
+ if (mt9m001->fmts == mt9m001_colour_fmts)
+ /*
+ * Bayer format - even number of rows for simplicity,
+ * but let the user play with the top row.
+ */
+ rect.height = ALIGN(rect.height, 2);
+
+ /* Datasheet requirement: see register description */
+ rect.width = ALIGN(rect.width, 2);
+ rect.left = ALIGN(rect.left, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
+
+ mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
+
+ /* Blanking and start values - default... */
+ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
+ if (!ret)
+ ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
+
+ /*
+ * The caller provides a supported format, as verified per
+ * call to .try_mbus_fmt()
+ */
+ if (!ret)
+ ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
+ if (!ret)
+ ret = reg_write(client, MT9M001_ROW_START, rect.top);
+ if (!ret)
+ ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
+ if (!ret)
+ ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
+ rect.height + mt9m001->y_skip_top - 1);
+ if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
+ ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
+
+ if (!ret)
+ mt9m001->rect = rect;
+
+ return ret;
+}
+
+static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ a->c = mt9m001->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9M001_COLUMN_SKIP;
+ a->bounds.top = MT9M001_ROW_SKIP;
+ a->bounds.width = MT9M001_MAX_WIDTH;
+ a->bounds.height = MT9M001_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m001_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ mf->width = mt9m001->rect.width;
+ mf->height = mt9m001->rect.height;
+ mf->code = mt9m001->fmt->code;
+ mf->colorspace = mt9m001->fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9m001_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9m001->rect.left,
+ .top = mt9m001->rect.top,
+ .width = mf->width,
+ .height = mf->height,
+ },
+ };
+ int ret;
+
+ /* No support for scaling so far, just crop. TODO: use skipping */
+ ret = mt9m001_s_crop(sd, &a);
+ if (!ret) {
+ mf->width = mt9m001->rect.width;
+ mf->height = mt9m001->rect.height;
+ mt9m001->fmt = mt9m001_find_datafmt(mf->code,
+ mt9m001->fmts, mt9m001->num_fmts);
+ mf->colorspace = mt9m001->fmt->colorspace;
+ }
+
+ return ret;
+}
+
+static int mt9m001_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ const struct mt9m001_datafmt *fmt;
+
+ v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
+ MT9M001_MAX_WIDTH, 1,
+ &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
+ MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
+
+ if (mt9m001->fmts == mt9m001_colour_fmts)
+ mf->height = ALIGN(mf->height - 1, 2);
+
+ fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
+ mt9m001->num_fmts);
+ if (!fmt) {
+ fmt = mt9m001->fmt;
+ mf->code = fmt->code;
+ }
+
+ mf->colorspace = fmt->colorspace;
+
+ return 0;
+}
+
+static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = mt9m001->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m001_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ reg->size = 2;
+ reg->val = reg_read(client, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9m001_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ if (reg_write(client, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+ struct mt9m001, hdl);
+ s32 min, max;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE_AUTO:
+ min = mt9m001->exposure->minimum;
+ max = mt9m001->exposure->maximum;
+ mt9m001->exposure->val =
+ (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
+ break;
+ }
+ return 0;
+}
+
+static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+ struct mt9m001, hdl);
+ struct v4l2_subdev *sd = &mt9m001->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_ctrl *exp = mt9m001->exposure;
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
+ else
+ data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
+ if (data < 0)
+ return -EIO;
+ return 0;
+
+ case V4L2_CID_GAIN:
+ /* See Datasheet Table 7, Gain settings. */
+ if (ctrl->val <= ctrl->default_value) {
+ /* Pack it into 0..1 step 0.125, register values 0..8 */
+ unsigned long range = ctrl->default_value - ctrl->minimum;
+ data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
+ data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ } else {
+ /* Pack it into 1.125..15 variable step, register values 9..67 */
+ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+ unsigned long range = ctrl->maximum - ctrl->default_value - 1;
+ unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+ 111 + range / 2) / range + 9;
+
+ if (gain <= 32)
+ data = gain;
+ else if (gain <= 64)
+ data = ((gain - 32) * 16 + 16) / 32 + 80;
+ else
+ data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+ dev_dbg(&client->dev, "Setting gain from %d to %d\n",
+ reg_read(client, MT9M001_GLOBAL_GAIN), data);
+ data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ }
+ return 0;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+ unsigned long range = exp->maximum - exp->minimum;
+ unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
+ range / 2) / range + 1;
+
+ dev_dbg(&client->dev,
+ "Setting shutter width from %d to %lu\n",
+ reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+ if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+ return -EIO;
+ } else {
+ const u16 vblank = 25;
+
+ mt9m001->total_h = mt9m001->rect.height +
+ mt9m001->y_skip_top + vblank;
+ if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
+ return -EIO;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m001_video_probe(struct soc_camera_link *icl,
+ struct i2c_client *client)
+{
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ s32 data;
+ unsigned long flags;
+ int ret;
+
+ ret = mt9m001_s_power(&mt9m001->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Enable the chip */
+ data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
+ dev_dbg(&client->dev, "write: %d\n", data);
+
+ /* Read out the chip version register */
+ data = reg_read(client, MT9M001_CHIP_VERSION);
+
+ /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+ switch (data) {
+ case 0x8411:
+ case 0x8421:
+ mt9m001->model = V4L2_IDENT_MT9M001C12ST;
+ mt9m001->fmts = mt9m001_colour_fmts;
+ break;
+ case 0x8431:
+ mt9m001->model = V4L2_IDENT_MT9M001C12STM;
+ mt9m001->fmts = mt9m001_monochrome_fmts;
+ break;
+ default:
+ dev_err(&client->dev,
+ "No MT9M001 chip detected, register read %x\n", data);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ mt9m001->num_fmts = 0;
+
+ /*
+ * This is a 10bit sensor, so by default we only allow 10bit.
+ * The platform may support different bus widths due to
+ * different routing of the data lines.
+ */
+ if (icl->query_bus_param)
+ flags = icl->query_bus_param(icl);
+ else
+ flags = SOCAM_DATAWIDTH_10;
+
+ if (flags & SOCAM_DATAWIDTH_10)
+ mt9m001->num_fmts++;
+ else
+ mt9m001->fmts++;
+
+ if (flags & SOCAM_DATAWIDTH_8)
+ mt9m001->num_fmts++;
+
+ mt9m001->fmt = &mt9m001->fmts[0];
+
+ dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ data == 0x8431 ? "C12STM" : "C12ST");
+
+ ret = mt9m001_init(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to initialise the camera\n");
+ goto done;
+ }
+
+ /* mt9m001_init() has reset the chip, returning registers to defaults */
+ ret = v4l2_ctrl_handler_setup(&mt9m001->hdl);
+
+done:
+ mt9m001_s_power(&mt9m001->subdev, 0);
+ return ret;
+}
+
+static void mt9m001_video_remove(struct soc_camera_link *icl)
+{
+ if (icl->free_bus)
+ icl->free_bus(icl);
+}
+
+static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ *lines = mt9m001->y_skip_top;
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
+ .g_volatile_ctrl = mt9m001_g_volatile_ctrl,
+ .s_ctrl = mt9m001_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
+ .g_chip_ident = mt9m001_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m001_g_register,
+ .s_register = mt9m001_s_register,
+#endif
+ .s_power = mt9m001_s_power,
+};
+
+static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+ if (index >= mt9m001->num_fmts)
+ return -EINVAL;
+
+ *code = mt9m001->fmts[index].code;
+ return 0;
+}
+
+static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ /* MT9M001 has all capture_format parameters fixed */
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ const struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
+
+ if (icl->set_bus_param)
+ return icl->set_bus_param(icl, 1 << (bps - 1));
+
+ /*
+ * Without board specific bus width settings we only support the
+ * sensors native bus width
+ */
+ return bps == 10 ? 0 : -EINVAL;
+}
+
+static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
+ .s_stream = mt9m001_s_stream,
+ .s_mbus_fmt = mt9m001_s_fmt,
+ .g_mbus_fmt = mt9m001_g_fmt,
+ .try_mbus_fmt = mt9m001_try_fmt,
+ .s_crop = mt9m001_s_crop,
+ .g_crop = mt9m001_g_crop,
+ .cropcap = mt9m001_cropcap,
+ .enum_mbus_fmt = mt9m001_enum_fmt,
+ .g_mbus_config = mt9m001_g_mbus_config,
+ .s_mbus_config = mt9m001_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
+ .g_skip_top_lines = mt9m001_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9m001_subdev_ops = {
+ .core = &mt9m001_subdev_core_ops,
+ .video = &mt9m001_subdev_video_ops,
+ .sensor = &mt9m001_subdev_sensor_ops,
+};
+
+static int mt9m001_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9m001 *mt9m001;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9M001 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
+ if (!mt9m001)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
+ v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
+ v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+ V4L2_CID_GAIN, 0, 127, 1, 64);
+ mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+ /*
+ * Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width
+ */
+ mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
+ &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+ V4L2_EXPOSURE_AUTO);
+ mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
+ if (mt9m001->hdl.error) {
+ int err = mt9m001->hdl.error;
+
+ kfree(mt9m001);
+ return err;
+ }
+ v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
+ V4L2_EXPOSURE_MANUAL, true);
+
+ /* Second stage probe - when a capture adapter is there */
+ mt9m001->y_skip_top = 0;
+ mt9m001->rect.left = MT9M001_COLUMN_SKIP;
+ mt9m001->rect.top = MT9M001_ROW_SKIP;
+ mt9m001->rect.width = MT9M001_MAX_WIDTH;
+ mt9m001->rect.height = MT9M001_MAX_HEIGHT;
+
+ ret = mt9m001_video_probe(icl, client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&mt9m001->hdl);
+ kfree(mt9m001);
+ }
+
+ return ret;
+}
+
+static int mt9m001_remove(struct i2c_client *client)
+{
+ struct mt9m001 *mt9m001 = to_mt9m001(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ v4l2_device_unregister_subdev(&mt9m001->subdev);
+ v4l2_ctrl_handler_free(&mt9m001->hdl);
+ mt9m001_video_remove(icl);
+ kfree(mt9m001);
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9m001_id[] = {
+ { "mt9m001", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
+static struct i2c_driver mt9m001_i2c_driver = {
+ .driver = {
+ .name = "mt9m001",
+ },
+ .probe = mt9m001_probe,
+ .remove = mt9m001_remove,
+ .id_table = mt9m001_id,
+};
+
+module_i2c_driver(mt9m001_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
new file mode 100644
index 000000000000..938c5c390eec
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -0,0 +1,1046 @@
+/*
+ * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
+ *
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+
+/*
+ * MT9M111, MT9M112 and MT9M131:
+ * i2c address is 0x48 or 0x5d (depending on SADDR pin)
+ * The platform has to define i2c_board_info and call i2c_register_board_info()
+ */
+
+/*
+ * Sensor core register addresses (0x000..0x0ff)
+ */
+#define MT9M111_CHIP_VERSION 0x000
+#define MT9M111_ROW_START 0x001
+#define MT9M111_COLUMN_START 0x002
+#define MT9M111_WINDOW_HEIGHT 0x003
+#define MT9M111_WINDOW_WIDTH 0x004
+#define MT9M111_HORIZONTAL_BLANKING_B 0x005
+#define MT9M111_VERTICAL_BLANKING_B 0x006
+#define MT9M111_HORIZONTAL_BLANKING_A 0x007
+#define MT9M111_VERTICAL_BLANKING_A 0x008
+#define MT9M111_SHUTTER_WIDTH 0x009
+#define MT9M111_ROW_SPEED 0x00a
+#define MT9M111_EXTRA_DELAY 0x00b
+#define MT9M111_SHUTTER_DELAY 0x00c
+#define MT9M111_RESET 0x00d
+#define MT9M111_READ_MODE_B 0x020
+#define MT9M111_READ_MODE_A 0x021
+#define MT9M111_FLASH_CONTROL 0x023
+#define MT9M111_GREEN1_GAIN 0x02b
+#define MT9M111_BLUE_GAIN 0x02c
+#define MT9M111_RED_GAIN 0x02d
+#define MT9M111_GREEN2_GAIN 0x02e
+#define MT9M111_GLOBAL_GAIN 0x02f
+#define MT9M111_CONTEXT_CONTROL 0x0c8
+#define MT9M111_PAGE_MAP 0x0f0
+#define MT9M111_BYTE_WISE_ADDR 0x0f1
+
+#define MT9M111_RESET_SYNC_CHANGES (1 << 15)
+#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9)
+#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8)
+#define MT9M111_RESET_RESET_SOC (1 << 5)
+#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4)
+#define MT9M111_RESET_CHIP_ENABLE (1 << 3)
+#define MT9M111_RESET_ANALOG_STANDBY (1 << 2)
+#define MT9M111_RESET_RESTART_FRAME (1 << 1)
+#define MT9M111_RESET_RESET_MODE (1 << 0)
+
+#define MT9M111_RM_FULL_POWER_RD (0 << 10)
+#define MT9M111_RM_LOW_POWER_RD (1 << 10)
+#define MT9M111_RM_COL_SKIP_4X (1 << 5)
+#define MT9M111_RM_ROW_SKIP_4X (1 << 4)
+#define MT9M111_RM_COL_SKIP_2X (1 << 3)
+#define MT9M111_RM_ROW_SKIP_2X (1 << 2)
+#define MT9M111_RMB_MIRROR_COLS (1 << 1)
+#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
+#define MT9M111_CTXT_CTRL_RESTART (1 << 15)
+#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12)
+#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10)
+#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9)
+#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8)
+#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7)
+#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3)
+#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
+#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
+#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
+
+/*
+ * Colorpipe register addresses (0x100..0x1ff)
+ */
+#define MT9M111_OPER_MODE_CTRL 0x106
+#define MT9M111_OUTPUT_FORMAT_CTRL 0x108
+#define MT9M111_REDUCER_XZOOM_B 0x1a0
+#define MT9M111_REDUCER_XSIZE_B 0x1a1
+#define MT9M111_REDUCER_YZOOM_B 0x1a3
+#define MT9M111_REDUCER_YSIZE_B 0x1a4
+#define MT9M111_REDUCER_XZOOM_A 0x1a6
+#define MT9M111_REDUCER_XSIZE_A 0x1a7
+#define MT9M111_REDUCER_YZOOM_A 0x1a9
+#define MT9M111_REDUCER_YSIZE_A 0x1aa
+
+#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
+#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
+
+#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
+#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
+#define MT9M111_OUTFMT_FLIP_BAYER_COL (1 << 9)
+#define MT9M111_OUTFMT_FLIP_BAYER_ROW (1 << 8)
+#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
+#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
+#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
+#define MT9M111_OUTFMT_RGB (1 << 8)
+#define MT9M111_OUTFMT_RGB565 (0 << 6)
+#define MT9M111_OUTFMT_RGB555 (1 << 6)
+#define MT9M111_OUTFMT_RGB444x (2 << 6)
+#define MT9M111_OUTFMT_RGBx444 (3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4)
+#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
+#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0)
+
+/*
+ * Camera control register addresses (0x200..0x2ff not implemented)
+ */
+
+#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
+#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
+ (val), (mask))
+
+#define MT9M111_MIN_DARK_ROWS 8
+#define MT9M111_MIN_DARK_COLS 26
+#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;
+};
+
+static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+};
+
+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 */
+ 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 */
+};
+
+/* 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);
+}
+
+static int reg_page_map_set(struct i2c_client *client, const u16 reg)
+{
+ int ret;
+ u16 page;
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ page = (reg >> 8);
+ if (page == mt9m111->lastpage)
+ return 0;
+ if (page > 2)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
+ if (!ret)
+ mt9m111->lastpage = page;
+ return ret;
+}
+
+static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
+{
+ int ret;
+
+ ret = reg_page_map_set(client, reg);
+ if (!ret)
+ ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
+
+ dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
+ return ret;
+}
+
+static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_page_map_set(client, reg);
+ if (!ret)
+ 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;
+}
+
+static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = mt9m111_reg_read(client, reg);
+ if (ret >= 0)
+ ret = mt9m111_reg_write(client, reg, ret | data);
+ return ret;
+}
+
+static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = mt9m111_reg_read(client, reg);
+ if (ret >= 0)
+ ret = mt9m111_reg_write(client, reg, ret & ~data);
+ return ret;
+}
+
+static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
+ const u16 data, const u16 mask)
+{
+ int ret;
+
+ ret = mt9m111_reg_read(client, reg);
+ if (ret >= 0)
+ ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
+ return ret;
+}
+
+static int mt9m111_set_context(struct mt9m111 *mt9m111,
+ struct mt9m111_context *ctx)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ return reg_write(CONTEXT_CONTROL, ctx->control);
+}
+
+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 = 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;
+}
+
+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 (!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 = mt9m111_setup_rect_ctx(mt9m111, &context_b,
+ rect, width, height);
+ if (!ret)
+ 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);
+ return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
+}
+
+static int mt9m111_reset(struct mt9m111 *mt9m111)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int ret;
+
+ ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+ if (!ret)
+ ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
+ if (!ret)
+ ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+ | MT9M111_RESET_RESET_SOC);
+
+ return ret;
+}
+
+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);
+ /* Let the user play with the starting pixel */
+ }
+
+ /* FIXME: the datasheet doesn't specify minimum sizes */
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
+
+ width = min(mt9m111->width, rect.width);
+ height = min(mt9m111->height, rect.height);
+
+ ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
+ if (!ret) {
+ mt9m111->rect = rect;
+ mt9m111->width = width;
+ mt9m111->height = height;
+ }
+
+ return ret;
+}
+
+static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+ a->c = mt9m111->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->bounds.left = MT9M111_MIN_DARK_COLS;
+ a->bounds.top = MT9M111_MIN_DARK_ROWS;
+ a->bounds.width = MT9M111_MAX_WIDTH;
+ a->bounds.height = MT9M111_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9m111_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+ mf->width = mt9m111->width;
+ mf->height = mt9m111->height;
+ mf->code = mt9m111->fmt->code;
+ mf->colorspace = mt9m111->fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
+ enum v4l2_mbus_pixelcode code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+ MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
+ MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+ MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+ int ret;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+ MT9M111_OUTFMT_RGB;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+ data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+ break;
+ case V4L2_MBUS_FMT_BGR565_2X8_BE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+ break;
+ case V4L2_MBUS_FMT_BGR565_2X8_LE:
+ data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ data_outfmt2 = 0;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+ break;
+ default:
+ dev_err(&client->dev, "Pixel format not handled: %x\n", code);
+ return -EINVAL;
+ }
+
+ ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
+ data_outfmt2, mask_outfmt2);
+ if (!ret)
+ ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
+ data_outfmt2, mask_outfmt2);
+
+ return ret;
+}
+
+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;
+ 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 (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;
+ }
+
+ 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)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = mt9m111->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m111_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int val;
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ return -EINVAL;
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ val = mt9m111_reg_read(client, reg->reg);
+ reg->size = 2;
+ reg->val = (u64)val;
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9m111_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int ret;
+
+ 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;
+}
+
+static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int data;
+
+ data = reg_read(GLOBAL_GAIN);
+ if (data >= 0)
+ return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
+ (1 << ((data >> 9) & 1));
+ return data;
+}
+
+static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ u16 val;
+
+ if (gain > 63 * 2 * 2)
+ return -EINVAL;
+
+ if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
+ val = (1 << 10) | (1 << 9) | (gain / 4);
+ else if ((gain >= 64) && (gain < 64 * 2))
+ val = (1 << 9) | (gain / 2);
+ else
+ val = gain;
+
+ return reg_write(GLOBAL_GAIN, val);
+}
+
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+
+ if (on)
+ return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+ return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+}
+
+static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+
+ if (on)
+ return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+ return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+}
+
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9m111 *mt9m111 = container_of(ctrl->handler,
+ struct mt9m111, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ return mt9m111_set_flip(mt9m111, ctrl->val,
+ MT9M111_RMB_MIRROR_ROWS);
+ case V4L2_CID_HFLIP:
+ return mt9m111_set_flip(mt9m111, ctrl->val,
+ MT9M111_RMB_MIRROR_COLS);
+ case V4L2_CID_GAIN:
+ return mt9m111_set_global_gain(mt9m111, ctrl->val);
+ case V4L2_CID_EXPOSURE_AUTO:
+ return mt9m111_set_autoexposure(mt9m111, ctrl->val);
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
+ }
+
+ return -EINVAL;
+}
+
+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));
+
+ 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->ctx);
+ mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
+ 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 = mt9m111_enable(mt9m111);
+ if (!ret)
+ ret = mt9m111_reset(mt9m111);
+ if (!ret)
+ mt9m111_restore_state(mt9m111);
+
+ return ret;
+}
+
+static int mt9m111_init(struct mt9m111 *mt9m111)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int ret;
+
+ /* 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->ctx);
+ if (ret)
+ dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
+ return ret;
+}
+
+static int mt9m111_power_on(struct mt9m111 *mt9m111)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ ret = soc_camera_power_on(&client->dev, icl);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9m111_resume(mt9m111);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
+ soc_camera_power_off(&client->dev, icl);
+ }
+
+ return ret;
+}
+
+static void mt9m111_power_off(struct mt9m111 *mt9m111)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ mt9m111_suspend(mt9m111);
+ soc_camera_power_off(&client->dev, icl);
+}
+
+static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9m111->power_lock);
+
+ /*
+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9m111->power_count == !on) {
+ if (on)
+ ret = mt9m111_power_on(mt9m111);
+ else
+ mt9m111_power_off(mt9m111);
+ }
+
+ if (!ret) {
+ /* Update the power count. */
+ mt9m111->power_count += on ? 1 : -1;
+ WARN_ON(mt9m111->power_count < 0);
+ }
+
+ mutex_unlock(&mt9m111->power_lock);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+ .s_ctrl = mt9m111_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
+ .g_chip_ident = mt9m111_g_chip_ident,
+ .s_power = mt9m111_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m111_g_register,
+ .s_register = mt9m111_s_register,
+#endif
+};
+
+static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
+ return -EINVAL;
+
+ *code = mt9m111_colour_fmts[index].code;
+ return 0;
+}
+
+static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
+ .s_mbus_fmt = mt9m111_s_fmt,
+ .g_mbus_fmt = mt9m111_g_fmt,
+ .try_mbus_fmt = mt9m111_try_fmt,
+ .s_crop = mt9m111_s_crop,
+ .g_crop = mt9m111_g_crop,
+ .cropcap = mt9m111_cropcap,
+ .enum_mbus_fmt = mt9m111_enum_fmt,
+ .g_mbus_config = mt9m111_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops mt9m111_subdev_ops = {
+ .core = &mt9m111_subdev_core_ops,
+ .video = &mt9m111_subdev_video_ops,
+};
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m111_video_probe(struct i2c_client *client)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+ s32 data;
+ int ret;
+
+ ret = mt9m111_s_power(&mt9m111->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ data = reg_read(CHIP_VERSION);
+
+ switch (data) {
+ case 0x143a: /* MT9M111 or MT9M131 */
+ mt9m111->model = V4L2_IDENT_MT9M111;
+ dev_info(&client->dev,
+ "Detected a MT9M111/MT9M131 chip ID %x\n", data);
+ break;
+ case 0x148c: /* MT9M112 */
+ mt9m111->model = V4L2_IDENT_MT9M112;
+ dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
+ break;
+ default:
+ dev_err(&client->dev,
+ "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
+ data);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = mt9m111_init(mt9m111);
+ if (ret)
+ goto done;
+
+ ret = v4l2_ctrl_handler_setup(&mt9m111->hdl);
+
+done:
+ mt9m111_s_power(&mt9m111->subdev, 0);
+ return ret;
+}
+
+static int mt9m111_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9m111 *mt9m111;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "mt9m111: driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+ if (!mt9m111)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
+ v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
+ v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
+ v4l2_ctrl_new_std_menu(&mt9m111->hdl,
+ &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+ V4L2_EXPOSURE_AUTO);
+ mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
+ if (mt9m111->hdl.error) {
+ int err = mt9m111->hdl.error;
+
+ kfree(mt9m111);
+ return err;
+ }
+
+ /* Second stage probe - when a capture adapter is there */
+ mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
+ mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
+ mt9m111->rect.width = MT9M111_MAX_WIDTH;
+ mt9m111->rect.height = MT9M111_MAX_HEIGHT;
+ mt9m111->fmt = &mt9m111_colour_fmts[0];
+ mt9m111->lastpage = -1;
+ mutex_init(&mt9m111->power_lock);
+
+ ret = mt9m111_video_probe(client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&mt9m111->hdl);
+ kfree(mt9m111);
+ }
+
+ return ret;
+}
+
+static int mt9m111_remove(struct i2c_client *client)
+{
+ struct mt9m111 *mt9m111 = to_mt9m111(client);
+
+ v4l2_device_unregister_subdev(&mt9m111->subdev);
+ v4l2_ctrl_handler_free(&mt9m111->hdl);
+ kfree(mt9m111);
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9m111_id[] = {
+ { "mt9m111", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m111_id);
+
+static struct i2c_driver mt9m111_i2c_driver = {
+ .driver = {
+ .name = "mt9m111",
+ },
+ .probe = mt9m111_probe,
+ .remove = mt9m111_remove,
+ .id_table = mt9m111_id,
+};
+
+module_i2c_driver(mt9m111_i2c_driver);
+
+MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
new file mode 100644
index 000000000000..d74607adc585
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -0,0 +1,857 @@
+/*
+ * Driver for MT9T031 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
+ *
+ * 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/device.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * ATTENTION: this driver still cannot be used outside of the soc-camera
+ * framework because of its PM implementation, using the video_device node.
+ * If hardware becomes available for testing, alternative PM approaches shall
+ * be considered and tested.
+ */
+
+/*
+ * mt9t031 i2c address 0x5d
+ * The platform has to define i2c_board_info and link to it from
+ * struct soc_camera_link
+ */
+
+/* mt9t031 selected register addresses */
+#define MT9T031_CHIP_VERSION 0x00
+#define MT9T031_ROW_START 0x01
+#define MT9T031_COLUMN_START 0x02
+#define MT9T031_WINDOW_HEIGHT 0x03
+#define MT9T031_WINDOW_WIDTH 0x04
+#define MT9T031_HORIZONTAL_BLANKING 0x05
+#define MT9T031_VERTICAL_BLANKING 0x06
+#define MT9T031_OUTPUT_CONTROL 0x07
+#define MT9T031_SHUTTER_WIDTH_UPPER 0x08
+#define MT9T031_SHUTTER_WIDTH 0x09
+#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a
+#define MT9T031_FRAME_RESTART 0x0b
+#define MT9T031_SHUTTER_DELAY 0x0c
+#define MT9T031_RESET 0x0d
+#define MT9T031_READ_MODE_1 0x1e
+#define MT9T031_READ_MODE_2 0x20
+#define MT9T031_READ_MODE_3 0x21
+#define MT9T031_ROW_ADDRESS_MODE 0x22
+#define MT9T031_COLUMN_ADDRESS_MODE 0x23
+#define MT9T031_GLOBAL_GAIN 0x35
+#define MT9T031_CHIP_ENABLE 0xF8
+
+#define MT9T031_MAX_HEIGHT 1536
+#define MT9T031_MAX_WIDTH 2048
+#define MT9T031_MIN_HEIGHT 2
+#define MT9T031_MIN_WIDTH 18
+#define MT9T031_HORIZONTAL_BLANK 142
+#define MT9T031_VERTICAL_BLANK 25
+#define MT9T031_COLUMN_SKIP 32
+#define MT9T031_ROW_SKIP 20
+
+struct mt9t031 {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* exposure/auto-exposure cluster */
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct v4l2_rect rect; /* Sensor window */
+ int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+ u16 xskip;
+ u16 yskip;
+ unsigned int total_h;
+ unsigned short y_skip_top; /* Lines to skip at the top */
+};
+
+static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9t031, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+ 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_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret & ~data);
+}
+
+static int set_shutter(struct i2c_client *client, const u32 data)
+{
+ int ret;
+
+ ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+
+ return ret;
+}
+
+static int get_shutter(struct i2c_client *client, u32 *data)
+{
+ int ret;
+
+ ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
+ *data = ret << 16;
+
+ if (ret >= 0)
+ ret = reg_read(client, MT9T031_SHUTTER_WIDTH);
+ *data |= ret & 0xffff;
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_idle(struct i2c_client *client)
+{
+ int ret;
+
+ /* Disable chip output, synchronous option update */
+ ret = reg_write(client, MT9T031_RESET, 1);
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_RESET, 0);
+ if (ret >= 0)
+ ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
+
+ return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (enable)
+ /* Switch to master "normal" mode */
+ ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2);
+ else
+ /* Stop sensor readout */
+ ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
+
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
+}
+
+/* target must be _even_ */
+static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
+{
+ unsigned int skip;
+
+ if (*source < target + target / 2) {
+ *source = target;
+ return 1;
+ }
+
+ skip = min(max, *source + target / 2) / target;
+ if (skip > 8)
+ skip = 8;
+ *source = target * skip;
+
+ return skip;
+}
+
+/* rect is the sensor rectangle, the caller guarantees parameter validity */
+static int mt9t031_set_params(struct i2c_client *client,
+ struct v4l2_rect *rect, u16 xskip, u16 yskip)
+{
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ int ret;
+ u16 xbin, ybin;
+ const u16 hblank = MT9T031_HORIZONTAL_BLANK,
+ vblank = MT9T031_VERTICAL_BLANK;
+
+ xbin = min(xskip, (u16)3);
+ ybin = min(yskip, (u16)3);
+
+ /*
+ * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper.
+ * There is always a valid suitably aligned value. The worst case is
+ * xbin = 3, width = 2048. Then we will start at 36, the last read out
+ * pixel will be 2083, which is < 2085 - first black pixel.
+ *
+ * MT9T031 datasheet imposes window left border alignment, depending on
+ * the selected xskip. Failing to conform to this requirement produces
+ * dark horizontal stripes in the image. However, even obeying to this
+ * requirement doesn't eliminate the stripes in all configurations. They
+ * appear "locally reproducibly," but can differ between tests under
+ * different lighting conditions.
+ */
+ switch (xbin) {
+ case 1:
+ rect->left &= ~1;
+ break;
+ case 2:
+ rect->left &= ~3;
+ break;
+ case 3:
+ rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ?
+ (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6);
+ }
+
+ rect->top &= ~1;
+
+ dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
+ xskip, yskip, rect->width, rect->height, rect->left, rect->top);
+
+ /* Disable register update, reconfigure atomically */
+ ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Blanking and start values - default... */
+ ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank);
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank);
+
+ if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
+ /* Binning, skipping */
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+ ((xbin - 1) << 4) | (xskip - 1));
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+ ((ybin - 1) << 4) | (yskip - 1));
+ }
+ dev_dbg(&client->dev, "new physical left %u, top %u\n",
+ rect->left, rect->top);
+
+ /*
+ * The caller provides a supported format, as guaranteed by
+ * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap()
+ */
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_ROW_START, rect->top);
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
+ if (ret >= 0)
+ ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
+ rect->height + mt9t031->y_skip_top - 1);
+ if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) {
+ mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank;
+
+ ret = set_shutter(client, mt9t031->total_h);
+ }
+
+ /* Re-enable register update, commit all changes */
+ if (ret >= 0)
+ ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
+
+ if (ret >= 0) {
+ mt9t031->rect = *rect;
+ mt9t031->xskip = xskip;
+ mt9t031->yskip = yskip;
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_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 mt9t031 *mt9t031 = to_mt9t031(client);
+
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
+
+ return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip);
+}
+
+static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ a->c = mt9t031->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9T031_COLUMN_SKIP;
+ a->bounds.top = MT9T031_ROW_SKIP;
+ a->bounds.width = MT9T031_MAX_WIDTH;
+ a->bounds.height = MT9T031_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9t031_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ mf->width = mt9t031->rect.width / mt9t031->xskip;
+ mf->height = mt9t031->rect.height / mt9t031->yskip;
+ mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9t031_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ u16 xskip, yskip;
+ struct v4l2_rect rect = mt9t031->rect;
+
+ /*
+ * try_fmt has put width and height within limits.
+ * S_FMT: use binning and skipping for scaling
+ */
+ xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
+ yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
+
+ mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ /* mt9t031_set_params() doesn't change width and height */
+ return mt9t031_set_params(client, &rect, xskip, yskip);
+}
+
+/*
+ * If a user window larger than sensor window is requested, we'll increase the
+ * sensor window.
+ */
+static int mt9t031_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ v4l_bound_align_image(
+ &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
+ &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
+
+ mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = mt9t031->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t031_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ reg->val = reg_read(client, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9t031_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ if (reg_write(client, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9t031 *mt9t031 = container_of(ctrl->handler,
+ struct mt9t031, hdl);
+ const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK;
+ s32 min, max;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE_AUTO:
+ min = mt9t031->exposure->minimum;
+ max = mt9t031->exposure->maximum;
+ mt9t031->exposure->val =
+ (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min))
+ / shutter_max + min;
+ break;
+ }
+ return 0;
+}
+
+static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9t031 *mt9t031 = container_of(ctrl->handler,
+ struct mt9t031, hdl);
+ struct v4l2_subdev *sd = &mt9t031->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_ctrl *exp = mt9t031->exposure;
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
+ else
+ data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
+ else
+ data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_GAIN:
+ /* See Datasheet Table 7, Gain settings. */
+ if (ctrl->val <= ctrl->default_value) {
+ /* Pack it into 0..1 step 0.125, register values 0..8 */
+ unsigned long range = ctrl->default_value - ctrl->minimum;
+ data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+
+ dev_dbg(&client->dev, "Setting gain %d\n", data);
+ data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ } else {
+ /* Pack it into 1.125..128 variable step, register values 9..0x7860 */
+ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+ unsigned long range = ctrl->maximum - ctrl->default_value - 1;
+ /* calculated gain: map 65..127 to 9..1024 step 0.125 */
+ unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+ 1015 + range / 2) / range + 9;
+
+ if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
+ data = gain;
+ else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */
+ data = ((gain - 32) * 16 + 16) / 32 + 80;
+ else
+ /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
+ data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
+
+ dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n",
+ reg_read(client, MT9T031_GLOBAL_GAIN), data);
+ data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ }
+ return 0;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+ unsigned int range = exp->maximum - exp->minimum;
+ unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
+ range / 2) / range + 1;
+ u32 old;
+
+ get_shutter(client, &old);
+ dev_dbg(&client->dev, "Set shutter from %u to %u\n",
+ old, shutter);
+ if (set_shutter(client, shutter) < 0)
+ return -EIO;
+ } else {
+ const u16 vblank = MT9T031_VERTICAL_BLANK;
+ mt9t031->total_h = mt9t031->rect.height +
+ mt9t031->y_skip_top + vblank;
+
+ if (set_shutter(client, mt9t031->total_h) < 0)
+ return -EIO;
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Power Management:
+ * This function does nothing for now but must be present for pm to work
+ */
+static int mt9t031_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+/*
+ * Power Management:
+ * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
+ * they are however changed at reset if the platform hook is present
+ * thus we rewrite them with the values stored by the driver
+ */
+static int mt9t031_runtime_resume(struct device *dev)
+{
+ struct video_device *vdev = to_video_device(dev);
+ struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ int ret;
+ u16 xbin, ybin;
+
+ xbin = min(mt9t031->xskip, (u16)3);
+ ybin = min(mt9t031->yskip, (u16)3);
+
+ ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
+ ((xbin - 1) << 4) | (mt9t031->xskip - 1));
+ if (ret < 0)
+ return ret;
+
+ ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
+ ((ybin - 1) << 4) | (mt9t031->yskip - 1));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct dev_pm_ops mt9t031_dev_pm_ops = {
+ .runtime_suspend = mt9t031_runtime_suspend,
+ .runtime_resume = mt9t031_runtime_resume,
+};
+
+static struct device_type mt9t031_dev_type = {
+ .name = "MT9T031",
+ .pm = &mt9t031_dev_pm_ops,
+};
+
+static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+ int ret;
+
+ if (on) {
+ ret = soc_camera_power_on(&client->dev, icl);
+ if (ret < 0)
+ return ret;
+ vdev->dev.type = &mt9t031_dev_type;
+ } else {
+ vdev->dev.type = NULL;
+ soc_camera_power_off(&client->dev, icl);
+ }
+
+ return 0;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9t031_video_probe(struct i2c_client *client)
+{
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+ s32 data;
+ int ret;
+
+ ret = mt9t031_s_power(&mt9t031->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9t031_idle(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to initialise the camera\n");
+ goto done;
+ }
+
+ /* Read out the chip version register */
+ data = reg_read(client, MT9T031_CHIP_VERSION);
+
+ switch (data) {
+ case 0x1621:
+ mt9t031->model = V4L2_IDENT_MT9T031;
+ break;
+ default:
+ dev_err(&client->dev,
+ "No MT9T031 chip detected, register read %x\n", data);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
+
+ ret = v4l2_ctrl_handler_setup(&mt9t031->hdl);
+
+done:
+ mt9t031_s_power(&mt9t031->subdev, 0);
+
+ return ret;
+}
+
+static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ *lines = mt9t031->y_skip_top;
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
+ .g_volatile_ctrl = mt9t031_g_volatile_ctrl,
+ .s_ctrl = mt9t031_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
+ .g_chip_ident = mt9t031_g_chip_ident,
+ .s_power = mt9t031_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9t031_g_register,
+ .s_register = mt9t031_s_register,
+#endif
+};
+
+static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ return 0;
+}
+
+static int mt9t031_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int mt9t031_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ if (soc_camera_apply_board_flags(icl, cfg) &
+ V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+ else
+ return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+}
+
+static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
+ .s_stream = mt9t031_s_stream,
+ .s_mbus_fmt = mt9t031_s_fmt,
+ .g_mbus_fmt = mt9t031_g_fmt,
+ .try_mbus_fmt = mt9t031_try_fmt,
+ .s_crop = mt9t031_s_crop,
+ .g_crop = mt9t031_g_crop,
+ .cropcap = mt9t031_cropcap,
+ .enum_mbus_fmt = mt9t031_enum_fmt,
+ .g_mbus_config = mt9t031_g_mbus_config,
+ .s_mbus_config = mt9t031_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
+ .g_skip_top_lines = mt9t031_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9t031_subdev_ops = {
+ .core = &mt9t031_subdev_core_ops,
+ .video = &mt9t031_subdev_video_ops,
+ .sensor = &mt9t031_subdev_sensor_ops,
+};
+
+static int mt9t031_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9t031 *mt9t031;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9T031 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
+ if (!mt9t031)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
+ v4l2_ctrl_handler_init(&mt9t031->hdl, 5);
+ v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+ V4L2_CID_GAIN, 0, 127, 1, 64);
+
+ /*
+ * Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width
+ */
+ mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl,
+ &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+ V4L2_EXPOSURE_AUTO);
+ mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+
+ mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
+ if (mt9t031->hdl.error) {
+ int err = mt9t031->hdl.error;
+
+ kfree(mt9t031);
+ return err;
+ }
+ v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure,
+ V4L2_EXPOSURE_MANUAL, true);
+
+ mt9t031->y_skip_top = 0;
+ mt9t031->rect.left = MT9T031_COLUMN_SKIP;
+ mt9t031->rect.top = MT9T031_ROW_SKIP;
+ mt9t031->rect.width = MT9T031_MAX_WIDTH;
+ mt9t031->rect.height = MT9T031_MAX_HEIGHT;
+
+ mt9t031->xskip = 1;
+ mt9t031->yskip = 1;
+
+ ret = mt9t031_video_probe(client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&mt9t031->hdl);
+ kfree(mt9t031);
+ }
+
+ return ret;
+}
+
+static int mt9t031_remove(struct i2c_client *client)
+{
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
+
+ v4l2_device_unregister_subdev(&mt9t031->subdev);
+ v4l2_ctrl_handler_free(&mt9t031->hdl);
+ kfree(mt9t031);
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9t031_id[] = {
+ { "mt9t031", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t031_id);
+
+static struct i2c_driver mt9t031_i2c_driver = {
+ .driver = {
+ .name = "mt9t031",
+ },
+ .probe = mt9t031_probe,
+ .remove = mt9t031_remove,
+ .id_table = mt9t031_id,
+};
+
+module_i2c_driver(mt9t031_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
new file mode 100644
index 000000000000..9ba428ede516
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -0,0 +1,1142 @@
+/*
+ * mt9t112 Camera Driver
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver, mt9m111 driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/mt9t112.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+
+/* you can check PLL/clock info */
+/* #define EXT_CLOCK 24000000 */
+
+/************************************************************************
+ macro
+************************************************************************/
+/*
+ * frame size
+ */
+#define MAX_WIDTH 2048
+#define MAX_HEIGHT 1536
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+
+/*
+ * macro of read/write
+ */
+#define ECHECKER(ret, x) \
+ do { \
+ (ret) = (x); \
+ if ((ret) < 0) \
+ return (ret); \
+ } while (0)
+
+#define mt9t112_reg_write(ret, client, a, b) \
+ ECHECKER(ret, __mt9t112_reg_write(client, a, b))
+#define mt9t112_mcu_write(ret, client, a, b) \
+ ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
+
+#define mt9t112_reg_mask_set(ret, client, a, b, c) \
+ ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
+#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
+ ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
+
+#define mt9t112_reg_read(ret, client, a) \
+ ECHECKER(ret, __mt9t112_reg_read(client, a))
+
+/*
+ * Logical address
+ */
+#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff))
+#define VAR(id, offset) _VAR(id, offset, 0x0000)
+#define VAR8(id, offset) _VAR(id, offset, 0x8000)
+
+/************************************************************************
+ struct
+************************************************************************/
+struct mt9t112_format {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+ u16 fmt;
+ u16 order;
+};
+
+struct mt9t112_priv {
+ struct v4l2_subdev subdev;
+ struct mt9t112_camera_info *info;
+ struct i2c_client *client;
+ struct v4l2_rect frame;
+ const struct mt9t112_format *format;
+ int model;
+ u32 flags;
+/* for flags */
+#define INIT_DONE (1 << 0)
+#define PCLK_RISING (1 << 1)
+};
+
+/************************************************************************
+ supported format
+************************************************************************/
+
+static const struct mt9t112_format mt9t112_cfmts[] = {
+ {
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ }, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 1,
+ }, {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 2,
+ }, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 3,
+ }, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 8,
+ .order = 2,
+ }, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 4,
+ .order = 2,
+ },
+};
+
+/************************************************************************
+ general function
+************************************************************************/
+static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client),
+ struct mt9t112_priv,
+ subdev);
+}
+
+static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ int ret;
+
+ command = swab16(command);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = (u8 *)&command;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = buf;
+
+ /*
+ * if return value of this function is < 0,
+ * it mean error.
+ * else, under 16bit is valid data.
+ */
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&ret, buf, 2);
+ return swab16(ret);
+}
+
+static int __mt9t112_reg_write(const struct i2c_client *client,
+ u16 command, u16 data)
+{
+ struct i2c_msg msg;
+ u8 buf[4];
+ int ret;
+
+ command = swab16(command);
+ data = swab16(data);
+
+ memcpy(buf + 0, &command, 2);
+ memcpy(buf + 2, &data, 2);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 4;
+ msg.buf = buf;
+
+ /*
+ * i2c_transfer return message length,
+ * but this function should return 0 if correct case
+ */
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret >= 0)
+ ret = 0;
+
+ return ret;
+}
+
+static int __mt9t112_reg_mask_set(const struct i2c_client *client,
+ u16 command,
+ u16 mask,
+ u16 set)
+{
+ int val = __mt9t112_reg_read(client, command);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return __mt9t112_reg_write(client, command, val);
+}
+
+/* mcu access */
+static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
+{
+ int ret;
+
+ ret = __mt9t112_reg_write(client, 0x098E, command);
+ if (ret < 0)
+ return ret;
+
+ return __mt9t112_reg_read(client, 0x0990);
+}
+
+static int __mt9t112_mcu_write(const struct i2c_client *client,
+ u16 command, u16 data)
+{
+ int ret;
+
+ ret = __mt9t112_reg_write(client, 0x098E, command);
+ if (ret < 0)
+ return ret;
+
+ return __mt9t112_reg_write(client, 0x0990, data);
+}
+
+static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
+ u16 command,
+ u16 mask,
+ u16 set)
+{
+ int val = __mt9t112_mcu_read(client, command);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return __mt9t112_mcu_write(client, command, val);
+}
+
+static int mt9t112_reset(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
+ msleep(1);
+ mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
+
+ return ret;
+}
+
+#ifndef EXT_CLOCK
+#define CLOCK_INFO(a, b)
+#else
+#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
+static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
+{
+ int m, n, p1, p2, p3, p4, p5, p6, p7;
+ u32 vco, clk;
+ char *enable;
+
+ ext /= 1000; /* kbyte order */
+
+ mt9t112_reg_read(n, client, 0x0012);
+ p1 = n & 0x000f;
+ n = n >> 4;
+ p2 = n & 0x000f;
+ n = n >> 4;
+ p3 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x002a);
+ p4 = n & 0x000f;
+ n = n >> 4;
+ p5 = n & 0x000f;
+ n = n >> 4;
+ p6 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x002c);
+ p7 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x0010);
+ m = n & 0x00ff;
+ n = (n >> 8) & 0x003f;
+
+ enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
+ dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable);
+
+ vco = 2 * m * ext / (n+1);
+ enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
+ dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable);
+
+ clk = vco / (p1+1) / (p2+1);
+ enable = (96000 < clk) ? "X" : "";
+ dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p3+1);
+ enable = (768000 < clk) ? "X" : "";
+ dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p6+1);
+ enable = (96000 < clk) ? "X" : "";
+ dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p5+1);
+ enable = (54000 < clk) ? "X" : "";
+ dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p4+1);
+ enable = (70000 < clk) ? "X" : "";
+ dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p7+1);
+ dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
+
+ clk = ext / (n+1);
+ enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
+ dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable);
+
+ return 0;
+}
+#endif
+
+static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
+{
+ soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
+ soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
+}
+
+static int mt9t112_set_a_frame_size(const struct i2c_client *client,
+ u16 width,
+ u16 height)
+{
+ int ret;
+ u16 wstart = (MAX_WIDTH - width) / 2;
+ u16 hstart = (MAX_HEIGHT - height) / 2;
+
+ /* (Context A) Image Width/Height */
+ mt9t112_mcu_write(ret, client, VAR(26, 0), width);
+ mt9t112_mcu_write(ret, client, VAR(26, 2), height);
+
+ /* (Context A) Output Width/Height */
+ mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
+ mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
+
+ /* (Context A) Start Row/Column */
+ mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
+ mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
+
+ /* (Context A) End Row/Column */
+ mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
+ mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart);
+
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ return ret;
+}
+
+static int mt9t112_set_pll_dividers(const struct i2c_client *client,
+ u8 m, u8 n,
+ u8 p1, u8 p2, u8 p3,
+ u8 p4, u8 p5, u8 p6,
+ u8 p7)
+{
+ int ret;
+ u16 val;
+
+ /* N/M */
+ val = (n << 8) |
+ (m << 0);
+ mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
+
+ /* P1/P2/P3 */
+ val = ((p3 & 0x0F) << 8) |
+ ((p2 & 0x0F) << 4) |
+ ((p1 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
+
+ /* P4/P5/P6 */
+ val = (0x7 << 12) |
+ ((p6 & 0x0F) << 8) |
+ ((p5 & 0x0F) << 4) |
+ ((p4 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
+
+ /* P7 */
+ val = (0x1 << 12) |
+ ((p7 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
+
+ return ret;
+}
+
+static int mt9t112_init_pll(const struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ int data, i, ret;
+
+ mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
+
+ /* PLL control: BYPASS PLL = 8517 */
+ mt9t112_reg_write(ret, client, 0x0014, 0x2145);
+
+ /* Replace these registers when new timing parameters are generated */
+ mt9t112_set_pll_dividers(client,
+ priv->info->divider.m,
+ priv->info->divider.n,
+ priv->info->divider.p1,
+ priv->info->divider.p2,
+ priv->info->divider.p3,
+ priv->info->divider.p4,
+ priv->info->divider.p5,
+ priv->info->divider.p6,
+ priv->info->divider.p7);
+
+ /*
+ * TEST_BYPASS on
+ * PLL_ENABLE on
+ * SEL_LOCK_DET on
+ * TEST_BYPASS off
+ */
+ mt9t112_reg_write(ret, client, 0x0014, 0x2525);
+ mt9t112_reg_write(ret, client, 0x0014, 0x2527);
+ mt9t112_reg_write(ret, client, 0x0014, 0x3427);
+ mt9t112_reg_write(ret, client, 0x0014, 0x3027);
+
+ mdelay(10);
+
+ /*
+ * PLL_BYPASS off
+ * Reference clock count
+ * I2C Master Clock Divider
+ */
+ mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+ mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
+ mt9t112_reg_write(ret, client, 0x0022, 0x0190);
+ mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
+
+ /* External sensor clock is PLL bypass */
+ mt9t112_reg_write(ret, client, 0x002E, 0x0500);
+
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
+ mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
+
+ /* MCU disabled */
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
+
+ /* out of standby */
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
+
+ mdelay(50);
+
+ /*
+ * Standby Workaround
+ * Disable Secondary I2C Pads
+ */
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+
+ /* poll to verify out of standby. Must Poll this bit */
+ for (i = 0; i < 100; i++) {
+ mt9t112_reg_read(data, client, 0x0018);
+ if (!(0x4000 & data))
+ break;
+
+ mdelay(10);
+ }
+
+ return ret;
+}
+
+static int mt9t112_init_setting(const struct i2c_client *client)
+{
+
+ int ret;
+
+ /* Adaptive Output Clock (A) */
+ mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
+
+ /* Read Mode (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
+
+ /* Fine Correction (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
+
+ /* Fine IT Min (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
+
+ /* Fine IT Max Margin (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
+
+ /* Base Frame Lines (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
+
+ /* Min Line Length (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
+
+ /* Line Length (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
+
+ /* Adaptive Output Clock (B) */
+ mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
+
+ /* Row Start (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
+
+ /* Column Start (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
+
+ /* Row End (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
+
+ /* Column End (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
+
+ /* Fine Correction (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
+
+ /* Fine IT Min (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
+
+ /* Fine IT Max Margin (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
+
+ /* Base Frame Lines (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
+
+ /* Min Line Length (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
+
+ /* Line Length (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
+
+ /*
+ * Flicker Dectection registers
+ * This section should be replaced whenever new Timing file is generated
+ * All the following registers need to be replaced
+ * Following registers are generated from Register Wizard but user can
+ * modify them. For detail see auto flicker detection tuning
+ */
+
+ /* FD_FDPERIOD_SELECT */
+ mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
+
+ /* PRI_B_CONFIG_FD_ALGO_RUN */
+ mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
+
+ /* PRI_A_CONFIG_FD_ALGO_RUN */
+ mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
+
+ /*
+ * AFD range detection tuning registers
+ */
+
+ /* search_f1_50 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
+
+ /* search_f2_50 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
+
+ /* search_f1_60 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
+
+ /* search_f2_60 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
+
+ /* period_50Hz (A) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
+
+ /* secret register by aptina */
+ /* period_50Hz (A MSB) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
+
+ /* period_60Hz (A) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
+
+ /* secret register by aptina */
+ /* period_60Hz (A MSB) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
+
+ /* period_50Hz (B) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
+
+ /* secret register by aptina */
+ /* period_50Hz (B) MSB */
+ mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
+
+ /* period_60Hz (B) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
+
+ /* secret register by aptina */
+ /* period_60Hz (B) MSB */
+ mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
+
+ /* FD Mode */
+ mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
+
+ /* Stat_min */
+ mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
+
+ /* Stat_max */
+ mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
+
+ /* Min_amplitude */
+ mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
+
+ /* RX FIFO Watermark (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
+
+ /* RX FIFO Watermark (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
+
+ /* MCLK: 16MHz
+ * PCLK: 73MHz
+ * CorePixCLK: 36.5 MHz
+ */
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
+
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
+
+ return ret;
+}
+
+static int mt9t112_auto_focus_setting(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F);
+ mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ mt9t112_reg_write(ret, client, 0x0614, 0x0000);
+
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
+ mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02);
+ mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002);
+ mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001);
+ mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025);
+ mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193);
+ mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
+
+ return ret;
+}
+
+static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
+
+ return ret;
+}
+
+static int mt9t112_init_camera(const struct i2c_client *client)
+{
+ int ret;
+
+ ECHECKER(ret, mt9t112_reset(client));
+
+ ECHECKER(ret, mt9t112_init_pll(client));
+
+ ECHECKER(ret, mt9t112_init_setting(client));
+
+ ECHECKER(ret, mt9t112_auto_focus_setting(client));
+
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
+
+ /* Analog setting B */
+ mt9t112_reg_write(ret, client, 0x3084, 0x2409);
+ mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
+ mt9t112_reg_write(ret, client, 0x3094, 0x4949);
+ mt9t112_reg_write(ret, client, 0x3096, 0x4950);
+
+ /*
+ * Disable adaptive clock
+ * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ */
+ mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
+ mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
+
+ /* Configure STatus in Status_before_length Format and enable header */
+ /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+ mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
+
+ /* Enable JPEG in context B */
+ /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+ mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
+
+ /* Disable Dac_TXLO */
+ mt9t112_reg_write(ret, client, 0x316C, 0x350F);
+
+ /* Set max slew rates */
+ mt9t112_reg_write(ret, client, 0x1E, 0x777);
+
+ return ret;
+}
+
+/************************************************************************
+ v4l2_subdev_core_ops
+************************************************************************/
+static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ id->ident = priv->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t112_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 2;
+ mt9t112_reg_read(ret, client, reg->reg);
+
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int mt9t112_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ mt9t112_reg_write(ret, client, reg->reg, reg->val);
+
+ return ret;
+}
+#endif
+
+static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
+ .g_chip_ident = mt9t112_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9t112_g_register,
+ .s_register = mt9t112_s_register,
+#endif
+ .s_power = mt9t112_s_power,
+};
+
+
+/************************************************************************
+ v4l2_subdev_video_ops
+************************************************************************/
+static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ int ret = 0;
+
+ if (!enable) {
+ /* FIXME
+ *
+ * If user selected large output size,
+ * and used it long time,
+ * mt9t112 camera will be very warm.
+ *
+ * But current driver can not stop mt9t112 camera.
+ * So, set small size here to solve this problem.
+ */
+ mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
+ return ret;
+ }
+
+ if (!(priv->flags & INIT_DONE)) {
+ u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000;
+
+ ECHECKER(ret, mt9t112_init_camera(client));
+
+ /* Invert PCLK (Data sampled on falling edge of pixclk) */
+ mt9t112_reg_write(ret, client, 0x3C20, param);
+
+ mdelay(5);
+
+ priv->flags |= INIT_DONE;
+ }
+
+ mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt);
+ mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ mt9t112_set_a_frame_size(client,
+ priv->frame.width,
+ priv->frame.height);
+
+ ECHECKER(ret, mt9t112_auto_focus_trigger(client));
+
+ dev_dbg(&client->dev, "format : %d\n", priv->format->code);
+ dev_dbg(&client->dev, "size : %d x %d\n",
+ priv->frame.width,
+ priv->frame.height);
+
+ CLOCK_INFO(client, EXT_CLOCK);
+
+ return ret;
+}
+
+static int mt9t112_set_params(struct mt9t112_priv *priv,
+ const struct v4l2_rect *rect,
+ enum v4l2_mbus_pixelcode code)
+{
+ int i;
+
+ /*
+ * get color format
+ */
+ for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+ if (mt9t112_cfmts[i].code == code)
+ break;
+
+ if (i == ARRAY_SIZE(mt9t112_cfmts))
+ return -EINVAL;
+
+ priv->frame = *rect;
+
+ /*
+ * frame size check
+ */
+ mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
+ &priv->frame.left, &priv->frame.top);
+
+ priv->format = mt9t112_cfmts + i;
+
+ return 0;
+}
+
+static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = MAX_WIDTH;
+ a->bounds.height = MAX_HEIGHT;
+ a->defrect.left = 0;
+ a->defrect.top = 0;
+ a->defrect.width = VGA_WIDTH;
+ a->defrect.height = VGA_HEIGHT;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ a->c = priv->frame;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ struct v4l2_rect *rect = &a->c;
+
+ return mt9t112_set_params(priv, rect, priv->format->code);
+}
+
+static int mt9t112_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ mf->width = priv->frame.width;
+ mf->height = priv->frame.height;
+ mf->colorspace = priv->format->colorspace;
+ mf->code = priv->format->code;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9t112_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ struct v4l2_rect rect = {
+ .width = mf->width,
+ .height = mf->height,
+ .left = priv->frame.left,
+ .top = priv->frame.top,
+ };
+ int ret;
+
+ ret = mt9t112_set_params(priv, &rect, mf->code);
+
+ if (!ret)
+ mf->colorspace = priv->format->colorspace;
+
+ return ret;
+}
+
+static int mt9t112_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ unsigned int top, left;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+ if (mt9t112_cfmts[i].code == mf->code)
+ break;
+
+ if (i == ARRAY_SIZE(mt9t112_cfmts)) {
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ } else {
+ mf->colorspace = mt9t112_cfmts[i].colorspace;
+ }
+
+ mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(mt9t112_cfmts))
+ return -EINVAL;
+
+ *code = mt9t112_cfmts[index].code;
+
+ return 0;
+}
+
+static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ priv->flags |= PCLK_RISING;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
+ .s_stream = mt9t112_s_stream,
+ .g_mbus_fmt = mt9t112_g_fmt,
+ .s_mbus_fmt = mt9t112_s_fmt,
+ .try_mbus_fmt = mt9t112_try_fmt,
+ .cropcap = mt9t112_cropcap,
+ .g_crop = mt9t112_g_crop,
+ .s_crop = mt9t112_s_crop,
+ .enum_mbus_fmt = mt9t112_enum_fmt,
+ .g_mbus_config = mt9t112_g_mbus_config,
+ .s_mbus_config = mt9t112_s_mbus_config,
+};
+
+/************************************************************************
+ i2c driver
+************************************************************************/
+static struct v4l2_subdev_ops mt9t112_subdev_ops = {
+ .core = &mt9t112_subdev_core_ops,
+ .video = &mt9t112_subdev_video_ops,
+};
+
+static int mt9t112_camera_probe(struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ const char *devname;
+ int chipid;
+ int ret;
+
+ ret = mt9t112_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show chip ID
+ */
+ mt9t112_reg_read(chipid, client, 0x0000);
+
+ switch (chipid) {
+ case 0x2680:
+ devname = "mt9t111";
+ priv->model = V4L2_IDENT_MT9T111;
+ break;
+ case 0x2682:
+ devname = "mt9t112";
+ priv->model = V4L2_IDENT_MT9T112;
+ break;
+ default:
+ dev_err(&client->dev, "Product ID error %04x\n", chipid);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
+
+done:
+ mt9t112_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static int mt9t112_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9t112_priv *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct v4l2_rect rect = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .left = (MAX_WIDTH - VGA_WIDTH) / 2,
+ .top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
+ };
+ int ret;
+
+ if (!icl || !icl->priv) {
+ dev_err(&client->dev, "mt9t112: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = icl->priv;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+
+ ret = mt9t112_camera_probe(client);
+ if (ret) {
+ kfree(priv);
+ return ret;
+ }
+
+ /* Cannot fail: using the default supported pixel code */
+ mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+
+ return ret;
+}
+
+static int mt9t112_remove(struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id mt9t112_id[] = {
+ { "mt9t112", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t112_id);
+
+static struct i2c_driver mt9t112_i2c_driver = {
+ .driver = {
+ .name = "mt9t112",
+ },
+ .probe = mt9t112_probe,
+ .remove = mt9t112_remove,
+ .id_table = mt9t112_id,
+};
+
+module_i2c_driver(mt9t112_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
new file mode 100644
index 000000000000..350d0d854447
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -0,0 +1,919 @@
+/*
+ * Driver for MT9V022 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_link
+ */
+
+static char *sensor_type;
+module_param(sensor_type, charp, S_IRUGO);
+MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
+
+/* mt9v022 selected register addresses */
+#define MT9V022_CHIP_VERSION 0x00
+#define MT9V022_COLUMN_START 0x01
+#define MT9V022_ROW_START 0x02
+#define MT9V022_WINDOW_HEIGHT 0x03
+#define MT9V022_WINDOW_WIDTH 0x04
+#define MT9V022_HORIZONTAL_BLANKING 0x05
+#define MT9V022_VERTICAL_BLANKING 0x06
+#define MT9V022_CHIP_CONTROL 0x07
+#define MT9V022_SHUTTER_WIDTH1 0x08
+#define MT9V022_SHUTTER_WIDTH2 0x09
+#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a
+#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b
+#define MT9V022_RESET 0x0c
+#define MT9V022_READ_MODE 0x0d
+#define MT9V022_MONITOR_MODE 0x0e
+#define MT9V022_PIXEL_OPERATION_MODE 0x0f
+#define MT9V022_LED_OUT_CONTROL 0x1b
+#define MT9V022_ADC_MODE_CONTROL 0x1c
+#define MT9V022_ANALOG_GAIN 0x35
+#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
+#define MT9V022_PIXCLK_FV_LV 0x74
+#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
+#define MT9V022_AEC_AGC_ENABLE 0xAF
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
+
+/* mt9v024 partial list register addresses changes with respect to mt9v022 */
+#define MT9V024_PIXCLK_FV_LV 0x72
+#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD
+
+/* Progressive scan, master, defaults */
+#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
+
+#define MT9V022_MAX_WIDTH 752
+#define MT9V022_MAX_HEIGHT 480
+#define MT9V022_MIN_WIDTH 48
+#define MT9V022_MIN_HEIGHT 32
+#define MT9V022_COLUMN_SKIP 1
+#define MT9V022_ROW_SKIP 4
+
+#define is_mt9v024(id) (id == 0x1324)
+
+/* MT9V022 has only one fixed colorspace per pixelcode */
+struct mt9v022_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9v022_datafmt *mt9v022_find_datafmt(
+ enum v4l2_mbus_pixelcode code, const struct mt9v022_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 mt9v022_datafmt mt9v022_colour_fmts[] = {
+ /*
+ * Order important: first natively supported,
+ * second supported with a GPIO extender
+ */
+ {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
+ /* Order important - see above */
+ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+/* only registers with different addresses on different mt9v02x sensors */
+struct mt9v02x_register {
+ u8 max_total_shutter_width;
+ u8 pixclk_fv_lv;
+};
+
+static const struct mt9v02x_register mt9v022_register = {
+ .max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+ .pixclk_fv_lv = MT9V022_PIXCLK_FV_LV,
+};
+
+static const struct mt9v02x_register mt9v024_register = {
+ .max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH,
+ .pixclk_fv_lv = MT9V024_PIXCLK_FV_LV,
+};
+
+struct mt9v022 {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* exposure/auto-exposure cluster */
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct {
+ /* gain/auto-gain cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ };
+ struct v4l2_rect rect; /* Sensor window */
+ const struct mt9v022_datafmt *fmt;
+ const struct mt9v022_datafmt *fmts;
+ const struct mt9v02x_register *reg;
+ int num_fmts;
+ int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+ u16 chip_control;
+ unsigned short y_skip_top; /* Lines to skip at the top */
+};
+
+static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+ 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_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9v022_init(struct i2c_client *client)
+{
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ int ret;
+
+ /*
+ * Almost the default mode: master, parallel, simultaneous, and an
+ * undocumented bit 0x200, which is present in table 7, but not in 8,
+ * plus snapshot mode to disable scan for now
+ */
+ mt9v022->chip_control |= 0x10;
+ ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+ if (!ret)
+ ret = reg_write(client, MT9V022_READ_MODE, 0x300);
+
+ /* All defaults */
+ if (!ret)
+ /* AEC, AGC on */
+ ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
+ if (!ret)
+ ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
+ if (!ret)
+ ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
+ if (!ret)
+ ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480);
+ if (!ret)
+ /* default - auto */
+ ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+ if (!ret)
+ ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
+ if (!ret)
+ return v4l2_ctrl_handler_setup(&mt9v022->hdl);
+
+ return ret;
+}
+
+static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ if (enable)
+ /* Switch to master "normal" mode */
+ mt9v022->chip_control &= ~0x10;
+ else
+ /* Switch to snapshot mode */
+ mt9v022->chip_control |= 0x10;
+
+ if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_rect rect = a->c;
+ int ret;
+
+ /* Bayer format - even size lengths */
+ if (mt9v022->fmts == mt9v022_colour_fmts) {
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
+ /* Let the user play with the starting pixel */
+ }
+
+ soc_camera_limit_side(&rect.left, &rect.width,
+ MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
+
+ soc_camera_limit_side(&rect.top, &rect.height,
+ MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
+
+ /* Like in example app. Contradicts the datasheet though */
+ ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
+ if (ret >= 0) {
+ if (ret & 1) /* Autoexposure */
+ ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
+ rect.height + mt9v022->y_skip_top + 43);
+ else
+ ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+ rect.height + mt9v022->y_skip_top + 43);
+ }
+ /* Setup frame format: defaults apart from width and height */
+ if (!ret)
+ ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
+ if (!ret)
+ ret = reg_write(client, MT9V022_ROW_START, rect.top);
+ if (!ret)
+ /*
+ * Default 94, Phytec driver says:
+ * "width + horizontal blank >= 660"
+ */
+ ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
+ rect.width > 660 - 43 ? 43 :
+ 660 - rect.width);
+ if (!ret)
+ ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
+ if (!ret)
+ ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
+ if (!ret)
+ ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
+ rect.height + mt9v022->y_skip_top);
+
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
+
+ mt9v022->rect = rect;
+
+ return 0;
+}
+
+static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ a->c = mt9v022->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = MT9V022_COLUMN_SKIP;
+ a->bounds.top = MT9V022_ROW_SKIP;
+ a->bounds.width = MT9V022_MAX_WIDTH;
+ a->bounds.height = MT9V022_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int mt9v022_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ mf->width = mt9v022->rect.width;
+ mf->height = mt9v022->rect.height;
+ mf->code = mt9v022->fmt->code;
+ mf->colorspace = mt9v022->fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9v022_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct v4l2_crop a = {
+ .c = {
+ .left = mt9v022->rect.left,
+ .top = mt9v022->rect.top,
+ .width = mf->width,
+ .height = mf->height,
+ },
+ };
+ int ret;
+
+ /*
+ * The caller provides a supported format, as verified per call to
+ * .try_mbus_fmt(), datawidth is from our supported format list
+ */
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_Y8_1X8:
+ case V4L2_MBUS_FMT_Y10_1X10:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ return -EINVAL;
+ break;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* No support for scaling on this camera, just crop. */
+ ret = mt9v022_s_crop(sd, &a);
+ if (!ret) {
+ mf->width = mt9v022->rect.width;
+ mf->height = mt9v022->rect.height;
+ mt9v022->fmt = mt9v022_find_datafmt(mf->code,
+ mt9v022->fmts, mt9v022->num_fmts);
+ mf->colorspace = mt9v022->fmt->colorspace;
+ }
+
+ return ret;
+}
+
+static int mt9v022_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ const struct mt9v022_datafmt *fmt;
+ int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+ mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
+
+ v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
+ MT9V022_MAX_WIDTH, align,
+ &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
+ MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
+
+ fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
+ mt9v022->num_fmts);
+ if (!fmt) {
+ fmt = mt9v022->fmt;
+ mf->code = fmt->code;
+ }
+
+ mf->colorspace = fmt->colorspace;
+
+ return 0;
+}
+
+static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = mt9v022->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v022_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ reg->size = 2;
+ reg->val = reg_read(client, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9v022_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ if (reg_write(client, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+ struct mt9v022, hdl);
+ struct v4l2_subdev *sd = &mt9v022->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_ctrl *gain = mt9v022->gain;
+ struct v4l2_ctrl *exp = mt9v022->exposure;
+ unsigned long range;
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ data = reg_read(client, MT9V022_ANALOG_GAIN);
+ if (data < 0)
+ return -EIO;
+
+ range = gain->maximum - gain->minimum;
+ gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
+ return 0;
+ case V4L2_CID_EXPOSURE_AUTO:
+ data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
+ if (data < 0)
+ return -EIO;
+
+ range = exp->maximum - exp->minimum;
+ exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+ struct mt9v022, hdl);
+ struct v4l2_subdev *sd = &mt9v022->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ data = reg_set(client, MT9V022_READ_MODE, 0x10);
+ else
+ data = reg_clear(client, MT9V022_READ_MODE, 0x10);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ data = reg_set(client, MT9V022_READ_MODE, 0x20);
+ else
+ data = reg_clear(client, MT9V022_READ_MODE, 0x20);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ if (ctrl->val) {
+ if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+ return -EIO;
+ } else {
+ struct v4l2_ctrl *gain = mt9v022->gain;
+ /* mt9v022 has minimum == default */
+ unsigned long range = gain->maximum - gain->minimum;
+ /* Valid values 16 to 64, 32 to 64 must be even. */
+ unsigned long gain_val = ((gain->val - gain->minimum) *
+ 48 + range / 2) / range + 16;
+
+ if (gain_val >= 32)
+ gain_val &= ~1;
+
+ /*
+ * The user wants to set gain manually, hope, she
+ * knows, what she's doing... Switch AGC off.
+ */
+ if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+ return -EIO;
+
+ dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
+ reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
+ if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
+ return -EIO;
+ }
+ return 0;
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->val == V4L2_EXPOSURE_AUTO) {
+ data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+ } else {
+ struct v4l2_ctrl *exp = mt9v022->exposure;
+ unsigned long range = exp->maximum - exp->minimum;
+ unsigned long shutter = ((exp->val - exp->minimum) *
+ 479 + range / 2) / range + 1;
+
+ /*
+ * The user wants to set shutter width manually, hope,
+ * she knows, what she's doing... Switch AEC off.
+ */
+ data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+ if (data < 0)
+ return -EIO;
+ dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
+ reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
+ shutter);
+ if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+ shutter) < 0)
+ return -EIO;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9v022_video_probe(struct i2c_client *client)
+{
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ s32 data;
+ int ret;
+ unsigned long flags;
+
+ ret = mt9v022_s_power(&mt9v022->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Read out the chip version register */
+ data = reg_read(client, MT9V022_CHIP_VERSION);
+
+ /* must be 0x1311, 0x1313 or 0x1324 */
+ if (data != 0x1311 && data != 0x1313 && data != 0x1324) {
+ ret = -ENODEV;
+ dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
+ data);
+ goto ei2c;
+ }
+
+ mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
+ &mt9v022_register;
+
+ /* Soft reset */
+ ret = reg_write(client, MT9V022_RESET, 1);
+ if (ret < 0)
+ goto ei2c;
+ /* 15 clock cycles */
+ udelay(200);
+ if (reg_read(client, MT9V022_RESET)) {
+ dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+ if (ret > 0)
+ ret = -EIO;
+ goto ei2c;
+ }
+
+ /* Set monochrome or colour sensor type */
+ if (sensor_type && (!strcmp("colour", sensor_type) ||
+ !strcmp("color", sensor_type))) {
+ ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ mt9v022->fmts = mt9v022_colour_fmts;
+ } else {
+ ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ mt9v022->fmts = mt9v022_monochrome_fmts;
+ }
+
+ if (ret < 0)
+ goto ei2c;
+
+ mt9v022->num_fmts = 0;
+
+ /*
+ * This is a 10bit sensor, so by default we only allow 10bit.
+ * The platform may support different bus widths due to
+ * different routing of the data lines.
+ */
+ if (icl->query_bus_param)
+ flags = icl->query_bus_param(icl);
+ else
+ flags = SOCAM_DATAWIDTH_10;
+
+ if (flags & SOCAM_DATAWIDTH_10)
+ mt9v022->num_fmts++;
+ else
+ mt9v022->fmts++;
+
+ if (flags & SOCAM_DATAWIDTH_8)
+ mt9v022->num_fmts++;
+
+ mt9v022->fmt = &mt9v022->fmts[0];
+
+ dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+ data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+ "monochrome" : "colour");
+
+ ret = mt9v022_init(client);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to initialise the camera\n");
+
+ei2c:
+ mt9v022_s_power(&mt9v022->subdev, 0);
+ return ret;
+}
+
+static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ *lines = mt9v022->y_skip_top;
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
+ .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
+ .s_ctrl = mt9v022_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
+ .g_chip_ident = mt9v022_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9v022_g_register,
+ .s_register = mt9v022_s_register,
+#endif
+ .s_power = mt9v022_s_power,
+};
+
+static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+ if (index >= mt9v022->num_fmts)
+ return -EINVAL;
+
+ *code = mt9v022->fmts[index].code;
+ return 0;
+}
+
+static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+ unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
+ int ret;
+ u16 pixclk = 0;
+
+ if (icl->set_bus_param) {
+ ret = icl->set_bus_param(icl, 1 << (bps - 1));
+ if (ret)
+ return ret;
+ } else if (bps != 10) {
+ /*
+ * Without board specific bus width settings we only support the
+ * sensors native bus width
+ */
+ return -EINVAL;
+ }
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ pixclk |= 0x10;
+
+ if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
+ pixclk |= 0x1;
+
+ if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
+ pixclk |= 0x2;
+
+ ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk);
+ if (ret < 0)
+ return ret;
+
+ if (!(flags & V4L2_MBUS_MASTER))
+ mt9v022->chip_control &= ~0x8;
+
+ ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+ pixclk, mt9v022->chip_control);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
+ .s_stream = mt9v022_s_stream,
+ .s_mbus_fmt = mt9v022_s_fmt,
+ .g_mbus_fmt = mt9v022_g_fmt,
+ .try_mbus_fmt = mt9v022_try_fmt,
+ .s_crop = mt9v022_s_crop,
+ .g_crop = mt9v022_g_crop,
+ .cropcap = mt9v022_cropcap,
+ .enum_mbus_fmt = mt9v022_enum_fmt,
+ .g_mbus_config = mt9v022_g_mbus_config,
+ .s_mbus_config = mt9v022_s_mbus_config,
+};
+
+static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
+ .g_skip_top_lines = mt9v022_g_skip_top_lines,
+};
+
+static struct v4l2_subdev_ops mt9v022_subdev_ops = {
+ .core = &mt9v022_subdev_core_ops,
+ .video = &mt9v022_subdev_video_ops,
+ .sensor = &mt9v022_subdev_sensor_ops,
+};
+
+static int mt9v022_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9v022 *mt9v022;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
+ if (!mt9v022)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
+ v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
+ v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+ V4L2_CID_GAIN, 0, 127, 1, 64);
+
+ /*
+ * Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width
+ */
+ mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
+ &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+ V4L2_EXPOSURE_AUTO);
+ mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+
+ mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
+ if (mt9v022->hdl.error) {
+ int err = mt9v022->hdl.error;
+
+ kfree(mt9v022);
+ return err;
+ }
+ v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
+ V4L2_EXPOSURE_MANUAL, true);
+ v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
+
+ mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
+
+ /*
+ * MT9V022 _really_ corrupts the first read out line.
+ * TODO: verify on i.MX31
+ */
+ mt9v022->y_skip_top = 1;
+ mt9v022->rect.left = MT9V022_COLUMN_SKIP;
+ mt9v022->rect.top = MT9V022_ROW_SKIP;
+ mt9v022->rect.width = MT9V022_MAX_WIDTH;
+ mt9v022->rect.height = MT9V022_MAX_HEIGHT;
+
+ ret = mt9v022_video_probe(client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&mt9v022->hdl);
+ kfree(mt9v022);
+ }
+
+ return ret;
+}
+
+static int mt9v022_remove(struct i2c_client *client)
+{
+ struct mt9v022 *mt9v022 = to_mt9v022(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ v4l2_device_unregister_subdev(&mt9v022->subdev);
+ if (icl->free_bus)
+ icl->free_bus(icl);
+ v4l2_ctrl_handler_free(&mt9v022->hdl);
+ kfree(mt9v022);
+
+ return 0;
+}
+static const struct i2c_device_id mt9v022_id[] = {
+ { "mt9v022", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
+static struct i2c_driver mt9v022_i2c_driver = {
+ .driver = {
+ .name = "mt9v022",
+ },
+ .probe = mt9v022_probe,
+ .remove = mt9v022_remove,
+ .id_table = mt9v022_id,
+};
+
+module_i2c_driver(mt9v022_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
new file mode 100644
index 000000000000..78ac5744cb5d
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -0,0 +1,1122 @@
+/*
+ * ov2640 Camera Driver
+ *
+ * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * Based on ov772x, ov9640 drivers and previous non merged implementations.
+ *
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2006, OmniVision
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+#define VAL_SET(x, mask, rshift, lshift) \
+ ((((x) >> rshift) & mask) << lshift)
+/*
+ * DSP registers
+ * register offset for BANK_SEL == BANK_SEL_DSP
+ */
+#define R_BYPASS 0x05 /* Bypass DSP */
+#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */
+#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */
+#define QS 0x44 /* Quantization Scale Factor */
+#define CTRLI 0x50
+#define CTRLI_LP_DP 0x80
+#define CTRLI_ROUND 0x40
+#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)
+#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */
+#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */
+#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define XOFFL 0x53 /* OFFSET_X[7:0] */
+#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define YOFFL 0x54 /* OFFSET_Y[7:0] */
+#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define VHYX 0x55 /* Offset and size completion */
+#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7)
+#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3)
+#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4)
+#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0)
+#define DPRP 0x56
+#define TEST 0x57 /* Horizontal size completion */
+#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7)
+#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */
+#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */
+#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMHH 0x5C /* Zoom: Speed and H&W completion */
+#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)
+#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2)
+#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0)
+#define BPADDR 0x7C /* SDE Indirect Register Access: Address */
+#define BPDATA 0x7D /* SDE Indirect Register Access: Data */
+#define CTRL2 0x86 /* DSP Module enable 2 */
+#define CTRL2_DCW_EN 0x20
+#define CTRL2_SDE_EN 0x10
+#define CTRL2_UV_ADJ_EN 0x08
+#define CTRL2_UV_AVG_EN 0x04
+#define CTRL2_CMX_EN 0x01
+#define CTRL3 0x87 /* DSP Module enable 3 */
+#define CTRL3_BPC_EN 0x80
+#define CTRL3_WPC_EN 0x40
+#define SIZEL 0x8C /* Image Size Completion */
+#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)
+#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3)
+#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0)
+#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */
+#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */
+#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define CTRL0 0xC2 /* DSP Module enable 0 */
+#define CTRL0_AEC_EN 0x80
+#define CTRL0_AEC_SEL 0x40
+#define CTRL0_STAT_SEL 0x20
+#define CTRL0_VFIRST 0x10
+#define CTRL0_YUV422 0x08
+#define CTRL0_YUV_EN 0x04
+#define CTRL0_RGB_EN 0x02
+#define CTRL0_RAW_EN 0x01
+#define CTRL1 0xC3 /* DSP Module enable 1 */
+#define CTRL1_CIP 0x80
+#define CTRL1_DMY 0x40
+#define CTRL1_RAW_GMA 0x20
+#define CTRL1_DG 0x10
+#define CTRL1_AWB 0x08
+#define CTRL1_AWB_GAIN 0x04
+#define CTRL1_LENC 0x02
+#define CTRL1_PRE 0x01
+#define R_DVP_SP 0xD3 /* DVP output speed control */
+#define R_DVP_SP_AUTO_MODE 0x80
+#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);
+ * = sysclk (48)/(2*[6:0]) (RAW);*/
+#define IMAGE_MODE 0xDA /* Image Output Format Select */
+#define IMAGE_MODE_Y8_DVP_EN 0x40
+#define IMAGE_MODE_JPEG_EN 0x10
+#define IMAGE_MODE_YUV422 0x00
+#define IMAGE_MODE_RAW10 0x04 /* (DVP) */
+#define IMAGE_MODE_RGB565 0x08
+#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output
+ * mode (0 for HREF is same as sensor) */
+#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP
+ * 1: Low byte first UYVY (C2[4] =0)
+ * VYUY (C2[4] =1)
+ * 0: High byte first YUYV (C2[4]=0)
+ * YVYU (C2[4] = 1) */
+#define RESET 0xE0 /* Reset */
+#define RESET_MICROC 0x40
+#define RESET_SCCB 0x20
+#define RESET_JPEG 0x10
+#define RESET_DVP 0x04
+#define RESET_IPU 0x02
+#define RESET_CIF 0x01
+#define REGED 0xED /* Register ED */
+#define REGED_CLK_OUT_DIS 0x10
+#define MS_SP 0xF0 /* SCCB Master Speed */
+#define SS_ID 0xF7 /* SCCB Slave ID */
+#define SS_CTRL 0xF8 /* SCCB Slave Control */
+#define SS_CTRL_ADD_AUTO_INC 0x20
+#define SS_CTRL_EN 0x08
+#define SS_CTRL_DELAY_CLK 0x04
+#define SS_CTRL_ACC_EN 0x02
+#define SS_CTRL_SEN_PASS_THR 0x01
+#define MC_BIST 0xF9 /* Microcontroller misc register */
+#define MC_BIST_RESET 0x80 /* Microcontroller Reset */
+#define MC_BIST_BOOT_ROM_SEL 0x40
+#define MC_BIST_12KB_SEL 0x20
+#define MC_BIST_12KB_MASK 0x30
+#define MC_BIST_512KB_SEL 0x08
+#define MC_BIST_512KB_MASK 0x0C
+#define MC_BIST_BUSY_BIT_R 0x02
+#define MC_BIST_MC_RES_ONE_SH_W 0x02
+#define MC_BIST_LAUNCH 0x01
+#define BANK_SEL 0xFF /* Register Bank Select */
+#define BANK_SEL_DSP 0x00
+#define BANK_SEL_SENS 0x01
+
+/*
+ * Sensor registers
+ * register offset for BANK_SEL == BANK_SEL_SENS
+ */
+#define GAIN 0x00 /* AGC - Gain control gain setting */
+#define COM1 0x03 /* Common control 1 */
+#define COM1_1_DUMMY_FR 0x40
+#define COM1_3_DUMMY_FR 0x80
+#define COM1_7_DUMMY_FR 0xC0
+#define COM1_VWIN_LSB_UXGA 0x0F
+#define COM1_VWIN_LSB_SVGA 0x0A
+#define COM1_VWIN_LSB_CIF 0x06
+#define REG04 0x04 /* Register 04 */
+#define REG04_DEF 0x20 /* Always set */
+#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */
+#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */
+#define REG04_VREF_EN 0x10
+#define REG04_HREF_EN 0x08
+#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */
+#define COM2 0x09 /* Common control 2 */
+#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
+ /* Output drive capability */
+#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */
+#define PID 0x0A /* Product ID Number MSB */
+#define VER 0x0B /* Product ID Number LSB */
+#define COM3 0x0C /* Common control 3 */
+#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */
+#define COM3_BAND_AUTO 0x02 /* Auto Banding */
+#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the
+ * snapshot sequence*/
+#define AEC 0x10 /* AEC[9:2] Exposure Value */
+#define CLKRC 0x11 /* Internal clock */
+#define CLKRC_EN 0x80
+#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */
+#define COM7 0x12 /* Common control 7 */
+#define COM7_SRST 0x80 /* Initiates system reset. All registers are
+ * set to factory default values after which
+ * the chip resumes normal operation */
+#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */
+#define COM7_RES_SVGA 0x40 /* SVGA */
+#define COM7_RES_CIF 0x20 /* CIF */
+#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */
+#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */
+#define COM8 0x13 /* Common control 8 */
+#define COM8_DEF 0xC0 /* Banding filter ON/OFF */
+#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */
+#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
+#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
+#define COM9 0x14 /* Common control 9
+ * Automatic gain ceiling - maximum AGC value [7:5]*/
+#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */
+#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */
+#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */
+#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */
+#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */
+#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */
+#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */
+#define COM10 0x15 /* Common control 10 */
+#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */
+#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of
+ * PCLK (user can latch data at the next
+ * falling edge of PCLK).
+ * 0 otherwise. */
+#define COM10_HREF_INV 0x08 /* Invert HREF polarity:
+ * HREF negative for valid data*/
+#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */
+#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */
+#define HEND 0x18 /* Horizontal Window end MSB 8 bit */
+#define VSTART 0x19 /* Vertical Window start MSB 8 bit */
+#define VEND 0x1A /* Vertical Window end MSB 8 bit */
+#define MIDH 0x1C /* Manufacturer ID byte - high */
+#define MIDL 0x1D /* Manufacturer ID byte - low */
+#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VV 0x26 /* AGC/AEC Fast mode operating region */
+#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4)
+#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0)
+#define REG2A 0x2A /* Dummy pixel insert MSB */
+#define FRARL 0x2B /* Dummy pixel insert LSB */
+#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */
+#define YAVG 0x2F /* Y/G Channel Average value */
+#define REG32 0x32 /* Common Control 32 */
+#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */
+#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */
+#define ARCOM2 0x34 /* Zoom: Horizontal start point */
+#define REG45 0x45 /* Register 45 */
+#define FLL 0x46 /* Frame Length Adjustment LSBs */
+#define FLH 0x47 /* Frame Length Adjustment MSBs */
+#define COM19 0x48 /* Zoom: Vertical start point */
+#define ZOOMS 0x49 /* Zoom: Vertical start point */
+#define COM22 0x4B /* Flash light control */
+#define COM25 0x4E /* For Banding operations */
+#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */
+#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */
+#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */
+#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */
+#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */
+#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */
+#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */
+#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */
+
+/*
+ * ID
+ */
+#define MANUFACTURER_ID 0x7FA2
+#define PID_OV2640 0x2642
+#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
+
+/*
+ * Struct
+ */
+struct regval_list {
+ u8 reg_num;
+ u8 value;
+};
+
+/* Supported resolutions */
+enum ov2640_width {
+ W_QCIF = 176,
+ W_QVGA = 320,
+ W_CIF = 352,
+ W_VGA = 640,
+ W_SVGA = 800,
+ W_XGA = 1024,
+ W_SXGA = 1280,
+ W_UXGA = 1600,
+};
+
+enum ov2640_height {
+ H_QCIF = 144,
+ H_QVGA = 240,
+ H_CIF = 288,
+ H_VGA = 480,
+ H_SVGA = 600,
+ H_XGA = 768,
+ H_SXGA = 1024,
+ H_UXGA = 1200,
+};
+
+struct ov2640_win_size {
+ char *name;
+ enum ov2640_width width;
+ enum ov2640_height height;
+ const struct regval_list *regs;
+};
+
+
+struct ov2640_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ enum v4l2_mbus_pixelcode cfmt_code;
+ const struct ov2640_win_size *win;
+ int model;
+};
+
+/*
+ * Registers settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list ov2640_init_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0x2c, 0xff },
+ { 0x2e, 0xdf },
+ { BANK_SEL, BANK_SEL_SENS },
+ { 0x3c, 0x32 },
+ { CLKRC, CLKRC_DIV_SET(1) },
+ { COM2, COM2_OCAP_Nx_SET(3) },
+ { REG04, REG04_DEF | REG04_HREF_EN },
+ { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN },
+ { COM9, COM9_AGC_GAIN_8x | 0x08},
+ { 0x2c, 0x0c },
+ { 0x33, 0x78 },
+ { 0x3a, 0x33 },
+ { 0x3b, 0xfb },
+ { 0x3e, 0x00 },
+ { 0x43, 0x11 },
+ { 0x16, 0x10 },
+ { 0x39, 0x02 },
+ { 0x35, 0x88 },
+ { 0x22, 0x0a },
+ { 0x37, 0x40 },
+ { 0x23, 0x00 },
+ { ARCOM2, 0xa0 },
+ { 0x06, 0x02 },
+ { 0x06, 0x88 },
+ { 0x07, 0xc0 },
+ { 0x0d, 0xb7 },
+ { 0x0e, 0x01 },
+ { 0x4c, 0x00 },
+ { 0x4a, 0x81 },
+ { 0x21, 0x99 },
+ { AEW, 0x40 },
+ { AEB, 0x38 },
+ { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) },
+ { 0x5c, 0x00 },
+ { 0x63, 0x00 },
+ { FLL, 0x22 },
+ { COM3, 0x38 | COM3_BAND_AUTO },
+ { REG5D, 0x55 },
+ { REG5E, 0x7d },
+ { REG5F, 0x7d },
+ { REG60, 0x55 },
+ { HISTO_LOW, 0x70 },
+ { HISTO_HIGH, 0x80 },
+ { 0x7c, 0x05 },
+ { 0x20, 0x80 },
+ { 0x28, 0x30 },
+ { 0x6c, 0x00 },
+ { 0x6d, 0x80 },
+ { 0x6e, 0x00 },
+ { 0x70, 0x02 },
+ { 0x71, 0x94 },
+ { 0x73, 0xc1 },
+ { 0x3d, 0x34 },
+ { COM7, COM7_RES_UXGA | COM7_ZOOM_EN },
+ { 0x5a, 0x57 },
+ { BD50, 0xbb },
+ { BD60, 0x9c },
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0xe5, 0x7f },
+ { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
+ { 0x41, 0x24 },
+ { RESET, RESET_JPEG | RESET_DVP },
+ { 0x76, 0xff },
+ { 0x33, 0xa0 },
+ { 0x42, 0x20 },
+ { 0x43, 0x18 },
+ { 0x4c, 0x00 },
+ { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
+ { 0x88, 0x3f },
+ { 0xd7, 0x03 },
+ { 0xd9, 0x10 },
+ { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 },
+ { 0xc8, 0x08 },
+ { 0xc9, 0x80 },
+ { BPADDR, 0x00 },
+ { BPDATA, 0x00 },
+ { BPADDR, 0x03 },
+ { BPDATA, 0x48 },
+ { BPDATA, 0x48 },
+ { BPADDR, 0x08 },
+ { BPDATA, 0x20 },
+ { BPDATA, 0x10 },
+ { BPDATA, 0x0e },
+ { 0x90, 0x00 },
+ { 0x91, 0x0e },
+ { 0x91, 0x1a },
+ { 0x91, 0x31 },
+ { 0x91, 0x5a },
+ { 0x91, 0x69 },
+ { 0x91, 0x75 },
+ { 0x91, 0x7e },
+ { 0x91, 0x88 },
+ { 0x91, 0x8f },
+ { 0x91, 0x96 },
+ { 0x91, 0xa3 },
+ { 0x91, 0xaf },
+ { 0x91, 0xc4 },
+ { 0x91, 0xd7 },
+ { 0x91, 0xe8 },
+ { 0x91, 0x20 },
+ { 0x92, 0x00 },
+ { 0x93, 0x06 },
+ { 0x93, 0xe3 },
+ { 0x93, 0x03 },
+ { 0x93, 0x03 },
+ { 0x93, 0x00 },
+ { 0x93, 0x02 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x96, 0x00 },
+ { 0x97, 0x08 },
+ { 0x97, 0x19 },
+ { 0x97, 0x02 },
+ { 0x97, 0x0c },
+ { 0x97, 0x24 },
+ { 0x97, 0x30 },
+ { 0x97, 0x28 },
+ { 0x97, 0x26 },
+ { 0x97, 0x02 },
+ { 0x97, 0x98 },
+ { 0x97, 0x80 },
+ { 0x97, 0x00 },
+ { 0x97, 0x00 },
+ { 0xa4, 0x00 },
+ { 0xa8, 0x00 },
+ { 0xc5, 0x11 },
+ { 0xc6, 0x51 },
+ { 0xbf, 0x80 },
+ { 0xc7, 0x10 },
+ { 0xb6, 0x66 },
+ { 0xb8, 0xA5 },
+ { 0xb7, 0x64 },
+ { 0xb9, 0x7C },
+ { 0xb3, 0xaf },
+ { 0xb4, 0x97 },
+ { 0xb5, 0xFF },
+ { 0xb0, 0xC5 },
+ { 0xb1, 0x94 },
+ { 0xb2, 0x0f },
+ { 0xc4, 0x5c },
+ { 0xa6, 0x00 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x1b },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0x7f, 0x00 },
+ { 0xe5, 0x1f },
+ { 0xe1, 0x77 },
+ { 0xdd, 0x7f },
+ { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
+ ENDMARKER,
+};
+
+/*
+ * Register settings for window size
+ * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.
+ * Then the different zooming configurations will setup the output image size.
+ */
+static const struct regval_list ov2640_size_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { RESET, RESET_DVP },
+ { HSIZE8, HSIZE8_SET(W_UXGA) },
+ { VSIZE8, VSIZE8_SET(H_UXGA) },
+ { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
+ CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
+ { HSIZE, HSIZE_SET(W_UXGA) },
+ { VSIZE, VSIZE_SET(H_UXGA) },
+ { XOFFL, XOFFL_SET(0) },
+ { YOFFL, YOFFL_SET(0) },
+ { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+ VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
+ { TEST, TEST_HSIZE_SET(W_UXGA) },
+ ENDMARKER,
+};
+
+#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \
+ { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \
+ CTRLI_H_DIV_SET(h_div)}, \
+ { ZMOW, ZMOW_OUTW_SET(x) }, \
+ { ZMOH, ZMOH_OUTH_SET(y) }, \
+ { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \
+ { R_DVP_SP, pclk_div }, \
+ { RESET, 0x00}
+
+static const struct regval_list ov2640_qcif_regs[] = {
+ PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_qvga_regs[] = {
+ PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_cif_regs[] = {
+ PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_vga_regs[] = {
+ PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_svga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_xga_regs[] = {
+ PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_sxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_uxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+#define OV2640_SIZE(n, w, h, r) \
+ {.name = n, .width = w , .height = h, .regs = r }
+
+static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
+ OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
+ OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
+ OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
+ OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
+ OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
+ OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
+ OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
+ OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+};
+
+/*
+ * Register settings for pixel formats
+ */
+static const struct regval_list ov2640_format_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_yuv422_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },
+ { 0xD7, 0x01 },
+ { 0x33, 0xa0 },
+ { 0xe1, 0x67 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_rgb565_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },
+ { 0xd7, 0x03 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static enum v4l2_mbus_pixelcode ov2640_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/*
+ * General functions
+ */
+static struct ov2640_priv *to_ov2640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov2640_priv,
+ subdev);
+}
+
+static int ov2640_write_array(struct i2c_client *client,
+ const struct regval_list *vals)
+{
+ int ret;
+
+ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {
+ ret = i2c_smbus_write_byte_data(client,
+ vals->reg_num, vals->value);
+ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",
+ vals->reg_num, vals->value);
+
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ return 0;
+}
+
+static int ov2640_mask_set(struct i2c_client *client,
+ u8 reg, u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, reg);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ov2640_reset(struct i2c_client *client)
+{
+ int ret;
+ const struct regval_list reset_seq[] = {
+ {BANK_SEL, BANK_SEL_SENS},
+ {COM7, COM7_SRST},
+ ENDMARKER,
+ };
+
+ ret = ov2640_write_array(client, reset_seq);
+ if (ret)
+ goto err;
+
+ msleep(5);
+err:
+ dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);
+ return ret;
+}
+
+/*
+ * soc_camera_ops functions
+ */
+static int ov2640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd =
+ &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->val ? REG04_VFLIP_IMG : 0x00;
+ return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val);
+ case V4L2_CID_HFLIP:
+ val = ctrl->val ? REG04_HFLIP_IMG : 0x00;
+ return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
+ }
+
+ return -EINVAL;
+}
+
+static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ id->ident = priv->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov2640_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 1;
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+
+ return 0;
+}
+
+static int ov2640_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov2640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+/* Select the nearest higher resolution for capture */
+static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
+{
+ int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
+
+ for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
+ if (ov2640_supported_win_sizes[i].width >= *width &&
+ ov2640_supported_win_sizes[i].height >= *height) {
+ *width = ov2640_supported_win_sizes[i].width;
+ *height = ov2640_supported_win_sizes[i].height;
+ return &ov2640_supported_win_sizes[i];
+ }
+ }
+
+ *width = ov2640_supported_win_sizes[default_size].width;
+ *height = ov2640_supported_win_sizes[default_size].height;
+ return &ov2640_supported_win_sizes[default_size];
+}
+
+static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
+ enum v4l2_mbus_pixelcode code)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ const struct regval_list *selected_cfmt_regs;
+ int ret;
+
+ /* select win */
+ priv->win = ov2640_select_win(width, height);
+
+ /* select format */
+ priv->cfmt_code = 0;
+ switch (code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__);
+ selected_cfmt_regs = ov2640_rgb565_regs;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__);
+ selected_cfmt_regs = ov2640_yuv422_regs;
+ }
+
+ /* reset hardware */
+ ov2640_reset(client);
+
+ /* initialize the sensor with default data */
+ dev_dbg(&client->dev, "%s: Init default", __func__);
+ ret = ov2640_write_array(client, ov2640_init_regs);
+ if (ret < 0)
+ goto err;
+
+ /* select preamble */
+ dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
+ ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set size win */
+ ret = ov2640_write_array(client, priv->win->regs);
+ if (ret < 0)
+ goto err;
+
+ /* cfmt preamble */
+ dev_dbg(&client->dev, "%s: Set cfmt", __func__);
+ ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set cfmt */
+ ret = ov2640_write_array(client, selected_cfmt_regs);
+ if (ret < 0)
+ goto err;
+
+ priv->cfmt_code = code;
+ *width = priv->win->width;
+ *height = priv->win->height;
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "%s: Error %d", __func__, ret);
+ ov2640_reset(client);
+ priv->win = NULL;
+
+ return ret;
+}
+
+static int ov2640_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ if (!priv->win) {
+ u32 width = W_SVGA, height = H_SVGA;
+ priv->win = ov2640_select_win(&width, &height);
+ priv->cfmt_code = V4L2_MBUS_FMT_UYVY8_2X8;
+ }
+
+ mf->width = priv->win->width;
+ mf->height = priv->win->height;
+ mf->code = priv->cfmt_code;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov2640_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code);
+
+ return ret;
+}
+
+static int ov2640_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct ov2640_win_size *win;
+
+ /*
+ * select suitable win
+ */
+ win = ov2640_select_win(&mf->width, &mf->height);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ return 0;
+}
+
+static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov2640_codes))
+ return -EINVAL;
+
+ *code = ov2640_codes[index];
+ return 0;
+}
+
+static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = W_UXGA;
+ a->c.height = H_UXGA;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = W_UXGA;
+ a->bounds.height = H_UXGA;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov2640_video_probe(struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ u8 pid, ver, midh, midl;
+ const char *devname;
+ int ret;
+
+ ret = ov2640_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
+ pid = i2c_smbus_read_byte_data(client, PID);
+ ver = i2c_smbus_read_byte_data(client, VER);
+ midh = i2c_smbus_read_byte_data(client, MIDH);
+ midl = i2c_smbus_read_byte_data(client, MIDL);
+
+ switch (VERSION(pid, ver)) {
+ case PID_OV2640:
+ devname = "ov2640";
+ priv->model = V4L2_IDENT_OV2640;
+ break;
+ default:
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev,
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname, pid, ver, midh, midl);
+
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov2640_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
+ .s_ctrl = ov2640_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
+ .g_chip_ident = ov2640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov2640_g_register,
+ .s_register = ov2640_s_register,
+#endif
+ .s_power = ov2640_s_power,
+};
+
+static int ov2640_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
+ .s_stream = ov2640_s_stream,
+ .g_mbus_fmt = ov2640_g_fmt,
+ .s_mbus_fmt = ov2640_s_fmt,
+ .try_mbus_fmt = ov2640_try_fmt,
+ .cropcap = ov2640_cropcap,
+ .g_crop = ov2640_g_crop,
+ .enum_mbus_fmt = ov2640_enum_fmt,
+ .g_mbus_config = ov2640_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov2640_subdev_ops = {
+ .core = &ov2640_subdev_core_ops,
+ .video = &ov2640_subdev_video_ops,
+};
+
+/*
+ * i2c_driver functions
+ */
+static int ov2640_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov2640_priv *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ int ret;
+
+ if (!icl) {
+ dev_err(&adapter->dev,
+ "OV2640: Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&adapter->dev,
+ "OV2640: I2C-Adapter doesn't support SMBUS\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&adapter->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->hdl, 2);
+ v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error) {
+ int err = priv->hdl.error;
+
+ kfree(priv);
+ return err;
+ }
+
+ ret = ov2640_video_probe(client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ } else {
+ dev_info(&adapter->dev, "OV2640 Probed\n");
+ }
+
+ return ret;
+}
+
+static int ov2640_remove(struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov2640_id[] = {
+ { "ov2640", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov2640_id);
+
+static struct i2c_driver ov2640_i2c_driver = {
+ .driver = {
+ .name = "ov2640",
+ },
+ .probe = ov2640_probe,
+ .remove = ov2640_remove,
+ .id_table = ov2640_id,
+};
+
+module_i2c_driver(ov2640_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
+MODULE_AUTHOR("Alberto Panizzo");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
new file mode 100644
index 000000000000..d886c0b9ce44
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -0,0 +1,1088 @@
+/*
+ * Driver for OV5642 CMOS Image Sensor from Omnivision
+ *
+ * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
+ *
+ * Based on Sony IMX074 Camera Driver
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * 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/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/* OV5642 registers */
+#define REG_CHIP_ID_HIGH 0x300a
+#define REG_CHIP_ID_LOW 0x300b
+
+#define REG_WINDOW_START_X_HIGH 0x3800
+#define REG_WINDOW_START_X_LOW 0x3801
+#define REG_WINDOW_START_Y_HIGH 0x3802
+#define REG_WINDOW_START_Y_LOW 0x3803
+#define REG_WINDOW_WIDTH_HIGH 0x3804
+#define REG_WINDOW_WIDTH_LOW 0x3805
+#define REG_WINDOW_HEIGHT_HIGH 0x3806
+#define REG_WINDOW_HEIGHT_LOW 0x3807
+#define REG_OUT_WIDTH_HIGH 0x3808
+#define REG_OUT_WIDTH_LOW 0x3809
+#define REG_OUT_HEIGHT_HIGH 0x380a
+#define REG_OUT_HEIGHT_LOW 0x380b
+#define REG_OUT_TOTAL_WIDTH_HIGH 0x380c
+#define REG_OUT_TOTAL_WIDTH_LOW 0x380d
+#define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e
+#define REG_OUT_TOTAL_HEIGHT_LOW 0x380f
+#define REG_OUTPUT_FORMAT 0x4300
+#define REG_ISP_CTRL_01 0x5001
+#define REG_AVG_WINDOW_END_X_HIGH 0x5682
+#define REG_AVG_WINDOW_END_X_LOW 0x5683
+#define REG_AVG_WINDOW_END_Y_HIGH 0x5686
+#define REG_AVG_WINDOW_END_Y_LOW 0x5687
+
+/* active pixel array size */
+#define OV5642_SENSOR_SIZE_X 2592
+#define OV5642_SENSOR_SIZE_Y 1944
+
+/*
+ * About OV5642 resolution, cropping and binning:
+ * This sensor supports it all, at least in the feature description.
+ * Unfortunately, no combination of appropriate registers settings could make
+ * the chip work the intended way. As it works with predefined register lists,
+ * some undocumented registers are presumably changed there to achieve their
+ * goals.
+ * This driver currently only works for resolutions up to 720 lines with a
+ * 1:1 scale. Hopefully these restrictions will be removed in the future.
+ */
+#define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X
+#define OV5642_MAX_HEIGHT 720
+
+/* default sizes */
+#define OV5642_DEFAULT_WIDTH 1280
+#define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT
+
+/* minimum extra blanking */
+#define BLANKING_EXTRA_WIDTH 500
+#define BLANKING_EXTRA_HEIGHT 20
+
+/*
+ * the sensor's autoexposure is buggy when setting total_height low.
+ * It tries to expose longer than 1 frame period without taking care of it
+ * and this leads to weird output. So we set 1000 lines as minimum.
+ */
+#define BLANKING_MIN_HEIGHT 1000
+
+struct regval_list {
+ u16 reg_num;
+ u8 value;
+};
+
+static struct regval_list ov5642_default_regs_init[] = {
+ { 0x3103, 0x93 },
+ { 0x3008, 0x82 },
+ { 0x3017, 0x7f },
+ { 0x3018, 0xfc },
+ { 0x3810, 0xc2 },
+ { 0x3615, 0xf0 },
+ { 0x3000, 0x0 },
+ { 0x3001, 0x0 },
+ { 0x3002, 0x0 },
+ { 0x3003, 0x0 },
+ { 0x3004, 0xff },
+ { 0x3030, 0x2b },
+ { 0x3011, 0x8 },
+ { 0x3010, 0x10 },
+ { 0x3604, 0x60 },
+ { 0x3622, 0x60 },
+ { 0x3621, 0x9 },
+ { 0x3709, 0x0 },
+ { 0x4000, 0x21 },
+ { 0x401d, 0x22 },
+ { 0x3600, 0x54 },
+ { 0x3605, 0x4 },
+ { 0x3606, 0x3f },
+ { 0x3c01, 0x80 },
+ { 0x300d, 0x22 },
+ { 0x3623, 0x22 },
+ { 0x5000, 0x4f },
+ { 0x5020, 0x4 },
+ { 0x5181, 0x79 },
+ { 0x5182, 0x0 },
+ { 0x5185, 0x22 },
+ { 0x5197, 0x1 },
+ { 0x5500, 0xa },
+ { 0x5504, 0x0 },
+ { 0x5505, 0x7f },
+ { 0x5080, 0x8 },
+ { 0x300e, 0x18 },
+ { 0x4610, 0x0 },
+ { 0x471d, 0x5 },
+ { 0x4708, 0x6 },
+ { 0x370c, 0xa0 },
+ { 0x5687, 0x94 },
+ { 0x501f, 0x0 },
+ { 0x5000, 0x4f },
+ { 0x5001, 0xcf },
+ { 0x4300, 0x30 },
+ { 0x4300, 0x30 },
+ { 0x460b, 0x35 },
+ { 0x471d, 0x0 },
+ { 0x3002, 0xc },
+ { 0x3002, 0x0 },
+ { 0x4713, 0x3 },
+ { 0x471c, 0x50 },
+ { 0x4721, 0x2 },
+ { 0x4402, 0x90 },
+ { 0x460c, 0x22 },
+ { 0x3815, 0x44 },
+ { 0x3503, 0x7 },
+ { 0x3501, 0x73 },
+ { 0x3502, 0x80 },
+ { 0x350b, 0x0 },
+ { 0x3818, 0xc8 },
+ { 0x3824, 0x11 },
+ { 0x3a00, 0x78 },
+ { 0x3a1a, 0x4 },
+ { 0x3a13, 0x30 },
+ { 0x3a18, 0x0 },
+ { 0x3a19, 0x7c },
+ { 0x3a08, 0x12 },
+ { 0x3a09, 0xc0 },
+ { 0x3a0a, 0xf },
+ { 0x3a0b, 0xa0 },
+ { 0x350c, 0x7 },
+ { 0x350d, 0xd0 },
+ { 0x3a0d, 0x8 },
+ { 0x3a0e, 0x6 },
+ { 0x3500, 0x0 },
+ { 0x3501, 0x0 },
+ { 0x3502, 0x0 },
+ { 0x350a, 0x0 },
+ { 0x350b, 0x0 },
+ { 0x3503, 0x0 },
+ { 0x3a0f, 0x3c },
+ { 0x3a10, 0x32 },
+ { 0x3a1b, 0x3c },
+ { 0x3a1e, 0x32 },
+ { 0x3a11, 0x80 },
+ { 0x3a1f, 0x20 },
+ { 0x3030, 0x2b },
+ { 0x3a02, 0x0 },
+ { 0x3a03, 0x7d },
+ { 0x3a04, 0x0 },
+ { 0x3a14, 0x0 },
+ { 0x3a15, 0x7d },
+ { 0x3a16, 0x0 },
+ { 0x3a00, 0x78 },
+ { 0x3a08, 0x9 },
+ { 0x3a09, 0x60 },
+ { 0x3a0a, 0x7 },
+ { 0x3a0b, 0xd0 },
+ { 0x3a0d, 0x10 },
+ { 0x3a0e, 0xd },
+ { 0x4407, 0x4 },
+ { 0x5193, 0x70 },
+ { 0x589b, 0x0 },
+ { 0x589a, 0xc0 },
+ { 0x401e, 0x20 },
+ { 0x4001, 0x42 },
+ { 0x401c, 0x6 },
+ { 0x3825, 0xac },
+ { 0x3827, 0xc },
+ { 0x528a, 0x1 },
+ { 0x528b, 0x4 },
+ { 0x528c, 0x8 },
+ { 0x528d, 0x10 },
+ { 0x528e, 0x20 },
+ { 0x528f, 0x28 },
+ { 0x5290, 0x30 },
+ { 0x5292, 0x0 },
+ { 0x5293, 0x1 },
+ { 0x5294, 0x0 },
+ { 0x5295, 0x4 },
+ { 0x5296, 0x0 },
+ { 0x5297, 0x8 },
+ { 0x5298, 0x0 },
+ { 0x5299, 0x10 },
+ { 0x529a, 0x0 },
+ { 0x529b, 0x20 },
+ { 0x529c, 0x0 },
+ { 0x529d, 0x28 },
+ { 0x529e, 0x0 },
+ { 0x529f, 0x30 },
+ { 0x5282, 0x0 },
+ { 0x5300, 0x0 },
+ { 0x5301, 0x20 },
+ { 0x5302, 0x0 },
+ { 0x5303, 0x7c },
+ { 0x530c, 0x0 },
+ { 0x530d, 0xc },
+ { 0x530e, 0x20 },
+ { 0x530f, 0x80 },
+ { 0x5310, 0x20 },
+ { 0x5311, 0x80 },
+ { 0x5308, 0x20 },
+ { 0x5309, 0x40 },
+ { 0x5304, 0x0 },
+ { 0x5305, 0x30 },
+ { 0x5306, 0x0 },
+ { 0x5307, 0x80 },
+ { 0x5314, 0x8 },
+ { 0x5315, 0x20 },
+ { 0x5319, 0x30 },
+ { 0x5316, 0x10 },
+ { 0x5317, 0x0 },
+ { 0x5318, 0x2 },
+ { 0x5380, 0x1 },
+ { 0x5381, 0x0 },
+ { 0x5382, 0x0 },
+ { 0x5383, 0x4e },
+ { 0x5384, 0x0 },
+ { 0x5385, 0xf },
+ { 0x5386, 0x0 },
+ { 0x5387, 0x0 },
+ { 0x5388, 0x1 },
+ { 0x5389, 0x15 },
+ { 0x538a, 0x0 },
+ { 0x538b, 0x31 },
+ { 0x538c, 0x0 },
+ { 0x538d, 0x0 },
+ { 0x538e, 0x0 },
+ { 0x538f, 0xf },
+ { 0x5390, 0x0 },
+ { 0x5391, 0xab },
+ { 0x5392, 0x0 },
+ { 0x5393, 0xa2 },
+ { 0x5394, 0x8 },
+ { 0x5480, 0x14 },
+ { 0x5481, 0x21 },
+ { 0x5482, 0x36 },
+ { 0x5483, 0x57 },
+ { 0x5484, 0x65 },
+ { 0x5485, 0x71 },
+ { 0x5486, 0x7d },
+ { 0x5487, 0x87 },
+ { 0x5488, 0x91 },
+ { 0x5489, 0x9a },
+ { 0x548a, 0xaa },
+ { 0x548b, 0xb8 },
+ { 0x548c, 0xcd },
+ { 0x548d, 0xdd },
+ { 0x548e, 0xea },
+ { 0x548f, 0x1d },
+ { 0x5490, 0x5 },
+ { 0x5491, 0x0 },
+ { 0x5492, 0x4 },
+ { 0x5493, 0x20 },
+ { 0x5494, 0x3 },
+ { 0x5495, 0x60 },
+ { 0x5496, 0x2 },
+ { 0x5497, 0xb8 },
+ { 0x5498, 0x2 },
+ { 0x5499, 0x86 },
+ { 0x549a, 0x2 },
+ { 0x549b, 0x5b },
+ { 0x549c, 0x2 },
+ { 0x549d, 0x3b },
+ { 0x549e, 0x2 },
+ { 0x549f, 0x1c },
+ { 0x54a0, 0x2 },
+ { 0x54a1, 0x4 },
+ { 0x54a2, 0x1 },
+ { 0x54a3, 0xed },
+ { 0x54a4, 0x1 },
+ { 0x54a5, 0xc5 },
+ { 0x54a6, 0x1 },
+ { 0x54a7, 0xa5 },
+ { 0x54a8, 0x1 },
+ { 0x54a9, 0x6c },
+ { 0x54aa, 0x1 },
+ { 0x54ab, 0x41 },
+ { 0x54ac, 0x1 },
+ { 0x54ad, 0x20 },
+ { 0x54ae, 0x0 },
+ { 0x54af, 0x16 },
+ { 0x54b0, 0x1 },
+ { 0x54b1, 0x20 },
+ { 0x54b2, 0x0 },
+ { 0x54b3, 0x10 },
+ { 0x54b4, 0x0 },
+ { 0x54b5, 0xf0 },
+ { 0x54b6, 0x0 },
+ { 0x54b7, 0xdf },
+ { 0x5402, 0x3f },
+ { 0x5403, 0x0 },
+ { 0x3406, 0x0 },
+ { 0x5180, 0xff },
+ { 0x5181, 0x52 },
+ { 0x5182, 0x11 },
+ { 0x5183, 0x14 },
+ { 0x5184, 0x25 },
+ { 0x5185, 0x24 },
+ { 0x5186, 0x6 },
+ { 0x5187, 0x8 },
+ { 0x5188, 0x8 },
+ { 0x5189, 0x7c },
+ { 0x518a, 0x60 },
+ { 0x518b, 0xb2 },
+ { 0x518c, 0xb2 },
+ { 0x518d, 0x44 },
+ { 0x518e, 0x3d },
+ { 0x518f, 0x58 },
+ { 0x5190, 0x46 },
+ { 0x5191, 0xf8 },
+ { 0x5192, 0x4 },
+ { 0x5193, 0x70 },
+ { 0x5194, 0xf0 },
+ { 0x5195, 0xf0 },
+ { 0x5196, 0x3 },
+ { 0x5197, 0x1 },
+ { 0x5198, 0x4 },
+ { 0x5199, 0x12 },
+ { 0x519a, 0x4 },
+ { 0x519b, 0x0 },
+ { 0x519c, 0x6 },
+ { 0x519d, 0x82 },
+ { 0x519e, 0x0 },
+ { 0x5025, 0x80 },
+ { 0x3a0f, 0x38 },
+ { 0x3a10, 0x30 },
+ { 0x3a1b, 0x3a },
+ { 0x3a1e, 0x2e },
+ { 0x3a11, 0x60 },
+ { 0x3a1f, 0x10 },
+ { 0x5688, 0xa6 },
+ { 0x5689, 0x6a },
+ { 0x568a, 0xea },
+ { 0x568b, 0xae },
+ { 0x568c, 0xa6 },
+ { 0x568d, 0x6a },
+ { 0x568e, 0x62 },
+ { 0x568f, 0x26 },
+ { 0x5583, 0x40 },
+ { 0x5584, 0x40 },
+ { 0x5580, 0x2 },
+ { 0x5000, 0xcf },
+ { 0x5800, 0x27 },
+ { 0x5801, 0x19 },
+ { 0x5802, 0x12 },
+ { 0x5803, 0xf },
+ { 0x5804, 0x10 },
+ { 0x5805, 0x15 },
+ { 0x5806, 0x1e },
+ { 0x5807, 0x2f },
+ { 0x5808, 0x15 },
+ { 0x5809, 0xd },
+ { 0x580a, 0xa },
+ { 0x580b, 0x9 },
+ { 0x580c, 0xa },
+ { 0x580d, 0xc },
+ { 0x580e, 0x12 },
+ { 0x580f, 0x19 },
+ { 0x5810, 0xb },
+ { 0x5811, 0x7 },
+ { 0x5812, 0x4 },
+ { 0x5813, 0x3 },
+ { 0x5814, 0x3 },
+ { 0x5815, 0x6 },
+ { 0x5816, 0xa },
+ { 0x5817, 0xf },
+ { 0x5818, 0xa },
+ { 0x5819, 0x5 },
+ { 0x581a, 0x1 },
+ { 0x581b, 0x0 },
+ { 0x581c, 0x0 },
+ { 0x581d, 0x3 },
+ { 0x581e, 0x8 },
+ { 0x581f, 0xc },
+ { 0x5820, 0xa },
+ { 0x5821, 0x5 },
+ { 0x5822, 0x1 },
+ { 0x5823, 0x0 },
+ { 0x5824, 0x0 },
+ { 0x5825, 0x3 },
+ { 0x5826, 0x8 },
+ { 0x5827, 0xc },
+ { 0x5828, 0xe },
+ { 0x5829, 0x8 },
+ { 0x582a, 0x6 },
+ { 0x582b, 0x4 },
+ { 0x582c, 0x5 },
+ { 0x582d, 0x7 },
+ { 0x582e, 0xb },
+ { 0x582f, 0x12 },
+ { 0x5830, 0x18 },
+ { 0x5831, 0x10 },
+ { 0x5832, 0xc },
+ { 0x5833, 0xa },
+ { 0x5834, 0xb },
+ { 0x5835, 0xe },
+ { 0x5836, 0x15 },
+ { 0x5837, 0x19 },
+ { 0x5838, 0x32 },
+ { 0x5839, 0x1f },
+ { 0x583a, 0x18 },
+ { 0x583b, 0x16 },
+ { 0x583c, 0x17 },
+ { 0x583d, 0x1e },
+ { 0x583e, 0x26 },
+ { 0x583f, 0x53 },
+ { 0x5840, 0x10 },
+ { 0x5841, 0xf },
+ { 0x5842, 0xd },
+ { 0x5843, 0xc },
+ { 0x5844, 0xe },
+ { 0x5845, 0x9 },
+ { 0x5846, 0x11 },
+ { 0x5847, 0x10 },
+ { 0x5848, 0x10 },
+ { 0x5849, 0x10 },
+ { 0x584a, 0x10 },
+ { 0x584b, 0xe },
+ { 0x584c, 0x10 },
+ { 0x584d, 0x10 },
+ { 0x584e, 0x11 },
+ { 0x584f, 0x10 },
+ { 0x5850, 0xf },
+ { 0x5851, 0xc },
+ { 0x5852, 0xf },
+ { 0x5853, 0x10 },
+ { 0x5854, 0x10 },
+ { 0x5855, 0xf },
+ { 0x5856, 0xe },
+ { 0x5857, 0xb },
+ { 0x5858, 0x10 },
+ { 0x5859, 0xd },
+ { 0x585a, 0xd },
+ { 0x585b, 0xc },
+ { 0x585c, 0xc },
+ { 0x585d, 0xc },
+ { 0x585e, 0xb },
+ { 0x585f, 0xc },
+ { 0x5860, 0xc },
+ { 0x5861, 0xc },
+ { 0x5862, 0xd },
+ { 0x5863, 0x8 },
+ { 0x5864, 0x11 },
+ { 0x5865, 0x18 },
+ { 0x5866, 0x18 },
+ { 0x5867, 0x19 },
+ { 0x5868, 0x17 },
+ { 0x5869, 0x19 },
+ { 0x586a, 0x16 },
+ { 0x586b, 0x13 },
+ { 0x586c, 0x13 },
+ { 0x586d, 0x12 },
+ { 0x586e, 0x13 },
+ { 0x586f, 0x16 },
+ { 0x5870, 0x14 },
+ { 0x5871, 0x12 },
+ { 0x5872, 0x10 },
+ { 0x5873, 0x11 },
+ { 0x5874, 0x11 },
+ { 0x5875, 0x16 },
+ { 0x5876, 0x14 },
+ { 0x5877, 0x11 },
+ { 0x5878, 0x10 },
+ { 0x5879, 0xf },
+ { 0x587a, 0x10 },
+ { 0x587b, 0x14 },
+ { 0x587c, 0x13 },
+ { 0x587d, 0x12 },
+ { 0x587e, 0x11 },
+ { 0x587f, 0x11 },
+ { 0x5880, 0x12 },
+ { 0x5881, 0x15 },
+ { 0x5882, 0x14 },
+ { 0x5883, 0x15 },
+ { 0x5884, 0x15 },
+ { 0x5885, 0x15 },
+ { 0x5886, 0x13 },
+ { 0x5887, 0x17 },
+ { 0x3710, 0x10 },
+ { 0x3632, 0x51 },
+ { 0x3702, 0x10 },
+ { 0x3703, 0xb2 },
+ { 0x3704, 0x18 },
+ { 0x370b, 0x40 },
+ { 0x370d, 0x3 },
+ { 0x3631, 0x1 },
+ { 0x3632, 0x52 },
+ { 0x3606, 0x24 },
+ { 0x3620, 0x96 },
+ { 0x5785, 0x7 },
+ { 0x3a13, 0x30 },
+ { 0x3600, 0x52 },
+ { 0x3604, 0x48 },
+ { 0x3606, 0x1b },
+ { 0x370d, 0xb },
+ { 0x370f, 0xc0 },
+ { 0x3709, 0x1 },
+ { 0x3823, 0x0 },
+ { 0x5007, 0x0 },
+ { 0x5009, 0x0 },
+ { 0x5011, 0x0 },
+ { 0x5013, 0x0 },
+ { 0x519e, 0x0 },
+ { 0x5086, 0x0 },
+ { 0x5087, 0x0 },
+ { 0x5088, 0x0 },
+ { 0x5089, 0x0 },
+ { 0x302b, 0x0 },
+ { 0x3503, 0x7 },
+ { 0x3011, 0x8 },
+ { 0x350c, 0x2 },
+ { 0x350d, 0xe4 },
+ { 0x3621, 0xc9 },
+ { 0x370a, 0x81 },
+ { 0xffff, 0xff },
+};
+
+static struct regval_list ov5642_default_regs_finalise[] = {
+ { 0x3810, 0xc2 },
+ { 0x3818, 0xc9 },
+ { 0x381c, 0x10 },
+ { 0x381d, 0xa0 },
+ { 0x381e, 0x5 },
+ { 0x381f, 0xb0 },
+ { 0x3820, 0x0 },
+ { 0x3821, 0x0 },
+ { 0x3824, 0x11 },
+ { 0x3a08, 0x1b },
+ { 0x3a09, 0xc0 },
+ { 0x3a0a, 0x17 },
+ { 0x3a0b, 0x20 },
+ { 0x3a0d, 0x2 },
+ { 0x3a0e, 0x1 },
+ { 0x401c, 0x4 },
+ { 0x5682, 0x5 },
+ { 0x5683, 0x0 },
+ { 0x5686, 0x2 },
+ { 0x5687, 0xcc },
+ { 0x5001, 0x4f },
+ { 0x589b, 0x6 },
+ { 0x589a, 0xc5 },
+ { 0x3503, 0x0 },
+ { 0x460c, 0x20 },
+ { 0x460b, 0x37 },
+ { 0x471c, 0xd0 },
+ { 0x471d, 0x5 },
+ { 0x3815, 0x1 },
+ { 0x3818, 0xc1 },
+ { 0x501f, 0x0 },
+ { 0x5002, 0xe0 },
+ { 0x4300, 0x32 }, /* UYVY */
+ { 0x3002, 0x1c },
+ { 0x4800, 0x14 },
+ { 0x4801, 0xf },
+ { 0x3007, 0x3b },
+ { 0x300e, 0x4 },
+ { 0x4803, 0x50 },
+ { 0x3815, 0x1 },
+ { 0x4713, 0x2 },
+ { 0x4842, 0x1 },
+ { 0x300f, 0xe },
+ { 0x3003, 0x3 },
+ { 0x3003, 0x1 },
+ { 0xffff, 0xff },
+};
+
+struct ov5642_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct ov5642 {
+ struct v4l2_subdev subdev;
+ const struct ov5642_datafmt *fmt;
+ struct v4l2_rect crop_rect;
+
+ /* blanking information */
+ int total_width;
+ int total_height;
+};
+
+static const struct ov5642_datafmt ov5642_colour_fmts[] = {
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5642 *to_ov5642(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5642_datafmt
+ *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
+ if (ov5642_colour_fmts[i].code == code)
+ return ov5642_colour_fmts + i;
+
+ return NULL;
+}
+
+static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+ int ret;
+ /* We have 16-bit i2c addresses - care for endianess */
+ unsigned char data[2] = { reg >> 8, reg & 0xff };
+
+ ret = i2c_master_send(client, data, 2);
+ if (ret < 2) {
+ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+
+ ret = i2c_master_recv(client, val, 1);
+ if (ret < 1) {
+ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+ return 0;
+}
+
+static int reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+ int ret;
+ unsigned char data[3] = { reg >> 8, reg & 0xff, val };
+
+ ret = i2c_master_send(client, data, 3);
+ if (ret < 3) {
+ dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * convenience function to write 16 bit register values that are split up
+ * into two consecutive high and low parts
+ */
+static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
+{
+ int ret;
+
+ ret = reg_write(client, reg, val16 >> 8);
+ if (ret)
+ return ret;
+ return reg_write(client, reg + 1, val16 & 0x00ff);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xffff)
+ return -EINVAL;
+
+ reg->size = 1;
+
+ ret = reg_read(client, reg->reg, &val);
+ if (!ret)
+ reg->val = (__u64)val;
+
+ return ret;
+}
+
+static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xffff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov5642_write_array(struct i2c_client *client,
+ struct regval_list *vals)
+{
+ while (vals->reg_num != 0xffff || vals->value != 0xff) {
+ int ret = reg_write(client, vals->reg_num, vals->value);
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ dev_dbg(&client->dev, "Register list loaded\n");
+ return 0;
+}
+
+static int ov5642_set_resolution(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+ int width = priv->crop_rect.width;
+ int height = priv->crop_rect.height;
+ int total_width = priv->total_width;
+ int total_height = priv->total_height;
+ int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
+ int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
+ int ret;
+
+ /*
+ * This should set the starting point for cropping.
+ * Doesn't work so far.
+ */
+ ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
+ if (!ret)
+ ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
+ if (!ret) {
+ priv->crop_rect.left = start_x;
+ priv->crop_rect.top = start_y;
+ }
+
+ if (!ret)
+ ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
+ if (!ret)
+ ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
+ if (ret)
+ return ret;
+ priv->crop_rect.width = width;
+ priv->crop_rect.height = height;
+
+ /* Set the output window size. Only 1:1 scale is supported so far. */
+ ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
+ if (!ret)
+ ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
+
+ /* Total width = output size + blanking */
+ if (!ret)
+ ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
+ if (!ret)
+ ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
+
+ /* Sets the window for AWB calculations */
+ if (!ret)
+ ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
+ if (!ret)
+ ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
+
+ return ret;
+}
+
+static int ov5642_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+ const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+
+ mf->width = priv->crop_rect.width;
+ mf->height = priv->crop_rect.height;
+
+ if (!fmt) {
+ mf->code = ov5642_colour_fmts[0].code;
+ mf->colorspace = ov5642_colour_fmts[0].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov5642_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+
+ /* MIPI CSI could have changed the format, double-check */
+ if (!ov5642_find_datafmt(mf->code))
+ return -EINVAL;
+
+ ov5642_try_fmt(sd, mf);
+ priv->fmt = ov5642_find_datafmt(mf->code);
+
+ return 0;
+}
+
+static int ov5642_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+
+ const struct ov5642_datafmt *fmt = priv->fmt;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->width = priv->crop_rect.width;
+ mf->height = priv->crop_rect.height;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov5642_colour_fmts))
+ return -EINVAL;
+
+ *code = ov5642_colour_fmts[index].code;
+ return 0;
+}
+
+static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = V4L2_IDENT_OV5642;
+ id->revision = 0;
+
+ return 0;
+}
+
+static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+ struct v4l2_rect *rect = &a->c;
+ int ret;
+
+ v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1,
+ &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0);
+
+ priv->crop_rect.width = rect->width;
+ priv->crop_rect.height = rect->height;
+ priv->total_width = rect->width + BLANKING_EXTRA_WIDTH;
+ priv->total_height = max_t(int, rect->height +
+ BLANKING_EXTRA_HEIGHT,
+ BLANKING_MIN_HEIGHT);
+ priv->crop_rect.width = rect->width;
+ priv->crop_rect.height = rect->height;
+
+ ret = ov5642_write_array(client, ov5642_default_regs_init);
+ if (!ret)
+ ret = ov5642_set_resolution(sd);
+ if (!ret)
+ ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+ return ret;
+}
+
+static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5642 *priv = to_ov5642(client);
+ struct v4l2_rect *rect = &a->c;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ *rect = priv->crop_rect;
+
+ return 0;
+}
+
+static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = OV5642_MAX_WIDTH;
+ a->bounds.height = OV5642_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ cfg->type = V4L2_MBUS_CSI2;
+ cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+ return 0;
+}
+
+static int ov5642_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!on)
+ return soc_camera_power_off(&client->dev, icl);
+
+ ret = soc_camera_power_on(&client->dev, icl);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5642_write_array(client, ov5642_default_regs_init);
+ if (!ret)
+ ret = ov5642_set_resolution(sd);
+ if (!ret)
+ ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+ return ret;
+}
+
+static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
+ .s_mbus_fmt = ov5642_s_fmt,
+ .g_mbus_fmt = ov5642_g_fmt,
+ .try_mbus_fmt = ov5642_try_fmt,
+ .enum_mbus_fmt = ov5642_enum_fmt,
+ .s_crop = ov5642_s_crop,
+ .g_crop = ov5642_g_crop,
+ .cropcap = ov5642_cropcap,
+ .g_mbus_config = ov5642_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
+ .s_power = ov5642_s_power,
+ .g_chip_ident = ov5642_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov5642_get_register,
+ .s_register = ov5642_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5642_subdev_ops = {
+ .core = &ov5642_subdev_core_ops,
+ .video = &ov5642_subdev_video_ops,
+};
+
+static int ov5642_video_probe(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ int ret;
+ u8 id_high, id_low;
+ u16 id;
+
+ ret = ov5642_s_power(subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Read sensor Model ID */
+ ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
+ if (ret < 0)
+ goto done;
+
+ id = id_high << 8;
+
+ ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
+ if (ret < 0)
+ goto done;
+
+ id |= id_low;
+
+ dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+ if (id != 0x5642) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ ov5642_s_power(subdev, 0);
+ return ret;
+}
+
+static int ov5642_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov5642 *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "OV5642: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
+
+ priv->fmt = &ov5642_colour_fmts[0];
+
+ priv->crop_rect.width = OV5642_DEFAULT_WIDTH;
+ priv->crop_rect.height = OV5642_DEFAULT_HEIGHT;
+ priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
+ priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
+ priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
+ priv->total_height = BLANKING_MIN_HEIGHT;
+
+ ret = ov5642_video_probe(client);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ kfree(priv);
+ return ret;
+}
+
+static int ov5642_remove(struct i2c_client *client)
+{
+ struct ov5642 *priv = to_ov5642(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ if (icl->free_bus)
+ icl->free_bus(icl);
+ kfree(priv);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+ { "ov5642", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct i2c_driver ov5642_i2c_driver = {
+ .driver = {
+ .name = "ov5642",
+ },
+ .probe = ov5642_probe,
+ .remove = ov5642_remove,
+ .id_table = ov5642_id,
+};
+
+module_i2c_driver(ov5642_i2c_driver);
+
+MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
new file mode 100644
index 000000000000..65b031f333b7
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -0,0 +1,1069 @@
+/*
+ * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor
+ *
+ * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on OmniVision OV96xx Camera Driver
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/sensor_ov6650.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+/* Register definitions */
+#define REG_GAIN 0x00 /* range 00 - 3F */
+#define REG_BLUE 0x01
+#define REG_RED 0x02
+#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */
+#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */
+
+#define REG_BRT 0x06
+
+#define REG_PIDH 0x0a
+#define REG_PIDL 0x0b
+
+#define REG_AECH 0x10
+#define REG_CLKRC 0x11 /* Data Format and Internal Clock */
+ /* [7:6] Input system clock (MHz)*/
+ /* 00=8, 01=12, 10=16, 11=24 */
+ /* [5:0]: Internal Clock Pre-Scaler */
+#define REG_COMA 0x12 /* [7] Reset */
+#define REG_COMB 0x13
+#define REG_COMC 0x14
+#define REG_COMD 0x15
+#define REG_COML 0x16
+#define REG_HSTRT 0x17
+#define REG_HSTOP 0x18
+#define REG_VSTRT 0x19
+#define REG_VSTOP 0x1a
+#define REG_PSHFT 0x1b
+#define REG_MIDH 0x1c
+#define REG_MIDL 0x1d
+#define REG_HSYNS 0x1e
+#define REG_HSYNE 0x1f
+#define REG_COME 0x20
+#define REG_YOFF 0x21
+#define REG_UOFF 0x22
+#define REG_VOFF 0x23
+#define REG_AEW 0x24
+#define REG_AEB 0x25
+#define REG_COMF 0x26
+#define REG_COMG 0x27
+#define REG_COMH 0x28
+#define REG_COMI 0x29
+
+#define REG_FRARL 0x2b
+#define REG_COMJ 0x2c
+#define REG_COMK 0x2d
+#define REG_AVGY 0x2e
+#define REG_REF0 0x2f
+#define REG_REF1 0x30
+#define REG_REF2 0x31
+#define REG_FRAJH 0x32
+#define REG_FRAJL 0x33
+#define REG_FACT 0x34
+#define REG_L1AEC 0x35
+#define REG_AVGU 0x36
+#define REG_AVGV 0x37
+
+#define REG_SPCB 0x60
+#define REG_SPCC 0x61
+#define REG_GAM1 0x62
+#define REG_GAM2 0x63
+#define REG_GAM3 0x64
+#define REG_SPCD 0x65
+
+#define REG_SPCE 0x68
+#define REG_ADCL 0x69
+
+#define REG_RMCO 0x6c
+#define REG_GMCO 0x6d
+#define REG_BMCO 0x6e
+
+
+/* Register bits, values, etc. */
+#define OV6650_PIDH 0x66 /* high byte of product ID number */
+#define OV6650_PIDL 0x50 /* low byte of product ID number */
+#define OV6650_MIDH 0x7F /* high byte of mfg ID */
+#define OV6650_MIDL 0xA2 /* low byte of mfg ID */
+
+#define DEF_GAIN 0x00
+#define DEF_BLUE 0x80
+#define DEF_RED 0x80
+
+#define SAT_SHIFT 4
+#define SAT_MASK (0xf << SAT_SHIFT)
+#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK)
+
+#define HUE_EN BIT(5)
+#define HUE_MASK 0x1f
+#define DEF_HUE 0x10
+#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK))
+
+#define DEF_AECH 0x4D
+
+#define CLKRC_6MHz 0x00
+#define CLKRC_12MHz 0x40
+#define CLKRC_16MHz 0x80
+#define CLKRC_24MHz 0xc0
+#define CLKRC_DIV_MASK 0x3f
+#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1)
+
+#define COMA_RESET BIT(7)
+#define COMA_QCIF BIT(5)
+#define COMA_RAW_RGB BIT(4)
+#define COMA_RGB BIT(3)
+#define COMA_BW BIT(2)
+#define COMA_WORD_SWAP BIT(1)
+#define COMA_BYTE_SWAP BIT(0)
+#define DEF_COMA 0x00
+
+#define COMB_FLIP_V BIT(7)
+#define COMB_FLIP_H BIT(5)
+#define COMB_BAND_FILTER BIT(4)
+#define COMB_AWB BIT(2)
+#define COMB_AGC BIT(1)
+#define COMB_AEC BIT(0)
+#define DEF_COMB 0x5f
+
+#define COML_ONE_CHANNEL BIT(7)
+
+#define DEF_HSTRT 0x24
+#define DEF_HSTOP 0xd4
+#define DEF_VSTRT 0x04
+#define DEF_VSTOP 0x94
+
+#define COMF_HREF_LOW BIT(4)
+
+#define COMJ_PCLK_RISING BIT(4)
+#define COMJ_VSYNC_HIGH BIT(0)
+
+/* supported resolutions */
+#define W_QCIF (DEF_HSTOP - DEF_HSTRT)
+#define W_CIF (W_QCIF << 1)
+#define H_QCIF (DEF_VSTOP - DEF_VSTRT)
+#define H_CIF (H_QCIF << 1)
+
+#define FRAME_RATE_MAX 30
+
+
+struct ov6650_reg {
+ u8 reg;
+ u8 val;
+};
+
+struct ov6650 {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* exposure/autoexposure cluster */
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct {
+ /* gain/autogain cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ };
+ struct {
+ /* blue/red/autowhitebalance cluster */
+ struct v4l2_ctrl *autowb;
+ struct v4l2_ctrl *blue;
+ struct v4l2_ctrl *red;
+ };
+ bool half_scale; /* scale down output by 2 */
+ struct v4l2_rect rect; /* sensor cropping window */
+ unsigned long pclk_limit; /* from host */
+ unsigned long pclk_max; /* from resolution and format */
+ struct v4l2_fract tpf; /* as requested with s_parm */
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+
+static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_Y8_1X8,
+};
+
+/* read a register */
+static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int ret;
+ u8 data = reg;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ msg.flags = I2C_M_RD;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ *val = data;
+ return 0;
+
+err:
+ dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+ return ret;
+}
+
+/* write a register */
+static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ int ret;
+ unsigned char data[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ udelay(100);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+ return ret;
+ }
+ return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask)
+{
+ u8 val;
+ int ret;
+
+ ret = ov6650_reg_read(client, reg, &val);
+ if (ret) {
+ dev_err(&client->dev,
+ "[Read]-Modify-Write of register 0x%02x failed!\n",
+ reg);
+ return ret;
+ }
+
+ val &= ~mask;
+ val |= set;
+
+ ret = ov6650_reg_write(client, reg, val);
+ if (ret)
+ dev_err(&client->dev,
+ "Read-Modify-[Write] of register 0x%02x failed!\n",
+ reg);
+
+ return ret;
+}
+
+static struct ov6650 *to_ov6650(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov6650, subdev);
+}
+
+/* Start/Stop streaming from the device */
+static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+/* Get status of additional camera capabilities */
+static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
+ struct v4l2_subdev *sd = &priv->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ uint8_t reg, reg2;
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ ret = ov6650_reg_read(client, REG_GAIN, &reg);
+ if (!ret)
+ priv->gain->val = reg;
+ return ret;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = ov6650_reg_read(client, REG_BLUE, &reg);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_RED, &reg2);
+ if (!ret) {
+ priv->blue->val = reg;
+ priv->red->val = reg2;
+ }
+ return ret;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = ov6650_reg_read(client, REG_AECH, &reg);
+ if (!ret)
+ priv->exposure->val = reg;
+ return ret;
+ }
+ return -EINVAL;
+}
+
+/* Set status of additional camera capabilities */
+static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
+ struct v4l2_subdev *sd = &priv->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->val ? COMB_AGC : 0, COMB_AGC);
+ if (!ret && !ctrl->val)
+ ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val);
+ return ret;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->val ? COMB_AWB : 0, COMB_AWB);
+ if (!ret && !ctrl->val) {
+ ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val);
+ if (!ret)
+ ret = ov6650_reg_write(client, REG_RED,
+ priv->red->val);
+ }
+ return ret;
+ case V4L2_CID_SATURATION:
+ return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val),
+ SAT_MASK);
+ case V4L2_CID_HUE:
+ return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val),
+ HUE_MASK);
+ case V4L2_CID_BRIGHTNESS:
+ return ov6650_reg_write(client, REG_BRT, ctrl->val);
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val ==
+ V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC);
+ if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL)
+ ret = ov6650_reg_write(client, REG_AECH,
+ priv->exposure->val);
+ return ret;
+ case V4L2_CID_GAMMA:
+ return ov6650_reg_write(client, REG_GAM1, ctrl->val);
+ case V4L2_CID_VFLIP:
+ return ov6650_reg_rmw(client, REG_COMB,
+ ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V);
+ case V4L2_CID_HFLIP:
+ return ov6650_reg_rmw(client, REG_COMB,
+ ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H);
+ }
+
+ return -EINVAL;
+}
+
+/* Get chip identification */
+static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ id->ident = V4L2_IDENT_OV6650;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov6650_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xff)
+ return -EINVAL;
+
+ reg->size = 1;
+
+ ret = ov6650_reg_read(client, reg->reg, &val);
+ if (!ret)
+ reg->val = (__u64)val;
+
+ return ret;
+}
+
+static int ov6650_set_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return ov6650_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov6650_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->c = priv->rect;
+
+ return 0;
+}
+
+static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ struct v4l2_rect *rect = &a->c;
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ rect->left = ALIGN(rect->left, 2);
+ rect->width = ALIGN(rect->width, 2);
+ rect->top = ALIGN(rect->top, 2);
+ rect->height = ALIGN(rect->height, 2);
+ soc_camera_limit_side(&rect->left, &rect->width,
+ DEF_HSTRT << 1, 2, W_CIF);
+ soc_camera_limit_side(&rect->top, &rect->height,
+ DEF_VSTRT << 1, 2, H_CIF);
+
+ ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1);
+ if (!ret) {
+ priv->rect.left = rect->left;
+ ret = ov6650_reg_write(client, REG_HSTOP,
+ (rect->left + rect->width) >> 1);
+ }
+ if (!ret) {
+ priv->rect.width = rect->width;
+ ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1);
+ }
+ if (!ret) {
+ priv->rect.top = rect->top;
+ ret = ov6650_reg_write(client, REG_VSTOP,
+ (rect->top + rect->height) >> 1);
+ }
+ if (!ret)
+ priv->rect.height = rect->height;
+
+ return ret;
+}
+
+static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->bounds.left = DEF_HSTRT << 1;
+ a->bounds.top = DEF_VSTRT << 1;
+ a->bounds.width = W_CIF;
+ a->bounds.height = H_CIF;
+ a->defrect = a->bounds;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov6650_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ mf->width = priv->rect.width >> priv->half_scale;
+ mf->height = priv->rect.height >> priv->half_scale;
+ mf->code = priv->code;
+ mf->colorspace = priv->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
+{
+ return width > rect->width >> 1 || height > rect->height >> 1;
+}
+
+static u8 to_clkrc(struct v4l2_fract *timeperframe,
+ unsigned long pclk_limit, unsigned long pclk_max)
+{
+ unsigned long pclk;
+
+ if (timeperframe->numerator && timeperframe->denominator)
+ pclk = pclk_max * timeperframe->denominator /
+ (FRAME_RATE_MAX * timeperframe->numerator);
+ else
+ pclk = pclk_max;
+
+ if (pclk_limit && pclk_limit < pclk)
+ pclk = pclk_limit;
+
+ return (pclk_max - 1) / pclk;
+}
+
+/* set the format we will capture in */
+static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
+ struct soc_camera_sense *sense = icd->sense;
+ struct ov6650 *priv = to_ov6650(client);
+ bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
+ struct v4l2_crop a = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .c = {
+ .left = priv->rect.left + (priv->rect.width >> 1) -
+ (mf->width >> (1 - half_scale)),
+ .top = priv->rect.top + (priv->rect.height >> 1) -
+ (mf->height >> (1 - half_scale)),
+ .width = mf->width << half_scale,
+ .height = mf->height << half_scale,
+ },
+ };
+ enum v4l2_mbus_pixelcode code = mf->code;
+ unsigned long mclk, pclk;
+ u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
+ int ret;
+
+ /* select color matrix configuration for given color encoding */
+ switch (code) {
+ case V4L2_MBUS_FMT_Y8_1X8:
+ dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+ coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+ coma_set |= COMA_BW;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
+ coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
+ coma_set |= COMA_WORD_SWAP;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
+ COMA_BYTE_SWAP;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
+ if (half_scale) {
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+ coma_set |= COMA_BYTE_SWAP;
+ } else {
+ coma_mask |= COMA_RGB | COMA_BW;
+ coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ }
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
+ if (half_scale) {
+ coma_mask |= COMA_RGB | COMA_BW;
+ coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ } else {
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+ coma_set |= COMA_BYTE_SWAP;
+ }
+ break;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
+ coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ coma_set |= COMA_RAW_RGB | COMA_RGB;
+ break;
+ default:
+ dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
+ return -EINVAL;
+ }
+ priv->code = code;
+
+ if (code == V4L2_MBUS_FMT_Y8_1X8 ||
+ code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+ coml_mask = COML_ONE_CHANNEL;
+ coml_set = 0;
+ priv->pclk_max = 4000000;
+ } else {
+ coml_mask = 0;
+ coml_set = COML_ONE_CHANNEL;
+ priv->pclk_max = 8000000;
+ }
+
+ if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ priv->colorspace = V4L2_COLORSPACE_SRGB;
+ else if (code != 0)
+ priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+ if (half_scale) {
+ dev_dbg(&client->dev, "max resolution: QCIF\n");
+ coma_set |= COMA_QCIF;
+ priv->pclk_max /= 2;
+ } else {
+ dev_dbg(&client->dev, "max resolution: CIF\n");
+ coma_mask |= COMA_QCIF;
+ }
+ priv->half_scale = half_scale;
+
+ if (sense) {
+ if (sense->master_clock == 8000000) {
+ dev_dbg(&client->dev, "8MHz input clock\n");
+ clkrc = CLKRC_6MHz;
+ } else if (sense->master_clock == 12000000) {
+ dev_dbg(&client->dev, "12MHz input clock\n");
+ clkrc = CLKRC_12MHz;
+ } else if (sense->master_clock == 16000000) {
+ dev_dbg(&client->dev, "16MHz input clock\n");
+ clkrc = CLKRC_16MHz;
+ } else if (sense->master_clock == 24000000) {
+ dev_dbg(&client->dev, "24MHz input clock\n");
+ clkrc = CLKRC_24MHz;
+ } else {
+ dev_err(&client->dev,
+ "unsupported input clock, check platform data\n");
+ return -EINVAL;
+ }
+ mclk = sense->master_clock;
+ priv->pclk_limit = sense->pixel_clock_max;
+ } else {
+ clkrc = CLKRC_24MHz;
+ mclk = 24000000;
+ priv->pclk_limit = 0;
+ dev_dbg(&client->dev, "using default 24MHz input clock\n");
+ }
+
+ clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+ pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
+ dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
+ mclk / pclk, 10 * mclk % pclk / pclk);
+
+ ret = ov6650_s_crop(sd, &a);
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+ if (!ret)
+ ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+
+ if (!ret) {
+ mf->colorspace = priv->colorspace;
+ mf->width = priv->rect.width >> half_scale;
+ mf->height = priv->rect.height >> half_scale;
+ }
+
+ return ret;
+}
+
+static int ov6650_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
+ v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
+ &mf->height, 2, H_CIF, 1, 0);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_Y10_1X10:
+ mf->code = V4L2_MBUS_FMT_Y8_1X8;
+ case V4L2_MBUS_FMT_Y8_1X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ return 0;
+}
+
+static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov6650_codes))
+ return -EINVAL;
+
+ *code = ov6650_codes[index];
+ return 0;
+}
+
+static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ 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 = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
+ priv->pclk_limit, priv->pclk_max));
+ cp->timeperframe.denominator = FRAME_RATE_MAX;
+
+ dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
+ cp->timeperframe.numerator, cp->timeperframe.denominator);
+
+ return 0;
+}
+
+static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ int div, ret;
+ u8 clkrc;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (cp->extendedmode != 0)
+ return -EINVAL;
+
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ div = 1; /* Reset to full rate */
+ else
+ div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator;
+
+ if (div == 0)
+ div = 1;
+ else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
+ div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
+
+ /*
+ * Keep result to be used as tpf limit
+ * for subseqent clock divider calculations
+ */
+ priv->tpf.numerator = div;
+ priv->tpf.denominator = FRAME_RATE_MAX;
+
+ clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+ ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
+ if (!ret) {
+ tpf->numerator = GET_CLKRC_DIV(clkrc);
+ tpf->denominator = FRAME_RATE_MAX;
+ }
+
+ return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov6650_reset(struct i2c_client *client)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "reset\n");
+
+ ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
+ if (ret)
+ dev_err(&client->dev,
+ "An error occurred while entering soft reset!\n");
+
+ return ret;
+}
+
+/* program default register values */
+static int ov6650_prog_dflt(struct i2c_client *client)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "initializing\n");
+
+ ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
+
+ return ret;
+}
+
+static int ov6650_video_probe(struct i2c_client *client)
+{
+ struct ov6650 *priv = to_ov6650(client);
+ u8 pidh, pidl, midh, midl;
+ int ret;
+
+ ret = ov6650_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ ret = ov6650_reg_read(client, REG_PIDH, &pidh);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_PIDL, &pidl);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_MIDH, &midh);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_MIDL, &midl);
+
+ if (ret)
+ goto done;
+
+ if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) {
+ dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n",
+ pidh, pidl);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev,
+ "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n",
+ pidh, pidl, midh, midl);
+
+ ret = ov6650_reset(client);
+ if (!ret)
+ ret = ov6650_prog_dflt(client);
+ if (!ret)
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov6650_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
+ .g_volatile_ctrl = ov6550_g_volatile_ctrl,
+ .s_ctrl = ov6550_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov6650_core_ops = {
+ .g_chip_ident = ov6650_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov6650_get_register,
+ .s_register = ov6650_set_register,
+#endif
+ .s_power = ov6650_s_power,
+};
+
+/* Request bus settings on camera side */
+static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_MASTER |
+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+/* Alter bus settings on camera side */
+static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+ int ret;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
+ if (ret)
+ return ret;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
+ if (ret)
+ return ret;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+
+ return ret;
+}
+
+static struct v4l2_subdev_video_ops ov6650_video_ops = {
+ .s_stream = ov6650_s_stream,
+ .g_mbus_fmt = ov6650_g_fmt,
+ .s_mbus_fmt = ov6650_s_fmt,
+ .try_mbus_fmt = ov6650_try_fmt,
+ .enum_mbus_fmt = ov6650_enum_fmt,
+ .cropcap = ov6650_cropcap,
+ .g_crop = ov6650_g_crop,
+ .s_crop = ov6650_s_crop,
+ .g_parm = ov6650_g_parm,
+ .s_parm = ov6650_s_parm,
+ .g_mbus_config = ov6650_g_mbus_config,
+ .s_mbus_config = ov6650_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov6650_subdev_ops = {
+ .core = &ov6650_core_ops,
+ .video = &ov6650_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov6650 *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->hdl, 13);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN);
+ priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE);
+ priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 0xf, 1, 0x8);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80);
+ priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl,
+ &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+ V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+ priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH);
+ v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
+
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error) {
+ int err = priv->hdl.error;
+
+ kfree(priv);
+ return err;
+ }
+ v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
+ v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
+ v4l2_ctrl_auto_cluster(2, &priv->autoexposure,
+ V4L2_EXPOSURE_MANUAL, true);
+
+ priv->rect.left = DEF_HSTRT << 1;
+ priv->rect.top = DEF_VSTRT << 1;
+ priv->rect.width = W_CIF;
+ priv->rect.height = H_CIF;
+ priv->half_scale = false;
+ priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+ ret = ov6650_video_probe(client);
+ if (ret) {
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int ov6650_remove(struct i2c_client *client)
+{
+ struct ov6650 *priv = to_ov6650(client);
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov6650_id[] = {
+ { "ov6650", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov6650_id);
+
+static struct i2c_driver ov6650_i2c_driver = {
+ .driver = {
+ .name = "ov6650",
+ },
+ .probe = ov6650_probe,
+ .remove = ov6650_remove,
+ .id_table = ov6650_id,
+};
+
+module_i2c_driver(ov6650_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
new file mode 100644
index 000000000000..e4a10751894d
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -0,0 +1,1137 @@
+/*
+ * ov772x Camera Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/ov772x.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/*
+ * register offset
+ */
+#define GAIN 0x00 /* AGC - Gain control gain setting */
+#define BLUE 0x01 /* AWB - Blue channel gain setting */
+#define RED 0x02 /* AWB - Red channel gain setting */
+#define GREEN 0x03 /* AWB - Green channel gain setting */
+#define COM1 0x04 /* Common control 1 */
+#define BAVG 0x05 /* U/B Average Level */
+#define GAVG 0x06 /* Y/Gb Average Level */
+#define RAVG 0x07 /* V/R Average Level */
+#define AECH 0x08 /* Exposure Value - AEC MSBs */
+#define COM2 0x09 /* Common control 2 */
+#define PID 0x0A /* Product ID Number MSB */
+#define VER 0x0B /* Product ID Number LSB */
+#define COM3 0x0C /* Common control 3 */
+#define COM4 0x0D /* Common control 4 */
+#define COM5 0x0E /* Common control 5 */
+#define COM6 0x0F /* Common control 6 */
+#define AEC 0x10 /* Exposure Value */
+#define CLKRC 0x11 /* Internal clock */
+#define COM7 0x12 /* Common control 7 */
+#define COM8 0x13 /* Common control 8 */
+#define COM9 0x14 /* Common control 9 */
+#define COM10 0x15 /* Common control 10 */
+#define REG16 0x16 /* Register 16 */
+#define HSTART 0x17 /* Horizontal sensor size */
+#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */
+#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */
+#define VSIZE 0x1A /* Vertical sensor size */
+#define PSHFT 0x1B /* Data format - pixel delay select */
+#define MIDH 0x1C /* Manufacturer ID byte - high */
+#define MIDL 0x1D /* Manufacturer ID byte - low */
+#define LAEC 0x1F /* Fine AEC value */
+#define COM11 0x20 /* Common control 11 */
+#define BDBASE 0x22 /* Banding filter Minimum AEC value */
+#define DBSTEP 0x23 /* Banding filter Maximum Setp */
+#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VPT 0x26 /* AGC/AEC Fast mode operating region */
+#define REG28 0x28 /* Register 28 */
+#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */
+#define EXHCH 0x2A /* Dummy pixel insert MSB */
+#define EXHCL 0x2B /* Dummy pixel insert LSB */
+#define VOUTSIZE 0x2C /* Vertical data output size MSBs */
+#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */
+#define YAVE 0x2F /* Y/G Channel Average value */
+#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */
+#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */
+#define HREF 0x32 /* Image start and size control */
+#define DM_LNL 0x33 /* Dummy line low 8 bits */
+#define DM_LNH 0x34 /* Dummy line high 8 bits */
+#define ADOFF_B 0x35 /* AD offset compensation value for B channel */
+#define ADOFF_R 0x36 /* AD offset compensation value for R channel */
+#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */
+#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */
+#define OFF_B 0x39 /* Analog process B channel offset value */
+#define OFF_R 0x3A /* Analog process R channel offset value */
+#define OFF_GB 0x3B /* Analog process Gb channel offset value */
+#define OFF_GR 0x3C /* Analog process Gr channel offset value */
+#define COM12 0x3D /* Common control 12 */
+#define COM13 0x3E /* Common control 13 */
+#define COM14 0x3F /* Common control 14 */
+#define COM15 0x40 /* Common control 15*/
+#define COM16 0x41 /* Common control 16 */
+#define TGT_B 0x42 /* BLC blue channel target value */
+#define TGT_R 0x43 /* BLC red channel target value */
+#define TGT_GB 0x44 /* BLC Gb channel target value */
+#define TGT_GR 0x45 /* BLC Gr channel target value */
+/* for ov7720 */
+#define LCC0 0x46 /* Lens correction control 0 */
+#define LCC1 0x47 /* Lens correction option 1 - X coordinate */
+#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */
+#define LCC3 0x49 /* Lens correction option 3 */
+#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */
+#define LCC5 0x4B /* Lens correction option 5 */
+#define LCC6 0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR 0x46 /* Lens correction control */
+#define LC_XC 0x47 /* X coordinate of lens correction center relative */
+#define LC_YC 0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF 0x49 /* Lens correction coefficient */
+#define LC_RADI 0x4A /* Lens correction radius */
+#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */
+
+#define FIXGAIN 0x4D /* Analog fix gain amplifer */
+#define AREF0 0x4E /* Sensor reference control */
+#define AREF1 0x4F /* Sensor reference current control */
+#define AREF2 0x50 /* Analog reference control */
+#define AREF3 0x51 /* ADC reference control */
+#define AREF4 0x52 /* ADC reference control */
+#define AREF5 0x53 /* ADC reference control */
+#define AREF6 0x54 /* Analog reference control */
+#define AREF7 0x55 /* Analog reference control */
+#define UFIX 0x60 /* U channel fixed value output */
+#define VFIX 0x61 /* V channel fixed value output */
+#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0 0x63 /* AWB control byte 0 */
+#define DSP_CTRL1 0x64 /* DSP control byte 1 */
+#define DSP_CTRL2 0x65 /* DSP control byte 2 */
+#define DSP_CTRL3 0x66 /* DSP control byte 3 */
+#define DSP_CTRL4 0x67 /* DSP control byte 4 */
+#define AWB_BIAS 0x68 /* AWB BLC level clip */
+#define AWB_CTRL1 0x69 /* AWB control 1 */
+#define AWB_CTRL2 0x6A /* AWB control 2 */
+#define AWB_CTRL3 0x6B /* AWB control 3 */
+#define AWB_CTRL4 0x6C /* AWB control 4 */
+#define AWB_CTRL5 0x6D /* AWB control 5 */
+#define AWB_CTRL6 0x6E /* AWB control 6 */
+#define AWB_CTRL7 0x6F /* AWB control 7 */
+#define AWB_CTRL8 0x70 /* AWB control 8 */
+#define AWB_CTRL9 0x71 /* AWB control 9 */
+#define AWB_CTRL10 0x72 /* AWB control 10 */
+#define AWB_CTRL11 0x73 /* AWB control 11 */
+#define AWB_CTRL12 0x74 /* AWB control 12 */
+#define AWB_CTRL13 0x75 /* AWB control 13 */
+#define AWB_CTRL14 0x76 /* AWB control 14 */
+#define AWB_CTRL15 0x77 /* AWB control 15 */
+#define AWB_CTRL16 0x78 /* AWB control 16 */
+#define AWB_CTRL17 0x79 /* AWB control 17 */
+#define AWB_CTRL18 0x7A /* AWB control 18 */
+#define AWB_CTRL19 0x7B /* AWB control 19 */
+#define AWB_CTRL20 0x7C /* AWB control 20 */
+#define AWB_CTRL21 0x7D /* AWB control 21 */
+#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
+#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
+#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
+#define GAM4 0x81 /* Gamma Curve 4th segment input end point */
+#define GAM5 0x82 /* Gamma Curve 5th segment input end point */
+#define GAM6 0x83 /* Gamma Curve 6th segment input end point */
+#define GAM7 0x84 /* Gamma Curve 7th segment input end point */
+#define GAM8 0x85 /* Gamma Curve 8th segment input end point */
+#define GAM9 0x86 /* Gamma Curve 9th segment input end point */
+#define GAM10 0x87 /* Gamma Curve 10th segment input end point */
+#define GAM11 0x88 /* Gamma Curve 11th segment input end point */
+#define GAM12 0x89 /* Gamma Curve 12th segment input end point */
+#define GAM13 0x8A /* Gamma Curve 13th segment input end point */
+#define GAM14 0x8B /* Gamma Curve 14th segment input end point */
+#define GAM15 0x8C /* Gamma Curve 15th segment input end point */
+#define SLOP 0x8D /* Gamma curve highest segment slope */
+#define DNSTH 0x8E /* De-noise threshold */
+#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */
+#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
+#define DNSOFF 0x91 /* Auto De-noise threshold control */
+#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */
+#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */
+#define MTX1 0x94 /* Matrix coefficient 1 */
+#define MTX2 0x95 /* Matrix coefficient 2 */
+#define MTX3 0x96 /* Matrix coefficient 3 */
+#define MTX4 0x97 /* Matrix coefficient 4 */
+#define MTX5 0x98 /* Matrix coefficient 5 */
+#define MTX6 0x99 /* Matrix coefficient 6 */
+#define MTX_CTRL 0x9A /* Matrix control */
+#define BRIGHT 0x9B /* Brightness control */
+#define CNTRST 0x9C /* Contrast contrast */
+#define CNTRST_CTRL 0x9D /* Contrast contrast center */
+#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */
+#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */
+#define SCAL0 0xA0 /* Scaling control 0 */
+#define SCAL1 0xA1 /* Scaling control 1 */
+#define SCAL2 0xA2 /* Scaling control 2 */
+#define FIFODLYM 0xA3 /* FIFO manual mode delay control */
+#define FIFODLYA 0xA4 /* FIFO auto mode delay control */
+#define SDE 0xA6 /* Special digital effect control */
+#define USAT 0xA7 /* U component saturation control */
+#define VSAT 0xA8 /* V component saturation control */
+/* for ov7720 */
+#define HUE0 0xA9 /* Hue control 0 */
+#define HUE1 0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS 0xA9 /* Cosine value */
+#define HUESIN 0xAA /* Sine value */
+
+#define SIGN 0xAB /* Sign bit for Hue and contrast */
+#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */
+
+/*
+ * register detail
+ */
+
+/* COM2 */
+#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
+ /* Output drive capability */
+#define OCAP_1x 0x00 /* 1x */
+#define OCAP_2x 0x01 /* 2x */
+#define OCAP_3x 0x02 /* 3x */
+#define OCAP_4x 0x03 /* 4x */
+
+/* COM3 */
+#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
+
+#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
+#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */
+#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */
+#define SWAP_ML 0x08 /* Swap output MSB/LSB */
+ /* Tri-state option for output clock */
+#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */
+ /* 1: No tri-state at this period */
+ /* Tri-state option for output data */
+#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */
+ /* 1: No tri-state at this period */
+#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */
+
+/* COM4 */
+ /* PLL frequency control */
+#define PLL_BYPASS 0x00 /* 00: Bypass PLL */
+#define PLL_4x 0x40 /* 01: PLL 4x */
+#define PLL_6x 0x80 /* 10: PLL 6x */
+#define PLL_8x 0xc0 /* 11: PLL 8x */
+ /* AEC evaluate window */
+#define AEC_FULL 0x00 /* 00: Full window */
+#define AEC_1p2 0x10 /* 01: 1/2 window */
+#define AEC_1p4 0x20 /* 10: 1/4 window */
+#define AEC_2p3 0x30 /* 11: Low 2/3 window */
+
+/* COM5 */
+#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */
+#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */
+ /* Auto frame rate max rate control */
+#define AFR_NO_RATE 0x00 /* No reduction of frame rate */
+#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */
+#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */
+#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */
+ /* Auto frame rate active point control */
+#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */
+#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */
+#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */
+#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */
+ /* AEC max step control */
+#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */
+ /* 1 : No limit to AEC increase step */
+
+/* COM7 */
+ /* SCCB Register Reset */
+#define SCCB_RESET 0x80 /* 0 : No change */
+ /* 1 : Resets all registers to default */
+ /* Resolution selection */
+#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */
+#define SLCT_VGA 0x00 /* 0 : VGA */
+#define SLCT_QVGA 0x40 /* 1 : QVGA */
+#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */
+#define SENSOR_RAW 0x10 /* Sensor RAW */
+ /* RGB output format control */
+#define FMT_MASK 0x0c /* Mask of color format */
+#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */
+#define FMT_RGB565 0x04 /* 01 : RGB 565 */
+#define FMT_RGB555 0x08 /* 10 : RGB 555 */
+#define FMT_RGB444 0x0c /* 11 : RGB 444 */
+ /* Output format control */
+#define OFMT_MASK 0x03 /* Mask of output format */
+#define OFMT_YUV 0x00 /* 00 : YUV */
+#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */
+#define OFMT_RGB 0x02 /* 10 : RGB */
+#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */
+
+/* COM8 */
+#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */
+ /* AEC Setp size limit */
+#define UNLMT_STEP 0x40 /* 0 : Step size is limited */
+ /* 1 : Unlimited step size */
+#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */
+#define AEC_BND 0x10 /* Enable AEC below banding value */
+#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */
+#define AGC_ON 0x04 /* AGC Enable */
+#define AWB_ON 0x02 /* AWB Enable */
+#define AEC_ON 0x01 /* AEC Enable */
+
+/* COM9 */
+#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */
+ /* Automatic gain ceiling - maximum AGC value */
+#define GAIN_2x 0x00 /* 000 : 2x */
+#define GAIN_4x 0x10 /* 001 : 4x */
+#define GAIN_8x 0x20 /* 010 : 8x */
+#define GAIN_16x 0x30 /* 011 : 16x */
+#define GAIN_32x 0x40 /* 100 : 32x */
+#define GAIN_64x 0x50 /* 101 : 64x */
+#define GAIN_128x 0x60 /* 110 : 128x */
+#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */
+#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */
+
+/* COM11 */
+#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */
+#define SGLF_TRIG 0x01 /* Single frame transfer trigger */
+
+/* HREF */
+#define HREF_VSTART_SHIFT 6 /* VSTART LSB */
+#define HREF_HSTART_SHIFT 4 /* HSTART 2 LSBs */
+#define HREF_VSIZE_SHIFT 2 /* VSIZE LSB */
+#define HREF_HSIZE_SHIFT 0 /* HSIZE 2 LSBs */
+
+/* EXHCH */
+#define EXHCH_VSIZE_SHIFT 2 /* VOUTSIZE LSB */
+#define EXHCH_HSIZE_SHIFT 0 /* HOUTSIZE 2 LSBs */
+
+/* DSP_CTRL1 */
+#define FIFO_ON 0x80 /* FIFO enable/disable selection */
+#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */
+#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */
+#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */
+#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */
+#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */
+#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */
+#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */
+
+/* DSP_CTRL3 */
+#define UV_MASK 0x80 /* UV output sequence option */
+#define UV_ON 0x80 /* ON */
+#define UV_OFF 0x00 /* OFF */
+#define CBAR_MASK 0x20 /* DSP Color bar mask */
+#define CBAR_ON 0x20 /* ON */
+#define CBAR_OFF 0x00 /* OFF */
+
+/* DSP_CTRL4 */
+#define DSP_OFMT_YUV 0x00
+#define DSP_OFMT_RGB 0x00
+#define DSP_OFMT_RAW8 0x02
+#define DSP_OFMT_RAW10 0x03
+
+/* DSPAUTO (DSP Auto Function ON/OFF Control) */
+#define AWB_ACTRL 0x80 /* AWB auto threshold control */
+#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */
+#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */
+#define UV_ACTRL 0x10 /* UV adjust auto slope control */
+#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */
+#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QVGA_WIDTH 320
+#define QVGA_HEIGHT 240
+#define OV772X_MAX_WIDTH VGA_WIDTH
+#define OV772X_MAX_HEIGHT VGA_HEIGHT
+
+/*
+ * ID
+ */
+#define OV7720 0x7720
+#define OV7725 0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
+ * struct
+ */
+
+struct ov772x_color_format {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+ u8 dsp3;
+ u8 dsp4;
+ u8 com3;
+ u8 com7;
+};
+
+struct ov772x_win_size {
+ char *name;
+ unsigned char com7_bit;
+ struct v4l2_rect rect;
+};
+
+struct ov772x_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct ov772x_camera_info *info;
+ const struct ov772x_color_format *cfmt;
+ const struct ov772x_win_size *win;
+ int model;
+ unsigned short flag_vflip:1;
+ unsigned short flag_hflip:1;
+ /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+ unsigned short band_filter;
+};
+
+/*
+ * supported color format list
+ */
+static const struct ov772x_color_format ov772x_cfmts[] = {
+ {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .dsp3 = UV_ON,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ {
+ /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output,
+ * regardless of the COM7 value. We can thus only support 10-bit
+ * Bayer until someone figures it out.
+ */
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_RAW10,
+ .com3 = 0x0,
+ .com7 = SENSOR_RAW | OFMT_BRAW,
+ },
+};
+
+
+/*
+ * window size list
+ */
+
+static const struct ov772x_win_size ov772x_win_sizes[] = {
+ {
+ .name = "VGA",
+ .com7_bit = SLCT_VGA,
+ .rect = {
+ .left = 140,
+ .top = 14,
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ },
+ }, {
+ .name = "QVGA",
+ .com7_bit = SLCT_QVGA,
+ .rect = {
+ .left = 252,
+ .top = 6,
+ .width = QVGA_WIDTH,
+ .height = QVGA_HEIGHT,
+ },
+ },
+};
+
+/*
+ * general function
+ */
+
+static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov772x_priv, subdev);
+}
+
+static inline int ov772x_read(struct i2c_client *client, u8 addr)
+{
+ return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask,
+ u8 set)
+{
+ s32 val = ov772x_read(client, command);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return ov772x_write(client, command, val);
+}
+
+static int ov772x_reset(struct i2c_client *client)
+{
+ int ret;
+
+ ret = ov772x_write(client, COM7, SCCB_RESET);
+ if (ret < 0)
+ return ret;
+
+ msleep(1);
+
+ return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+}
+
+/*
+ * soc_camera_ops function
+ */
+
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ if (!enable) {
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return 0;
+ }
+
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
+
+ dev_dbg(&client->dev, "format %d, win %s\n",
+ priv->cfmt->code, priv->win->name);
+
+ return 0;
+}
+
+static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov772x_priv *priv = container_of(ctrl->handler,
+ struct ov772x_priv, hdl);
+ struct v4l2_subdev *sd = &priv->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->val ? VFLIP_IMG : 0x00;
+ priv->flag_vflip = ctrl->val;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val ^= VFLIP_IMG;
+ return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
+ case V4L2_CID_HFLIP:
+ val = ctrl->val ? HFLIP_IMG : 0x00;
+ priv->flag_hflip = ctrl->val;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val ^= HFLIP_IMG;
+ return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+ case V4L2_CID_BAND_STOP_FILTER:
+ if (!ctrl->val) {
+ /* Switch the filter off, it is on now */
+ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+ if (!ret)
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, 0);
+ } else {
+ /* Switch the filter on, set AEC low limit */
+ val = 256 - ctrl->val;
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, val);
+ }
+ if (!ret)
+ priv->band_filter = ctrl->val;
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ id->ident = priv->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov772x_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 1;
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = ov772x_read(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int ov772x_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return ov772x_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov772x_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
+{
+ const struct ov772x_win_size *win = &ov772x_win_sizes[0];
+ u32 best_diff = UINT_MAX;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
+ u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
+ + abs(height - ov772x_win_sizes[i].rect.height);
+ if (diff < best_diff) {
+ best_diff = diff;
+ win = &ov772x_win_sizes[i];
+ }
+ }
+
+ return win;
+}
+
+static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
+ const struct ov772x_color_format **cfmt,
+ const struct ov772x_win_size **win)
+{
+ unsigned int i;
+
+ /* Select a format. */
+ *cfmt = &ov772x_cfmts[0];
+
+ for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+ if (mf->code == ov772x_cfmts[i].code) {
+ *cfmt = &ov772x_cfmts[i];
+ break;
+ }
+ }
+
+ /* Select a window size. */
+ *win = ov772x_select_win(mf->width, mf->height);
+}
+
+static int ov772x_set_params(struct ov772x_priv *priv,
+ const struct ov772x_color_format *cfmt,
+ const struct ov772x_win_size *win)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ int ret;
+ u8 val;
+
+ /*
+ * reset hardware
+ */
+ ov772x_reset(client);
+
+ /*
+ * Edge Ctrl
+ */
+ if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
+
+ /*
+ * Manual Edge Control Mode
+ *
+ * Edge auto strength bit is set by default.
+ * Remove it when manual mode.
+ */
+
+ ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
+ priv->info->edgectrl.threshold);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
+ priv->info->edgectrl.strength);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
+ /*
+ * Auto Edge Control Mode
+ *
+ * set upper and lower limit
+ */
+ ret = ov772x_mask_set(client,
+ EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
+ priv->info->edgectrl.upper);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
+ priv->info->edgectrl.lower);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /* Format and window size */
+ ret = ov772x_write(client, HSTART, win->rect.left >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VSTART, win->rect.top >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HREF,
+ ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
+ ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
+ ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
+ ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, EXHCH,
+ ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
+ ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /*
+ * set DSP_CTRL3
+ */
+ val = cfmt->dsp3;
+ if (val) {
+ ret = ov772x_mask_set(client,
+ DSP_CTRL3, UV_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /* DSP_CTRL4: AEC reference point and DSP output format. */
+ if (cfmt->dsp4) {
+ ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /*
+ * set COM3
+ */
+ val = cfmt->com3;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val |= VFLIP_IMG;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val |= HFLIP_IMG;
+ if (priv->flag_vflip)
+ val ^= VFLIP_IMG;
+ if (priv->flag_hflip)
+ val ^= HFLIP_IMG;
+
+ ret = ov772x_mask_set(client,
+ COM3, SWAP_MASK | IMG_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /* COM7: Sensor resolution and output format control. */
+ ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /*
+ * set COM8
+ */
+ if (priv->band_filter) {
+ ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, 256 - priv->band_filter);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ return ret;
+
+ov772x_set_fmt_error:
+
+ ov772x_reset(client);
+
+ return ret;
+}
+
+static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = VGA_WIDTH;
+ a->c.height = VGA_HEIGHT;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = OV772X_MAX_WIDTH;
+ a->bounds.height = OV772X_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov772x_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ mf->width = priv->win->rect.width;
+ mf->height = priv->win->rect.height;
+ mf->code = priv->cfmt->code;
+ mf->colorspace = priv->cfmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+ const struct ov772x_color_format *cfmt;
+ const struct ov772x_win_size *win;
+ int ret;
+
+ ov772x_select_params(mf, &cfmt, &win);
+
+ ret = ov772x_set_params(priv, cfmt, win);
+ if (ret < 0)
+ return ret;
+
+ priv->win = win;
+ priv->cfmt = cfmt;
+
+ mf->code = cfmt->code;
+ mf->width = win->rect.width;
+ mf->height = win->rect.height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = cfmt->colorspace;
+
+ return 0;
+}
+
+static int ov772x_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct ov772x_color_format *cfmt;
+ const struct ov772x_win_size *win;
+
+ ov772x_select_params(mf, &cfmt, &win);
+
+ mf->code = cfmt->code;
+ mf->width = win->rect.width;
+ mf->height = win->rect.height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = cfmt->colorspace;
+
+ return 0;
+}
+
+static int ov772x_video_probe(struct ov772x_priv *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ u8 pid, ver;
+ const char *devname;
+ int ret;
+
+ ret = ov772x_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ pid = ov772x_read(client, PID);
+ ver = ov772x_read(client, VER);
+
+ switch (VERSION(pid, ver)) {
+ case OV7720:
+ devname = "ov7720";
+ priv->model = V4L2_IDENT_OV7720;
+ break;
+ case OV7725:
+ devname = "ov7725";
+ priv->model = V4L2_IDENT_OV7725;
+ break;
+ default:
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev,
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname,
+ pid,
+ ver,
+ ov772x_read(client, MIDH),
+ ov772x_read(client, MIDL));
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov772x_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
+ .s_ctrl = ov772x_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+ .g_chip_ident = ov772x_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov772x_g_register,
+ .s_register = ov772x_s_register,
+#endif
+ .s_power = ov772x_s_power,
+};
+
+static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov772x_cfmts))
+ return -EINVAL;
+
+ *code = ov772x_cfmts[index].code;
+ return 0;
+}
+
+static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+ .s_stream = ov772x_s_stream,
+ .g_mbus_fmt = ov772x_g_fmt,
+ .s_mbus_fmt = ov772x_s_fmt,
+ .try_mbus_fmt = ov772x_try_fmt,
+ .cropcap = ov772x_cropcap,
+ .g_crop = ov772x_g_crop,
+ .enum_mbus_fmt = ov772x_enum_fmt,
+ .g_mbus_config = ov772x_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov772x_subdev_ops = {
+ .core = &ov772x_subdev_core_ops,
+ .video = &ov772x_subdev_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int ov772x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov772x_priv *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ int ret;
+
+ if (!icl || !icl->priv) {
+ dev_err(&client->dev, "OV772X: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&adapter->dev,
+ "I2C-Adapter doesn't support "
+ "I2C_FUNC_SMBUS_BYTE_DATA\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = icl->priv;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->hdl, 3);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error) {
+ ret = priv->hdl.error;
+ goto done;
+ }
+
+ ret = ov772x_video_probe(priv);
+ if (ret < 0)
+ goto done;
+
+ priv->cfmt = &ov772x_cfmts[0];
+ priv->win = &ov772x_win_sizes[0];
+
+done:
+ if (ret) {
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ }
+ return ret;
+}
+
+static int ov772x_remove(struct i2c_client *client)
+{
+ struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov772x_id[] = {
+ { "ov772x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov772x_id);
+
+static struct i2c_driver ov772x_i2c_driver = {
+ .driver = {
+ .name = "ov772x",
+ },
+ .probe = ov772x_probe,
+ .remove = ov772x_remove,
+ .id_table = ov772x_id,
+};
+
+module_i2c_driver(ov772x_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov772x");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
new file mode 100644
index 000000000000..b323684eaf77
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -0,0 +1,763 @@
+/*
+ * OmniVision OV96xx Camera Driver
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ov9640.h"
+
+#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev)
+
+/* default register setup */
+static const struct ov9640_reg ov9640_regs_dflt[] = {
+ { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
+ { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
+ OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
+ { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) },
+ { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
+ { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY },
+ { OV9640_COM16, OV9640_COM16_RB_AVG },
+
+ /* Gamma curve P */
+ { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 },
+ { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 },
+ { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 },
+ { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 },
+
+ /* Gamma curve T */
+ { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 },
+ { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 },
+ { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e },
+ { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 },
+};
+
+/* Configurations
+ * NOTE: for YUV, alter the following registers:
+ * COM12 |= OV9640_COM12_YUV_AVG
+ *
+ * for RGB, alter the following registers:
+ * COM7 |= OV9640_COM7_RGB
+ * COM13 |= OV9640_COM13_RGB_AVG
+ * COM15 |= proper RGB color encoding mode
+ */
+static const struct ov9640_reg ov9640_regs_qqcif[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
+ { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+ { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+ { OV9640_COM7, OV9640_COM7_QCIF },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qqvga[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+ { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+ { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+ { OV9640_COM7, OV9640_COM7_QVGA },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qcif[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+ { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+ { OV9640_COM7, OV9640_COM7_QCIF },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qvga[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+ { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+ { OV9640_COM7, OV9640_COM7_QVGA },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_cif[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+ { OV9640_COM3, OV9640_COM3_VP },
+ { OV9640_COM7, OV9640_COM7_CIF },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_vga[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+ { OV9640_COM3, OV9640_COM3_VP },
+ { OV9640_COM7, OV9640_COM7_VGA },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_sxga[] = {
+ { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+ { OV9640_COM3, OV9640_COM3_VP },
+ { OV9640_COM7, 0 },
+ { OV9640_COM12, OV9640_COM12_RSVD },
+ { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+ { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_yuv[] = {
+ { OV9640_MTX1, 0x58 },
+ { OV9640_MTX2, 0x48 },
+ { OV9640_MTX3, 0x10 },
+ { OV9640_MTX4, 0x28 },
+ { OV9640_MTX5, 0x48 },
+ { OV9640_MTX6, 0x70 },
+ { OV9640_MTX7, 0x40 },
+ { OV9640_MTX8, 0x40 },
+ { OV9640_MTX9, 0x40 },
+ { OV9640_MTXS, 0x0f },
+};
+
+static const struct ov9640_reg ov9640_regs_rgb[] = {
+ { OV9640_MTX1, 0x71 },
+ { OV9640_MTX2, 0x3e },
+ { OV9640_MTX3, 0x0c },
+ { OV9640_MTX4, 0x33 },
+ { OV9640_MTX5, 0x72 },
+ { OV9640_MTX6, 0x00 },
+ { OV9640_MTX7, 0x2b },
+ { OV9640_MTX8, 0x66 },
+ { OV9640_MTX9, 0xd2 },
+ { OV9640_MTXS, 0x65 },
+};
+
+static enum v4l2_mbus_pixelcode ov9640_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/* read a register */
+static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int ret;
+ u8 data = reg;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ msg.flags = I2C_M_RD;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ *val = data;
+ return 0;
+
+err:
+ dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+ return ret;
+}
+
+/* write a register */
+static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ int ret;
+ u8 _val;
+ unsigned char data[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+ return ret;
+ }
+
+ /* we have to read the register back ... no idea why, maybe HW bug */
+ ret = ov9640_reg_read(client, reg, &_val);
+ if (ret)
+ dev_err(&client->dev,
+ "Failed reading back register 0x%02x!\n", reg);
+
+ return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
+{
+ u8 val;
+ int ret;
+
+ ret = ov9640_reg_read(client, reg, &val);
+ if (ret) {
+ dev_err(&client->dev,
+ "[Read]-Modify-Write of register %02x failed!\n", reg);
+ return val;
+ }
+
+ val |= set;
+ val &= ~unset;
+
+ ret = ov9640_reg_write(client, reg, val);
+ if (ret)
+ dev_err(&client->dev,
+ "Read-Modify-[Write] of register %02x failed!\n", reg);
+
+ return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov9640_reset(struct i2c_client *client)
+{
+ int ret;
+
+ ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
+ if (ret)
+ dev_err(&client->dev,
+ "An error occurred while entering soft reset!\n");
+
+ return ret;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl);
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ return ov9640_reg_rmw(client, OV9640_MVFP,
+ OV9640_MVFP_V, 0);
+ return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ return ov9640_reg_rmw(client, OV9640_MVFP,
+ OV9640_MVFP_H, 0);
+ return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
+ }
+ return -EINVAL;
+}
+
+/* Get chip identification */
+static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+ id->ident = priv->model;
+ id->revision = priv->revision;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9640_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xff)
+ return -EINVAL;
+
+ reg->size = 1;
+
+ ret = ov9640_reg_read(client, reg->reg, &val);
+ if (ret)
+ return ret;
+
+ reg->val = (__u64)val;
+
+ return 0;
+}
+
+static int ov9640_set_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return ov9640_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+/* select nearest higher resolution for capture */
+static void ov9640_res_roundup(u32 *width, u32 *height)
+{
+ int i;
+ enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+ int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
+ int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
+
+ for (i = 0; i < ARRAY_SIZE(res_x); i++) {
+ if (res_x[i] >= *width && res_y[i] >= *height) {
+ *width = res_x[i];
+ *height = res_y[i];
+ return;
+ }
+ }
+
+ *width = res_x[SXGA];
+ *height = res_y[SXGA];
+}
+
+/* Prepare necessary register changes depending on color encoding */
+static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
+ struct ov9640_reg_alt *alt)
+{
+ switch (code) {
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ alt->com12 = OV9640_COM12_YUV_AVG;
+ alt->com13 = OV9640_COM13_Y_DELAY_EN |
+ OV9640_COM13_YUV_DLY(0x01);
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ alt->com7 = OV9640_COM7_RGB;
+ alt->com13 = OV9640_COM13_RGB_AVG;
+ alt->com15 = OV9640_COM15_RGB_555;
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ alt->com7 = OV9640_COM7_RGB;
+ alt->com13 = OV9640_COM13_RGB_AVG;
+ alt->com15 = OV9640_COM15_RGB_565;
+ break;
+ };
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9640_write_regs(struct i2c_client *client, u32 width,
+ enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts)
+{
+ const struct ov9640_reg *ov9640_regs, *matrix_regs;
+ int ov9640_regs_len, matrix_regs_len;
+ int i, ret;
+ u8 val;
+
+ /* select register configuration for given resolution */
+ switch (width) {
+ case W_QQCIF:
+ ov9640_regs = ov9640_regs_qqcif;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif);
+ break;
+ case W_QQVGA:
+ ov9640_regs = ov9640_regs_qqvga;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga);
+ break;
+ case W_QCIF:
+ ov9640_regs = ov9640_regs_qcif;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif);
+ break;
+ case W_QVGA:
+ ov9640_regs = ov9640_regs_qvga;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga);
+ break;
+ case W_CIF:
+ ov9640_regs = ov9640_regs_cif;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif);
+ break;
+ case W_VGA:
+ ov9640_regs = ov9640_regs_vga;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga);
+ break;
+ case W_SXGA:
+ ov9640_regs = ov9640_regs_sxga;
+ ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga);
+ break;
+ default:
+ dev_err(&client->dev, "Failed to select resolution!\n");
+ return -EINVAL;
+ }
+
+ /* select color matrix configuration for given color encoding */
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ matrix_regs = ov9640_regs_yuv;
+ matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
+ } else {
+ matrix_regs = ov9640_regs_rgb;
+ matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
+ }
+
+ /* write register settings into the module */
+ for (i = 0; i < ov9640_regs_len; i++) {
+ val = ov9640_regs[i].val;
+
+ switch (ov9640_regs[i].reg) {
+ case OV9640_COM7:
+ val |= alts->com7;
+ break;
+ case OV9640_COM12:
+ val |= alts->com12;
+ break;
+ case OV9640_COM13:
+ val |= alts->com13;
+ break;
+ case OV9640_COM15:
+ val |= alts->com15;
+ break;
+ }
+
+ ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
+ if (ret)
+ return ret;
+ }
+
+ /* write color matrix configuration into the module */
+ for (i = 0; i < matrix_regs_len; i++) {
+ ret = ov9640_reg_write(client, matrix_regs[i].reg,
+ matrix_regs[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* program default register values */
+static int ov9640_prog_dflt(struct i2c_client *client)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
+ ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
+ ov9640_regs_dflt[i].val);
+ if (ret)
+ return ret;
+ }
+
+ /* wait for the changes to actually happen, 140ms are not enough yet */
+ mdelay(150);
+
+ return 0;
+}
+
+/* set the format we will capture in */
+static int ov9640_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov9640_reg_alt alts = {0};
+ enum v4l2_colorspace cspace;
+ enum v4l2_mbus_pixelcode code = mf->code;
+ int ret;
+
+ ov9640_res_roundup(&mf->width, &mf->height);
+ ov9640_alter_regs(mf->code, &alts);
+
+ ov9640_reset(client);
+
+ ret = ov9640_prog_dflt(client);
+ if (ret)
+ return ret;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ cspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ ret = ov9640_write_regs(client, mf->width, code, &alts);
+ if (!ret) {
+ mf->code = code;
+ mf->colorspace = cspace;
+ }
+
+ return ret;
+}
+
+static int ov9640_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ ov9640_res_roundup(&mf->width, &mf->height);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ return 0;
+}
+
+static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov9640_codes))
+ return -EINVAL;
+
+ *code = ov9640_codes[index];
+ return 0;
+}
+
+static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = W_SXGA;
+ a->c.height = H_SXGA;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = W_SXGA;
+ a->bounds.height = H_SXGA;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov9640_video_probe(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
+ u8 pid, ver, midh, midl;
+ const char *devname;
+ int ret;
+
+ ret = ov9640_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+
+ ret = ov9640_reg_read(client, OV9640_PID, &pid);
+ if (!ret)
+ ret = ov9640_reg_read(client, OV9640_VER, &ver);
+ if (!ret)
+ ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
+ if (!ret)
+ ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
+ if (ret)
+ goto done;
+
+ switch (VERSION(pid, ver)) {
+ case OV9640_V2:
+ devname = "ov9640";
+ priv->model = V4L2_IDENT_OV9640;
+ priv->revision = 2;
+ break;
+ case OV9640_V3:
+ devname = "ov9640";
+ priv->model = V4L2_IDENT_OV9640;
+ priv->revision = 3;
+ break;
+ default:
+ dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname, pid, ver, midh, midl);
+
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov9640_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
+ .s_ctrl = ov9640_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops ov9640_core_ops = {
+ .g_chip_ident = ov9640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov9640_get_register,
+ .s_register = ov9640_set_register,
+#endif
+ .s_power = ov9640_s_power,
+};
+
+/* Request bus settings on camera side */
+static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov9640_video_ops = {
+ .s_stream = ov9640_s_stream,
+ .s_mbus_fmt = ov9640_s_fmt,
+ .try_mbus_fmt = ov9640_try_fmt,
+ .enum_mbus_fmt = ov9640_enum_fmt,
+ .cropcap = ov9640_cropcap,
+ .g_crop = ov9640_g_crop,
+ .g_mbus_config = ov9640_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops ov9640_subdev_ops = {
+ .core = &ov9640_core_ops,
+ .video = &ov9640_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9640_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov9640_priv *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
+
+ v4l2_ctrl_handler_init(&priv->hdl, 2);
+ v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error) {
+ int err = priv->hdl.error;
+
+ kfree(priv);
+ return err;
+ }
+
+ ret = ov9640_video_probe(client);
+
+ if (ret) {
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int ov9640_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov9640_id[] = {
+ { "ov9640", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov9640_id);
+
+static struct i2c_driver ov9640_i2c_driver = {
+ .driver = {
+ .name = "ov9640",
+ },
+ .probe = ov9640_probe,
+ .remove = ov9640_remove,
+ .id_table = ov9640_id,
+};
+
+module_i2c_driver(ov9640_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov9640.h b/drivers/media/i2c/soc_camera/ov9640.h
index 6b33a972c83c..6b33a972c83c 100644
--- a/drivers/media/video/ov9640.h
+++ b/drivers/media/i2c/soc_camera/ov9640.h
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
new file mode 100644
index 000000000000..7a55889e397b
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -0,0 +1,1020 @@
+/*
+ * OmniVision OV9740 Camera Driver
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Based on ov9640 camera driver.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev)
+
+/* General Status Registers */
+#define OV9740_MODEL_ID_HI 0x0000
+#define OV9740_MODEL_ID_LO 0x0001
+#define OV9740_REVISION_NUMBER 0x0002
+#define OV9740_MANUFACTURER_ID 0x0003
+#define OV9740_SMIA_VERSION 0x0004
+
+/* General Setup Registers */
+#define OV9740_MODE_SELECT 0x0100
+#define OV9740_IMAGE_ORT 0x0101
+#define OV9740_SOFTWARE_RESET 0x0103
+#define OV9740_GRP_PARAM_HOLD 0x0104
+#define OV9740_MSK_CORRUP_FM 0x0105
+
+/* Timing Setting */
+#define OV9740_FRM_LENGTH_LN_HI 0x0340 /* VTS */
+#define OV9740_FRM_LENGTH_LN_LO 0x0341 /* VTS */
+#define OV9740_LN_LENGTH_PCK_HI 0x0342 /* HTS */
+#define OV9740_LN_LENGTH_PCK_LO 0x0343 /* HTS */
+#define OV9740_X_ADDR_START_HI 0x0344
+#define OV9740_X_ADDR_START_LO 0x0345
+#define OV9740_Y_ADDR_START_HI 0x0346
+#define OV9740_Y_ADDR_START_LO 0x0347
+#define OV9740_X_ADDR_END_HI 0x0348
+#define OV9740_X_ADDR_END_LO 0x0349
+#define OV9740_Y_ADDR_END_HI 0x034a
+#define OV9740_Y_ADDR_END_LO 0x034b
+#define OV9740_X_OUTPUT_SIZE_HI 0x034c
+#define OV9740_X_OUTPUT_SIZE_LO 0x034d
+#define OV9740_Y_OUTPUT_SIZE_HI 0x034e
+#define OV9740_Y_OUTPUT_SIZE_LO 0x034f
+
+/* IO Control Registers */
+#define OV9740_IO_CREL00 0x3002
+#define OV9740_IO_CREL01 0x3004
+#define OV9740_IO_CREL02 0x3005
+#define OV9740_IO_OUTPUT_SEL01 0x3026
+#define OV9740_IO_OUTPUT_SEL02 0x3027
+
+/* AWB Registers */
+#define OV9740_AWB_MANUAL_CTRL 0x3406
+
+/* Analog Control Registers */
+#define OV9740_ANALOG_CTRL01 0x3601
+#define OV9740_ANALOG_CTRL02 0x3602
+#define OV9740_ANALOG_CTRL03 0x3603
+#define OV9740_ANALOG_CTRL04 0x3604
+#define OV9740_ANALOG_CTRL10 0x3610
+#define OV9740_ANALOG_CTRL12 0x3612
+#define OV9740_ANALOG_CTRL15 0x3615
+#define OV9740_ANALOG_CTRL20 0x3620
+#define OV9740_ANALOG_CTRL21 0x3621
+#define OV9740_ANALOG_CTRL22 0x3622
+#define OV9740_ANALOG_CTRL30 0x3630
+#define OV9740_ANALOG_CTRL31 0x3631
+#define OV9740_ANALOG_CTRL32 0x3632
+#define OV9740_ANALOG_CTRL33 0x3633
+
+/* Sensor Control */
+#define OV9740_SENSOR_CTRL03 0x3703
+#define OV9740_SENSOR_CTRL04 0x3704
+#define OV9740_SENSOR_CTRL05 0x3705
+#define OV9740_SENSOR_CTRL07 0x3707
+
+/* Timing Control */
+#define OV9740_TIMING_CTRL17 0x3817
+#define OV9740_TIMING_CTRL19 0x3819
+#define OV9740_TIMING_CTRL33 0x3833
+#define OV9740_TIMING_CTRL35 0x3835
+
+/* Banding Filter */
+#define OV9740_AEC_MAXEXPO_60_H 0x3a02
+#define OV9740_AEC_MAXEXPO_60_L 0x3a03
+#define OV9740_AEC_B50_STEP_HI 0x3a08
+#define OV9740_AEC_B50_STEP_LO 0x3a09
+#define OV9740_AEC_B60_STEP_HI 0x3a0a
+#define OV9740_AEC_B60_STEP_LO 0x3a0b
+#define OV9740_AEC_CTRL0D 0x3a0d
+#define OV9740_AEC_CTRL0E 0x3a0e
+#define OV9740_AEC_MAXEXPO_50_H 0x3a14
+#define OV9740_AEC_MAXEXPO_50_L 0x3a15
+
+/* AEC/AGC Control */
+#define OV9740_AEC_ENABLE 0x3503
+#define OV9740_GAIN_CEILING_01 0x3a18
+#define OV9740_GAIN_CEILING_02 0x3a19
+#define OV9740_AEC_HI_THRESHOLD 0x3a11
+#define OV9740_AEC_3A1A 0x3a1a
+#define OV9740_AEC_CTRL1B_WPT2 0x3a1b
+#define OV9740_AEC_CTRL0F_WPT 0x3a0f
+#define OV9740_AEC_CTRL10_BPT 0x3a10
+#define OV9740_AEC_CTRL1E_BPT2 0x3a1e
+#define OV9740_AEC_LO_THRESHOLD 0x3a1f
+
+/* BLC Control */
+#define OV9740_BLC_AUTO_ENABLE 0x4002
+#define OV9740_BLC_MODE 0x4005
+
+/* VFIFO */
+#define OV9740_VFIFO_READ_START_HI 0x4608
+#define OV9740_VFIFO_READ_START_LO 0x4609
+
+/* DVP Control */
+#define OV9740_DVP_VSYNC_CTRL02 0x4702
+#define OV9740_DVP_VSYNC_MODE 0x4704
+#define OV9740_DVP_VSYNC_CTRL06 0x4706
+
+/* PLL Setting */
+#define OV9740_PLL_MODE_CTRL01 0x3104
+#define OV9740_PRE_PLL_CLK_DIV 0x0305
+#define OV9740_PLL_MULTIPLIER 0x0307
+#define OV9740_VT_SYS_CLK_DIV 0x0303
+#define OV9740_VT_PIX_CLK_DIV 0x0301
+#define OV9740_PLL_CTRL3010 0x3010
+#define OV9740_VFIFO_CTRL00 0x460e
+
+/* ISP Control */
+#define OV9740_ISP_CTRL00 0x5000
+#define OV9740_ISP_CTRL01 0x5001
+#define OV9740_ISP_CTRL03 0x5003
+#define OV9740_ISP_CTRL05 0x5005
+#define OV9740_ISP_CTRL12 0x5012
+#define OV9740_ISP_CTRL19 0x5019
+#define OV9740_ISP_CTRL1A 0x501a
+#define OV9740_ISP_CTRL1E 0x501e
+#define OV9740_ISP_CTRL1F 0x501f
+#define OV9740_ISP_CTRL20 0x5020
+#define OV9740_ISP_CTRL21 0x5021
+
+/* AWB */
+#define OV9740_AWB_CTRL00 0x5180
+#define OV9740_AWB_CTRL01 0x5181
+#define OV9740_AWB_CTRL02 0x5182
+#define OV9740_AWB_CTRL03 0x5183
+#define OV9740_AWB_ADV_CTRL01 0x5184
+#define OV9740_AWB_ADV_CTRL02 0x5185
+#define OV9740_AWB_ADV_CTRL03 0x5186
+#define OV9740_AWB_ADV_CTRL04 0x5187
+#define OV9740_AWB_ADV_CTRL05 0x5188
+#define OV9740_AWB_ADV_CTRL06 0x5189
+#define OV9740_AWB_ADV_CTRL07 0x518a
+#define OV9740_AWB_ADV_CTRL08 0x518b
+#define OV9740_AWB_ADV_CTRL09 0x518c
+#define OV9740_AWB_ADV_CTRL10 0x518d
+#define OV9740_AWB_ADV_CTRL11 0x518e
+#define OV9740_AWB_CTRL0F 0x518f
+#define OV9740_AWB_CTRL10 0x5190
+#define OV9740_AWB_CTRL11 0x5191
+#define OV9740_AWB_CTRL12 0x5192
+#define OV9740_AWB_CTRL13 0x5193
+#define OV9740_AWB_CTRL14 0x5194
+
+/* MIPI Control */
+#define OV9740_MIPI_CTRL00 0x4800
+#define OV9740_MIPI_3837 0x3837
+#define OV9740_MIPI_CTRL01 0x4801
+#define OV9740_MIPI_CTRL03 0x4803
+#define OV9740_MIPI_CTRL05 0x4805
+#define OV9740_VFIFO_RD_CTRL 0x4601
+#define OV9740_MIPI_CTRL_3012 0x3012
+#define OV9740_SC_CMMM_MIPI_CTR 0x3014
+
+#define OV9740_MAX_WIDTH 1280
+#define OV9740_MAX_HEIGHT 720
+
+/* Misc. structures */
+struct ov9740_reg {
+ u16 reg;
+ u8 val;
+};
+
+struct ov9740_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+
+ int ident;
+ u16 model;
+ u8 revision;
+ u8 manid;
+ u8 smiaver;
+
+ bool flag_vflip;
+ bool flag_hflip;
+
+ /* For suspend/resume. */
+ struct v4l2_mbus_framefmt current_mf;
+ bool current_enable;
+};
+
+static const struct ov9740_reg ov9740_defaults[] = {
+ /* Software Reset */
+ { OV9740_SOFTWARE_RESET, 0x01 },
+
+ /* Banding Filter */
+ { OV9740_AEC_B50_STEP_HI, 0x00 },
+ { OV9740_AEC_B50_STEP_LO, 0xe8 },
+ { OV9740_AEC_CTRL0E, 0x03 },
+ { OV9740_AEC_MAXEXPO_50_H, 0x15 },
+ { OV9740_AEC_MAXEXPO_50_L, 0xc6 },
+ { OV9740_AEC_B60_STEP_HI, 0x00 },
+ { OV9740_AEC_B60_STEP_LO, 0xc0 },
+ { OV9740_AEC_CTRL0D, 0x04 },
+ { OV9740_AEC_MAXEXPO_60_H, 0x18 },
+ { OV9740_AEC_MAXEXPO_60_L, 0x20 },
+
+ /* LC */
+ { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
+ { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
+
+ /* Un-documented OV9740 registers */
+ { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
+ { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
+ { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
+ { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
+ { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
+ { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
+ { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
+ { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
+ { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
+ { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
+ { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
+ { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
+ { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
+ { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
+ { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
+ { 0x583c, 0x5f },
+
+ /* Y Gamma */
+ { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
+ { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
+ { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
+ { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
+
+ /* UV Gamma */
+ { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
+ { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
+ { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
+ { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
+ { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
+ { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
+ { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
+ { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
+
+ /* AWB */
+ { OV9740_AWB_CTRL00, 0xf0 },
+ { OV9740_AWB_CTRL01, 0x00 },
+ { OV9740_AWB_CTRL02, 0x41 },
+ { OV9740_AWB_CTRL03, 0x42 },
+ { OV9740_AWB_ADV_CTRL01, 0x8a },
+ { OV9740_AWB_ADV_CTRL02, 0x61 },
+ { OV9740_AWB_ADV_CTRL03, 0xce },
+ { OV9740_AWB_ADV_CTRL04, 0xa8 },
+ { OV9740_AWB_ADV_CTRL05, 0x17 },
+ { OV9740_AWB_ADV_CTRL06, 0x1f },
+ { OV9740_AWB_ADV_CTRL07, 0x27 },
+ { OV9740_AWB_ADV_CTRL08, 0x41 },
+ { OV9740_AWB_ADV_CTRL09, 0x34 },
+ { OV9740_AWB_ADV_CTRL10, 0xf0 },
+ { OV9740_AWB_ADV_CTRL11, 0x10 },
+ { OV9740_AWB_CTRL0F, 0xff },
+ { OV9740_AWB_CTRL10, 0x00 },
+ { OV9740_AWB_CTRL11, 0xff },
+ { OV9740_AWB_CTRL12, 0x00 },
+ { OV9740_AWB_CTRL13, 0xff },
+ { OV9740_AWB_CTRL14, 0x00 },
+
+ /* CIP */
+ { 0x530d, 0x12 },
+
+ /* CMX */
+ { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
+ { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
+ { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
+ { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
+ { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
+ { 0x5394, 0x18 },
+
+ /* 50/60 Detection */
+ { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
+
+ /* Output Select */
+ { OV9740_IO_OUTPUT_SEL01, 0x00 },
+ { OV9740_IO_OUTPUT_SEL02, 0x00 },
+ { OV9740_IO_CREL00, 0x00 },
+ { OV9740_IO_CREL01, 0x00 },
+ { OV9740_IO_CREL02, 0x00 },
+
+ /* AWB Control */
+ { OV9740_AWB_MANUAL_CTRL, 0x00 },
+
+ /* Analog Control */
+ { OV9740_ANALOG_CTRL03, 0xaa },
+ { OV9740_ANALOG_CTRL32, 0x2f },
+ { OV9740_ANALOG_CTRL20, 0x66 },
+ { OV9740_ANALOG_CTRL21, 0xc0 },
+ { OV9740_ANALOG_CTRL31, 0x52 },
+ { OV9740_ANALOG_CTRL33, 0x50 },
+ { OV9740_ANALOG_CTRL30, 0xca },
+ { OV9740_ANALOG_CTRL04, 0x0c },
+ { OV9740_ANALOG_CTRL01, 0x40 },
+ { OV9740_ANALOG_CTRL02, 0x16 },
+ { OV9740_ANALOG_CTRL10, 0xa1 },
+ { OV9740_ANALOG_CTRL12, 0x24 },
+ { OV9740_ANALOG_CTRL22, 0x9f },
+ { OV9740_ANALOG_CTRL15, 0xf0 },
+
+ /* Sensor Control */
+ { OV9740_SENSOR_CTRL03, 0x42 },
+ { OV9740_SENSOR_CTRL04, 0x10 },
+ { OV9740_SENSOR_CTRL05, 0x45 },
+ { OV9740_SENSOR_CTRL07, 0x14 },
+
+ /* Timing Control */
+ { OV9740_TIMING_CTRL33, 0x04 },
+ { OV9740_TIMING_CTRL35, 0x02 },
+ { OV9740_TIMING_CTRL19, 0x6e },
+ { OV9740_TIMING_CTRL17, 0x94 },
+
+ /* AEC/AGC Control */
+ { OV9740_AEC_ENABLE, 0x10 },
+ { OV9740_GAIN_CEILING_01, 0x00 },
+ { OV9740_GAIN_CEILING_02, 0x7f },
+ { OV9740_AEC_HI_THRESHOLD, 0xa0 },
+ { OV9740_AEC_3A1A, 0x05 },
+ { OV9740_AEC_CTRL1B_WPT2, 0x50 },
+ { OV9740_AEC_CTRL0F_WPT, 0x50 },
+ { OV9740_AEC_CTRL10_BPT, 0x4c },
+ { OV9740_AEC_CTRL1E_BPT2, 0x4c },
+ { OV9740_AEC_LO_THRESHOLD, 0x26 },
+
+ /* BLC Control */
+ { OV9740_BLC_AUTO_ENABLE, 0x45 },
+ { OV9740_BLC_MODE, 0x18 },
+
+ /* DVP Control */
+ { OV9740_DVP_VSYNC_CTRL02, 0x04 },
+ { OV9740_DVP_VSYNC_MODE, 0x00 },
+ { OV9740_DVP_VSYNC_CTRL06, 0x08 },
+
+ /* PLL Setting */
+ { OV9740_PLL_MODE_CTRL01, 0x20 },
+ { OV9740_PRE_PLL_CLK_DIV, 0x03 },
+ { OV9740_PLL_MULTIPLIER, 0x4c },
+ { OV9740_VT_SYS_CLK_DIV, 0x01 },
+ { OV9740_VT_PIX_CLK_DIV, 0x08 },
+ { OV9740_PLL_CTRL3010, 0x01 },
+ { OV9740_VFIFO_CTRL00, 0x82 },
+
+ /* Timing Setting */
+ /* VTS */
+ { OV9740_FRM_LENGTH_LN_HI, 0x03 },
+ { OV9740_FRM_LENGTH_LN_LO, 0x07 },
+ /* HTS */
+ { OV9740_LN_LENGTH_PCK_HI, 0x06 },
+ { OV9740_LN_LENGTH_PCK_LO, 0x62 },
+
+ /* MIPI Control */
+ { OV9740_MIPI_CTRL00, 0x44 }, /* 0x64 for discontinuous clk */
+ { OV9740_MIPI_3837, 0x01 },
+ { OV9740_MIPI_CTRL01, 0x0f },
+ { OV9740_MIPI_CTRL03, 0x05 },
+ { OV9740_MIPI_CTRL05, 0x10 },
+ { OV9740_VFIFO_RD_CTRL, 0x16 },
+ { OV9740_MIPI_CTRL_3012, 0x70 },
+ { OV9740_SC_CMMM_MIPI_CTR, 0x01 },
+
+ /* YUYV order */
+ { OV9740_ISP_CTRL19, 0x02 },
+};
+
+static enum v4l2_mbus_pixelcode ov9740_codes[] = {
+ V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+/* read a register */
+static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+ int ret;
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = (u8 *)&reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = val,
+ },
+ };
+
+ reg = swab16(reg);
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* write a register */
+static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+ struct i2c_msg msg;
+ struct {
+ u16 reg;
+ u8 val;
+ } __packed buf;
+ int ret;
+
+ reg = swab16(reg);
+
+ buf.reg = reg;
+ buf.val = val;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = (u8 *)&buf;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
+{
+ u8 val;
+ int ret;
+
+ ret = ov9740_reg_read(client, reg, &val);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "[Read]-Modify-Write of register 0x%04x failed!\n",
+ reg);
+ return ret;
+ }
+
+ val |= set;
+ val &= ~unset;
+
+ ret = ov9740_reg_write(client, reg, val);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Read-Modify-[Write] of register 0x%04x failed!\n",
+ reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ov9740_reg_write_array(struct i2c_client *client,
+ const struct ov9740_reg *regarray,
+ int regarraylen)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < regarraylen; i++) {
+ ret = ov9740_reg_write(client,
+ regarray[i].reg, regarray[i].val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov9740_priv *priv = to_ov9740(sd);
+ int ret;
+
+ /* Program orientation register. */
+ if (priv->flag_vflip)
+ ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
+ else
+ ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
+ if (ret < 0)
+ return ret;
+
+ if (priv->flag_hflip)
+ ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
+ else
+ ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
+ if (ret < 0)
+ return ret;
+
+ if (enable) {
+ dev_dbg(&client->dev, "Enabling Streaming\n");
+ /* Start Streaming */
+ ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
+
+ } else {
+ dev_dbg(&client->dev, "Disabling Streaming\n");
+ /* Software Reset */
+ ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
+ if (!ret)
+ /* Setting Streaming to Standby */
+ ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
+ 0x00);
+ }
+
+ priv->current_enable = enable;
+
+ return ret;
+}
+
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
+{
+ /* Width must be a multiple of 4 pixels. */
+ *width = ALIGN(*width, 4);
+
+ /* Max resolution is 1280x720 (720p). */
+ if (*width > OV9740_MAX_WIDTH)
+ *width = OV9740_MAX_WIDTH;
+
+ if (*height > OV9740_MAX_HEIGHT)
+ *height = OV9740_MAX_HEIGHT;
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
+{
+ u32 x_start;
+ u32 y_start;
+ u32 x_end;
+ u32 y_end;
+ bool scaling = 0;
+ u32 scale_input_x;
+ u32 scale_input_y;
+ int ret;
+
+ if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
+ scaling = 1;
+
+ /*
+ * Try to use as much of the sensor area as possible when supporting
+ * smaller resolutions. Depending on the aspect ratio of the
+ * chosen resolution, we can either use the full width of the sensor,
+ * or the full height of the sensor (or both if the aspect ratio is
+ * the same as 1280x720.
+ */
+ if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
+ scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
+ scale_input_y = OV9740_MAX_HEIGHT;
+ } else {
+ scale_input_x = OV9740_MAX_WIDTH;
+ scale_input_y = (OV9740_MAX_WIDTH * height) / width;
+ }
+
+ /* These describe the area of the sensor to use. */
+ x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
+ y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
+ x_end = x_start + scale_input_x - 1;
+ y_end = y_start + scale_input_y - 1;
+
+ ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
+ if (ret)
+ goto done;
+
+ ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
+ if (ret)
+ goto done;
+
+ ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
+ if (ret)
+ goto done;
+
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
+ if (ret)
+ goto done;
+
+ ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
+ (scale_input_x - width) >> 8);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
+ (scale_input_x - width) & 0xff);
+ if (ret)
+ goto done;
+
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
+ (scaling << 4));
+ if (ret)
+ goto done;
+ ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
+
+done:
+ return ret;
+}
+
+/* set the format we will capture in */
+static int ov9740_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov9740_priv *priv = to_ov9740(sd);
+ enum v4l2_colorspace cspace;
+ enum v4l2_mbus_pixelcode code = mf->code;
+ int ret;
+
+ ov9740_res_roundup(&mf->width, &mf->height);
+
+ switch (code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = ov9740_reg_write_array(client, ov9740_defaults,
+ ARRAY_SIZE(ov9740_defaults));
+ if (ret < 0)
+ return ret;
+
+ ret = ov9740_set_res(client, mf->width, mf->height);
+ if (ret < 0)
+ return ret;
+
+ mf->code = code;
+ mf->colorspace = cspace;
+
+ memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
+ return ret;
+}
+
+static int ov9740_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ ov9740_res_roundup(&mf->width, &mf->height);
+
+ mf->field = V4L2_FIELD_NONE;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov9740_codes))
+ return -EINVAL;
+
+ *code = ov9740_codes[index];
+
+ return 0;
+}
+
+static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = OV9740_MAX_WIDTH;
+ a->bounds.height = OV9740_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = OV9740_MAX_WIDTH;
+ a->c.height = OV9740_MAX_HEIGHT;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov9740_priv *priv =
+ container_of(ctrl->handler, struct ov9740_priv, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ priv->flag_vflip = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ priv->flag_hflip = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Get chip identification */
+static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct ov9740_priv *priv = to_ov9740(sd);
+
+ id->ident = priv->ident;
+ id->revision = priv->revision;
+
+ return 0;
+}
+
+static int ov9740_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct ov9740_priv *priv = to_ov9740(sd);
+ int ret;
+
+ if (on) {
+ ret = soc_camera_power_on(&client->dev, icl);
+ if (ret < 0)
+ return ret;
+
+ if (priv->current_enable) {
+ ov9740_s_fmt(sd, &priv->current_mf);
+ ov9740_s_stream(sd, 1);
+ }
+ } else {
+ if (priv->current_enable) {
+ ov9740_s_stream(sd, 0);
+ priv->current_enable = true;
+ }
+
+ soc_camera_power_off(&client->dev, icl);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xffff)
+ return -EINVAL;
+
+ reg->size = 2;
+
+ ret = ov9740_reg_read(client, reg->reg, &val);
+ if (ret)
+ return ret;
+
+ reg->val = (__u64)val;
+
+ return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xffff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9740_video_probe(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9740_priv *priv = to_ov9740(sd);
+ u8 modelhi, modello;
+ int ret;
+
+ ret = ov9740_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
+ if (ret < 0)
+ goto done;
+
+ ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
+ if (ret < 0)
+ goto done;
+
+ priv->model = (modelhi << 8) | modello;
+
+ ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
+ if (ret < 0)
+ goto done;
+
+ ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
+ if (ret < 0)
+ goto done;
+
+ ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
+ if (ret < 0)
+ goto done;
+
+ if (priv->model != 0x9740) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ priv->ident = V4L2_IDENT_OV9740;
+
+ dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
+ "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
+ priv->model, priv->revision, priv->manid, priv->smiaver);
+
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov9740_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+/* Request bus settings on camera side */
+static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov9740_video_ops = {
+ .s_stream = ov9740_s_stream,
+ .s_mbus_fmt = ov9740_s_fmt,
+ .try_mbus_fmt = ov9740_try_fmt,
+ .enum_mbus_fmt = ov9740_enum_fmt,
+ .cropcap = ov9740_cropcap,
+ .g_crop = ov9740_g_crop,
+ .g_mbus_config = ov9740_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ov9740_core_ops = {
+ .g_chip_ident = ov9740_g_chip_ident,
+ .s_power = ov9740_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov9740_get_register,
+ .s_register = ov9740_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov9740_subdev_ops = {
+ .core = &ov9740_core_ops,
+ .video = &ov9740_video_ops,
+};
+
+static const struct v4l2_ctrl_ops ov9740_ctrl_ops = {
+ .s_ctrl = ov9740_s_ctrl,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9740_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov9740_priv *priv;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev, "Failed to allocate private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->hdl, 13);
+ v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error) {
+ int err = priv->hdl.error;
+
+ kfree(priv);
+ return err;
+ }
+
+ ret = ov9740_video_probe(client);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int ov9740_remove(struct i2c_client *client)
+{
+ struct ov9740_priv *priv = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov9740_id[] = {
+ { "ov9740", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov9740_id);
+
+static struct i2c_driver ov9740_i2c_driver = {
+ .driver = {
+ .name = "ov9740",
+ },
+ .probe = ov9740_probe,
+ .remove = ov9740_remove,
+ .id_table = ov9740_id,
+};
+
+module_i2c_driver(ov9740_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
+MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
new file mode 100644
index 000000000000..32226c9024f9
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -0,0 +1,1431 @@
+/*
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/rj54n1cb0c.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#define RJ54N1_DEV_CODE 0x0400
+#define RJ54N1_DEV_CODE2 0x0401
+#define RJ54N1_OUT_SEL 0x0403
+#define RJ54N1_XY_OUTPUT_SIZE_S_H 0x0404
+#define RJ54N1_X_OUTPUT_SIZE_S_L 0x0405
+#define RJ54N1_Y_OUTPUT_SIZE_S_L 0x0406
+#define RJ54N1_XY_OUTPUT_SIZE_P_H 0x0407
+#define RJ54N1_X_OUTPUT_SIZE_P_L 0x0408
+#define RJ54N1_Y_OUTPUT_SIZE_P_L 0x0409
+#define RJ54N1_LINE_LENGTH_PCK_S_H 0x040a
+#define RJ54N1_LINE_LENGTH_PCK_S_L 0x040b
+#define RJ54N1_LINE_LENGTH_PCK_P_H 0x040c
+#define RJ54N1_LINE_LENGTH_PCK_P_L 0x040d
+#define RJ54N1_RESIZE_N 0x040e
+#define RJ54N1_RESIZE_N_STEP 0x040f
+#define RJ54N1_RESIZE_STEP 0x0410
+#define RJ54N1_RESIZE_HOLD_H 0x0411
+#define RJ54N1_RESIZE_HOLD_L 0x0412
+#define RJ54N1_H_OBEN_OFS 0x0413
+#define RJ54N1_V_OBEN_OFS 0x0414
+#define RJ54N1_RESIZE_CONTROL 0x0415
+#define RJ54N1_STILL_CONTROL 0x0417
+#define RJ54N1_INC_USE_SEL_H 0x0425
+#define RJ54N1_INC_USE_SEL_L 0x0426
+#define RJ54N1_MIRROR_STILL_MODE 0x0427
+#define RJ54N1_INIT_START 0x0428
+#define RJ54N1_SCALE_1_2_LEV 0x0429
+#define RJ54N1_SCALE_4_LEV 0x042a
+#define RJ54N1_Y_GAIN 0x04d8
+#define RJ54N1_APT_GAIN_UP 0x04fa
+#define RJ54N1_RA_SEL_UL 0x0530
+#define RJ54N1_BYTE_SWAP 0x0531
+#define RJ54N1_OUT_SIGPO 0x053b
+#define RJ54N1_WB_SEL_WEIGHT_I 0x054e
+#define RJ54N1_BIT8_WB 0x0569
+#define RJ54N1_HCAPS_WB 0x056a
+#define RJ54N1_VCAPS_WB 0x056b
+#define RJ54N1_HCAPE_WB 0x056c
+#define RJ54N1_VCAPE_WB 0x056d
+#define RJ54N1_EXPOSURE_CONTROL 0x058c
+#define RJ54N1_FRAME_LENGTH_S_H 0x0595
+#define RJ54N1_FRAME_LENGTH_S_L 0x0596
+#define RJ54N1_FRAME_LENGTH_P_H 0x0597
+#define RJ54N1_FRAME_LENGTH_P_L 0x0598
+#define RJ54N1_PEAK_H 0x05b7
+#define RJ54N1_PEAK_50 0x05b8
+#define RJ54N1_PEAK_60 0x05b9
+#define RJ54N1_PEAK_DIFF 0x05ba
+#define RJ54N1_IOC 0x05ef
+#define RJ54N1_TG_BYPASS 0x0700
+#define RJ54N1_PLL_L 0x0701
+#define RJ54N1_PLL_N 0x0702
+#define RJ54N1_PLL_EN 0x0704
+#define RJ54N1_RATIO_TG 0x0706
+#define RJ54N1_RATIO_T 0x0707
+#define RJ54N1_RATIO_R 0x0708
+#define RJ54N1_RAMP_TGCLK_EN 0x0709
+#define RJ54N1_OCLK_DSP 0x0710
+#define RJ54N1_RATIO_OP 0x0711
+#define RJ54N1_RATIO_O 0x0712
+#define RJ54N1_OCLK_SEL_EN 0x0713
+#define RJ54N1_CLK_RST 0x0717
+#define RJ54N1_RESET_STANDBY 0x0718
+#define RJ54N1_FWFLG 0x07fe
+
+#define E_EXCLK (1 << 7)
+#define SOFT_STDBY (1 << 4)
+#define SEN_RSTX (1 << 2)
+#define TG_RSTX (1 << 1)
+#define DSP_RSTX (1 << 0)
+
+#define RESIZE_HOLD_SEL (1 << 2)
+#define RESIZE_GO (1 << 1)
+
+/*
+ * When cropping, the camera automatically centers the cropped region, there
+ * doesn't seem to be a way to specify an explicit location of the rectangle.
+ */
+#define RJ54N1_COLUMN_SKIP 0
+#define RJ54N1_ROW_SKIP 0
+#define RJ54N1_MAX_WIDTH 1600
+#define RJ54N1_MAX_HEIGHT 1200
+
+#define PLL_L 2
+#define PLL_N 0x31
+
+/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
+
+/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
+struct rj54n1_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct rj54n1_datafmt *rj54n1_find_datafmt(
+ enum v4l2_mbus_pixelcode code, const struct rj54n1_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 rj54n1_datafmt rj54n1_colour_fmts[] = {
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
+ {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+};
+
+struct rj54n1_clock_div {
+ u8 ratio_tg; /* can be 0 or an odd number */
+ u8 ratio_t;
+ u8 ratio_r;
+ u8 ratio_op;
+ u8 ratio_o;
+};
+
+struct rj54n1 {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct rj54n1_clock_div clk_div;
+ const struct rj54n1_datafmt *fmt;
+ struct v4l2_rect rect; /* Sensor window */
+ unsigned int tgclk_mhz;
+ bool auto_wb;
+ unsigned short width; /* Output window */
+ unsigned short height;
+ unsigned short resize; /* Sensor * 1024 / resize = Output */
+ unsigned short scale;
+ u8 bank;
+};
+
+struct rj54n1_reg_val {
+ u16 reg;
+ u8 val;
+};
+
+static const struct rj54n1_reg_val bank_4[] = {
+ {0x417, 0},
+ {0x42c, 0},
+ {0x42d, 0xf0},
+ {0x42e, 0},
+ {0x42f, 0x50},
+ {0x430, 0xf5},
+ {0x431, 0x16},
+ {0x432, 0x20},
+ {0x433, 0},
+ {0x434, 0xc8},
+ {0x43c, 8},
+ {0x43e, 0x90},
+ {0x445, 0x83},
+ {0x4ba, 0x58},
+ {0x4bb, 4},
+ {0x4bc, 0x20},
+ {0x4db, 4},
+ {0x4fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_5[] = {
+ {0x514, 0},
+ {0x516, 0},
+ {0x518, 0},
+ {0x51a, 0},
+ {0x51d, 0xff},
+ {0x56f, 0x28},
+ {0x575, 0x40},
+ {0x5bc, 0x48},
+ {0x5c1, 6},
+ {0x5e5, 0x11},
+ {0x5e6, 0x43},
+ {0x5e7, 0x33},
+ {0x5e8, 0x21},
+ {0x5e9, 0x30},
+ {0x5ea, 0x0},
+ {0x5eb, 0xa5},
+ {0x5ec, 0xff},
+ {0x5fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_7[] = {
+ {0x70a, 0},
+ {0x714, 0xff},
+ {0x715, 0xff},
+ {0x716, 0x1f},
+ {0x7FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_8[] = {
+ {0x800, 0x00},
+ {0x801, 0x01},
+ {0x802, 0x61},
+ {0x805, 0x00},
+ {0x806, 0x00},
+ {0x807, 0x00},
+ {0x808, 0x00},
+ {0x809, 0x01},
+ {0x80A, 0x61},
+ {0x80B, 0x00},
+ {0x80C, 0x01},
+ {0x80D, 0x00},
+ {0x80E, 0x00},
+ {0x80F, 0x00},
+ {0x810, 0x00},
+ {0x811, 0x01},
+ {0x812, 0x61},
+ {0x813, 0x00},
+ {0x814, 0x11},
+ {0x815, 0x00},
+ {0x816, 0x41},
+ {0x817, 0x00},
+ {0x818, 0x51},
+ {0x819, 0x01},
+ {0x81A, 0x1F},
+ {0x81B, 0x00},
+ {0x81C, 0x01},
+ {0x81D, 0x00},
+ {0x81E, 0x11},
+ {0x81F, 0x00},
+ {0x820, 0x41},
+ {0x821, 0x00},
+ {0x822, 0x51},
+ {0x823, 0x00},
+ {0x824, 0x00},
+ {0x825, 0x00},
+ {0x826, 0x47},
+ {0x827, 0x01},
+ {0x828, 0x4F},
+ {0x829, 0x00},
+ {0x82A, 0x00},
+ {0x82B, 0x00},
+ {0x82C, 0x30},
+ {0x82D, 0x00},
+ {0x82E, 0x40},
+ {0x82F, 0x00},
+ {0x830, 0xB3},
+ {0x831, 0x00},
+ {0x832, 0xE3},
+ {0x833, 0x00},
+ {0x834, 0x00},
+ {0x835, 0x00},
+ {0x836, 0x00},
+ {0x837, 0x00},
+ {0x838, 0x00},
+ {0x839, 0x01},
+ {0x83A, 0x61},
+ {0x83B, 0x00},
+ {0x83C, 0x01},
+ {0x83D, 0x00},
+ {0x83E, 0x00},
+ {0x83F, 0x00},
+ {0x840, 0x00},
+ {0x841, 0x01},
+ {0x842, 0x61},
+ {0x843, 0x00},
+ {0x844, 0x1D},
+ {0x845, 0x00},
+ {0x846, 0x00},
+ {0x847, 0x00},
+ {0x848, 0x00},
+ {0x849, 0x01},
+ {0x84A, 0x1F},
+ {0x84B, 0x00},
+ {0x84C, 0x05},
+ {0x84D, 0x00},
+ {0x84E, 0x19},
+ {0x84F, 0x01},
+ {0x850, 0x21},
+ {0x851, 0x01},
+ {0x852, 0x5D},
+ {0x853, 0x00},
+ {0x854, 0x00},
+ {0x855, 0x00},
+ {0x856, 0x19},
+ {0x857, 0x01},
+ {0x858, 0x21},
+ {0x859, 0x00},
+ {0x85A, 0x00},
+ {0x85B, 0x00},
+ {0x85C, 0x00},
+ {0x85D, 0x00},
+ {0x85E, 0x00},
+ {0x85F, 0x00},
+ {0x860, 0xB3},
+ {0x861, 0x00},
+ {0x862, 0xE3},
+ {0x863, 0x00},
+ {0x864, 0x00},
+ {0x865, 0x00},
+ {0x866, 0x00},
+ {0x867, 0x00},
+ {0x868, 0x00},
+ {0x869, 0xE2},
+ {0x86A, 0x00},
+ {0x86B, 0x01},
+ {0x86C, 0x06},
+ {0x86D, 0x00},
+ {0x86E, 0x00},
+ {0x86F, 0x00},
+ {0x870, 0x60},
+ {0x871, 0x8C},
+ {0x872, 0x10},
+ {0x873, 0x00},
+ {0x874, 0xE0},
+ {0x875, 0x00},
+ {0x876, 0x27},
+ {0x877, 0x01},
+ {0x878, 0x00},
+ {0x879, 0x00},
+ {0x87A, 0x00},
+ {0x87B, 0x03},
+ {0x87C, 0x00},
+ {0x87D, 0x00},
+ {0x87E, 0x00},
+ {0x87F, 0x00},
+ {0x880, 0x00},
+ {0x881, 0x00},
+ {0x882, 0x00},
+ {0x883, 0x00},
+ {0x884, 0x00},
+ {0x885, 0x00},
+ {0x886, 0xF8},
+ {0x887, 0x00},
+ {0x888, 0x03},
+ {0x889, 0x00},
+ {0x88A, 0x64},
+ {0x88B, 0x00},
+ {0x88C, 0x03},
+ {0x88D, 0x00},
+ {0x88E, 0xB1},
+ {0x88F, 0x00},
+ {0x890, 0x03},
+ {0x891, 0x01},
+ {0x892, 0x1D},
+ {0x893, 0x00},
+ {0x894, 0x03},
+ {0x895, 0x01},
+ {0x896, 0x4B},
+ {0x897, 0x00},
+ {0x898, 0xE5},
+ {0x899, 0x00},
+ {0x89A, 0x01},
+ {0x89B, 0x00},
+ {0x89C, 0x01},
+ {0x89D, 0x04},
+ {0x89E, 0xC8},
+ {0x89F, 0x00},
+ {0x8A0, 0x01},
+ {0x8A1, 0x01},
+ {0x8A2, 0x61},
+ {0x8A3, 0x00},
+ {0x8A4, 0x01},
+ {0x8A5, 0x00},
+ {0x8A6, 0x00},
+ {0x8A7, 0x00},
+ {0x8A8, 0x00},
+ {0x8A9, 0x00},
+ {0x8AA, 0x7F},
+ {0x8AB, 0x03},
+ {0x8AC, 0x00},
+ {0x8AD, 0x00},
+ {0x8AE, 0x00},
+ {0x8AF, 0x00},
+ {0x8B0, 0x00},
+ {0x8B1, 0x00},
+ {0x8B6, 0x00},
+ {0x8B7, 0x01},
+ {0x8B8, 0x00},
+ {0x8B9, 0x00},
+ {0x8BA, 0x02},
+ {0x8BB, 0x00},
+ {0x8BC, 0xFF},
+ {0x8BD, 0x00},
+ {0x8FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_10[] = {
+ {0x10bf, 0x69}
+};
+
+/* Clock dividers - these are default register values, divider = register + 1 */
+static const struct rj54n1_clock_div clk_div = {
+ .ratio_tg = 3 /* default: 5 */,
+ .ratio_t = 4 /* default: 1 */,
+ .ratio_r = 4 /* default: 0 */,
+ .ratio_op = 1 /* default: 5 */,
+ .ratio_o = 9 /* default: 0 */,
+};
+
+static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u16 reg)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ int ret;
+
+ /* set bank */
+ if (rj54n1->bank != reg >> 8) {
+ dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+ ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+ if (ret < 0)
+ return ret;
+ rj54n1->bank = reg >> 8;
+ }
+ return i2c_smbus_read_byte_data(client, reg & 0xff);
+}
+
+static int reg_write(struct i2c_client *client, const u16 reg,
+ const u8 data)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ int ret;
+
+ /* set bank */
+ if (rj54n1->bank != reg >> 8) {
+ dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+ ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+ if (ret < 0)
+ return ret;
+ rj54n1->bank = reg >> 8;
+ }
+ dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
+ return i2c_smbus_write_byte_data(client, reg & 0xff, data);
+}
+
+static int reg_set(struct i2c_client *client, const u16 reg,
+ const u8 data, const u8 mask)
+{
+ int ret;
+
+ ret = reg_read(client, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static int reg_write_multiple(struct i2c_client *client,
+ const struct rj54n1_reg_val *rv, const int n)
+{
+ int i, ret;
+
+ for (i = 0; i < n; i++) {
+ ret = reg_write(client, rv->reg, rv->val);
+ if (ret < 0)
+ return ret;
+ rv++;
+ }
+
+ return 0;
+}
+
+static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
+ return -EINVAL;
+
+ *code = rj54n1_colour_fmts[index].code;
+ return 0;
+}
+
+static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* Switch between preview and still shot modes */
+ return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
+}
+
+static int rj54n1_set_rect(struct i2c_client *client,
+ u16 reg_x, u16 reg_y, u16 reg_xy,
+ u32 width, u32 height)
+{
+ int ret;
+
+ ret = reg_write(client, reg_xy,
+ ((width >> 4) & 0x70) |
+ ((height >> 8) & 7));
+
+ if (!ret)
+ ret = reg_write(client, reg_x, width & 0xff);
+ if (!ret)
+ ret = reg_write(client, reg_y, height & 0xff);
+
+ return ret;
+}
+
+/*
+ * Some commands, specifically certain initialisation sequences, require
+ * a commit operation.
+ */
+static int rj54n1_commit(struct i2c_client *client)
+{
+ int ret = reg_write(client, RJ54N1_INIT_START, 1);
+ msleep(10);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_INIT_START, 0);
+ return ret;
+}
+
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+ s32 *out_w, s32 *out_h);
+
+static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ struct v4l2_rect *rect = &a->c;
+ int dummy = 0, output_w, output_h,
+ input_w = rect->width, input_h = rect->height;
+ int ret;
+
+ /* arbitrary minimum width and height, edges unimportant */
+ soc_camera_limit_side(&dummy, &input_w,
+ RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
+
+ soc_camera_limit_side(&dummy, &input_h,
+ RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
+
+ output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+ output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+
+ dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
+ input_w, input_h, rj54n1->resize, output_w, output_h);
+
+ ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+ if (ret < 0)
+ return ret;
+
+ rj54n1->width = output_w;
+ rj54n1->height = output_h;
+ rj54n1->resize = ret;
+ rj54n1->rect.width = input_w;
+ rj54n1->rect.height = input_h;
+
+ return 0;
+}
+
+static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+ a->c = rj54n1->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = RJ54N1_COLUMN_SKIP;
+ a->bounds.top = RJ54N1_ROW_SKIP;
+ a->bounds.width = RJ54N1_MAX_WIDTH;
+ a->bounds.height = RJ54N1_MAX_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int rj54n1_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+ mf->code = rj54n1->fmt->code;
+ mf->colorspace = rj54n1->fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+ mf->width = rj54n1->width;
+ mf->height = rj54n1->height;
+
+ return 0;
+}
+
+/*
+ * The actual geometry configuration routine. It scales the input window into
+ * the output one, updates the window sizes and returns an error or the resize
+ * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
+ */
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+ s32 *out_w, s32 *out_h)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
+ output_w = *out_w, output_h = *out_h;
+ u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
+ unsigned int peak, peak_50, peak_60;
+ int ret;
+
+ /*
+ * We have a problem with crops, where the window is larger than 512x384
+ * and output window is larger than a half of the input one. In this
+ * case we have to either reduce the input window to equal or below
+ * 512x384 or the output window to equal or below 1/2 of the input.
+ */
+ if (output_w > max(512U, input_w / 2)) {
+ if (2 * output_w > RJ54N1_MAX_WIDTH) {
+ input_w = RJ54N1_MAX_WIDTH;
+ output_w = RJ54N1_MAX_WIDTH / 2;
+ } else {
+ input_w = output_w * 2;
+ }
+
+ dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
+ input_w, output_w);
+ }
+
+ if (output_h > max(384U, input_h / 2)) {
+ if (2 * output_h > RJ54N1_MAX_HEIGHT) {
+ input_h = RJ54N1_MAX_HEIGHT;
+ output_h = RJ54N1_MAX_HEIGHT / 2;
+ } else {
+ input_h = output_h * 2;
+ }
+
+ dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
+ input_h, output_h);
+ }
+
+ /* Idea: use the read mode for snapshots, handle separate geometries */
+ ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
+ RJ54N1_Y_OUTPUT_SIZE_S_L,
+ RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
+ if (!ret)
+ ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
+ RJ54N1_Y_OUTPUT_SIZE_P_L,
+ RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
+
+ if (ret < 0)
+ return ret;
+
+ if (output_w > input_w && output_h > input_h) {
+ input_w = output_w;
+ input_h = output_h;
+
+ resize = 1024;
+ } else {
+ unsigned int resize_x, resize_y;
+ resize_x = (input_w * 1024 + output_w / 2) / output_w;
+ resize_y = (input_h * 1024 + output_h / 2) / output_h;
+
+ /* We want max(resize_x, resize_y), check if it still fits */
+ if (resize_x > resize_y &&
+ (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
+ resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
+ output_h;
+ else if (resize_y > resize_x &&
+ (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
+ resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
+ output_w;
+ else
+ resize = max(resize_x, resize_y);
+
+ /* Prohibited value ranges */
+ switch (resize) {
+ case 2040 ... 2047:
+ resize = 2039;
+ break;
+ case 4080 ... 4095:
+ resize = 4079;
+ break;
+ case 8160 ... 8191:
+ resize = 8159;
+ break;
+ case 16320 ... 16384:
+ resize = 16319;
+ }
+ }
+
+ /* Set scaling */
+ ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Configure a skipping bitmask. The sensor will select a skipping value
+ * among set bits automatically. This is very unclear in the datasheet
+ * too. I was told, in this register one enables all skipping values,
+ * that are required for a specific resize, and the camera selects
+ * automatically, which ones to use. But it is unclear how to identify,
+ * which cropping values are needed. Secondly, why don't we just set all
+ * bits and let the camera choose? Would it increase processing time and
+ * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
+ * improve the image quality or stability for larger frames (see comment
+ * above), but I didn't check the framerate.
+ */
+ skip = min(resize / 1024, 15U);
+
+ inc_sel = 1 << skip;
+
+ if (inc_sel <= 2)
+ inc_sel = 0xc;
+ else if (resize & 1023 && skip < 15)
+ inc_sel |= 1 << (skip + 1);
+
+ ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
+
+ if (!rj54n1->auto_wb) {
+ /* Auto white balance window */
+ wb_left = output_w / 16;
+ wb_right = (3 * output_w / 4 - 3) / 4;
+ wb_top = output_h / 16;
+ wb_bottom = (3 * output_h / 4 - 3) / 4;
+ wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
+ ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
+
+ if (!ret)
+ ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
+ }
+
+ /* Antiflicker */
+ peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
+ 10000;
+ peak_50 = peak / 6;
+ peak_60 = peak / 5;
+
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PEAK_H,
+ ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
+
+ /* Start resizing */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+ RESIZE_HOLD_SEL | RESIZE_GO | 1);
+
+ if (ret < 0)
+ return ret;
+
+ /* Constant taken from manufacturer's example */
+ msleep(230);
+
+ ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
+ if (ret < 0)
+ return ret;
+
+ *in_w = (output_w * resize + 512) / 1024;
+ *in_h = (output_h * resize + 512) / 1024;
+ *out_w = output_w;
+ *out_h = output_h;
+
+ dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
+ *in_w, *in_h, resize, output_w, output_h, skip);
+
+ return resize;
+}
+
+static int rj54n1_set_clock(struct i2c_client *client)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ int ret;
+
+ /* Enable external clock */
+ ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
+ /* Leave stand-by. Note: use this when implementing suspend / resume */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
+
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
+
+ /* TGCLK dividers */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RATIO_TG,
+ rj54n1->clk_div.ratio_tg);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RATIO_T,
+ rj54n1->clk_div.ratio_t);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RATIO_R,
+ rj54n1->clk_div.ratio_r);
+
+ /* Enable TGCLK & RAMP */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
+
+ /* Disable clock output */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
+
+ /* Set divisors */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RATIO_OP,
+ rj54n1->clk_div.ratio_op);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RATIO_O,
+ rj54n1->clk_div.ratio_o);
+
+ /* Enable OCLK */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+ /* Use PLL for Timing Generator, write 2 to reserved bits */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
+
+ /* Take sensor out of reset */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESET_STANDBY,
+ E_EXCLK | SEN_RSTX);
+ /* Enable PLL */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_PLL_EN, 1);
+
+ /* Wait for PLL to stabilise */
+ msleep(10);
+
+ /* Enable clock to frequency divider */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_CLK_RST, 1);
+
+ if (!ret)
+ ret = reg_read(client, RJ54N1_CLK_RST);
+ if (ret != 1) {
+ dev_err(&client->dev,
+ "Resetting RJ54N1CB0C clock failed: %d!\n", ret);
+ return -EIO;
+ }
+
+ /* Start the PLL */
+ ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
+
+ /* Enable OCLK */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+ return ret;
+}
+
+static int rj54n1_reg_init(struct i2c_client *client)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ int ret = rj54n1_set_clock(client);
+
+ if (!ret)
+ ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
+ if (!ret)
+ ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
+
+ /* Set binning divisors */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
+ if (!ret)
+ ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
+
+ /* Switch to fixed resize mode */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+ RESIZE_HOLD_SEL | 1);
+
+ /* Set gain */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
+
+ /*
+ * Mirror the image back: default is upside down and left-to-right...
+ * Set manual preview / still shot switching
+ */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
+
+ if (!ret)
+ ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
+
+ /* Auto exposure area */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
+ /* Check current auto WB config */
+ if (!ret)
+ ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
+ if (ret >= 0) {
+ rj54n1->auto_wb = ret & 0x80;
+ ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
+ }
+ if (!ret)
+ ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
+
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESET_STANDBY,
+ E_EXCLK | DSP_RSTX | SEN_RSTX);
+
+ /* Commit init */
+ if (!ret)
+ ret = rj54n1_commit(client);
+
+ /* Take DSP, TG, sensor out of reset */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RESET_STANDBY,
+ E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
+
+ /* Start register update? Same register as 0x?FE in many bank_* sets */
+ if (!ret)
+ ret = reg_write(client, RJ54N1_FWFLG, 2);
+
+ /* Constant taken from manufacturer's example */
+ msleep(700);
+
+ return ret;
+}
+
+static int rj54n1_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ const struct rj54n1_datafmt *fmt;
+ int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
+ mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE ||
+ mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE ||
+ mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE ||
+ mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE;
+
+ dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
+ __func__, mf->code, mf->width, mf->height);
+
+ fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+ ARRAY_SIZE(rj54n1_colour_fmts));
+ if (!fmt) {
+ fmt = rj54n1->fmt;
+ mf->code = fmt->code;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = fmt->colorspace;
+
+ v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
+ &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
+
+ return 0;
+}
+
+static int rj54n1_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ const struct rj54n1_datafmt *fmt;
+ int output_w, output_h, max_w, max_h,
+ input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
+ int ret;
+
+ /*
+ * The host driver can call us without .try_fmt(), so, we have to take
+ * care ourseleves
+ */
+ rj54n1_try_fmt(sd, mf);
+
+ /*
+ * Verify if the sensor has just been powered on. TODO: replace this
+ * with proper PM, when a suitable API is available.
+ */
+ ret = reg_read(client, RJ54N1_RESET_STANDBY);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & E_EXCLK)) {
+ ret = rj54n1_reg_init(client);
+ if (ret < 0)
+ return ret;
+ }
+
+ dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
+ __func__, mf->code, mf->width, mf->height);
+
+ /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+ if (!ret)
+ ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+ if (!ret)
+ ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ ret = reg_write(client, RJ54N1_OUT_SEL, 5);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ /* Special case: a raw mode with 10 bits of data per clock tick */
+ if (!ret)
+ ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
+ (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2);
+
+ if (ret < 0)
+ return ret;
+
+ /* Supported scales 1:1 >= scale > 1:16 */
+ max_w = mf->width * (16 * 1024 - 1) / 1024;
+ if (input_w > max_w)
+ input_w = max_w;
+ max_h = mf->height * (16 * 1024 - 1) / 1024;
+ if (input_h > max_h)
+ input_h = max_h;
+
+ output_w = mf->width;
+ output_h = mf->height;
+
+ ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+ if (ret < 0)
+ return ret;
+
+ fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+ ARRAY_SIZE(rj54n1_colour_fmts));
+
+ rj54n1->fmt = fmt;
+ rj54n1->resize = ret;
+ rj54n1->rect.width = input_w;
+ rj54n1->rect.height = input_h;
+ rj54n1->width = output_w;
+ rj54n1->height = output_h;
+
+ mf->width = output_w;
+ mf->height = output_h;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = fmt->colorspace;
+
+ return 0;
+}
+
+static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = V4L2_IDENT_RJ54N1CB0C;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int rj54n1_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+ reg->reg < 0x400 || reg->reg > 0x1fff)
+ /* Registers > 0x0800 are only available from Sharp support */
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ reg->size = 1;
+ reg->val = reg_read(client, reg->reg);
+
+ if (reg->val > 0xff)
+ return -EIO;
+
+ return 0;
+}
+
+static int rj54n1_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+ reg->reg < 0x400 || reg->reg > 0x1fff)
+ /* Registers >= 0x0800 are only available from Sharp support */
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ if (reg_write(client, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl);
+ struct v4l2_subdev *sd = &rj54n1->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
+ else
+ data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
+ else
+ data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
+ if (data < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_GAIN:
+ if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ /* Auto WB area - whole image */
+ if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7,
+ 0x80) < 0)
+ return -EIO;
+ rj54n1->auto_wb = ctrl->val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
+ .s_ctrl = rj54n1_s_ctrl,
+};
+
+static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
+ .g_chip_ident = rj54n1_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = rj54n1_g_register,
+ .s_register = rj54n1_s_register,
+#endif
+ .s_power = rj54n1_s_power,
+};
+
+static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags =
+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
+ if (soc_camera_apply_board_flags(icl, cfg) &
+ V4L2_MBUS_PCLK_SAMPLE_RISING)
+ return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
+ else
+ return reg_write(client, RJ54N1_OUT_SIGPO, 0);
+}
+
+static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
+ .s_stream = rj54n1_s_stream,
+ .s_mbus_fmt = rj54n1_s_fmt,
+ .g_mbus_fmt = rj54n1_g_fmt,
+ .try_mbus_fmt = rj54n1_try_fmt,
+ .enum_mbus_fmt = rj54n1_enum_fmt,
+ .g_crop = rj54n1_g_crop,
+ .s_crop = rj54n1_s_crop,
+ .cropcap = rj54n1_cropcap,
+ .g_mbus_config = rj54n1_g_mbus_config,
+ .s_mbus_config = rj54n1_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops rj54n1_subdev_ops = {
+ .core = &rj54n1_subdev_core_ops,
+ .video = &rj54n1_subdev_video_ops,
+};
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int rj54n1_video_probe(struct i2c_client *client,
+ struct rj54n1_pdata *priv)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ int data1, data2;
+ int ret;
+
+ ret = rj54n1_s_power(&rj54n1->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Read out the chip version register */
+ data1 = reg_read(client, RJ54N1_DEV_CODE);
+ data2 = reg_read(client, RJ54N1_DEV_CODE2);
+
+ if (data1 != 0x51 || data2 != 0x10) {
+ ret = -ENODEV;
+ dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
+ data1, data2);
+ goto done;
+ }
+
+ /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
+ ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
+ if (ret < 0)
+ goto done;
+
+ dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
+ data1, data2);
+
+ ret = v4l2_ctrl_handler_setup(&rj54n1->hdl);
+
+done:
+ rj54n1_s_power(&rj54n1->subdev, 0);
+ return ret;
+}
+
+static int rj54n1_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct rj54n1 *rj54n1;
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct rj54n1_pdata *rj54n1_priv;
+ int ret;
+
+ if (!icl || !icl->priv) {
+ dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ rj54n1_priv = icl->priv;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+ return -EIO;
+ }
+
+ rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL);
+ if (!rj54n1)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
+ v4l2_ctrl_handler_init(&rj54n1->hdl, 4);
+ v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+ V4L2_CID_GAIN, 0, 127, 1, 66);
+ v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
+ if (rj54n1->hdl.error) {
+ int err = rj54n1->hdl.error;
+
+ kfree(rj54n1);
+ return err;
+ }
+
+ rj54n1->clk_div = clk_div;
+ rj54n1->rect.left = RJ54N1_COLUMN_SKIP;
+ rj54n1->rect.top = RJ54N1_ROW_SKIP;
+ rj54n1->rect.width = RJ54N1_MAX_WIDTH;
+ rj54n1->rect.height = RJ54N1_MAX_HEIGHT;
+ rj54n1->width = RJ54N1_MAX_WIDTH;
+ rj54n1->height = RJ54N1_MAX_HEIGHT;
+ rj54n1->fmt = &rj54n1_colour_fmts[0];
+ rj54n1->resize = 1024;
+ rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
+ (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
+
+ ret = rj54n1_video_probe(client, rj54n1_priv);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&rj54n1->hdl);
+ kfree(rj54n1);
+ }
+
+ return ret;
+}
+
+static int rj54n1_remove(struct i2c_client *client)
+{
+ struct rj54n1 *rj54n1 = to_rj54n1(client);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ v4l2_device_unregister_subdev(&rj54n1->subdev);
+ if (icl->free_bus)
+ icl->free_bus(icl);
+ v4l2_ctrl_handler_free(&rj54n1->hdl);
+ kfree(rj54n1);
+
+ return 0;
+}
+
+static const struct i2c_device_id rj54n1_id[] = {
+ { "rj54n1cb0c", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rj54n1_id);
+
+static struct i2c_driver rj54n1_i2c_driver = {
+ .driver = {
+ .name = "rj54n1cb0c",
+ },
+ .probe = rj54n1_probe,
+ .remove = rj54n1_remove,
+ .id_table = rj54n1_id,
+};
+
+module_i2c_driver(rj54n1_i2c_driver);
+
+MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
new file mode 100644
index 000000000000..140716e71a15
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -0,0 +1,973 @@
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/tw9910.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+#define GET_ID(val) ((val & 0xF8) >> 3)
+#define GET_REV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID 0x00 /* Product ID Code Register */
+#define STATUS1 0x01 /* Chip Status Register I */
+#define INFORM 0x02 /* Input Format */
+#define OPFORM 0x03 /* Output Format Control Register */
+#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1 0x05 /* Output Control I */
+#define ACNTL1 0x06 /* Analog Control Register 1 */
+#define CROP_HI 0x07 /* Cropping Register, High */
+#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */
+#define CNTRL1 0x0C /* Control Register I */
+#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI 0x0E /* Scaling Register, High */
+#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT 0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST 0x11 /* CONTRAST Control Register */
+#define SHARPNESS 0x12 /* SHARPNESS Control Register I */
+#define SAT_U 0x13 /* Chroma (U) Gain Register */
+#define SAT_V 0x14 /* Chroma (V) Gain Register */
+#define HUE 0x15 /* Hue Control Register */
+#define CORING1 0x17
+#define CORING2 0x18 /* Coring and IF compensation */
+#define VBICNTL 0x19 /* VBI Control Register */
+#define ACNTL2 0x1A /* Analog Control 2 */
+#define OUTCTR2 0x1B /* Output Control 2 */
+#define SDT 0x1C /* Standard Selection */
+#define SDTR 0x1D /* Standard Recognition */
+#define TEST 0x1F /* Test Control Register */
+#define CLMPG 0x20 /* Clamping Gain */
+#define IAGC 0x21 /* Individual AGC Gain */
+#define AGCGAIN 0x22 /* AGC Gain */
+#define PEAKWT 0x23 /* White Peak Threshold */
+#define CLMPL 0x24 /* Clamp level */
+#define SYNCT 0x25 /* Sync Amplitude */
+#define MISSCNT 0x26 /* Sync Miss Count Register */
+#define PCLAMP 0x27 /* Clamp Position Register */
+#define VCNTL1 0x28 /* Vertical Control I */
+#define VCNTL2 0x29 /* Vertical Control II */
+#define CKILL 0x2A /* Color Killer Level Control */
+#define COMB 0x2B /* Comb Filter Control */
+#define LDLY 0x2C /* Luma Delay and H Filter Control */
+#define MISC1 0x2D /* Miscellaneous Control I */
+#define LOOP 0x2E /* LOOP Control Register */
+#define MISC2 0x2F /* Miscellaneous Control II */
+#define MVSN 0x30 /* Macrovision Detection */
+#define STATUS2 0x31 /* Chip STATUS II */
+#define HFREF 0x32 /* H monitor */
+#define CLMD 0x33 /* CLAMP MODE */
+#define IDCNTL 0x34 /* ID Detection Control */
+#define CLCNTL1 0x35 /* Clamp Control I */
+#define ANAPLLCTL 0x4C
+#define VBIMIN 0x4D
+#define HSLOWCTL 0x4E
+#define WSS3 0x4F
+#define FILLDATA 0x50
+#define SDID 0x51
+#define DID 0x52
+#define WSS1 0x53
+#define WSS2 0x54
+#define VVBI 0x55
+#define LCTL6 0x56
+#define LCTL7 0x57
+#define LCTL8 0x58
+#define LCTL9 0x59
+#define LCTL10 0x5A
+#define LCTL11 0x5B
+#define LCTL12 0x5C
+#define LCTL13 0x5D
+#define LCTL14 0x5E
+#define LCTL15 0x5F
+#define LCTL16 0x60
+#define LCTL17 0x61
+#define LCTL18 0x62
+#define LCTL19 0x63
+#define LCTL20 0x64
+#define LCTL21 0x65
+#define LCTL22 0x66
+#define LCTL23 0x67
+#define LCTL24 0x68
+#define LCTL25 0x69
+#define LCTL26 0x6A
+#define HSBEGIN 0x6B
+#define HSEND 0x6C
+#define OVSDLY 0x6D
+#define OVSEND 0x6E
+#define VBIDELAY 0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF 0x00 /* 0 : Square pixel mode. */
+ /* Must use 24.54MHz for 60Hz field rate */
+ /* source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S 0x10 /* 01 : S-video decoding */
+#define IFSEL_C 0x00 /* 00 : Composite video decoding */
+ /* Y input video selection */
+#define YSEL_M0 0x00 /* 00 : Mux0 selected */
+#define YSEL_M1 0x04 /* 01 : Mux1 selected */
+#define YSEL_M2 0x08 /* 10 : Mux2 selected */
+#define YSEL_M3 0x10 /* 11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+ /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+ /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE 0x20 /* 1 : LLC output mode. */
+ /* 0 : free-run output mode */
+#define AINC 0x10 /* Serial interface auto-indexing control */
+ /* 0 : auto-increment */
+ /* 1 : non-auto */
+#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */
+ /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN_TRI_SEL_MASK 0x07
+#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */
+#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */
+#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */
+
+/* OUTCTR1 */
+#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */
+ /* VS pin output control */
+#define VSSL_VSYNC 0x00 /* 0 : VSYNC */
+#define VSSL_VACT 0x10 /* 1 : VACT */
+#define VSSL_FIELD 0x20 /* 2 : FIELD */
+#define VSSL_VVALID 0x30 /* 3 : VVALID */
+#define VSSL_ZERO 0x70 /* 7 : 0 */
+#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/
+ /* HS pin output control */
+#define HSSL_HACT 0x00 /* 0 : HACT */
+#define HSSL_HSYNC 0x01 /* 1 : HSYNC */
+#define HSSL_DVALID 0x02 /* 2 : DVALID */
+#define HSSL_HLOCK 0x03 /* 3 : HLOCK */
+#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */
+#define HSSL_ZERO 0x07 /* 7 : 0 */
+
+/* ACNTL1 */
+#define SRESET 0x80 /* resets the device to its default state
+ * but all register content remain unchanged.
+ * This bit is self-resetting.
+ */
+#define ACNTL1_PDN_MASK 0x0e
+#define CLK_PDN 0x08 /* system clock power down */
+#define Y_PDN 0x04 /* Luma ADC power down */
+#define C_PDN 0x02 /* Chroma ADC power down */
+
+/* ACNTL2 */
+#define ACNTL2_PDN_MASK 0x40
+#define PLL_PDN 0x40 /* PLL power down */
+
+/* VBICNTL */
+
+/* RTSEL : control the real time signal output from the MPOUT pin */
+#define RTSEL_MASK 0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO 0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/* HSYNC start and end are constant for now */
+#define HSYNC_START 0x0260
+#define HSYNC_END 0x0300
+
+/*
+ * structure
+ */
+
+struct regval_list {
+ unsigned char reg_num;
+ unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+ char *name;
+ unsigned short width;
+ unsigned short height;
+ u16 hscale;
+ u16 vscale;
+};
+
+struct tw9910_priv {
+ struct v4l2_subdev subdev;
+ struct tw9910_video_info *info;
+ const struct tw9910_scale_ctrl *scale;
+ v4l2_std_id norm;
+ u32 revision;
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+ {
+ .name = "NTSC SQ",
+ .width = 640,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC CCIR601",
+ .width = 720,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC SQ (CIF)",
+ .width = 320,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC CCIR601 (CIF)",
+ .width = 360,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC SQ (QCIF)",
+ .width = 160,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "NTSC CCIR601 (QCIF)",
+ .width = 180,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+ {
+ .name = "PAL SQ",
+ .width = 768,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL CCIR601",
+ .width = 720,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL SQ (CIF)",
+ .width = 384,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL CCIR601 (CIF)",
+ .width = 360,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL SQ (QCIF)",
+ .width = 192,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "PAL CCIR601 (QCIF)",
+ .width = 180,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+/*
+ * general function
+ */
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+ subdev);
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+ u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, command);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static int tw9910_set_scale(struct i2c_client *client,
+ const struct tw9910_scale_ctrl *scale)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+ (scale->vscale & 0x0F00) >> 4 |
+ (scale->hscale & 0x0F00) >> 8);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+ scale->hscale & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+ scale->vscale & 0x00FF);
+
+ return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+ int ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSBEGIN,
+ (HSYNC_START & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSEND,
+ (HSYNC_END & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* So far only revisions 0 and 1 have been seen */
+ /* bit 2 - 0 */
+ if (1 == priv->revision)
+ ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
+ (HSYNC_START & 0x0007) << 4 |
+ (HSYNC_END & 0x0007));
+
+ return ret;
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+ tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
+ msleep(1);
+}
+
+static int tw9910_power(struct i2c_client *client, int enable)
+{
+ int ret;
+ u8 acntl1;
+ u8 acntl2;
+
+ if (enable) {
+ acntl1 = 0;
+ acntl2 = 0;
+ } else {
+ acntl1 = CLK_PDN | Y_PDN | C_PDN;
+ acntl2 = PLL_PDN;
+ }
+
+ ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
+ if (ret < 0)
+ return ret;
+
+ return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
+}
+
+static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
+ u32 width, u32 height)
+{
+ const struct tw9910_scale_ctrl *scale;
+ const struct tw9910_scale_ctrl *ret = NULL;
+ __u32 diff = 0xffffffff, tmp;
+ int size, i;
+
+ if (norm & V4L2_STD_NTSC) {
+ scale = tw9910_ntsc_scales;
+ size = ARRAY_SIZE(tw9910_ntsc_scales);
+ } else if (norm & V4L2_STD_PAL) {
+ scale = tw9910_pal_scales;
+ size = ARRAY_SIZE(tw9910_pal_scales);
+ } else {
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ tmp = abs(width - scale[i].width) +
+ abs(height - scale[i].height);
+ if (tmp < diff) {
+ diff = tmp;
+ ret = scale + i;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * subdevice operations
+ */
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ u8 val;
+ int ret;
+
+ if (!enable) {
+ switch (priv->revision) {
+ case 0:
+ val = OEN_TRI_SEL_ALL_OFF_r0;
+ break;
+ case 1:
+ val = OEN_TRI_SEL_ALL_OFF_r1;
+ break;
+ default:
+ dev_err(&client->dev, "un-supported revision\n");
+ return -EINVAL;
+ }
+ } else {
+ val = OEN_TRI_SEL_ALL_ON;
+
+ if (!priv->scale) {
+ dev_err(&client->dev, "norm select error\n");
+ return -EPERM;
+ }
+
+ dev_dbg(&client->dev, "%s %dx%d\n",
+ priv->scale->name,
+ priv->scale->width,
+ priv->scale->height);
+ }
+
+ ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return tw9910_power(client, enable);
+}
+
+static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ *norm = priv->norm;
+
+ return 0;
+}
+
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+ return -EINVAL;
+
+ priv->norm = norm;
+
+ return 0;
+}
+
+static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ id->ident = V4L2_IDENT_TW9910;
+ id->revision = priv->revision;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * ret = int
+ * reg->val = __u64
+ */
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int tw9910_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ return soc_camera_set_power(&client->dev, icl, on);
+}
+
+static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ int ret = -EINVAL;
+ u8 val;
+
+ /*
+ * select suitable norm
+ */
+ priv->scale = tw9910_select_norm(priv->norm, *width, *height);
+ if (!priv->scale)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * reset hardware
+ */
+ tw9910_reset(client);
+
+ /*
+ * set bus width
+ */
+ val = 0x00;
+ if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
+ val = LEN;
+
+ ret = tw9910_mask_set(client, OPFORM, LEN, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * select MPOUT behavior
+ */
+ switch (priv->info->mpout) {
+ case TW9910_MPO_VLOSS:
+ val = RTSEL_VLOSS; break;
+ case TW9910_MPO_HLOCK:
+ val = RTSEL_HLOCK; break;
+ case TW9910_MPO_SLOCK:
+ val = RTSEL_SLOCK; break;
+ case TW9910_MPO_VLOCK:
+ val = RTSEL_VLOCK; break;
+ case TW9910_MPO_MONO:
+ val = RTSEL_MONO; break;
+ case TW9910_MPO_DET50:
+ val = RTSEL_DET50; break;
+ case TW9910_MPO_FIELD:
+ val = RTSEL_FIELD; break;
+ case TW9910_MPO_RTCO:
+ val = RTSEL_RTCO; break;
+ default:
+ val = 0;
+ }
+
+ ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set scale
+ */
+ ret = tw9910_set_scale(client, priv->scale);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /*
+ * set hsync
+ */
+ ret = tw9910_set_hsync(client);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ *width = priv->scale->width;
+ *height = priv->scale->height;
+
+ return ret;
+
+tw9910_set_fmt_error:
+
+ tw9910_reset(client);
+ priv->scale = NULL;
+
+ return ret;
+}
+
+static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ a->c.left = 0;
+ a->c.top = 0;
+ if (priv->norm & V4L2_STD_NTSC) {
+ a->c.width = 640;
+ a->c.height = 480;
+ } else {
+ a->c.width = 768;
+ a->c.height = 576;
+ }
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ if (priv->norm & V4L2_STD_NTSC) {
+ a->bounds.width = 640;
+ a->bounds.height = 480;
+ } else {
+ a->bounds.width = 768;
+ a->bounds.height = 576;
+ }
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int tw9910_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (!priv->scale) {
+ priv->scale = tw9910_select_norm(priv->norm, 640, 480);
+ if (!priv->scale)
+ return -EINVAL;
+ }
+
+ mf->width = priv->scale->width;
+ mf->height = priv->scale->height;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ mf->field = V4L2_FIELD_INTERLACED_BT;
+
+ return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ u32 width = mf->width, height = mf->height;
+ int ret;
+
+ WARN_ON(mf->field != V4L2_FIELD_ANY &&
+ mf->field != V4L2_FIELD_INTERLACED_BT);
+
+ /*
+ * check color format
+ */
+ if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
+ return -EINVAL;
+
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ ret = tw9910_set_frame(sd, &width, &height);
+ if (!ret) {
+ mf->width = width;
+ mf->height = height;
+ }
+ return ret;
+}
+
+static int tw9910_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ const struct tw9910_scale_ctrl *scale;
+
+ if (V4L2_FIELD_ANY == mf->field) {
+ mf->field = V4L2_FIELD_INTERLACED_BT;
+ } else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
+ dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
+ return -EINVAL;
+ }
+
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ /*
+ * select suitable norm
+ */
+ scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
+ if (!scale)
+ return -EINVAL;
+
+ mf->width = scale->width;
+ mf->height = scale->height;
+
+ return 0;
+}
+
+static int tw9910_video_probe(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+ s32 id;
+ int ret;
+
+ /*
+ * tw9910 only use 8 or 16 bit bus width
+ */
+ if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
+ SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
+ dev_err(&client->dev, "bus width error\n");
+ return -ENODEV;
+ }
+
+ ret = tw9910_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * check and show Product ID
+ * So far only revisions 0 and 1 have been seen
+ */
+ id = i2c_smbus_read_byte_data(client, ID);
+ priv->revision = GET_REV(id);
+ id = GET_ID(id);
+
+ if (0x0B != id ||
+ 0x01 < priv->revision) {
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n",
+ id, priv->revision);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev,
+ "tw9910 Product ID %0x:%0x\n", id, priv->revision);
+
+ priv->norm = V4L2_STD_NTSC;
+
+done:
+ tw9910_s_power(&priv->subdev, 0);
+ return ret;
+}
+
+static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+ .g_chip_ident = tw9910_g_chip_ident,
+ .s_std = tw9910_s_std,
+ .g_std = tw9910_g_std,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = tw9910_g_register,
+ .s_register = tw9910_s_register,
+#endif
+ .s_power = tw9910_s_power,
+};
+
+static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ return 0;
+}
+
+static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+
+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_PARALLEL;
+ cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+
+ return 0;
+}
+
+static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
+ const struct v4l2_mbus_config *cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ u8 val = VSSL_VVALID | HSSL_DVALID;
+ unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+
+ /*
+ * set OUTCTR1
+ *
+ * We use VVALID and DVALID signals to control VSYNC and HSYNC
+ * outputs, in this mode their polarity is inverted.
+ */
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ val |= HSP_HI;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ val |= VSP_HI;
+
+ return i2c_smbus_write_byte_data(client, OUTCTR1, val);
+}
+
+static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+ .s_stream = tw9910_s_stream,
+ .g_mbus_fmt = tw9910_g_fmt,
+ .s_mbus_fmt = tw9910_s_fmt,
+ .try_mbus_fmt = tw9910_try_fmt,
+ .cropcap = tw9910_cropcap,
+ .g_crop = tw9910_g_crop,
+ .enum_mbus_fmt = tw9910_enum_fmt,
+ .g_mbus_config = tw9910_g_mbus_config,
+ .s_mbus_config = tw9910_s_mbus_config,
+};
+
+static struct v4l2_subdev_ops tw9910_subdev_ops = {
+ .core = &tw9910_subdev_core_ops,
+ .video = &tw9910_subdev_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int tw9910_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+
+{
+ struct tw9910_priv *priv;
+ struct tw9910_video_info *info;
+ struct i2c_adapter *adapter =
+ to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ int ret;
+
+ if (!icl || !icl->priv) {
+ dev_err(&client->dev, "TW9910: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ info = icl->priv;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "I2C-Adapter doesn't support "
+ "I2C_FUNC_SMBUS_BYTE_DATA\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = info;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
+ ret = tw9910_video_probe(client);
+ if (ret)
+ kfree(priv);
+
+ return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id tw9910_id[] = {
+ { "tw9910", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+static struct i2c_driver tw9910_i2c_driver = {
+ .driver = {
+ .name = "tw9910",
+ },
+ .probe = tw9910_probe,
+ .remove = tw9910_remove,
+ .id_table = tw9910_id,
+};
+
+module_i2c_driver(tw9910_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for tw9910");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index e9d95bda2ab1..e9d95bda2ab1 100644
--- a/drivers/media/video/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
diff --git a/drivers/media/i2c/tcm825x.c b/drivers/media/i2c/tcm825x.c
new file mode 100644
index 000000000000..9252529fc5dd
--- /dev/null
+++ b/drivers/media/i2c/tcm825x.c
@@ -0,0 +1,937 @@
+/*
+ * drivers/media/i2c/tcm825x.c
+ *
+ * TCM825X camera sensor driver.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from David Cohen <david.cohen@indt.org.br>
+ *
+ * This driver was based on ov9640 sensor driver from MontaVista
+ *
+ * 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/i2c.h>
+#include <linux/module.h>
+#include <media/v4l2-int-device.h>
+
+#include "tcm825x.h"
+
+/*
+ * The sensor has two fps modes: the lower one just gives half the fps
+ * at the same xclk than the high one.
+ */
+#define MAX_FPS 30
+#define MIN_FPS 8
+#define MAX_HALF_FPS (MAX_FPS / 2)
+#define HIGH_FPS_MODE_LOWER_LIMIT 14
+#define DEFAULT_FPS MAX_HALF_FPS
+
+struct tcm825x_sensor {
+ const struct tcm825x_platform_data *platform_data;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe;
+};
+
+/* list of image formats supported by TCM825X sensor */
+static const struct v4l2_fmtdesc tcm825x_formats[] = {
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ }, {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+};
+
+#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
+
+/*
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
+static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
+static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
+static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
+static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
+static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
+
+static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
+static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
+
+/* Our own specific controls */
+#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
+#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
+#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
+
+/* Video controls */
+static struct vcontrol {
+ struct v4l2_queryctrl qc;
+ u16 reg;
+ u16 start_bit;
+} video_control[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ },
+ .reg = TCM825X_AG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MRG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MBG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_AWBSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure Time",
+ .minimum = 0,
+ .maximum = 0x1fff,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRSPD_U,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_H_INV,
+ .start_bit = 6,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_V_INV,
+ .start_bit = 7,
+ },
+ /* Private controls */
+ {
+ {
+ .id = V4L2_CID_ALC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Luminance Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_ALCSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_H_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_HDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_V_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_VDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_LENS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Lens Shading Compensation",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ },
+ .reg = TCM825X_LENS,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_MAX_EXPOSURE_TIME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Maximum Exposure Time",
+ .minimum = 0,
+ .maximum = 0x3,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRLIM,
+ .start_bit = 5,
+ },
+};
+
+
+static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+{ &yuv422, &rgb565 };
+
+/*
+ * Read a value from a register in an TCM825X sensor device. The value is
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_read_reg(struct i2c_client *client, int reg)
+{
+ int err;
+ struct i2c_msg msg[2];
+ u8 reg_buf, data_buf = 0;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &reg_buf;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = &data_buf;
+
+ reg_buf = reg;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err < 0)
+ return err;
+ return data_buf;
+}
+
+/*
+ * Write a value to a register in an TCM825X sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 2;
+ msg->buf = data;
+ data[0] = reg;
+ data[1] = val;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+static int __tcm825x_write_reg_mask(struct i2c_client *client,
+ u8 reg, u8 val, u8 mask)
+{
+ int rc;
+
+ /* need to do read - modify - write */
+ rc = tcm825x_read_reg(client, reg);
+ if (rc < 0)
+ return rc;
+
+ rc &= (~mask); /* Clear the masked bits */
+ val &= mask; /* Enforce mask on value */
+ val |= rc;
+
+ /* write the new value to the register */
+ rc = tcm825x_write_reg(client, reg, val);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+#define tcm825x_write_reg_mask(client, regmask, val) \
+ __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
+ TCM825X_MASK((regmask)))
+
+
+/*
+ * Initialize a list of TCM825X registers.
+ * The list of registers is terminated by the pair of values
+ * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_default_regs(struct i2c_client *client,
+ const struct tcm825x_reg *reglist)
+{
+ int err;
+ const struct tcm825x_reg *next = reglist;
+
+ while (!((next->reg == TCM825X_REG_TERM)
+ && (next->val == TCM825X_VAL_TERM))) {
+ err = tcm825x_write_reg(client, next->reg, next->val);
+ if (err) {
+ dev_err(&client->dev, "register writing failed\n");
+ return err;
+ }
+ next++;
+ }
+
+ return 0;
+}
+
+static struct vcontrol *find_vctrl(int id)
+{
+ int i;
+
+ if (id < V4L2_CID_BASE)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(video_control); i++)
+ if (video_control[i].qc.id == id)
+ return &video_control[i];
+
+ return NULL;
+}
+
+/*
+ * Find the best match for a requested image capture size. The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
+ unsigned int width,
+ unsigned int height)
+{
+ enum image_size isize;
+ unsigned long pixels = width * height;
+ struct tcm825x_sensor *sensor = s->priv;
+
+ for (isize = subQCIF; isize < VGA; isize++) {
+ if (tcm825x_sizes[isize + 1].height
+ * tcm825x_sizes[isize + 1].width > pixels) {
+ dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
+
+ return isize;
+ }
+ }
+
+ dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
+
+ return VGA;
+}
+
+/*
+ * Configure the TCM825X for current image size, pixel format, and
+ * frame period. fper is the frame period (in seconds) expressed as a
+ * fraction. Returns zero if successful, or non-zero otherwise. The
+ * actual frame period is returned in fper.
+ */
+static int tcm825x_configure(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
+ struct v4l2_fract *fper = &sensor->timeperframe;
+ enum pixel_format pfmt;
+ int err;
+ u32 tgt_fps;
+ u8 val;
+
+ /* common register initialization */
+ err = tcm825x_write_default_regs(
+ sensor->i2c_client, sensor->platform_data->default_regs());
+ if (err)
+ return err;
+
+ /* configure image size */
+ val = tcm825x_siz_reg[isize]->val;
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring image size %d\n", isize);
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_siz_reg[isize]->reg, val);
+ if (err)
+ return err;
+
+ /* configure pixel format */
+ switch (pix->pixelformat) {
+ default:
+ case V4L2_PIX_FMT_RGB565:
+ pfmt = RGB565;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ pfmt = YUV422;
+ break;
+ }
+
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring pixel format %d\n", pfmt);
+ val = tcm825x_fmt_reg[pfmt]->val;
+
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_fmt_reg[pfmt]->reg, val);
+ if (err)
+ return err;
+
+ /*
+ * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
+ * set. Frame rate will be halved from the normal.
+ */
+ tgt_fps = fper->denominator / fper->numerator;
+ if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
+ val = tcm825x_read_reg(sensor->i2c_client, 0x02);
+ val |= 0x80;
+ tcm825x_write_reg(sensor->i2c_client, 0x02, val);
+ }
+
+ return 0;
+}
+
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ struct vcontrol *control;
+
+ control = find_vctrl(qc->id);
+
+ if (control == NULL)
+ return -EINVAL;
+
+ *qc = control->qc;
+
+ return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int val, r;
+ struct vcontrol *lvc;
+
+ /* exposure time is special, spread across 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+
+ val_upper = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_U));
+ if (val_upper < 0)
+ return val_upper;
+ val_lower = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_L));
+ if (val_lower < 0)
+ return val_lower;
+
+ vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
+ if (r < 0)
+ return r;
+ val = r & TCM825X_MASK(lvc->reg);
+ val >>= lvc->start_bit;
+
+ if (val < 0)
+ return val;
+
+ if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+ val ^= sensor->platform_data->is_upside_down();
+
+ vc->value = val;
+ return 0;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ struct vcontrol *lvc;
+ int val = vc->value;
+
+ /* exposure time is special, spread across 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+ val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
+ val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_U, val_upper))
+ return -EIO;
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_L, val_lower))
+ return -EIO;
+
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+ val ^= sensor->platform_data->is_upside_down();
+
+ val = val << lvc->start_bit;
+ if (tcm825x_write_reg_mask(client, lvc->reg, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (index >= TCM825X_NUM_CAPTURE_FORMATS)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ fmt->flags = tcm825x_formats[index].flags;
+ strlcpy(fmt->description, tcm825x_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = tcm825x_formats[index].pixelformat;
+
+ return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ enum image_size isize;
+ int ifmt;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ isize = tcm825x_find_size(s, pix->width, pix->height);
+ dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
+ isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
+
+ pix->width = tcm825x_sizes[isize].width;
+ pix->height = tcm825x_sizes[isize].height;
+
+ for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
+ if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
+ break;
+
+ if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
+ ifmt = 0; /* Default = YUV 4:2:2 */
+
+ pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+ dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
+ pix->pixelformat);
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int rval;
+
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ rval = tcm825x_configure(s);
+
+ sensor->pix = *pix;
+
+ return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe = sensor->timeperframe;
+
+ return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if ((timeperframe->numerator == 0)
+ || (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ sensor->timeperframe = *timeperframe;
+
+ rval = tcm825x_configure(s);
+
+ return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->power_set(on);
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency.
+ *
+ * TCM825X input frequency characteristics are:
+ * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
+ */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &sensor->timeperframe;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ rval = sensor->platform_data->ifparm(p);
+ if (rval)
+ return rval;
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
+ (2457 * tgt_fps) / MAX_HALF_FPS :
+ (2457 * tgt_fps) / MAX_FPS;
+ tgt_xclk *= 10000;
+
+ tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
+
+ p->u.bt656.clock_curr = tgt_xclk;
+
+ return 0;
+}
+
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
+}
+
+static int ioctl_reset(struct v4l2_int_device *s)
+{
+ return -EBUSY;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ return tcm825x_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ int r;
+
+ r = tcm825x_read_reg(sensor->i2c_client, 0x01);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(&sensor->i2c_client->dev, "device not detected\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_exit },
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+ { vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
+ { vidioc_int_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_reset },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+ { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+ { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+ { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_queryctrl },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave tcm825x_slave = {
+ .ioctls = tcm825x_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
+};
+
+static struct tcm825x_sensor tcm825x;
+
+static struct v4l2_int_device tcm825x_int_device = {
+ .module = THIS_MODULE,
+ .name = TCM825X_NAME,
+ .priv = &tcm825x,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &tcm825x_slave,
+ },
+};
+
+static int tcm825x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct tcm825x_sensor *sensor = &tcm825x;
+
+ if (i2c_get_clientdata(client))
+ return -EBUSY;
+
+ sensor->platform_data = client->dev.platform_data;
+
+ if (sensor->platform_data == NULL
+ || !sensor->platform_data->is_okay())
+ return -ENODEV;
+
+ sensor->v4l2_int_device = &tcm825x_int_device;
+
+ sensor->i2c_client = client;
+ i2c_set_clientdata(client, sensor);
+
+ /* Make the default capture format QVGA RGB565 */
+ sensor->pix.width = tcm825x_sizes[QVGA].width;
+ sensor->pix.height = tcm825x_sizes[QVGA].height;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+ return v4l2_int_device_register(sensor->v4l2_int_device);
+}
+
+static int tcm825x_remove(struct i2c_client *client)
+{
+ struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(sensor->v4l2_int_device);
+
+ return 0;
+}
+
+static const struct i2c_device_id tcm825x_id[] = {
+ { "tcm825x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tcm825x_id);
+
+static struct i2c_driver tcm825x_i2c_driver = {
+ .driver = {
+ .name = TCM825X_NAME,
+ },
+ .probe = tcm825x_probe,
+ .remove = tcm825x_remove,
+ .id_table = tcm825x_id,
+};
+
+static struct tcm825x_sensor tcm825x = {
+ .timeperframe = {
+ .numerator = 1,
+ .denominator = DEFAULT_FPS,
+ },
+};
+
+static int __init tcm825x_init(void)
+{
+ int rval;
+
+ rval = i2c_add_driver(&tcm825x_i2c_driver);
+ if (rval)
+ printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
+ __func__);
+
+ return rval;
+}
+
+static void __exit tcm825x_exit(void)
+{
+ i2c_del_driver(&tcm825x_i2c_driver);
+}
+
+/*
+ * FIXME: Menelaus isn't ready (?) at module_init stage, so use
+ * late_initcall for now.
+ */
+late_initcall(tcm825x_init);
+module_exit(tcm825x_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("TCM825x camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tcm825x.h b/drivers/media/i2c/tcm825x.h
new file mode 100644
index 000000000000..8ebab953963f
--- /dev/null
+++ b/drivers/media/i2c/tcm825x.h
@@ -0,0 +1,200 @@
+/*
+ * drivers/media/i2c/tcm825x.h
+ *
+ * Register definitions for the TCM825X CameraChip.
+ *
+ * Author: David Cohen (david.cohen@indt.org.br)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file was based on ov9640.h from MontaVista
+ */
+
+#ifndef TCM825X_H
+#define TCM825X_H
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#define TCM825X_NAME "tcm825x"
+
+#define TCM825X_MASK(x) x & 0x00ff
+#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+
+/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
+#define TCM825X_I2C_ADDR 0x3d
+
+/*
+ * define register offsets for the TCM825X sensor chip
+ * OFFSET(8 bits) + MASK(8 bits)
+ * MASK bit 4 and 3 are used when the register uses more than one address
+ */
+#define TCM825X_FPS 0x0280
+#define TCM825X_ACF 0x0240
+#define TCM825X_DOUTBUF 0x020C
+#define TCM825X_DCLKP 0x0202
+#define TCM825X_ACFDET 0x0201
+#define TCM825X_DOUTSW 0x0380
+#define TCM825X_DATAHZ 0x0340
+#define TCM825X_PICSIZ 0x033c
+#define TCM825X_PICFMT 0x0302
+#define TCM825X_V_INV 0x0480
+#define TCM825X_H_INV 0x0440
+#define TCM825X_ESRLSW 0x0430
+#define TCM825X_V_LENGTH 0x040F
+#define TCM825X_ALCSW 0x0580
+#define TCM825X_ESRLIM 0x0560
+#define TCM825X_ESRSPD_U 0x051F
+#define TCM825X_ESRSPD_L 0x06FF
+#define TCM825X_AG 0x07FF
+#define TCM825X_ESRSPD2 0x06FF
+#define TCM825X_ALCMODE 0x0830
+#define TCM825X_ALCH 0x080F
+#define TCM825X_ALCL 0x09FF
+#define TCM825X_AWBSW 0x0A80
+#define TCM825X_MRG 0x0BFF
+#define TCM825X_MBG 0x0CFF
+#define TCM825X_GAMSW 0x0D80
+#define TCM825X_HDTG 0x0EFF
+#define TCM825X_VDTG 0x0FFF
+#define TCM825X_HDTCORE 0x10F0
+#define TCM825X_VDTCORE 0x100F
+#define TCM825X_CONT 0x11FF
+#define TCM825X_BRIGHT 0x12FF
+#define TCM825X_VHUE 0x137F
+#define TCM825X_UHUE 0x147F
+#define TCM825X_VGAIN 0x153F
+#define TCM825X_UGAIN 0x163F
+#define TCM825X_UVCORE 0x170F
+#define TCM825X_SATU 0x187F
+#define TCM825X_MHMODE 0x1980
+#define TCM825X_MHLPFSEL 0x1940
+#define TCM825X_YMODE 0x1930
+#define TCM825X_MIXHG 0x1907
+#define TCM825X_LENS 0x1A3F
+#define TCM825X_AGLIM 0x1BE0
+#define TCM825X_LENSRPOL 0x1B10
+#define TCM825X_LENSRGAIN 0x1B0F
+#define TCM825X_ES100S 0x1CFF
+#define TCM825X_ES120S 0x1DFF
+#define TCM825X_DMASK 0x1EC0
+#define TCM825X_CODESW 0x1E20
+#define TCM825X_CODESEL 0x1E10
+#define TCM825X_TESPIC 0x1E04
+#define TCM825X_PICSEL 0x1E03
+#define TCM825X_HNUM 0x20FF
+#define TCM825X_VOUTPH 0x287F
+#define TCM825X_ESROUT 0x327F
+#define TCM825X_ESROUT2 0x33FF
+#define TCM825X_AGOUT 0x34FF
+#define TCM825X_DGOUT 0x353F
+#define TCM825X_AGSLOW1 0x39C0
+#define TCM825X_FLLSMODE 0x3930
+#define TCM825X_FLLSLIM 0x390F
+#define TCM825X_DETSEL 0x3AF0
+#define TCM825X_ACDETNC 0x3A0F
+#define TCM825X_AGSLOW2 0x3BC0
+#define TCM825X_DG 0x3B3F
+#define TCM825X_REJHLEV 0x3CFF
+#define TCM825X_ALCLOCK 0x3D80
+#define TCM825X_FPSLNKSW 0x3D40
+#define TCM825X_ALCSPD 0x3D30
+#define TCM825X_REJH 0x3D03
+#define TCM825X_SHESRSW 0x3E80
+#define TCM825X_ESLIMSEL 0x3E40
+#define TCM825X_SHESRSPD 0x3E30
+#define TCM825X_ELSTEP 0x3E0C
+#define TCM825X_ELSTART 0x3E03
+#define TCM825X_AGMIN 0x3FFF
+#define TCM825X_PREGRG 0x423F
+#define TCM825X_PREGBG 0x433F
+#define TCM825X_PRERG 0x443F
+#define TCM825X_PREBG 0x453F
+#define TCM825X_MSKBR 0x477F
+#define TCM825X_MSKGR 0x487F
+#define TCM825X_MSKRB 0x497F
+#define TCM825X_MSKGB 0x4A7F
+#define TCM825X_MSKRG 0x4B7F
+#define TCM825X_MSKBG 0x4C7F
+#define TCM825X_HDTCSW 0x4D80
+#define TCM825X_VDTCSW 0x4D40
+#define TCM825X_DTCYL 0x4D3F
+#define TCM825X_HDTPSW 0x4E80
+#define TCM825X_VDTPSW 0x4E40
+#define TCM825X_DTCGAIN 0x4E3F
+#define TCM825X_DTLLIMSW 0x4F10
+#define TCM825X_DTLYLIM 0x4F0F
+#define TCM825X_YLCUTLMSK 0x5080
+#define TCM825X_YLCUTL 0x503F
+#define TCM825X_YLCUTHMSK 0x5180
+#define TCM825X_YLCUTH 0x513F
+#define TCM825X_UVSKNC 0x527F
+#define TCM825X_UVLJ 0x537F
+#define TCM825X_WBGMIN 0x54FF
+#define TCM825X_WBGMAX 0x55FF
+#define TCM825X_WBSPDUP 0x5603
+#define TCM825X_ALLAREA 0x5820
+#define TCM825X_WBLOCK 0x5810
+#define TCM825X_WB2SP 0x580F
+#define TCM825X_KIZUSW 0x5920
+#define TCM825X_PBRSW 0x5910
+#define TCM825X_ABCSW 0x5903
+#define TCM825X_PBDLV 0x5AFF
+#define TCM825X_PBC1LV 0x5BFF
+
+#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
+
+#define TCM825X_BYTES_PER_PIXEL 2
+
+#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
+#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
+
+/* define a structure for tcm825x register initialization values */
+struct tcm825x_reg {
+ u8 val;
+ u16 reg;
+};
+
+enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
+enum pixel_format { YUV422 = 0, RGB565 };
+#define NUM_IMAGE_SIZES 6
+#define NUM_PIXEL_FORMATS 2
+
+#define TCM825X_XCLK_MIN 11900000
+#define TCM825X_XCLK_MAX 25000000
+
+struct capture_size {
+ unsigned long width;
+ unsigned long height;
+};
+
+struct tcm825x_platform_data {
+ /* Is the sensor usable? Doesn't yet mean it's there, but you
+ * can try! */
+ int (*is_okay)(void);
+ /* Set power state, zero is off, non-zero is on. */
+ int (*power_set)(int power);
+ /* Default registers written after power-on or reset. */
+ const struct tcm825x_reg *(*default_regs)(void);
+ int (*needs_reset)(struct v4l2_int_device *s, void *buf,
+ struct v4l2_pix_format *fmt);
+ int (*ifparm)(struct v4l2_ifparm *p);
+ int (*is_upside_down)(void);
+};
+
+/* Array of image sizes supported by TCM825X. These must be ordered from
+ * smallest image size to largest.
+ */
+static const struct capture_size tcm825x_sizes[] = {
+ { 128, 96 }, /* subQCIF */
+ { 160, 120 }, /* QQVGA */
+ { 176, 144 }, /* QCIF */
+ { 320, 240 }, /* QVGA */
+ { 352, 288 }, /* CIF */
+ { 640, 480 }, /* VGA */
+};
+
+#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/video/tda7432.c b/drivers/media/i2c/tda7432.c
index f7707e65761e..f7707e65761e 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
diff --git a/drivers/media/video/tda9840.c b/drivers/media/i2c/tda9840.c
index 3d7ddd93282d..3d7ddd93282d 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/i2c/tda9840.c
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/i2c/tea6415c.c
index d1d6ea1dd273..d1d6ea1dd273 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/i2c/tea6415c.c
diff --git a/drivers/media/video/tea6415c.h b/drivers/media/i2c/tea6415c.h
index 3a47d697536e..3a47d697536e 100644
--- a/drivers/media/video/tea6415c.h
+++ b/drivers/media/i2c/tea6415c.h
diff --git a/drivers/media/video/tea6420.c b/drivers/media/i2c/tea6420.c
index 38757217a074..38757217a074 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/i2c/tea6420.c
diff --git a/drivers/media/video/tea6420.h b/drivers/media/i2c/tea6420.h
index 4aa3edb3e193..4aa3edb3e193 100644
--- a/drivers/media/video/tea6420.h
+++ b/drivers/media/i2c/tea6420.h
diff --git a/drivers/media/video/ths7303.c b/drivers/media/i2c/ths7303.c
index e5c0eedebc58..e5c0eedebc58 100644
--- a/drivers/media/video/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c
index 809a75a558ee..809a75a558ee 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/i2c/tlv320aic23b.c
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 321b3153df87..321b3153df87 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/i2c/tveeprom.c
index 3b6cf034976a..3b6cf034976a 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/i2c/tveeprom.c
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
new file mode 100644
index 000000000000..1f3943bb87d5
--- /dev/null
+++ b/drivers/media/i2c/tvp514x.c
@@ -0,0 +1,1166 @@
+/*
+ * drivers/media/i2c/tvp514x.c
+ *
+ * TI TVP5146/47 decoder driver
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ * Sivaraj R <sivaraj@ti.com>
+ * Brijesh R Jadav <brijesh.j@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/tvp514x.h>
+
+#include "tvp514x_regs.h"
+
+/* Module Name */
+#define TVP514X_MODULE_NAME "tvp514x"
+
+/* Private macros for TVP */
+#define I2C_RETRY_COUNT (5)
+#define LOCK_RETRY_COUNT (5)
+#define LOCK_RETRY_DELAY (200)
+
+/* Debug functions */
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
+
+/* enum tvp514x_std - enum for supported standards */
+enum tvp514x_std {
+ STD_NTSC_MJ = 0,
+ STD_PAL_BDGHIN,
+ STD_INVALID
+};
+
+/**
+ * struct tvp514x_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @video_std: Value to write in REG_VIDEO_STD register
+ * @standard: v4l2 standard structure information
+ */
+struct tvp514x_std_info {
+ unsigned long width;
+ unsigned long height;
+ u8 video_std;
+ struct v4l2_standard standard;
+};
+
+static struct tvp514x_reg tvp514x_reg_list_default[0x40];
+
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
+/**
+ * struct tvp514x_decoder - TVP5146/47 decoder object
+ * @sd: Subdevice Slave handle
+ * @tvp514x_regs: copy of hw's regs with preset values.
+ * @pdata: Board specific
+ * @ver: Chip version
+ * @streaming: TVP5146/47 decoder streaming - enabled or disabled.
+ * @current_std: Current standard
+ * @num_stds: Number of standards
+ * @std_list: Standards list
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
+ */
+struct tvp514x_decoder {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
+ const struct tvp514x_platform_data *pdata;
+
+ int ver;
+ int streaming;
+
+ enum tvp514x_std current_std;
+ int num_stds;
+ const struct tvp514x_std_info *std_list;
+ /* Input and Output Routing parameters */
+ u32 input;
+ u32 output;
+};
+
+/* TVP514x default register values */
+static struct tvp514x_reg tvp514x_reg_list_default[] = {
+ /* Composite selected */
+ {TOK_WRITE, REG_INPUT_SEL, 0x05},
+ {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
+ /* Auto mode */
+ {TOK_WRITE, REG_VIDEO_STD, 0x00},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
+ {TOK_WRITE, REG_COLOR_KILLER, 0x10},
+ {TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
+ {TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
+ {TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
+ {TOK_WRITE, REG_BRIGHTNESS, 0x80},
+ {TOK_WRITE, REG_CONTRAST, 0x80},
+ {TOK_WRITE, REG_SATURATION, 0x80},
+ {TOK_WRITE, REG_HUE, 0x00},
+ {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
+ {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
+ /* Reserved */
+ {TOK_SKIP, 0x0F, 0x00},
+ {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
+ {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
+ {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
+ /* Reserved */
+ {TOK_SKIP, 0x13, 0x00},
+ {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
+ /* Reserved */
+ {TOK_SKIP, 0x15, 0x00},
+ /* NTSC timing */
+ {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},
+ {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
+ {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
+ {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
+ /* NTSC timing */
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
+ {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
+ {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
+ /* NTSC timing */
+ {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
+ {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
+ {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
+ {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
+ /* NTSC timing */
+ {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
+ {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
+ {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
+ {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x26, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x27, 0x00},
+ {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
+ /* Reserved */
+ {TOK_SKIP, 0x29, 0x00},
+ {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x2B, 0x00},
+ {TOK_SKIP, REG_SCART_DELAY, 0x00},
+ {TOK_SKIP, REG_CTI_DELAY, 0x00},
+ {TOK_SKIP, REG_CTI_CONTROL, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x2F, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x30, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x31, 0x00},
+ /* HS, VS active high */
+ {TOK_WRITE, REG_SYNC_CONTROL, 0x00},
+ /* 10-bit BT.656 */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},
+ /* Enable clk & data */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
+ /* Enable AVID & FLD */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
+ /* Enable VS & HS */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
+ {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
+ {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
+ /* Clear status */
+ {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
+ {TOK_TERM, 0, 0},
+};
+
+/**
+ * Supported standards -
+ *
+ * Currently supports two standards only, need to add support for rest of the
+ * modes, like SECAM, etc...
+ */
+static const struct tvp514x_std_info tvp514x_std_list[] = {
+ /* Standard: STD_NTSC_MJ */
+ [STD_NTSC_MJ] = {
+ .width = NTSC_NUM_ACTIVE_PIXELS,
+ .height = NTSC_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STD_NTSC_MJ_BIT,
+ .standard = {
+ .index = 0,
+ .id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .frameperiod = {1001, 30000},
+ .framelines = 525
+ },
+ /* Standard: STD_PAL_BDGHIN */
+ },
+ [STD_PAL_BDGHIN] = {
+ .width = PAL_NUM_ACTIVE_PIXELS,
+ .height = PAL_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STD_PAL_BDGHIN_BIT,
+ .standard = {
+ .index = 1,
+ .id = V4L2_STD_PAL,
+ .name = "PAL",
+ .frameperiod = {1, 25},
+ .framelines = 625
+ },
+ },
+ /* Standard: need to add for additional standard */
+};
+
+
+static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tvp514x_decoder, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd;
+}
+
+
+/**
+ * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ *
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+read_again:
+
+ err = i2c_smbus_read_byte_data(client, reg);
+ if (err < 0) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l2_warn(sd, "Read: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto read_again;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * dump_reg() - dump the register content of TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ */
+static void dump_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ u32 val;
+
+ val = tvp514x_read_reg(sd, reg);
+ v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
+}
+
+/**
+ * tvp514x_write_reg() - Write a value to a register in TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ * @val: value to be written to the register
+ *
+ * Write a value to a register in an TVP5146/47 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+write_again:
+
+ err = i2c_smbus_write_byte_data(client, reg, val);
+ if (err) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto write_again;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @reglist: list of TVP5146/47 registers and values
+ *
+ * Initializes a list of TVP5146/47 registers:-
+ * if token is TOK_TERM, then entire write operation terminates
+ * if token is TOK_DELAY, then a delay of 'val' msec is introduced
+ * if token is TOK_SKIP, then the register write is skipped
+ * if token is TOK_WRITE, then the register write is performed
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_regs(struct v4l2_subdev *sd,
+ const struct tvp514x_reg reglist[])
+{
+ int err;
+ const struct tvp514x_reg *next = reglist;
+
+ for (; next->token != TOK_TERM; next++) {
+ if (next->token == TOK_DELAY) {
+ msleep(next->val);
+ continue;
+ }
+
+ if (next->token == TOK_SKIP)
+ continue;
+
+ err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
+ if (err) {
+ v4l2_err(sd, "Write failed. Err[%d]\n", err);
+ return err;
+ }
+ }
+ return 0;
+}
+
+/**
+ * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
+ * standard detected.
+ */
+static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
+{
+ u8 std, std_status;
+
+ std = tvp514x_read_reg(sd, REG_VIDEO_STD);
+ if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
+ /* use the standard status register */
+ std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
+ else
+ /* use the standard register itself */
+ std_status = std;
+
+ switch (std_status & VIDEO_STD_MASK) {
+ case VIDEO_STD_NTSC_MJ_BIT:
+ return STD_NTSC_MJ;
+
+ case VIDEO_STD_PAL_BDGHIN_BIT:
+ return STD_PAL_BDGHIN;
+
+ default:
+ return STD_INVALID;
+ }
+
+ return STD_INVALID;
+}
+
+/* TVP5146/47 register dump function */
+static void tvp514x_reg_dump(struct v4l2_subdev *sd)
+{
+ dump_reg(sd, REG_INPUT_SEL);
+ dump_reg(sd, REG_AFE_GAIN_CTRL);
+ dump_reg(sd, REG_VIDEO_STD);
+ dump_reg(sd, REG_OPERATION_MODE);
+ dump_reg(sd, REG_COLOR_KILLER);
+ dump_reg(sd, REG_LUMA_CONTROL1);
+ dump_reg(sd, REG_LUMA_CONTROL2);
+ dump_reg(sd, REG_LUMA_CONTROL3);
+ dump_reg(sd, REG_BRIGHTNESS);
+ dump_reg(sd, REG_CONTRAST);
+ dump_reg(sd, REG_SATURATION);
+ dump_reg(sd, REG_HUE);
+ dump_reg(sd, REG_CHROMA_CONTROL1);
+ dump_reg(sd, REG_CHROMA_CONTROL2);
+ dump_reg(sd, REG_COMP_PR_SATURATION);
+ dump_reg(sd, REG_COMP_Y_CONTRAST);
+ dump_reg(sd, REG_COMP_PB_SATURATION);
+ dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
+ dump_reg(sd, REG_AVID_START_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_START_PIXEL_MSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_MSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
+ dump_reg(sd, REG_VBLK_START_LINE_LSB);
+ dump_reg(sd, REG_VBLK_START_LINE_MSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
+ dump_reg(sd, REG_SYNC_CONTROL);
+ dump_reg(sd, REG_OUTPUT_FORMATTER1);
+ dump_reg(sd, REG_OUTPUT_FORMATTER2);
+ dump_reg(sd, REG_OUTPUT_FORMATTER3);
+ dump_reg(sd, REG_OUTPUT_FORMATTER4);
+ dump_reg(sd, REG_OUTPUT_FORMATTER5);
+ dump_reg(sd, REG_OUTPUT_FORMATTER6);
+ dump_reg(sd, REG_CLEAR_LOST_LOCK);
+}
+
+/**
+ * tvp514x_configure() - Configure the TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @decoder: ptr to tvp514x_decoder structure
+ *
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_configure(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
+{
+ int err;
+
+ /* common register initialization */
+ err =
+ tvp514x_write_regs(sd, decoder->tvp514x_regs);
+ if (err)
+ return err;
+
+ if (debug)
+ tvp514x_reg_dump(sd);
+
+ return 0;
+}
+
+/**
+ * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @decoder: pointer to tvp514x_decoder structure
+ *
+ * A device is considered to be detected if the chip ID (LSB and MSB)
+ * registers match the expected values.
+ * Any value of the rom version register is accepted.
+ * Returns ENODEV error number if no device is detected, or zero
+ * if a device is detected.
+ */
+static int tvp514x_detect(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
+{
+ u8 chip_id_msb, chip_id_lsb, rom_ver;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
+ chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
+ rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
+
+ v4l2_dbg(1, debug, sd,
+ "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
+ chip_id_msb, chip_id_lsb, rom_ver);
+ if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
+ || ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
+ && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
+ /* We didn't read the values we expected, so this must not be
+ * an TVP5146/47.
+ */
+ v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
+ chip_id_msb, chip_id_lsb);
+ return -ENODEV;
+ }
+
+ decoder->ver = rom_ver;
+
+ v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
+ client->name, decoder->ver,
+ client->addr << 1, client->adapter->name);
+ return 0;
+}
+
+/**
+ * tvp514x_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by TVP5146/47. If no active input is
+ * detected then *std_id is set to 0 and the function returns 0.
+ */
+static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ enum tvp514x_std current_std;
+ enum tvp514x_input input_sel;
+ u8 sync_lock_status, lock_mask;
+
+ if (std_id == NULL)
+ return -EINVAL;
+
+ *std_id = V4L2_STD_UNKNOWN;
+
+ /* query the current standard */
+ current_std = tvp514x_query_current_std(sd);
+ if (current_std == STD_INVALID)
+ return 0;
+
+ input_sel = decoder->input;
+
+ switch (input_sel) {
+ case INPUT_CVBS_VI1A:
+ case INPUT_CVBS_VI1B:
+ case INPUT_CVBS_VI1C:
+ case INPUT_CVBS_VI2A:
+ case INPUT_CVBS_VI2B:
+ case INPUT_CVBS_VI2C:
+ case INPUT_CVBS_VI3A:
+ case INPUT_CVBS_VI3B:
+ case INPUT_CVBS_VI3C:
+ case INPUT_CVBS_VI4A:
+ lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+ STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+
+ case INPUT_SVIDEO_VI2A_VI1A:
+ case INPUT_SVIDEO_VI2B_VI1B:
+ case INPUT_SVIDEO_VI2C_VI1C:
+ case INPUT_SVIDEO_VI2A_VI3A:
+ case INPUT_SVIDEO_VI2B_VI3B:
+ case INPUT_SVIDEO_VI2C_VI3C:
+ case INPUT_SVIDEO_VI4A_VI1A:
+ case INPUT_SVIDEO_VI4A_VI1B:
+ case INPUT_SVIDEO_VI4A_VI1C:
+ case INPUT_SVIDEO_VI4A_VI3A:
+ case INPUT_SVIDEO_VI4A_VI3B:
+ case INPUT_SVIDEO_VI4A_VI3C:
+ lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+ /*Need to add other interfaces*/
+ default:
+ return -EINVAL;
+ }
+ /* check whether signal is locked */
+ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
+ if (lock_mask != (sync_lock_status & lock_mask))
+ return 0; /* No input detected */
+
+ *std_id = decoder->std_list[current_std].standard.id;
+
+ v4l2_dbg(1, debug, sd, "Current STD: %s\n",
+ decoder->std_list[current_std].standard.name);
+ return 0;
+}
+
+/**
+ * tvp514x_s_std() - V4L2 decoder interface handler for s_std
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 v4l2_std_id ioctl enum
+ *
+ * If std_id is supported, sets the requested standard. Otherwise, returns
+ * -EINVAL
+ */
+static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ int err, i;
+
+ for (i = 0; i < decoder->num_stds; i++)
+ if (std_id & decoder->std_list[i].standard.id)
+ break;
+
+ if ((i == decoder->num_stds) || (i == STD_INVALID))
+ return -EINVAL;
+
+ err = tvp514x_write_reg(sd, REG_VIDEO_STD,
+ decoder->std_list[i].video_std);
+ if (err)
+ return err;
+
+ decoder->current_std = i;
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ decoder->std_list[i].video_std;
+
+ v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
+ decoder->std_list[i].standard.name);
+ return 0;
+}
+
+/**
+ * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @input: input selector for routing the signal
+ * @output: output selector for routing the signal
+ * @config: config value. Not used
+ *
+ * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
+ * the input is not supported or there is no active signal present in the
+ * selected input.
+ */
+static int tvp514x_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ int err;
+ enum tvp514x_input input_sel;
+ enum tvp514x_output output_sel;
+ u8 sync_lock_status, lock_mask;
+ int try_count = LOCK_RETRY_COUNT;
+
+ if ((input >= INPUT_INVALID) ||
+ (output >= OUTPUT_INVALID))
+ /* Index out of bound */
+ return -EINVAL;
+
+ /*
+ * For the sequence streamon -> streamoff and again s_input
+ * it fails to lock the signal, since streamoff puts TVP514x
+ * into power off state which leads to failure in sub-sequent s_input.
+ *
+ * So power up the TVP514x device here, since it is important to lock
+ * the signal at this stage.
+ */
+ if (!decoder->streaming)
+ tvp514x_s_stream(sd, 1);
+
+ input_sel = input;
+ output_sel = output;
+
+ err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
+ if (err)
+ return err;
+
+ output_sel |= tvp514x_read_reg(sd,
+ REG_OUTPUT_FORMATTER1) & 0x7;
+ err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
+ output_sel);
+ if (err)
+ return err;
+
+ decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
+ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
+
+ /* Clear status */
+ msleep(LOCK_RETRY_DELAY);
+ err =
+ tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
+ if (err)
+ return err;
+
+ switch (input_sel) {
+ case INPUT_CVBS_VI1A:
+ case INPUT_CVBS_VI1B:
+ case INPUT_CVBS_VI1C:
+ case INPUT_CVBS_VI2A:
+ case INPUT_CVBS_VI2B:
+ case INPUT_CVBS_VI2C:
+ case INPUT_CVBS_VI3A:
+ case INPUT_CVBS_VI3B:
+ case INPUT_CVBS_VI3C:
+ case INPUT_CVBS_VI4A:
+ lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+ STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+
+ case INPUT_SVIDEO_VI2A_VI1A:
+ case INPUT_SVIDEO_VI2B_VI1B:
+ case INPUT_SVIDEO_VI2C_VI1C:
+ case INPUT_SVIDEO_VI2A_VI3A:
+ case INPUT_SVIDEO_VI2B_VI3B:
+ case INPUT_SVIDEO_VI2C_VI3C:
+ case INPUT_SVIDEO_VI4A_VI1A:
+ case INPUT_SVIDEO_VI4A_VI1B:
+ case INPUT_SVIDEO_VI4A_VI1C:
+ case INPUT_SVIDEO_VI4A_VI3A:
+ case INPUT_SVIDEO_VI4A_VI3B:
+ case INPUT_SVIDEO_VI4A_VI3C:
+ lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+ STATUS_VIRT_SYNC_LOCK_BIT;
+ break;
+ /* Need to add other interfaces*/
+ default:
+ return -EINVAL;
+ }
+
+ while (try_count-- > 0) {
+ /* Allow decoder to sync up with new input */
+ msleep(LOCK_RETRY_DELAY);
+
+ sync_lock_status = tvp514x_read_reg(sd,
+ REG_STATUS1);
+ if (lock_mask == (sync_lock_status & lock_mask))
+ /* Input detected */
+ break;
+ }
+
+ if (try_count < 0)
+ return -EINVAL;
+
+ decoder->input = input;
+ decoder->output = output;
+
+ v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
+
+ return 0;
+}
+
+/**
+ * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
+ * @ctrl: pointer to v4l2_ctrl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW. Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ int err = -EINVAL, value;
+
+ value = ctrl->val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value);
+ if (!err)
+ decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
+ break;
+ case V4L2_CID_CONTRAST:
+ err = tvp514x_write_reg(sd, REG_CONTRAST, value);
+ if (!err)
+ decoder->tvp514x_regs[REG_CONTRAST].val = value;
+ break;
+ case V4L2_CID_SATURATION:
+ err = tvp514x_write_reg(sd, REG_SATURATION, value);
+ if (!err)
+ decoder->tvp514x_regs[REG_SATURATION].val = value;
+ break;
+ case V4L2_CID_HUE:
+ if (value == 180)
+ value = 0x7F;
+ else if (value == -180)
+ value = 0x80;
+ err = tvp514x_write_reg(sd, REG_HUE, value);
+ if (!err)
+ decoder->tvp514x_regs[REG_HUE].val = value;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c);
+ if (!err)
+ decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
+ break;
+ }
+
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
+ ctrl->id, ctrl->val);
+ return err;
+}
+
+/**
+ * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @index: index of pixelcode to retrieve
+ * @code: receives the pixelcode
+ *
+ * Enumerates supported mediabus formats
+ */
+static int
+tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_YUYV10_2X10;
+ return 0;
+}
+
+/**
+ * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to the mediabus format structure
+ *
+ * Negotiates the image capture size and mediabus format.
+ */
+static int
+tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ enum tvp514x_std current_std;
+
+ if (f == NULL)
+ return -EINVAL;
+
+ /* Calculate height and width based on current standard */
+ current_std = decoder->current_std;
+
+ f->code = V4L2_MBUS_FMT_YUYV10_2X10;
+ f->width = decoder->std_list[current_std].width;
+ f->height = decoder->std_list[current_std].height;
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
+ f->width, f->height);
+ return 0;
+}
+
+/**
+ * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int
+tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ struct v4l2_captureparm *cparm;
+ enum tvp514x_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
+ return -EINVAL;
+
+ /* get the current standard */
+ current_std = decoder->current_std;
+
+ cparm = &a->parm.capture;
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+/**
+ * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int
+tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ struct v4l2_fract *timeperframe;
+ enum tvp514x_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
+ return -EINVAL;
+
+ timeperframe = &a->parm.capture.timeperframe;
+
+ /* get the current standard */
+ current_std = decoder->current_std;
+
+ *timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+/**
+ * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable, if possible.
+ */
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int err = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+
+ if (decoder->streaming == enable)
+ return 0;
+
+ switch (enable) {
+ case 0:
+ {
+ /* Power Down Sequence */
+ err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
+ if (err) {
+ v4l2_err(sd, "Unable to turn off decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
+ break;
+ }
+ case 1:
+ {
+ struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
+ client->driver->id_table->driver_data;
+
+ /* Power Up Sequence */
+ err = tvp514x_write_regs(sd, int_seq);
+ if (err) {
+ v4l2_err(sd, "Unable to turn on decoder\n");
+ return err;
+ }
+ /* Detect if not already detected */
+ err = tvp514x_detect(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to detect decoder\n");
+ return err;
+ }
+ err = tvp514x_configure(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to configure decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
+ break;
+ }
+ default:
+ err = -ENODEV;
+ break;
+ }
+
+ return err;
+}
+
+static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
+ .s_ctrl = tvp514x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+ .s_std = tvp514x_s_std,
+};
+
+static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+ .s_routing = tvp514x_s_routing,
+ .querystd = tvp514x_querystd,
+ .enum_mbus_fmt = tvp514x_enum_mbus_fmt,
+ .g_mbus_fmt = tvp514x_mbus_fmt,
+ .try_mbus_fmt = tvp514x_mbus_fmt,
+ .s_mbus_fmt = tvp514x_mbus_fmt,
+ .g_parm = tvp514x_g_parm,
+ .s_parm = tvp514x_s_parm,
+ .s_stream = tvp514x_s_stream,
+};
+
+static const struct v4l2_subdev_ops tvp514x_ops = {
+ .core = &tvp514x_core_ops,
+ .video = &tvp514x_video_ops,
+};
+
+static struct tvp514x_decoder tvp514x_dev = {
+ .streaming = 0,
+ .current_std = STD_NTSC_MJ,
+ .std_list = tvp514x_std_list,
+ .num_stds = ARRAY_SIZE(tvp514x_std_list),
+
+};
+
+/**
+ * tvp514x_probe() - decoder driver i2c probe handler
+ * @client: i2c driver client device structure
+ * @id: i2c driver id table
+ *
+ * Register decoder as an i2c client device and V4L2
+ * device.
+ */
+static int
+tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct tvp514x_decoder *decoder;
+ struct v4l2_subdev *sd;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ if (!client->dev.platform_data) {
+ v4l2_err(client, "No platform data!!\n");
+ return -ENODEV;
+ }
+
+ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
+
+ /* Initialize the tvp514x_decoder with default configuration */
+ *decoder = tvp514x_dev;
+ /* Copy default register configuration */
+ memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
+ sizeof(tvp514x_reg_list_default));
+
+ /* Copy board specific information here */
+ decoder->pdata = client->dev.platform_data;
+
+ /**
+ * Fetch platform specific data, and configure the
+ * tvp514x_reg_list[] accordingly. Since this is one
+ * time configuration, no need to preserve.
+ */
+ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
+ (decoder->pdata->clk_polarity << 1);
+ decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
+ ((decoder->pdata->hs_polarity << 2) |
+ (decoder->pdata->vs_polarity << 3));
+ /* Set default standard to auto */
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ VIDEO_STD_AUTO_SWITCH_BIT;
+
+ /* Register with V4L2 layer as slave device */
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
+
+ v4l2_ctrl_handler_init(&decoder->hdl, 5);
+ v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+ V4L2_CID_HUE, -180, 180, 180, 0);
+ v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ sd->ctrl_handler = &decoder->hdl;
+ if (decoder->hdl.error) {
+ int err = decoder->hdl.error;
+
+ v4l2_ctrl_handler_free(&decoder->hdl);
+ kfree(decoder);
+ return err;
+ }
+ v4l2_ctrl_handler_setup(&decoder->hdl);
+
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
+ return 0;
+
+}
+
+/**
+ * tvp514x_remove() - decoder driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister decoder as an i2c client device and V4L2
+ * device. Complement of tvp514x_probe().
+ */
+static int tvp514x_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&decoder->hdl);
+ kfree(decoder);
+ return 0;
+}
+/* TVP5146 Init/Power on Sequence */
+static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
+};
+
+/* TVP5147 Init/Power on Sequence */
+static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+ {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+ {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
+};
+
+/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
+static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
+};
+
+/**
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id tvp514x_id[] = {
+ {"tvp5146", (unsigned long)tvp5146_init_reg_seq},
+ {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
+ {"tvp5147", (unsigned long)tvp5147_init_reg_seq},
+ {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tvp514x_id);
+
+static struct i2c_driver tvp514x_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TVP514X_MODULE_NAME,
+ },
+ .probe = tvp514x_probe,
+ .remove = tvp514x_remove,
+ .id_table = tvp514x_id,
+};
+
+module_i2c_driver(tvp514x_driver);
diff --git a/drivers/media/i2c/tvp514x_regs.h b/drivers/media/i2c/tvp514x_regs.h
new file mode 100644
index 000000000000..d23aa2fbb9b1
--- /dev/null
+++ b/drivers/media/i2c/tvp514x_regs.h
@@ -0,0 +1,287 @@
+/*
+ * drivers/media/i2c/tvp514x_regs.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ * Sivaraj R <sivaraj@ti.com>
+ * Brijesh R Jadav <brijesh.j@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package 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 _TVP514X_REGS_H
+#define _TVP514X_REGS_H
+
+/*
+ * TVP5146/47 registers
+ */
+#define REG_INPUT_SEL (0x00)
+#define REG_AFE_GAIN_CTRL (0x01)
+#define REG_VIDEO_STD (0x02)
+#define REG_OPERATION_MODE (0x03)
+#define REG_AUTOSWITCH_MASK (0x04)
+
+#define REG_COLOR_KILLER (0x05)
+#define REG_LUMA_CONTROL1 (0x06)
+#define REG_LUMA_CONTROL2 (0x07)
+#define REG_LUMA_CONTROL3 (0x08)
+
+#define REG_BRIGHTNESS (0x09)
+#define REG_CONTRAST (0x0A)
+#define REG_SATURATION (0x0B)
+#define REG_HUE (0x0C)
+
+#define REG_CHROMA_CONTROL1 (0x0D)
+#define REG_CHROMA_CONTROL2 (0x0E)
+
+/* 0x0F Reserved */
+
+#define REG_COMP_PR_SATURATION (0x10)
+#define REG_COMP_Y_CONTRAST (0x11)
+#define REG_COMP_PB_SATURATION (0x12)
+
+/* 0x13 Reserved */
+
+#define REG_COMP_Y_BRIGHTNESS (0x14)
+
+/* 0x15 Reserved */
+
+#define REG_AVID_START_PIXEL_LSB (0x16)
+#define REG_AVID_START_PIXEL_MSB (0x17)
+#define REG_AVID_STOP_PIXEL_LSB (0x18)
+#define REG_AVID_STOP_PIXEL_MSB (0x19)
+
+#define REG_HSYNC_START_PIXEL_LSB (0x1A)
+#define REG_HSYNC_START_PIXEL_MSB (0x1B)
+#define REG_HSYNC_STOP_PIXEL_LSB (0x1C)
+#define REG_HSYNC_STOP_PIXEL_MSB (0x1D)
+
+#define REG_VSYNC_START_LINE_LSB (0x1E)
+#define REG_VSYNC_START_LINE_MSB (0x1F)
+#define REG_VSYNC_STOP_LINE_LSB (0x20)
+#define REG_VSYNC_STOP_LINE_MSB (0x21)
+
+#define REG_VBLK_START_LINE_LSB (0x22)
+#define REG_VBLK_START_LINE_MSB (0x23)
+#define REG_VBLK_STOP_LINE_LSB (0x24)
+#define REG_VBLK_STOP_LINE_MSB (0x25)
+
+/* 0x26 - 0x27 Reserved */
+
+#define REG_FAST_SWTICH_CONTROL (0x28)
+
+/* 0x29 Reserved */
+
+#define REG_FAST_SWTICH_SCART_DELAY (0x2A)
+
+/* 0x2B Reserved */
+
+#define REG_SCART_DELAY (0x2C)
+#define REG_CTI_DELAY (0x2D)
+#define REG_CTI_CONTROL (0x2E)
+
+/* 0x2F - 0x31 Reserved */
+
+#define REG_SYNC_CONTROL (0x32)
+#define REG_OUTPUT_FORMATTER1 (0x33)
+#define REG_OUTPUT_FORMATTER2 (0x34)
+#define REG_OUTPUT_FORMATTER3 (0x35)
+#define REG_OUTPUT_FORMATTER4 (0x36)
+#define REG_OUTPUT_FORMATTER5 (0x37)
+#define REG_OUTPUT_FORMATTER6 (0x38)
+#define REG_CLEAR_LOST_LOCK (0x39)
+
+#define REG_STATUS1 (0x3A)
+#define REG_STATUS2 (0x3B)
+
+#define REG_AGC_GAIN_STATUS_LSB (0x3C)
+#define REG_AGC_GAIN_STATUS_MSB (0x3D)
+
+/* 0x3E Reserved */
+
+#define REG_VIDEO_STD_STATUS (0x3F)
+#define REG_GPIO_INPUT1 (0x40)
+#define REG_GPIO_INPUT2 (0x41)
+
+/* 0x42 - 0x45 Reserved */
+
+#define REG_AFE_COARSE_GAIN_CH1 (0x46)
+#define REG_AFE_COARSE_GAIN_CH2 (0x47)
+#define REG_AFE_COARSE_GAIN_CH3 (0x48)
+#define REG_AFE_COARSE_GAIN_CH4 (0x49)
+
+#define REG_AFE_FINE_GAIN_PB_B_LSB (0x4A)
+#define REG_AFE_FINE_GAIN_PB_B_MSB (0x4B)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB (0x4C)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB (0x4D)
+#define REG_AFE_FINE_GAIN_PR_R_LSB (0x4E)
+#define REG_AFE_FINE_GAIN_PR_R_MSB (0x4F)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB (0x50)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB (0x51)
+
+/* 0x52 - 0x68 Reserved */
+
+#define REG_FBIT_VBIT_CONTROL1 (0x69)
+
+/* 0x6A - 0x6B Reserved */
+
+#define REG_BACKEND_AGC_CONTROL (0x6C)
+
+/* 0x6D - 0x6E Reserved */
+
+#define REG_AGC_DECREMENT_SPEED_CONTROL (0x6F)
+#define REG_ROM_VERSION (0x70)
+
+/* 0x71 - 0x73 Reserved */
+
+#define REG_AGC_WHITE_PEAK_PROCESSING (0x74)
+#define REG_FBIT_VBIT_CONTROL2 (0x75)
+#define REG_VCR_TRICK_MODE_CONTROL (0x76)
+#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77)
+#define REG_AGC_INCREMENT_SPEED (0x78)
+#define REG_AGC_INCREMENT_DELAY (0x79)
+
+/* 0x7A - 0x7F Reserved */
+
+#define REG_CHIP_ID_MSB (0x80)
+#define REG_CHIP_ID_LSB (0x81)
+
+/* 0x82 Reserved */
+
+#define REG_CPLL_SPEED_CONTROL (0x83)
+
+/* 0x84 - 0x96 Reserved */
+
+#define REG_STATUS_REQUEST (0x97)
+
+/* 0x98 - 0x99 Reserved */
+
+#define REG_VERTICAL_LINE_COUNT_LSB (0x9A)
+#define REG_VERTICAL_LINE_COUNT_MSB (0x9B)
+
+/* 0x9C - 0x9D Reserved */
+
+#define REG_AGC_DECREMENT_DELAY (0x9E)
+
+/* 0x9F - 0xB0 Reserved */
+
+#define REG_VDP_TTX_FILTER_1_MASK1 (0xB1)
+#define REG_VDP_TTX_FILTER_1_MASK2 (0xB2)
+#define REG_VDP_TTX_FILTER_1_MASK3 (0xB3)
+#define REG_VDP_TTX_FILTER_1_MASK4 (0xB4)
+#define REG_VDP_TTX_FILTER_1_MASK5 (0xB5)
+#define REG_VDP_TTX_FILTER_2_MASK1 (0xB6)
+#define REG_VDP_TTX_FILTER_2_MASK2 (0xB7)
+#define REG_VDP_TTX_FILTER_2_MASK3 (0xB8)
+#define REG_VDP_TTX_FILTER_2_MASK4 (0xB9)
+#define REG_VDP_TTX_FILTER_2_MASK5 (0xBA)
+#define REG_VDP_TTX_FILTER_CONTROL (0xBB)
+#define REG_VDP_FIFO_WORD_COUNT (0xBC)
+#define REG_VDP_FIFO_INTERRUPT_THRLD (0xBD)
+
+/* 0xBE Reserved */
+
+#define REG_VDP_FIFO_RESET (0xBF)
+#define REG_VDP_FIFO_OUTPUT_CONTROL (0xC0)
+#define REG_VDP_LINE_NUMBER_INTERRUPT (0xC1)
+#define REG_VDP_PIXEL_ALIGNMENT_LSB (0xC2)
+#define REG_VDP_PIXEL_ALIGNMENT_MSB (0xC3)
+
+/* 0xC4 - 0xD5 Reserved */
+
+#define REG_VDP_LINE_START (0xD6)
+#define REG_VDP_LINE_STOP (0xD7)
+#define REG_VDP_GLOBAL_LINE_MODE (0xD8)
+#define REG_VDP_FULL_FIELD_ENABLE (0xD9)
+#define REG_VDP_FULL_FIELD_MODE (0xDA)
+
+/* 0xDB - 0xDF Reserved */
+
+#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0)
+#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR (0xE1)
+#define REG_FIFO_READ_DATA (0xE2)
+
+/* 0xE3 - 0xE7 Reserved */
+
+#define REG_VBUS_ADDRESS_ACCESS1 (0xE8)
+#define REG_VBUS_ADDRESS_ACCESS2 (0xE9)
+#define REG_VBUS_ADDRESS_ACCESS3 (0xEA)
+
+/* 0xEB - 0xEF Reserved */
+
+#define REG_INTERRUPT_RAW_STATUS0 (0xF0)
+#define REG_INTERRUPT_RAW_STATUS1 (0xF1)
+#define REG_INTERRUPT_STATUS0 (0xF2)
+#define REG_INTERRUPT_STATUS1 (0xF3)
+#define REG_INTERRUPT_MASK0 (0xF4)
+#define REG_INTERRUPT_MASK1 (0xF5)
+#define REG_INTERRUPT_CLEAR0 (0xF6)
+#define REG_INTERRUPT_CLEAR1 (0xF7)
+
+/* 0xF8 - 0xFF Reserved */
+
+/*
+ * Mask and bit definitions of TVP5146/47 registers
+ */
+/* The ID values we are looking for */
+#define TVP514X_CHIP_ID_MSB (0x51)
+#define TVP5146_CHIP_ID_LSB (0x46)
+#define TVP5147_CHIP_ID_LSB (0x47)
+
+#define VIDEO_STD_MASK (0x07)
+#define VIDEO_STD_AUTO_SWITCH_BIT (0x00)
+#define VIDEO_STD_NTSC_MJ_BIT (0x01)
+#define VIDEO_STD_PAL_BDGHIN_BIT (0x02)
+#define VIDEO_STD_PAL_M_BIT (0x03)
+#define VIDEO_STD_PAL_COMBINATION_N_BIT (0x04)
+#define VIDEO_STD_NTSC_4_43_BIT (0x05)
+#define VIDEO_STD_SECAM_BIT (0x06)
+#define VIDEO_STD_PAL_60_BIT (0x07)
+
+/*
+ * Status bit
+ */
+#define STATUS_TV_VCR_BIT (1<<0)
+#define STATUS_HORZ_SYNC_LOCK_BIT (1<<1)
+#define STATUS_VIRT_SYNC_LOCK_BIT (1<<2)
+#define STATUS_CLR_SUBCAR_LOCK_BIT (1<<3)
+#define STATUS_LOST_LOCK_DETECT_BIT (1<<4)
+#define STATUS_FEILD_RATE_BIT (1<<5)
+#define STATUS_LINE_ALTERNATING_BIT (1<<6)
+#define STATUS_PEAK_WHITE_DETECT_BIT (1<<7)
+
+/* Tokens for register write */
+#define TOK_WRITE (0) /* token for write operation */
+#define TOK_TERM (1) /* terminating token */
+#define TOK_DELAY (2) /* delay token for reg list */
+#define TOK_SKIP (3) /* token to skip a register */
+/**
+ * struct tvp514x_reg - Structure for TVP5146/47 register initialization values
+ * @token - Token: TOK_WRITE, TOK_TERM etc..
+ * @reg - Register offset
+ * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
+ */
+struct tvp514x_reg {
+ u8 token;
+ u8 reg;
+ u32 val;
+};
+
+#endif /* ifndef _TVP514X_REGS_H */
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/i2c/tvp5150.c
index a751b6c146fd..a751b6c146fd 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h
index 25a994944918..25a994944918 100644
--- a/drivers/media/video/tvp5150_reg.h
+++ b/drivers/media/i2c/tvp5150_reg.h
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/i2c/tvp7002.c
index fb6a5b57eb83..fb6a5b57eb83 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
diff --git a/drivers/media/video/tvp7002_reg.h b/drivers/media/i2c/tvp7002_reg.h
index 0e34ca9bccf3..0e34ca9bccf3 100644
--- a/drivers/media/video/tvp7002_reg.h
+++ b/drivers/media/i2c/tvp7002_reg.h
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/i2c/upd64031a.c
index 1e7446542091..1e7446542091 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/i2c/upd64031a.c
diff --git a/drivers/media/video/upd64083.c b/drivers/media/i2c/upd64083.c
index 75d6acc62018..75d6acc62018 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/i2c/upd64083.c
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
index 7cfbc9d94a48..7cfbc9d94a48 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/i2c/vp27smpx.c
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/i2c/vpx3220.c
index 2f67b4c5c823..2f67b4c5c823 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/i2c/vpx3220.c
diff --git a/drivers/media/video/vs6624.c b/drivers/media/i2c/vs6624.c
index 42ae9dc9c574..42ae9dc9c574 100644
--- a/drivers/media/video/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
diff --git a/drivers/media/video/vs6624_regs.h b/drivers/media/i2c/vs6624_regs.h
index 6ba2ee25827e..6ba2ee25827e 100644
--- a/drivers/media/video/vs6624_regs.h
+++ b/drivers/media/i2c/vs6624_regs.h
diff --git a/drivers/media/video/wm8739.c b/drivers/media/i2c/wm8739.c
index 3bb99e93febe..3bb99e93febe 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/i2c/wm8739.c
diff --git a/drivers/media/video/wm8775.c b/drivers/media/i2c/wm8775.c
index bee77ea9f49e..bee77ea9f49e 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/i2c/wm8775.c
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6f9eb94e85b3..d01fcb7e87c2 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -59,7 +59,9 @@ static int media_device_get_info(struct media_device *dev,
info.hw_revision = dev->hw_revision;
info.driver_version = dev->driver_version;
- return copy_to_user(__info, &info, sizeof(*__info));
+ if (copy_to_user(__info, &info, sizeof(*__info)))
+ return -EFAULT;
+ return 0;
}
static struct media_entity *find_entity(struct media_device *mdev, u32 id)
diff --git a/drivers/media/mmc/Kconfig b/drivers/media/mmc/Kconfig
new file mode 100644
index 000000000000..8c30ada27c79
--- /dev/null
+++ b/drivers/media/mmc/Kconfig
@@ -0,0 +1,2 @@
+comment "Supported MMC/SDIO adapters"
+source "drivers/media/mmc/siano/Kconfig"
diff --git a/drivers/media/mmc/Makefile b/drivers/media/mmc/Makefile
new file mode 100644
index 000000000000..31e297a202fb
--- /dev/null
+++ b/drivers/media/mmc/Makefile
@@ -0,0 +1 @@
+obj-y += siano/
diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig
new file mode 100644
index 000000000000..fa62475be3bf
--- /dev/null
+++ b/drivers/media/mmc/siano/Kconfig
@@ -0,0 +1,10 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_SDIO_DRV
+ tristate "Siano SMS1xxx based MDTV via SDIO interface"
+ depends on DVB_CORE && RC_CORE && HAS_DMA
+ depends on MMC
+ ---help---
+ Choose if you would like to have Siano's support for SDIO interface
diff --git a/drivers/media/mmc/siano/Makefile b/drivers/media/mmc/siano/Makefile
new file mode 100644
index 000000000000..0e01f973db6b
--- /dev/null
+++ b/drivers/media/mmc/siano/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/common/siano
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c
index d6f3f100699a..d6f3f100699a 100644
--- a/drivers/media/dvb/siano/smssdio.c
+++ b/drivers/media/mmc/siano/smssdio.c
diff --git a/drivers/media/parport/Kconfig b/drivers/media/parport/Kconfig
new file mode 100644
index 000000000000..ece13dcff07d
--- /dev/null
+++ b/drivers/media/parport/Kconfig
@@ -0,0 +1,52 @@
+menuconfig MEDIA_PARPORT_SUPPORT
+ bool "ISA and parallel port devices"
+ depends on (ISA || PARPORT) && MEDIA_CAMERA_SUPPORT
+ help
+ Enables drivers for ISA and parallel port bus. If you
+ need media drivers using those legacy buses, say Y.
+
+if MEDIA_PARPORT_SUPPORT
+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 bw-qcam.
+
+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 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
diff --git a/drivers/media/parport/Makefile b/drivers/media/parport/Makefile
new file mode 100644
index 000000000000..4eea06d7af5b
--- /dev/null
+++ b/drivers/media/parport/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
+obj-$(CONFIG_VIDEO_PMS) += pms.o
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index 5b75a64b199b..5b75a64b199b 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/parport/c-qcam.c
index ec51e1f12e82..ec51e1f12e82 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/parport/c-qcam.c
diff --git a/drivers/media/video/pms.c b/drivers/media/parport/pms.c
index 77f9c92186f4..77f9c92186f4 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/parport/pms.c
diff --git a/drivers/media/video/w9966.c b/drivers/media/parport/w9966.c
index db2a6003a1c3..db2a6003a1c3 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/parport/w9966.c
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
new file mode 100644
index 000000000000..d4e2ed3f27e5
--- /dev/null
+++ b/drivers/media/pci/Kconfig
@@ -0,0 +1,47 @@
+menuconfig MEDIA_PCI_SUPPORT
+ bool "Media PCI Adapters"
+ depends on PCI && MEDIA_SUPPORT
+ help
+ Enable media drivers for PCI/PCIe bus.
+ If you have such devices, say Y.
+
+if MEDIA_PCI_SUPPORT
+
+if MEDIA_CAMERA_SUPPORT
+ comment "Media capture support"
+source "drivers/media/pci/meye/Kconfig"
+source "drivers/media/pci/sta2x11/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT
+ comment "Media capture/analog TV support"
+source "drivers/media/pci/ivtv/Kconfig"
+source "drivers/media/pci/zoran/Kconfig"
+source "drivers/media/pci/saa7146/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
+ comment "Media capture/analog/hybrid TV support"
+source "drivers/media/pci/cx18/Kconfig"
+source "drivers/media/pci/cx23885/Kconfig"
+source "drivers/media/pci/cx25821/Kconfig"
+source "drivers/media/pci/cx88/Kconfig"
+source "drivers/media/pci/bt8xx/Kconfig"
+source "drivers/media/pci/saa7134/Kconfig"
+source "drivers/media/pci/saa7164/Kconfig"
+
+endif
+
+if MEDIA_DIGITAL_TV_SUPPORT
+ comment "Media digital TV PCI Adapters"
+source "drivers/media/pci/ttpci/Kconfig"
+source "drivers/media/pci/b2c2/Kconfig"
+source "drivers/media/pci/pluto2/Kconfig"
+source "drivers/media/pci/dm1105/Kconfig"
+source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/mantis/Kconfig"
+source "drivers/media/pci/ngene/Kconfig"
+source "drivers/media/pci/ddbridge/Kconfig"
+endif
+
+endif #MEDIA_PCI_SUPPORT
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
new file mode 100644
index 000000000000..35cc57862c01
--- /dev/null
+++ b/drivers/media/pci/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the kernel multimedia device drivers.
+#
+
+obj-y += ttpci/ \
+ b2c2/ \
+ pluto2/ \
+ dm1105/ \
+ pt1/ \
+ mantis/ \
+ ngene/ \
+ ddbridge/ \
+ b2c2/ \
+ saa7146/
+
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CX18) += cx18/
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+obj-$(CONFIG_VIDEO_CX25821) += cx25821/
+obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
+obj-$(CONFIG_VIDEO_MEYE) += meye/
+obj-$(CONFIG_STA2X11_VIP) += sta2x11/
diff --git a/drivers/media/pci/b2c2/Kconfig b/drivers/media/pci/b2c2/Kconfig
new file mode 100644
index 000000000000..58761a21caa0
--- /dev/null
+++ b/drivers/media/pci/b2c2/Kconfig
@@ -0,0 +1,15 @@
+config DVB_B2C2_FLEXCOP_PCI
+ tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
+ depends on DVB_CORE && I2C
+ help
+ Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_PCI_DEBUG
+ bool "Enable debug for the B2C2 FlexCop drivers"
+ depends on DVB_B2C2_FLEXCOP_PCI
+ select DVB_B2C2_FLEXCOP_DEBUG
+ help
+ Say Y if you want to enable the module option to control debug messages
+ of all B2C2 FlexCop drivers.
diff --git a/drivers/media/pci/b2c2/Makefile b/drivers/media/pci/b2c2/Makefile
new file mode 100644
index 000000000000..b894320a5f21
--- /dev/null
+++ b/drivers/media/pci/b2c2/Makefile
@@ -0,0 +1,9 @@
+ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
+b2c2-flexcop-pci-objs += flexcop-dma.o
+endif
+
+b2c2-flexcop-pci-objs += flexcop-pci.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/common/b2c2/
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/pci/b2c2/flexcop-dma.c
index 2881e0d956ad..2881e0d956ad 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/pci/b2c2/flexcop-dma.c
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c
index 44f8fb5f17ff..44f8fb5f17ff 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/pci/b2c2/flexcop-pci.c
diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig
new file mode 100644
index 000000000000..61d09e010814
--- /dev/null
+++ b/drivers/media/pci/bt8xx/Kconfig
@@ -0,0 +1,43 @@
+config VIDEO_BT848
+ tristate "BT848 Video For Linux"
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
+ select I2C_ALGOBIT
+ select VIDEO_BTCX
+ select VIDEOBUF_DMA_SG
+ depends on RC_CORE
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ Support for BT848 based frame grabber/overlay boards. This includes
+ the Miro, Hauppauge and STB boards. Please read the material in
+ <file:Documentation/video4linux/bttv/> for more information.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bttv.
+
+config DVB_BT8XX
+ tristate "DVB/ATSC Support for bt878 based TV cards"
+ depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SP887X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24110 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_OR51211 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for PCI cards based on the Bt8xx PCI bridge. Examples are
+ the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+ the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
+ some AVerMedia cards.
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the PCI bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y if you own such a device and want to use it.
diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile
new file mode 100644
index 000000000000..5f06597c6a6e
--- /dev/null
+++ b/drivers/media/pci/bt8xx/Makefile
@@ -0,0 +1,11 @@
+bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
+ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+ bttv-input.o bttv-audio-hook.o
+
+obj-$(CONFIG_VIDEO_BT848) += bttv.o
+obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/pci/bt8xx/bt848.h
index c37e6acffded..c37e6acffded 100644
--- a/drivers/media/video/bt8xx/bt848.h
+++ b/drivers/media/pci/bt8xx/bt848.h
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c
index b34fa95185e4..b34fa95185e4 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/pci/bt8xx/bt878.c
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/pci/bt8xx/bt878.h
index d19b59299d78..d19b59299d78 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/pci/bt8xx/bt878.h
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c
index 2364d16586b3..2364d16586b3 100644
--- a/drivers/media/video/bt8xx/bttv-audio-hook.c
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h
index 159d07adeff8..159d07adeff8 100644
--- a/drivers/media/video/bt8xx/bttv-audio-hook.h
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index 38952faaffda..38952faaffda 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index b58ff87db771..b58ff87db771 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c
index 922e8233fd0b..922e8233fd0b 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/pci/bt8xx/bttv-gpio.c
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c
index 580c8e682392..580c8e682392 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/pci/bt8xx/bttv-i2c.c
diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c
index a6a540dc9e4b..a6a540dc9e4b 100644
--- a/drivers/media/video/bt8xx/bttv-if.c
+++ b/drivers/media/pci/bt8xx/bttv-if.c
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index ef4c7cd41982..ef4c7cd41982 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c
index 82cc47d2e3fa..82cc47d2e3fa 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/pci/bt8xx/bttv-risc.c
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c
index b433267d9aa9..b433267d9aa9 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/pci/bt8xx/bttv-vbi.c
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index 79a11240a590..79a11240a590 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 70fd4f23f605..70fd4f23f605 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c
index 430b3eb11815..430b3eb11815 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/pci/bt8xx/dst.c
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
new file mode 100644
index 000000000000..ee3884fbc9ce
--- /dev/null
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -0,0 +1,726 @@
+/*
+ CA-driver for TwinHan DST Frontend/Card
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/dvb/ca.h>
+#include "dvbdev.h"
+#include "dvb_frontend.h"
+#include "dst_ca.h"
+#include "dst_common.h"
+
+#define DST_CA_ERROR 0
+#define DST_CA_NOTICE 1
+#define DST_CA_INFO 2
+#define DST_CA_DEBUG 3
+
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > DST_CA_ERROR) && (x > y)) \
+ printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
+ else if ((x > DST_CA_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
+ else if ((x > DST_CA_INFO) && (x > y)) \
+ printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
+ else if ((x > DST_CA_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ## arg); \
+ } \
+} while(0)
+
+
+static DEFINE_MUTEX(dst_ca_mutex);
+static unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+/* Need some more work */
+static int ca_set_slot_descr(void)
+{
+ /* We could make this more graceful ? */
+ return -EOPNOTSUPP;
+}
+
+/* Need some more work */
+static int ca_set_pid(void)
+{
+ /* We could make this more graceful ? */
+ return -EOPNOTSUPP;
+}
+
+static void put_command_and_length(u8 *data, int command, int length)
+{
+ data[0] = (command >> 16) & 0xff;
+ data[1] = (command >> 8) & 0xff;
+ data[2] = command & 0xff;
+ data[3] = length;
+}
+
+static void put_checksum(u8 *check_string, int length)
+{
+ dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
+ dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
+ check_string[length] = dst_check_sum (check_string, length);
+ dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
+}
+
+static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
+{
+ u8 reply;
+
+ mutex_lock(&state->dst_mutex);
+ dst_comm_init(state);
+ msleep(65);
+
+ if (write_dst(state, data, len)) {
+ dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
+ dst_error_recovery(state);
+ goto error;
+ }
+ if ((dst_pio_disable(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
+ goto error;
+ }
+ if (read_dst(state, &reply, GET_ACK) < 0) {
+ dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
+ dst_error_recovery(state);
+ goto error;
+ }
+ if (read) {
+ if (! dst_wait_dst_ready(state, LONG_DELAY)) {
+ dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
+ goto error;
+ }
+ if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
+ dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
+ dst_error_recovery(state);
+ goto error;
+ }
+ }
+ mutex_unlock(&state->dst_mutex);
+ return 0;
+
+error:
+ mutex_unlock(&state->dst_mutex);
+ return -EIO;
+}
+
+
+static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
+{
+ u8 dst_ca_comm_err = 0;
+
+ while (dst_ca_comm_err < RETRIES) {
+ dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
+ if (dst_ci_command(state, data, ca_string, len, read)) { // If error
+ dst_error_recovery(state);
+ dst_ca_comm_err++; // work required here.
+ } else {
+ break;
+ }
+ }
+
+ if(dst_ca_comm_err == RETRIES)
+ return -1;
+
+ return 0;
+}
+
+
+
+static int ca_get_app_info(struct dst_state *state)
+{
+ int length, str_length;
+ static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
+
+ put_checksum(&command[0], command[0]);
+ if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+ dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
+ dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
+ state->messages[7], (state->messages[8] << 8) | state->messages[9],
+ (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
+ dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
+
+ // Transform dst message to correct application_info message
+ length = state->messages[5];
+ str_length = length - 6;
+ if (str_length < 0) {
+ str_length = 0;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+ }
+
+ // First, the command and length fields
+ put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+ // Copy application_type, application_manufacturer and manufacturer_code
+ memcpy(&state->messages[4], &state->messages[7], 5);
+
+ // Set string length and copy string
+ state->messages[9] = str_length;
+ memcpy(&state->messages[10], &state->messages[12], str_length);
+
+ return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+ int srcPtr, dstPtr, i, num_ids;
+ static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+ const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+ put_checksum(&slot_command[0], slot_command[0]);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+ // Print raw data
+ dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+ for (i = 0; i < state->messages[0] + 1; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+ // Set the command and length of the output
+ num_ids = state->messages[in_num_ids_pos];
+ if (num_ids >= 100) {
+ num_ids = 100;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+ }
+ put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+ dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+ srcPtr = in_system_id_pos;
+ dstPtr = out_system_id_pos;
+ for(i = 0; i < num_ids; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+ // Append to output
+ state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+ state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+ srcPtr += 2;
+ dstPtr += 2;
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
+{
+ int i;
+ u8 slot_cap[256];
+ static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
+
+ put_checksum(&slot_command[0], slot_command[0]);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
+
+ /* Will implement the rest soon */
+
+ dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
+ dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
+ for (i = 0; i < slot_cap[0] + 1; i++)
+ dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
+ dprintk(verbose, DST_CA_INFO, 0, "\n");
+
+ p_ca_caps->slot_num = 1;
+ p_ca_caps->slot_type = 1;
+ p_ca_caps->descr_num = slot_cap[7];
+ p_ca_caps->descr_type = 1;
+
+ if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Need some more work */
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+ return -EOPNOTSUPP;
+}
+
+
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
+{
+ int i;
+ static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+
+ u8 *slot_info = state->messages;
+
+ put_checksum(&slot_command[0], 7);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+ /* Will implement the rest soon */
+
+ dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
+ dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
+ for (i = 0; i < 8; i++)
+ dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
+ dprintk(verbose, DST_CA_INFO, 0, "\n");
+
+ if (slot_info[4] & 0x80) {
+ p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
+ p_ca_slot_info->num = 1;
+ p_ca_slot_info->type = CA_CI;
+ } else if (slot_info[4] & 0x40) {
+ p_ca_slot_info->flags = CA_CI_MODULE_READY;
+ p_ca_slot_info->num = 1;
+ p_ca_slot_info->type = CA_CI;
+ } else
+ p_ca_slot_info->flags = 0;
+
+ if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+ u8 i = 0;
+ u32 command = 0;
+
+ if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
+ return -EFAULT;
+
+ if (p_ca_message->msg) {
+ dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]",
+ 3, p_ca_message->msg);
+
+ for (i = 0; i < 3; i++) {
+ command = command | p_ca_message->msg[i];
+ if (i < 2)
+ command = command << 8;
+ }
+ dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
+
+ switch (command) {
+ case CA_APP_INFO:
+ memcpy(p_ca_message->msg, state->messages, 128);
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+ return -EFAULT;
+ break;
+ case CA_INFO:
+ memcpy(p_ca_message->msg, state->messages, 128);
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+ return -EFAULT;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
+{
+ if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
+ hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
+ hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
+ } else {
+ if (length > 247) {
+ dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
+ return -1;
+ }
+ hw_buffer->msg[0] = (length & 0xff) + 7;
+ hw_buffer->msg[1] = 0x40;
+ hw_buffer->msg[2] = 0x03;
+ hw_buffer->msg[3] = 0x00;
+ hw_buffer->msg[4] = 0x03;
+ hw_buffer->msg[5] = length & 0xff;
+ hw_buffer->msg[6] = 0x00;
+
+ /*
+ * Need to compute length for EN50221 section 8.3.2, for the time being
+ * assuming 8.3.2 is not applicable
+ */
+ memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
+ }
+
+ return 0;
+}
+
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
+{
+ if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
+ dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
+ rdc_reset_state(state);
+ return -1;
+ }
+ dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
+
+ return 0;
+}
+
+static u32 asn_1_decode(u8 *asn_1_array)
+{
+ u8 length_field = 0, word_count = 0, count = 0;
+ u32 length = 0;
+
+ length_field = asn_1_array[0];
+ dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
+ if (length_field < 0x80) {
+ length = length_field & 0x7f;
+ dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
+ } else {
+ word_count = length_field & 0x7f;
+ for (count = 0; count < word_count; count++) {
+ length = length << 8;
+ length += asn_1_array[count + 1];
+ dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
+ }
+ }
+ return length;
+}
+
+static int debug_string(u8 *msg, u32 length, u32 offset)
+{
+ u32 i;
+
+ dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
+ for (i = offset; i < length; i++)
+ dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
+ dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
+
+ return 0;
+}
+
+
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+ u32 length = 0;
+ u8 tag_length = 8;
+
+ length = asn_1_decode(&p_ca_message->msg[3]);
+ dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
+ debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */
+
+ memset(hw_buffer->msg, '\0', length);
+ handle_dst_tag(state, p_ca_message, hw_buffer, length);
+ put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
+
+ debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */
+ write_to_8820(state, hw_buffer, (length + tag_length), reply);
+
+ return 0;
+}
+
+
+/* Board supports CA PMT reply ? */
+static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+{
+ int ca_pmt_reply_test = 0;
+
+ /* Do test board */
+ /* Not there yet but soon */
+
+ /* CA PMT Reply capable */
+ if (ca_pmt_reply_test) {
+ if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
+ return -1;
+ }
+
+ /* Process CA PMT Reply */
+ /* will implement soon */
+ dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
+ }
+ /* CA PMT Reply not capable */
+ if (!ca_pmt_reply_test) {
+ if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
+ /* put a dummy message */
+
+ }
+ return 0;
+}
+
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
+{
+ int i = 0;
+
+ u32 command = 0;
+ struct ca_msg *hw_buffer;
+ int result = 0;
+
+ if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
+ dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
+ return -ENOMEM;
+ }
+ dprintk(verbose, DST_CA_DEBUG, 1, " ");
+
+ if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
+ result = -EFAULT;
+ goto free_mem_and_exit;
+ }
+
+
+ if (p_ca_message->msg) {
+ /* EN50221 tag */
+ command = 0;
+
+ for (i = 0; i < 3; i++) {
+ command = command | p_ca_message->msg[i];
+ if (i < 2)
+ command = command << 8;
+ }
+ dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
+
+ switch (command) {
+ case CA_PMT:
+ dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
+ if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
+ break;
+ case CA_PMT_REPLY:
+ dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
+ /* Have to handle the 2 basic types of cards here */
+ if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
+ break;
+ case CA_APP_INFO_ENQUIRY: // only for debugging
+ dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
+
+ if ((ca_get_app_info(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
+ break;
+ case CA_INFO_ENQUIRY:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+ if ((ca_get_ca_info(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+ break;
+ }
+ }
+free_mem_and_exit:
+ kfree (hw_buffer);
+
+ return result;
+}
+
+static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
+{
+ struct dvb_device *dvbdev;
+ struct dst_state *state;
+ struct ca_slot_info *p_ca_slot_info;
+ struct ca_caps *p_ca_caps;
+ struct ca_msg *p_ca_message;
+ void __user *arg = (void __user *)ioctl_arg;
+ int result = 0;
+
+ mutex_lock(&dst_ca_mutex);
+ dvbdev = file->private_data;
+ state = (struct dst_state *)dvbdev->priv;
+ p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+ p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+ p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+ if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
+ dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
+ result = -ENOMEM;
+ goto free_mem_and_exit;
+ }
+
+ /* We have now only the standard ioctl's, the driver is upposed to handle internals. */
+ switch (cmd) {
+ case CA_SEND_MSG:
+ dprintk(verbose, DST_CA_INFO, 1, " Sending message");
+ if ((ca_send_message(state, p_ca_message, arg)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ break;
+ case CA_GET_MSG:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting message");
+ if ((ca_get_message(state, p_ca_message, arg)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
+ break;
+ case CA_RESET:
+ dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
+ dst_error_bailout(state);
+ msleep(4000);
+ break;
+ case CA_GET_SLOT_INFO:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
+ if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
+ break;
+ case CA_GET_CAP:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
+ if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
+ break;
+ case CA_GET_DESCR_INFO:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
+ if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
+ break;
+ case CA_SET_DESCR:
+ dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
+ if ((ca_set_slot_descr()) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
+ break;
+ case CA_SET_PID:
+ dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
+ if ((ca_set_pid()) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
+ default:
+ result = -EOPNOTSUPP;
+ };
+ free_mem_and_exit:
+ kfree (p_ca_message);
+ kfree (p_ca_slot_info);
+ kfree (p_ca_caps);
+
+ mutex_unlock(&dst_ca_mutex);
+ return result;
+}
+
+static int dst_ca_open(struct inode *inode, struct file *file)
+{
+ dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
+ try_module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static int dst_ca_release(struct inode *inode, struct file *file)
+{
+ dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
+{
+ ssize_t bytes_read = 0;
+
+ dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
+
+ return bytes_read;
+}
+
+static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
+{
+ dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
+
+ return 0;
+}
+
+static const struct file_operations dst_ca_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dst_ca_ioctl,
+ .open = dst_ca_open,
+ .release = dst_ca_release,
+ .read = dst_ca_read,
+ .write = dst_ca_write,
+ .llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_ca = {
+ .priv = NULL,
+ .users = 1,
+ .readers = 1,
+ .writers = 1,
+ .fops = &dst_ca_fops
+};
+
+struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+{
+ struct dvb_device *dvbdev;
+
+ dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
+ if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
+ dst->dst_ca = dvbdev;
+ return dst->dst_ca;
+ }
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(dst_ca_attach);
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/pci/bt8xx/dst_ca.h
index 59cd0ddd6d8e..59cd0ddd6d8e 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.h
+++ b/drivers/media/pci/bt8xx/dst_ca.h
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h
index d70d98f1a571..d70d98f1a571 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/pci/bt8xx/dst_common.h
diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/pci/bt8xx/dst_priv.h
index 3974a4c6ebe7..3974a4c6ebe7 100644
--- a/drivers/media/dvb/bt8xx/dst_priv.h
+++ b/drivers/media/pci/bt8xx/dst_priv.h
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
index 81fab9adc1ca..81fab9adc1ca 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/pci/bt8xx/dvb-bt8xx.h
index 4499ed2ac0ed..4499ed2ac0ed 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.h
diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig
new file mode 100644
index 000000000000..9a9f765dad45
--- /dev/null
+++ b/drivers/media/pci/cx18/Kconfig
@@ -0,0 +1,35 @@
+config VIDEO_CX18
+ tristate "Conexant cx23418 MPEG encoder support"
+ depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+ select I2C_ALGOBIT
+ select VIDEOBUF_VMALLOC
+ depends on RC_CORE
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_CS5345
+ select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for Conexant cx23418 based
+ PCI combo video recorder devices.
+
+ This is used in devices such as the Hauppauge HVR-1600
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18.
+
+config VIDEO_CX18_ALSA
+ tristate "Conexant 23418 DMA audio support"
+ depends on VIDEO_CX18 && SND && EXPERIMENTAL
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio on
+ Conexant 23418 based TV cards using ALSA.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18-alsa.
diff --git a/drivers/media/pci/cx18/Makefile b/drivers/media/pci/cx18/Makefile
new file mode 100644
index 000000000000..d3ff1545c2c5
--- /dev/null
+++ b/drivers/media/pci/cx18/Makefile
@@ -0,0 +1,13 @@
+cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
+ cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
+ cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
+ cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
+ cx18-dvb.o cx18-io.o
+cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
+
+obj-$(CONFIG_VIDEO_CX18) += cx18.o
+obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index 6d2a98246b6d..6d2a98246b6d 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c
index 341bddc00b77..341bddc00b77 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.c
+++ b/drivers/media/pci/cx18/cx18-alsa-mixer.c
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/pci/cx18/cx18-alsa-mixer.h
index ec9238793f6f..ec9238793f6f 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.h
+++ b/drivers/media/pci/cx18/cx18-alsa-mixer.h
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c
index 7a5b84a86bb3..7a5b84a86bb3 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/pci/cx18/cx18-alsa-pcm.h
index d26e51f94577..d26e51f94577 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.h
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.h
diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/pci/cx18/cx18-alsa.h
index 447da374c9e8..447da374c9e8 100644
--- a/drivers/media/video/cx18/cx18-alsa.h
+++ b/drivers/media/pci/cx18/cx18-alsa.h
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/pci/cx18/cx18-audio.c
index 35268923911c..35268923911c 100644
--- a/drivers/media/video/cx18/cx18-audio.c
+++ b/drivers/media/pci/cx18/cx18-audio.c
diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/pci/cx18/cx18-audio.h
index 2731d29b0ab9..2731d29b0ab9 100644
--- a/drivers/media/video/cx18/cx18-audio.h
+++ b/drivers/media/pci/cx18/cx18-audio.h
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c
index 4a24ffb17a7d..4a24ffb17a7d 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/pci/cx18/cx18-av-audio.c
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index f164b7f610a5..f164b7f610a5 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/pci/cx18/cx18-av-core.h
index e9c69d9c9e4a..e9c69d9c9e4a 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/pci/cx18/cx18-av-core.h
diff --git a/drivers/media/pci/cx18/cx18-av-firmware.c b/drivers/media/pci/cx18/cx18-av-firmware.c
new file mode 100644
index 000000000000..a34fd082b76e
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-av-firmware.c
@@ -0,0 +1,225 @@
+/*
+ * cx18 ADEC firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
+ *
+ * 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 "cx18-driver.h"
+#include "cx18-io.h"
+#include <linux/firmware.h>
+
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AI1_MUX_MASK 0x30
+#define CX18_AI1_MUX_I2S1 0x00
+#define CX18_AI1_MUX_I2S2 0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
+#define FWFILE "v4l-cx23418-dig.fw"
+
+static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
+{
+ struct v4l2_subdev *sd = &cx->av_state.sd;
+ int ret = 0;
+ const u8 *data;
+ u32 size;
+ int addr;
+ u32 expected, dl_control;
+
+ /* Ensure we put the 8051 in reset and enable firmware upload mode */
+ dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+ do {
+ dl_control &= 0x00ffffff;
+ dl_control |= 0x0f000000;
+ cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
+ dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+ } while ((dl_control & 0xff000000) != 0x0f000000);
+
+ /* Read and auto increment until at address 0x0000 */
+ while (dl_control & 0x3fff)
+ dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+
+ data = fw->data;
+ size = fw->size;
+ for (addr = 0; addr < size; addr++) {
+ dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
+ expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
+ if (expected != dl_control) {
+ CX18_ERR_DEV(sd, "verification of %s firmware load "
+ "failed: expected %#010x got %#010x\n",
+ FWFILE, expected, dl_control);
+ ret = -EIO;
+ break;
+ }
+ dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+ }
+ if (ret == 0)
+ CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
+ FWFILE, size);
+ return ret;
+}
+
+int cx18_av_loadfw(struct cx18 *cx)
+{
+ struct v4l2_subdev *sd = &cx->av_state.sd;
+ const struct firmware *fw = NULL;
+ u32 size;
+ u32 u, v;
+ const u8 *ptr;
+ int i;
+ int retries1 = 0;
+
+ if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) {
+ CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE);
+ return -EINVAL;
+ }
+
+ /* The firmware load often has byte errors, so allow for several
+ retries, both at byte level and at the firmware load level. */
+ while (retries1 < 5) {
+ cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
+ 0x00008430, 0xffffffff); /* cx25843 */
+ cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
+
+ /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
+ cx18_av_write4_expect(cx, 0x8100, 0x00010000,
+ 0x00008430, 0xffffffff); /* cx25843 */
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries2;
+ int unrec_err = 0;
+
+ for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES;
+ retries2++) {
+ cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
+ dl_control);
+ udelay(10);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if (value == dl_control)
+ break;
+ /* Check if we can correct the byte by changing
+ the address. We can only write the lower
+ address byte of the address. */
+ if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+ unrec_err = 1;
+ break;
+ }
+ }
+ if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES)
+ break;
+ }
+ if (i == size)
+ break;
+ retries1++;
+ }
+ if (retries1 >= 5) {
+ CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
+ }
+
+ cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+ 0x03000000 | fw->size, 0x03000000, 0x13000000);
+
+ CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+
+ if (cx18_av_verifyfw(cx, fw) == 0)
+ cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+ 0x13000000 | fw->size, 0x13000000, 0x13000000);
+
+ /* Output to the 416 */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
+
+ /* Audio input control 1 set to Sony mode */
+ /* Audio output input 2 is 0 for slave operation input */
+ /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
+
+ /* Audio output control 1 is set to Sony mode */
+ /* Audio output control 2 is set to 1 for master mode */
+ /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
+ are generated) */
+ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+ /* set alt I2s master clock to /0x16 and enable alt divider i2s
+ passthrough */
+ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687);
+
+ cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
+ 0x3F00FFFF);
+ /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
+
+ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
+ /* Register 0x09CC is defined by the Merlin firmware, and doesn't
+ have a name in the spec. */
+ cx18_av_write4(cx, 0x09CC, 1);
+
+ v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+ /* If bit 11 is 1, clear bit 10 */
+ if (v & 0x800)
+ cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
+ 0, 0x400);
+
+ /* Toggle the AI1 MUX */
+ v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+ u = v & CX18_AI1_MUX_MASK;
+ v &= ~CX18_AI1_MUX_MASK;
+ if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+ /* Switch to I2S1 */
+ v |= CX18_AI1_MUX_I2S1;
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+ /* Switch back to the A/V decoder core I2S output */
+ v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+ } else {
+ /* Switch to the A/V decoder core I2S output */
+ v |= CX18_AI1_MUX_843_I2S;
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+ /* Switch back to I2S1 or I2S2 */
+ v = (v & ~CX18_AI1_MUX_MASK) | u;
+ }
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+
+ /* Enable WW auto audio standard detection */
+ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+ v |= 0xFF; /* Auto by default */
+ v |= 0x400; /* Stereo by default */
+ v |= 0x14000000;
+ cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
+
+ release_firmware(fw);
+ return 0;
+}
+
+MODULE_FIRMWARE(FWFILE);
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/pci/cx18/cx18-av-vbi.c
index baa36fbcd4d4..baa36fbcd4d4 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/pci/cx18/cx18-av-vbi.c
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c
index c07c849b1aaf..c07c849b1aaf 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/pci/cx18/cx18-cards.c
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/pci/cx18/cx18-cards.h
index add7391ecaba..add7391ecaba 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/pci/cx18/cx18-cards.h
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c
index 282a3d29fdaa..282a3d29fdaa 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/pci/cx18/cx18-controls.c
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/pci/cx18/cx18-controls.h
index cb5dfc7b2054..cb5dfc7b2054 100644
--- a/drivers/media/video/cx18/cx18-controls.h
+++ b/drivers/media/pci/cx18/cx18-controls.h
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
new file mode 100644
index 000000000000..c67733d32c8a
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -0,0 +1,1360 @@
+/*
+ * cx18 driver initialization and card probing
+ *
+ * Derived from ivtv-driver.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
+ *
+ * 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
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-version.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+#include "cx18-gpio.h"
+#include "cx18-firmware.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-av-core.h"
+#include "cx18-scb.h"
+#include "cx18-mailbox.h"
+#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
+ the device numbers stay matched. Example: you have a WinTV card
+ without radio and a Compro H900 with. Normally this would give a
+ video1 device together with a radio0 device for the Compro. By
+ setting this to 1 you ensure that radio0 is now also radio1. */
+int cx18_first_minor;
+
+/* Callback for registering extensions */
+int (*cx18_ext_init)(struct cx18 *);
+EXPORT_SYMBOL(cx18_ext_init);
+
+/* add your revision and whatnot here */
+static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
+static atomic_t cx18_instance = ATOMIC_INIT(0);
+
+/* Parameter declarations */
+static int cardtype[CX18_MAX_CARDS];
+static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
+static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+
+static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
+static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
+static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
+static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
+static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
+
+static int enc_ts_bufs = -1;
+static int enc_mpg_bufs = -1;
+static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM;
+static int enc_yuv_bufs = -1;
+static int enc_vbi_bufs = -1;
+static int enc_pcm_bufs = -1;
+
+
+static int cx18_pci_latency = 1;
+
+static int mmio_ndelay;
+static int retry_mmio = 1;
+
+int cx18_debug;
+
+module_param_array(tuner, int, &tuner_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);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug, cx18_debug, int, 0644);
+module_param(mmio_ndelay, int, 0644);
+module_param(retry_mmio, int, 0644);
+module_param(cx18_pci_latency, int, 0644);
+module_param(cx18_first_minor, int, 0644);
+
+module_param(enc_ts_buffers, int, 0644);
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_idx_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+
+module_param(enc_ts_bufsize, int, 0644);
+module_param(enc_mpg_bufsize, int, 0644);
+module_param(enc_idx_bufsize, int, 0644);
+module_param(enc_yuv_bufsize, int, 0644);
+module_param(enc_pcm_bufsize, int, 0644);
+
+module_param(enc_ts_bufs, int, 0644);
+module_param(enc_mpg_bufs, int, 0644);
+module_param(enc_idx_bufs, int, 0644);
+module_param(enc_yuv_bufs, int, 0644);
+module_param(enc_vbi_bufs, int, 0644);
+module_param(enc_pcm_bufs, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+ "\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+ "Enable or disable the radio. Use only if autodetection\n"
+ "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+ "Only use this option if your card is not detected properly.\n"
+ "\t\tSpecify card type:\n"
+ "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
+ "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
+ "\t\t\t 3 = Compro VideoMate H900\n"
+ "\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
+ "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
+ "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+ "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
+ "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
+ "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n"
+ "\t\t\t 0 = Autodetect (default)\n"
+ "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n"
+ "\t\t\t 4/0x0004: mailbox\n"
+ "\t\t\t 8/0x0008: dma\n"
+ "\t\t\t 16/0x0010: ioctl\n"
+ "\t\t\t 32/0x0020: file\n"
+ "\t\t\t 64/0x0040: i2c\n"
+ "\t\t\t128/0x0080: irq\n"
+ "\t\t\t256/0x0100: high volume\n");
+MODULE_PARM_DESC(cx18_pci_latency,
+ "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+ "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(retry_mmio,
+ "(Deprecated) MMIO writes are now always checked and retried\n"
+ "\t\t\tEffectively: 1 [Yes]");
+MODULE_PARM_DESC(mmio_ndelay,
+ "(Deprecated) MMIO accesses are now never purposely delayed\n"
+ "\t\t\tEffectively: 0 ns");
+MODULE_PARM_DESC(enc_ts_buffers,
+ "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_ts_bufsize,
+ "Size of an encoder TS buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
+MODULE_PARM_DESC(enc_ts_bufs,
+ "Number of encoder TS buffers\n"
+ "\t\t\tDefault is computed from other enc_ts_* parameters");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_mpg_bufsize,
+ "Size of an encoder MPG buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
+MODULE_PARM_DESC(enc_mpg_bufs,
+ "Number of encoder MPG buffers\n"
+ "\t\t\tDefault is computed from other enc_mpg_* parameters");
+MODULE_PARM_DESC(enc_idx_buffers,
+ "(Deprecated) Encoder IDX buffer memory (MB)\n"
+ "\t\t\tIgnored, except 0 disables IDX buffer allocations\n"
+ "\t\t\tDefault: 1 [Enabled]");
+MODULE_PARM_DESC(enc_idx_bufsize,
+ "Size of an encoder IDX buffer (kB)\n"
+ "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n"
+ "\t\t\t(multiples of size required for 64 index entries)\n"
+ "\t\t\tDefault: 2");
+MODULE_PARM_DESC(enc_idx_bufs,
+ "Number of encoder IDX buffers\n"
+ "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM));
+MODULE_PARM_DESC(enc_yuv_buffers,
+ "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_bufsize,
+ "Size of an encoder YUV buffer (kB)\n"
+ "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
+ "\t\t\t(multiples of size required for 32 screen lines)\n"
+ "\t\t\tDefault: 102");
+MODULE_PARM_DESC(enc_yuv_bufs,
+ "Number of encoder YUV buffers\n"
+ "\t\t\tDefault is computed from other enc_yuv_* parameters");
+MODULE_PARM_DESC(enc_vbi_buffers,
+ "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_bufs,
+ "Number of encoder VBI buffers\n"
+ "\t\t\tDefault is computed from enc_vbi_buffers");
+MODULE_PARM_DESC(enc_pcm_buffers,
+ "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_bufsize,
+ "Size of an encoder PCM buffer (kB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
+MODULE_PARM_DESC(enc_pcm_bufs,
+ "Number of encoder PCM buffers\n"
+ "\t\t\tDefault is computed from other enc_pcm_* parameters");
+
+MODULE_PARM_DESC(cx18_first_minor,
+ "Set device node number assigned to first card");
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("CX23418 driver");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+ struct cx18 *dev = container_of(work, struct cx18, request_module_wk);
+
+ /* Make sure cx18-alsa module is loaded */
+ request_module("cx18-alsa");
+
+ /* Initialize cx18-alsa for this instance of the cx18 device */
+ if (cx18_ext_init != NULL)
+ cx18_ext_init(dev);
+}
+
+static void request_modules(struct cx18 *dev)
+{
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+ schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct cx18 *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/* Generic utility functions */
+int cx18_msleep_timeout(unsigned int msecs, int intr)
+{
+ long int timeout = msecs_to_jiffies(msecs);
+ int sig;
+
+ do {
+ set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ sig = intr ? signal_pending(current) : 0;
+ } while (!sig && timeout);
+ return sig;
+}
+
+/* Release ioremapped memory */
+static void cx18_iounmap(struct cx18 *cx)
+{
+ if (cx == NULL)
+ return;
+
+ /* Release io memory */
+ if (cx->enc_mem != NULL) {
+ CX18_DEBUG_INFO("releasing enc_mem\n");
+ iounmap(cx->enc_mem);
+ cx->enc_mem = NULL;
+ }
+}
+
+static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
+{
+ int i;
+
+ CX18_INFO("eeprom dump:\n");
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ CX18_INFO("eeprom %02x:", i);
+ printk(KERN_CONT " %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk(KERN_CONT "\n");
+ }
+}
+
+/* Hauppauge card? get values from tveeprom */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+{
+ struct i2c_client c;
+ u8 eedata[256];
+
+ memset(&c, 0, sizeof(c));
+ strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
+ c.adapter = &cx->i2c_adap[0];
+ c.addr = 0xA0 >> 1;
+
+ memset(tv, 0, sizeof(*tv));
+ if (tveeprom_read(&c, eedata, sizeof(eedata)))
+ return;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ case CX18_CARD_HVR_1600_S5H1411:
+ tveeprom_hauppauge_analog(&c, tv, eedata);
+ break;
+ case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
+ tv->model = 0x718;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
+ eedata[2], eedata[1], eedata[4], eedata[3]);
+ break;
+ default:
+ tv->model = 0xffffffff;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ break;
+ }
+}
+
+static void cx18_process_eeprom(struct cx18 *cx)
+{
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+
+ /* Many thanks to Steven Toth from Hauppauge for providing the
+ model numbers */
+ /* Note: the Samsung memory models cannot be reliably determined
+ from the model number. Use the cardtype module option if you
+ have one of these preproduction models. */
+ switch (tv.model) {
+ case 74301: /* Retail models */
+ case 74321:
+ case 74351: /* OEM models */
+ case 74361:
+ /* Digital side is s5h1411/tda18271 */
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411);
+ break;
+ case 74021: /* Retail models */
+ case 74031:
+ case 74041:
+ case 74141:
+ case 74541: /* OEM models */
+ case 74551:
+ case 74591:
+ case 74651:
+ case 74691:
+ case 74751:
+ case 74891:
+ /* Digital side is s5h1409/mxl5005s */
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ case 0x718:
+ return;
+ case 0xffffffff:
+ CX18_INFO("Unknown EEPROM encoding\n");
+ return;
+ case 0:
+ CX18_ERR("Invalid EEPROM\n");
+ return;
+ default:
+ CX18_ERR("Unknown model %d, defaulting to original HVR-1600 "
+ "(cardtype=1)\n", tv.model);
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ }
+
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+
+ CX18_INFO("Autodetected %s\n", cx->card_name);
+
+ if (tv.tuner_type == TUNER_ABSENT)
+ CX18_ERR("tveeprom cannot autodetect tuner!\n");
+
+ if (cx->options.tuner == -1)
+ cx->options.tuner = tv.tuner_type;
+ if (cx->options.radio == -1)
+ cx->options.radio = (tv.has_radio != 0);
+
+ if (cx->std != 0)
+ /* user specified tuner standard */
+ return;
+
+ /* autodetect tuner standard */
+#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \
+ V4L2_STD_MN | \
+ V4L2_STD_PAL_I | \
+ V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
+ V4L2_STD_DK)
+ if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
+ == TVEEPROM_TUNER_FORMAT_ALL) {
+ CX18_DEBUG_INFO("Worldwide tuner detected\n");
+ cx->std = V4L2_STD_ALL;
+ } else if (tv.tuner_formats & V4L2_STD_PAL) {
+ CX18_DEBUG_INFO("PAL tuner detected\n");
+ cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ } else if (tv.tuner_formats & V4L2_STD_NTSC) {
+ CX18_DEBUG_INFO("NTSC tuner detected\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ } else if (tv.tuner_formats & V4L2_STD_SECAM) {
+ CX18_DEBUG_INFO("SECAM tuner detected\n");
+ cx->std |= V4L2_STD_SECAM_L;
+ } else {
+ CX18_INFO("No tuner detected, default to NTSC-M\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ }
+}
+
+static v4l2_std_id cx18_parse_std(struct cx18 *cx)
+{
+ switch (pal[0]) {
+ case '6':
+ return V4L2_STD_PAL_60;
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ return V4L2_STD_PAL_BG;
+ case 'h':
+ case 'H':
+ return V4L2_STD_PAL_H;
+ case 'n':
+ case 'N':
+ if (pal[1] == 'c' || pal[1] == 'C')
+ return V4L2_STD_PAL_Nc;
+ return V4L2_STD_PAL_N;
+ case 'i':
+ case 'I':
+ return V4L2_STD_PAL_I;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_PAL_DK;
+ case 'M':
+ case 'm':
+ return V4L2_STD_PAL_M;
+ case '-':
+ break;
+ default:
+ CX18_WARN("pal= argument not recognised\n");
+ return 0;
+ }
+
+ switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_SECAM_DK;
+ case 'l':
+ case 'L':
+ if (secam[1] == 'C' || secam[1] == 'c')
+ return V4L2_STD_SECAM_LC;
+ return V4L2_STD_SECAM_L;
+ case '-':
+ break;
+ default:
+ CX18_WARN("secam= argument not recognised\n");
+ return 0;
+ }
+
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ return V4L2_STD_NTSC_M;
+ case 'j':
+ case 'J':
+ return V4L2_STD_NTSC_M_JP;
+ case 'k':
+ case 'K':
+ return V4L2_STD_NTSC_M_KR;
+ case '-':
+ break;
+ default:
+ CX18_WARN("ntsc= argument not recognised\n");
+ return 0;
+ }
+
+ /* no match found */
+ return 0;
+}
+
+static void cx18_process_options(struct cx18 *cx)
+{
+ int i, j;
+
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
+
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
+ cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+ /* Ensure stream_buffers & stream_buf_size are valid */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */
+ cx->options.megabytes[i] <= 0 || /* User said 0 MB total */
+ cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+ /*
+ * YUV is a special case where the stream_buf_size needs to be
+ * an integral multiple of 33.75 kB (storage for 32 screens
+ * lines to maintain alignment in case of lost buffers).
+ *
+ * IDX is a special case where the stream_buf_size should be
+ * an integral multiple of 1.5 kB (storage for 64 index entries
+ * to maintain alignment in case of lost buffers).
+ *
+ */
+ if (i == CX18_ENC_STREAM_TYPE_YUV) {
+ cx->stream_buf_size[i] *= 1024;
+ cx->stream_buf_size[i] -=
+ (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
+
+ if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
+ cx->stream_buf_size[i] =
+ CX18_UNIT_ENC_YUV_BUFSIZE;
+ } else if (i == CX18_ENC_STREAM_TYPE_IDX) {
+ cx->stream_buf_size[i] *= 1024;
+ cx->stream_buf_size[i] -=
+ (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE);
+
+ if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE)
+ cx->stream_buf_size[i] =
+ CX18_UNIT_ENC_IDX_BUFSIZE;
+ }
+ /*
+ * YUV and IDX are special cases where the stream_buf_size is
+ * now in bytes.
+ * VBI is a special case where the stream_buf_size is fixed
+ * and already in bytes
+ */
+ if (i == CX18_ENC_STREAM_TYPE_VBI ||
+ i == CX18_ENC_STREAM_TYPE_YUV ||
+ i == CX18_ENC_STREAM_TYPE_IDX) {
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] =
+ cx->options.megabytes[i] * 1024 * 1024
+ / cx->stream_buf_size[i];
+ } else {
+ /* N.B. This might round down to 0 */
+ cx->options.megabytes[i] =
+ cx->stream_buffers[i]
+ * cx->stream_buf_size[i]/(1024 * 1024);
+ }
+ } else {
+ /* All other streams have stream_buf_size in kB here */
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] =
+ cx->options.megabytes[i] * 1024
+ / cx->stream_buf_size[i];
+ } else {
+ /* N.B. This might round down to 0 */
+ cx->options.megabytes[i] =
+ cx->stream_buffers[i]
+ * cx->stream_buf_size[i] / 1024;
+ }
+ /* convert from kB to bytes */
+ cx->stream_buf_size[i] *= 1024;
+ }
+ CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
+ "%d bytes\n", i, cx->options.megabytes[i],
+ cx->stream_buffers[i], cx->stream_buf_size[i]);
+ }
+
+ cx->options.cardtype = cardtype[cx->instance];
+ cx->options.tuner = tuner[cx->instance];
+ cx->options.radio = radio[cx->instance];
+
+ cx->std = cx18_parse_std(cx);
+ if (cx->options.cardtype == -1) {
+ CX18_INFO("Ignore card\n");
+ return;
+ }
+ cx->card = cx18_get_card(cx->options.cardtype - 1);
+ if (cx->card)
+ CX18_INFO("User specified %s card\n", cx->card->name);
+ else if (cx->options.cardtype != 0)
+ CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+ if (cx->card == NULL) {
+ if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_INFO("Autodetected Hauppauge card\n");
+ }
+ }
+ if (cx->card == NULL) {
+ for (i = 0; (cx->card = cx18_get_card(i)); i++) {
+ if (cx->card->pci_list == NULL)
+ continue;
+ for (j = 0; cx->card->pci_list[j].device; j++) {
+ if (cx->pci_dev->device !=
+ cx->card->pci_list[j].device)
+ continue;
+ if (cx->pci_dev->subsystem_vendor !=
+ cx->card->pci_list[j].subsystem_vendor)
+ continue;
+ if (cx->pci_dev->subsystem_device !=
+ cx->card->pci_list[j].subsystem_device)
+ continue;
+ CX18_INFO("Autodetected %s card\n", cx->card->name);
+ goto done;
+ }
+ }
+ }
+done:
+
+ if (cx->card == NULL) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
+ cx->pci_dev->vendor, cx->pci_dev->device);
+ CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n",
+ cx->pci_dev->subsystem_vendor,
+ cx->pci_dev->subsystem_device);
+ CX18_ERR("Defaulting to %s card\n", cx->card->name);
+ CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+ CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
+ }
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+}
+
+static int __devinit cx18_create_in_workq(struct cx18 *cx)
+{
+ snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
+ cx->v4l2_dev.name);
+ cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
+ if (cx->in_work_queue == NULL) {
+ CX18_ERR("Unable to create incoming mailbox handler thread\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+{
+ int i;
+ for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+ cx->in_work_order[i].cx = cx;
+ cx->in_work_order[i].str = cx->epu_debug_str;
+ INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
+ }
+}
+
+/* Precondition: the cx18 structure has been memset to 0. Only
+ the dev and instance fields have been filled in.
+ No assumptions on the card type may be made here (see cx18_init_struct2
+ for that).
+ */
+static int __devinit cx18_init_struct1(struct cx18 *cx)
+{
+ int ret;
+
+ cx->base_addr = pci_resource_start(cx->pci_dev, 0);
+
+ mutex_init(&cx->serialize_lock);
+ mutex_init(&cx->gpio_lock);
+ mutex_init(&cx->epu2apu_mb_lock);
+ mutex_init(&cx->epu2cpu_mb_lock);
+
+ ret = cx18_create_in_workq(cx);
+ if (ret)
+ return ret;
+
+ cx18_init_in_work_orders(cx);
+
+ /* start counting open_id at 1 */
+ cx->open_id = 1;
+
+ /* Initial settings */
+ cx->cxhdl.port = CX2341X_PORT_MEMORY;
+ cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+ cx->cxhdl.ops = &cx18_cxhdl_ops;
+ cx->cxhdl.func = cx18_api_func;
+ cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+ ret = cx2341x_handler_init(&cx->cxhdl, 50);
+ if (ret)
+ return ret;
+ cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
+
+ cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
+ cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
+ cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
+ (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
+ (cx->cxhdl.video_median_filter_type->cur.val << 2);
+
+ init_waitqueue_head(&cx->cap_w);
+ init_waitqueue_head(&cx->mb_apu_waitq);
+ init_waitqueue_head(&cx->mb_cpu_waitq);
+ init_waitqueue_head(&cx->dma_waitq);
+
+ /* VBI */
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+
+ /* IVTV style VBI insertion into MPEG streams */
+ INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list);
+ INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list);
+ INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list);
+ list_add(&cx->vbi.sliced_mpeg_buf.list,
+ &cx->vbi.sliced_mpeg_mdl.buf_list);
+ return 0;
+}
+
+/* Second initialization part. Here the card type has been
+ autodetected. */
+static void __devinit cx18_init_struct2(struct cx18 *cx)
+{
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
+ if (cx->card->video_inputs[i].video_type == 0)
+ break;
+ cx->nof_inputs = i;
+ for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
+ if (cx->card->audio_inputs[i].audio_type == 0)
+ break;
+ cx->nof_audio_inputs = i;
+
+ /* Find tuner input */
+ for (i = 0; i < cx->nof_inputs; i++) {
+ if (cx->card->video_inputs[i].video_type ==
+ CX18_CARD_INPUT_VID_TUNER)
+ break;
+ }
+ if (i == cx->nof_inputs)
+ i = 0;
+ cx->active_input = i;
+ cx->audio_input = cx->card->video_inputs[i].audio_index;
+}
+
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 cmd;
+ unsigned char pci_latency;
+
+ CX18_DEBUG_INFO("Enabling pci device\n");
+
+ if (pci_enable_device(pci_dev)) {
+ CX18_ERR("Can't enable device %d!\n", cx->instance);
+ return -EIO;
+ }
+ if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
+ CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
+ return -EIO;
+ }
+ if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+ CX18_ERR("Cannot request encoder memory region, card %d\n",
+ cx->instance);
+ return -EIO;
+ }
+
+ /* Enable bus mastering and memory mapped IO for the CX23418 */
+ pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
+
+ cx->card_rev = pci_dev->revision;
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && cx18_pci_latency) {
+ CX18_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+ pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+
+ CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%llx\n",
+ cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
+ PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
+ cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
+
+ return 0;
+}
+
+static void cx18_init_subdevs(struct cx18 *cx)
+{
+ u32 hw = cx->card->hw_all;
+ u32 device;
+ int i;
+
+ for (i = 0, device = 1; i < 32; i++, device <<= 1) {
+
+ if (!(device & hw))
+ continue;
+
+ switch (device) {
+ case CX18_HW_DVB:
+ case CX18_HW_TVEEPROM:
+ /* These subordinate devices do not use probing */
+ cx->hw_flags |= device;
+ break;
+ case CX18_HW_418_AV:
+ /* The A/V decoder gets probed earlier to set PLLs */
+ /* Just note that the card uses it (i.e. has analog) */
+ cx->hw_flags |= device;
+ break;
+ case CX18_HW_GPIO_RESET_CTRL:
+ /*
+ * The Reset Controller gets probed and added to
+ * hw_flags earlier for i2c adapter/bus initialization
+ */
+ break;
+ case CX18_HW_GPIO_MUX:
+ if (cx18_gpio_register(cx, device) == 0)
+ cx->hw_flags |= device;
+ break;
+ default:
+ if (cx18_i2c_register(cx, i) == 0)
+ cx->hw_flags |= device;
+ break;
+ }
+ }
+
+ if (cx->hw_flags & CX18_HW_418_AV)
+ cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
+
+ if (cx->card->hw_muxer != 0)
+ cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
+}
+
+static int __devinit cx18_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ int retval = 0;
+ int i;
+ u32 devtype;
+ struct cx18 *cx;
+
+ /* FIXME - module parameter arrays constrain max instances */
+ i = atomic_inc_return(&cx18_instance) - 1;
+ if (i >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
+ "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
+ return -ENOMEM;
+ }
+
+ cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+ if (cx == NULL) {
+ printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
+ i);
+ return -ENOMEM;
+ }
+ cx->pci_dev = pci_dev;
+ cx->instance = i;
+
+ retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
+ if (retval) {
+ printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
+ "\n", cx->instance);
+ kfree(cx);
+ return retval;
+ }
+ snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
+ cx->instance);
+ CX18_INFO("Initializing card %d\n", cx->instance);
+
+ cx18_process_options(cx);
+ if (cx->options.cardtype == -1) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ retval = cx18_init_struct1(cx);
+ if (retval)
+ goto err;
+
+ CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr);
+
+ /* PCI Device Setup */
+ retval = cx18_setup_pci(cx, pci_dev, pci_id);
+ if (retval != 0)
+ goto free_workqueues;
+
+ /* map io memory */
+ CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
+ (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+ cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
+ CX18_MEM_SIZE);
+ if (!cx->enc_mem) {
+ CX18_ERR("ioremap failed. Can't get a window into CX23418 "
+ "memory and register space\n");
+ CX18_ERR("Each capture card with a CX23418 needs 64 MB of "
+ "vmalloc address space for the window\n");
+ CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ CX18_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
+ retval = -ENOMEM;
+ goto free_mem;
+ }
+ cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
+ devtype = cx18_read_reg(cx, 0xC72028);
+ switch (devtype & 0xff000000) {
+ case 0xff000000:
+ CX18_INFO("cx23418 revision %08x (A)\n", devtype);
+ break;
+ case 0x01000000:
+ CX18_INFO("cx23418 revision %08x (B)\n", devtype);
+ break;
+ default:
+ CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
+ break;
+ }
+
+ cx18_init_power(cx, 1);
+ cx18_init_memory(cx);
+
+ cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
+ cx18_init_scb(cx);
+
+ cx18_gpio_init(cx);
+
+ /* Initialize integrated A/V decoder early to set PLLs, just in case */
+ retval = cx18_av_probe(cx);
+ if (retval) {
+ CX18_ERR("Could not register A/V decoder subdevice\n");
+ goto free_map;
+ }
+
+ /* Initialize GPIO Reset Controller to do chip resets during i2c init */
+ if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
+ if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
+ CX18_WARN("Could not register GPIO reset controller"
+ "subdevice; proceeding anyway.\n");
+ else
+ cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
+ }
+
+ /* active i2c */
+ CX18_DEBUG_INFO("activating i2c...\n");
+ retval = init_cx18_i2c(cx);
+ if (retval) {
+ CX18_ERR("Could not initialize i2c\n");
+ goto free_map;
+ }
+
+ if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+ /* Based on the model number the cardtype may be changed.
+ The PCI IDs are not always reliable. */
+ const struct cx18_card *orig_card = cx->card;
+ cx18_process_eeprom(cx);
+
+ if (cx->card != orig_card) {
+ /* Changed the cardtype; re-reset the I2C chips */
+ cx18_gpio_init(cx);
+ cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+ core, reset, (u32) CX18_GPIO_RESET_I2C);
+ }
+ }
+ if (cx->card->comment)
+ CX18_INFO("%s", cx->card->comment);
+ if (cx->card->v4l2_capabilities == 0) {
+ retval = -ENODEV;
+ goto free_i2c;
+ }
+ cx18_init_memory(cx);
+ cx18_init_scb(cx);
+
+ /* Register IRQ */
+ retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
+ IRQF_SHARED | IRQF_DISABLED,
+ cx->v4l2_dev.name, (void *)cx);
+ if (retval) {
+ CX18_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+ }
+
+ if (cx->std == 0)
+ cx->std = V4L2_STD_NTSC_M;
+
+ if (cx->options.tuner == -1) {
+ for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
+ if ((cx->std & cx->card->tuners[i].std) == 0)
+ continue;
+ cx->options.tuner = cx->card->tuners[i].tuner;
+ break;
+ }
+ }
+ /* if no tuner was found, then pick the first tuner in the card list */
+ if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
+ cx->std = cx->card->tuners[0].std;
+ if (cx->std & V4L2_STD_PAL)
+ cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ else if (cx->std & V4L2_STD_NTSC)
+ cx->std = V4L2_STD_NTSC_M;
+ else if (cx->std & V4L2_STD_SECAM)
+ cx->std = V4L2_STD_SECAM_L;
+ cx->options.tuner = cx->card->tuners[0].tuner;
+ }
+ if (cx->options.radio == -1)
+ cx->options.radio = (cx->card->radio_input.audio_type != 0);
+
+ /* The card is now fully identified, continue with card-specific
+ initialization. */
+ cx18_init_struct2(cx);
+
+ cx18_init_subdevs(cx);
+
+ if (cx->std & V4L2_STD_525_60)
+ cx->is_60hz = 1;
+ else
+ cx->is_50hz = 1;
+
+ cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
+
+ if (cx->options.radio > 0)
+ cx->v4l2_cap |= V4L2_CAP_RADIO;
+
+ if (cx->options.tuner > -1) {
+ struct tuner_setup setup;
+
+ setup.addr = ADDR_UNSET;
+ setup.type = cx->options.tuner;
+ setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
+ if (cx->options.radio > 0)
+ setup.mode_mask |= T_RADIO;
+ setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+ cx18_reset_tuner_gpio : NULL;
+ cx18_call_all(cx, tuner, s_type_addr, &setup);
+ if (setup.type == TUNER_XC2028) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = cx->options.tuner,
+ .priv = &ctrl,
+ };
+ cx18_call_all(cx, tuner, s_config, &cfg);
+ }
+ }
+
+ /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+ are not. */
+ cx->tuner_std = cx->std;
+ if (cx->std == V4L2_STD_ALL)
+ cx->std = V4L2_STD_NTSC_M;
+
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
+
+ CX18_INFO("Initialized card: %s\n", cx->card_name);
+
+ /* Load cx18 submodules (cx18-alsa) */
+ request_modules(cx);
+ return 0;
+
+free_streams:
+ cx18_streams_cleanup(cx, 1);
+free_irq:
+ free_irq(cx->pci_dev->irq, (void *)cx);
+free_i2c:
+ exit_cx18_i2c(cx);
+free_map:
+ cx18_iounmap(cx);
+free_mem:
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+free_workqueues:
+ destroy_workqueue(cx->in_work_queue);
+err:
+ if (retval == 0)
+ retval = -ENODEV;
+ CX18_ERR("Error %d on initialization\n", retval);
+
+ v4l2_device_unregister(&cx->v4l2_dev);
+ kfree(cx);
+ return retval;
+}
+
+int cx18_init_on_first_open(struct cx18 *cx)
+{
+ int video_input;
+ int fw_retry_count = 3;
+ struct v4l2_frequency vf;
+ struct cx18_open_id fh;
+ v4l2_std_id std;
+
+ fh.cx = cx;
+
+ if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+ set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+ /*
+ * Init the firmware twice to work around a silicon bug
+ * with the digital TS.
+ *
+ * The second firmware load requires us to normalize the APU state,
+ * or the audio for the first analog capture will be badly incorrect.
+ *
+ * I can't seem to call APU_RESETAI and have it succeed without the
+ * APU capturing audio, so we start and stop it here to do the reset
+ */
+
+ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+ cx18_vapi(cx, CX18_APU_RESETAI, 0);
+ cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+ fw_retry_count = 3;
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+
+ /*
+ * The second firmware load requires us to normalize the APU state,
+ * or the audio for the first analog capture will be badly incorrect.
+ *
+ * I can't seem to call APU_RESETAI and have it succeed without the
+ * APU capturing audio, so we start and stop it here to do the reset
+ */
+
+ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
+ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
+ cx18_vapi(cx, CX18_APU_RESETAI, 0);
+ cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+ /* Init the A/V decoder, if it hasn't been already */
+ v4l2_subdev_call(cx->sd_av, core, load_fw);
+
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+ /* Set initial frequency. For PAL/SECAM broadcasts no
+ 'default' channel exists AFAIK. */
+ if (cx->std == V4L2_STD_NTSC_M_JP)
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ else if (cx->std & V4L2_STD_NTSC_M)
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+
+ video_input = cx->active_input;
+ cx->active_input++; /* Force update of input */
+ cx18_s_input(NULL, &fh, video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ cx->std++; /* Force full standard initialization */
+ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
+ cx18_s_std(NULL, &fh, &std);
+ cx18_s_frequency(NULL, &fh, &vf);
+ return 0;
+}
+
+static void cx18_cancel_in_work_orders(struct cx18 *cx)
+{
+ int i;
+ for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
+ cancel_work_sync(&cx->in_work_order[i].work);
+}
+
+static void cx18_cancel_out_work_orders(struct cx18 *cx)
+{
+ int i;
+ for (i = 0; i < CX18_MAX_STREAMS; i++)
+ if (&cx->streams[i].video_dev != NULL)
+ cancel_work_sync(&cx->streams[i].out_work_order);
+}
+
+static void cx18_remove(struct pci_dev *pci_dev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct cx18 *cx = to_cx18(v4l2_dev);
+ int i;
+
+ CX18_DEBUG_INFO("Removing Card\n");
+
+ flush_request_modules(cx);
+
+ /* Stop all captures */
+ CX18_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&cx->tot_capturing) > 0)
+ cx18_stop_all_captures(cx);
+
+ /* Stop interrupts that cause incoming work to be queued */
+ cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+
+ /* Incoming work can cause outgoing work, so clean up incoming first */
+ cx18_cancel_in_work_orders(cx);
+ cx18_cancel_out_work_orders(cx);
+
+ /* Stop ack interrupts that may have been needed for work to finish */
+ cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+
+ destroy_workqueue(cx->in_work_queue);
+
+ cx18_streams_cleanup(cx, 1);
+
+ exit_cx18_i2c(cx);
+
+ free_irq(cx->pci_dev->irq, (void *)cx);
+
+ cx18_iounmap(cx);
+
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+ pci_disable_device(cx->pci_dev);
+
+ if (cx->vbi.sliced_mpeg_data[0] != NULL)
+ for (i = 0; i < CX18_VBI_FRAMES; i++)
+ kfree(cx->vbi.sliced_mpeg_data[i]);
+
+ v4l2_ctrl_handler_free(&cx->av_state.hdl);
+
+ CX18_INFO("Removed %s\n", cx->card_name);
+
+ v4l2_device_unregister(v4l2_dev);
+ kfree(cx);
+}
+
+
+/* define a pci_driver for card detection */
+static struct pci_driver cx18_pci_driver = {
+ .name = "cx18",
+ .id_table = cx18_pci_tbl,
+ .probe = cx18_probe,
+ .remove = cx18_remove,
+};
+
+static int __init module_start(void)
+{
+ printk(KERN_INFO "cx18: Start initialization, version %s\n",
+ CX18_VERSION);
+
+ /* Validate parameters */
+ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
+ CX18_MAX_CARDS - 1);
+ return -1;
+ }
+
+ if (cx18_debug < 0 || cx18_debug > 511) {
+ cx18_debug = 0;
+ printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
+ }
+
+ if (pci_register_driver(&cx18_pci_driver)) {
+ printk(KERN_ERR "cx18: Error detecting PCI card\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "cx18: End initialization\n");
+ return 0;
+}
+
+static void __exit module_cleanup(void)
+{
+ pci_unregister_driver(&cx18_pci_driver);
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
index 2767c64df0c8..2767c64df0c8 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/pci/cx18/cx18-driver.h
diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c
new file mode 100644
index 000000000000..3eac59c51231
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-dvb.c
@@ -0,0 +1,609 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
+ *
+ * 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 "cx18-version.h"
+#include "cx18-dvb.h"
+#include "cx18-io.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "s5h1409.h"
+#include "mxl5005s.h"
+#include "s5h1411.h"
+#include "tda18271.h"
+#include "zl10353.h"
+
+#include <linux/firmware.h>
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "tuner-xc2028.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define FWFILE "dvb-cx18-mpc718-mt352.fw"
+
+#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+#define CX18_CLOCK_ENABLE2 0xc71024
+#define CX18_DMUX_CLK_MASK 0x0080
+
+/*
+ * CX18_CARD_HVR_1600_ESMT
+ * CX18_CARD_HVR_1600_SAMSUNG
+ */
+
+static struct mxl5005s_config hauppauge_hvr1600_tuner = {
+ .i2c_address = 0xC6 >> 1,
+ .if_freq = IF_FREQ_5380000HZ,
+ .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,
+ .qam_gain = 0x02,
+ .AgcMasterByte = 0x00,
+};
+
+static struct s5h1409_config hauppauge_hvr1600_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE
+};
+
+/*
+ * CX18_CARD_HVR_1600_S5H1411
+ */
+static struct s5h1411_config hcw_s5h1411_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_44000,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 5380, .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 hauppauge_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+/*
+ * CX18_CARD_LEADTEK_DVR3100H
+ */
+/* Information/confirmation of proper config values provided by Terry Wu */
+static struct zl10353_config leadtek_dvr3100h_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
+};
+
+/*
+ * CX18_CARD_YUAN_MPC718
+ */
+/*
+ * Due to
+ *
+ * 1. an absence of information on how to prgram the MT352
+ * 2. the Linux mt352 module pushing MT352 initialzation off onto us here
+ *
+ * We have to use an init sequence that *you* must extract from the Windows
+ * driver (yuanrap.sys) and which we load as a firmware.
+ *
+ * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual
+ * with chip programming details, then I can remove this annoyance.
+ */
+static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
+ const struct firmware **fw)
+{
+ struct cx18 *cx = stream->cx;
+ const char *fn = FWFILE;
+ int ret;
+
+ ret = request_firmware(fw, fn, &cx->pci_dev->dev);
+ if (ret)
+ CX18_ERR("Unable to open firmware file %s\n", fn);
+ else {
+ size_t sz = (*fw)->size;
+ if (sz < 2 || sz > 64 || (sz % 2) != 0) {
+ CX18_ERR("Firmware %s has a bad size: %lu bytes\n",
+ fn, (unsigned long) sz);
+ ret = -EILSEQ;
+ release_firmware(*fw);
+ *fw = NULL;
+ }
+ }
+
+ if (ret) {
+ CX18_ERR("The MPC718 board variant with the MT352 DVB-T"
+ "demodualtor will not work without it\n");
+ CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware "
+ "mpc718' if you need the firmware\n");
+ }
+ return ret;
+}
+
+static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
+{
+ struct cx18_dvb *dvb = container_of(fe->dvb,
+ struct cx18_dvb, dvb_adapter);
+ struct cx18_stream *stream = dvb->stream;
+ const struct firmware *fw = NULL;
+ int ret;
+ int i;
+ u8 buf[3];
+
+ ret = yuan_mpc718_mt352_reqfw(stream, &fw);
+ if (ret)
+ return ret;
+
+ /* Loop through all the register-value pairs in the firmware file */
+ for (i = 0; i < fw->size; i += 2) {
+ buf[0] = fw->data[i];
+ /* Intercept a few registers we want to set ourselves */
+ switch (buf[0]) {
+ case TRL_NOMINAL_RATE_0:
+ /* Set our custom OFDM bandwidth in the case below */
+ break;
+ case TRL_NOMINAL_RATE_1:
+ /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */
+ /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */
+ /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */
+ buf[1] = 0x72;
+ buf[2] = 0x49;
+ mt352_write(fe, buf, 3);
+ break;
+ case INPUT_FREQ_0:
+ /* Set our custom IF in the case below */
+ break;
+ case INPUT_FREQ_1:
+ /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */
+ buf[1] = 0x31;
+ buf[2] = 0xc0;
+ mt352_write(fe, buf, 3);
+ break;
+ default:
+ /* Pass through the register-value pair from the fw */
+ buf[1] = fw->data[i+1];
+ mt352_write(fe, buf, 2);
+ break;
+ }
+ }
+
+ buf[0] = (u8) TUNER_GO;
+ buf[1] = 0x01; /* Go */
+ mt352_write(fe, buf, 2);
+ release_firmware(fw);
+ return 0;
+}
+
+static struct mt352_config yuan_mpc718_mt352_demod = {
+ .demod_address = 0x1e >> 1,
+ .adc_clock = 20480, /* 20.480 MHz */
+ .if2 = 4560, /* 4.560 MHz */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .demod_init = yuan_mpc718_mt352_init,
+};
+
+static struct zl10353_config yuan_mpc718_zl10353_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
+};
+
+static struct zl10353_config gotview_dvd3_zl10353_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
+};
+
+static int dvb_register(struct cx18_stream *stream);
+
+/* Kernel DVB framework calls this when the feed needs to start.
+ * The CX18 framework should enable the transport DMA handling
+ * and queue processing.
+ */
+static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
+ struct cx18 *cx;
+ int ret;
+ u32 v;
+
+ if (!stream)
+ return -EINVAL;
+
+ cx = stream->cx;
+ CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
+ mutex_lock(&cx->serialize_lock);
+ ret = cx18_init_on_first_open(cx);
+ mutex_unlock(&cx->serialize_lock);
+ if (ret) {
+ CX18_ERR("Failed to initialize firmware starting DVB feed\n");
+ return ret;
+ }
+ ret = -EINVAL;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ case CX18_CARD_HVR_1600_S5H1411:
+ v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ v |= 0x00400000; /* Serial Mode */
+ v |= 0x00002000; /* Data Length - Byte */
+ v |= 0x00010000; /* Error - Polarity */
+ v |= 0x00020000; /* Error - Passthru */
+ v |= 0x000c0000; /* Error - Ignore */
+ cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ break;
+
+ case CX18_CARD_LEADTEK_DVR3100H:
+ case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
+ default:
+ /* Assumption - Parallel transport - Signalling
+ * undefined or default.
+ */
+ break;
+ }
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&stream->dvb->feedlock);
+ if (stream->dvb->feeding++ == 0) {
+ CX18_DEBUG_INFO("Starting Transport DMA\n");
+ mutex_lock(&cx->serialize_lock);
+ set_bit(CX18_F_S_STREAMING, &stream->s_flags);
+ ret = cx18_start_v4l2_encode_stream(stream);
+ if (ret < 0) {
+ CX18_DEBUG_INFO("Failed to start Transport DMA\n");
+ stream->dvb->feeding--;
+ if (stream->dvb->feeding == 0)
+ clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
+ }
+ mutex_unlock(&cx->serialize_lock);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb->feedlock);
+
+ return ret;
+}
+
+/* Kernel DVB framework calls this when the feed needs to stop. */
+static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
+ struct cx18 *cx;
+ int ret = -EINVAL;
+
+ if (stream) {
+ cx = stream->cx;
+ CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
+ mutex_lock(&stream->dvb->feedlock);
+ if (--stream->dvb->feeding == 0) {
+ CX18_DEBUG_INFO("Stopping Transport DMA\n");
+ mutex_lock(&cx->serialize_lock);
+ ret = cx18_stop_v4l2_encode_stream(stream, 0);
+ mutex_unlock(&cx->serialize_lock);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb->feedlock);
+ }
+
+ return ret;
+}
+
+int cx18_dvb_register(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret;
+
+ if (!dvb)
+ return -EINVAL;
+
+ dvb->enabled = 0;
+ dvb->stream = stream;
+
+ ret = dvb_register_adapter(&dvb->dvb_adapter,
+ CX18_DRIVER_NAME,
+ THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_out;
+
+ dvb_adapter = &dvb->dvb_adapter;
+
+ dvbdemux = &dvb->demux;
+
+ dvbdemux->priv = (void *)stream;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = cx18_dvb_start_feed;
+ dvbdemux->stop_feed = cx18_dvb_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ dvb->hw_frontend.source = DMX_FRONTEND_0;
+ dvb->mem_frontend.source = DMX_MEMORY_FE;
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = dvb_register(stream);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
+
+ CX18_INFO("DVB Frontend registered\n");
+ CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
+ stream->dvb->dvb_adapter.num, stream->name,
+ stream->buffers, stream->buf_size/1024,
+ (stream->buf_size * 100 / 1024) % 100);
+
+ mutex_init(&dvb->feedlock);
+ dvb->enabled = 1;
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&dvb->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_out:
+ return ret;
+}
+
+void cx18_dvb_unregister(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+
+ CX18_INFO("unregister DVB\n");
+
+ if (dvb == NULL || !dvb->enabled)
+ return;
+
+ dvb_adapter = &dvb->dvb_adapter;
+ dvbdemux = &dvb->demux;
+ dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&dvb->dvbnet);
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_frontend(dvb->fe);
+ dvb_frontend_detach(dvb->fe);
+ dvb_unregister_adapter(dvb_adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. cx18_dvb_start_feed() will also need changes.
+ */
+static int dvb_register(struct cx18_stream *stream)
+{
+ struct cx18_dvb *dvb = stream->dvb;
+ struct cx18 *cx = stream->cx;
+ int ret = 0;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ dvb->fe = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1600_config,
+ &cx->i2c_adap[0]);
+ if (dvb->fe != NULL) {
+ dvb_attach(mxl5005s_attach, dvb->fe,
+ &cx->i2c_adap[0],
+ &hauppauge_hvr1600_tuner);
+ ret = 0;
+ }
+ break;
+ case CX18_CARD_HVR_1600_S5H1411:
+ dvb->fe = dvb_attach(s5h1411_attach,
+ &hcw_s5h1411_config,
+ &cx->i2c_adap[0]);
+ if (dvb->fe != NULL)
+ dvb_attach(tda18271_attach, dvb->fe,
+ 0x60, &cx->i2c_adap[0],
+ &hauppauge_tda18271_config);
+ break;
+ case CX18_CARD_LEADTEK_DVR3100H:
+ dvb->fe = dvb_attach(zl10353_attach,
+ &leadtek_dvr3100h_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
+ case CX18_CARD_YUAN_MPC718:
+ /*
+ * TODO
+ * Apparently, these cards also could instead have a
+ * DiBcom demod supported by one of the db7000 drivers
+ */
+ dvb->fe = dvb_attach(mt352_attach,
+ &yuan_mpc718_mt352_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe == NULL)
+ dvb->fe = dvb_attach(zl10353_attach,
+ &yuan_mpc718_zl10353_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
+ dvb->fe = dvb_attach(zl10353_attach,
+ &gotview_dvd3_zl10353_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
+ default:
+ /* No Digital Tv Support */
+ break;
+ }
+
+ if (dvb->fe == NULL) {
+ CX18_ERR("frontend initialization failed\n");
+ return -1;
+ }
+
+ dvb->fe->callback = cx18_reset_tuner_gpio;
+
+ ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
+ if (ret < 0) {
+ if (dvb->fe->ops.release)
+ dvb->fe->ops.release(dvb->fe);
+ return ret;
+ }
+
+ /*
+ * The firmware seems to enable the TS DMUX clock
+ * under various circumstances. However, since we know we
+ * might use it, let's just turn it on ourselves here.
+ */
+ cx18_write_reg_expect(cx,
+ (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
+ CX18_CLOCK_ENABLE2,
+ CX18_DMUX_CLK_MASK,
+ (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
+
+ return ret;
+}
+
+MODULE_FIRMWARE(FWFILE);
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/pci/cx18/cx18-dvb.h
index bf8d8f6f5455..bf8d8f6f5455 100644
--- a/drivers/media/video/cx18/cx18-dvb.h
+++ b/drivers/media/pci/cx18/cx18-dvb.h
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c
index 4bfd865a4106..4bfd865a4106 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/pci/cx18/cx18-fileops.c
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/pci/cx18/cx18-fileops.h
index b9e5110ad043..b9e5110ad043 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/pci/cx18/cx18-fileops.h
diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c
new file mode 100644
index 000000000000..a1c1cec05f98
--- /dev/null
+++ b/drivers/media/pci/cx18/cx18-firmware.c
@@ -0,0 +1,459 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
+ *
+ * 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
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-firmware.h"
+#include "cx18-cards.h"
+#include <linux/firmware.h>
+
+#define CX18_PROC_SOFT_RESET 0xc70010
+#define CX18_DDR_SOFT_RESET 0xc70014
+#define CX18_CLOCK_SELECT1 0xc71000
+#define CX18_CLOCK_SELECT2 0xc71004
+#define CX18_HALF_CLOCK_SELECT1 0xc71008
+#define CX18_HALF_CLOCK_SELECT2 0xc7100C
+#define CX18_CLOCK_POLARITY1 0xc71010
+#define CX18_CLOCK_POLARITY2 0xc71014
+#define CX18_ADD_DELAY_ENABLE1 0xc71018
+#define CX18_ADD_DELAY_ENABLE2 0xc7101C
+#define CX18_CLOCK_ENABLE1 0xc71020
+#define CX18_CLOCK_ENABLE2 0xc71024
+
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_FAST_CLOCK_PLL_INT 0xc78000
+#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
+#define CX18_FAST_CLOCK_PLL_POST 0xc78008
+#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
+#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
+
+#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
+#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
+#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
+#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
+#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
+#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
+#define CX18_PLL_POWER_DOWN 0xc78088
+#define CX18_SW1_INT_STATUS 0xc73104
+#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
+#define CX18_SW2_INT_SET 0xc73140
+#define CX18_SW2_INT_STATUS 0xc73144
+#define CX18_ADEC_CONTROL 0xc78120
+
+#define CX18_DDR_REQUEST_ENABLE 0xc80000
+#define CX18_DDR_CHIP_CONFIG 0xc80004
+#define CX18_DDR_REFRESH 0xc80008
+#define CX18_DDR_TIMING1 0xc8000C
+#define CX18_DDR_TIMING2 0xc80010
+#define CX18_DDR_POWER_REG 0xc8001C
+
+#define CX18_DDR_TUNE_LANE 0xc80048
+#define CX18_DDR_INITIAL_EMRS 0xc80054
+#define CX18_DDR_MB_PER_ROW_7 0xc8009C
+#define CX18_DDR_BASE_63_ADDR 0xc804FC
+
+#define CX18_WMB_CLIENT02 0xc90108
+#define CX18_WMB_CLIENT05 0xc90114
+#define CX18_WMB_CLIENT06 0xc90118
+#define CX18_WMB_CLIENT07 0xc9011C
+#define CX18_WMB_CLIENT08 0xc90120
+#define CX18_WMB_CLIENT09 0xc90124
+#define CX18_WMB_CLIENT10 0xc90128
+#define CX18_WMB_CLIENT11 0xc9012C
+#define CX18_WMB_CLIENT12 0xc90130
+#define CX18_WMB_CLIENT13 0xc90134
+#define CX18_WMB_CLIENT14 0xc90138
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
+#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
+
+struct cx18_apu_rom_seghdr {
+ u32 sync1;
+ u32 sync2;
+ u32 addr;
+ u32 size;
+};
+
+static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
+{
+ const struct firmware *fw = NULL;
+ int i, j;
+ unsigned size;
+ u32 __iomem *dst = (u32 __iomem *)mem;
+ const u32 *src;
+
+ if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+ CX18_ERR("Unable to open firmware %s\n", fn);
+ CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+
+ for (i = 0; i < fw->size; i += 4096) {
+ cx18_setup_page(cx, i);
+ for (j = i; j < fw->size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ cx18_raw_writel(cx, *src, dst);
+ if (cx18_raw_readl(cx, dst) != *src) {
+ CX18_ERR("Mismatch at offset %x\n", i);
+ release_firmware(fw);
+ cx18_setup_page(cx, 0);
+ return -EIO;
+ }
+ dst++;
+ src++;
+ }
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ size = fw->size;
+ release_firmware(fw);
+ cx18_setup_page(cx, SCB_OFFSET);
+ return size;
+}
+
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
+ u32 *entry_addr)
+{
+ const struct firmware *fw = NULL;
+ int i, j;
+ unsigned size;
+ const u32 *src;
+ struct cx18_apu_rom_seghdr seghdr;
+ const u8 *vers;
+ u32 offset = 0;
+ u32 apu_version = 0;
+ int sz;
+
+ if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+ CX18_ERR("unable to open firmware %s\n", fn);
+ CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ cx18_setup_page(cx, 0);
+ return -ENOMEM;
+ }
+
+ *entry_addr = 0;
+ src = (const u32 *)fw->data;
+ vers = fw->data + sizeof(seghdr);
+ sz = fw->size;
+
+ apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
+ while (offset + sizeof(seghdr) < fw->size) {
+ const u32 *shptr = src + offset / 4;
+
+ seghdr.sync1 = le32_to_cpu(shptr[0]);
+ seghdr.sync2 = le32_to_cpu(shptr[1]);
+ seghdr.addr = le32_to_cpu(shptr[2]);
+ seghdr.size = le32_to_cpu(shptr[3]);
+
+ offset += sizeof(seghdr);
+ if (seghdr.sync1 != APU_ROM_SYNC1 ||
+ seghdr.sync2 != APU_ROM_SYNC2) {
+ offset += seghdr.size;
+ continue;
+ }
+ CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
+ seghdr.addr + seghdr.size - 1);
+ if (*entry_addr == 0)
+ *entry_addr = seghdr.addr;
+ if (offset + seghdr.size > sz)
+ break;
+ for (i = 0; i < seghdr.size; i += 4096) {
+ cx18_setup_page(cx, seghdr.addr + i);
+ for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ cx18_raw_writel(cx, src[(offset + j) / 4],
+ dst + seghdr.addr + j);
+ if (cx18_raw_readl(cx, dst + seghdr.addr + j)
+ != src[(offset + j) / 4]) {
+ CX18_ERR("Mismatch at offset %x\n",
+ offset + j);
+ release_firmware(fw);
+ cx18_setup_page(cx, 0);
+ return -EIO;
+ }
+ }
+ }
+ offset += seghdr.size;
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+ fn, apu_version, fw->size);
+ size = fw->size;
+ release_firmware(fw);
+ cx18_setup_page(cx, 0);
+ return size;
+}
+
+void cx18_halt_firmware(struct cx18 *cx)
+{
+ CX18_DEBUG_INFO("Preparing for firmware halt.\n");
+ cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+ 0x0000000F, 0x000F000F);
+ cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
+ 0x00000002, 0x00020002);
+}
+
+void cx18_init_power(struct cx18 *cx, int lowpwr)
+{
+ /* power-down Spare and AOM PLLs */
+ /* power-up fast, slow and mpeg PLLs */
+ cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
+
+ /* ADEC out of sleep */
+ cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
+ 0x00000000, 0x00020002);
+
+ /*
+ * The PLL parameters are based on the external crystal frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 =
+ * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * The accidents of history and rationale that explain from where this
+ * combination of magic numbers originate can be found in:
+ *
+ * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+ * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+ *
+ * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+ * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+ *
+ * As Mike Bradley has rightly pointed out, it's not the exact crystal
+ * frequency that matters, only that all parts of the driver and
+ * firmware are using the same value (close to the ideal value).
+ *
+ * Since I have a strong suspicion that, if the firmware ever assumes a
+ * crystal value at all, it will assume 28.636360 MHz, the crystal
+ * freq used in calculations in this driver will be:
+ *
+ * xtal_freq = 28.636360 MHz
+ *
+ * an error of less than 0.13 ppm which is way, way better than any off
+ * the shelf crystal will have for accuracy anyway.
+ *
+ * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+ *
+ * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+ * investigation, experimentation, testing, and suggested solutions of
+ * of audio/video sync problems with SVideo and CVBS captures.
+ */
+
+ /* the fast clock is at 200/245 MHz */
+ /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
+ /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
+ cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+ cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
+ CX18_FAST_CLOCK_PLL_FRAC);
+
+ cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
+ cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
+ cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+
+ /* set slow clock to 125/120 MHz */
+ /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
+ /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
+ cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
+ cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
+ CX18_SLOW_CLOCK_PLL_FRAC);
+ cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
+
+ /* mpeg clock pll 54MHz */
+ /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
+ cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
+ cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
+ cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
+
+ /* Defaults */
+ /* APU = SC or SC/2 = 125/62.5 */
+ /* EPU = SC = 125 */
+ /* DDR = FC = 180 */
+ /* ENC = SC = 125 */
+ /* AI1 = SC = 125 */
+ /* VIM2 = disabled */
+ /* PCI = FC/2 = 90 */
+ /* AI2 = disabled */
+ /* DEMUX = disabled */
+ /* AO = SC/2 = 62.5 */
+ /* SER = 54MHz */
+ /* VFC = disabled */
+ /* USB = disabled */
+
+ if (lowpwr) {
+ cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
+ 0x00000020, 0xFFFFFFFF);
+ cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
+ 0x00000004, 0xFFFFFFFF);
+ } else {
+ /* This doesn't explicitly set every clock select */
+ cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
+ 0x00000004, 0x00060006);
+ cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
+ 0x00000006, 0x00060006);
+ }
+
+ cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
+ 0x00000002, 0xFFFFFFFF);
+ cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
+ 0x00000104, 0xFFFFFFFF);
+ cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
+ 0x00009026, 0xFFFFFFFF);
+ cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
+ 0x00003105, 0xFFFFFFFF);
+}
+
+void cx18_init_memory(struct cx18 *cx)
+{
+ cx18_msleep_timeout(10, 0);
+ cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
+ 0x00000000, 0x00010001);
+ cx18_msleep_timeout(10, 0);
+
+ cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+
+ cx18_msleep_timeout(10, 0);
+
+ cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
+ cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
+ cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
+
+ cx18_msleep_timeout(10, 0);
+
+ /* Initialize DQS pad time */
+ cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+ cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+
+ cx18_msleep_timeout(10, 0);
+
+ cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
+ 0x00000000, 0x00020002);
+ cx18_msleep_timeout(10, 0);
+
+ /* use power-down mode when idle */
+ cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
+
+ cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
+ 0x00000001, 0x00010001);
+
+ cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
+ cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
+
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */
+ cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */
+}
+
+#define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw"
+#define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw"
+
+int cx18_firmware_init(struct cx18 *cx)
+{
+ u32 fw_entry_addr;
+ int sz, retries;
+ u32 api_args[MAX_MB_ARGUMENTS];
+
+ /* Allow chip to control CLKRUN */
+ cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
+
+ /* Stop the firmware */
+ cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+ 0x0000000F, 0x000F000F);
+
+ cx18_msleep_timeout(1, 0);
+
+ /* If the CPU is still running */
+ if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
+ CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
+ return -EIO;
+ }
+
+ cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx);
+ if (sz <= 0)
+ return sz;
+
+ /* The SCB & IPC area *must* be correct before starting the firmwares */
+ cx18_init_scb(cx);
+
+ fw_entry_addr = 0;
+ sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx,
+ &fw_entry_addr);
+ if (sz <= 0)
+ return sz;
+
+ /* Start the CPU. The CPU will take care of the APU for us. */
+ cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
+ 0x00000000, 0x00080008);
+
+ /* Wait up to 500 ms for the APU to come out of reset */
+ for (retries = 0;
+ retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
+ retries++)
+ cx18_msleep_timeout(10, 0);
+
+ cx18_msleep_timeout(200, 0);
+
+ if (retries == 50 &&
+ (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
+ CX18_ERR("Could not start the CPU\n");
+ return -EIO;
+ }
+
+ /*
+ * The CPU had once before set up to receive an interrupt for it's
+ * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an
+ * interrupt when it sends us an ack, but by the time we process it,
+ * that flag in the SW2 status register has been cleared by the CPU
+ * firmware. We'll prevent that not so useful condition from happening
+ * by clearing the CPU's interrupt enables for Ack IRQ's we want to
+ * process.
+ */
+ cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ /* Try a benign command to see if the CPU is alive and well */
+ sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
+ if (sz < 0)
+ return sz;
+
+ /* initialize GPIO */
+ cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
+ return 0;
+}
+
+MODULE_FIRMWARE(CX18_CPU_FIRMWARE);
+MODULE_FIRMWARE(CX18_APU_FIRMWARE);
diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/pci/cx18/cx18-firmware.h
index 38d4c05e8499..38d4c05e8499 100644
--- a/drivers/media/video/cx18/cx18-firmware.h
+++ b/drivers/media/pci/cx18/cx18-firmware.h
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/pci/cx18/cx18-gpio.c
index 5374aeb0cd22..5374aeb0cd22 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/pci/cx18/cx18-gpio.c
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/pci/cx18/cx18-gpio.h
index 4aea2ef88e8d..4aea2ef88e8d 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/pci/cx18/cx18-gpio.h
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c
index 51609d5c88ce..51609d5c88ce 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/pci/cx18/cx18-i2c.c
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/pci/cx18/cx18-i2c.h
index 1180fdc8d983..1180fdc8d983 100644
--- a/drivers/media/video/cx18/cx18-i2c.h
+++ b/drivers/media/pci/cx18/cx18-i2c.h
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/pci/cx18/cx18-io.c
index 49b9dbd06248..49b9dbd06248 100644
--- a/drivers/media/video/cx18/cx18-io.c
+++ b/drivers/media/pci/cx18/cx18-io.c
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/pci/cx18/cx18-io.h
index 18974d886cf7..18974d886cf7 100644
--- a/drivers/media/video/cx18/cx18-io.h
+++ b/drivers/media/pci/cx18/cx18-io.h
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index e9912db3b496..e9912db3b496 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h
index 2f9dd591ee0f..2f9dd591ee0f 100644
--- a/drivers/media/video/cx18/cx18-ioctl.h
+++ b/drivers/media/pci/cx18/cx18-ioctl.h
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/pci/cx18/cx18-irq.c
index 80edfe93a3d8..80edfe93a3d8 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/pci/cx18/cx18-irq.c
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/pci/cx18/cx18-irq.h
index 30e7eaf8cb55..30e7eaf8cb55 100644
--- a/drivers/media/video/cx18/cx18-irq.h
+++ b/drivers/media/pci/cx18/cx18-irq.h
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c
index eabf00c6351b..eabf00c6351b 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/pci/cx18/cx18-mailbox.c
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/pci/cx18/cx18-mailbox.h
index b63fdfaac49e..b63fdfaac49e 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/pci/cx18/cx18-mailbox.h
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c
index 8884537bd62f..8884537bd62f 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/pci/cx18/cx18-queue.c
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/pci/cx18/cx18-queue.h
index 4201ddc16091..4201ddc16091 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/pci/cx18/cx18-queue.h
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/pci/cx18/cx18-scb.c
index 85cc59637e54..85cc59637e54 100644
--- a/drivers/media/video/cx18/cx18-scb.c
+++ b/drivers/media/pci/cx18/cx18-scb.c
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/pci/cx18/cx18-scb.h
index 08877652e321..08877652e321 100644
--- a/drivers/media/video/cx18/cx18-scb.h
+++ b/drivers/media/pci/cx18/cx18-scb.h
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 9d598ab88615..9d598ab88615 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h
index 713b0e61536d..713b0e61536d 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/pci/cx18/cx18-streams.h
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c
index 6d3121ff45a2..6d3121ff45a2 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/pci/cx18/cx18-vbi.c
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/pci/cx18/cx18-vbi.h
index b365cf4b4668..b365cf4b4668 100644
--- a/drivers/media/video/cx18/cx18-vbi.h
+++ b/drivers/media/pci/cx18/cx18-vbi.h
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/pci/cx18/cx18-version.h
index fed48b6bb67b..fed48b6bb67b 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/pci/cx18/cx18-version.h
diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/pci/cx18/cx18-video.c
index 6dc84aac8f44..6dc84aac8f44 100644
--- a/drivers/media/video/cx18/cx18-video.c
+++ b/drivers/media/pci/cx18/cx18-video.c
diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/pci/cx18/cx18-video.h
index 529006a06e5c..529006a06e5c 100644
--- a/drivers/media/video/cx18/cx18-video.h
+++ b/drivers/media/pci/cx18/cx18-video.h
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h
index 767a8d23e3f2..767a8d23e3f2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/pci/cx18/cx23418.h
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
new file mode 100644
index 000000000000..9c6afe922586
--- /dev/null
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -0,0 +1,46 @@
+config VIDEO_CX23885
+ tristate "Conexant cx23885 (2388x successor) support"
+ depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
+ select SND_PCM
+ select I2C_ALGOBIT
+ select VIDEO_BTCX
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ depends on RC_CORE
+ select VIDEOBUF_DVB
+ select VIDEOBUF_DMA_SG
+ select VIDEO_CX25840
+ select VIDEO_CX2341X
+ select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for Conexant 23885 based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx23885
+
+config MEDIA_ALTERA_CI
+ tristate "Altera FPGA based CI module"
+ depends on VIDEO_CX23885 && DVB_CORE
+ select ALTERA_STAPL
+ ---help---
+ An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card.
+
+ To compile this driver as a module, choose M here: the
+ module will be called altera-ci
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
new file mode 100644
index 000000000000..a2cbdcf15a8c
--- /dev/null
+++ b/drivers/media/pci/cx23885/Makefile
@@ -0,0 +1,15 @@
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
+ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
+ cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \
+ cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \
+ cx23885-f300.o cx23885-alsa.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 1fa8927f0d36..1fa8927f0d36 100644
--- a/drivers/media/video/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 70e4fd69ad9e..70e4fd69ad9e 100644
--- a/drivers/media/video/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
index c9f15d6dec40..c9f15d6dec40 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/pci/cx23885/cimax2.c
diff --git a/drivers/media/video/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
index 518744a4c8a5..518744a4c8a5 100644
--- a/drivers/media/video/cx23885/cimax2.h
+++ b/drivers/media/pci/cx23885/cimax2.h
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
new file mode 100644
index 000000000000..5d5052d0253f
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -0,0 +1,1790 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx23885 host port.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.us>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2008 Steven Toth <stoth@linuxtv.org>
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+
+#include "cx23885.h"
+#include "cx23885-ioctl.h"
+
+#define CX23885_FIRM_IMAGE_SIZE 376836
+#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 32;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+ "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+
+#define dprintk(level, fmt, arg...)\
+ do { if (v4l_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, \
+ (dev) ? dev->name : "cx23885[?]", ## arg); \
+ } while (0)
+
+static struct cx23885_tvnorm cx23885_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }, {
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ }, {
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ }, {
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }, {
+ .name = "PAL-N",
+ .id = V4L2_STD_PAL_N,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ }, {
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ }, {
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx23885_capture_type {
+ CX23885_MPEG_CAPTURE,
+ CX23885_RAW_CAPTURE,
+ CX23885_RAW_PASSTHRU_CAPTURE
+};
+enum cx23885_capture_bits {
+ CX23885_RAW_BITS_NONE = 0x00,
+ CX23885_RAW_BITS_YUV_CAPTURE = 0x01,
+ CX23885_RAW_BITS_PCM_CAPTURE = 0x02,
+ CX23885_RAW_BITS_VBI_CAPTURE = 0x04,
+ CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+enum cx23885_capture_end {
+ CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
+ CX23885_END_NOW, /* stop immediately, no irq */
+};
+enum cx23885_framerate {
+ CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+enum cx23885_stream_port {
+ CX23885_OUTPUT_PORT_MEMORY,
+ CX23885_OUTPUT_PORT_STREAMING,
+ CX23885_OUTPUT_PORT_SERIAL
+};
+enum cx23885_data_xfer_status {
+ CX23885_MORE_BUFFERS_FOLLOW,
+ CX23885_LAST_BUFFER,
+};
+enum cx23885_picture_mask {
+ CX23885_PICTURE_MASK_NONE,
+ CX23885_PICTURE_MASK_I_FRAMES,
+ CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
+ CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx23885_vbi_mode_bits {
+ CX23885_VBI_BITS_SLICED,
+ CX23885_VBI_BITS_RAW,
+};
+enum cx23885_vbi_insertion_bits {
+ CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx23885_dma_unit {
+ CX23885_DMA_BYTES,
+ CX23885_DMA_FRAMES,
+};
+enum cx23885_dma_transfer_status_bits {
+ CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
+ CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
+ CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx23885_pause {
+ CX23885_PAUSE_ENCODING,
+ CX23885_RESUME_ENCODING,
+};
+enum cx23885_copyright {
+ CX23885_COPYRIGHT_OFF,
+ CX23885_COPYRIGHT_ON,
+};
+enum cx23885_notification_type {
+ CX23885_NOTIFICATION_REFRESH,
+};
+enum cx23885_notification_status {
+ CX23885_NOTIFICATION_OFF,
+ CX23885_NOTIFICATION_ON,
+};
+enum cx23885_notification_mailbox {
+ CX23885_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx23885_field1_lines {
+ CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx23885_field2_lines {
+ CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx23885_custom_data_type {
+ CX23885_CUSTOM_EXTENSION_USR_DATA,
+ CX23885_CUSTOM_PRIVATE_PACKET,
+};
+enum cx23885_mute {
+ CX23885_UNMUTE,
+ CX23885_MUTE,
+};
+enum cx23885_mute_video_mask {
+ CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx23885_mute_video_shift {
+ CX23885_MUTE_VIDEO_V_SHIFT = 8,
+ CX23885_MUTE_VIDEO_U_SHIFT = 16,
+ CX23885_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
+ bits 31-16
++-----------+
+| Reserved |
++-----------+
+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+#define MC417_MIWR 0x8000
+#define MC417_MIRD 0x4000
+#define MC417_MICS 0x2000
+#define MC417_MIRDY 0x1000
+#define MC417_MIADDR 0x0F00
+#define MC417_MIDATA 0x00FF
+
+/* MIADDR* nibble definitions */
+#define MCI_MEMORY_DATA_BYTE0 0x000
+#define MCI_MEMORY_DATA_BYTE1 0x100
+#define MCI_MEMORY_DATA_BYTE2 0x200
+#define MCI_MEMORY_DATA_BYTE3 0x300
+#define MCI_MEMORY_ADDRESS_BYTE2 0x400
+#define MCI_MEMORY_ADDRESS_BYTE1 0x500
+#define MCI_MEMORY_ADDRESS_BYTE0 0x600
+#define MCI_REGISTER_DATA_BYTE0 0x800
+#define MCI_REGISTER_DATA_BYTE1 0x900
+#define MCI_REGISTER_DATA_BYTE2 0xA00
+#define MCI_REGISTER_DATA_BYTE3 0xB00
+#define MCI_REGISTER_ADDRESS_BYTE0 0xC00
+#define MCI_REGISTER_ADDRESS_BYTE1 0xD00
+#define MCI_REGISTER_MODE 0xE00
+
+/* Read and write modes */
+#define MCI_MODE_REGISTER_READ 0
+#define MCI_MODE_REGISTER_WRITE 1
+#define MCI_MODE_MEMORY_READ 0
+#define MCI_MODE_MEMORY_WRITE 0x40
+
+/*** Bit definitions for MC417_CTL register ****
+ bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
++--------+-------------+--------+--------------+------------+
+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
++--------+-------------+--------+--------------+------------+
+***/
+#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN 0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW 0x1
+#define MC417_SPD_CTL_MEDIUM 0x0
+#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3 0x3
+#define MC417_GPIO_SEL_GPIO2 0x2
+#define MC417_GPIO_SEL_GPIO1 0x1
+#define MC417_GPIO_SEL_GPIO0 0x0
+
+void cx23885_mc417_init(struct cx23885_dev *dev)
+{
+ u32 regval;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Configure MC417_CTL register to defaults. */
+ regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) |
+ MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) |
+ MC417_UART_GPIO_EN;
+ cx_write(MC417_CTL, regval);
+
+ /* Configure MC417_OEN to defaults. */
+ regval = MC417_MIRDY;
+ cx_write(MC417_OEN, regval);
+
+ /* Configure MC417_RWD to defaults. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
+ cx_write(MC417_RWD, regval);
+}
+
+static int mc417_wait_ready(struct cx23885_dev *dev)
+{
+ u32 mi_ready;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+ for (;;) {
+ mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
+ if (mi_ready != 0)
+ return 0;
+ if (time_after(jiffies, timeout))
+ return -1;
+ udelay(1);
+ }
+}
+
+int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a write. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_WRITE;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ ((address & 0x00FF));
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a register read. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_READ;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus.
+ * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
+ * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
+ * input only...)
+ */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = tempval & 0x000000FF;
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 24);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus. */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = ((tempval & 0x000000FF) << 24);
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= (tempval & 0x000000FF);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Set the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val |= (mask & 0x000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Clear the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val &= ~(mask & 0x0000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+ u32 val;
+
+ /* Enable GPIO direction bits */
+ mc417_register_read(dev, 0x9020, &val);
+ if (asoutput)
+ val |= (mask & 0x0000ffff);
+ else
+ val &= ~(mask & 0x0000ffff);
+
+ mc417_register_write(dev, 0x9020, val);
+}
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+ switch (cmd) {
+ case CX2341X_ENC_PING_FW:
+ return "PING_FW";
+ case CX2341X_ENC_START_CAPTURE:
+ return "START_CAPTURE";
+ case CX2341X_ENC_STOP_CAPTURE:
+ return "STOP_CAPTURE";
+ case CX2341X_ENC_SET_AUDIO_ID:
+ return "SET_AUDIO_ID";
+ case CX2341X_ENC_SET_VIDEO_ID:
+ return "SET_VIDEO_ID";
+ case CX2341X_ENC_SET_PCR_ID:
+ return "SET_PCR_ID";
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return "SET_FRAME_RATE";
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return "SET_FRAME_SIZE";
+ case CX2341X_ENC_SET_BIT_RATE:
+ return "SET_BIT_RATE";
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return "SET_GOP_PROPERTIES";
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return "SET_ASPECT_RATIO";
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ return "SET_DNR_FILTER_MODE";
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return "SET_CORING_LEVELS";
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return "SET_SPATIAL_FILTER_TYPE";
+ case CX2341X_ENC_SET_VBI_LINE:
+ return "SET_VBI_LINE";
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return "SET_STREAM_TYPE";
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return "SET_OUTPUT_PORT";
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return "SET_AUDIO_PROPERTIES";
+ case CX2341X_ENC_HALT_FW:
+ return "HALT_FW";
+ case CX2341X_ENC_GET_VERSION:
+ return "GET_VERSION";
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return "SET_GOP_CLOSURE";
+ case CX2341X_ENC_GET_SEQ_END:
+ return "GET_SEQ_END";
+ case CX2341X_ENC_SET_PGM_INDEX_INFO:
+ return "SET_PGM_INDEX_INFO";
+ case CX2341X_ENC_SET_VBI_CONFIG:
+ return "SET_VBI_CONFIG";
+ case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+ return "SET_DMA_BLOCK_SIZE";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+ return "GET_PREV_DMA_INFO_MB_10";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+ return "GET_PREV_DMA_INFO_MB_9";
+ case CX2341X_ENC_SCHED_DMA_TO_HOST:
+ return "SCHED_DMA_TO_HOST";
+ case CX2341X_ENC_INITIALIZE_INPUT:
+ return "INITIALIZE_INPUT";
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return "SET_FRAME_DROP_RATE";
+ case CX2341X_ENC_PAUSE_ENCODER:
+ return "PAUSE_ENCODER";
+ case CX2341X_ENC_REFRESH_INPUT:
+ return "REFRESH_INPUT";
+ case CX2341X_ENC_SET_COPYRIGHT:
+ return "SET_COPYRIGHT";
+ case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+ return "SET_EVENT_NOTIFICATION";
+ case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+ return "SET_NUM_VSYNC_LINES";
+ case CX2341X_ENC_SET_PLACEHOLDER:
+ return "SET_PLACEHOLDER";
+ case CX2341X_ENC_MUTE_VIDEO:
+ return "MUTE_VIDEO";
+ case CX2341X_ENC_MUTE_AUDIO:
+ return "MUTE_AUDIO";
+ case CX2341X_ENC_MISC:
+ return "MISC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int cx23885_mbox_func(void *priv,
+ u32 command,
+ int in,
+ int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx23885_dev *dev = priv;
+ unsigned long timeout;
+ u32 value, flag, retval = 0;
+ int i;
+
+ dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+ cmd_to_str(command));
+
+ /* this may not be 100% safe if we can't read any memory location
+ without side effects */
+ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ printk(KERN_ERR
+ "Firmware and/or mailbox pointer not initialized "
+ "or corrupted, signature = 0x%x, cmd = %s\n", value,
+ cmd_to_str(command));
+ return -1;
+ }
+
+ /* This read looks at 32 bits, but flag is only 8 bits.
+ * Seems we also bail if CMD or TIMEOUT bytes are set???
+ */
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (flag) {
+ printk(KERN_ERR "ERROR: Mailbox appears to be in use "
+ "(%x), cmd = %s\n", flag, cmd_to_str(command));
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* write command + args + fill remaining with zeros */
+ /* command code */
+ mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+ mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+ IVTV_API_STD_TIMEOUT); /* timeout */
+ for (i = 0; i < in; i++) {
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+ dprintk(3, "API Input %d = %d\n", i, data[i]);
+ }
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+ flag |= 3; /* tell 'em we're done writing */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (0 != (flag & 4))
+ break;
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
+ udelay(10);
+ }
+
+ /* read output values */
+ for (i = 0; i < out; i++) {
+ mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+ dprintk(3, "API Output %d = %d\n", i, data[i]);
+ }
+
+ mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+ dprintk(3, "API result = %d\n", retval);
+
+ flag = 0;
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx23885_api_cmd(struct cx23885_dev *dev,
+ u32 command,
+ u32 inputcnt,
+ u32 outputcnt,
+ ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+ va_start(vargs, outputcnt);
+ for (i = 0; i < inputcnt; i++)
+ data[i] = va_arg(vargs, int);
+
+ err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+
+ return err;
+}
+
+static int cx23885_find_mailbox(struct cx23885_dev *dev)
+{
+ u32 signature[4] = {
+ 0x12345678, 0x34567812, 0x56781234, 0x78123456
+ };
+ int signaturecnt = 0;
+ u32 value;
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
+ mc417_memory_read(dev, i, &value);
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+ return i+1;
+ }
+ }
+ printk(KERN_ERR "Mailbox signature values not found!\n");
+ return -1;
+}
+
+static int cx23885_load_firmware(struct cx23885_dev *dev)
+{
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
+ int i, retval = 0;
+ u32 value = 0;
+ u32 gpio_output = 0;
+ u32 gpio_value;
+ u32 checksum = 0;
+ u32 *dataptr;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Save GPIO settings before reset of APU */
+ retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+ retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
+
+ retval = mc417_register_write(dev,
+ IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_APU, 0);
+
+ if (retval != 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return -1;
+ }
+
+ retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
+ &dev->pci->dev);
+
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+ CX23885_FIRM_IMAGE_NAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+ }
+
+ if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
+ printk(KERN_ERR "ERROR: Firmware size mismatch "
+ "(have %zd, expected %d)\n",
+ firmware->size, CX23885_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
+ return -1;
+ }
+
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ printk(KERN_ERR
+ "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
+ return -1;
+ }
+
+ /* transfer to the chip */
+ dprintk(2, "Loading firmware ...\n");
+ dataptr = (u32 *)firmware->data;
+ for (i = 0; i < (firmware->size >> 2); i++) {
+ value = *dataptr;
+ checksum += ~value;
+ if (mc417_memory_write(dev, i, value) != 0) {
+ printk(KERN_ERR "ERROR: Loading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ dataptr++;
+ }
+
+ /* read back to verify with the checksum */
+ dprintk(1, "Verifying firmware ...\n");
+ for (i--; i >= 0; i--) {
+ if (mc417_memory_read(dev, i, &value) != 0) {
+ printk(KERN_ERR "ERROR: Reading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ checksum -= ~value;
+ }
+ if (checksum) {
+ printk(KERN_ERR
+ "ERROR: Firmware load failed (checksum mismatch).\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ release_firmware(firmware);
+ dprintk(1, "Firmware upload successful.\n");
+
+ retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+ IVTV_CMD_HW_BLOCKS_RST);
+
+ /* F/W power up disturbs the GPIOs, restore state */
+ retval |= mc417_register_write(dev, 0x9020, gpio_output);
+ 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__);
+ return 0;
+}
+
+void cx23885_417_check_encoder(struct cx23885_dev *dev)
+{
+ u32 status, seq;
+
+ status = seq = 0;
+ cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+ dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+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);
+
+ dev->mpeg_params.width = dev->ts1.width;
+ dev->mpeg_params.height = dev->ts1.height;
+ dev->mpeg_params.is_50hz =
+ (dev->encodernorm.id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
+{
+ int version;
+ int retval;
+ u32 i, data[7];
+
+ dprintk(1, "%s()\n", __func__);
+
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(2, "%s() PING OK\n", __func__);
+ retval = cx23885_load_firmware(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ return retval;
+ }
+ retval = cx23885_find_mailbox(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() mailbox < 0, error\n",
+ __func__);
+ return -1;
+ }
+ dev->cx23417_mailbox = retval;
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "ERROR: cx23417 firmware ping failed!\n");
+ return -1;
+ }
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+ &version);
+ if (retval < 0) {
+ printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+ "version failed!\n");
+ return -1;
+ }
+ dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+ msleep(200);
+ }
+
+ cx23885_codec_settings(dev);
+ msleep(60);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0);
+
+ /* Setup to capture VBI */
+ data[0] = 0x0001BD00;
+ data[1] = 1; /* frames per interrupt */
+ data[2] = 4; /* total bufs */
+ data[3] = 0x91559155; /* start codes */
+ data[4] = 0x206080C0; /* stop codes */
+ data[5] = 6; /* lines */
+ data[6] = 64; /* BPL */
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6]);
+
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ valid = ((i >= 19) && (i <= 21));
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+ valid, 0 , 0, 0);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+ i | 0x80000000, valid, 0, 0, 0);
+ }
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
+ msleep(60);
+
+ /* initialize the video input */
+ cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+ msleep(60);
+
+ /* Enable VIP style pixel invalidation so we work with scaled mode */
+ mc417_memory_write(dev, 2120, 0x00000080);
+
+ /* start capturing to the host interface */
+ if (startencoder) {
+ cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+ msleep(10);
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_fh *fh = q->priv_data;
+
+ fh->dev->ts1.ts_packet_size = mpeglinesize;
+ fh->dev->ts1.ts_packet_count = mpeglines;
+
+ *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+ *count = mpegbufs;
+
+ return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ return cx23885_buf_prepare(q, &fh->dev->ts1,
+ (struct cx23885_buffer *)vb,
+ field);
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static struct videobuf_queue_ops cx23885_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx23885_queryctrl(struct cx23885_dev *dev,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+ return 0;
+}
+
+static int cx23885_querymenu(struct cx23885_dev *dev,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx23885_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ 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;
+ struct cx23885_dev *dev = fh->dev;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+ if (*id & cx23885_tvnorms[i].id)
+ break;
+ 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 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)
+{
+ return cx23885_get_input(file, priv, i);
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return cx23885_set_input(file, priv, i);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+ strcpy(t->name, "Television");
+ call_all(dev, tuner, g_tuner, t);
+
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+
+ /* Update the A/V core */
+ call_all(dev, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ call_all(dev, tuner, g_frequency, f);
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ return cx23885_set_frequency(file, priv, f);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+ return cx23885_get_control(dev, ctl);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+ return cx23885_set_control(dev, ctl);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ strlcpy(cap->driver, dev->name, sizeof(cap->driver));
+ strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ 0;
+ if (UNSET != dev->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_reqbufs(&fh->mpegq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_querybuf(&fh->mpegq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_qbuf(&fh->mpegq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx23885_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_streamon(&fh->mpegq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_streamoff(&fh->mpegq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
+
+ if (err == 0) {
+ err = cx2341x_update(dev, cx23885_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
+ }
+ return err;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ printk(KERN_INFO
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ call_all(dev, core, log_status);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ printk(KERN_INFO
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *a)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ return cx23885_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ return cx23885_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+ struct cx23885_dev *dev = video_drvdata(file);
+ struct cx23885_fh *fh;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh)
+ return -ENOMEM;
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
+ &dev->pci->dev, &dev->ts1.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx23885_buffer),
+ fh, NULL);
+ return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* FIXME: Review this crap */
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+ /* stop mpeg capture */
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+
+ msleep(500);
+ cx23885_417_check_encoder(dev);
+
+ cx23885_cancel_buffers(&fh->dev->ts1);
+ }
+ }
+
+ if (fh->mpegq.streaming)
+ videobuf_streamoff(&fh->mpegq);
+ if (fh->mpegq.reading)
+ videobuf_read_stop(&fh->mpegq);
+
+ videobuf_mmap_free(&fh->mpegq);
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+ /* 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, 1) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s\n", __func__);
+
+ return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = video_ioctl2,
+};
+
+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,
+ .vidioc_s_input = vidioc_s_input,
+ .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_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,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .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_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_querymenu = vidioc_querymenu,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_chip_ident = cx23885_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = cx23885_g_register,
+ .vidioc_s_register = cx23885_s_register,
+#endif
+};
+
+static struct video_device cx23885_mpeg_template = {
+ .name = "cx23885",
+ .fops = &mpeg_fops,
+ .ioctl_ops = &mpeg_ioctl_ops,
+ .tvnorms = CX23885_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+void cx23885_417_unregister(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ if (dev->v4l_device) {
+ if (video_is_registered(dev->v4l_device))
+ video_unregister_device(dev->v4l_device);
+ else
+ video_device_release(dev->v4l_device);
+ dev->v4l_device = NULL;
+ }
+}
+
+static struct video_device *cx23885_video_dev_alloc(
+ struct cx23885_tsport *tsport,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+ struct cx23885_dev *dev = tsport->dev;
+
+ dprintk(1, "%s()\n", __func__);
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ 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;
+}
+
+int cx23885_417_register(struct cx23885_dev *dev)
+{
+ /* FIXME: Port1 hardcoded here */
+ int err = -ENODEV;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
+ return err;
+
+ /* Set default TV standard */
+ dev->encodernorm = cx23885_tvnorms[0];
+
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ tsport->height = 480;
+ else
+ tsport->height = 576;
+
+ tsport->width = 720;
+ cx2341x_fill_defaults(&dev->mpeg_params);
+
+ dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+ /* Allocate and initialize V4L video device */
+ dev->v4l_device = cx23885_video_dev_alloc(tsport,
+ dev->pci, &cx23885_mpeg_template, "mpeg");
+ video_set_drvdata(dev->v4l_device, dev);
+ err = video_register_device(dev->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
+ return err;
+ }
+
+ 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;
+}
+
+MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME);
diff --git a/drivers/media/video/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index 795169237e70..795169237e70 100644
--- a/drivers/media/video/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
diff --git a/drivers/media/video/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c
index 134ebddd860f..134ebddd860f 100644
--- a/drivers/media/video/cx23885/cx23885-av.c
+++ b/drivers/media/pci/cx23885/cx23885-av.c
diff --git a/drivers/media/video/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h
index d2915c3e53a2..d2915c3e53a2 100644
--- a/drivers/media/video/cx23885/cx23885-av.h
+++ b/drivers/media/pci/cx23885/cx23885-av.h
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
new file mode 100644
index 000000000000..d889bd2fe9cc
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -0,0 +1,1684 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/pci.h>
+#include <linux/delay.h>
+#include <media/cx25840.h>
+#include <linux/firmware.h>
+#include <misc/altera.h>
+
+#include "cx23885.h"
+#include "tuner-xc2028.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
+#include "altera-ci.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "cx23888-ir.h"
+
+static unsigned int netup_card_rev = 4;
+module_param(netup_card_rev, int, 0644);
+MODULE_PARM_DESC(netup_card_rev,
+ "NetUP Dual DVB-T/C CI card revision");
+static unsigned int enable_885_ir;
+module_param(enable_885_ir, int, 0644);
+MODULE_PARM_DESC(enable_885_ir,
+ "Enable integrated IR controller for supported\n"
+ "\t\t CX2388[57] boards that are wired for it:\n"
+ "\t\t\tHVR-1250 (reported safe)\n"
+ "\t\t\tTerraTec Cinergy T PCIe Dual (not well tested, appears to be safe)\n"
+ "\t\t\tTeVii S470 (reported unsafe)\n"
+ "\t\t This can cause an interrupt storm with some cards.\n"
+ "\t\t Default: 0 [Disabled]");
+
+/* ------------------------------------------------------------------ */
+/* board config info */
+
+struct cx23885_board cx23885_boards[] = {
+ [CX23885_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ /* Ensure safe default for unknown boards */
+ .clk_freq = 0,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = 1,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE3,
+ .vmux = 2,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE4,
+ .vmux = 3,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+ .name = "Hauppauge WinTV-HVR1800lp",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ }, {
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+ .name = "Hauppauge WinTV-HVR1800",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_ENCODER,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .tuner_bus = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1,
+ .amux = CX25840_AUDIO8,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ .gpio0 = 0,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+ .name = "Hauppauge WinTV-HVR1250",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .tuner_bus = 1,
+#endif
+ .force_bff = 1,
+ .input = {{
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1,
+ .amux = CX25840_AUDIO8,
+ .gpio0 = 0xff00,
+ }, {
+#endif
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ .gpio0 = 0xff02,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ .gpio0 = 0xff02,
+ } },
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
+ .name = "DViCO FusionHDTV5 Express",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
+ .name = "Hauppauge WinTV-HVR1500Q",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1500] = {
+ .name = "Hauppauge WinTV-HVR1500",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61, /* 0xc2 >> 1 */
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .gpio0 = 0,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1200] = {
+ .name = "Hauppauge WinTV-HVR1200",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1700] = {
+ .name = "Hauppauge WinTV-HVR1700",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1400] = {
+ .name = "Hauppauge WinTV-HVR1400",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = {
+ .name = "DViCO FusionHDTV7 Dual Express",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
+ .name = "DViCO FusionHDTV DVB-T Dual Express",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = {
+ .name = "Leadtek Winfast PxDVR3200 H",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
+ .name = "Leadtek Winfast PxDVR3200 H XC4000",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_XC4000,
+ .tuner_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2 |
+ CX25840_NONE0_CH3,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN7_CH1 |
+ CX25840_VIN6_CH2 |
+ CX25840_VIN8_CH3 |
+ CX25840_COMPONENT_ON,
+ } },
+ },
+ [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
+ .name = "Compro VideoMate E650F",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_TBS_6920] = {
+ .name = "TurboSight TBS 6920",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_TEVII_S470] = {
+ .name = "TeVii S470",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVBWORLD_2005] = {
+ .name = "DVBWorld DVB-S2 2005",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
+ .ci_type = 1,
+ .name = "NetUP Dual DVB-S2 CI",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1270] = {
+ .name = "Hauppauge WinTV-HVR1270",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1275] = {
+ .name = "Hauppauge WinTV-HVR1275",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1255] = {
+ .name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
+ .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_HAUPPAUGE_HVR1255_22111] = {
+ .name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
+ .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_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1210] = {
+ .name = "Hauppauge WinTV-HVR1210",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_MYGICA_X8506] = {
+ .name = "Mygica X8506 DMB-TH",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_bus = 1,
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .input = {
+ {
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_COMPOSITE2,
+ },
+ {
+ .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_MAGICPRO_PROHDTVE2] = {
+ .name = "Magic-Pro ProHDTV Extreme 2",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_bus = 1,
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .input = {
+ {
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_COMPOSITE2,
+ },
+ {
+ .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_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",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1290] = {
+ .name = "Hauppauge WinTV-HVR1290",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_MYGICA_X8558PRO] = {
+ .name = "Mygica X8558 PRO DMB-TH",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = {
+ .name = "LEADTEK WinFast PxTV1200",
+ .porta = CX23885_ANALOG_VIDEO,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .tuner_bus = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2 |
+ CX25840_NONE0_CH3,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN7_CH1 |
+ CX25840_VIN6_CH2 |
+ CX25840_VIN8_CH3 |
+ CX25840_COMPONENT_ON,
+ } },
+ },
+ [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = {
+ .name = "GoTView X5 3D Hybrid",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x64,
+ .tuner_bus = 1,
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2,
+ .gpio0 = 0x02,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX23885_VMUX_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ } },
+ },
+ [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = {
+ .ci_type = 2,
+ .name = "NetUP Dual DVB-T/C-CI RF",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ .num_fds_portb = 2,
+ .num_fds_portc = 2,
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x64,
+ .input = { {
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_COMPOSITE1,
+ } },
+ },
+ [CX23885_BOARD_MPX885] = {
+ .name = "MPX-885",
+ .porta = CX23885_ANALOG_VIDEO,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_COMPOSITE1,
+ .amux = CX25840_AUDIO6,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = CX25840_COMPOSITE2,
+ .amux = CX25840_AUDIO6,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE3,
+ .vmux = CX25840_COMPOSITE3,
+ .amux = CX25840_AUDIO7,
+ .gpio0 = 0,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE4,
+ .vmux = CX25840_COMPOSITE4,
+ .amux = CX25840_AUDIO7,
+ .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,
+ },
+ [CX23885_BOARD_TEVII_S471] = {
+ .name = "TeVii S471",
+ .portb = CX23885_MPEG_DVB,
+ }
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs */
+
+struct cx23885_subid cx23885_subids[] = {
+ {
+ .subvendor = 0x0070,
+ .subdevice = 0x3400,
+ .card = CX23885_BOARD_UNKNOWN,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7600,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7800,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7801,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7809,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7911,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1250,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xd500,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7790,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7797,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7710,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1500,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7717,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1500,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x71d1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x71d3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8101,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1700,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8010,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1400,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xd618,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb78,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6681,
+ .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6f39,
+ .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000,
+ }, {
+ .subvendor = 0x185b,
+ .subdevice = 0xe800,
+ .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
+ }, {
+ .subvendor = 0x6920,
+ .subdevice = 0x8888,
+ .card = CX23885_BOARD_TBS_6920,
+ }, {
+ .subvendor = 0xd470,
+ .subdevice = 0x9022,
+ .card = CX23885_BOARD_TEVII_S470,
+ }, {
+ .subvendor = 0x0001,
+ .subdevice = 0x2005,
+ .card = CX23885_BOARD_DVBWORLD_2005,
+ }, {
+ .subvendor = 0x1b55,
+ .subdevice = 0x2a2c,
+ .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2211,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1270,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2215,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x221d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2251,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2259,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255_22111,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2291,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2295,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2299,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x229d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f0,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f2,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f4,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f5,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8651,
+ .card = CX23885_BOARD_MYGICA_X8506,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8657,
+ .card = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8541,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1850,
+ }, {
+ .subvendor = 0x1858,
+ .subdevice = 0xe800,
+ .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8551,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1290,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8578,
+ .card = CX23885_BOARD_MYGICA_X8558PRO,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6f22,
+ .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
+ }, {
+ .subvendor = 0x5654,
+ .subdevice = 0x2390,
+ .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
+ }, {
+ .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,
+ }, {
+ .subvendor = 0xd471,
+ .subdevice = 0x9022,
+ .card = CX23885_BOARD_TEVII_S471,
+ },
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+ int i;
+
+ if (0 == dev->pci->subsystem_vendor &&
+ 0 == dev->pci->subsystem_device) {
+ printk(KERN_INFO
+ "%s: Board has no valid PCIe Subsystem ID and can't\n"
+ "%s: be autodetected. Pass card=<n> insmod option\n"
+ "%s: to workaround that. Redirect complaints to the\n"
+ "%s: vendor of the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name, dev->name, dev->name, dev->name, dev->name);
+ } else {
+ printk(KERN_INFO
+ "%s: Your board isn't known (yet) to the driver.\n"
+ "%s: Try to pick one of the existing card configs via\n"
+ "%s: card=<n> insmod option. Updating to the latest\n"
+ "%s: version might help as well.\n",
+ dev->name, dev->name, dev->name, dev->name);
+ }
+ printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < cx23885_bcount; i++)
+ printk(KERN_INFO "%s: card=%d -> %s\n",
+ dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
+ eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 22001:
+ /* WinTV-HVR1270 (PCIe, Retail, half height)
+ * ATSC/QAM and basic analog, IR Blast */
+ case 22009:
+ /* WinTV-HVR1210 (PCIe, Retail, half height)
+ * DVB-T and basic analog, IR Blast */
+ case 22011:
+ /* WinTV-HVR1270 (PCIe, Retail, half height)
+ * ATSC/QAM and basic analog, IR Recv */
+ case 22019:
+ /* WinTV-HVR1210 (PCIe, Retail, half height)
+ * DVB-T and basic analog, IR Recv */
+ case 22021:
+ /* WinTV-HVR1275 (PCIe, Retail, half height)
+ * ATSC/QAM and basic analog, IR Recv */
+ case 22029:
+ /* WinTV-HVR1210 (PCIe, Retail, half height)
+ * DVB-T and basic analog, IR Recv */
+ case 22101:
+ /* WinTV-HVR1270 (PCIe, Retail, full height)
+ * ATSC/QAM and basic analog, IR Blast */
+ case 22109:
+ /* WinTV-HVR1210 (PCIe, Retail, full height)
+ * DVB-T and basic analog, IR Blast */
+ case 22111:
+ /* WinTV-HVR1270 (PCIe, Retail, full height)
+ * ATSC/QAM and basic analog, IR Recv */
+ case 22119:
+ /* WinTV-HVR1210 (PCIe, Retail, full height)
+ * DVB-T and basic analog, IR Recv */
+ case 22121:
+ /* WinTV-HVR1275 (PCIe, Retail, full height)
+ * ATSC/QAM and basic analog, IR Recv */
+ case 22129:
+ /* WinTV-HVR1210 (PCIe, Retail, full height)
+ * DVB-T and basic analog, IR Recv */
+ case 71009:
+ /* WinTV-HVR1200 (PCIe, Retail, full height)
+ * DVB-T and basic analog */
+ case 71359:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71439:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71449:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71939:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71949:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71959:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71979:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71999:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 76601:
+ /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual
+ channel ATSC and MPEG2 HW Encoder */
+ case 77001:
+ /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC
+ and Basic analog */
+ case 77011:
+ /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC
+ and Basic analog */
+ case 77041:
+ /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM
+ and Basic analog */
+ case 77051:
+ /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM
+ and Basic analog */
+ case 78011:
+ /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78501:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78521:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78531:
+ /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 78631:
+ /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ case 79001:
+ /* WinTV-HVR1250 (PCIe, Retail, IR, full height,
+ ATSC and Basic analog */
+ case 79101:
+ /* WinTV-HVR1250 (PCIe, Retail, IR, half height,
+ ATSC and Basic analog */
+ case 79501:
+ /* WinTV-HVR1250 (PCIe, No IR, half height,
+ ATSC [at least] and Basic analog) */
+ case 79561:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+ ATSC and Basic analog */
+ case 79571:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, full height,
+ ATSC and Basic analog */
+ case 79671:
+ /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
+ ATSC and Basic analog */
+ case 80019:
+ /* WinTV-HVR1400 (Express Card, Retail, IR,
+ * DVB-T and Basic analog */
+ case 81509:
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
+ * DVB-T and MPEG2 HW Encoder */
+ case 81519:
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
+ * DVB-T and MPEG2 HW Encoder */
+ break;
+ case 85021:
+ /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ break;
+ case 85721:
+ /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
+ Dual channel ATSC and Basic analog */
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n",
+ dev->name, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ dev->name, tv.model);
+}
+
+int cx23885_tuner_callback(void *priv, int component, int command, int arg)
+{
+ struct cx23885_tsport *port = priv;
+ struct cx23885_dev *dev = port->dev;
+ u32 bitmask = 0;
+
+ if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH))
+ return 0;
+
+ if (command != 0) {
+ printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
+ __func__, command);
+ return -EINVAL;
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+ /* Tuner Reset Command */
+ bitmask = 0x04;
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ /* Two identical tuners on two different i2c buses,
+ * we need to reset the correct gpio. */
+ if (port->nr == 1)
+ bitmask = 0x01;
+ else if (port->nr == 2)
+ bitmask = 0x04;
+ break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ /* Tuner Reset Command */
+ bitmask = 0x02;
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ altera_ci_tuner_reset(dev, port->nr);
+ break;
+ }
+
+ if (bitmask) {
+ /* Drive the tuner into reset and back out */
+ cx_clear(GP0_IO, bitmask);
+ mdelay(200);
+ cx_set(GP0_IO, bitmask);
+ }
+
+ return 0;
+}
+
+void cx23885_gpio_setup(struct cx23885_dev *dev)
+{
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* GPIO-0 cx24227 demodulator reset */
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ /* GPIO-0 cx24227 demodulator */
+ /* GPIO-2 xc3028 tuner */
+
+ /* Put the parts into reset */
+ cx_set(GP0_IO, 0x00050000);
+ cx_clear(GP0_IO, 0x00000005);
+ msleep(5);
+
+ /* Bring the parts out of reset */
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ /* GPIO-0 cx24227 demodulator reset */
+ /* GPIO-2 xc5000 tuner reset */
+ cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+
+ /* CX23417 GPIO's */
+ /* EIO15 Zilog Reset */
+ /* EIO14 S5H1409/CX24227 Reset */
+ mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
+
+ /* Bring the demod and blaster out of reset */
+ mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
+
+ /* Force the TDA8295A into reset and back */
+ cx23885_gpio_enable(dev, GPIO_2, 1);
+ cx23885_gpio_set(dev, GPIO_2);
+ mdelay(20);
+ cx23885_gpio_clear(dev, GPIO_2);
+ mdelay(20);
+ cx23885_gpio_set(dev, GPIO_2);
+ mdelay(20);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ /* GPIO-0 tda10048 demodulator reset */
+ /* GPIO-2 tda18271 tuner reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ /* GPIO-0 TDA10048 demodulator reset */
+ /* GPIO-2 TDA8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+
+ /* The following GPIO's are on the interna AVCore (cx25840) */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 IR_TX 416/DVBT Select */
+ /* GPIO-21 IIS DAT */
+ /* GPIO-22 IIS WCLK */
+ /* GPIO-23 IIS BCLK */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ /* GPIO-0 Dibcom7000p demodulator reset */
+ /* GPIO-2 xc3028L tuner reset */
+ /* GPIO-13 LED */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ /* GPIO-0 xc5000 tuner reset i2c bus 0 */
+ /* GPIO-1 s5h1409 demod reset i2c bus 0 */
+ /* GPIO-2 xc5000 tuner reset i2c bus 1 */
+ /* GPIO-3 s5h1409 demod reset i2c bus 0 */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x000f0000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x0000000f);
+ mdelay(20);
+ cx_set(GP0_IO, 0x000f000f);
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ /* GPIO-0 portb xc3028 reset */
+ /* GPIO-1 portb zl10353 reset */
+ /* GPIO-2 portc xc3028 reset */
+ /* GPIO-3 portc zl10353 reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x000f0000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x0000000f);
+ mdelay(20);
+ cx_set(GP0_IO, 0x000f000f);
+ break;
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+ /* GPIO-2 xc3028 tuner reset */
+
+ /* The following GPIO's are on the internal AVCore (cx25840) */
+ /* GPIO-? zl10353 demod reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00040000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000004);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00040004);
+ break;
+ case CX23885_BOARD_TBS_6920:
+ cx_write(MC417_CTL, 0x00000036);
+ cx_write(MC417_OEN, 0x00001000);
+ cx_set(MC417_RWD, 0x00000002);
+ mdelay(200);
+ cx_clear(MC417_RWD, 0x00000800);
+ mdelay(200);
+ cx_set(MC417_RWD, 0x00000800);
+ mdelay(200);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ /* GPIO-0 INTA from CiMax1
+ GPIO-1 INTB from CiMax2
+ GPIO-2 reset chips
+ GPIO-3 to GPIO-10 data/addr for CA
+ GPIO-11 ~CS0 to CiMax1
+ GPIO-12 ~CS1 to CiMax2
+ GPIO-13 ADL0 load LSB addr
+ GPIO-14 ADL1 load MSB addr
+ GPIO-15 ~RDY from CiMax
+ GPIO-17 ~RD to CiMax
+ GPIO-18 ~WR to CiMax
+ */
+ cx_set(GP0_IO, 0x00040000); /* GPIO as out */
+ /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
+ cx_clear(GP0_IO, 0x00030004);
+ mdelay(100);/* reset delay */
+ cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
+ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+ /* GPIO-15 IN as ~ACK, rest as OUT */
+ cx_write(MC417_OEN, 0x00001000);
+ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+ cx_write(MC417_RWD, 0x0000c300);
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
+ /* GPIO-6 I2C Gate which can isolate the demod from the bus */
+ /* GPIO-9 Demod reset */
+
+ /* Put the parts into reset and back */
+ cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1);
+ cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5);
+ cx23885_gpio_clear(dev, GPIO_9);
+ mdelay(20);
+ cx23885_gpio_set(dev, GPIO_9);
+ 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 */
+ cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1);
+ cx23885_gpio_clear(dev, GPIO_1 | GPIO_2);
+ mdelay(100);
+ cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2);
+ mdelay(100);
+ break;
+ case CX23885_BOARD_MYGICA_X8558PRO:
+ /* GPIO-0 reset first ATBM8830 */
+ /* GPIO-1 reset second ATBM8830 */
+ cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+ cx23885_gpio_clear(dev, GPIO_0 | GPIO_1);
+ mdelay(100);
+ cx23885_gpio_set(dev, GPIO_0 | GPIO_1);
+ mdelay(100);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 Wake# */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 C_IR_TX */
+ /* GPIO-21 I2S DAT */
+ /* GPIO-22 I2S WCLK */
+ /* GPIO-23 I2S BCLK */
+ /* ALT GPIO: EXP GPIO LATCH */
+
+ /* CX23417 GPIO's */
+ /* GPIO-14 S5H1411/CX24228 Reset */
+ /* GPIO-13 EEPROM write protect */
+ mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+ mdelay(100);
+
+ /* Bring the demod out of reset */
+ mc417_gpio_set(dev, GPIO_14);
+ mdelay(100);
+
+ /* CX24228 GPIO */
+ /* Connected to IF / Mux */
+ break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ /* GPIO-0 ~INT in
+ GPIO-1 TMS out
+ GPIO-2 ~reset chips out
+ GPIO-3 to GPIO-10 data/addr for CA in/out
+ GPIO-11 ~CS out
+ GPIO-12 ADDR out
+ GPIO-13 ~WR out
+ GPIO-14 ~RD out
+ GPIO-15 ~RDY in
+ GPIO-16 TCK out
+ GPIO-17 TDO in
+ GPIO-18 TDI out
+ */
+ cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */
+ /* GPIO-0 as INT, reset & TMS low */
+ cx_clear(GP0_IO, 0x00010006);
+ mdelay(100);/* reset delay */
+ cx_set(GP0_IO, 0x00000004); /* reset high */
+ cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */
+ /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */
+ cx_write(MC417_OEN, 0x00005000);
+ /* ~RD, ~WR high; ADDR low; ~CS high */
+ cx_write(MC417_RWD, 0x00000d00);
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+ break;
+ }
+}
+
+int cx23885_ir_init(struct cx23885_dev *dev)
+{
+ static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
+ {
+ .flags = V4L2_SUBDEV_IO_PIN_INPUT,
+ .pin = CX23885_PIN_IR_RX_GPIO19,
+ .function = CX23885_PAD_IR_RX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }, {
+ .flags = V4L2_SUBDEV_IO_PIN_OUTPUT,
+ .pin = CX23885_PIN_IR_TX_GPIO20,
+ .function = CX23885_PAD_IR_TX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }
+ };
+ const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg);
+
+ static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = {
+ {
+ .flags = V4L2_SUBDEV_IO_PIN_INPUT,
+ .pin = CX23885_PIN_IR_RX_GPIO19,
+ .function = CX23885_PAD_IR_RX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }
+ };
+ const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
+
+ struct v4l2_subdev_ir_parameters params;
+ int ret = 0;
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ /* FIXME: Implement me */
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ ret = cx23888_ir_probe(dev);
+ if (ret)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ ret = cx23888_ir_probe(dev);
+ if (ret)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+ /*
+ * For these boards we need to invert the Tx output via the
+ * IR controller to have the LED off while idle
+ */
+ v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, &params);
+ params.enable = false;
+ params.shutdown = false;
+ params.invert_level = true;
+ v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+ params.shutdown = true;
+ v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+ break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_TEVII_S470:
+ if (!enable_885_ir)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+ if (dev->sd_ir == NULL) {
+ ret = -ENODEV;
+ break;
+ }
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (!enable_885_ir)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+ if (dev->sd_ir == NULL) {
+ ret = -ENODEV;
+ break;
+ }
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ request_module("ir-kbd-i2c");
+ break;
+ }
+
+ return ret;
+}
+
+void cx23885_ir_fini(struct cx23885_dev *dev)
+{
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ cx23885_irq_remove(dev, PCI_MSK_IR);
+ cx23888_ir_remove(dev);
+ dev->sd_ir = NULL;
+ break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
+ /* sd_ir is a duplicate pointer to the AV Core, just clear it */
+ dev->sd_ir = NULL;
+ break;
+ }
+}
+
+int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
+{
+ int data;
+ int tdo = 0;
+ struct cx23885_dev *dev = (struct cx23885_dev *)device;
+ /*TMS*/
+ data = ((cx_read(GP0_IO)) & (~0x00000002));
+ data |= (tms ? 0x00020002 : 0x00020000);
+ cx_write(GP0_IO, data);
+
+ /*TDI*/
+ data = ((cx_read(MC417_RWD)) & (~0x0000a000));
+ data |= (tdi ? 0x00008000 : 0);
+ cx_write(MC417_RWD, data);
+ if (read_tdo)
+ tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/
+
+ cx_write(MC417_RWD, data | 0x00002000);
+ udelay(1);
+ /*TCK*/
+ cx_write(MC417_RWD, data);
+
+ return tdo;
+}
+
+void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
+{
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ if (dev->sd_ir)
+ cx23885_irq_add_enable(dev, PCI_MSK_IR);
+ break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (dev->sd_ir)
+ cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
+ break;
+ }
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+ struct cx23885_tsport *ts1 = &dev->ts1;
+ struct cx23885_tsport *ts2 = &dev->ts2;
+
+ static u8 eeprom[256];
+
+ 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));
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (dev->i2c_bus[0].i2c_rc == 0) {
+ if (eeprom[0x80] != 0x84)
+ hauppauge_eeprom(dev, eeprom+0xc0);
+ else
+ hauppauge_eeprom(dev, eeprom+0x80);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0x80);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0xc0);
+ break;
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ /* break omitted intentionally */
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ 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;
+ 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 */
+ ts1->gen_ctrl_val = 0x10e;
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+ /* 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 */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_TBS_6920:
+ ts1->gen_ctrl_val = 0x4; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_TEVII_S471:
+ case CX23885_BOARD_DVBWORLD_2005:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ 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;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_MYGICA_X8558PRO:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ default:
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ }
+
+ /* Certain boards support analog, or require the avcore to be
+ * loaded, ensure this happens.
+ */
+ switch (dev->board) {
+ case CX23885_BOARD_TEVII_S470:
+ /* Currently only enabled for the integrated IR controller */
+ if (!enable_885_ir)
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+ 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);
+ if (dev->sd_cx25840) {
+ dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
+ v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+ }
+ break;
+ }
+
+ /* AUX-PLL 27MHz CLK */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ netup_initialize(dev);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+ int ret;
+ const struct firmware *fw;
+ const char *filename = "dvb-netup-altera-01.fw";
+ char *action = "configure";
+ static struct netup_card_info cinfo;
+ struct altera_config netup_config = {
+ .dev = dev,
+ .action = action,
+ .jtag_io = netup_jtag_io,
+ };
+
+ netup_initialize(dev);
+
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+ if (netup_card_rev)
+ cinfo.rev = netup_card_rev;
+
+ switch (cinfo.rev) {
+ case 0x4:
+ filename = "dvb-netup-altera-04.fw";
+ break;
+ default:
+ filename = "dvb-netup-altera-01.fw";
+ break;
+ }
+ printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n",
+ cinfo.rev, filename);
+
+ ret = request_firmware(&fw, filename, &dev->pci->dev);
+ if (ret != 0)
+ printk(KERN_ERR "did not find the firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details "
+ "on firmware-problems.", filename);
+ else
+ altera_init(&netup_config, fw);
+
+ release_firmware(fw);
+ break;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 697728f09430..697728f09430 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
new file mode 100644
index 000000000000..f3202a52d535
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -0,0 +1,1356 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#include "dvb_ca_en50221.h"
+#include "s5h1409.h"
+#include "s5h1411.h"
+#include "mt2131.h"
+#include "tda8290.h"
+#include "tda18271.h"
+#include "lgdt330x.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "max2165.h"
+#include "tda10048.h"
+#include "tuner-xc2028.h"
+#include "tuner-simple.h"
+#include "dib7000p.h"
+#include "dibx000_common.h"
+#include "zl10353.h"
+#include "stv0900.h"
+#include "stv0900_reg.h"
+#include "stv6110.h"
+#include "lnbh24.h"
+#include "cx24116.h"
+#include "cimax2.h"
+#include "lgs8gxx.h"
+#include "netup-eeprom.h"
+#include "netup-init.h"
+#include "lgdt3305.h"
+#include "atbm8830.h"
+#include "ds3000.h"
+#include "cx23885-f300.h"
+#include "altera-ci.h"
+#include "stv0367.h"
+#include "drxk.h"
+#include "mt2063.h"
+
+static unsigned int debug;
+
+#define dprintk(level, fmt, arg...)\
+ do { if (debug >= level)\
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+ } while (0)
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int alt_tuner;
+module_param(alt_tuner, int, 0644);
+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_tsport *port = q->priv_data;
+
+ port->ts_packet_size = 188 * 4;
+ port->ts_packet_count = 32;
+
+ *size = port->ts_packet_size * port->ts_packet_count;
+ *count = 32;
+ return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ 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;
+ struct videobuf_dvb_frontend *fe;
+
+ f = &port->frontends;
+
+ if (f->gate <= 1) /* undefined or fe0 */
+ fe = videobuf_dvb_get_frontend(f, 1);
+ else
+ fe = videobuf_dvb_get_frontend(f, f->gate);
+
+ 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 = {
+ .buf_setup = dvb_buf_setup,
+ .buf_prepare = dvb_buf_prepare,
+ .buf_queue = dvb_buf_queue,
+ .buf_release = dvb_buf_release,
+};
+
+static struct s5h1409_config hauppauge_generic_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda10048_config hauppauge_hvr1200_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3800,
+ .dtv8_if_freq_khz = TDA10048_IF_4300,
+ .clk_freq_khz = TDA10048_CLK_16000,
+};
+
+static struct tda10048_config hauppauge_hvr1210_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+};
+
+static struct s5h1409_config hauppauge_ezqam_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .qam_if = 4000,
+ .inversion = S5H1409_INVERSION_ON,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1500_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct mt2131_config hauppauge_generic_tunerconfig = {
+ 0x61
+};
+
+static struct lgdt330x_config fusionhdtv_5_express = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40,
+};
+
+static struct s5h1409_config hauppauge_hvr1500q_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config dvico_s5h1409_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1411_config dvico_s5h1411_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_ON,
+ .qam_if = S5H1411_IF_44000,
+ .vsb_if = S5H1411_IF_44000,
+ .inversion = S5H1411_INVERSION_OFF,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1411_config hcw_s5h1411_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_44000,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
+ .i2c_address = 0x61,
+ .if_khz = 5380,
+};
+
+static struct xc5000_config dvico_xc5000_tunerconfig = {
+ .i2c_address = 0x64,
+ .if_khz = 5380,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 5380, .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_std_map hauppauge_hvr1200_tda18271_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_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+ .std_map = &hauppauge_hvr1200_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_config hauppauge_hvr1210_tuner_config = {
+ .gate = TDA18271_GATE_DIGITAL,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_std_map hauppauge_hvr127x_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x58 },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x58 },
+};
+
+static struct tda18271_config hauppauge_hvr127x_config = {
+ .std_map = &hauppauge_hvr127x_std_map,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+ .i2c_addr = 0x0e,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+};
+
+static struct dibx000_agc_config xc3028_agc_config = {
+ BAND_VHF | BAND_UHF, /* band_caps */
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+ * 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=2, P_agc_write=0
+ */
+ (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+ (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+ 712, /* inv_gain */
+ 21, /* time_stabiliz */
+
+ 0, /* alpha_level */
+ 118, /* thlock */
+
+ 0, /* wbd_inv */
+ 2867, /* wbd_ref */
+ 0, /* wbd_sel */
+ 2, /* wbd_alpha */
+
+ 0, /* agc1_max */
+ 0, /* agc1_min */
+ 39718, /* agc2_max */
+ 9930, /* agc2_min */
+ 0, /* agc1_pt1 */
+ 0, /* agc1_pt2 */
+ 0, /* agc1_pt3 */
+ 0, /* agc1_slope1 */
+ 0, /* agc1_slope2 */
+ 0, /* agc2_pt1 */
+ 128, /* agc2_pt2 */
+ 29, /* agc2_slope1 */
+ 29, /* agc2_slope2 */
+
+ 17, /* alpha_mant */
+ 27, /* alpha_exp */
+ 23, /* beta_mant */
+ 51, /* beta_exp */
+
+ 1, /* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.000000
+ * With external clock = 30.000000 */
+static struct dibx000_bandwidth_config xc3028_bw_config = {
+ 60000, /* internal */
+ 30000, /* sampling */
+ 1, /* pll_cfg: prediv */
+ 8, /* pll_cfg: ratio */
+ 3, /* pll_cfg: range */
+ 1, /* pll_cfg: reset */
+ 0, /* pll_cfg: bypass */
+ 0, /* misc: refdiv */
+ 0, /* misc: bypclk_div */
+ 1, /* misc: IO_CLK_en_core */
+ 1, /* misc: ADClkSrc */
+ 0, /* misc: modulo */
+ (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+ (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+ 20452225, /* timf */
+ 30000000 /* xtal_hz */
+};
+
+static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 0,
+ .update_lna = NULL,
+
+ .agc_config_count = 1,
+ .agc = &xc3028_agc_config,
+ .bw = &xc3028_bw_config,
+
+ .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 = NULL,
+ .spur_protect = 0,
+
+ .output_mode = OUTMODE_MPEG2_SERIAL,
+};
+
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+ .demod_address = 0x0f,
+ .if2 = 45600,
+ .no_tuner = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct stv0900_reg stv0900_ts_regs[] = {
+ { R0900_TSGENERAL, 0x00 },
+ { R0900_P1_TSSPEED, 0x40 },
+ { R0900_P2_TSSPEED, 0x40 },
+ { R0900_P1_TSCFGM, 0xc0 },
+ { R0900_P2_TSCFGM, 0xc0 },
+ { R0900_P1_TSCFGH, 0xe0 },
+ { R0900_P2_TSCFGH, 0xe0 },
+ { R0900_P1_TSCFGL, 0x20 },
+ { R0900_P2_TSCFGL, 0x20 },
+ { 0xffff, 0xff }, /* terminate */
+};
+
+static struct stv0900_config netup_stv0900_config = {
+ .demod_address = 0x68,
+ .demod_mode = 1, /* dual */
+ .xtal = 8000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .ts_config_regs = stv0900_ts_regs,
+ .tun1_maddress = 0,/* 0x60 */
+ .tun2_maddress = 3,/* 0x63 */
+ .tun1_adc = 1,/* 1 Vpp */
+ .tun2_adc = 1,/* 1 Vpp */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
+ .i2c_address = 0x60,
+ .mclk = 16000000,
+ .clk_div = 1,
+ .gain = 8, /* +16 dB - maximum gain */
+};
+
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
+ .i2c_address = 0x63,
+ .mclk = 16000000,
+ .clk_div = 1,
+ .gain = 8, /* +16 dB - maximum gain */
+};
+
+static struct cx24116_config tbs_cx24116_config = {
+ .demod_address = 0x55,
+};
+
+static struct ds3000_config tevii_ds3000_config = {
+ .demod_address = 0x68,
+};
+
+static struct cx24116_config dvbworld_cx24116_config = {
+ .demod_address = 0x05,
+};
+
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
+ .prod = LGS8GXX_PROD_LGS8GL5,
+ .demod_address = 0x19,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 1,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 5380, /* 5.38 MHz */
+ .if_neg_center = 1,
+ .ext_adc = 0,
+ .adc_signed = 0,
+ .if_neg_edge = 0,
+};
+
+static struct xc5000_config mygica_x8506_xc5000_config = {
+ .i2c_address = 0x61,
+ .if_khz = 5380,
+};
+
+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 (p->modulation) {
+ case VSB_8:
+ cx23885_gpio_clear(dev, GPIO_5);
+ break;
+ case QAM_64:
+ case QAM_256:
+ default:
+ cx23885_gpio_set(dev, GPIO_5);
+ break;
+ }
+ break;
+ case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ /* Select Digital TV */
+ cx23885_gpio_set(dev, GPIO_0);
+ break;
+ }
+ return 0;
+}
+
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x19,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 1,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 6500, /* 6.50 MHz */
+ .if_neg_center = 1,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 2, /* 1.6 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6500,
+};
+
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
+ .prod = ATBM8830_PROD_8830,
+ .demod_address = 0x44,
+ .serial_ts = 0,
+ .ts_sampling_edge = 1,
+ .ts_clk_gated = 0,
+ .osc_clk_freq = 30400, /* in kHz */
+ .if_freq = 0, /* zero IF */
+ .zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
+ .i2c_address = 0x60,
+ .osc_clk = 20
+};
+
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
+ .prod = ATBM8830_PROD_8830,
+ .demod_address = 0x44,
+ .serial_ts = 1,
+ .ts_sampling_edge = 1,
+ .ts_clk_gated = 0,
+ .osc_clk_freq = 30400, /* in kHz */
+ .if_freq = 0, /* zero IF */
+ .zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
+ .i2c_address = 0x60,
+ .osc_clk = 20
+};
+static struct stv0367_config netup_stv0367_config[] = {
+ {
+ .demod_address = 0x1c,
+ .xtal = 27000000,
+ .if_khz = 4500,
+ .if_iq_mode = 0,
+ .ts_mode = 1,
+ .clk_pol = 0,
+ }, {
+ .demod_address = 0x1d,
+ .xtal = 27000000,
+ .if_khz = 4500,
+ .if_iq_mode = 0,
+ .ts_mode = 1,
+ .clk_pol = 0,
+ },
+};
+
+static struct xc5000_config netup_xc5000_config[] = {
+ {
+ .i2c_address = 0x61,
+ .if_khz = 4500,
+ }, {
+ .i2c_address = 0x64,
+ .if_khz = 4500,
+ },
+};
+
+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;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+ uint32_t mem = 0;
+
+ mem = cx_read(MC417_RWD);
+ if (read)
+ cx_set(MC417_OEN, ALT_DATA);
+ else {
+ cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */
+ mem &= ~ALT_DATA;
+ mem |= (data & ALT_DATA);
+ }
+
+ if (flag)
+ mem |= ALT_AD_RG;
+ else
+ mem &= ~ALT_AD_RG;
+
+ mem &= ~ALT_CS;
+ if (read)
+ mem = (mem & ~ALT_RD) | ALT_WR;
+ else
+ mem = (mem & ~ALT_WR) | ALT_RD;
+
+ cx_write(MC417_RWD, mem); /* start RW cycle */
+
+ for (;;) {
+ mem = cx_read(MC417_RWD);
+ if ((mem & ALT_RDY) == 0)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ udelay(1);
+ }
+
+ cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS);
+ if (read)
+ return mem & ALT_DATA;
+
+ return 0;
+};
+
+static int dvb_register(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
+ struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+ int mfe_shared = 0; /* bus not shared by default */
+ int ret;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ /* init struct videobuf_dvb */
+ fe0->dvb.name = dev->name;
+
+ /* multi-frontend gate control is undefined or defaults to fe0 */
+ port->frontends.gate = 0;
+
+ /* Sets the gate control callback to be used by i2c command calls */
+ port->gate_ctrl = cx23885_dvb_gate_ctrl;
+
+ /* init frontend */
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_generic_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+ &hauppauge_lgdt3305_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr127x_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ 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[1].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_HVR1800:
+ i2c_bus = &dev->i2c_bus[0];
+ switch (alt_tuner) {
+ case 1:
+ fe0->dvb.frontend =
+ dvb_attach(s5h1409_attach,
+ &hauppauge_ezqam_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_tda18271_config);
+ }
+ break;
+ case 0:
+ default:
+ fe0->dvb.frontend =
+ dvb_attach(s5h1409_attach,
+ &hauppauge_generic_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ break;
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1800lp_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_5_express,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ i2c_bus = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1500q_config,
+ &dev->i2c_bus[0].i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_hvr1500q_tunerconfig);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ i2c_bus = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1500_config,
+ &dev->i2c_bus[0].i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &i2c_bus->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_OREN538,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ fe0->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &hauppauge_hvr1200_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr1200_tuner_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &hauppauge_hvr1210_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr1210_tuner_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(dib7000p_attach,
+ &i2c_bus->i2c_adap,
+ 0x12, &hauppauge_hvr1400_dib7000_config);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
+ .i2c_addr = 0x64,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = XC3028L_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_DIBCOM52,
+ /* This is true for all demods with
+ v36 firmware? */
+ .type = XC2028_D2633,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ fe0->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &dvico_s5h1409_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend == NULL)
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &dvico_s5h1411_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &dvico_xc5000_tunerconfig);
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &i2c_bus->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ };
+
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
+ &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ }
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ i2c_bus = &dev->i2c_bus[0];
+
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
+ .i2c_addr = 0x61,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ };
+
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
+ &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+ i2c_bus = &dev->i2c_bus[0];
+
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc4000_config cfg = {
+ .i2c_address = 0x61,
+ .default_pm = 0,
+ .dvb_amplitude = 134,
+ .set_smoothedcvbs = 1,
+ .if_khz = 4560
+ };
+
+ 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:
+ i2c_bus = &dev->i2c_bus[1];
+
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &tbs_cx24116_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
+
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ i2c_bus = &dev->i2c_bus[1];
+
+ fe0->dvb.frontend = dvb_attach(ds3000_attach,
+ &tevii_ds3000_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
+
+ break;
+ case CX23885_BOARD_DVBWORLD_2005:
+ i2c_bus = &dev->i2c_bus[1];
+
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &dvbworld_cx24116_config,
+ &i2c_bus->i2c_adap);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ i2c_bus = &dev->i2c_bus[0];
+ switch (port->nr) {
+ /* port B */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 0);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_a,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL | LNBH24_TTX,
+ LNBH24_TEN, 0x09))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ /* port C */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &netup_stv0900_config,
+ &i2c_bus->i2c_adap, 1);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(stv6110_attach,
+ fe0->dvb.frontend,
+ &netup_stv6110_tunerconfig_b,
+ &i2c_bus->i2c_adap)) {
+ if (!dvb_attach(lnbh24_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ LNBH24_PCL | LNBH24_TTX,
+ LNBH24_TEN, 0x0a))
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+
+ }
+ }
+ break;
+ }
+ break;
+ case CX23885_BOARD_MYGICA_X8506:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &mygica_x8506_lgs8gl5_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &mygica_x8506_xc5000_config);
+ }
+ break;
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &magicpro_prohdtve2_lgs8g75_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &magicpro_prohdtve2_xc5000_config);
+ }
+ 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,
+ &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);
+ break;
+ case CX23885_BOARD_MYGICA_X8558PRO:
+ switch (port->nr) {
+ /* port B */
+ case 1:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+ &mygica_x8558pro_atbm8830_cfg1,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(max2165_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &mygic_x8558pro_max2165_cfg1);
+ }
+ break;
+ /* port C */
+ case 2:
+ i2c_bus = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+ &mygica_x8558pro_atbm8830_cfg2,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(max2165_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &mygic_x8558pro_max2165_cfg2);
+ }
+ break;
+ }
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ i2c_bus = &dev->i2c_bus[0];
+ mfe_shared = 1;/* MFE */
+ port->frontends.gate = 0;/* not clear for me yet */
+ /* ports B, C */
+ /* MFE frontend 1 DVB-T */
+ fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
+ &netup_stv0367_config[port->nr - 1],
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (NULL == dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &netup_xc5000_config[port->nr - 1]))
+ goto frontend_detach;
+ /* load xc5000 firmware */
+ fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
+ }
+ /* MFE frontend 2 */
+ fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+ if (fe1 == NULL)
+ goto frontend_detach;
+ /* DVB-C init */
+ fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
+ &netup_stv0367_config[port->nr - 1],
+ &i2c_bus->i2c_adap);
+ if (fe1->dvb.frontend != NULL) {
+ fe1->dvb.frontend->id = 1;
+ if (NULL == dvb_attach(xc5000_attach,
+ fe1->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &netup_xc5000_config[port->nr - 1]))
+ 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;
+ case CX23885_BOARD_TEVII_S471:
+ i2c_bus = &dev->i2c_bus[1];
+
+ fe0->dvb.frontend = dvb_attach(ds3000_attach,
+ &tevii_ds3000_config,
+ &i2c_bus->i2c_adap);
+ break;
+ default:
+ printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+ " isn't supported yet\n",
+ dev->name);
+ break;
+ }
+
+ if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
+ printk(KERN_ERR "%s: frontend initialization failed\n",
+ dev->name);
+ goto frontend_detach;
+ }
+
+ /* define general-purpose callback pointer */
+ fe0->dvb.frontend->callback = cx23885_tuner_callback;
+ if (fe1)
+ fe1->dvb.frontend->callback = cx23885_tuner_callback;
+#if 0
+ /* Ensure all frontends negotiate bus access */
+ fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+ if (fe1)
+ fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+#endif
+
+ /* Put the analog decoder in standby to keep it quiet */
+ call_all(dev, core, s_power, 0);
+
+ if (fe0->dvb.frontend->ops.analog_ops.standby)
+ fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
+
+ /* register everything */
+ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ &dev->pci->dev, adapter_nr, mfe_shared);
+ if (ret)
+ goto frontend_detach;
+
+ /* init CI & MAC */
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+ static struct netup_card_info cinfo;
+
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+ memcpy(port->frontends.adapter.proposed_mac,
+ cinfo.port[port->nr - 1].mac, 6);
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+ port->nr, port->frontends.adapter.proposed_mac);
+
+ netup_ci_init(port);
+ break;
+ }
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+ struct altera_ci_config netup_ci_cfg = {
+ .dev = dev,/* magic number to identify*/
+ .adapter = &port->frontends.adapter,/* for CI */
+ .demux = &fe0->dvb.demux,/* for hw pid filter */
+ .fpga_rw = netup_altera_fpga_rw,
+ };
+
+ altera_ci_init(&netup_ci_cfg, port->nr);
+ break;
+ }
+ case CX23885_BOARD_TEVII_S470: {
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+ if (port->nr != 1)
+ break;
+
+ /* Read entire EEPROM */
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+ printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+ break;
+ }
+ }
+
+ return ret;
+
+frontend_detach:
+ port->gate_ctrl = NULL;
+ videobuf_dvb_dealloc_frontends(&port->frontends);
+ return -EINVAL;
+}
+
+int cx23885_dvb_register(struct cx23885_tsport *port)
+{
+
+ struct videobuf_dvb_frontend *fe0;
+ struct cx23885_dev *dev = port->dev;
+ int err, i;
+
+ /* Here we need to allocate the correct number of frontends,
+ * as reflected in the cards struct. The reality is that currently
+ * no cx23885 boards support this - yet. But, if we don't modify this
+ * code then the second frontend would never be allocated (later)
+ * and fail with error before the attach in dvb_register().
+ * Without these changes we risk an OOPS later. The changes here
+ * are for safety, and should provide a good foundation for the
+ * future addition of any multi-frontend cx23885 based boards.
+ */
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+ port->num_frontends);
+
+ for (i = 1; i <= port->num_frontends; i++) {
+ if (videobuf_dvb_alloc_frontend(
+ &port->frontends, i) == NULL) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ return -ENOMEM;
+ }
+
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+ if (!fe0)
+ err = -EINVAL;
+
+ dprintk(1, "%s\n", __func__);
+ dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ dev->board,
+ dev->name,
+ dev->pci_bus,
+ dev->pci_slot);
+
+ err = -ENODEV;
+
+ /* dvb stuff */
+ /* We have to init the queue for each frontend on a port. */
+ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
+ videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
+ &dev->pci->dev, &port->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
+ sizeof(struct cx23885_buffer), port, NULL);
+ }
+ err = dvb_register(port);
+ if (err != 0)
+ printk(KERN_ERR "%s() dvb_register failed err = %d\n",
+ __func__, err);
+
+ return err;
+}
+
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
+{
+ struct videobuf_dvb_frontend *fe0;
+
+ /* FIXME: in an error condition where the we have
+ * an expected number of frontends (attach problem)
+ * then this might not clean up correctly, if 1
+ * is invalid.
+ * This comment only applies to future boards IF they
+ * implement MFE support.
+ */
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ if (fe0 && fe0->dvb.frontend)
+ videobuf_dvb_unregister_bus(&port->frontends);
+
+ switch (port->dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+ netup_ci_exit(port);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ altera_ci_release(port->dev, port->nr);
+ break;
+ }
+
+ port->gate_ctrl = NULL;
+
+ return 0;
+}
+
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c
index 93998f220986..93998f220986 100644
--- a/drivers/media/video/cx23885/cx23885-f300.c
+++ b/drivers/media/pci/cx23885/cx23885-f300.c
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/pci/cx23885/cx23885-f300.h
index e73344c94963..e73344c94963 100644
--- a/drivers/media/video/cx23885/cx23885-f300.h
+++ b/drivers/media/pci/cx23885/cx23885-f300.h
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index 4887314339cb..4887314339cb 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
new file mode 100644
index 000000000000..56066721edc1
--- /dev/null
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -0,0 +1,365 @@
+/*
+ * Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ * Infrared remote control input device
+ *
+ * Most of this file is
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
+ *
+ * However, the cx23885_input_{init,fini} functions contained herein are
+ * derived from Linux kernel files linux/media/video/.../...-input.c marked as:
+ *
+ * Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ * Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ * Markus Rechberger <mrechberger@gmail.com>
+ * Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Sascha Sommer <saschasommer@freenet.de>
+ * Copyright (C) 2004, 2005 Chris Pascoe
+ * Copyright (C) 2003, 2004 Gerd Knorr
+ * Copyright (C) 2003 Pavel Machek
+ *
+ * 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 <linux/slab.h>
+#include <media/rc-core.h>
+#include <media/v4l2-subdev.h>
+
+#include "cx23885.h"
+
+#define MODULE_NAME "cx23885"
+
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+ bool overrun)
+{
+ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
+
+ ssize_t num;
+ int count, i;
+ bool handle = false;
+ struct ir_raw_event ir_core_event[64];
+
+ do {
+ num = 0;
+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
+ sizeof(ir_core_event), &num);
+
+ count = num / sizeof(struct ir_raw_event);
+
+ for (i = 0; i < count; i++) {
+ ir_raw_event_store(kernel_ir->rc,
+ &ir_core_event[i]);
+ handle = true;
+ }
+ } while (num != 0);
+
+ if (overrun)
+ ir_raw_event_reset(kernel_ir->rc);
+ else if (handle)
+ ir_raw_event_handle(kernel_ir->rc);
+}
+
+void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
+{
+ struct v4l2_subdev_ir_parameters params;
+ int overrun, data_available;
+
+ if (dev->sd_ir == NULL || events == 0)
+ return;
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /*
+ * The only boards we handle right now. However other boards
+ * using the CX2388x integrated IR controller should be similar
+ */
+ break;
+ default:
+ return;
+ }
+
+ overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN |
+ V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN);
+
+ data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED |
+ V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ);
+
+ if (overrun) {
+ /* If there was a FIFO overrun, stop the device */
+ v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+ params.enable = false;
+ /* Mitigate race with cx23885_input_ir_stop() */
+ params.shutdown = atomic_read(&dev->ir_input_stopping);
+ v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ }
+
+ if (data_available)
+ cx23885_input_process_measurements(dev, overrun);
+
+ if (overrun) {
+ /* If there was a FIFO overrun, clear & restart the device */
+ params.enable = true;
+ /* Mitigate race with cx23885_input_ir_stop() */
+ params.shutdown = atomic_read(&dev->ir_input_stopping);
+ v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ }
+}
+
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
+{
+ struct v4l2_subdev_ir_parameters params;
+
+ if (dev->sd_ir == NULL)
+ return -ENODEV;
+
+ atomic_set(&dev->ir_input_stopping, 0);
+
+ v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /*
+ * The IR controller on this board only returns pulse widths.
+ * Any other mode setting will fail to set up the device.
+ */
+ params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+ params.enable = true;
+ params.interrupt_enable = true;
+ params.shutdown = false;
+
+ /* Setup for baseband compatible with both RC-5 and RC-6A */
+ params.modulation = false;
+ /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/
+ /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/
+ params.max_pulse_width = 3333333; /* ns */
+ /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+ /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+ params.noise_filter_min_width = 333333; /* ns */
+ /*
+ * This board has inverted receive sense:
+ * mark is received as low logic level;
+ * falling edges are detected as rising edges; etc.
+ */
+ params.invert_level = true;
+ break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_TEVII_S470:
+ /*
+ * The IR controller on this board only returns pulse widths.
+ * Any other mode setting will fail to set up the device.
+ */
+ params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+ params.enable = true;
+ params.interrupt_enable = true;
+ params.shutdown = false;
+
+ /* Setup for a standard NEC protocol */
+ params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
+ params.carrier_range_lower = 33000; /* Hz */
+ params.carrier_range_upper = 43000; /* Hz */
+ params.duty_cycle = 33; /* percent, 33 percent for NEC */
+
+ /*
+ * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
+ * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
+ */
+ params.max_pulse_width = 12378022; /* ns */
+
+ /*
+ * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
+ * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
+ */
+ params.noise_filter_min_width = 351648; /* ns */
+
+ params.modulation = false;
+ params.invert_level = true;
+ break;
+ }
+ v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ return 0;
+}
+
+static int cx23885_input_ir_open(struct rc_dev *rc)
+{
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
+
+ if (kernel_ir->cx == NULL)
+ return -ENODEV;
+
+ return cx23885_input_ir_start(kernel_ir->cx);
+}
+
+static void cx23885_input_ir_stop(struct cx23885_dev *dev)
+{
+ struct v4l2_subdev_ir_parameters params;
+
+ if (dev->sd_ir == NULL)
+ return;
+
+ /*
+ * Stop the sd_ir subdevice from generating notifications and
+ * scheduling work.
+ * It is shutdown this way in order to mitigate a race with
+ * cx23885_input_rx_work_handler() in the overrun case, which could
+ * re-enable the subdevice.
+ */
+ atomic_set(&dev->ir_input_stopping, 1);
+ v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+ while (params.shutdown == false) {
+ params.enable = false;
+ params.interrupt_enable = false;
+ params.shutdown = true;
+ v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+ }
+ flush_work_sync(&dev->cx25840_work);
+ flush_work_sync(&dev->ir_rx_work);
+ flush_work_sync(&dev->ir_tx_work);
+}
+
+static void cx23885_input_ir_close(struct rc_dev *rc)
+{
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
+
+ if (kernel_ir->cx != NULL)
+ cx23885_input_ir_stop(kernel_ir->cx);
+}
+
+int cx23885_input_init(struct cx23885_dev *dev)
+{
+ struct cx23885_kernel_ir *kernel_ir;
+ struct rc_dev *rc;
+ char *rc_map;
+ enum rc_driver_type driver_type;
+ unsigned long allowed_protos;
+
+ int ret;
+
+ /*
+ * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't
+ * encapsulated in a v4l2_subdev, then I'm not going to deal with it.
+ */
+ if (dev->sd_ir == NULL)
+ return -ENODEV;
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* Integrated CX2388[58] IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_TYPE_ALL;
+ /* The grey Hauppauge RC-5 remote */
+ rc_map = RC_MAP_HAUPPAUGE;
+ break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_TYPE_NEC;
+ /* The grey Terratec remote with orange buttons */
+ rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_TYPE_ALL;
+ /* A guess at the remote */
+ rc_map = RC_MAP_TEVII_NEC;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ /* cx23885 board instance kernel IR state */
+ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+ if (kernel_ir == NULL)
+ return -ENOMEM;
+
+ kernel_ir->cx = dev;
+ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+ cx23885_boards[dev->board].name);
+ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+ pci_name(dev->pci));
+
+ /* input device */
+ rc = rc_allocate_device();
+ if (!rc) {
+ ret = -ENOMEM;
+ goto err_out_free;
+ }
+
+ kernel_ir->rc = rc;
+ rc->input_name = kernel_ir->name;
+ rc->input_phys = kernel_ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
+ if (dev->pci->subsystem_vendor) {
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
+ } else {
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
+ }
+ rc->dev.parent = &dev->pci->dev;
+ rc->driver_type = driver_type;
+ rc->allowed_protos = allowed_protos;
+ rc->priv = kernel_ir;
+ rc->open = cx23885_input_ir_open;
+ rc->close = cx23885_input_ir_close;
+ rc->map_name = rc_map;
+ rc->driver_name = MODULE_NAME;
+
+ /* Go */
+ dev->kernel_ir = kernel_ir;
+ ret = rc_register_device(rc);
+ if (ret)
+ goto err_out_stop;
+
+ return 0;
+
+err_out_stop:
+ cx23885_input_ir_stop(dev);
+ dev->kernel_ir = NULL;
+ rc_free_device(rc);
+err_out_free:
+ kfree(kernel_ir->phys);
+ kfree(kernel_ir->name);
+ kfree(kernel_ir);
+ return ret;
+}
+
+void cx23885_input_fini(struct cx23885_dev *dev)
+{
+ /* Always stop the IR hardware from generating interrupts */
+ cx23885_input_ir_stop(dev);
+
+ if (dev->kernel_ir == NULL)
+ return;
+ rc_unregister_device(dev->kernel_ir->rc);
+ kfree(dev->kernel_ir->phys);
+ kfree(dev->kernel_ir->name);
+ kfree(dev->kernel_ir);
+ dev->kernel_ir = NULL;
+}
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h
index 75ef15d3f523..75ef15d3f523 100644
--- a/drivers/media/video/cx23885/cx23885-input.h
+++ b/drivers/media/pci/cx23885/cx23885-input.h
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index 44812ca78899..44812ca78899 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index 315be0ca5a04..315be0ca5a04 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c
index 7125247dd255..7125247dd255 100644
--- a/drivers/media/video/cx23885/cx23885-ir.c
+++ b/drivers/media/pci/cx23885/cx23885-ir.c
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h
index 0c9d8bda9e28..0c9d8bda9e28 100644
--- a/drivers/media/video/cx23885/cx23885-ir.h
+++ b/drivers/media/pci/cx23885/cx23885-ir.h
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h
index a99936e0cbc2..a99936e0cbc2 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/pci/cx23885/cx23885-reg.h
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index a1154f035bc1..a1154f035bc1 100644
--- a/drivers/media/video/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 22f8e7fbd665..22f8e7fbd665 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 5d560c747e09..5d560c747e09 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index c2bc39c58f82..c2bc39c58f82 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h
index d2de41caaf1d..d2de41caaf1d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.h
+++ b/drivers/media/pci/cx23885/cx23888-ir.h
diff --git a/drivers/media/video/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c
index 98a48f500684..98a48f500684 100644
--- a/drivers/media/video/cx23885/netup-eeprom.c
+++ b/drivers/media/pci/cx23885/netup-eeprom.c
diff --git a/drivers/media/video/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h
index 13926e18feba..13926e18feba 100644
--- a/drivers/media/video/cx23885/netup-eeprom.h
+++ b/drivers/media/pci/cx23885/netup-eeprom.h
diff --git a/drivers/media/video/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c
index f4893e69cd89..f4893e69cd89 100644
--- a/drivers/media/video/cx23885/netup-init.c
+++ b/drivers/media/pci/cx23885/netup-init.c
diff --git a/drivers/media/video/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h
index d26ae4b1590e..d26ae4b1590e 100644
--- a/drivers/media/video/cx23885/netup-init.h
+++ b/drivers/media/pci/cx23885/netup-init.h
diff --git a/drivers/media/video/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig
index 5f6b54213713..5f6b54213713 100644
--- a/drivers/media/video/cx25821/Kconfig
+++ b/drivers/media/pci/cx25821/Kconfig
diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile
new file mode 100644
index 000000000000..5bf3ea4c1556
--- /dev/null
+++ b/drivers/media/pci/cx25821/Makefile
@@ -0,0 +1,13 @@
+cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
+ cx25821-gpio.o cx25821-medusa-video.o \
+ cx25821-video.o cx25821-video-upstream.o \
+ cx25821-video-upstream-ch2.o \
+ cx25821-audio-upstream.o
+
+obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
+obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index 1858a45dd081..1858a45dd081 100644
--- a/drivers/media/video/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
index 8b2a99975c23..8b2a99975c23 100644
--- a/drivers/media/video/cx25821/cx25821-audio-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.h b/drivers/media/pci/cx25821/cx25821-audio-upstream.h
index af2ae7c5815a..af2ae7c5815a 100644
--- a/drivers/media/video/cx25821/cx25821-audio-upstream.h
+++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.h
diff --git a/drivers/media/video/cx25821/cx25821-audio.h b/drivers/media/pci/cx25821/cx25821-audio.h
index 1fc2d24f5110..1fc2d24f5110 100644
--- a/drivers/media/video/cx25821/cx25821-audio.h
+++ b/drivers/media/pci/cx25821/cx25821-audio.h
diff --git a/drivers/media/video/cx25821/cx25821-biffuncs.h b/drivers/media/pci/cx25821/cx25821-biffuncs.h
index 9326a7c729ec..9326a7c729ec 100644
--- a/drivers/media/video/cx25821/cx25821-biffuncs.h
+++ b/drivers/media/pci/cx25821/cx25821-biffuncs.h
diff --git a/drivers/media/video/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c
index 99988c988095..99988c988095 100644
--- a/drivers/media/video/cx25821/cx25821-cards.c
+++ b/drivers/media/pci/cx25821/cx25821-cards.c
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index f11f6f07e915..f11f6f07e915 100644
--- a/drivers/media/video/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
diff --git a/drivers/media/video/cx25821/cx25821-gpio.c b/drivers/media/pci/cx25821/cx25821-gpio.c
index 29e43b03c85e..29e43b03c85e 100644
--- a/drivers/media/video/cx25821/cx25821-gpio.c
+++ b/drivers/media/pci/cx25821/cx25821-gpio.c
diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c
index 9844549764c9..9844549764c9 100644
--- a/drivers/media/video/cx25821/cx25821-i2c.c
+++ b/drivers/media/pci/cx25821/cx25821-i2c.c
diff --git a/drivers/media/video/cx25821/cx25821-medusa-defines.h b/drivers/media/pci/cx25821/cx25821-medusa-defines.h
index 7a9e6470ba22..7a9e6470ba22 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-defines.h
+++ b/drivers/media/pci/cx25821/cx25821-medusa-defines.h
diff --git a/drivers/media/video/cx25821/cx25821-medusa-reg.h b/drivers/media/pci/cx25821/cx25821-medusa-reg.h
index c98ac946b277..c98ac946b277 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-reg.h
+++ b/drivers/media/pci/cx25821/cx25821-medusa-reg.h
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c
index 6a92e5c70c2a..6a92e5c70c2a 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-video.c
+++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.h b/drivers/media/pci/cx25821/cx25821-medusa-video.h
index 6175e0961855..6175e0961855 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-video.h
+++ b/drivers/media/pci/cx25821/cx25821-medusa-video.h
diff --git a/drivers/media/video/cx25821/cx25821-reg.h b/drivers/media/pci/cx25821/cx25821-reg.h
index a3fc25a4dc0b..a3fc25a4dc0b 100644
--- a/drivers/media/video/cx25821/cx25821-reg.h
+++ b/drivers/media/pci/cx25821/cx25821-reg.h
diff --git a/drivers/media/video/cx25821/cx25821-sram.h b/drivers/media/pci/cx25821/cx25821-sram.h
index 5f05d153bc4d..5f05d153bc4d 100644
--- a/drivers/media/video/cx25821/cx25821-sram.h
+++ b/drivers/media/pci/cx25821/cx25821-sram.h
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
index c8c94fbf5d8d..c8c94fbf5d8d 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
index d42dab59b663..d42dab59b663 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
index 52c13e0b6492..52c13e0b6492 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.h b/drivers/media/pci/cx25821/cx25821-video-upstream.h
index 268ec8aa6a61..268ec8aa6a61 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream.h
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.h
diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index b38d4379cc36..b38d4379cc36 100644
--- a/drivers/media/video/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
diff --git a/drivers/media/video/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h
index 9652a5e35ba2..9652a5e35ba2 100644
--- a/drivers/media/video/cx25821/cx25821-video.h
+++ b/drivers/media/pci/cx25821/cx25821-video.h
diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h
index 8a9c0c869412..8a9c0c869412 100644
--- a/drivers/media/video/cx25821/cx25821.h
+++ b/drivers/media/pci/cx25821/cx25821.h
diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig
new file mode 100644
index 000000000000..d27fccbf03c4
--- /dev/null
+++ b/drivers/media/pci/cx88/Kconfig
@@ -0,0 +1,86 @@
+config VIDEO_CX88
+ tristate "Conexant 2388x (bt878 successor) support"
+ depends on VIDEO_DEV && PCI && I2C && RC_CORE
+ select I2C_ALGOBIT
+ select VIDEO_BTCX
+ select VIDEOBUF_DMA_SG
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for Conexant 2388x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx8800
+
+config VIDEO_CX88_ALSA
+ tristate "Conexant 2388x DMA audio support"
+ depends on VIDEO_CX88 && SND
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio on
+ Conexant 2388x based TV cards using ALSA.
+
+ It only works with boards with function 01 enabled.
+ To check if your board supports, use lspci -n.
+ If supported, you should see 14f1:8801 or 14f1:8811
+ PCI device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-alsa.
+
+config VIDEO_CX88_BLACKBIRD
+ tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
+ depends on VIDEO_CX88
+ select VIDEO_CX2341X
+ ---help---
+ This adds support for MPEG encoder cards based on the
+ Blackbird reference design, using the Conexant 2388x
+ and 23416 chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-blackbird.
+
+config VIDEO_CX88_DVB
+ tristate "DVB/ATSC Support for cx2388x based TV cards"
+ depends on VIDEO_CX88 && DVB_CORE
+ select VIDEOBUF_DVB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_OR51132 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This adds support for DVB/ATSC cards based on the
+ Conexant 2388x chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-dvb.
+
+config VIDEO_CX88_VP3054
+ tristate "VP-3054 Secondary I2C Bus Support"
+ default m
+ depends on VIDEO_CX88_DVB && DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+ 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/pci/cx88/Makefile b/drivers/media/pci/cx88/Makefile
new file mode 100644
index 000000000000..d3679c3ee248
--- /dev/null
+++ b/drivers/media/pci/cx88/Makefile
@@ -0,0 +1,16 @@
+cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
+ cx88-dsp.o cx88-input.o
+cx8800-objs := cx88-video.o cx88-vbi.o
+cx8802-objs := cx88-mpeg.o
+
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
+obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o
+obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
+obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
new file mode 100644
index 000000000000..3aa6856ead3b
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -0,0 +1,975 @@
+/*
+ *
+ * Support for audio capture
+ * PCI function #1 of the cx2388x.
+ *
+ * (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
+ * (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ * Based on dummy.c by Jaroslav Kysela <perex@perex.cz>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <media/wm8775.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
+
+/****************************************************************************
+ Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+struct cx88_audio_buffer {
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct videobuf_dmabuf dma;
+};
+
+struct cx88_audio_dev {
+ struct cx88_core *core;
+ struct cx88_dmaqueue q;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+
+ /* audio controls */
+ int irq;
+
+ struct snd_card *card;
+
+ spinlock_t reg_lock;
+ atomic_t count;
+
+ unsigned int dma_size;
+ unsigned int period_size;
+ unsigned int num_periods;
+
+ struct videobuf_dmabuf *dma_risc;
+
+ struct cx88_audio_buffer *buf;
+
+ struct snd_pcm_substream *substream;
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+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 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.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
+
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Ricardo Cerqueira");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
+ "{{Conexant,23882},"
+ "{{Conexant,23883}");
+static unsigned int debug;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+/****************************************************************************
+ Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
+{
+ struct cx88_audio_buffer *buf = chip->buf;
+ struct cx88_core *core=chip->core;
+ const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+
+ /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+ /* setup fifo + format - out channel */
+ cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
+
+ /* sets bpl size */
+ cx_write(MO_AUDD_LNGTH, buf->bpl);
+
+ /* reset counter */
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ atomic_set(&chip->count, 0);
+
+ dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+ "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
+ chip->num_periods, buf->bpl * chip->num_periods);
+
+ /* Enables corresponding bits at AUD_INT_STAT */
+ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+ /* Clean any pending interrupt bits already set */
+ cx_write(MO_AUD_INTSTAT, ~0);
+
+ /* enable audio irqs */
+ cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
+
+ /* start dma */
+ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+ if (debug)
+ cx88_sram_channel_dump(chip->core, audio_ch);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
+{
+ struct cx88_core *core=chip->core;
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* stop dma */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+ /* disable irqs */
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+ cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+ if (debug)
+ cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+ return 0;
+}
+
+#define MAX_IRQ_LOOP 50
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static const char *cx88_aud_irqs[32] = {
+ "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
+ 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 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx8801_aud_irq(snd_cx88_card_t *chip)
+{
+ struct cx88_core *core = chip->core;
+ u32 status, mask;
+
+ status = cx_read(MO_AUD_INTSTAT);
+ mask = cx_read(MO_AUD_INTMSK);
+ if (0 == (status & mask))
+ return;
+ cx_write(MO_AUD_INTSTAT, status);
+ if (debug > 1 || (status & mask & ~0xff))
+ cx88_print_irqbits(core->name, "irq aud",
+ cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
+ status, mask);
+ /* risc op code error */
+ if (status & AUD_INT_OPC_ERR) {
+ printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+ cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
+ }
+ if (status & AUD_INT_DN_SYNC) {
+ dprintk(1, "Downstream sync error\n");
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ return;
+ }
+ /* risc1 downstream */
+ if (status & AUD_INT_DN_RISCI1) {
+ atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
+ snd_pcm_period_elapsed(chip->substream);
+ }
+ /* FIXME: Any other status should deserve a special handling? */
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx8801_irq(int irq, void *dev_id)
+{
+ snd_cx88_card_t *chip = dev_id;
+ struct cx88_core *core = chip->core;
+ u32 status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_AUDINT);
+ if (0 == status)
+ goto out;
+ dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
+ loop, MAX_IRQ_LOOP, status);
+ handled = 1;
+ cx_write(MO_PCI_INTSTAT, status);
+
+ if (status & core->pci_irqmask)
+ cx88_core_irq(core, status);
+ if (status & PCI_INT_AUDINT)
+ cx8801_aud_irq(chip);
+ }
+
+ if (MAX_IRQ_LOOP == loop) {
+ printk(KERN_ERR
+ "%s/1: IRQ loop detected, disabling interrupts\n",
+ core->name);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+ }
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+
+static int dsp_buffer_free(snd_cx88_card_t *chip)
+{
+ BUG_ON(!chip->dma_size);
+
+ dprintk(2,"Freeing buffer\n");
+ videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
+ videobuf_dma_free(chip->dma_risc);
+ btcx_riscmem_free(chip->pci,&chip->buf->risc);
+ kfree(chip->buf);
+
+ chip->dma_risc = NULL;
+ chip->dma_size = 0;
+
+ return 0;
+}
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE 4096
+static const struct snd_pcm_hardware snd_cx88_digital_hw = {
+ .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,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* Analog audio output will be full of clicks and pops if there
+ are not exactly four lines in the SRAM FIFO buffer. */
+ .period_bytes_min = DEFAULT_FIFO_SIZE/4,
+ .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ if (!chip) {
+ printk(KERN_ERR "BUG: cx88 can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
+ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+
+ runtime->hw = snd_cx88_digital_hw;
+
+ if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
+ unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
+ bpl &= ~7; /* must be multiple of 8 */
+ runtime->hw.period_bytes_min = bpl;
+ runtime->hw.period_bytes_max = bpl;
+ }
+
+ return 0;
+_error:
+ dprintk(1,"Error opening PCM!\n");
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
+ struct snd_pcm_hw_params * hw_params)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct videobuf_dmabuf *dma;
+
+ struct cx88_audio_buffer *buf;
+ int ret;
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+ chip->period_size = params_period_bytes(hw_params);
+ chip->num_periods = params_periods(hw_params);
+ chip->dma_size = chip->period_size * params_periods(hw_params);
+
+ BUG_ON(!chip->dma_size);
+ BUG_ON(chip->num_periods & (chip->num_periods-1));
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (NULL == buf)
+ return -ENOMEM;
+
+ buf->bpl = chip->period_size;
+
+ dma = &buf->dma;
+ videobuf_dma_init(dma);
+ ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+ (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
+ if (ret < 0)
+ goto error;
+
+ ret = videobuf_dma_map(&chip->pci->dev, dma);
+ if (ret < 0)
+ goto error;
+
+ ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ chip->period_size, chip->num_periods, 1);
+ if (ret < 0)
+ goto error;
+
+ /* Loop back to start of program */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+ chip->buf = buf;
+ chip->dma_risc = dma;
+
+ substream->runtime->dma_area = chip->dma_risc->vaddr;
+ substream->runtime->dma_bytes = chip->dma_size;
+ substream->runtime->dma_addr = 0;
+ return 0;
+
+error:
+ kfree(buf);
+ return ret;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
+{
+
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ /* Local interrupts are already disabled by ALSA */
+ spin_lock(&chip->reg_lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err=_cx88_start_audio_dma(chip);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err=_cx88_stop_audio_dma(chip);
+ break;
+ default:
+ err=-EINVAL;
+ break;
+ }
+
+ spin_unlock(&chip->reg_lock);
+
+ return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u16 count;
+
+ count = atomic_read(&chip->count);
+
+// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
+// count, new, count & (runtime->periods-1),
+// runtime->period_size * (count & (runtime->periods-1)));
+ return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ void *pageptr = substream->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_cx88_pcm_ops = {
+ .open = snd_cx88_pcm_open,
+ .close = snd_cx88_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx88_hw_params,
+ .hw_free = snd_cx88_hw_free,
+ .prepare = snd_cx88_prepare,
+ .trigger = snd_cx88_card_trigger,
+ .pointer = snd_cx88_pointer,
+ .page = snd_cx88_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
+{
+ int err;
+ struct snd_pcm *pcm;
+
+ err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, name);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+
+ return 0;
+}
+
+/****************************************************************************
+ CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 0;
+ info->value.integer.max = 0x3f;
+
+ return 0;
+}
+
+static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core=chip->core;
+ int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
+ bal = cx_read(AUD_BAL_CTL);
+
+ value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
+ vol -= (bal & 0x3f);
+ value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
+
+ return 0;
+}
+
+static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core = chip->core;
+ int left = value->value.integer.value[0];
+ int right = value->value.integer.value[1];
+ int v, b;
+
+ /* Pass volume & balance onto any WM8775 */
+ if (left >= right) {
+ v = left << 10;
+ b = left ? (0x8000 * right) / left : 0x8000;
+ } else {
+ v = right << 10;
+ b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
+ }
+ wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);
+ wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core=chip->core;
+ int left, right, v, b;
+ int changed = 0;
+ u32 old;
+
+ if (core->board.audio_chip == V4L2_IDENT_WM8775)
+ snd_cx88_wm8775_volume_put(kcontrol, value);
+
+ left = value->value.integer.value[0] & 0x3f;
+ right = value->value.integer.value[1] & 0x3f;
+ b = right - left;
+ if (b < 0) {
+ v = 0x3f - left;
+ b = (-b) | 0x40;
+ } else {
+ v = 0x3f - right;
+ }
+ /* Do we really know this will always be called with IRQs on? */
+ spin_lock_irq(&chip->reg_lock);
+ old = cx_read(AUD_VOL_CTL);
+ if (v != (old & 0x3f)) {
+ cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
+ changed = 1;
+ }
+ if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
+ cx_write(AUD_BAL_CTL, b);
+ changed = 1;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+
+ return changed;
+}
+
+static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+
+static const struct snd_kcontrol_new snd_cx88_volume = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "Analog-TV Volume",
+ .info = snd_cx88_volume_info,
+ .get = snd_cx88_volume_get,
+ .put = snd_cx88_volume_put,
+ .tlv.p = snd_cx88_db_scale,
+};
+
+static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core = chip->core;
+ u32 bit = kcontrol->private_value;
+
+ value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
+ return 0;
+}
+
+static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core = chip->core;
+ u32 bit = kcontrol->private_value;
+ int ret = 0;
+ u32 vol;
+
+ spin_lock_irq(&chip->reg_lock);
+ vol = cx_read(AUD_VOL_CTL);
+ if (value->value.integer.value[0] != !(vol & bit)) {
+ vol ^= bit;
+ cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
+ /* Pass mute onto any WM8775 */
+ if ((core->board.audio_chip == V4L2_IDENT_WM8775) &&
+ ((1<<6) == bit))
+ wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));
+ ret = 1;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+ return ret;
+}
+
+static const struct snd_kcontrol_new snd_cx88_dac_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Audio-Out Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+ .private_value = (1<<8),
+};
+
+static const struct snd_kcontrol_new snd_cx88_source_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog-TV Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+ .private_value = (1<<6),
+};
+
+static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core = chip->core;
+ s32 val;
+
+ val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);
+ value->value.integer.value[0] = val ? 1 : 0;
+ return 0;
+}
+
+static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ struct cx88_core *core = chip->core;
+ struct v4l2_control client_ctl;
+
+ memset(&client_ctl, 0, sizeof(client_ctl));
+ client_ctl.value = 0 != value->value.integer.value[0];
+ client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+ call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new snd_cx88_alc_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line-In ALC Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_alc_get,
+ .put = snd_cx88_alc_put,
+};
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+static const struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
+ {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Chip-specific destructor
+ */
+
+static int snd_cx88_free(snd_cx88_card_t *chip)
+{
+
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
+
+ cx88_core_put(chip->core,chip->pci);
+
+ pci_disable_device(chip->pci);
+ return 0;
+}
+
+/*
+ * Component Destructor
+ */
+static void snd_cx88_dev_free(struct snd_card * card)
+{
+ snd_cx88_card_t *chip = card->private_data;
+
+ snd_cx88_free(chip);
+}
+
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+static int devno;
+static int __devinit snd_cx88_create(struct snd_card *card,
+ struct pci_dev *pci,
+ snd_cx88_card_t **rchip,
+ struct cx88_core **core_ptr)
+{
+ snd_cx88_card_t *chip;
+ struct cx88_core *core;
+ int err;
+ unsigned char pci_lat;
+
+ *rchip = NULL;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ pci_set_master(pci);
+
+ chip = card->private_data;
+
+ core = cx88_core_get(pci);
+ if (NULL == core) {
+ err = -EINVAL;
+ return err;
+ }
+
+ if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
+ dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+ err = -EIO;
+ cx88_core_put(core, pci);
+ return err;
+ }
+
+
+ /* pci init */
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+ spin_lock_init(&chip->reg_lock);
+
+ chip->core = core;
+
+ /* get irq */
+ err = request_irq(chip->pci->irq, cx8801_irq,
+ IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip);
+ if (err < 0) {
+ dprintk(0, "%s: can't get IRQ %d\n",
+ chip->core->name, chip->pci->irq);
+ return err;
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
+
+ dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%llx\n", core->name, devno,
+ pci_name(pci), pci->revision, pci->irq,
+ pci_lat, (unsigned long long)pci_resource_start(pci,0));
+
+ chip->irq = pci->irq;
+ synchronize_irq(chip->irq);
+
+ snd_card_set_dev(card, &pci->dev);
+
+ *rchip = chip;
+ *core_ptr = core;
+
+ return 0;
+}
+
+static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ struct snd_card *card;
+ snd_cx88_card_t *chip;
+ struct cx88_core *core = NULL;
+ int err;
+
+ if (devno >= SNDRV_CARDS)
+ return (-ENODEV);
+
+ if (!enable[devno]) {
+ ++devno;
+ return (-ENOENT);
+ }
+
+ err = snd_card_create(index[devno], id[devno], THIS_MODULE,
+ sizeof(snd_cx88_card_t), &card);
+ if (err < 0)
+ return err;
+
+ card->private_free = snd_cx88_dev_free;
+
+ err = snd_cx88_create(card, pci, &chip, &core);
+ if (err < 0)
+ goto error;
+
+ err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+ if (err < 0)
+ goto error;
+
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
+ if (err < 0)
+ goto error;
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
+ if (err < 0)
+ goto error;
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
+ if (err < 0)
+ goto error;
+
+ /* If there's a wm8775 then add a Line-In ALC switch */
+ if (core->board.audio_chip == V4L2_IDENT_WM8775)
+ snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));
+
+ strcpy (card->driver, "CX88x");
+ sprintf(card->shortname, "Conexant CX%x", pci->device);
+ sprintf(card->longname, "%s at %#llx",
+ card->shortname,(unsigned long long)pci_resource_start(pci, 0));
+ strcpy (card->mixername, "CX88");
+
+ dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
+ card->driver,devno);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+ pci_set_drvdata(pci,card);
+
+ devno++;
+ return 0;
+
+error:
+ snd_card_free(card);
+ return err;
+}
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+{
+ struct cx88_audio_dev *card = pci_get_drvdata(pci);
+
+ snd_card_free((void *)card);
+
+ pci_set_drvdata(pci, NULL);
+
+ devno--;
+}
+
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+ .name = "cx88_audio",
+ .id_table = cx88_audio_pci_tbl,
+ .probe = cx88_audio_initdev,
+ .remove = __devexit_p(cx88_audio_finidev),
+};
+
+/****************************************************************************
+ LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int __init cx88_audio_init(void)
+{
+ printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
+ CX88_VERSION);
+ return pci_register_driver(&cx88_audio_pci_driver);
+}
+
+/*
+ * module remove
+ */
+static void __exit cx88_audio_fini(void)
+{
+ pci_unregister_driver(&cx88_audio_pci_driver);
+}
+
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 843ffd9e533b..843ffd9e533b 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 4e9d4f722960..4e9d4f722960 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
new file mode 100644
index 000000000000..c97b174be3ab
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -0,0 +1,1131 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * driver core
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
+ * 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+
+#include "cx88.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int nicam;
+module_param(nicam,int,0644);
+MODULE_PARM_DESC(nicam,"tv audio is nicam");
+
+static unsigned int nocomb;
+module_param(nocomb,int,0644);
+MODULE_PARM_DESC(nocomb,"disable comb filter");
+
+#define dprintk(level,fmt, arg...) if (core_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+
+static unsigned int cx88_devcount;
+static LIST_HEAD(cx88_devlist);
+static DEFINE_MUTEX(devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
+ generated _after_ lpi lines are transferred. */
+static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
+ unsigned int offset, u32 sync_line,
+ unsigned int bpl, unsigned int padding,
+ unsigned int lines, unsigned int lpi)
+{
+ struct scatterlist *sg;
+ unsigned int line,todo,sol;
+
+ /* sync instruction */
+ if (sync_line != NO_SYNC_LINE)
+ *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+ /* scan lines */
+ sg = sglist;
+ for (line = 0; line < lines; line++) {
+ while (offset && offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ sg++;
+ }
+ if (lpi && line>0 && !(line % lpi))
+ sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+ else
+ sol = RISC_SOL;
+ 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(sg_dma_address(sg)+offset);
+ offset+=bpl;
+ } else {
+ /* scanline needs to be split */
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|
+ (sg_dma_len(sg)-offset));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(RISC_WRITE|
+ sg_dma_len(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ todo -= sg_dma_len(sg);
+ sg++;
+ }
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ offset += todo;
+ }
+ offset += padding;
+ }
+
+ return rp;
+}
+
+int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist,
+ unsigned int top_offset, unsigned int bottom_offset,
+ unsigned int bpl, unsigned int padding, unsigned int lines)
+{
+ u32 instructions,fields;
+ __le32 *rp;
+ int rc;
+
+ fields = 0;
+ if (UNSET != top_offset)
+ fields++;
+ if (UNSET != bottom_offset)
+ fields++;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Padding
+ can cause next bpl to start close to a page border. First DMA
+ region may be smaller than PAGE_SIZE */
+ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions += 2;
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ if (UNSET != top_offset)
+ rp = cx88_risc_field(rp, sglist, top_offset, 0,
+ bpl, padding, lines, 0);
+ if (UNSET != bottom_offset)
+ rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
+ bpl, padding, lines, 0);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int bpl,
+ unsigned int lines, unsigned int lpi)
+{
+ u32 instructions;
+ __le32 *rp;
+ int rc;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Here
+ there is no padding and no sync. First DMA region may be smaller
+ than PAGE_SIZE */
+ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
+ instructions += 1;
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value)
+{
+ __le32 *rp;
+ int rc;
+
+ if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
+ *(rp++) = cpu_to_le32(reg);
+ *(rp++) = cpu_to_le32(value);
+ *(rp++) = cpu_to_le32(mask);
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = cpu_to_le32(risc->dma);
+ return 0;
+}
+
+void
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
+{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
+ BUG_ON(in_interrupt());
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
+ videobuf_dma_free(dma);
+ btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* ------------------------------------------------------------------ */
+/* our SRAM memory layout */
+
+/* we are going to put all thr risc programs into host memory, so we
+ * can use the whole SDRAM for the DMA fifos. To simplify things, we
+ * use a static memory layout. That surely will waste memory in case
+ * we don't use all DMA channels at the same time (which will be the
+ * case most of the time). But that still gives us enough FIFO space
+ * to be able to deal with insane long pci latencies ...
+ *
+ * FIFO space allocations:
+ * channel 21 (y video) - 10.0k
+ * channel 22 (u video) - 2.0k
+ * channel 23 (v video) - 2.0k
+ * channel 24 (vbi) - 4.0k
+ * channels 25+26 (audio) - 4.0k
+ * channel 28 (mpeg) - 4.0k
+ * channel 27 (audio rds)- 3.0k
+ * TOTAL = 29.0k
+ *
+ * Every channel has 160 bytes control data (64 bytes instruction
+ * queue and 6 CDT entries), which is close to 2k total.
+ *
+ * Address layout:
+ * 0x0000 - 0x03ff CMDs / reserved
+ * 0x0400 - 0x0bff instruction queues + CDs
+ * 0x0c00 - FIFOs
+ */
+
+const struct sram_channel cx88_sram_channels[] = {
+ [SRAM_CH21] = {
+ .name = "video y / packed",
+ .cmds_start = 0x180040,
+ .ctrl_start = 0x180400,
+ .cdt = 0x180400 + 64,
+ .fifo_start = 0x180c00,
+ .fifo_size = 0x002800,
+ .ptr1_reg = MO_DMA21_PTR1,
+ .ptr2_reg = MO_DMA21_PTR2,
+ .cnt1_reg = MO_DMA21_CNT1,
+ .cnt2_reg = MO_DMA21_CNT2,
+ },
+ [SRAM_CH22] = {
+ .name = "video u",
+ .cmds_start = 0x180080,
+ .ctrl_start = 0x1804a0,
+ .cdt = 0x1804a0 + 64,
+ .fifo_start = 0x183400,
+ .fifo_size = 0x000800,
+ .ptr1_reg = MO_DMA22_PTR1,
+ .ptr2_reg = MO_DMA22_PTR2,
+ .cnt1_reg = MO_DMA22_CNT1,
+ .cnt2_reg = MO_DMA22_CNT2,
+ },
+ [SRAM_CH23] = {
+ .name = "video v",
+ .cmds_start = 0x1800c0,
+ .ctrl_start = 0x180540,
+ .cdt = 0x180540 + 64,
+ .fifo_start = 0x183c00,
+ .fifo_size = 0x000800,
+ .ptr1_reg = MO_DMA23_PTR1,
+ .ptr2_reg = MO_DMA23_PTR2,
+ .cnt1_reg = MO_DMA23_CNT1,
+ .cnt2_reg = MO_DMA23_CNT2,
+ },
+ [SRAM_CH24] = {
+ .name = "vbi",
+ .cmds_start = 0x180100,
+ .ctrl_start = 0x1805e0,
+ .cdt = 0x1805e0 + 64,
+ .fifo_start = 0x184400,
+ .fifo_size = 0x001000,
+ .ptr1_reg = MO_DMA24_PTR1,
+ .ptr2_reg = MO_DMA24_PTR2,
+ .cnt1_reg = MO_DMA24_CNT1,
+ .cnt2_reg = MO_DMA24_CNT2,
+ },
+ [SRAM_CH25] = {
+ .name = "audio from",
+ .cmds_start = 0x180140,
+ .ctrl_start = 0x180680,
+ .cdt = 0x180680 + 64,
+ .fifo_start = 0x185400,
+ .fifo_size = 0x001000,
+ .ptr1_reg = MO_DMA25_PTR1,
+ .ptr2_reg = MO_DMA25_PTR2,
+ .cnt1_reg = MO_DMA25_CNT1,
+ .cnt2_reg = MO_DMA25_CNT2,
+ },
+ [SRAM_CH26] = {
+ .name = "audio to",
+ .cmds_start = 0x180180,
+ .ctrl_start = 0x180720,
+ .cdt = 0x180680 + 64, /* same as audio IN */
+ .fifo_start = 0x185400, /* same as audio IN */
+ .fifo_size = 0x001000, /* same as audio IN */
+ .ptr1_reg = MO_DMA26_PTR1,
+ .ptr2_reg = MO_DMA26_PTR2,
+ .cnt1_reg = MO_DMA26_CNT1,
+ .cnt2_reg = MO_DMA26_CNT2,
+ },
+ [SRAM_CH28] = {
+ .name = "mpeg",
+ .cmds_start = 0x180200,
+ .ctrl_start = 0x1807C0,
+ .cdt = 0x1807C0 + 64,
+ .fifo_start = 0x186400,
+ .fifo_size = 0x001000,
+ .ptr1_reg = MO_DMA28_PTR1,
+ .ptr2_reg = MO_DMA28_PTR2,
+ .cnt1_reg = MO_DMA28_CNT1,
+ .cnt2_reg = MO_DMA28_CNT2,
+ },
+ [SRAM_CH27] = {
+ .name = "audio rds",
+ .cmds_start = 0x1801C0,
+ .ctrl_start = 0x180860,
+ .cdt = 0x180860 + 64,
+ .fifo_start = 0x187400,
+ .fifo_size = 0x000C00,
+ .ptr1_reg = MO_DMA27_PTR1,
+ .ptr2_reg = MO_DMA27_PTR2,
+ .cnt1_reg = MO_DMA27_CNT1,
+ .cnt2_reg = MO_DMA27_CNT2,
+ },
+};
+
+int cx88_sram_channel_setup(struct cx88_core *core,
+ const struct sram_channel *ch,
+ unsigned int bpl, u32 risc)
+{
+ unsigned int i,lines;
+ u32 cdt;
+
+ bpl = (bpl + 7) & ~7; /* alignment */
+ cdt = ch->cdt;
+ lines = ch->fifo_size / bpl;
+ if (lines > 6)
+ lines = 6;
+ BUG_ON(lines < 2);
+
+ /* write CDT */
+ for (i = 0; i < lines; i++)
+ cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+
+ /* write CMDS */
+ cx_write(ch->cmds_start + 0, risc);
+ cx_write(ch->cmds_start + 4, cdt);
+ cx_write(ch->cmds_start + 8, (lines*16) >> 3);
+ cx_write(ch->cmds_start + 12, ch->ctrl_start);
+ cx_write(ch->cmds_start + 16, 64 >> 2);
+ for (i = 20; i < 64; i += 4)
+ cx_write(ch->cmds_start + i, 0);
+
+ /* fill registers */
+ cx_write(ch->ptr1_reg, ch->fifo_start);
+ cx_write(ch->ptr2_reg, cdt);
+ cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+ cx_write(ch->cnt2_reg, (lines*16) >> 3);
+
+ dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* debug helper code */
+
+static int cx88_risc_decode(u32 risc)
+{
+ static const char * const instr[16] = {
+ [ RISC_SYNC >> 28 ] = "sync",
+ [ RISC_WRITE >> 28 ] = "write",
+ [ RISC_WRITEC >> 28 ] = "writec",
+ [ RISC_READ >> 28 ] = "read",
+ [ RISC_READC >> 28 ] = "readc",
+ [ RISC_JUMP >> 28 ] = "jump",
+ [ RISC_SKIP >> 28 ] = "skip",
+ [ RISC_WRITERM >> 28 ] = "writerm",
+ [ RISC_WRITECM >> 28 ] = "writecm",
+ [ RISC_WRITECR >> 28 ] = "writecr",
+ };
+ static int const incr[16] = {
+ [ RISC_WRITE >> 28 ] = 2,
+ [ RISC_JUMP >> 28 ] = 2,
+ [ RISC_WRITERM >> 28 ] = 3,
+ [ RISC_WRITECM >> 28 ] = 3,
+ [ RISC_WRITECR >> 28 ] = 4,
+ };
+ static const char * const bits[] = {
+ "12", "13", "14", "resync",
+ "cnt0", "cnt1", "18", "19",
+ "20", "21", "22", "23",
+ "irq1", "irq2", "eol", "sol",
+ };
+ int i;
+
+ printk("0x%08x [ %s", risc,
+ instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+ for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+ if (risc & (1 << (i + 12)))
+ printk(" %s",bits[i]);
+ printk(" count=%d ]\n", risc & 0xfff);
+ return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+
+void cx88_sram_channel_dump(struct cx88_core *core,
+ const struct sram_channel *ch)
+{
+ static const char * const name[] = {
+ "initial risc",
+ "cdt base",
+ "cdt size",
+ "iq base",
+ "iq size",
+ "risc pc",
+ "iq wr ptr",
+ "iq rd ptr",
+ "cdt current",
+ "pci target",
+ "line / byte",
+ };
+ u32 risc;
+ unsigned int i,j,n;
+
+ printk("%s: %s - dma channel status dump\n",
+ core->name,ch->name);
+ for (i = 0; i < ARRAY_SIZE(name); i++)
+ printk("%s: cmds: %-12s: 0x%08x\n",
+ core->name,name[i],
+ cx_read(ch->cmds_start + 4*i));
+ for (n = 1, i = 0; i < 4; i++) {
+ risc = cx_read(ch->cmds_start + 4 * (i+11));
+ printk("%s: risc%d: ", core->name, i);
+ if (--n)
+ printk("0x%08x [ arg #%d ]\n", risc, n);
+ else
+ n = cx88_risc_decode(risc);
+ }
+ for (i = 0; i < 16; i += n) {
+ risc = cx_read(ch->ctrl_start + 4 * i);
+ printk("%s: iq %x: ", core->name, i);
+ n = cx88_risc_decode(risc);
+ for (j = 1; j < n; j++) {
+ risc = cx_read(ch->ctrl_start + 4 * (i+j));
+ printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
+ core->name, i+j, risc, j);
+ }
+ }
+
+ printk("%s: fifo: 0x%08x -> 0x%x\n",
+ core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+ printk("%s: ctrl: 0x%08x -> 0x%x\n",
+ core->name, ch->ctrl_start, ch->ctrl_start+6*16);
+ printk("%s: ptr1_reg: 0x%08x\n",
+ core->name,cx_read(ch->ptr1_reg));
+ printk("%s: ptr2_reg: 0x%08x\n",
+ core->name,cx_read(ch->ptr2_reg));
+ printk("%s: cnt1_reg: 0x%08x\n",
+ core->name,cx_read(ch->cnt1_reg));
+ printk("%s: cnt2_reg: 0x%08x\n",
+ core->name,cx_read(ch->cnt2_reg));
+}
+
+static const char *cx88_pci_irqs[32] = {
+ "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
+ "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
+ "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
+ "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
+};
+
+void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
+ int len, u32 bits, u32 mask)
+{
+ unsigned int i;
+
+ printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
+ for (i = 0; i < len; i++) {
+ if (!(bits & (1 << i)))
+ continue;
+ if (strings[i])
+ printk(" %s", strings[i]);
+ else
+ printk(" %d", i);
+ if (!(mask & (1 << i)))
+ continue;
+ printk("*");
+ }
+ printk("\n");
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx88_core_irq(struct cx88_core *core, u32 status)
+{
+ int handled = 0;
+
+ if (status & PCI_INT_IR_SMPINT) {
+ cx88_ir_irq(core);
+ handled++;
+ }
+ if (!handled)
+ cx88_print_irqbits(core->name, "irq pci",
+ cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
+ status, core->pci_irqmask);
+ return handled;
+}
+
+void cx88_wakeup(struct cx88_core *core,
+ struct cx88_dmaqueue *q, u32 count)
+{
+ struct cx88_buffer *buf;
+ int bc;
+
+ for (bc = 0;; bc++) {
+ if (list_empty(&q->active))
+ break;
+ buf = list_entry(q->active.next,
+ struct cx88_buffer, vb.queue);
+ /* count comes from the hw and is is 16bit wide --
+ * this trick handles wrap-arounds correctly for
+ * up to 32767 buffers in flight... */
+ if ((s16) (count - buf->count) < 0)
+ break;
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+ count, buf->count);
+ buf->vb.state = VIDEOBUF_DONE;
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ }
+ if (list_empty(&q->active)) {
+ del_timer(&q->timeout);
+ } else {
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ }
+ if (bc != 1)
+ dprintk(2, "%s: %d buffers handled (should be 1)\n",
+ __func__, bc);
+}
+
+void cx88_shutdown(struct cx88_core *core)
+{
+ /* disable RISC controller + IRQs */
+ cx_write(MO_DEV_CNTRL2, 0);
+
+ /* stop dma transfers */
+ cx_write(MO_VID_DMACNTRL, 0x0);
+ cx_write(MO_AUD_DMACNTRL, 0x0);
+ cx_write(MO_TS_DMACNTRL, 0x0);
+ cx_write(MO_VIP_DMACNTRL, 0x0);
+ cx_write(MO_GPHST_DMACNTRL, 0x0);
+
+ /* stop interrupts */
+ cx_write(MO_PCI_INTMSK, 0x0);
+ cx_write(MO_VID_INTMSK, 0x0);
+ cx_write(MO_AUD_INTMSK, 0x0);
+ cx_write(MO_TS_INTMSK, 0x0);
+ cx_write(MO_VIP_INTMSK, 0x0);
+ cx_write(MO_GPHST_INTMSK, 0x0);
+
+ /* stop capturing */
+ cx_write(VID_CAPTURE_CONTROL, 0);
+}
+
+int cx88_reset(struct cx88_core *core)
+{
+ dprintk(1,"%s\n",__func__);
+ cx88_shutdown(core);
+
+ /* clear irq status */
+ cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+ cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+ cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
+
+ /* wait a bit */
+ msleep(100);
+
+ /* init sram */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0);
+
+ /* misc init ... */
+ cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
+ (1 << 12) | // agc gain
+ (1 << 11) | // adaptibe agc
+ (0 << 10) | // chroma agc
+ (0 << 9) | // ckillen
+ (7)));
+
+ /* setup image format */
+ cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
+
+ /* setup FIFO Thresholds */
+ cx_write(MO_PDMA_STHRSH, 0x0807);
+ cx_write(MO_PDMA_DTHRSH, 0x0807);
+
+ /* fixes flashing of image */
+ cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
+ cx_write(MO_AGC_BACK_VBI, 0x00E00555);
+
+ cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+ cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+ cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
+
+ /* Reset on-board parts */
+ cx_write(MO_SRST_IO, 0);
+ msleep(10);
+ cx_write(MO_SRST_IO, 1);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int inline norm_swidth(v4l2_std_id norm)
+{
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+}
+
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
+{
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+}
+
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
+{
+ return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
+}
+
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
+{
+ if (norm & V4L2_STD_PAL_M)
+ return 28604892; // 3.575611 MHz
+
+ if (norm & (V4L2_STD_PAL_Nc))
+ return 28656448; // 3.582056 MHz
+
+ if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
+ return 28636360; // 3.57954545 MHz +/- 10 Hz
+
+ /* SECAM have also different sub carrier for chroma,
+ but step_db and step_dr, at cx88_set_tvnorm already handles that.
+
+ The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
+ */
+
+ return 35468950; // 4.43361875 MHz +/- 5 Hz
+}
+
+static unsigned int inline norm_htotal(v4l2_std_id norm)
+{
+
+ unsigned int fsc4=norm_fsc8(norm)/2;
+
+ /* returns 4*FSC / vtotal / frames per seconds */
+ return (norm & V4L2_STD_625_50) ?
+ ((fsc4+312)/625+12)/25 :
+ ((fsc4+262)/525*1001+15000)/30000;
+}
+
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
+{
+ return (norm & V4L2_STD_625_50) ? 511 : 400;
+}
+
+int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
+ enum v4l2_field field)
+{
+ unsigned int swidth = norm_swidth(core->tvnorm);
+ unsigned int sheight = norm_maxh(core->tvnorm);
+ u32 value;
+
+ dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+ V4L2_FIELD_HAS_TOP(field) ? "T" : "",
+ V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+ v4l2_norm_to_name(core->tvnorm));
+ if (!V4L2_FIELD_HAS_BOTH(field))
+ height *= 2;
+
+ // recalc H delay and scale registers
+ value = (width * norm_hdelay(core->tvnorm)) / swidth;
+ value &= 0x3fe;
+ cx_write(MO_HDELAY_EVEN, value);
+ cx_write(MO_HDELAY_ODD, value);
+ dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
+
+ value = (swidth * 4096 / width) - 4096;
+ cx_write(MO_HSCALE_EVEN, value);
+ cx_write(MO_HSCALE_ODD, value);
+ dprintk(1,"set_scale: hscale 0x%04x\n", value);
+
+ cx_write(MO_HACTIVE_EVEN, width);
+ cx_write(MO_HACTIVE_ODD, width);
+ dprintk(1,"set_scale: hactive 0x%04x\n", width);
+
+ // recalc V scale Register (delay is constant)
+ cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
+ cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
+ dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
+
+ value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
+ cx_write(MO_VSCALE_EVEN, value);
+ cx_write(MO_VSCALE_ODD, value);
+ dprintk(1,"set_scale: vscale 0x%04x\n", value);
+
+ cx_write(MO_VACTIVE_EVEN, sheight);
+ cx_write(MO_VACTIVE_ODD, sheight);
+ dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
+
+ // setup filters
+ value = 0;
+ value |= (1 << 19); // CFILT (default)
+ if (core->tvnorm & V4L2_STD_SECAM) {
+ value |= (1 << 15);
+ value |= (1 << 16);
+ }
+ if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
+ value |= (1 << 13) | (1 << 5);
+ if (V4L2_FIELD_INTERLACED == field)
+ value |= (1 << 3); // VINT (interlaced vertical scaling)
+ if (width < 385)
+ value |= (1 << 0); // 3-tap interpolation
+ if (width < 193)
+ value |= (1 << 1); // 5-tap interpolation
+ if (nocomb)
+ value |= (3 << 5); // disable comb filter
+
+ cx_andor(MO_FILTER_EVEN, 0x7ffc7f, value); /* preserve PEAKEN, PSEL */
+ cx_andor(MO_FILTER_ODD, 0x7ffc7f, value);
+ dprintk(1,"set_scale: filter 0x%04x\n", value);
+
+ return 0;
+}
+
+static const u32 xtal = 28636363;
+
+static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
+{
+ static const u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+ u64 pll;
+ u32 reg;
+ int i;
+
+ if (prescale < 2)
+ prescale = 2;
+ if (prescale > 5)
+ prescale = 5;
+
+ pll = ofreq * 8 * prescale * (u64)(1 << 20);
+ do_div(pll,xtal);
+ reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
+ if (((reg >> 20) & 0x3f) < 14) {
+ printk("%s/0: pll out of range\n",core->name);
+ return -1;
+ }
+
+ dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
+ reg, cx_read(MO_PLL_REG), ofreq);
+ cx_write(MO_PLL_REG, reg);
+ for (i = 0; i < 100; i++) {
+ reg = cx_read(MO_DEVICE_STATUS);
+ if (reg & (1<<2)) {
+ dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
+ prescale,ofreq);
+ return 0;
+ }
+ dprintk(1,"pll not locked yet, waiting ...\n");
+ msleep(10);
+ }
+ dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
+ return -1;
+}
+
+int cx88_start_audio_dma(struct cx88_core *core)
+{
+ /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
+ int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
+
+ int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES;
+
+ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+ return 0;
+
+ /* setup fifo + format */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27],
+ rds_bpl, 0);
+
+ cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
+ cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */
+
+ /* enable Up, Down and Audio RDS fifo */
+ cx_write(MO_AUD_DMACNTRL, 0x0007);
+
+ return 0;
+}
+
+int cx88_stop_audio_dma(struct cx88_core *core)
+{
+ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+ return 0;
+
+ /* stop dma */
+ cx_write(MO_AUD_DMACNTRL, 0x0000);
+
+ return 0;
+}
+
+static int set_tvaudio(struct cx88_core *core)
+{
+ v4l2_std_id norm = core->tvnorm;
+
+ if (CX88_VMUX_TELEVISION != INPUT(core->input).type &&
+ CX88_VMUX_CABLE != INPUT(core->input).type)
+ return 0;
+
+ if (V4L2_STD_PAL_BG & norm) {
+ core->tvaudio = WW_BG;
+
+ } else if (V4L2_STD_PAL_DK & norm) {
+ core->tvaudio = WW_DK;
+
+ } else if (V4L2_STD_PAL_I & norm) {
+ core->tvaudio = WW_I;
+
+ } else if (V4L2_STD_SECAM_L & norm) {
+ core->tvaudio = WW_L;
+
+ } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) {
+ core->tvaudio = WW_BG;
+
+ } else if (V4L2_STD_SECAM_DK & norm) {
+ core->tvaudio = WW_DK;
+
+ } else if ((V4L2_STD_NTSC_M & norm) ||
+ (V4L2_STD_PAL_M & norm)) {
+ core->tvaudio = WW_BTSC;
+
+ } else if (V4L2_STD_NTSC_M_JP & norm) {
+ core->tvaudio = WW_EIAJ;
+
+ } else {
+ printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
+ core->name, v4l2_norm_to_name(core->tvnorm));
+ core->tvaudio = WW_NONE;
+ return 0;
+ }
+
+ cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
+ cx88_set_tvaudio(core);
+ /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
+
+/*
+ This should be needed only on cx88-alsa. It seems that some cx88 chips have
+ bugs and does require DMA enabled for it to work.
+ */
+ cx88_start_audio_dma(core);
+ return 0;
+}
+
+
+
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
+{
+ u32 fsc8;
+ u32 adc_clock;
+ u32 vdec_clock;
+ u32 step_db,step_dr;
+ u64 tmp64;
+ u32 bdelay,agcdelay,htotal;
+ u32 cxiformat, cxoformat;
+
+ core->tvnorm = norm;
+ fsc8 = norm_fsc8(norm);
+ adc_clock = xtal;
+ vdec_clock = fsc8;
+ step_db = fsc8;
+ step_dr = fsc8;
+
+ if (norm & V4L2_STD_NTSC_M_JP) {
+ cxiformat = VideoFormatNTSCJapan;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC_443) {
+ cxiformat = VideoFormatNTSC443;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_PAL_M) {
+ cxiformat = VideoFormatPALM;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_N) {
+ cxiformat = VideoFormatPALN;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_Nc) {
+ cxiformat = VideoFormatPALNC;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_60) {
+ cxiformat = VideoFormatPAL60;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC) {
+ cxiformat = VideoFormatNTSC;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_SECAM) {
+ step_db = 4250000 * 8;
+ step_dr = 4406250 * 8;
+
+ cxiformat = VideoFormatSECAM;
+ cxoformat = 0x181f0008;
+ } else { /* PAL */
+ cxiformat = VideoFormatPAL;
+ cxoformat = 0x181f0008;
+ }
+
+ dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
+ v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+ step_db, step_dr);
+ set_pll(core,2,vdec_clock);
+
+ dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
+ cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+ /* Chroma AGC must be disabled if SECAM is used, we enable it
+ by default on PAL and NTSC */
+ cx_andor(MO_INPUT_FORMAT, 0x40f,
+ norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);
+
+ // FIXME: as-is from DScaler
+ dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
+ cxoformat, cx_read(MO_OUTPUT_FORMAT));
+ cx_write(MO_OUTPUT_FORMAT, cxoformat);
+
+ // MO_SCONV_REG = adc clock / video dec clock * 2^17
+ tmp64 = adc_clock * (u64)(1 << 17);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SCONV_REG));
+ cx_write(MO_SCONV_REG, (u32)tmp64);
+
+ // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
+ tmp64 = step_db * (u64)(1 << 22);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SUB_STEP));
+ cx_write(MO_SUB_STEP, (u32)tmp64);
+
+ // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
+ tmp64 = step_dr * (u64)(1 << 22);
+ do_div(tmp64, vdec_clock);
+ dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
+ (u32)tmp64, cx_read(MO_SUB_STEP_DR));
+ cx_write(MO_SUB_STEP_DR, (u32)tmp64);
+
+ // bdelay + agcdelay
+ bdelay = vdec_clock * 65 / 20000000 + 21;
+ agcdelay = vdec_clock * 68 / 20000000 + 15;
+ dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
+ (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
+ cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
+
+ // htotal
+ tmp64 = norm_htotal(norm) * (u64)vdec_clock;
+ do_div(tmp64, fsc8);
+ htotal = (u32)tmp64;
+ dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
+ htotal, cx_read(MO_HTOTAL), (u32)tmp64);
+ cx_andor(MO_HTOTAL, 0x07ff, htotal);
+
+ // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+ // the effective vbi offset ~244 samples, the same as the Bt8x8
+ cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
+
+ // this is needed as well to set all tvnorm parameter
+ cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
+
+ // audio
+ set_tvaudio(core);
+
+ // tell i2c chips
+ call_all(core, core, s_std, norm);
+
+ /* The chroma_agc control should be inaccessible if the video format is SECAM */
+ v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM);
+
+ // done
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+struct video_device *cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ const struct video_device *template_,
+ const char *type)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template_;
+ vfd->v4l2_dev = &core->v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ core->name, type, core->board.name);
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ return vfd;
+}
+
+struct cx88_core* cx88_core_get(struct pci_dev *pci)
+{
+ struct cx88_core *core;
+
+ mutex_lock(&devlist);
+ list_for_each_entry(core, &cx88_devlist, devlist) {
+ if (pci->bus->number != core->pci_bus)
+ continue;
+ if (PCI_SLOT(pci->devfn) != core->pci_slot)
+ continue;
+
+ if (0 != cx88_get_resources(core, pci)) {
+ mutex_unlock(&devlist);
+ return NULL;
+ }
+ atomic_inc(&core->refcount);
+ mutex_unlock(&devlist);
+ return core;
+ }
+
+ core = cx88_core_create(pci, cx88_devcount);
+ if (NULL != core) {
+ cx88_devcount++;
+ list_add_tail(&core->devlist, &cx88_devlist);
+ }
+
+ mutex_unlock(&devlist);
+ return core;
+}
+
+void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
+{
+ release_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0));
+
+ if (!atomic_dec_and_test(&core->refcount))
+ return;
+
+ mutex_lock(&devlist);
+ cx88_ir_fini(core);
+ if (0 == core->i2c_rc) {
+ if (core->i2c_rtc)
+ i2c_unregister_device(core->i2c_rtc);
+ i2c_del_adapter(&core->i2c_adap);
+ }
+ list_del(&core->devlist);
+ iounmap(core->lmmio);
+ cx88_devcount--;
+ mutex_unlock(&devlist);
+ v4l2_ctrl_handler_free(&core->video_hdl);
+ v4l2_ctrl_handler_free(&core->audio_hdl);
+ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx88_print_irqbits);
+
+EXPORT_SYMBOL(cx88_core_irq);
+EXPORT_SYMBOL(cx88_wakeup);
+EXPORT_SYMBOL(cx88_reset);
+EXPORT_SYMBOL(cx88_shutdown);
+
+EXPORT_SYMBOL(cx88_risc_buffer);
+EXPORT_SYMBOL(cx88_risc_databuffer);
+EXPORT_SYMBOL(cx88_risc_stopper);
+EXPORT_SYMBOL(cx88_free_buffer);
+
+EXPORT_SYMBOL(cx88_sram_channels);
+EXPORT_SYMBOL(cx88_sram_channel_setup);
+EXPORT_SYMBOL(cx88_sram_channel_dump);
+
+EXPORT_SYMBOL(cx88_set_tvnorm);
+EXPORT_SYMBOL(cx88_set_scale);
+
+EXPORT_SYMBOL(cx88_vdev_init);
+EXPORT_SYMBOL(cx88_core_get);
+EXPORT_SYMBOL(cx88_core_put);
+
+EXPORT_SYMBOL(cx88_ir_start);
+EXPORT_SYMBOL(cx88_ir_stop);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c
index a9907265ff66..a9907265ff66 100644
--- a/drivers/media/video/cx88/cx88-dsp.c
+++ b/drivers/media/pci/cx88/cx88-dsp.c
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
new file mode 100644
index 000000000000..d803bba09525
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -0,0 +1,1778 @@
+/*
+ *
+ * device driver for Conexant 2388x based TV cards
+ * MPEG Transport Stream (DVB) routines
+ *
+ * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx88.h"
+#include "dvb-pll.h"
+#include <media/v4l2-common.h>
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "cx88-vp3054-i2c.h"
+#include "zl10353.h"
+#include "cx22702.h"
+#include "or51132.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "xc4000.h"
+#include "xc5000.h"
+#include "nxt200x.h"
+#include "cx24123.h"
+#include "isl6421.h"
+#include "tuner-simple.h"
+#include "tda9887.h"
+#include "s5h1411.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stb6100.h"
+#include "stb6100_proc.h"
+#include "mb86a16.h"
+#include "ds3000.h"
+
+MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+
+static unsigned int dvb_buf_tscnt = 32;
+module_param(dvb_buf_tscnt, int, 0644);
+MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx8802_dev *dev = q->priv_data;
+
+ dev->ts_packet_size = 188 * 4;
+ dev->ts_packet_count = dvb_buf_tscnt;
+
+ *size = dev->ts_packet_size * dev->ts_packet_count;
+ *count = dvb_buf_tscnt;
+ return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx8802_dev *dev = q->priv_data;
+ return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx8802_dev *dev = q->priv_data;
+ cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx88_free_buffer(q, (struct cx88_buffer*)vb);
+}
+
+static const struct videobuf_queue_ops dvb_qops = {
+ .buf_setup = dvb_buf_setup,
+ .buf_prepare = dvb_buf_prepare,
+ .buf_queue = dvb_buf_queue,
+ .buf_release = dvb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx8802_driver *drv = NULL;
+ int ret = 0;
+ int fe_id;
+
+ fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
+ if (!fe_id) {
+ printk(KERN_ERR "%s() No frontend found\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->core->lock);
+ drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
+ if (drv) {
+ if (acquire){
+ dev->frontends.active_fe_id = fe_id;
+ ret = drv->request_acquire(drv);
+ } else {
+ ret = drv->request_release(drv);
+ dev->frontends.active_fe_id = 0;
+ }
+ }
+ mutex_unlock(&dev->core->lock);
+
+ return ret;
+}
+
+static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
+{
+ struct videobuf_dvb_frontends *f;
+ struct videobuf_dvb_frontend *fe;
+
+ if (!core->dvbdev)
+ return;
+
+ f = &core->dvbdev->frontends;
+
+ if (!f)
+ return;
+
+ if (f->gate <= 1) /* undefined or fe0 */
+ fe = videobuf_dvb_get_frontend(f, 1);
+ else
+ fe = videobuf_dvb_get_frontend(f, f->gate);
+
+ if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+ fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
+{
+ static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
+ static const u8 reset [] = { RESET, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
+ static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ return 0;
+}
+
+static int dvico_dual_demod_init(struct dvb_frontend *fe)
+{
+ static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
+ static const u8 reset [] = { RESET, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
+ static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
+{
+ static const u8 clock_config [] = { 0x89, 0x38, 0x39 };
+ static const u8 reset [] = { 0x50, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ static const u8 dntv_extra[] = { 0xB5, 0x7A };
+ static const u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(2000);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ udelay(2000);
+ mt352_write(fe, dntv_extra, sizeof(dntv_extra));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static const struct mt352_config dvico_fusionhdtv = {
+ .demod_address = 0x0f,
+ .demod_init = dvico_fusionhdtv_demod_init,
+};
+
+static const struct mt352_config dntv_live_dvbt_config = {
+ .demod_address = 0x0f,
+ .demod_init = dntv_live_dvbt_demod_init,
+};
+
+static const struct mt352_config dvico_fusionhdtv_dual = {
+ .demod_address = 0x0f,
+ .demod_init = dvico_dual_demod_init,
+};
+
+static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .if2 = 45600,
+};
+
+static struct mb86a16_config twinhan_vp1027 = {
+ .demod_address = 0x08,
+};
+
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+{
+ static const u8 clock_config [] = { 0x89, 0x38, 0x38 };
+ static const u8 reset [] = { 0x50, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ static const u8 dntv_extra[] = { 0xB5, 0x7A };
+ static const u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(2000);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ udelay(2000);
+ mt352_write(fe, dntv_extra, sizeof(dntv_extra));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static const struct mt352_config dntv_live_dvbt_pro_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .demod_init = dntv_live_dvbt_pro_demod_init,
+};
+#endif
+
+static const struct zl10353_config dvico_fusionhdtv_hybrid = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+};
+
+static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
+ .demod_address = 0x0f,
+ .if2 = 45600,
+ .no_tuner = 1,
+};
+
+static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
+ .demod_address = 0x0f,
+ .if2 = 4560,
+ .no_tuner = 1,
+ .demod_init = dvico_fusionhdtv_demod_init,
+};
+
+static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+ .demod_address = 0x0f,
+};
+
+static const struct cx22702_config connexant_refboard_config = {
+ .demod_address = 0x43,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+};
+
+static const struct cx22702_config hauppauge_hvr_config = {
+ .demod_address = 0x63,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+};
+
+static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+ return 0;
+}
+
+static const struct or51132_config pchdtv_hd3000 = {
+ .demod_address = 0x15,
+ .set_ts_params = or51132_set_ts_param,
+};
+
+static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ dprintk(1, "%s: index = %d\n", __func__, index);
+ if (index == 0)
+ cx_clear(MO_GP0_IO, 8);
+ else
+ cx_set(MO_GP0_IO, 8);
+ return 0;
+}
+
+static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ if (is_punctured)
+ dev->ts_gen_cntrl |= 0x04;
+ else
+ dev->ts_gen_cntrl &= ~0x04;
+ return 0;
+}
+
+static struct lgdt330x_config fusionhdtv_3_gold = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3302,
+ .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static const struct lgdt330x_config fusionhdtv_5_gold = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static const struct lgdt330x_config pchdtv_hd5500 = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+ return 0;
+}
+
+static const struct nxt200x_config ati_hdtvwonder = {
+ .demod_address = 0x0a,
+ .set_ts_params = nxt200x_set_ts_param,
+};
+
+static int cx24123_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = 0x02;
+ return 0;
+}
+
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ if (voltage == SEC_VOLTAGE_OFF)
+ cx_write(MO_GP0_IO, 0x000006fb);
+ else
+ cx_write(MO_GP0_IO, 0x000006f9);
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ if (voltage == SEC_VOLTAGE_OFF) {
+ dprintk(1,"LNB Voltage OFF\n");
+ cx_write(MO_GP0_IO, 0x0000efff);
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ cx_set(MO_GP0_IO, 0x6040);
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ cx_clear(MO_GP0_IO, 0x20);
+ break;
+ case SEC_VOLTAGE_18:
+ cx_set(MO_GP0_IO, 0x20);
+ break;
+ case SEC_VOLTAGE_OFF:
+ cx_clear(MO_GP0_IO, 0x20);
+ break;
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static int vp1027_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(1, "LNB SEC Voltage=13\n");
+ cx_write(MO_GP0_IO, 0x00001220);
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(1, "LNB SEC Voltage=18\n");
+ cx_write(MO_GP0_IO, 0x00001222);
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(1, "LNB Voltage OFF\n");
+ cx_write(MO_GP0_IO, 0x00001230);
+ break;
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static const struct cx24123_config geniatech_dvbs_config = {
+ .demod_address = 0x55,
+ .set_ts_params = cx24123_set_ts_param,
+};
+
+static const struct cx24123_config hauppauge_novas_config = {
+ .demod_address = 0x55,
+ .set_ts_params = cx24123_set_ts_param,
+};
+
+static const struct cx24123_config kworld_dvbs_100_config = {
+ .demod_address = 0x15,
+ .set_ts_params = cx24123_set_ts_param,
+ .lnb_polarity = 1,
+};
+
+static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_PARALLEL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct s5h1409_config kworld_atsc_120_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+ .i2c_address = 0x64,
+ .if_khz = 5380,
+};
+
+static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .if2 = 45600,
+};
+
+static const struct zl10353_config cx88_geniatech_x8000_mt = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static const struct s5h1411_config dvico_fusionhdtv7_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_ON,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .qam_if = S5H1411_IF_44000,
+ .vsb_if = S5H1411_IF_44000,
+ .inversion = S5H1411_INVERSION_OFF,
+ .status_mode = S5H1411_DEMODLOCKING
+};
+
+static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+ .i2c_address = 0xc2 >> 1,
+ .if_khz = 5380,
+};
+
+static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
+{
+ struct dvb_frontend *fe;
+ struct videobuf_dvb_frontend *fe0 = NULL;
+ struct xc2028_ctrl ctl;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->core->i2c_adap,
+ .i2c_addr = addr,
+ .ctrl = &ctl,
+ };
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ if (!fe0->dvb.frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc3028\n",
+ dev->core->name);
+ return -EINVAL;
+ }
+
+ /*
+ * Some xc3028 devices may be hidden by an I2C gate. This is known
+ * to happen with some s5h1409-based devices.
+ * Now that I2C gate is open, sets up xc3028 configuration
+ */
+ cx88_setup_xc3028(dev->core, &ctl);
+
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->core->name);
+ dvb_frontend_detach(fe0->dvb.frontend);
+ dvb_unregister_frontend(fe0->dvb.frontend);
+ fe0->dvb.frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc3028 attached\n",
+ dev->core->name);
+
+ return 0;
+}
+
+static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
+{
+ struct dvb_frontend *fe;
+ struct videobuf_dvb_frontend *fe0 = NULL;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ if (!fe0->dvb.frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc4000\n",
+ dev->core->name);
+ return -EINVAL;
+ }
+
+ fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
+ cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+ dev->core->name);
+ dvb_frontend_detach(fe0->dvb.frontend);
+ dvb_unregister_frontend(fe0->dvb.frontend);
+ fe0->dvb.frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name);
+
+ return 0;
+}
+
+static int cx24116_set_ts_param(struct dvb_frontend *fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ dev->ts_gen_cntrl = 0x2;
+
+ return 0;
+}
+
+static int stv0900_set_ts_param(struct dvb_frontend *fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ dev->ts_gen_cntrl = 0;
+
+ return 0;
+}
+
+static int cx24116_reset_device(struct dvb_frontend *fe)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ /* Reset the part */
+ /* Put the cx24116 into reset */
+ cx_write(MO_SRST_IO, 0);
+ msleep(10);
+ /* Take the cx24116 out of reset */
+ cx_write(MO_SRST_IO, 1);
+ msleep(10);
+
+ return 0;
+}
+
+static const struct cx24116_config hauppauge_hvr4000_config = {
+ .demod_address = 0x05,
+ .set_ts_params = cx24116_set_ts_param,
+ .reset_device = cx24116_reset_device,
+};
+
+static const struct cx24116_config tevii_s460_config = {
+ .demod_address = 0x55,
+ .set_ts_params = cx24116_set_ts_param,
+ .reset_device = cx24116_reset_device,
+};
+
+static int ds3000_set_ts_param(struct dvb_frontend *fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ dev->ts_gen_cntrl = 4;
+
+ return 0;
+}
+
+static struct ds3000_config tevii_ds3000_config = {
+ .demod_address = 0x68,
+ .set_ts_params = ds3000_set_ts_param,
+};
+
+static const struct stv0900_config prof_7301_stv0900_config = {
+ .demod_address = 0x6a,
+/* demod_mode = 0,*/
+ .xtal = 27000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .tun1_maddress = 0,/* 0x60 */
+ .tun1_adc = 0,/* 2 Vpp */
+ .path1_mode = 3,
+ .set_ts_params = stv0900_set_ts_param,
+};
+
+static const struct stb6100_config prof_7301_stb6100_config = {
+ .tuner_address = 0x60,
+ .refclock = 27000000,
+};
+
+static const struct stv0299_config tevii_tuner_sharp_config = {
+ .demod_address = 0x68,
+ .inittab = sharp_z0194a_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = 1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+ .set_ts_params = cx24116_set_ts_param,
+};
+
+static const struct stv0288_config tevii_tuner_earda_config = {
+ .demod_address = 0x68,
+ .min_delay_ms = 100,
+ .set_ts_params = cx24116_set_ts_param,
+};
+
+static int cx8802_alloc_frontends(struct cx8802_dev *dev)
+{
+ struct cx88_core *core = dev->core;
+ struct videobuf_dvb_frontend *fe = NULL;
+ int i;
+
+ mutex_init(&dev->frontends.lock);
+ INIT_LIST_HEAD(&dev->frontends.felist);
+
+ if (!core->board.num_frontends)
+ return -ENODEV;
+
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+ core->board.num_frontends);
+ for (i = 1; i <= core->board.num_frontends; i++) {
+ fe = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+ if (!fe) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ videobuf_dvb_dealloc_frontends(&dev->frontends);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+
+
+static const u8 samsung_smt_7020_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7D,
+ 0x05, 0x0F,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x60,
+
+ 0x0A, 0xC2,
+ 0x0B, 0x00,
+ 0x0C, 0x01,
+ 0x0D, 0x81,
+ 0x0E, 0x44,
+ 0x0F, 0x09,
+ 0x10, 0x3C,
+ 0x11, 0x84,
+ 0x12, 0xDA,
+ 0x13, 0x99,
+ 0x14, 0x8D,
+ 0x15, 0xCE,
+ 0x16, 0xE8,
+ 0x17, 0x43,
+ 0x18, 0x1C,
+ 0x19, 0x1B,
+ 0x1A, 0x1D,
+
+ 0x1C, 0x12,
+ 0x1D, 0x00,
+ 0x1E, 0x00,
+ 0x1F, 0x00,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+
+ 0x28, 0x02,
+ 0x29, 0x28,
+ 0x2A, 0x14,
+ 0x2B, 0x0F,
+ 0x2C, 0x09,
+ 0x2D, 0x05,
+
+ 0x31, 0x1F,
+ 0x32, 0x19,
+ 0x33, 0xFC,
+ 0x34, 0x13,
+ 0xff, 0xff,
+};
+
+
+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;
+ struct i2c_msg msg = {
+ .addr = 0x61,
+ .flags = 0,
+ .buf = buf,
+ .len = sizeof(buf) };
+
+ div = c->frequency / 125;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x84; /* 0xC4 */
+ buf[3] = 0x00;
+
+ if (c->frequency < 1500000)
+ buf[3] |= 0x10;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
+ fe_sec_tone_mode_t tone)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ cx_set(MO_GP0_IO, 0x0800);
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ cx_set(MO_GP0_IO, 0x08);
+ break;
+ case SEC_TONE_OFF:
+ cx_clear(MO_GP0_IO, 0x08);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ u8 data;
+ struct i2c_msg msg = {
+ .addr = 8,
+ .flags = 0,
+ .buf = &data,
+ .len = sizeof(data) };
+
+ cx_set(MO_GP0_IO, 0x8000);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ data = ISL6421_EN1 | ISL6421_LLC1;
+ cx_clear(MO_GP0_IO, 0x80);
+ break;
+ case SEC_VOLTAGE_18:
+ data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
+ cx_clear(MO_GP0_IO, 0x80);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+
+static const struct stv0299_config samsung_stv0299_config = {
+ .demod_address = 0x68,
+ .inittab = samsung_smt_7020_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_LK,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
+};
+
+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);
+ goto frontend_detach;
+ }
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ goto frontend_detach;
+
+ /* multi-frontend gate control is undefined or defaults to fe0 */
+ dev->frontends.gate = 0;
+
+ /* Sets the gate control callback to be used by i2c command calls */
+ core->gate_ctrl = cx88_dvb_gate_ctrl;
+
+ /* init frontend(s) */
+ switch (core->boardnr) {
+ case CX88_BOARD_HAUPPAUGE_DVB_T1:
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
+ &connexant_refboard_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x61, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT759X))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+ case CX88_BOARD_CONEXANT_DVB_T1:
+ case CX88_BOARD_KWORLD_DVB_T_CX22702:
+ case CX88_BOARD_WINFAST_DTV1000:
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
+ &connexant_refboard_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x60, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_WINFAST_DTV2000H:
+ case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ 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_FMD1216ME_MK3))
+ 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;
+ dev->frontends.gate = 2;
+ /* DVB-S init */
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
+ &hauppauge_novas_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach,
+ fe0->dvb.frontend,
+ &dev->core->i2c_adap,
+ 0x08, ISL6421_DCL, 0x00))
+ goto frontend_detach;
+ }
+ /* MFE frontend 2 */
+ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ if (!fe1)
+ goto frontend_detach;
+ /* DVB-T init */
+ fe1->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_config,
+ &dev->core->i2c_adap);
+ if (fe1->dvb.frontend) {
+ fe1->dvb.frontend->id = 1;
+ if (!dvb_attach(simple_tuner_attach,
+ fe1->dvb.frontend,
+ &dev->core->i2c_adap,
+ 0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
+ break;
+ }
+ /* ZL10353 replaces MT352 on later cards */
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_plus_v1_1,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv_dual,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
+ break;
+ }
+ /* ZL10353 replaces MT352 on later cards */
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_plus_v1_1,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x61, NULL, DVB_PLL_LG_Z201))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_KWORLD_DVB_T:
+ case CX88_BOARD_DNTV_LIVE_DVB_T:
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &dntv_live_dvbt_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
+ 0x61, NULL, DVB_PLL_UNKNOWN_1))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+ /* MT352 is on a secondary I2C bus made from some GPIO lines */
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
+ &dev->vp3054->adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
+ }
+#else
+ printk(KERN_ERR "%s/2: built without vp3054 support\n",
+ core->name);
+#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_hybrid,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_FE6600))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend == NULL)
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv_mt352_xc3028,
+ &core->i2c_adap);
+ /*
+ * On this board, the demod provides the I2C bus pullup.
+ * We must not permit gate_ctrl to be performed, or
+ * the xc3028 cannot communicate on the bus.
+ */
+ if (fe0->dvb.frontend)
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ break;
+ case CX88_BOARD_PCHDTV_HD3000:
+ fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+ dev->ts_gen_cntrl = 0x08;
+
+ /* Do a hardware reset of chip before using it. */
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+
+ /* Select RF connector callback */
+ fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_3_gold,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_MICROTUNE_4042FI5))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+ dev->ts_gen_cntrl = 0x08;
+
+ /* Do a hardware reset of chip before using it. */
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 9);
+ mdelay(200);
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_3_gold,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ dev->ts_gen_cntrl = 0x08;
+
+ /* Do a hardware reset of chip before using it. */
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_5_gold,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_PCHDTV_HD5500:
+ dev->ts_gen_cntrl = 0x08;
+
+ /* Do a hardware reset of chip before using it. */
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &pchdtv_hd5500,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_ATI_HDTVWONDER:
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach,
+ &ati_hdtvwonder,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
+ &hauppauge_novas_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_KWORLD_DVBS_100:
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
+ &kworld_dvbs_100_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ }
+ break;
+ case CX88_BOARD_GENIATECH_DVBS:
+ fe0->dvb.frontend = dvb_attach(cx24123_attach,
+ &geniatech_dvbs_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+ }
+ break;
+ case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &pinnacle_pctv_hd_800i_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &core->i2c_adap,
+ &pinnacle_pctv_hd_800i_tuner_config))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &dvico_hdtv5_pci_nano_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &core->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .scode_table = XC3028_FE_OREN538,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ fe0->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+ case CX88_BOARD_WINFAST_DTV1800H:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_pinnacle_hybrid_pctv,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+ case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_pinnacle_hybrid_pctv,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ struct xc4000_config cfg = {
+ .i2c_address = 0x61,
+ .default_pm = 0,
+ .dvb_amplitude = 134,
+ .set_smoothedcvbs = 1,
+ .if_khz = 4560
+ };
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc4000(dev, &cfg) < 0)
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_GENIATECH_X8000_MT:
+ dev->ts_gen_cntrl = 0x00;
+
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_geniatech_x8000_mt,
+ &core->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ break;
+ case CX88_BOARD_KWORLD_ATSC_120:
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
+ &kworld_atsc_120_config,
+ &core->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &dvico_fusionhdtv7_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &core->i2c_adap,
+ &dvico_fusionhdtv7_tuner_config))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ /* MFE frontend 1 */
+ mfe_shared = 1;
+ dev->frontends.gate = 2;
+ /* DVB-S/S2 Init */
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &hauppauge_hvr4000_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach,
+ fe0->dvb.frontend,
+ &dev->core->i2c_adap,
+ 0x08, ISL6421_DCL, 0x00))
+ goto frontend_detach;
+ }
+ /* MFE frontend 2 */
+ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ if (!fe1)
+ goto frontend_detach;
+ /* DVB-T Init */
+ fe1->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_config,
+ &dev->core->i2c_adap);
+ if (fe1->dvb.frontend) {
+ fe1->dvb.frontend->id = 1;
+ if (!dvb_attach(simple_tuner_attach,
+ fe1->dvb.frontend,
+ &dev->core->i2c_adap,
+ 0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &hauppauge_hvr4000_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (!dvb_attach(isl6421_attach,
+ fe0->dvb.frontend,
+ &dev->core->i2c_adap,
+ 0x08, ISL6421_DCL, 0x00))
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_PROF_6200:
+ case CX88_BOARD_TBS_8910:
+ case CX88_BOARD_TEVII_S420:
+ fe0->dvb.frontend = dvb_attach(stv0299_attach,
+ &tevii_tuner_sharp_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
+ &core->i2c_adap, DVB_PLL_OPERA1))
+ goto frontend_detach;
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+ } else {
+ fe0->dvb.frontend = dvb_attach(stv0288_attach,
+ &tevii_tuner_earda_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
+ &core->i2c_adap))
+ goto frontend_detach;
+ core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ }
+ }
+ break;
+ case CX88_BOARD_TEVII_S460:
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &tevii_s460_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ break;
+ case CX88_BOARD_TEVII_S464:
+ fe0->dvb.frontend = dvb_attach(ds3000_attach,
+ &tevii_ds3000_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage =
+ tevii_dvbs_set_voltage;
+ break;
+ case CX88_BOARD_OMICOM_SS4_PCI:
+ case CX88_BOARD_TBS_8920:
+ case CX88_BOARD_PROF_7300:
+ case CX88_BOARD_SATTRADE_ST4200:
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
+ &hauppauge_hvr4000_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ break;
+ case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_terratec_cinergy_ht_pci_mkii_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc3028(0x61, dev) < 0)
+ goto frontend_detach;
+ }
+ break;
+ case CX88_BOARD_PROF_7301:{
+ struct dvb_tuner_ops *tuner_ops = NULL;
+
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
+ &prof_7301_stv0900_config,
+ &core->i2c_adap, 0);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(stb6100_attach, fe0->dvb.frontend,
+ &prof_7301_stb6100_config,
+ &core->i2c_adap))
+ goto frontend_detach;
+
+ tuner_ops = &fe0->dvb.frontend->ops.tuner_ops;
+ tuner_ops->set_frequency = stb6100_set_freq;
+ tuner_ops->get_frequency = stb6100_get_freq;
+ tuner_ops->set_bandwidth = stb6100_set_bandw;
+ tuner_ops->get_bandwidth = stb6100_get_bandw;
+
+ core->prev_set_voltage =
+ fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage =
+ tevii_dvbs_set_voltage;
+ }
+ break;
+ }
+ case CX88_BOARD_SAMSUNG_SMT_7020:
+ dev->ts_gen_cntrl = 0x08;
+
+ cx_set(MO_GP0_IO, 0x0101);
+
+ cx_clear(MO_GP0_IO, 0x01);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 0x01);
+ mdelay(200);
+
+ fe0->dvb.frontend = dvb_attach(stv0299_attach,
+ &samsung_stv0299_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.set_params =
+ samsung_smt_7020_tuner_set_params;
+ fe0->dvb.frontend->tuner_priv =
+ &dev->core->i2c_adap;
+ fe0->dvb.frontend->ops.set_voltage =
+ samsung_smt_7020_set_voltage;
+ fe0->dvb.frontend->ops.set_tone =
+ samsung_smt_7020_set_tone;
+ }
+
+ break;
+ case CX88_BOARD_TWINHAN_VP1027_DVBS:
+ dev->ts_gen_cntrl = 0x00;
+ fe0->dvb.frontend = dvb_attach(mb86a16_attach,
+ &twinhan_vp1027,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage =
+ fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage =
+ vp1027_set_voltage;
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
+ core->name);
+ break;
+ }
+
+ if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n",
+ core->name);
+ goto frontend_detach;
+ }
+ /* define general-purpose callback pointer */
+ fe0->dvb.frontend->callback = cx88_tuner_callback;
+
+ /* Ensure all frontends negotiate bus access */
+ fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+ if (fe1)
+ fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+
+ /* Put the analog decoder in standby to keep it quiet */
+ call_all(core, core, s_power, 0);
+
+ /* register everything */
+ res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr, mfe_shared);
+ if (res)
+ goto frontend_detach;
+ return res;
+
+frontend_detach:
+ core->gate_ctrl = NULL;
+ videobuf_dvb_dealloc_frontends(&dev->frontends);
+ return res;
+}
+
+/* ----------------------------------------------------------- */
+
+/* CX8802 MPEG -> mini driver - We have been given the hardware */
+static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ int err = 0;
+ dprintk( 1, "%s\n", __func__);
+
+ switch (core->boardnr) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* We arrive here with either the cx23416 or the cx22702
+ * on the bus. Take the bus from the cx23416 and enable the
+ * cx22702 demod
+ */
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ /* enable the cx22702 pins */
+ cx_clear(MO_GP0_IO, 0x00000004);
+ udelay(1000);
+ break;
+
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ /* Toggle reset on cx22702 leaving i2c active */
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080);
+ udelay(1000);
+ switch (core->dvbdev->frontends.active_fe_id) {
+ case 1: /* DVB-S/S2 Enabled */
+ /* tri-state the cx22702 pins */
+ cx_set(MO_GP0_IO, 0x00000004);
+ /* Take the cx24116/cx24123 out of reset */
+ cx_write(MO_SRST_IO, 1);
+ core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
+ break;
+ case 2: /* DVB-T Enabled */
+ /* Put the cx24116/cx24123 into reset */
+ cx_write(MO_SRST_IO, 0);
+ /* enable the cx22702 pins */
+ cx_clear(MO_GP0_IO, 0x00000004);
+ core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
+ break;
+ }
+ udelay(1000);
+ break;
+
+ case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+ /* set RF input to AIR for DVB-T (GPIO 16) */
+ cx_write(MO_GP2_IO, 0x0101);
+ break;
+
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
+/* CX8802 MPEG -> mini driver - We no longer have the hardware */
+static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ int err = 0;
+ dprintk( 1, "%s\n", __func__);
+
+ switch (core->boardnr) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* Do Nothing, leave the cx22702 on the bus. */
+ break;
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ break;
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
+static int cx8802_dvb_probe(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ struct cx8802_dev *dev = drv->core->dvbdev;
+ int err;
+ struct videobuf_dvb_frontend *fe;
+ int i;
+
+ dprintk( 1, "%s\n", __func__);
+ dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ core->boardnr,
+ core->name,
+ core->pci_bus,
+ core->pci_slot);
+
+ err = -ENODEV;
+ if (!(core->board.mpeg & CX88_MPEG_DVB))
+ goto fail_core;
+
+ /* If vp3054 isn't enabled, a stub will just return 0 */
+ err = vp3054_i2c_probe(dev);
+ if (0 != err)
+ goto fail_core;
+
+ /* dvb stuff */
+ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
+ dev->ts_gen_cntrl = 0x0c;
+
+ err = cx8802_alloc_frontends(dev);
+ if (err)
+ goto fail_core;
+
+ err = -ENODEV;
+ for (i = 1; i <= core->board.num_frontends; i++) {
+ fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+ if (fe == NULL) {
+ printk(KERN_ERR "%s() failed to get frontend(%d)\n",
+ __func__, i);
+ goto fail_probe;
+ }
+ videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
+ &dev->pci->dev, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_TOP,
+ sizeof(struct cx88_buffer),
+ dev, NULL);
+ /* init struct videobuf_dvb */
+ fe->dvb.name = dev->core->name;
+ }
+
+ err = dvb_register(dev);
+ if (err)
+ /* frontends/adapter de-allocated in dvb_register */
+ printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
+ core->name, err);
+ return err;
+fail_probe:
+ videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends);
+fail_core:
+ return err;
+}
+
+static int cx8802_dvb_remove(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ struct cx8802_dev *dev = drv->core->dvbdev;
+
+ dprintk( 1, "%s\n", __func__);
+
+ videobuf_dvb_unregister_bus(&dev->frontends);
+
+ vp3054_i2c_remove(dev);
+
+ core->gate_ctrl = NULL;
+
+ return 0;
+}
+
+static struct cx8802_driver cx8802_dvb_driver = {
+ .type_id = CX88_MPEG_DVB,
+ .hw_access = CX8802_DRVCTL_SHARED,
+ .probe = cx8802_dvb_probe,
+ .remove = cx8802_dvb_remove,
+ .advise_acquire = cx8802_dvb_advise_acquire,
+ .advise_release = cx8802_dvb_advise_release,
+};
+
+static int __init dvb_init(void)
+{
+ printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n",
+ CX88_VERSION);
+ return cx8802_register_driver(&cx8802_dvb_driver);
+}
+
+static void __exit dvb_fini(void)
+{
+ cx8802_unregister_driver(&cx8802_dvb_driver);
+}
+
+module_init(dvb_init);
+module_exit(dvb_fini);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c
index de0f1af74e41..de0f1af74e41 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/pci/cx88/cx88-i2c.c
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index ebf448c48ca3..ebf448c48ca3 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index cd5386ee210c..cd5386ee210c 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/pci/cx88/cx88-reg.h
index 2ec52d1cdea0..2ec52d1cdea0 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/pci/cx88/cx88-reg.h
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c
index 770ec05b5e9b..770ec05b5e9b 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/pci/cx88/cx88-tvaudio.c
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
index f8f8389c0362..f8f8389c0362 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/pci/cx88/cx88-vbi.c
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index f6fcc7e763ab..f6fcc7e763ab 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
index d77f8ecab9d7..d77f8ecab9d7 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
index be99c931dc3e..be99c931dc3e 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
new file mode 100644
index 000000000000..44ffc8b3d45f
--- /dev/null
+++ b/drivers/media/pci/cx88/cx88.h
@@ -0,0 +1,748 @@
+/*
+ *
+ * v4l2 device driver for cx2388x based TV cards
+ *
+ * (c) 2003,04 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
+ * 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/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev2.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/cx2341x.h>
+#include <media/videobuf-dvb.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/wm8775.h>
+
+#include "btcx-risc.h"
+#include "cx88-reg.h"
+#include "tuner-xc2028.h"
+
+#include <linux/mutex.h>
+
+#define CX88_VERSION "0.0.9"
+
+#define UNSET (-1U)
+
+#define CX88_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX88_INPUT 8
+
+/* ----------------------------------------------------------- */
+/* defines and enums */
+
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */
+#define CX88_NORMS (V4L2_STD_ALL \
+ & ~V4L2_STD_PAL_H \
+ & ~V4L2_STD_NTSC_M_KR \
+ & ~V4L2_STD_SECAM_LC)
+
+#define FORMAT_FLAGS_PACKED 0x01
+#define FORMAT_FLAGS_PLANAR 0x02
+
+#define VBI_LINE_COUNT 17
+#define VBI_LINE_LENGTH 2048
+
+#define AUD_RDS_LINES 4
+
+/* need "shadow" registers for some write-only ones ... */
+#define SHADOW_AUD_VOL_CTL 1
+#define SHADOW_AUD_BAL_CTL 2
+#define SHADOW_MAX 3
+
+/* FM Radio deemphasis type */
+enum cx88_deemph_type {
+ FM_NO_DEEMPH = 0,
+ FM_DEEMPH_50,
+ FM_DEEMPH_75
+};
+
+enum cx88_board_type {
+ CX88_BOARD_NONE = 0,
+ CX88_MPEG_DVB,
+ CX88_MPEG_BLACKBIRD
+};
+
+enum cx8802_board_access {
+ CX8802_DRVCTL_SHARED = 1,
+ CX8802_DRVCTL_EXCLUSIVE = 2,
+};
+
+/* ----------------------------------------------------------- */
+/* tv norms */
+
+static unsigned int inline norm_maxw(v4l2_std_id norm)
+{
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+}
+
+
+static unsigned int inline norm_maxh(v4l2_std_id norm)
+{
+ return (norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+/* ----------------------------------------------------------- */
+/* static data */
+
+struct cx8800_fmt {
+ const char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+ int flags;
+ u32 cxformat;
+};
+
+/* ----------------------------------------------------------- */
+/* SRAM memory management data (see cx88-core.c) */
+
+#define SRAM_CH21 0 /* video */
+#define SRAM_CH22 1
+#define SRAM_CH23 2
+#define SRAM_CH24 3 /* vbi */
+#define SRAM_CH25 4 /* audio */
+#define SRAM_CH26 5
+#define SRAM_CH28 6 /* mpeg */
+#define SRAM_CH27 7 /* audio rds */
+/* more */
+
+struct sram_channel {
+ const char *name;
+ u32 cmds_start;
+ u32 ctrl_start;
+ u32 cdt;
+ u32 fifo_start;
+ u32 fifo_size;
+ u32 ptr1_reg;
+ u32 ptr2_reg;
+ u32 cnt1_reg;
+ u32 cnt2_reg;
+};
+extern const struct sram_channel cx88_sram_channels[];
+
+/* ----------------------------------------------------------- */
+/* card configuration */
+
+#define CX88_BOARD_NOAUTO UNSET
+#define CX88_BOARD_UNKNOWN 0
+#define CX88_BOARD_HAUPPAUGE 1
+#define CX88_BOARD_GDI 2
+#define CX88_BOARD_PIXELVIEW 3
+#define CX88_BOARD_ATI_WONDER_PRO 4
+#define CX88_BOARD_WINFAST2000XP_EXPERT 5
+#define CX88_BOARD_AVERTV_STUDIO_303 6
+#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
+#define CX88_BOARD_WINFAST_DV2000 8
+#define CX88_BOARD_LEADTEK_PVR2000 9
+#define CX88_BOARD_IODATA_GVVCP3PCI 10
+#define CX88_BOARD_PROLINK_PLAYTVPVR 11
+#define CX88_BOARD_ASUS_PVR_416 12
+#define CX88_BOARD_MSI_TVANYWHERE 13
+#define CX88_BOARD_KWORLD_DVB_T 14
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
+#define CX88_BOARD_KWORLD_LTV883 16
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17
+#define CX88_BOARD_HAUPPAUGE_DVB_T1 18
+#define CX88_BOARD_CONEXANT_DVB_T1 19
+#define CX88_BOARD_PROVIDEO_PV259 20
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
+#define CX88_BOARD_PCHDTV_HD3000 22
+#define CX88_BOARD_DNTV_LIVE_DVB_T 23
+#define CX88_BOARD_HAUPPAUGE_ROSLYN 24
+#define CX88_BOARD_DIGITALLOGIC_MEC 25
+#define CX88_BOARD_IODATA_GVBCTV7E 26
+#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28
+#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
+#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER 34
+#define CX88_BOARD_WINFAST_DTV1000 35
+#define CX88_BOARD_AVERTV_303 36
+#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37
+#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38
+#define CX88_BOARD_KWORLD_DVBS_100 39
+#define CX88_BOARD_HAUPPAUGE_HVR1100 40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41
+#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42
+#define CX88_BOARD_KWORLD_DVB_T_CX22702 43
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
+#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500 47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
+#define CX88_BOARD_WINFAST_DTV2000H 51
+#define CX88_BOARD_GENIATECH_DVBS 52
+#define CX88_BOARD_HAUPPAUGE_HVR3000 53
+#define CX88_BOARD_NORWOOD_MICRO 54
+#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
+#define CX88_BOARD_HAUPPAUGE_HVR1300 56
+#define CX88_BOARD_ADSTECH_PTV_390 57
+#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
+#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
+#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62
+#define CX88_BOARD_GENIATECH_X8000_MT 63
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
+#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
+#define CX88_BOARD_PROLINK_PV_8000GT 66
+#define CX88_BOARD_KWORLD_ATSC_120 67
+#define CX88_BOARD_HAUPPAUGE_HVR4000 68
+#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69
+#define CX88_BOARD_TEVII_S460 70
+#define CX88_BOARD_OMICOM_SS4_PCI 71
+#define CX88_BOARD_TBS_8920 72
+#define CX88_BOARD_TEVII_S420 73
+#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
+#define CX88_BOARD_PROF_7300 75
+#define CX88_BOARD_SATTRADE_ST4200 76
+#define CX88_BOARD_TBS_8910 77
+#define CX88_BOARD_PROF_6200 78
+#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
+#define CX88_BOARD_HAUPPAUGE_IRONLY 80
+#define CX88_BOARD_WINFAST_DTV1800H 81
+#define CX88_BOARD_WINFAST_DTV2000H_J 82
+#define CX88_BOARD_PROF_7301 83
+#define CX88_BOARD_SAMSUNG_SMT_7020 84
+#define CX88_BOARD_TWINHAN_VP1027_DVBS 85
+#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,
+ CX88_VMUX_COMPOSITE2,
+ CX88_VMUX_COMPOSITE3,
+ CX88_VMUX_COMPOSITE4,
+ CX88_VMUX_SVIDEO,
+ CX88_VMUX_TELEVISION,
+ CX88_VMUX_CABLE,
+ CX88_VMUX_DVB,
+ CX88_VMUX_DEBUG,
+ CX88_RADIO,
+};
+
+struct cx88_input {
+ enum cx88_itype type;
+ u32 gpio0, gpio1, gpio2, gpio3;
+ unsigned int vmux:2;
+ unsigned int audioroute:4;
+};
+
+struct cx88_board {
+ const char *name;
+ unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+ int tda9887_conf;
+ struct cx88_input input[MAX_CX88_INPUT];
+ struct cx88_input radio;
+ enum cx88_board_type mpeg;
+ unsigned int audio_chip;
+ int num_frontends;
+
+ /* Used for I2S devices */
+ int i2sinputcntl;
+};
+
+struct cx88_subid {
+ u16 subvendor;
+ u16 subdevice;
+ u32 card;
+};
+
+enum cx88_tvaudio {
+ WW_NONE = 1,
+ WW_BTSC,
+ WW_BG,
+ WW_DK,
+ WW_I,
+ WW_L,
+ WW_EIAJ,
+ WW_I2SPT,
+ WW_FM,
+ WW_I2SADC,
+ WW_M
+};
+
+#define INPUT(nr) (core->board.input[nr])
+
+/* ----------------------------------------------------------- */
+/* device / file handle status */
+
+#define RESOURCE_OVERLAY 1
+#define RESOURCE_VIDEO 2
+#define RESOURCE_VBI 4
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(2000)
+
+/* buffer for one video frame */
+struct cx88_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ /* cx88 specific */
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ const struct cx8800_fmt *fmt;
+ u32 count;
+};
+
+struct cx88_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+ struct btcx_riscmem stopper;
+ u32 count;
+};
+
+struct cx88_core {
+ struct list_head devlist;
+ atomic_t refcount;
+
+ /* board name */
+ int nr;
+ char name[32];
+
+ /* pci stuff */
+ int pci_bus;
+ int pci_slot;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
+ u32 shadow[SHADOW_MAX];
+ int pci_irqmask;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_state, i2c_rc;
+
+ /* config info -- analog */
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler video_hdl;
+ struct v4l2_ctrl *chroma_agc;
+ struct v4l2_ctrl_handler audio_hdl;
+ struct v4l2_subdev *sd_wm8775;
+ struct i2c_client *i2c_rtc;
+ unsigned int boardnr;
+ struct cx88_board board;
+
+ /* Supported V4L _STD_ tuner formats */
+ unsigned int tuner_formats;
+
+ /* config info -- dvb */
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+ int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+#endif
+ void (*gate_ctrl)(struct cx88_core *core, int open);
+
+ /* state info */
+ struct task_struct *kthread;
+ v4l2_std_id tvnorm;
+ enum cx88_tvaudio tvaudio;
+ u32 audiomode_manual;
+ u32 audiomode_current;
+ u32 input;
+ u32 last_analog_input;
+ u32 astat;
+ u32 use_nicam;
+ unsigned long last_change;
+
+ /* IR remote control state */
+ struct cx88_IR *ir;
+
+ /* I2C remote data */
+ struct IR_i2c_init_data init_data;
+ struct wm8775_platform_data wm8775_data;
+
+ struct mutex lock;
+ /* various v4l controls */
+ u32 freq;
+ int users;
+ int mpeg_users;
+
+ /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+ struct cx8802_dev *dvbdev;
+ enum cx88_board_type active_type_id;
+ int active_ref;
+ int active_fe_id;
+};
+
+static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
+}
+
+#define call_hw(core, grpid, o, f, args...) \
+ do { \
+ if (!core->i2c_rc) { \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 1); \
+ v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 0); \
+ } \
+ } while (0)
+
+#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
+
+#define WM8775_GID (1 << 0)
+
+#define wm8775_s_ctrl(core, id, val) \
+ do { \
+ struct v4l2_ctrl *ctrl_ = \
+ v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
+ if (ctrl_ && !core->i2c_rc) { \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 1); \
+ v4l2_ctrl_s_ctrl(ctrl_, val); \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 0); \
+ } \
+ } while (0)
+
+#define wm8775_g_ctrl(core, id) \
+ ({ \
+ struct v4l2_ctrl *ctrl_ = \
+ v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
+ s32 val = 0; \
+ if (ctrl_ && !core->i2c_rc) { \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 1); \
+ val = v4l2_ctrl_g_ctrl(ctrl_); \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 0); \
+ } \
+ val; \
+ })
+
+struct cx8800_dev;
+struct cx8802_dev;
+
+/* ----------------------------------------------------------- */
+/* function 0: video stuff */
+
+struct cx8800_fh {
+ struct v4l2_fh fh;
+ struct cx8800_dev *dev;
+ unsigned int resources;
+
+ /* video capture */
+ struct videobuf_queue vidq;
+
+ /* vbi capture */
+ struct videobuf_queue vbiq;
+};
+
+struct cx8800_suspend_state {
+ int disabled;
+};
+
+struct cx8800_dev {
+ struct cx88_core *core;
+ spinlock_t slock;
+
+ /* various device info */
+ unsigned int resources;
+ struct video_device *video_dev;
+ struct video_device *vbi_dev;
+ struct video_device *radio_dev;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+
+ const struct cx8800_fmt *fmt;
+ unsigned int width, height;
+
+ /* capture queues */
+ struct cx88_dmaqueue vidq;
+ struct cx88_dmaqueue vbiq;
+
+ /* various v4l controls */
+
+ /* other global state info */
+ struct cx8800_suspend_state state;
+};
+
+/* ----------------------------------------------------------- */
+/* function 1: audio/alsa stuff */
+/* =============> moved to cx88-alsa.c <====================== */
+
+
+/* ----------------------------------------------------------- */
+/* function 2: mpeg stuff */
+
+struct cx8802_fh {
+ struct v4l2_fh fh;
+ struct cx8802_dev *dev;
+ struct videobuf_queue mpegq;
+};
+
+struct cx8802_suspend_state {
+ int disabled;
+};
+
+struct cx8802_driver {
+ struct cx88_core *core;
+
+ /* List of drivers attached to device */
+ struct list_head drvlist;
+
+ /* Type of driver and access required */
+ enum cx88_board_type type_id;
+ enum cx8802_board_access hw_access;
+
+ /* MPEG 8802 internal only */
+ int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
+ int (*resume)(struct pci_dev *pci_dev);
+
+ /* Callers to the following functions must hold core->lock */
+
+ /* MPEG 8802 -> mini driver - Driver probe and configuration */
+ int (*probe)(struct cx8802_driver *drv);
+ int (*remove)(struct cx8802_driver *drv);
+
+ /* MPEG 8802 -> mini driver - Access for hardware control */
+ int (*advise_acquire)(struct cx8802_driver *drv);
+ int (*advise_release)(struct cx8802_driver *drv);
+
+ /* MPEG 8802 <- mini driver - Access for hardware control */
+ int (*request_acquire)(struct cx8802_driver *drv);
+ int (*request_release)(struct cx8802_driver *drv);
+};
+
+struct cx8802_dev {
+ struct cx88_core *core;
+ spinlock_t slock;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+
+ /* dma queues */
+ struct cx88_dmaqueue mpegq;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+
+ /* other global state info */
+ struct cx8802_suspend_state state;
+
+ /* for blackbird only */
+ struct list_head devlist;
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+ defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
+ struct video_device *mpeg_dev;
+ u32 mailbox;
+ int width;
+ int height;
+ unsigned char mpeg_active; /* nonzero if mpeg encoder is active */
+
+ /* mpeg params */
+ struct cx2341x_handler cxhdl;
+#endif
+
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+ /* for dvb only */
+ struct videobuf_dvb_frontends frontends;
+#endif
+
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+ defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+ /* For VP3045 secondary I2C bus support */
+ struct vp3054_i2c_state *vp3054;
+#endif
+ /* for switching modulation types */
+ unsigned char ts_gen_cntrl;
+
+ /* List of attached drivers; must hold core->lock to access */
+ struct list_head drvlist;
+
+ struct work_struct request_module_wk;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg) readl(core->lmmio + ((reg)>>2))
+#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2))
+#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg))
+
+#define cx_andor(reg,mask,value) \
+ writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), core->lmmio+((reg)>>2))
+#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
+#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
+
+#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
+
+/* shadow registers */
+#define cx_sread(sreg) (core->shadow[sreg])
+#define cx_swrite(sreg,reg,value) \
+ (core->shadow[sreg] = value, \
+ writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
+#define cx_sandor(sreg,reg,mask,value) \
+ (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
+ writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
+
+/* ----------------------------------------------------------- */
+/* cx88-core.c */
+
+extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
+ int len, u32 bits, u32 mask);
+
+extern int cx88_core_irq(struct cx88_core *core, u32 status);
+extern void cx88_wakeup(struct cx88_core *core,
+ struct cx88_dmaqueue *q, u32 count);
+extern void cx88_shutdown(struct cx88_core *core);
+extern int cx88_reset(struct cx88_core *core);
+
+extern int
+cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist,
+ unsigned int top_offset, unsigned int bottom_offset,
+ unsigned int bpl, unsigned int padding, unsigned int lines);
+extern int
+cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int bpl,
+ unsigned int lines, unsigned int lpi);
+extern int
+cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value);
+extern void
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
+
+extern void cx88_risc_disasm(struct cx88_core *core,
+ struct btcx_riscmem *risc);
+extern int cx88_sram_channel_setup(struct cx88_core *core,
+ const struct sram_channel *ch,
+ unsigned int bpl, u32 risc);
+extern void cx88_sram_channel_dump(struct cx88_core *core,
+ const struct sram_channel *ch);
+
+extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
+ unsigned int height, enum v4l2_field field);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
+
+extern struct video_device *cx88_vdev_init(struct cx88_core *core,
+ struct pci_dev *pci,
+ const struct video_device *template_,
+ const char *type);
+extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
+extern void cx88_core_put(struct cx88_core *core,
+ struct pci_dev *pci);
+
+extern int cx88_start_audio_dma(struct cx88_core *core);
+extern int cx88_stop_audio_dma(struct cx88_core *core);
+
+
+/* ----------------------------------------------------------- */
+/* cx88-vbi.c */
+
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f);
+
+/*
+int cx8800_start_vbi_dma(struct cx8800_dev *dev,
+ struct cx88_dmaqueue *q,
+ struct cx88_buffer *buf);
+*/
+int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
+int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
+ struct cx88_dmaqueue *q);
+void cx8800_vbi_timeout(unsigned long data);
+
+extern const struct videobuf_queue_ops cx8800_vbi_qops;
+
+/* ----------------------------------------------------------- */
+/* cx88-i2c.c */
+
+extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+
+
+/* ----------------------------------------------------------- */
+/* cx88-cards.c */
+
+extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
+extern int cx88_get_resources(const struct cx88_core *core,
+ struct pci_dev *pci);
+extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
+extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
+
+/* ----------------------------------------------------------- */
+/* cx88-tvaudio.c */
+
+void cx88_set_tvaudio(struct cx88_core *core);
+void cx88_newstation(struct cx88_core *core);
+void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
+int cx88_audio_thread(void *data);
+
+int cx8802_register_driver(struct cx8802_driver *drv);
+int cx8802_unregister_driver(struct cx8802_driver *drv);
+
+/* Caller must hold core->lock */
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
+
+/* ----------------------------------------------------------- */
+/* cx88-dsp.c */
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
+/* cx88-input.c */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
+int cx88_ir_fini(struct cx88_core *core);
+void cx88_ir_irq(struct cx88_core *core);
+int cx88_ir_start(struct cx88_core *core);
+void cx88_ir_stop(struct cx88_core *core);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
+/* cx88-mpeg.c */
+
+int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
+ struct cx88_buffer *buf, enum v4l2_field field);
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
+void cx8802_cancel_buffers(struct cx8802_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* cx88-video.c*/
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
+void cx88_querycap(struct file *file, struct cx88_core *core,
+ struct v4l2_capability *cap);
diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
new file mode 100644
index 000000000000..44e5dc15e60a
--- /dev/null
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -0,0 +1,18 @@
+config DVB_DDBRIDGE
+ tristate "Digital Devices bridge support"
+ depends on DVB_CORE && PCI && I2C
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ Support for cards with the Digital Devices PCI express bridge:
+ - Octopus PCIe Bridge
+ - Octopus mini PCIe Bridge
+ - Octopus LE
+ - DuoFlex S2 Octopus
+ - DuoFlex CT Octopus
+ - cineS2(v6)
+
+ Say Y if you own such a card and want to use it.
diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
new file mode 100644
index 000000000000..7446c8b677b5
--- /dev/null
+++ b/drivers/media/pci/ddbridge/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the ddbridge device driver
+#
+
+ddbridge-objs := ddbridge-core.o
+
+obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
+
+# For the staging CI driver cxd2099
+ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index ebf3f05839d2..ebf3f05839d2 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h
index a3ccb318b500..a3ccb318b500 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-regs.h
+++ b/drivers/media/pci/ddbridge/ddbridge-regs.h
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 8b1b41d2a52d..8b1b41d2a52d 100644
--- a/drivers/media/dvb/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig
new file mode 100644
index 000000000000..013df4e015cd
--- /dev/null
+++ b/drivers/media/pci/dm1105/Kconfig
@@ -0,0 +1,20 @@
+config DVB_DM1105
+ tristate "SDMC DM1105 based PCI cards"
+ depends on DVB_CORE && PCI && I2C
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ depends on RC_CORE
+ help
+ Support for cards based on the SDMC DM1105 PCI chip like
+ DvbWorld 2002
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the PCI bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/dm1105/Makefile b/drivers/media/pci/dm1105/Makefile
new file mode 100644
index 000000000000..327585143c83
--- /dev/null
+++ b/drivers/media/pci/dm1105/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DM1105) += dm1105.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index a609b3a9b146..a609b3a9b146 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig
index 89f65914cc8e..89f65914cc8e 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/pci/ivtv/Kconfig
diff --git a/drivers/media/pci/ivtv/Makefile b/drivers/media/pci/ivtv/Makefile
new file mode 100644
index 000000000000..1408c9f1de93
--- /dev/null
+++ b/drivers/media/pci/ivtv/Makefile
@@ -0,0 +1,14 @@
+ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
+ ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
+ ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
+ ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
+ ivtv-vbi.o ivtv-yuv.o
+
+obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c
index 145e4749a69d..145e4749a69d 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/pci/ivtv/ivtv-cards.c
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h
index e6f5c02981f1..e6f5c02981f1 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/pci/ivtv/ivtv-cards.h
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index c60424601cb9..c60424601cb9 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/pci/ivtv/ivtv-controls.h
index 3999e6358312..3999e6358312 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/pci/ivtv/ivtv-controls.h
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index 5462ce2f60ea..5462ce2f60ea 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
index a7e00f8938f8..a7e00f8938f8 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
new file mode 100644
index 000000000000..88bce907cdef
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -0,0 +1,1070 @@
+/*
+ file operation functions
+ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
+ Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ Copyright (C) 2005-2007 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
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-vbi.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-routing.h"
+#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include "ivtv-firmware.h"
+#include <media/v4l2-event.h>
+#include <media/saa7115.h>
+
+/* This function tries to claim the stream for a specific file descriptor.
+ If no one else is using this stream then the stream is claimed and
+ associated VBI streams are also automatically claimed.
+ Possible error returns: -EBUSY if someone else has claimed
+ the stream or 0 on success. */
+static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
+{
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[type];
+ struct ivtv_stream *s_vbi;
+ int vbi_type;
+
+ if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+ /* someone already claimed this stream */
+ if (s->fh == &id->fh) {
+ /* yes, this file descriptor did. So that's OK. */
+ return 0;
+ }
+ 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->fh = &id->fh;
+ IVTV_DEBUG_INFO("Start Read VBI\n");
+ return 0;
+ }
+ /* someone else is using this stream already */
+ IVTV_DEBUG_INFO("Stream %d is busy\n", type);
+ return -EBUSY;
+ }
+ 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);
+ }
+
+ /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI,
+ IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI
+ (provided VBI insertion is on and sliced VBI is selected), for all
+ other streams we're done */
+ if (type == IVTV_DEC_STREAM_TYPE_MPG) {
+ vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
+ } else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
+ itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
+ vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
+ } else {
+ return 0;
+ }
+ s_vbi = &itv->streams[vbi_type];
+
+ if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) {
+ /* Enable reinsertion interrupt */
+ if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI)
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+ }
+ /* mark that it is used internally */
+ set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags);
+ return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+ account associated VBI streams. */
+void ivtv_release_stream(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+ struct ivtv_stream *s_vbi;
+
+ 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 */
+ return;
+ }
+ if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+ IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+ return;
+ }
+
+ ivtv_flush_queues(s);
+
+ /* disable reinsertion interrupt */
+ if (s->type == IVTV_DEC_STREAM_TYPE_VBI)
+ ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+
+ /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI,
+ IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI,
+ for all other streams we're done */
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+ s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
+ else if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+ s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+ else
+ return;
+
+ /* clear internal use flag */
+ if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+ /* was already cleared */
+ return;
+ }
+ if (s_vbi->fh) {
+ /* VBI stream still claimed by a file descriptor */
+ return;
+ }
+ /* disable reinsertion interrupt */
+ if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI)
+ ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+ clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags);
+ ivtv_flush_queues(s_vbi);
+}
+
+static void ivtv_dualwatch(struct ivtv *itv)
+{
+ struct v4l2_tuner vt;
+ u32 new_stereo_mode;
+ const u32 dual = 0x02;
+
+ new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
+ memset(&vt, 0, sizeof(vt));
+ ivtv_call_all(itv, tuner, g_tuner, &vt);
+ if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+ new_stereo_mode = dual;
+
+ if (new_stereo_mode == itv->dualwatch_stereo_mode)
+ return;
+
+ IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+ itv->dualwatch_stereo_mode, new_stereo_mode);
+ if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode))
+ IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+static void ivtv_update_pgm_info(struct ivtv *itv)
+{
+ u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24;
+ int cnt;
+ int i = 0;
+
+ if (wr_idx >= itv->pgm_info_num) {
+ IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num);
+ return;
+ }
+ cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num;
+ while (i < cnt) {
+ int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+ struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
+ u32 addr = itv->pgm_info_offset + 4 + idx * 24;
+ const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
+ V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
+ // 1=I, 2=P, 4=B
+
+ e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
+ if (e->offset > itv->mpg_data_received) {
+ break;
+ }
+ e->offset += itv->vbi_data_inserted;
+ e->length = read_enc(addr);
+ e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
+ e->flags = mapping[read_enc(addr + 12) & 7];
+ i++;
+ }
+ itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+}
+
+static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
+{
+ struct ivtv *itv = s->itv;
+ struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+ struct ivtv_buffer *buf;
+ DEFINE_WAIT(wait);
+
+ *err = 0;
+ while (1) {
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG) {
+ /* Process pending program info updates and pending VBI data */
+ ivtv_update_pgm_info(itv);
+
+ if (time_after(jiffies,
+ itv->dualwatch_jiffies +
+ msecs_to_jiffies(1000))) {
+ itv->dualwatch_jiffies = jiffies;
+ ivtv_dualwatch(itv);
+ }
+
+ if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+ while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) {
+ /* byteswap and process VBI data */
+ ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type);
+ ivtv_enqueue(s_vbi, buf, &s_vbi->q_free);
+ }
+ }
+ buf = &itv->vbi.sliced_mpeg_buf;
+ if (buf->readpos != buf->bytesused) {
+ return buf;
+ }
+ }
+
+ /* do we have leftover data? */
+ buf = ivtv_dequeue(s, &s->q_io);
+ if (buf)
+ return buf;
+
+ /* do we have new data? */
+ buf = ivtv_dequeue(s, &s->q_full);
+ if (buf) {
+ if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
+ return buf;
+ buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+ /* byteswap MPG data */
+ ivtv_buf_swap(buf);
+ else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) {
+ /* byteswap and process VBI data */
+ ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type);
+ }
+ return buf;
+ }
+
+ /* return if end of stream */
+ if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ IVTV_DEBUG_INFO("EOS %s\n", s->name);
+ return NULL;
+ }
+
+ /* return if file was opened with O_NONBLOCK */
+ if (non_block) {
+ *err = -EAGAIN;
+ return NULL;
+ }
+
+ /* 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);
+ *err = -EINTR;
+ return NULL;
+ }
+ }
+}
+
+static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv)
+{
+ int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+
+ itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx];
+ itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx];
+ itv->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf,
+ char __user *ubuf, size_t ucount)
+{
+ struct ivtv *itv = s->itv;
+ size_t len = buf->bytesused - buf->readpos;
+
+ if (len > ucount) len = ucount;
+ if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+ !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
+ const char *start = buf->buf + buf->readpos;
+ const char *p = start + 1;
+ const u8 *q;
+ u8 ch = itv->search_pack_header ? 0xba : 0xe0;
+ int stuffing, i;
+
+ while (start + len > p && (q = memchr(p, 0, start + len - p))) {
+ p = q + 1;
+ if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+ q[1] != 0 || q[2] != 1 || q[3] != ch) {
+ continue;
+ }
+ if (!itv->search_pack_header) {
+ if ((q[6] & 0xc0) != 0x80)
+ continue;
+ if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) ||
+ ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) {
+ ch = 0xba;
+ itv->search_pack_header = 1;
+ p = q + 9;
+ }
+ continue;
+ }
+ stuffing = q[13] & 7;
+ /* all stuffing bytes must be 0xff */
+ for (i = 0; i < stuffing; i++)
+ if (q[14 + i] != 0xff)
+ break;
+ if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 &&
+ q[14 + stuffing] == 0 && q[15 + stuffing] == 0 &&
+ q[16 + stuffing] == 1) {
+ itv->search_pack_header = 0;
+ len = (char *)q - start;
+ ivtv_setup_sliced_vbi_buf(itv);
+ break;
+ }
+ }
+ }
+ if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+ IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name);
+ return -EFAULT;
+ }
+ /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount,
+ buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len,
+ buf == &itv->vbi.sliced_mpeg_buf); */
+ buf->readpos += len;
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf)
+ itv->mpg_data_received += len;
+ return len;
+}
+
+static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block)
+{
+ struct ivtv *itv = s->itv;
+ size_t tot_written = 0;
+ int single_frame = 0;
+
+ 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;
+ }
+
+ /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
+ arrive one-by-one, so make sure we never output more than one VBI frame at a time */
+ if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
+ (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
+ single_frame = 1;
+
+ for (;;) {
+ struct ivtv_buffer *buf;
+ int rc;
+
+ buf = ivtv_get_buffer(s, non_block, &rc);
+ /* if there is no data available... */
+ if (buf == NULL) {
+ /* if we got data, then return that regardless */
+ if (tot_written)
+ break;
+ /* EOS condition */
+ if (rc == 0) {
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ ivtv_release_stream(s);
+ }
+ /* set errno */
+ return rc;
+ }
+ rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
+ if (buf != &itv->vbi.sliced_mpeg_buf) {
+ ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
+ }
+ else if (buf->readpos == buf->bytesused) {
+ int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+ itv->vbi.sliced_mpeg_size[idx] = 0;
+ itv->vbi.inserted_frame++;
+ itv->vbi_data_inserted += buf->bytesused;
+ }
+ if (rc < 0)
+ return rc;
+ tot_written += rc;
+
+ if (tot_written == tot_count || single_frame)
+ break;
+ }
+ return tot_written;
+}
+
+static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count,
+ loff_t *pos, int non_block)
+{
+ ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
+ struct ivtv *itv = s->itv;
+
+ IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+ if (rc > 0)
+ pos += rc;
+ return rc;
+}
+
+int ivtv_start_capture(struct ivtv_open_id *id)
+{
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ struct ivtv_stream *s_vbi;
+
+ if (s->type == IVTV_ENC_STREAM_TYPE_RAD ||
+ s->type == IVTV_DEC_STREAM_TYPE_MPG ||
+ s->type == IVTV_DEC_STREAM_TYPE_YUV ||
+ s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+ /* you cannot read from these stream types. */
+ return -EPERM;
+ }
+
+ /* Try to claim this stream. */
+ if (ivtv_claim_stream(id, s->type))
+ return -EBUSY;
+
+ /* This stream does not need to start capturing */
+ if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+ set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ return 0;
+ }
+
+ /* If capture is already in progress, then we also have to
+ do nothing extra. */
+ if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ return 0;
+ }
+
+ /* Start VBI capture if required */
+ s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+ test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+ /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed
+ automatically when the MPG stream is claimed.
+ We only need to start the VBI capturing. */
+ if (ivtv_start_v4l2_encode_stream(s_vbi)) {
+ IVTV_DEBUG_WARN("VBI capture start failed\n");
+
+ /* Failure, clean up and return an error */
+ clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ /* also releases the associated VBI stream */
+ ivtv_release_stream(s);
+ return -EIO;
+ }
+ IVTV_DEBUG_INFO("VBI insertion started\n");
+ }
+
+ /* Tell the card to start capturing */
+ if (!ivtv_start_v4l2_encode_stream(s)) {
+ /* We're done */
+ set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ /* Resume a possibly paused encoder */
+ if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+ ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+ return 0;
+ }
+
+ /* failure, clean up */
+ IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+ /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released
+ automatically when the MPG stream is released.
+ We only need to stop the VBI capturing. */
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+ test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+ ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+ clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+ }
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ ivtv_release_stream(s);
+ return -EIO;
+}
+
+ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos)
+{
+ struct ivtv_open_id *id = fh2id(filp->private_data);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ ssize_t rc;
+
+ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+ if (mutex_lock_interruptible(&itv->serialize_lock))
+ return -ERESTARTSYS;
+ rc = ivtv_start_capture(id);
+ if (!rc)
+ rc = ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+ mutex_unlock(&itv->serialize_lock);
+ return rc;
+}
+
+int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
+{
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ int rc;
+
+ if (atomic_read(&itv->decoding) == 0) {
+ if (ivtv_claim_stream(id, s->type)) {
+ /* someone else is using this stream already */
+ IVTV_DEBUG_WARN("start decode, stream already claimed\n");
+ return -EBUSY;
+ }
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0) {
+ if (rc == -EAGAIN)
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0)
+ return rc;
+ }
+ }
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+ return ivtv_set_speed(itv, speed);
+ return 0;
+}
+
+static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+ struct ivtv_open_id *id = fh2id(filp->private_data);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ struct yuv_playback_info *yi = &itv->yuv_info;
+ struct ivtv_buffer *buf;
+ struct ivtv_queue q;
+ int bytes_written = 0;
+ int mode;
+ int rc;
+ DEFINE_WAIT(wait);
+
+ IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
+
+ if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
+ s->type != IVTV_DEC_STREAM_TYPE_YUV &&
+ s->type != IVTV_DEC_STREAM_TYPE_VOUT)
+ /* not decoder streams */
+ return -EPERM;
+
+ /* Try to claim this stream */
+ if (ivtv_claim_stream(id, s->type))
+ return -EBUSY;
+
+ /* This stream does not need to start any decoding */
+ if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+ int elems = count / sizeof(struct v4l2_sliced_vbi_data);
+
+ set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ return ivtv_write_vbi_from_user(itv,
+ (const struct v4l2_sliced_vbi_data __user *)user_buf, elems);
+ }
+
+ mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
+
+ if (ivtv_set_output_mode(itv, mode) != mode) {
+ ivtv_release_stream(s);
+ return -EBUSY;
+ }
+ ivtv_queue_init(&q);
+ set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+
+ /* Start decoder (returns 0 if already started) */
+ rc = ivtv_start_decoding(id, itv->speed);
+ if (rc) {
+ IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
+
+ /* failure, clean up */
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ return rc;
+ }
+
+retry:
+ /* If possible, just DMA the entire frame - Check the data transfer size
+ since we may get here before the stream has been fully set-up */
+ if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
+ while (count >= itv->dma_data_req_size) {
+ rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
+
+ if (rc < 0)
+ return rc;
+
+ bytes_written += itv->dma_data_req_size;
+ user_buf += itv->dma_data_req_size;
+ count -= itv->dma_data_req_size;
+ }
+ if (count == 0) {
+ IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ return bytes_written;
+ }
+ }
+
+ for (;;) {
+ /* Gather buffers */
+ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
+ ivtv_enqueue(s, buf, &q);
+ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) {
+ ivtv_enqueue(s, buf, &q);
+ }
+ if (q.buffers)
+ 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;
+ }
+ }
+
+ /* copy user data into buffers */
+ while ((buf = ivtv_dequeue(s, &q))) {
+ /* yuv is a pain. Don't copy more data than needed for a single
+ frame, otherwise we lose sync with the incoming stream */
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+ yi->stream_size + count > itv->dma_data_req_size)
+ rc = ivtv_buf_copy_from_user(s, buf, user_buf,
+ itv->dma_data_req_size - yi->stream_size);
+ else
+ rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+
+ /* Make sure we really got all the user data */
+ if (rc < 0) {
+ ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
+ return rc;
+ }
+ user_buf += rc;
+ count -= rc;
+ bytes_written += rc;
+
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ yi->stream_size += rc;
+ /* If we have a complete yuv frame, break loop now */
+ if (yi->stream_size == itv->dma_data_req_size) {
+ ivtv_enqueue(s, buf, &s->q_full);
+ yi->stream_size = 0;
+ break;
+ }
+ }
+
+ if (buf->bytesused != s->buf_size) {
+ /* incomplete, leave in q_io for next time */
+ ivtv_enqueue(s, buf, &s->q_io);
+ break;
+ }
+ /* Byteswap MPEG buffer */
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+ ivtv_buf_swap(buf);
+ ivtv_enqueue(s, buf, &s->q_full);
+ }
+
+ if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
+ if (s->q_full.length >= itv->dma_data_req_size) {
+ int got_sig;
+
+ 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;
+ }
+
+ clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+ ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+ ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1);
+ }
+ }
+ /* more user data is available, wait until buffers become free
+ to transfer the rest. */
+ if (count && !(filp->f_flags & O_NONBLOCK))
+ goto retry;
+ IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ return bytes_written;
+}
+
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+ struct ivtv_open_id *id = fh2id(filp->private_data);
+ struct ivtv *itv = id->itv;
+ ssize_t res;
+
+ if (mutex_lock_interruptible(&itv->serialize_lock))
+ return -ERESTARTSYS;
+ res = ivtv_write(filp, user_buf, count, pos);
+ mutex_unlock(&itv->serialize_lock);
+ return res;
+}
+
+unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
+{
+ struct ivtv_open_id *id = fh2id(filp->private_data);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ int res = 0;
+
+ /* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Decoder poll\n");
+
+ /* If there are subscribed events, then only use the new event
+ API instead of the old video.h based API. */
+ if (!list_empty(&id->fh.subscribed)) {
+ poll_wait(filp, &id->fh.wait, wait);
+ /* Turn off the old-style vsync events */
+ clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+ if (v4l2_event_pending(&id->fh))
+ res = POLLPRI;
+ } else {
+ /* This is the old-style API which is here only for backwards
+ compatibility. */
+ poll_wait(filp, &s->waitq, wait);
+ set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+ if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
+ test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+ res = POLLPRI;
+ }
+
+ /* Allow write if buffers are available for writing */
+ if (s->q_free.buffers)
+ res |= POLLOUT | POLLWRNORM;
+ return res;
+}
+
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+ unsigned long req_events = poll_requested_events(wait);
+ struct ivtv_open_id *id = fh2id(filp->private_data);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+ int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ unsigned res = 0;
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
+ 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);
+ return POLLERR;
+ }
+ IVTV_DEBUG_FILE("Encoder poll started capture\n");
+ }
+
+ /* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Encoder poll\n");
+ poll_wait(filp, &s->waitq, wait);
+ if (v4l2_event_pending(&id->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(filp, &id->fh.wait, wait);
+
+ if (s->q_full.length || s->q_io.length)
+ return res | POLLIN | POLLRDNORM;
+ if (eof)
+ return res | POLLHUP;
+ return res;
+}
+
+void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
+{
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
+
+ /* 'Unclaim' this stream */
+
+ /* Stop capturing */
+ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+
+ IVTV_DEBUG_INFO("close stopping capture\n");
+ /* Special case: a running VBI capture for VBI insertion
+ in the mpeg stream. Need to stop that too. */
+ if (id->type == IVTV_ENC_STREAM_TYPE_MPG &&
+ test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+ IVTV_DEBUG_INFO("close stopping embedded VBI capture\n");
+ ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+ }
+ if ((id->type == IVTV_DEC_STREAM_TYPE_VBI ||
+ 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->fh = NULL;
+ }
+ else {
+ ivtv_stop_v4l2_encode_stream(s, gop_end);
+ }
+ }
+ if (!gop_end) {
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ ivtv_release_stream(s);
+ }
+}
+
+static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
+{
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
+
+ if (id->type == IVTV_DEC_STREAM_TYPE_YUV &&
+ test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
+ /* Restore registers we've changed & clean up any mess */
+ ivtv_yuv_close(itv);
+ }
+
+ /* Stop decoding */
+ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ IVTV_DEBUG_INFO("close stopping decode\n");
+
+ ivtv_stop_v4l2_decode_stream(s, flags, pts);
+ itv->output_mode = OUT_NONE;
+ }
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+ if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
+ itv->output_mode = OUT_NONE;
+
+ itv->speed = 0;
+ clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
+ ivtv_release_stream(s);
+}
+
+int ivtv_v4l2_close(struct file *filp)
+{
+ struct v4l2_fh *fh = filp->private_data;
+ struct ivtv_open_id *id = fh2id(fh);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
+
+ IVTV_DEBUG_FILE("close %s\n", s->name);
+
+ mutex_lock(&itv->serialize_lock);
+
+ /* Stop radio */
+ 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 */
+ clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+ /* Switch tuner to TV */
+ ivtv_call_all(itv, core, s_std, itv->std);
+ /* Select correct audio input (i.e. TV tuner or Line in) */
+ ivtv_audio_set_io(itv);
+ if (itv->hw_flags & IVTV_HW_SAA711X) {
+ ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
+ SAA7115_FREQ_32_11_MHZ, 0);
+ }
+ 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));
+ }
+ /* Done! Unmute and continue. */
+ ivtv_unmute(itv);
+ }
+
+ v4l2_fh_del(fh);
+ v4l2_fh_exit(fh);
+
+ /* Easy case first: this stream was never claimed by us */
+ if (s->fh != &id->fh)
+ goto close_done;
+
+ /* '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, 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. */
+ if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
+ /* disable CC on TV-out */
+ ivtv_disable_cc(itv);
+ }
+ } else {
+ ivtv_stop_capture(id, 0);
+ }
+close_done:
+ kfree(id);
+ mutex_unlock(&itv->serialize_lock);
+ return 0;
+}
+
+static int ivtv_open(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ 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) {
+ IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+ video_device_node_name(vdev));
+ IVTV_WARN("Selected firmware errors will be ignored\n");
+ } else {
+#else
+ if (1) {
+#endif
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res == -EAGAIN)
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res < 0)
+ return -EIO;
+ }
+
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
+ test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
+ return -EBUSY;
+
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+ test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
+ return -EBUSY;
+
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ if (read_reg(0x82c) == 0) {
+ IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
+ /* return -ENODEV; */
+ }
+ ivtv_udma_alloc(itv);
+ }
+
+ /* Allocate memory */
+ item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+ if (NULL == item) {
+ IVTV_DEBUG_WARN("nomem on v4l2 open\n");
+ return -ENOMEM;
+ }
+ v4l2_fh_init(&item->fh, s->vdev);
+ item->itv = itv;
+ item->type = s->type;
+
+ filp->private_data = &item->fh;
+ v4l2_fh_add(&item->fh);
+
+ 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 */
+ v4l2_fh_del(&item->fh);
+ v4l2_fh_exit(&item->fh);
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+ /* Mark that the radio is being used. */
+ set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+ /* We have the radio */
+ ivtv_mute(itv);
+ /* Switch tuner to radio */
+ ivtv_call_all(itv, tuner, s_radio);
+ /* Select the correct audio input (i.e. radio tuner) */
+ ivtv_audio_set_io(itv);
+ if (itv->hw_flags & IVTV_HW_SAA711X) {
+ ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
+ SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL);
+ }
+ /* Done! Unmute and continue. */
+ ivtv_unmute(itv);
+ }
+
+ /* YUV or MPG Decoding Mode? */
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
+ clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+ } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+ /* For yuv, we need to know the dma size before we start */
+ itv->dma_data_req_size =
+ 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+ itv->yuv_info.stream_size = 0;
+ }
+ return 0;
+}
+
+int ivtv_v4l2_open(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int res;
+
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ res = ivtv_open(filp);
+ mutex_unlock(vdev->lock);
+ return res;
+}
+
+void ivtv_mute(struct ivtv *itv)
+{
+ if (atomic_read(&itv->capturing))
+ ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
+ IVTV_DEBUG_INFO("Mute\n");
+}
+
+void ivtv_unmute(struct ivtv *itv)
+{
+ if (atomic_read(&itv->capturing)) {
+ ivtv_msleep_timeout(100, 0);
+ ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+ ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
+ }
+ IVTV_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/pci/ivtv/ivtv-fileops.h
index 049a2923965d..049a2923965d 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/drivers/media/pci/ivtv/ivtv-fileops.h
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
new file mode 100644
index 000000000000..6ec7705af555
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -0,0 +1,402 @@
+/*
+ ivtv firmware functions.
+ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
+ Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ Copyright (C) 2005-2007 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
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include <linux/firmware.h>
+#include <media/saa7127.h>
+
+#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
+#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
+#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB
+#define IVTV_CMD_VDM_STOP 0x00000000
+#define IVTV_CMD_AO_STOP 0x00000005
+#define IVTV_CMD_APU_PING 0x00000000
+#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE
+#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+#define IVTV_CMD_SPU_STOP 0x00000001
+#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
+#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
+#define IVTV_SDRAM_SLEEPTIME 600
+
+#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg"
+#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024)
+
+/* Encoder/decoder firmware sizes */
+#define IVTV_FW_ENC_SIZE (376836)
+#define IVTV_FW_DEC_SIZE (256*1024)
+
+static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+
+retry:
+ if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
+ int i;
+ volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
+ const u32 *src = (const u32 *)fw->data;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with udev <0.95)
+ the wrong file was sometimes loaded. So we check filesizes to
+ see if at least the right-sized file was loaded. If not, then we
+ retry. */
+ IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ for (i = 0; i < fw->size; i += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(*src, dst);
+ dst++;
+ src++;
+ }
+ IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ release_firmware(fw);
+ return size;
+ }
+ IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+ IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+}
+
+void ivtv_halt_firmware(struct ivtv *itv)
+{
+ IVTV_DEBUG_INFO("Preparing for firmware halt.\n");
+ if (itv->has_cx23415 && itv->dec_mbox.mbox)
+ ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0);
+ if (itv->enc_mbox.mbox)
+ ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
+
+ ivtv_msleep_timeout(10, 0);
+ itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
+
+ IVTV_DEBUG_INFO("Stopping VDM\n");
+ write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM);
+
+ IVTV_DEBUG_INFO("Stopping AO\n");
+ write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO);
+
+ IVTV_DEBUG_INFO("pinging (?) APU\n");
+ write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU);
+
+ IVTV_DEBUG_INFO("Stopping VPU\n");
+ if (!itv->has_cx23415)
+ write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU);
+ else
+ write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU);
+
+ IVTV_DEBUG_INFO("Resetting Hw Blocks\n");
+ write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS);
+
+ IVTV_DEBUG_INFO("Stopping SPU\n");
+ write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
+
+ ivtv_msleep_timeout(10, 0);
+
+ IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
+ write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
+
+ IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n");
+ write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH);
+
+ if (itv->has_cx23415) {
+ IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n");
+ write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE);
+
+ IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n");
+ write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
+ }
+
+ IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+ ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+}
+
+void ivtv_firmware_versions(struct ivtv *itv)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+
+ /* Encoder */
+ ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0);
+ IVTV_INFO("Encoder revision: 0x%08x\n", data[0]);
+
+ if (data[0] != 0x02060039)
+ IVTV_WARN("Recommended firmware version is 0x02060039.\n");
+
+ if (itv->has_cx23415) {
+ /* Decoder */
+ ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0);
+ IVTV_INFO("Decoder revision: 0x%08x\n", data[0]);
+ }
+}
+
+static int ivtv_firmware_copy(struct ivtv *itv)
+{
+ IVTV_DEBUG_INFO("Loading encoder image\n");
+ if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME,
+ itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) {
+ IVTV_DEBUG_WARN("failed loading encoder firmware\n");
+ return -3;
+ }
+ if (!itv->has_cx23415)
+ return 0;
+
+ IVTV_DEBUG_INFO("Loading decoder image\n");
+ if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME,
+ itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) {
+ IVTV_DEBUG_WARN("failed loading decoder firmware\n");
+ return -1;
+ }
+ return 0;
+}
+
+static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size)
+{
+ int i;
+
+ /* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte
+ address boundary */
+ for (i = 0; i < size; i += 0x100) {
+ if (readl(mem + i) == 0x12345678 &&
+ readl(mem + i + 4) == 0x34567812 &&
+ readl(mem + i + 8) == 0x56781234 &&
+ readl(mem + i + 12) == 0x78123456) {
+ return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16);
+ }
+ }
+ return NULL;
+}
+
+int ivtv_firmware_init(struct ivtv *itv)
+{
+ int err;
+
+ ivtv_halt_firmware(itv);
+
+ /* load firmware */
+ err = ivtv_firmware_copy(itv);
+ if (err) {
+ IVTV_DEBUG_WARN("Error %d loading firmware\n", err);
+ return err;
+ }
+
+ /* start firmware */
+ write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
+ ivtv_msleep_timeout(100, 0);
+ if (itv->has_cx23415)
+ write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
+ else
+ write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
+ ivtv_msleep_timeout(100, 0);
+
+ /* find mailboxes and ping firmware */
+ itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
+ if (itv->enc_mbox.mbox == NULL)
+ IVTV_ERR("Encoder mailbox not found\n");
+ else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) {
+ IVTV_ERR("Encoder firmware dead!\n");
+ itv->enc_mbox.mbox = NULL;
+ }
+ if (itv->enc_mbox.mbox == NULL)
+ return -ENODEV;
+
+ if (!itv->has_cx23415)
+ return 0;
+
+ itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE);
+ if (itv->dec_mbox.mbox == NULL) {
+ IVTV_ERR("Decoder mailbox not found\n");
+ } else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) {
+ IVTV_ERR("Decoder firmware dead!\n");
+ itv->dec_mbox.mbox = NULL;
+ } else {
+ /* Firmware okay, so check yuv output filter table */
+ ivtv_yuv_filter_check(itv);
+ }
+ return itv->dec_mbox.mbox ? 0 : -ENODEV;
+}
+
+void ivtv_init_mpeg_decoder(struct ivtv *itv)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ long readbytes;
+ volatile u8 __iomem *mem_offset;
+
+ data[0] = 0;
+ data[1] = itv->cxhdl.width; /* YUV source width */
+ data[2] = itv->cxhdl.height;
+ data[3] = itv->cxhdl.audio_properties; /* Audio settings to use,
+ bitmap. see docs. */
+ if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) {
+ IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n");
+ return;
+ }
+
+ if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) {
+ IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n");
+ return;
+ }
+ ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
+ mem_offset = itv->dec_mem + data[1];
+
+ if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME,
+ mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) {
+ IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n",
+ IVTV_DECODE_INIT_MPEG_FILENAME);
+ } else {
+ ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
+ ivtv_msleep_timeout(100, 0);
+ }
+ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
+}
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+ int rc = 0;
+ v4l2_std_id std;
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+ /* Display test image during restart */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_TEST_IMAGE,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+
+ mutex_lock(&itv->udma.lock);
+
+ rc = ivtv_firmware_init(itv);
+ if (rc) {
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+ }
+
+ /* Allow settings to reload */
+ ivtv_mailbox_cache_invalidate(itv);
+
+ /* Restore encoder video standard */
+ std = itv->std;
+ itv->std = 0;
+ ivtv_s_std_enc(itv, &std);
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+
+ /* Restore decoder video standard */
+ std = itv->std_out;
+ itv->std_out = 0;
+ ivtv_s_std_dec(itv, &std);
+
+ /* Restore framebuffer if active */
+ if (itv->ivtvfb_restore)
+ itv->ivtvfb_restore(itv);
+
+ /* Restore alpha settings */
+ ivtv_set_osd_alpha(itv);
+
+ /* Restore normal output */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_NORMAL,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+ }
+
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+}
+
+/* Check firmware running state. The checks fall through
+ allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+ int res = 0;
+
+ /* Check encoder is still running */
+ if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+ IVTV_WARN("Encoder has died : %s\n", where);
+ res = -1;
+ }
+
+ /* Also check audio. Only check if not in use & encoder is okay */
+ if (!res && !atomic_read(&itv->capturing) &&
+ (!atomic_read(&itv->decoding) ||
+ (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+ &itv->i_flags)))) {
+
+ if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+ IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+ res = -2;
+ }
+ }
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ /* Second audio check. Skip if audio already failed */
+ if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+ /* Wait & try again to be certain. */
+ ivtv_msleep_timeout(14, 0);
+ if (read_dec(0x100) != read_dec(0x104)) {
+ IVTV_WARN("Audio has died (Decoder) : %s\n",
+ where);
+ res = -1;
+ }
+ }
+
+ /* Check decoder is still running */
+ if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+ IVTV_WARN("Decoder has died : %s\n", where);
+ res = -1;
+ }
+ }
+
+ /* If something failed & currently idle, try to reload */
+ if (res && !atomic_read(&itv->capturing) &&
+ !atomic_read(&itv->decoding)) {
+ IVTV_INFO("Detected in %s that firmware had failed - "
+ "Reloading\n", where);
+ res = ivtv_firmware_restart(itv);
+ /*
+ * Even if restarted ok, still signal a problem had occurred.
+ * The caller can come through this function again to check
+ * if things are really ok after the restart.
+ */
+ if (!res) {
+ IVTV_INFO("Firmware restart okay\n");
+ res = -EAGAIN;
+ } else {
+ IVTV_INFO("Firmware restart failed\n");
+ }
+ } else if (res) {
+ res = -EIO;
+ }
+
+ return res;
+}
+
+MODULE_FIRMWARE(CX2341X_FIRM_ENC_FILENAME);
+MODULE_FIRMWARE(CX2341X_FIRM_DEC_FILENAME);
+MODULE_FIRMWARE(IVTV_DECODE_INIT_MPEG_FILENAME);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/pci/ivtv/ivtv-firmware.h
index 52bb4e5598fd..52bb4e5598fd 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/pci/ivtv/ivtv-firmware.h
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c
index 8f0d07789053..8f0d07789053 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/pci/ivtv/ivtv-gpio.c
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/pci/ivtv/ivtv-gpio.h
index 0b5d19c8ecb4..0b5d19c8ecb4 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/pci/ivtv/ivtv-gpio.h
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index d47f41a0ef66..d47f41a0ef66 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/pci/ivtv/ivtv-i2c.h
index 7b9ec1cfeb80..7b9ec1cfeb80 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/pci/ivtv/ivtv-i2c.h
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 32a591062d0b..32a591062d0b 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h
index 7c553d16579b..7c553d16579b 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.h
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index 1b3b9578bf47..1b3b9578bf47 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h
index 1e84433737cc..1e84433737cc 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/pci/ivtv/ivtv-irq.h
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/pci/ivtv/ivtv-mailbox.c
index e3ce96763785..e3ce96763785 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/pci/ivtv/ivtv-mailbox.c
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/pci/ivtv/ivtv-mailbox.h
index 2c834d2cb56f..2c834d2cb56f 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/pci/ivtv/ivtv-mailbox.h
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/pci/ivtv/ivtv-queue.c
index 7fde36e6d227..7fde36e6d227 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/pci/ivtv/ivtv-queue.c
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/pci/ivtv/ivtv-queue.h
index 91233839a26c..91233839a26c 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/pci/ivtv/ivtv-queue.h
diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/pci/ivtv/ivtv-routing.c
index 8898c569a1c9..8898c569a1c9 100644
--- a/drivers/media/video/ivtv/ivtv-routing.c
+++ b/drivers/media/pci/ivtv/ivtv-routing.c
diff --git a/drivers/media/video/ivtv/ivtv-routing.h b/drivers/media/pci/ivtv/ivtv-routing.h
index c72a9731ca01..c72a9731ca01 100644
--- a/drivers/media/video/ivtv/ivtv-routing.h
+++ b/drivers/media/pci/ivtv/ivtv-routing.h
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
new file mode 100644
index 000000000000..f08ec17cc3dc
--- /dev/null
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -0,0 +1,1014 @@
+/*
+ init/start/stop/exit stream functions
+ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
+ Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ Copyright (C) 2005-2007 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
+ */
+
+/* License: GPL
+ * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
+ *
+ * This file will hold API related functions, both internal (firmware api)
+ * and external (v4l2, etc)
+ *
+ * -----
+ * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com>
+ * and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ * using information provided by Jiun-Kuei Jung @ AVerMedia.
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-queue.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-irq.h"
+#include "ivtv-yuv.h"
+#include "ivtv-cards.h"
+#include "ivtv-streams.h"
+#include "ivtv-firmware.h"
+#include <media/v4l2-event.h>
+
+static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .unlocked_ioctl = video_ioctl2,
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_enc_poll,
+};
+
+static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .unlocked_ioctl = video_ioctl2,
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_dec_poll,
+};
+
+#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
+
+static struct {
+ const char *name;
+ int vfl_type;
+ 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
+ }
+};
+
+static void ivtv_stream_init(struct ivtv *itv, int type)
+{
+ struct ivtv_stream *s = &itv->streams[type];
+ struct video_device *vdev = s->vdev;
+
+ /* we need to keep vdev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+ s->vdev = vdev;
+
+ /* initialize ivtv_stream fields */
+ 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;
+ else
+ s->dma = ivtv_stream_info[type].dma;
+ s->buf_size = itv->stream_buf_size[type];
+ if (s->buf_size)
+ 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->sg_handle = IVTV_DMA_UNMAPPED;
+ ivtv_queue_init(&s->q_free);
+ ivtv_queue_init(&s->q_full);
+ ivtv_queue_init(&s->q_dma);
+ ivtv_queue_init(&s->q_predma);
+ ivtv_queue_init(&s->q_io);
+}
+
+static int ivtv_prep_dev(struct ivtv *itv, int type)
+{
+ struct ivtv_stream *s = &itv->streams[type];
+ int num_offset = ivtv_stream_info[type].num_offset;
+ int num = itv->instance + ivtv_first_minor + num_offset;
+
+ /* These four fields are always initialized. If vdev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+ s->vdev = NULL;
+ s->itv = itv;
+ s->type = type;
+ s->name = ivtv_stream_info[type].name;
+
+ /* Check whether the radio is supported */
+ if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))
+ return 0;
+ if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return 0;
+
+ /* User explicitly selected 0 buffers for these streams, so don't
+ create them. */
+ if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+ itv->options.kilobytes[type] == 0) {
+ IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
+ return 0;
+ }
+
+ ivtv_stream_init(itv, type);
+
+ /* allocate and initialize the v4l2 video device structure */
+ s->vdev = video_device_alloc();
+ if (s->vdev == NULL) {
+ IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
+ return -ENOMEM;
+ }
+
+ snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
+ itv->v4l2_dev.name, s->name);
+
+ s->vdev->num = num;
+ s->vdev->v4l2_dev = &itv->v4l2_dev;
+ 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;
+}
+
+/* Initialize v4l2 variables and prepare v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+ int type;
+
+ /* Setup V4L2 Devices */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+ /* Prepare device */
+ if (ivtv_prep_dev(itv, type))
+ break;
+
+ if (itv->streams[type].vdev == NULL)
+ continue;
+
+ /* Allocate Stream */
+ if (ivtv_stream_alloc(&itv->streams[type]))
+ break;
+ }
+ if (type == IVTV_MAX_STREAMS)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ ivtv_streams_cleanup(itv, 0);
+ return -ENOMEM;
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+ struct ivtv_stream *s = &itv->streams[type];
+ int vfl_type = ivtv_stream_info[type].vfl_type;
+ const char *name;
+ int num;
+
+ if (s->vdev == NULL)
+ return 0;
+
+ num = s->vdev->num;
+ /* card number + user defined offset + device offset */
+ if (type != IVTV_ENC_STREAM_TYPE_MPG) {
+ struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+
+ if (s_mpg->vdev)
+ num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
+ }
+ video_set_drvdata(s->vdev, s);
+
+ /* Register device. First try the desired minor, then any free one. */
+ if (video_register_device_no_warn(s->vdev, vfl_type, num)) {
+ IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
+ s->name, num);
+ video_device_release(s->vdev);
+ s->vdev = NULL;
+ return -ENOMEM;
+ }
+ name = video_device_node_name(s->vdev);
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+ IVTV_INFO("Registered device %s for %s (%d kB)\n",
+ name, s->name, itv->options.kilobytes[type]);
+ break;
+ case VFL_TYPE_RADIO:
+ IVTV_INFO("Registered device %s for %s\n",
+ name, s->name);
+ break;
+ case VFL_TYPE_VBI:
+ if (itv->options.kilobytes[type])
+ IVTV_INFO("Registered device %s for %s (%d kB)\n",
+ name, s->name, itv->options.kilobytes[type]);
+ else
+ IVTV_INFO("Registered device %s for %s\n",
+ name, s->name);
+ break;
+ }
+ return 0;
+}
+
+/* Register v4l2 devices */
+int ivtv_streams_register(struct ivtv *itv)
+{
+ int type;
+ int err = 0;
+
+ /* Register V4L2 devices */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++)
+ err |= ivtv_reg_dev(itv, type);
+
+ if (err == 0)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ ivtv_streams_cleanup(itv, 1);
+ return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
+{
+ int type;
+
+ /* Teardown all streams */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+ struct video_device *vdev = itv->streams[type].vdev;
+
+ itv->streams[type].vdev = NULL;
+ if (vdev == NULL)
+ continue;
+
+ ivtv_stream_free(&itv->streams[type]);
+ /* Unregister or release device */
+ if (unregister)
+ video_unregister_device(vdev);
+ else
+ video_device_release(vdev);
+ }
+}
+
+static void ivtv_vbi_setup(struct ivtv *itv)
+{
+ int raw = ivtv_raw_vbi(itv);
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int lines;
+ int i;
+
+ /* Reset VBI */
+ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
+
+ /* setup VBI registers */
+ if (raw)
+ v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi);
+ else
+ v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced);
+
+ /* determine number of lines and total number of VBI bytes.
+ A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+ The '- 1' byte is probably an unused U or V byte. Or something...
+ A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+ header, 42 data bytes + checksum (to be confirmed) */
+ if (raw) {
+ lines = itv->vbi.count * 2;
+ } else {
+ lines = itv->is_60hz ? 24 : 38;
+ if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))
+ lines += 2;
+ }
+
+ itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+
+ /* Note: sliced vs raw flag doesn't seem to have any effect
+ TODO: check mode (0x02) value with older ivtv versions. */
+ data[0] = raw | 0x02 | (0xbd << 8);
+
+ /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
+ data[1] = 1;
+ /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
+ data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
+ /* The start/stop codes determine which VBI lines end up in the raw VBI data area.
+ The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
+ is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
+ code. These values for raw VBI are obtained from a driver disassembly. The sliced
+ start/stop codes was deduced from this, but they do not appear in the driver.
+ Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.
+ However, I have no idea what these values are for. */
+ if (itv->hw_flags & IVTV_HW_CX25840) {
+ /* Setup VBI for the cx25840 digitizer */
+ if (raw) {
+ data[3] = 0x20602060;
+ data[4] = 0x30703070;
+ } else {
+ data[3] = 0xB0F0B0F0;
+ data[4] = 0xA0E0A0E0;
+ }
+ /* Lines per frame */
+ data[5] = lines;
+ /* bytes per line */
+ data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+ } else {
+ /* Setup VBI for the saa7115 digitizer */
+ if (raw) {
+ data[3] = 0x25256262;
+ data[4] = 0x387F7F7F;
+ } else {
+ data[3] = 0xABABECEC;
+ data[4] = 0xB6F1F1F1;
+ }
+ /* Lines per frame */
+ data[5] = lines;
+ /* bytes per line */
+ data[6] = itv->vbi.enc_size / lines;
+ }
+
+ IVTV_DEBUG_INFO(
+ "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",
+ data[0], data[1], data[2], data[5], data[6]);
+
+ ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);
+
+ /* returns the VBI encoder memory area. */
+ itv->vbi.enc_start = data[2];
+ itv->vbi.fpi = data[0];
+ if (!itv->vbi.fpi)
+ itv->vbi.fpi = 1;
+
+ IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
+ itv->vbi.enc_start, data[1], itv->vbi.fpi);
+
+ /* select VBI lines.
+ Note that the sliced argument seems to have no effect. */
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ if (itv->is_60hz) {
+ valid = i >= 10 && i < 22;
+ } else {
+ valid = i >= 6 && i < 24;
+ }
+ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,
+ valid, 0 , 0, 0);
+ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,
+ valid, 0, 0, 0);
+ }
+
+ /* Remaining VBI questions:
+ - Is it possible to select particular VBI lines only for inclusion in the MPEG
+ stream? Currently you can only get the first X lines.
+ - Is mixed raw and sliced VBI possible?
+ - What's the meaning of the raw/sliced flag?
+ - What's the meaning of params 2, 3 & 4 of the Select VBI command? */
+}
+
+int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ struct ivtv *itv = s->itv;
+ int captype = 0, subtype = 0;
+ int enable_passthrough = 0;
+
+ if (s->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+ switch (s->type) {
+ case IVTV_ENC_STREAM_TYPE_MPG:
+ captype = 0;
+ subtype = 3;
+
+ /* Stop Passthrough */
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ ivtv_passthrough_mode(itv, 0);
+ enable_passthrough = 1;
+ }
+ itv->mpg_data_received = itv->vbi_data_inserted = 0;
+ itv->dualwatch_jiffies = jiffies;
+ itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
+ itv->search_pack_header = 0;
+ break;
+
+ case IVTV_ENC_STREAM_TYPE_YUV:
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ captype = 2;
+ subtype = 11; /* video+audio+decoder */
+ break;
+ }
+ captype = 1;
+ subtype = 1;
+ break;
+ case IVTV_ENC_STREAM_TYPE_PCM:
+ captype = 1;
+ subtype = 2;
+ break;
+ case IVTV_ENC_STREAM_TYPE_VBI:
+ captype = 1;
+ subtype = 4;
+
+ itv->vbi.frame = 0;
+ itv->vbi.inserted_frame = 0;
+ memset(itv->vbi.sliced_mpeg_size,
+ 0, sizeof(itv->vbi.sliced_mpeg_size));
+ break;
+ default:
+ return -EINVAL;
+ }
+ s->subtype = subtype;
+ s->buffers_stolen = 0;
+
+ /* Clear Streamoff flags in case left from last capture */
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+ if (atomic_read(&itv->capturing) == 0) {
+ int digitizer;
+
+ /* Always use frame based mode. Experiments have demonstrated that byte
+ stream based mode results in dropped frames and corruption. Not often,
+ but occasionally. Many thanks go to Leonard Orb who spent a lot of
+ effort and time trying to trace the cause of the drop outs. */
+ /* 1 frame per DMA */
+ /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
+ ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
+
+ /* Stuff from Windows, we don't know what it is */
+ ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0);
+ /* According to the docs, this should be correct. However, this is
+ untested. I don't dare enable this without having tested it.
+ Only very few old cards actually have this hardware combination.
+ ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1,
+ ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0);
+ */
+ ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
+ ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
+ ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
+ ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+
+ /* assign placeholder */
+ ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+ digitizer = 0xF1;
+ else if (itv->card->hw_all & IVTV_HW_SAA7114)
+ digitizer = 0xEF;
+ else /* cx25840 */
+ digitizer = 0x140;
+
+ ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
+
+ /* Setup VBI */
+ if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
+ ivtv_vbi_setup(itv);
+ }
+
+ /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */
+ ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400);
+ itv->pgm_info_offset = data[0];
+ itv->pgm_info_num = data[1];
+ itv->pgm_info_write_idx = 0;
+ itv->pgm_info_read_idx = 0;
+
+ IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n",
+ itv->pgm_info_offset, itv->pgm_info_num);
+
+ /* Setup API for Stream */
+ cx2341x_handler_setup(&itv->cxhdl);
+
+ /* mute if capturing radio */
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+ ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+ 1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
+ }
+
+ /* Vsync Setup */
+ if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+ /* event notification (on) */
+ ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1);
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+ }
+
+ if (atomic_read(&itv->capturing) == 0) {
+ /* Clear all Pending Interrupts */
+ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+ clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+
+ cx2341x_handler_set_busy(&itv->cxhdl, 1);
+
+ /* Initialize Digitizer for Capture */
+ /* Avoid tinny audio problem - ensure audio clocks are going */
+ v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
+ /* Avoid unpredictable PCI bus hang - disable video clocks */
+ v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
+ ivtv_msleep_timeout(300, 0);
+ ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
+ v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
+ }
+
+ /* begin_capture */
+ if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
+ {
+ IVTV_DEBUG_WARN( "Error starting capture!\n");
+ return -EINVAL;
+ }
+
+ /* Start Passthrough */
+ if (enable_passthrough) {
+ ivtv_passthrough_mode(itv, 1);
+ }
+
+ if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+ else
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+ /* you're live! sit back and await interrupts :) */
+ atomic_inc(&itv->capturing);
+ return 0;
+}
+
+static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ struct ivtv *itv = s->itv;
+ int datatype;
+ u16 width;
+ u16 height;
+
+ if (s->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+
+ width = itv->cxhdl.width;
+ height = itv->cxhdl.height;
+
+ /* set audio mode to left/stereo for dual/stereo mode. */
+ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+
+ /* set number of internal decoder buffers */
+ ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
+
+ /* prebuffering */
+ ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1);
+
+ /* extract from user packets */
+ ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1);
+ itv->vbi.dec_start = data[0];
+
+ IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n",
+ itv->vbi.dec_start, data[1]);
+
+ /* set decoder source settings */
+ /* Data type: 0 = mpeg from host,
+ 1 = yuv from encoder,
+ 2 = yuv_from_host */
+ switch (s->type) {
+ case IVTV_DEC_STREAM_TYPE_YUV:
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ datatype = 1;
+ } else {
+ /* Fake size to avoid switching video standard */
+ datatype = 2;
+ width = 720;
+ height = itv->is_out_50hz ? 576 : 480;
+ }
+ IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
+ break;
+ case IVTV_DEC_STREAM_TYPE_MPG:
+ default:
+ datatype = 0;
+ break;
+ }
+ if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
+ width, height, itv->cxhdl.audio_properties)) {
+ IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
+ }
+
+ /* Decoder sometimes dies here, so wait a moment */
+ ivtv_msleep_timeout(10, 0);
+
+ /* Known failure point for firmware, so check */
+ return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
+}
+
+int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
+{
+ struct ivtv *itv = s->itv;
+ int rc;
+
+ if (s->vdev == NULL)
+ return -EINVAL;
+
+ if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
+ return 0; /* already started */
+
+ IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
+
+ rc = ivtv_setup_v4l2_decode_stream(s);
+ if (rc < 0) {
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ return rc;
+ }
+
+ /* set dma size to 65536 bytes */
+ ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
+
+ /* Clear Streamoff */
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+ /* Zero out decoder counters */
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]);
+
+ /* turn on notification of dual/stereo mode change */
+ ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
+
+ /* start playback */
+ ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
+
+ /* Let things settle before we actually start */
+ ivtv_msleep_timeout(10, 0);
+
+ /* Clear the following Interrupt mask bits for decoding */
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+ IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
+
+ /* you're live! sit back and await interrupts :) */
+ atomic_inc(&itv->decoding);
+ return 0;
+}
+
+void ivtv_stop_all_captures(struct ivtv *itv)
+{
+ int i;
+
+ for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+ struct ivtv_stream *s = &itv->streams[i];
+
+ if (s->vdev == NULL)
+ continue;
+ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ ivtv_stop_v4l2_encode_stream(s, 0);
+ }
+ }
+}
+
+int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
+{
+ struct ivtv *itv = s->itv;
+ DECLARE_WAITQUEUE(wait, current);
+ int cap_type;
+ int stopmode;
+
+ if (s->vdev == NULL)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+ and that we are actually capturing */
+
+ IVTV_DEBUG_INFO("Stop Capture\n");
+
+ if (s->type == IVTV_DEC_STREAM_TYPE_VOUT)
+ return 0;
+ if (atomic_read(&itv->capturing) == 0)
+ return 0;
+
+ switch (s->type) {
+ case IVTV_ENC_STREAM_TYPE_YUV:
+ cap_type = 1;
+ break;
+ case IVTV_ENC_STREAM_TYPE_PCM:
+ cap_type = 1;
+ break;
+ case IVTV_ENC_STREAM_TYPE_VBI:
+ cap_type = 1;
+ break;
+ case IVTV_ENC_STREAM_TYPE_MPG:
+ default:
+ cap_type = 0;
+ break;
+ }
+
+ /* Stop Capture Mode */
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+ stopmode = 0;
+ } else {
+ stopmode = 1;
+ }
+
+ /* end_capture */
+ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
+ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
+
+ if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+ /* only run these if we're shutting down the last cap */
+ unsigned long duration;
+ unsigned long then = jiffies;
+
+ add_wait_queue(&itv->eos_waitq, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /* wait 2s for EOS interrupt */
+ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+ time_before(jiffies,
+ then + msecs_to_jiffies(2000))) {
+ schedule_timeout(msecs_to_jiffies(10));
+ }
+
+ /* To convert jiffies to ms, we must multiply by 1000
+ * and divide by HZ. To avoid runtime division, we
+ * convert this to multiplication by 1000/HZ.
+ * Since integer division truncates, we get the best
+ * accuracy if we do a rounding calculation of the constant.
+ * Think of the case where HZ is 1024.
+ */
+ duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
+
+ if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
+ IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
+ IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
+ } else {
+ IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&itv->eos_waitq, &wait);
+ set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ }
+
+ /* Handle any pending interrupts */
+ ivtv_msleep_timeout(100, 0);
+ }
+
+ atomic_dec(&itv->capturing);
+
+ /* Clear capture and no-read bits */
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+
+ if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+ ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+
+ if (atomic_read(&itv->capturing) > 0) {
+ return 0;
+ }
+
+ cx2341x_handler_set_busy(&itv->cxhdl, 0);
+
+ /* Set the following Interrupt mask bits for capture */
+ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ del_timer(&itv->dma_timer);
+
+ /* event notification (off) */
+ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+ /* type: 0 = refresh */
+ /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+ ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+ ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+ }
+
+ /* Raw-passthrough is implied on start. Make sure it's stopped so
+ the encoder will re-initialize when next started */
+ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
+
+ wake_up(&s->waitq);
+
+ return 0;
+}
+
+int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
+{
+ static const struct v4l2_event ev = {
+ .type = V4L2_EVENT_EOS,
+ };
+ struct ivtv *itv = s->itv;
+
+ if (s->vdev == NULL)
+ return -EINVAL;
+
+ if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
+ return -EINVAL;
+
+ if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags))
+ return 0;
+
+ IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
+
+ /* Stop Decoder */
+ if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
+ u32 tmp = 0;
+
+ /* Wait until the decoder is no longer running */
+ if (pts) {
+ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3,
+ 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32));
+ }
+ while (1) {
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0);
+ if (s->q_full.buffers + s->q_dma.buffers == 0) {
+ if (tmp == data[3])
+ break;
+ tmp = data[3];
+ }
+ if (ivtv_msleep_timeout(100, 1))
+ break;
+ }
+ }
+ 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);
+
+ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+ del_timer(&itv->dma_timer);
+
+ clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ ivtv_flush_queues(s);
+
+ /* decoder needs time to settle */
+ ivtv_msleep_timeout(40, 0);
+
+ /* decrement decoding */
+ atomic_dec(&itv->decoding);
+
+ set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
+ wake_up(&itv->event_waitq);
+ v4l2_event_queue(s->vdev, &ev);
+
+ /* wake up wait queues */
+ wake_up(&s->waitq);
+
+ return 0;
+}
+
+int ivtv_passthrough_mode(struct ivtv *itv, int enable)
+{
+ struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
+ struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+
+ if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
+
+ /* Prevent others from starting/stopping streams while we
+ initiate/terminate passthrough mode */
+ if (enable) {
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ return 0;
+ }
+ if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH)
+ return -EBUSY;
+
+ /* Fully initialize stream, and then unflag init */
+ set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+ set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+
+ /* Setup YUV Decoder */
+ ivtv_setup_v4l2_decode_stream(dec_stream);
+
+ /* Start Decoder */
+ ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1);
+ atomic_inc(&itv->decoding);
+
+ /* Setup capture if not already done */
+ if (atomic_read(&itv->capturing) == 0) {
+ cx2341x_handler_setup(&itv->cxhdl);
+ cx2341x_handler_set_busy(&itv->cxhdl, 1);
+ }
+
+ /* Start Passthrough Mode */
+ ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11);
+ atomic_inc(&itv->capturing);
+ return 0;
+ }
+
+ if (itv->output_mode != OUT_PASSTHROUGH)
+ return 0;
+
+ /* Stop Passthrough Mode */
+ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11);
+ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0);
+
+ atomic_dec(&itv->capturing);
+ atomic_dec(&itv->decoding);
+ clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+ clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+ itv->output_mode = OUT_NONE;
+ if (atomic_read(&itv->capturing) == 0)
+ cx2341x_handler_set_busy(&itv->cxhdl, 0);
+
+ return 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/pci/ivtv/ivtv-streams.h
index a653a5136417..a653a5136417 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/pci/ivtv/ivtv-streams.h
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c
index 7338cb2d0a38..7338cb2d0a38 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/pci/ivtv/ivtv-udma.c
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/pci/ivtv/ivtv-udma.h
index ee3c9efb5b72..ee3c9efb5b72 100644
--- a/drivers/media/video/ivtv/ivtv-udma.h
+++ b/drivers/media/pci/ivtv/ivtv-udma.h
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c
index 293db806d936..293db806d936 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/pci/ivtv/ivtv-vbi.c
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/pci/ivtv/ivtv-vbi.h
index 166dd0b75d0f..166dd0b75d0f 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/pci/ivtv/ivtv-vbi.h
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/pci/ivtv/ivtv-version.h
index a20f346fcad8..a20f346fcad8 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/pci/ivtv/ivtv-version.h
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c
index 2ad65eb29832..2ad65eb29832 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/pci/ivtv/ivtv-yuv.c
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/pci/ivtv/ivtv-yuv.h
index ca5173fbf006..ca5173fbf006 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/pci/ivtv/ivtv-yuv.h
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 05b94aa8ba32..05b94aa8ba32 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig
new file mode 100644
index 000000000000..d3cc21633b94
--- /dev/null
+++ b/drivers/media/pci/mantis/Kconfig
@@ -0,0 +1,38 @@
+config MANTIS_CORE
+ tristate "Mantis/Hopper PCI bridge based devices"
+ depends on PCI && I2C && INPUT && RC_CORE
+
+ help
+ Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+ tristate "MANTIS based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_MB86A16 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA665x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Mantis PCI bridge.
+ Say Y when you have a Mantis based DVB card and want to use it.
+
+ If unsure say N.
+
+config DVB_HOPPER
+ tristate "HOPPER based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Hopper PCI bridge.
+ Say Y when you have a Hopper based DVB card and want to use it.
+
+ If unsure say N
diff --git a/drivers/media/pci/mantis/Makefile b/drivers/media/pci/mantis/Makefile
new file mode 100644
index 000000000000..f715051e4453
--- /dev/null
+++ b/drivers/media/pci/mantis/Makefile
@@ -0,0 +1,28 @@
+mantis_core-objs := mantis_ioc.o \
+ mantis_uart.o \
+ mantis_dma.o \
+ mantis_pci.o \
+ mantis_i2c.o \
+ mantis_dvb.o \
+ mantis_evm.o \
+ mantis_hif.o \
+ mantis_ca.o \
+ mantis_pcmcia.o \
+ mantis_input.o
+
+mantis-objs := mantis_cards.o \
+ mantis_vp1033.o \
+ mantis_vp1034.o \
+ mantis_vp1041.o \
+ mantis_vp2033.o \
+ mantis_vp2040.o \
+ mantis_vp3030.o
+
+hopper-objs := hopper_cards.o \
+ hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE) += mantis_core.o
+obj-$(CONFIG_DVB_MANTIS) += mantis.o
+obj-$(CONFIG_DVB_HOPPER) += hopper.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c
index cc0251e01077..cc0251e01077 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/pci/mantis/hopper_cards.c
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c
index 68a29f8bdf73..68a29f8bdf73 100644
--- a/drivers/media/dvb/mantis/hopper_vp3028.c
+++ b/drivers/media/pci/mantis/hopper_vp3028.c
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/pci/mantis/hopper_vp3028.h
index 57239498bc87..57239498bc87 100644
--- a/drivers/media/dvb/mantis/hopper_vp3028.h
+++ b/drivers/media/pci/mantis/hopper_vp3028.h
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c
index 3d7046909009..3d7046909009 100644
--- a/drivers/media/dvb/mantis/mantis_ca.c
+++ b/drivers/media/pci/mantis/mantis_ca.c
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/pci/mantis/mantis_ca.h
index dc63e55f7eca..dc63e55f7eca 100644
--- a/drivers/media/dvb/mantis/mantis_ca.h
+++ b/drivers/media/pci/mantis/mantis_ca.h
diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c
new file mode 100644
index 000000000000..0207d1f064e0
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_cards.c
@@ -0,0 +1,307 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
+
+static int devs;
+
+#define DRIVER_NAME "Mantis"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &mantis_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+ goto fail6;
+ }
+
+ devs++;
+
+ return err;
+
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+ mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+
+ mantis_uart_exit(mantis);
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+ MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, mantis_pci_table);
+
+static struct pci_driver mantis_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = mantis_pci_table,
+ .probe = mantis_pci_probe,
+ .remove = mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+ return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+ return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
index f2410cf0a6bf..f2410cf0a6bf 100644
--- a/drivers/media/dvb/mantis/mantis_common.h
+++ b/drivers/media/pci/mantis/mantis_common.h
diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c
new file mode 100644
index 000000000000..684d9061fe2a
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_core.c
@@ -0,0 +1,235 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+ struct i2c_msg msg[] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = 1
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .buf = data,
+ .len = length
+ },
+ };
+
+ err = i2c_transfer(&mantis->adapter, msg, 2);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+
+ struct i2c_msg msg = {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = length
+ };
+
+ err = i2c_transfer(&mantis->adapter, &msg, 1);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+ err, length, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis->mac_address[0] = 0x08;
+ err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+ return err;
+ }
+ dprintk(verbose, MANTIS_ERROR, 0,
+ " MAC Address=[%pM]\n", mantis->mac_address);
+
+ return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
+#define MANTIS_DEV_UNKNOWN "UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+ .model_name = MANTIS_MODEL_UNKNOWN,
+ .dev_type = MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+ switch (mantis->subsystem_device) {
+ case MANTIS_VP_1033_DVB_S: /* VP-1033 */
+ mantis->hwconfig = &vp1033_mantis_config;
+ break;
+ case MANTIS_VP_1034_DVB_S: /* VP-1034 */
+ mantis->hwconfig = &vp1034_mantis_config;
+ break;
+ case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
+ case TECHNISAT_SKYSTAR_HD2:
+ mantis->hwconfig = &vp1041_mantis_config;
+ break;
+ case MANTIS_VP_2033_DVB_C: /* VP-2033 */
+ mantis->hwconfig = &vp2033_mantis_config;
+ break;
+ case MANTIS_VP_2040_DVB_C: /* VP-2040 */
+ case CINERGY_C: /* VP-2040 clone */
+ case TECHNISAT_CABLESTAR_HD2:
+ mantis->hwconfig = &vp2040_mantis_config;
+ break;
+ case MANTIS_VP_3030_DVB_T: /* VP-3030 */
+ mantis->hwconfig = &vp3030_mantis_config;
+ break;
+ default:
+ mantis->hwconfig = &unknown_device;
+ break;
+ }
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ mantis_load_config(mantis);
+ dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+ mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+ dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->subsystem_vendor, mantis->subsystem_device);
+ dprintk(verbose, MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq, mantis->latency,
+ mantis->mantis_addr, mantis->mantis_mmio);
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+ return err;
+ }
+ err = get_mac_address(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+ return err;
+ }
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+ return err;
+ }
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+ return err;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+ return err;
+ }
+
+ return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+ mantis_dma_stop(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+ mantis_uart_exit(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+ if (mantis_dma_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+ if (mantis_dvb_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+ if (mantis_i2c_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+ return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+ udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+ u32 reg;
+
+ reg = mmread(0x28);
+ dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+ if (direction == 0x01) {
+ /* to CI */
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ } else {
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h
index 833ee42e694e..833ee42e694e 100644
--- a/drivers/media/dvb/mantis/mantis_core.h
+++ b/drivers/media/pci/mantis/mantis_core.h
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c
index 566c407175a4..566c407175a4 100644
--- a/drivers/media/dvb/mantis/mantis_dma.c
+++ b/drivers/media/pci/mantis/mantis_dma.c
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h
index 6be00fa82094..6be00fa82094 100644
--- a/drivers/media/dvb/mantis/mantis_dma.h
+++ b/drivers/media/pci/mantis/mantis_dma.h
diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c
new file mode 100644
index 000000000000..5d15c6b74d9b
--- /dev/null
+++ b/drivers/media/pci/mantis/mantis_dvb.c
@@ -0,0 +1,301 @@
+/*
+ Mantis PCI bridge driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ switch (power) {
+ case POWER_ON:
+ dprintk(MANTIS_DEBUG, 1, "Power ON");
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ break;
+
+ case POWER_OFF:
+ dprintk(MANTIS_DEBUG, 1, "Power OFF");
+ mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
+ msleep(100);
+ break;
+
+ default:
+ dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+ mantis_gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis_frontend_soft_reset(mantis);
+ err = mantis_frontend_power(mantis, POWER_OFF);
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds++;
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
+
+ if (mantis->feeds == 1) {
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+ mantis_dma_start(mantis);
+ tasklet_enable(&mantis->tasklet);
+ }
+
+ return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds--;
+ if (mantis->feeds == 0) {
+ dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ tasklet_disable(&mantis->tasklet);
+ mantis_dma_stop(mantis);
+ }
+
+ return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int result = -1;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+ result = dvb_register_adapter(&mantis->dvb_adapter,
+ "Mantis DVB adapter",
+ THIS_MODULE,
+ &mantis->pdev->dev,
+ adapter_nr);
+
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+ return -ENODEV;
+ }
+
+ mantis->dvb_adapter.priv = mantis;
+ mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+
+ mantis->demux.priv = mantis;
+ mantis->demux.filternum = 256;
+ mantis->demux.feednum = 256;
+ mantis->demux.start_feed = mantis_dvb_start_feed;
+ mantis->demux.stop_feed = mantis_dvb_stop_feed;
+ mantis->demux.write_to_decoder = NULL;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+ result = dvb_dmx_init(&mantis->demux);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+ goto err0;
+ }
+
+ mantis->dmxdev.filternum = 256;
+ mantis->dmxdev.demux = &mantis->demux.dmx;
+ mantis->dmxdev.capabilities = 0;
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+ result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+ goto err1;
+ }
+
+ mantis->fe_hw.source = DMX_FRONTEND_0;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err2;
+ }
+
+ mantis->fe_mem.source = DMX_MEMORY_FE;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err3;
+ }
+
+ result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err4;
+ }
+
+ dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+ tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ tasklet_disable(&mantis->tasklet);
+ if (mantis->hwconfig) {
+ result = config->frontend_init(mantis, mantis->fe);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+ goto err5;
+ } else {
+ if (mantis->fe == NULL) {
+ dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+ goto err5;
+ }
+
+ if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+ if (mantis->fe->ops.release)
+ mantis->fe->ops.release(mantis->fe);
+
+ mantis->fe = NULL;
+ goto err5;
+ }
+ }
+ }
+
+ return 0;
+
+ /* Error conditions .. */
+err5:
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+ if (mantis->fe) {
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+ }
+err4:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+ dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+ dvb_dmx_release(&mantis->demux);
+
+err0:
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+ int err;
+
+ if (mantis->fe) {
+ /* mantis_ca_exit(mantis); */
+ err = mantis_frontend_shutdown(mantis);
+ if (err != 0)
+ dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+ }
+
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+ dvb_dmxdev_release(&mantis->dmxdev);
+ dvb_dmx_release(&mantis->demux);
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/pci/mantis/mantis_dvb.h
index 464199db304e..464199db304e 100644
--- a/drivers/media/dvb/mantis/mantis_dvb.h
+++ b/drivers/media/pci/mantis/mantis_dvb.h
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/pci/mantis/mantis_evm.c
index 71ce52875c38..71ce52875c38 100644
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ b/drivers/media/pci/mantis/mantis_evm.c
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/pci/mantis/mantis_hif.c
index 10c68df7e16f..10c68df7e16f 100644
--- a/drivers/media/dvb/mantis/mantis_hif.c
+++ b/drivers/media/pci/mantis/mantis_hif.c
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/pci/mantis/mantis_hif.h
index 9094f9ed2362..9094f9ed2362 100644
--- a/drivers/media/dvb/mantis/mantis_hif.h
+++ b/drivers/media/pci/mantis/mantis_hif.h
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c
index e7794517fe26..e7794517fe26 100644
--- a/drivers/media/dvb/mantis/mantis_i2c.c
+++ b/drivers/media/pci/mantis/mantis_i2c.c
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/pci/mantis/mantis_i2c.h
index 1342df2faed8..1342df2faed8 100644
--- a/drivers/media/dvb/mantis/mantis_i2c.h
+++ b/drivers/media/pci/mantis/mantis_i2c.h
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c
index db6d54d3fec0..db6d54d3fec0 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/pci/mantis/mantis_input.c
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/pci/mantis/mantis_ioc.c
index 24fcdc63d6d5..24fcdc63d6d5 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.c
+++ b/drivers/media/pci/mantis/mantis_ioc.c
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/pci/mantis/mantis_ioc.h
index d56e002b2955..d56e002b2955 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.h
+++ b/drivers/media/pci/mantis/mantis_ioc.h
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/pci/mantis/mantis_link.h
index 2a814774a001..2a814774a001 100644
--- a/drivers/media/dvb/mantis/mantis_link.h
+++ b/drivers/media/pci/mantis/mantis_link.h
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/pci/mantis/mantis_pci.c
index 371558af2d96..371558af2d96 100644
--- a/drivers/media/dvb/mantis/mantis_pci.c
+++ b/drivers/media/pci/mantis/mantis_pci.c
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/pci/mantis/mantis_pci.h
index 65f004519086..65f004519086 100644
--- a/drivers/media/dvb/mantis/mantis_pci.h
+++ b/drivers/media/pci/mantis/mantis_pci.h
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c
index 2f188c089666..2f188c089666 100644
--- a/drivers/media/dvb/mantis/mantis_pcmcia.c
+++ b/drivers/media/pci/mantis/mantis_pcmcia.c
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/pci/mantis/mantis_reg.h
index 7761f9dc7fe0..7761f9dc7fe0 100644
--- a/drivers/media/dvb/mantis/mantis_reg.h
+++ b/drivers/media/pci/mantis/mantis_reg.h
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c
index 18340dafa426..18340dafa426 100644
--- a/drivers/media/dvb/mantis/mantis_uart.c
+++ b/drivers/media/pci/mantis/mantis_uart.c
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/pci/mantis/mantis_uart.h
index ffb62a0a5a13..ffb62a0a5a13 100644
--- a/drivers/media/dvb/mantis/mantis_uart.h
+++ b/drivers/media/pci/mantis/mantis_uart.h
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c
index ad013e93ed11..ad013e93ed11 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ b/drivers/media/pci/mantis/mantis_vp1033.c
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/pci/mantis/mantis_vp1033.h
index 7daaa1bf127d..7daaa1bf127d 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.h
+++ b/drivers/media/pci/mantis/mantis_vp1033.h
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c
index 430ae84ce528..430ae84ce528 100644
--- a/drivers/media/dvb/mantis/mantis_vp1034.c
+++ b/drivers/media/pci/mantis/mantis_vp1034.c
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h
index 323f38ef8e3d..323f38ef8e3d 100644
--- a/drivers/media/dvb/mantis/mantis_vp1034.h
+++ b/drivers/media/pci/mantis/mantis_vp1034.h
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
index 07aa887a4b4a..07aa887a4b4a 100644
--- a/drivers/media/dvb/mantis/mantis_vp1041.c
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/pci/mantis/mantis_vp1041.h
index 1ae5b3de8081..1ae5b3de8081 100644
--- a/drivers/media/dvb/mantis/mantis_vp1041.h
+++ b/drivers/media/pci/mantis/mantis_vp1041.h
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c
index 1ca6837fbe46..1ca6837fbe46 100644
--- a/drivers/media/dvb/mantis/mantis_vp2033.c
+++ b/drivers/media/pci/mantis/mantis_vp2033.c
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/pci/mantis/mantis_vp2033.h
index c55242b79d54..c55242b79d54 100644
--- a/drivers/media/dvb/mantis/mantis_vp2033.h
+++ b/drivers/media/pci/mantis/mantis_vp2033.h
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c
index d480741afd78..d480741afd78 100644
--- a/drivers/media/dvb/mantis/mantis_vp2040.c
+++ b/drivers/media/pci/mantis/mantis_vp2040.c
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/pci/mantis/mantis_vp2040.h
index d125e219b685..d125e219b685 100644
--- a/drivers/media/dvb/mantis/mantis_vp2040.h
+++ b/drivers/media/pci/mantis/mantis_vp2040.h
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c
index 4155c838a18a..4155c838a18a 100644
--- a/drivers/media/dvb/mantis/mantis_vp3028.c
+++ b/drivers/media/pci/mantis/mantis_vp3028.c
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h
index b07be6adc522..b07be6adc522 100644
--- a/drivers/media/dvb/mantis/mantis_vp3028.h
+++ b/drivers/media/pci/mantis/mantis_vp3028.h
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c
index c09308cd3ac6..c09308cd3ac6 100644
--- a/drivers/media/dvb/mantis/mantis_vp3030.c
+++ b/drivers/media/pci/mantis/mantis_vp3030.c
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/pci/mantis/mantis_vp3030.h
index 5f12c4266277..5f12c4266277 100644
--- a/drivers/media/dvb/mantis/mantis_vp3030.h
+++ b/drivers/media/pci/mantis/mantis_vp3030.h
diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig
new file mode 100644
index 000000000000..b4bf848be5a0
--- /dev/null
+++ b/drivers/media/pci/meye/Kconfig
@@ -0,0 +1,13 @@
+config VIDEO_MEYE
+ tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
+ depends on PCI && SONY_LAPTOP && VIDEO_V4L2
+ ---help---
+ This is the video4linux driver for the Motion Eye camera found
+ in the Vaio Picturebook laptops. Please read the material in
+ <file:Documentation/video4linux/meye.txt> for more information.
+
+ If you say Y or M here, you need to say Y or M to "Sony Laptop
+ Extras" in the misc device section.
+
+ To compile this driver as a module, choose M here: the
+ module will be called meye.
diff --git a/drivers/media/pci/meye/Makefile b/drivers/media/pci/meye/Makefile
new file mode 100644
index 000000000000..49388518cd01
--- /dev/null
+++ b/drivers/media/pci/meye/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_MEYE) += meye.o
diff --git a/drivers/media/video/meye.c b/drivers/media/pci/meye/meye.c
index 7bc775219f97..7bc775219f97 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/pci/meye/meye.c
diff --git a/drivers/media/video/meye.h b/drivers/media/pci/meye/meye.h
index 4bdeb03f1644..4bdeb03f1644 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/pci/meye/meye.h
diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig
new file mode 100644
index 000000000000..637d506b23c5
--- /dev/null
+++ b/drivers/media/pci/ngene/Kconfig
@@ -0,0 +1,13 @@
+config DVB_NGENE
+ tristate "Micronas nGene support"
+ depends on DVB_CORE && PCI && I2C
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ Support for Micronas PCI express cards with nGene bridge.
+
diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile
new file mode 100644
index 000000000000..5c0b5d6b9d69
--- /dev/null
+++ b/drivers/media/pci/ngene/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the nGene device driver
+#
+
+ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
+
+obj-$(CONFIG_DVB_NGENE) += ngene.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
+
+# For the staging CI driver cxd2099
+ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
new file mode 100644
index 000000000000..a6cd6959ad19
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -0,0 +1,823 @@
+/*
+ * ngene-cards.c: nGene PCIe bridge driver - card specific info
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ * Modifications for new nGene firmware,
+ * support for EEPROM-copying,
+ * support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include "ngene.h"
+
+/* demods/tuners */
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "lgdt330x.h"
+#include "mt2131.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
+#include "drxd.h"
+#include "dvb-pll.h"
+
+
+/****************************************************************************/
+/* Demod/tuner attachment ***************************************************/
+/****************************************************************************/
+
+static int tuner_attach_stv6110(struct ngene_channel *chan)
+{
+ struct i2c_adapter *i2c;
+ struct stv090x_config *feconf = (struct stv090x_config *)
+ chan->dev->card_info->fe_config[chan->number];
+ struct stv6110x_config *tunerconf = (struct stv6110x_config *)
+ chan->dev->card_info->tuner_config[chan->number];
+ struct stv6110x_devctl *ctl;
+
+ /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+ if (chan->number < 2)
+ i2c = &chan->dev->channel[0].i2c_adapter;
+ else
+ i2c = &chan->dev->channel[1].i2c_adapter;
+
+ ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
+ if (ctl == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");
+ return -ENODEV;
+ }
+
+ feconf->tuner_init = ctl->tuner_init;
+ feconf->tuner_sleep = ctl->tuner_sleep;
+ feconf->tuner_set_mode = ctl->tuner_set_mode;
+ feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+ feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+ feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ feconf->tuner_set_bbgain = ctl->tuner_set_bbgain;
+ feconf->tuner_get_bbgain = ctl->tuner_get_bbgain;
+ feconf->tuner_set_refclk = ctl->tuner_set_refclk;
+ feconf->tuner_get_status = ctl->tuner_get_status;
+
+ return 0;
+}
+
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct ngene_channel *chan = fe->sec_priv;
+ int status;
+
+ if (enable) {
+ down(&chan->dev->pll_mutex);
+ status = chan->gate_ctrl(fe, 1);
+ } else {
+ status = chan->gate_ctrl(fe, 0);
+ up(&chan->dev->pll_mutex);
+ }
+ return status;
+}
+
+static int tuner_attach_tda18271(struct ngene_channel *chan)
+{
+ struct i2c_adapter *i2c;
+ struct dvb_frontend *fe;
+
+ i2c = &chan->dev->channel[0].i2c_adapter;
+ if (chan->fe->ops.i2c_gate_ctrl)
+ chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
+ fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
+ if (chan->fe->ops.i2c_gate_ctrl)
+ chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
+ if (!fe) {
+ printk(KERN_ERR "No TDA18271 found!\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int tuner_attach_probe(struct ngene_channel *chan)
+{
+ if (chan->demod_type == 0)
+ return tuner_attach_stv6110(chan);
+ if (chan->demod_type == 1)
+ return tuner_attach_tda18271(chan);
+ return -EINVAL;
+}
+
+static int demod_attach_stv0900(struct ngene_channel *chan)
+{
+ struct i2c_adapter *i2c;
+ struct stv090x_config *feconf = (struct stv090x_config *)
+ chan->dev->card_info->fe_config[chan->number];
+
+ /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+ /* Note: Both adapters share the same i2c bus, but the demod */
+ /* driver requires that each demod has its own i2c adapter */
+ if (chan->number < 2)
+ i2c = &chan->dev->channel[0].i2c_adapter;
+ else
+ i2c = &chan->dev->channel[1].i2c_adapter;
+
+ chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
+ (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
+ : STV090x_DEMODULATOR_1);
+ if (chan->fe == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");
+ return -ENODEV;
+ }
+
+ /* store channel info */
+ if (feconf->tuner_i2c_lock)
+ chan->fe->analog_demod_priv = chan;
+
+ if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
+ 0, chan->dev->card_info->lnb[chan->number])) {
+ printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+ dvb_frontend_detach(chan->fe);
+ chan->fe = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
+{
+ struct ngene_channel *chan = fe->analog_demod_priv;
+
+ if (lock)
+ down(&chan->dev->pll_mutex);
+ else
+ up(&chan->dev->pll_mutex);
+}
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+ struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
+ .buf = val, .len = 1 } };
+ return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+ u16 reg, u8 *val)
+{
+ u8 msg[2] = {reg>>8, reg&0xff};
+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+ .buf = msg, .len = 2},
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = val, .len = 1} };
+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int port_has_stv0900(struct i2c_adapter *i2c, int port)
+{
+ u8 val;
+ if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+ return 0;
+ return 1;
+}
+
+static int port_has_drxk(struct i2c_adapter *i2c, int port)
+{
+ u8 val;
+
+ if (i2c_read(i2c, 0x29+port, &val) < 0)
+ return 0;
+ return 1;
+}
+
+static int demod_attach_drxk(struct ngene_channel *chan,
+ struct i2c_adapter *i2c)
+{
+ struct drxk_config config;
+
+ memset(&config, 0, sizeof(config));
+ config.microcode_name = "drxk_a3.mc";
+ config.qam_demod_parameter_count = 4;
+ config.adr = 0x29 + (chan->number ^ 2);
+
+ chan->fe = dvb_attach(drxk_attach, &config, i2c);
+ if (!chan->fe) {
+ printk(KERN_ERR "No DRXK found!\n");
+ return -ENODEV;
+ }
+ chan->fe->sec_priv = chan;
+ chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+ chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+ return 0;
+}
+
+static int cineS2_probe(struct ngene_channel *chan)
+{
+ struct i2c_adapter *i2c;
+ struct stv090x_config *fe_conf;
+ u8 buf[3];
+ struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
+ int rc;
+
+ /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+ if (chan->number < 2)
+ i2c = &chan->dev->channel[0].i2c_adapter;
+ else
+ i2c = &chan->dev->channel[1].i2c_adapter;
+
+ if (port_has_stv0900(i2c, chan->number)) {
+ chan->demod_type = 0;
+ fe_conf = chan->dev->card_info->fe_config[chan->number];
+ /* demod found, attach it */
+ rc = demod_attach_stv0900(chan);
+ if (rc < 0 || chan->number < 2)
+ return rc;
+
+ /* demod #2: reprogram outputs DPN1 & DPN2 */
+ i2c_msg.addr = fe_conf->address;
+ i2c_msg.len = 3;
+ buf[0] = 0xf1;
+ switch (chan->number) {
+ case 2:
+ buf[1] = 0x5c;
+ buf[2] = 0xc2;
+ break;
+ case 3:
+ buf[1] = 0x61;
+ buf[2] = 0xcc;
+ break;
+ default:
+ return -ENODEV;
+ }
+ rc = i2c_transfer(i2c, &i2c_msg, 1);
+ if (rc != 1) {
+ printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+ return -EIO;
+ }
+ } else if (port_has_drxk(i2c, chan->number^2)) {
+ chan->demod_type = 1;
+ demod_attach_drxk(chan, i2c);
+ } else {
+ printk(KERN_ERR "No demod found on chan %d\n", chan->number);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+
+static struct lgdt330x_config aver_m780 = {
+ .demod_address = 0xb2 >> 1,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x00, /* PARALLEL */
+ .clock_polarity_flip = 1,
+};
+
+static struct mt2131_config m780_tunerconfig = {
+ 0xc0 >> 1
+};
+
+/* A single func to attach the demo and tuner, rather than
+ * use two sep funcs like the current design mandates.
+ */
+static int demod_attach_lg330x(struct ngene_channel *chan)
+{
+ chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
+ if (chan->fe == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n");
+ return -ENODEV;
+ }
+
+ dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
+ &m780_tunerconfig, 0);
+
+ return (chan->fe) ? 0 : -ENODEV;
+}
+
+static int demod_attach_drxd(struct ngene_channel *chan)
+{
+ struct drxd_config *feconf;
+
+ feconf = chan->dev->card_info->fe_config[chan->number];
+
+ chan->fe = dvb_attach(drxd_attach, feconf, chan,
+ &chan->i2c_adapter, &chan->dev->pci_dev->dev);
+ if (!chan->fe) {
+ pr_err("No DRXD found!\n");
+ return -ENODEV;
+ }
+
+ if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
+ &chan->i2c_adapter,
+ feconf->pll_type)) {
+ pr_err("No pll(%d) found!\n", feconf->pll_type);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/****************************************************************************/
+/* EEPROM TAGS **************************************************************/
+/****************************************************************************/
+
+#define MICNG_EE_START 0x0100
+#define MICNG_EE_END 0x0FF0
+
+#define MICNG_EETAG_END0 0x0000
+#define MICNG_EETAG_END1 0xFFFF
+
+/* 0x0001 - 0x000F reserved for housekeeping */
+/* 0xFFFF - 0xFFFE reserved for housekeeping */
+
+/* Micronas assigned tags
+ EEProm tags for hardware support */
+
+#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000 /* 2 Bytes data */
+#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001 /* 2 Bytes data */
+
+#define MICNG_EETAG_MT2060_1_1STIF 0x1100 /* 2 Bytes data */
+#define MICNG_EETAG_MT2060_2_1STIF 0x1101 /* 2 Bytes data */
+
+/* Tag range for OEMs */
+
+#define MICNG_EETAG_OEM_FIRST 0xC000
+#define MICNG_EETAG_OEM_LAST 0xFFEF
+
+static int i2c_write_eeprom(struct i2c_adapter *adapter,
+ u8 adr, u16 reg, u8 data)
+{
+ u8 m[3] = {(reg >> 8), (reg & 0xff), data};
+ struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m,
+ .len = sizeof(m)};
+
+ if (i2c_transfer(adapter, &msg, 1) != 1) {
+ pr_err(DEVICE_NAME ": Error writing EEPROM!\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int i2c_read_eeprom(struct i2c_adapter *adapter,
+ u8 adr, u16 reg, u8 *data, int len)
+{
+ u8 msg[2] = {(reg >> 8), (reg & 0xff)};
+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+ .buf = msg, .len = 2 },
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = data, .len = len} };
+
+ if (i2c_transfer(adapter, msgs, 2) != 2) {
+ pr_err(DEVICE_NAME ": Error reading EEPROM\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int ReadEEProm(struct i2c_adapter *adapter,
+ u16 Tag, u32 MaxLen, u8 *data, u32 *pLength)
+{
+ int status = 0;
+ u16 Addr = MICNG_EE_START, Length, tag = 0;
+ u8 EETag[3];
+
+ while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+ if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+ return -1;
+ tag = (EETag[0] << 8) | EETag[1];
+ if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+ return -1;
+ if (tag == Tag)
+ break;
+ Addr += sizeof(u16) + 1 + EETag[2];
+ }
+ if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+ pr_err(DEVICE_NAME
+ ": Reached EOEE @ Tag = %04x Length = %3d\n",
+ tag, EETag[2]);
+ return -1;
+ }
+ Length = EETag[2];
+ if (Length > MaxLen)
+ Length = (u16) MaxLen;
+ if (Length > 0) {
+ Addr += sizeof(u16) + 1;
+ status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length);
+ if (!status) {
+ *pLength = EETag[2];
+ if (Length < EETag[2])
+ ; /*status=STATUS_BUFFER_OVERFLOW; */
+ }
+ }
+ return status;
+}
+
+static int WriteEEProm(struct i2c_adapter *adapter,
+ u16 Tag, u32 Length, u8 *data)
+{
+ int status = 0;
+ u16 Addr = MICNG_EE_START;
+ u8 EETag[3];
+ u16 tag = 0;
+ int retry, i;
+
+ while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+ if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+ return -1;
+ tag = (EETag[0] << 8) | EETag[1];
+ if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+ return -1;
+ if (tag == Tag)
+ break;
+ Addr += sizeof(u16) + 1 + EETag[2];
+ }
+ if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+ pr_err(DEVICE_NAME
+ ": Reached EOEE @ Tag = %04x Length = %3d\n",
+ tag, EETag[2]);
+ return -1;
+ }
+
+ if (Length > EETag[2])
+ return -EINVAL;
+ /* Note: We write the data one byte at a time to avoid
+ issues with page sizes. (which are different for
+ each manufacture and eeprom size)
+ */
+ Addr += sizeof(u16) + 1;
+ for (i = 0; i < Length; i++, Addr++) {
+ status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]);
+
+ if (status)
+ break;
+
+ /* Poll for finishing write cycle */
+ retry = 10;
+ while (retry) {
+ u8 Tmp;
+
+ msleep(50);
+ status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1);
+ if (status)
+ break;
+ if (Tmp != data[i])
+ pr_err(DEVICE_NAME
+ "eeprom write error\n");
+ retry -= 1;
+ }
+ if (status) {
+ pr_err(DEVICE_NAME
+ ": Timeout polling eeprom\n");
+ break;
+ }
+ }
+ return status;
+}
+
+static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data)
+{
+ int stat;
+ u8 buf[2];
+ u32 len = 0;
+
+ stat = ReadEEProm(adapter, tag, 2, buf, &len);
+ if (stat)
+ return stat;
+ if (len != 2)
+ return -EINVAL;
+
+ *data = (buf[0] << 8) | buf[1];
+ return 0;
+}
+
+static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data)
+{
+ int stat;
+ u8 buf[2];
+
+ buf[0] = data >> 8;
+ buf[1] = data & 0xff;
+ stat = WriteEEProm(adapter, tag, 2, buf);
+ if (stat)
+ return stat;
+ return 0;
+}
+
+static s16 osc_deviation(void *priv, s16 deviation, int flag)
+{
+ struct ngene_channel *chan = priv;
+ struct i2c_adapter *adap = &chan->i2c_adapter;
+ u16 data = 0;
+
+ if (flag) {
+ data = (u16) deviation;
+ pr_info(DEVICE_NAME ": write deviation %d\n",
+ deviation);
+ eeprom_write_ushort(adap, 0x1000 + chan->number, data);
+ } else {
+ if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data))
+ data = 0;
+ pr_info(DEVICE_NAME ": read deviation %d\n",
+ (s16) data);
+ }
+
+ return (s16) data;
+}
+
+/****************************************************************************/
+/* Switch control (I2C gates, etc.) *****************************************/
+/****************************************************************************/
+
+
+static struct stv090x_config fe_cineS2 = {
+ .device = STV0900,
+ .demod_mode = STV090x_DUAL,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 27000000,
+ .address = 0x68,
+
+ .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+ .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .adc1_range = STV090x_ADC_1Vpp,
+ .adc2_range = STV090x_ADC_1Vpp,
+
+ .diseqc_envelope_mode = true,
+
+ .tuner_i2c_lock = cineS2_tuner_i2c_lock,
+};
+
+static struct stv090x_config fe_cineS2_2 = {
+ .device = STV0900,
+ .demod_mode = STV090x_DUAL,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 27000000,
+ .address = 0x69,
+
+ .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+ .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .adc1_range = STV090x_ADC_1Vpp,
+ .adc2_range = STV090x_ADC_1Vpp,
+
+ .diseqc_envelope_mode = true,
+
+ .tuner_i2c_lock = cineS2_tuner_i2c_lock,
+};
+
+static struct stv6110x_config tuner_cineS2_0 = {
+ .addr = 0x60,
+ .refclk = 27000000,
+ .clk_div = 1,
+};
+
+static struct stv6110x_config tuner_cineS2_1 = {
+ .addr = 0x63,
+ .refclk = 27000000,
+ .clk_div = 1,
+};
+
+static struct ngene_info ngene_info_cineS2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Linux4Media cineS2 DVB-S2 Twin Tuner",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0b, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 18,
+ .msi_supported = true,
+};
+
+static struct ngene_info ngene_info_satixS2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Mystique SaTiX-S2 Dual",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0b, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 18,
+ .msi_supported = true,
+};
+
+static struct ngene_info ngene_info_satixS2v2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Mystique SaTiX-S2 Dual (v2)",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+ NGENE_IO_TSOUT},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
+ .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0a, 0x08, 0x0b, 0x09},
+ .tsf = {3, 3},
+ .fw_version = 18,
+ .msi_supported = true,
+};
+
+static struct ngene_info ngene_info_cineS2v5 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+ NGENE_IO_TSOUT},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
+ .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0a, 0x08, 0x0b, 0x09},
+ .tsf = {3, 3},
+ .fw_version = 18,
+ .msi_supported = true,
+};
+
+
+static struct ngene_info ngene_info_duoFlex = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Digital Devices DuoFlex PCIe or miniPCIe",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+ NGENE_IO_TSOUT},
+ .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
+ .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
+ .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0a, 0x08, 0x0b, 0x09},
+ .tsf = {3, 3},
+ .fw_version = 18,
+ .msi_supported = true,
+};
+
+static struct ngene_info ngene_info_m780 = {
+ .type = NGENE_APP,
+ .name = "Aver M780 ATSC/QAM-B",
+
+ /* Channel 0 is analog, which is currently unsupported */
+ .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN },
+ .demod_attach = { NULL, demod_attach_lg330x },
+
+ /* Ensure these are NULL else the frame will call them (as funcs) */
+ .tuner_attach = { 0, 0, 0, 0 },
+ .fe_config = { NULL, &aver_m780 },
+ .avf = { 0 },
+
+ /* A custom electrical interface config for the demod to bridge */
+ .tsf = { 4, 4 },
+ .fw_version = 15,
+};
+
+static struct drxd_config fe_terratec_dvbt_0 = {
+ .index = 0,
+ .demod_address = 0x70,
+ .demod_revision = 0xa2,
+ .demoda_address = 0x00,
+ .pll_address = 0x60,
+ .pll_type = DVB_PLL_THOMSON_DTT7520X,
+ .clock = 20000,
+ .osc_deviation = osc_deviation,
+};
+
+static struct drxd_config fe_terratec_dvbt_1 = {
+ .index = 1,
+ .demod_address = 0x71,
+ .demod_revision = 0xa2,
+ .demoda_address = 0x00,
+ .pll_address = 0x60,
+ .pll_type = DVB_PLL_THOMSON_DTT7520X,
+ .clock = 20000,
+ .osc_deviation = osc_deviation,
+};
+
+static struct ngene_info ngene_info_terratec = {
+ .type = NGENE_TERRATEC,
+ .name = "Terratec Integra/Cinergy2400i Dual DVB-T",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_drxd, demod_attach_drxd},
+ .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1},
+ .i2c_access = 1,
+};
+
+/****************************************************************************/
+
+
+
+/****************************************************************************/
+/* PCI Subsystem ID *********************************************************/
+/****************************************************************************/
+
+#define NGENE_ID(_subvend, _subdev, _driverdata) { \
+ .vendor = NGENE_VID, .device = NGENE_PID, \
+ .subvendor = _subvend, .subdevice = _subdev, \
+ .driver_data = (unsigned long) &_driverdata }
+
+/****************************************************************************/
+
+static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+ NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
+ NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
+ NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
+ NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
+ NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+ NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
+ NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
+ NGENE_ID(0x1461, 0x062e, ngene_info_m780),
+ NGENE_ID(0x153b, 0x1167, ngene_info_terratec),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
+
+/****************************************************************************/
+/* Init/Exit ****************************************************************/
+/****************************************************************************/
+
+static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
+ enum pci_channel_state state)
+{
+ printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+ if (state == pci_channel_io_frozen)
+ return PCI_ERS_RESULT_NEED_RESET;
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": link reset\n");
+ return 0;
+}
+
+static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+ return 0;
+}
+
+static void ngene_resume(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": resume\n");
+}
+
+static struct pci_error_handlers ngene_errors = {
+ .error_detected = ngene_error_detected,
+ .link_reset = ngene_link_reset,
+ .slot_reset = ngene_slot_reset,
+ .resume = ngene_resume,
+};
+
+static struct pci_driver ngene_pci_driver = {
+ .name = "ngene",
+ .id_table = ngene_id_tbl,
+ .probe = ngene_probe,
+ .remove = __devexit_p(ngene_remove),
+ .err_handler = &ngene_errors,
+ .shutdown = ngene_shutdown,
+};
+
+static __init int module_init_ngene(void)
+{
+ printk(KERN_INFO
+ "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+ return pci_register_driver(&ngene_pci_driver);
+}
+
+static __exit void module_exit_ngene(void)
+{
+ pci_unregister_driver(&ngene_pci_driver);
+}
+
+module_init(module_init_ngene);
+module_exit(module_exit_ngene);
+
+MODULE_DESCRIPTION("nGene");
+MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
new file mode 100644
index 000000000000..c8e0d5b99d4c
--- /dev/null
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -0,0 +1,1707 @@
+/*
+ * ngene.c: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ * Modifications for new nGene firmware,
+ * support for EEPROM-copying,
+ * support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+static int one_adapter;
+module_param(one_adapter, int, 0444);
+MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
+
+static int shutdown_workaround;
+module_param(shutdown_workaround, int, 0644);
+MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Print debugging information.");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk if (debug) printk
+
+#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngreadl(adr) readl(dev->iomem + (adr))
+#define ngreadb(adr) readb(dev->iomem + (adr))
+#define ngcpyto(adr, src, count) memcpy_toio((char *) \
+ (dev->iomem + (adr)), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
+ (dev->iomem + (adr)), (count))
+
+/****************************************************************************/
+/* nGene interrupt handler **************************************************/
+/****************************************************************************/
+
+static void event_tasklet(unsigned long data)
+{
+ struct ngene *dev = (struct ngene *)data;
+
+ while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
+ struct EVENT_BUFFER Event =
+ dev->EventQueue[dev->EventQueueReadIndex];
+ dev->EventQueueReadIndex =
+ (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
+
+ if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
+ dev->TxEventNotify(dev, Event.TimeStamp);
+ if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
+ dev->RxEventNotify(dev, Event.TimeStamp,
+ Event.RXCharacter);
+ }
+}
+
+static void demux_tasklet(unsigned long data)
+{
+ struct ngene_channel *chan = (struct ngene_channel *)data;
+ struct SBufferHeader *Cur = chan->nextBuffer;
+
+ spin_lock_irq(&chan->state_lock);
+
+ while (Cur->ngeneBuffer.SR.Flags & 0x80) {
+ if (chan->mode & NGENE_IO_TSOUT) {
+ u32 Flags = chan->DataFormatFlags;
+ if (Cur->ngeneBuffer.SR.Flags & 0x20)
+ Flags |= BEF_OVERFLOW;
+ if (chan->pBufferExchange) {
+ if (!chan->pBufferExchange(chan,
+ Cur->Buffer1,
+ chan->Capture1Length,
+ Cur->ngeneBuffer.SR.
+ Clock, Flags)) {
+ /*
+ We didn't get data
+ Clear in service flag to make sure we
+ get called on next interrupt again.
+ leave fill/empty (0x80) flag alone
+ to avoid hardware running out of
+ buffers during startup, we hold only
+ in run state ( the source may be late
+ delivering data )
+ */
+
+ if (chan->HWState == HWSTATE_RUN) {
+ Cur->ngeneBuffer.SR.Flags &=
+ ~0x40;
+ break;
+ /* Stop processing stream */
+ }
+ } else {
+ /* We got a valid buffer,
+ so switch to run state */
+ chan->HWState = HWSTATE_RUN;
+ }
+ } else {
+ printk(KERN_ERR DEVICE_NAME ": OOPS\n");
+ if (chan->HWState == HWSTATE_RUN) {
+ Cur->ngeneBuffer.SR.Flags &= ~0x40;
+ break; /* Stop processing stream */
+ }
+ }
+ if (chan->AudioDTOUpdated) {
+ printk(KERN_INFO DEVICE_NAME
+ ": Update AudioDTO = %d\n",
+ chan->AudioDTOValue);
+ Cur->ngeneBuffer.SR.DTOUpdate =
+ chan->AudioDTOValue;
+ chan->AudioDTOUpdated = 0;
+ }
+ } else {
+ if (chan->HWState == HWSTATE_RUN) {
+ u32 Flags = chan->DataFormatFlags;
+ IBufferExchange *exch1 = chan->pBufferExchange;
+ IBufferExchange *exch2 = chan->pBufferExchange2;
+ if (Cur->ngeneBuffer.SR.Flags & 0x01)
+ Flags |= BEF_EVEN_FIELD;
+ if (Cur->ngeneBuffer.SR.Flags & 0x20)
+ Flags |= BEF_OVERFLOW;
+ spin_unlock_irq(&chan->state_lock);
+ if (exch1)
+ exch1(chan, Cur->Buffer1,
+ chan->Capture1Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ if (exch2)
+ exch2(chan, Cur->Buffer2,
+ chan->Capture2Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ spin_lock_irq(&chan->state_lock);
+ } else if (chan->HWState != HWSTATE_STOP)
+ chan->HWState = HWSTATE_RUN;
+ }
+ Cur->ngeneBuffer.SR.Flags = 0x00;
+ Cur = Cur->Next;
+ }
+ chan->nextBuffer = Cur;
+
+ spin_unlock_irq(&chan->state_lock);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+ struct ngene *dev = (struct ngene *)dev_id;
+ u32 icounts = 0;
+ irqreturn_t rc = IRQ_NONE;
+ u32 i = MAX_STREAM;
+ u8 *tmpCmdDoneByte;
+
+ if (dev->BootFirmware) {
+ icounts = ngreadl(NGENE_INT_COUNTS);
+ if (icounts != dev->icounts) {
+ ngwritel(0, FORCE_NMI);
+ dev->cmd_done = 1;
+ wake_up(&dev->cmd_wq);
+ dev->icounts = icounts;
+ rc = IRQ_HANDLED;
+ }
+ return rc;
+ }
+
+ ngwritel(0, FORCE_NMI);
+
+ spin_lock(&dev->cmd_lock);
+ tmpCmdDoneByte = dev->CmdDoneByte;
+ if (tmpCmdDoneByte &&
+ (*tmpCmdDoneByte ||
+ (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
+ dev->CmdDoneByte = NULL;
+ dev->cmd_done = 1;
+ wake_up(&dev->cmd_wq);
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock(&dev->cmd_lock);
+
+ if (dev->EventBuffer->EventStatus & 0x80) {
+ u8 nextWriteIndex =
+ (dev->EventQueueWriteIndex + 1) &
+ (EVENT_QUEUE_SIZE - 1);
+ if (nextWriteIndex != dev->EventQueueReadIndex) {
+ dev->EventQueue[dev->EventQueueWriteIndex] =
+ *(dev->EventBuffer);
+ dev->EventQueueWriteIndex = nextWriteIndex;
+ } else {
+ printk(KERN_ERR DEVICE_NAME ": event overflow\n");
+ dev->EventQueueOverflowCount += 1;
+ dev->EventQueueOverflowFlag = 1;
+ }
+ dev->EventBuffer->EventStatus &= ~0x80;
+ tasklet_schedule(&dev->event_tasklet);
+ rc = IRQ_HANDLED;
+ }
+
+ while (i > 0) {
+ i--;
+ spin_lock(&dev->channel[i].state_lock);
+ /* if (dev->channel[i].State>=KSSTATE_RUN) { */
+ if (dev->channel[i].nextBuffer) {
+ if ((dev->channel[i].nextBuffer->
+ ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
+ dev->channel[i].nextBuffer->
+ ngeneBuffer.SR.Flags |= 0x40;
+ tasklet_schedule(
+ &dev->channel[i].demux_tasklet);
+ rc = IRQ_HANDLED;
+ }
+ }
+ spin_unlock(&dev->channel[i].state_lock);
+ }
+
+ /* Request might have been processed by a previous call. */
+ return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+/* nGene command interface **************************************************/
+/****************************************************************************/
+
+static void dump_command_io(struct ngene *dev)
+{
+ u8 buf[8], *b;
+
+ ngcpyfrom(buf, HOST_TO_NGENE, 8);
+ printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf);
+
+ ngcpyfrom(buf, NGENE_TO_HOST, 8);
+ printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf);
+
+ b = dev->hosttongene;
+ printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b);
+
+ b = dev->ngenetohost;
+ printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b);
+}
+
+static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
+{
+ int ret;
+ u8 *tmpCmdDoneByte;
+
+ dev->cmd_done = 0;
+
+ if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
+ dev->BootFirmware = 1;
+ dev->icounts = ngreadl(NGENE_INT_COUNTS);
+ ngwritel(0, NGENE_COMMAND);
+ ngwritel(0, NGENE_COMMAND_HI);
+ ngwritel(0, NGENE_STATUS);
+ ngwritel(0, NGENE_STATUS_HI);
+ ngwritel(0, NGENE_EVENT);
+ ngwritel(0, NGENE_EVENT_HI);
+ } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
+ u64 fwio = dev->PAFWInterfaceBuffer;
+
+ ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
+ ngwritel(fwio >> 32, NGENE_COMMAND_HI);
+ ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
+ ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
+ ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
+ ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
+ }
+
+ memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
+
+ if (dev->BootFirmware)
+ ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
+
+ spin_lock_irq(&dev->cmd_lock);
+ tmpCmdDoneByte = dev->ngenetohost + com->out_len;
+ if (!com->out_len)
+ tmpCmdDoneByte++;
+ *tmpCmdDoneByte = 0;
+ dev->ngenetohost[0] = 0;
+ dev->ngenetohost[1] = 0;
+ dev->CmdDoneByte = tmpCmdDoneByte;
+ spin_unlock_irq(&dev->cmd_lock);
+
+ /* Notify 8051. */
+ ngwritel(1, FORCE_INT);
+
+ ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
+ if (!ret) {
+ /*ngwritel(0, FORCE_NMI);*/
+
+ printk(KERN_ERR DEVICE_NAME
+ ": Command timeout cmd=%02x prev=%02x\n",
+ com->cmd.hdr.Opcode, dev->prev_cmd);
+ dump_command_io(dev);
+ return -1;
+ }
+ if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
+ dev->BootFirmware = 0;
+
+ dev->prev_cmd = com->cmd.hdr.Opcode;
+
+ if (!com->out_len)
+ return 0;
+
+ memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
+
+ return 0;
+}
+
+int ngene_command(struct ngene *dev, struct ngene_command *com)
+{
+ int result;
+
+ down(&dev->cmd_mutex);
+ result = ngene_command_mutex(dev, com);
+ up(&dev->cmd_mutex);
+ return result;
+}
+
+
+static int ngene_command_load_firmware(struct ngene *dev,
+ u8 *ngene_fw, u32 size)
+{
+#define FIRSTCHUNK (1024)
+ u32 cleft;
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
+ com.cmd.hdr.Length = 0;
+ com.in_len = 0;
+ com.out_len = 0;
+
+ ngene_command(dev, &com);
+
+ cleft = (size + 3) & ~3;
+ if (cleft > FIRSTCHUNK) {
+ ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
+ cleft - FIRSTCHUNK);
+ cleft = FIRSTCHUNK;
+ }
+ ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
+
+ memset(&com, 0, sizeof(struct ngene_command));
+ com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
+ com.cmd.hdr.Length = 4;
+ com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
+ com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
+ com.in_len = 4;
+ com.out_len = 0;
+
+ return ngene_command(dev, &com);
+}
+
+
+static int ngene_command_config_buf(struct ngene *dev, u8 config)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
+ com.cmd.hdr.Length = 1;
+ com.cmd.ConfigureBuffers.config = config;
+ com.in_len = 1;
+ com.out_len = 0;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
+ com.cmd.hdr.Length = 6;
+ memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
+ com.in_len = 6;
+ com.out_len = 0;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
+ com.cmd.hdr.Length = 1;
+ com.cmd.SetGpioPin.select = select | (level << 7);
+ com.in_len = 1;
+ com.out_len = 0;
+
+ return ngene_command(dev, &com);
+}
+
+
+/*
+ 02000640 is sample on rising edge.
+ 02000740 is sample on falling edge.
+ 02000040 is ignore "valid" signal
+
+ 0: FD_CTL1 Bit 7,6 must be 0,1
+ 7 disable(fw controlled)
+ 6 0-AUX,1-TS
+ 5 0-par,1-ser
+ 4 0-lsb/1-msb
+ 3,2 reserved
+ 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
+ 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
+ 2: FD_STA is read-only. 0-sync
+ 3: FD_INSYNC is number of 47s to trigger "in sync".
+ 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
+ 5: FD_MAXBYTE1 is low-order of bytes per packet.
+ 6: FD_MAXBYTE2 is high-order of bytes per packet.
+ 7: Top byte is unused.
+*/
+
+/****************************************************************************/
+
+static u8 TSFeatureDecoderSetup[8 * 5] = {
+ 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
+ 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
+ 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
+ 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
+};
+
+/* Set NGENE I2S Config to 16 bit packed */
+static u8 I2SConfiguration[] = {
+ 0x00, 0x10, 0x00, 0x00,
+ 0x80, 0x10, 0x00, 0x00,
+};
+
+static u8 SPDIFConfiguration[10] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Set NGENE I2S Config to transport stream compatible mode */
+
+static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
+
+static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
+
+static u8 ITUDecoderSetup[4][16] = {
+ {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */
+ 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
+ {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+ {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+ {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+};
+
+/*
+ * 50 48 60 gleich
+ * 27p50 9f 00 22 80 42 69 18 ...
+ * 27p60 93 00 22 80 82 69 1c ...
+ */
+
+/* Maxbyte to 1144 (for raw data) */
+static u8 ITUFeatureDecoderSetup[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
+};
+
+void FillTSBuffer(void *Buffer, int Length, u32 Flags)
+{
+ u32 *ptr = Buffer;
+
+ memset(Buffer, TS_FILLER, Length);
+ while (Length > 0) {
+ if (Flags & DF_SWAP32)
+ *ptr = 0x471FFF10;
+ else
+ *ptr = 0x10FF1F47;
+ ptr += (188 / 4);
+ Length -= 188;
+ }
+}
+
+
+static void flush_buffers(struct ngene_channel *chan)
+{
+ u8 val;
+
+ do {
+ msleep(1);
+ spin_lock_irq(&chan->state_lock);
+ val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
+ spin_unlock_irq(&chan->state_lock);
+ } while (val);
+}
+
+static void clear_buffers(struct ngene_channel *chan)
+{
+ struct SBufferHeader *Cur = chan->nextBuffer;
+
+ do {
+ memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
+ if (chan->mode & NGENE_IO_TSOUT)
+ FillTSBuffer(Cur->Buffer1,
+ chan->Capture1Length,
+ chan->DataFormatFlags);
+ Cur = Cur->Next;
+ } while (Cur != chan->nextBuffer);
+
+ if (chan->mode & NGENE_IO_TSOUT) {
+ chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
+ chan->AudioDTOValue;
+ chan->AudioDTOUpdated = 0;
+
+ Cur = chan->TSIdleBuffer.Head;
+
+ do {
+ memset(&Cur->ngeneBuffer.SR, 0,
+ sizeof(Cur->ngeneBuffer.SR));
+ FillTSBuffer(Cur->Buffer1,
+ chan->Capture1Length,
+ chan->DataFormatFlags);
+ Cur = Cur->Next;
+ } while (Cur != chan->TSIdleBuffer.Head);
+ }
+}
+
+static int ngene_command_stream_control(struct ngene *dev, u8 stream,
+ u8 control, u8 mode, u8 flags)
+{
+ struct ngene_channel *chan = &dev->channel[stream];
+ struct ngene_command com;
+ u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
+ u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
+ u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
+ u16 BsSDO = 0x9B00;
+
+ down(&dev->stream_mutex);
+ memset(&com, 0, sizeof(com));
+ com.cmd.hdr.Opcode = CMD_CONTROL;
+ com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
+ com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
+ if (chan->mode & NGENE_IO_TSOUT)
+ com.cmd.StreamControl.Stream |= 0x07;
+ com.cmd.StreamControl.Control = control |
+ (flags & SFLAG_ORDER_LUMA_CHROMA);
+ com.cmd.StreamControl.Mode = mode;
+ com.in_len = sizeof(struct FW_STREAM_CONTROL);
+ com.out_len = 0;
+
+ dprintk(KERN_INFO DEVICE_NAME
+ ": Stream=%02x, Control=%02x, Mode=%02x\n",
+ com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
+ com.cmd.StreamControl.Mode);
+
+ chan->Mode = mode;
+
+ if (!(control & 0x80)) {
+ spin_lock_irq(&chan->state_lock);
+ if (chan->State == KSSTATE_RUN) {
+ chan->State = KSSTATE_ACQUIRE;
+ chan->HWState = HWSTATE_STOP;
+ spin_unlock_irq(&chan->state_lock);
+ if (ngene_command(dev, &com) < 0) {
+ up(&dev->stream_mutex);
+ return -1;
+ }
+ /* clear_buffers(chan); */
+ flush_buffers(chan);
+ up(&dev->stream_mutex);
+ return 0;
+ }
+ spin_unlock_irq(&chan->state_lock);
+ up(&dev->stream_mutex);
+ return 0;
+ }
+
+ if (mode & SMODE_AUDIO_CAPTURE) {
+ com.cmd.StreamControl.CaptureBlockCount =
+ chan->Capture1Length / AUDIO_BLOCK_SIZE;
+ com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+ } else if (mode & SMODE_TRANSPORT_STREAM) {
+ com.cmd.StreamControl.CaptureBlockCount =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.MaxLinesPerField =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.Buffer_Address =
+ chan->TSRingBuffer.PAHead;
+ if (chan->mode & NGENE_IO_TSOUT) {
+ com.cmd.StreamControl.BytesPerVBILine =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.Stream |= 0x07;
+ }
+ } else {
+ com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
+ com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
+ com.cmd.StreamControl.MinLinesPerField = 100;
+ com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+
+ if (mode & SMODE_VBI_CAPTURE) {
+ com.cmd.StreamControl.MaxVBILinesPerField =
+ chan->nVBILines;
+ com.cmd.StreamControl.MinVBILinesPerField = 0;
+ com.cmd.StreamControl.BytesPerVBILine =
+ chan->nBytesPerVBILine;
+ }
+ if (flags & SFLAG_COLORBAR)
+ com.cmd.StreamControl.Stream |= 0x04;
+ }
+
+ spin_lock_irq(&chan->state_lock);
+ if (mode & SMODE_AUDIO_CAPTURE) {
+ chan->nextBuffer = chan->RingBuffer.Head;
+ if (mode & SMODE_AUDIO_SPDIF) {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(SPDIFConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSPI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ SPDIFConfiguration, sizeof(SPDIFConfiguration));
+ } else {
+ com.cmd.StreamControl.SetupDataLen = 4;
+ com.cmd.StreamControl.SetupDataAddr = BsSDI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ I2SConfiguration +
+ 4 * dev->card_info->i2s[stream], 4);
+ }
+ } else if (mode & SMODE_TRANSPORT_STREAM) {
+ chan->nextBuffer = chan->TSRingBuffer.Head;
+ if (stream >= STREAM_AUDIOIN1) {
+ if (chan->mode & NGENE_IO_TSOUT) {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(TS_I2SOutConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSDO;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TS_I2SOutConfiguration,
+ sizeof(TS_I2SOutConfiguration));
+ } else {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(TS_I2SConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSDI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TS_I2SConfiguration,
+ sizeof(TS_I2SConfiguration));
+ }
+ } else {
+ com.cmd.StreamControl.SetupDataLen = 8;
+ com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TSFeatureDecoderSetup +
+ 8 * dev->card_info->tsf[stream], 8);
+ }
+ } else {
+ chan->nextBuffer = chan->RingBuffer.Head;
+ com.cmd.StreamControl.SetupDataLen =
+ 16 + sizeof(ITUFeatureDecoderSetup);
+ com.cmd.StreamControl.SetupDataAddr = BsUVI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ ITUDecoderSetup[chan->itumode], 16);
+ memcpy(com.cmd.StreamControl.SetupData + 16,
+ ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
+ }
+ clear_buffers(chan);
+ chan->State = KSSTATE_RUN;
+ if (mode & SMODE_TRANSPORT_STREAM)
+ chan->HWState = HWSTATE_RUN;
+ else
+ chan->HWState = HWSTATE_STARTUP;
+ spin_unlock_irq(&chan->state_lock);
+
+ if (ngene_command(dev, &com) < 0) {
+ up(&dev->stream_mutex);
+ return -1;
+ }
+ up(&dev->stream_mutex);
+ return 0;
+}
+
+void set_transfer(struct ngene_channel *chan, int state)
+{
+ u8 control = 0, mode = 0, flags = 0;
+ struct ngene *dev = chan->dev;
+ int ret;
+
+ /*
+ printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
+ msleep(100);
+ */
+
+ if (state) {
+ if (chan->running) {
+ printk(KERN_INFO DEVICE_NAME ": already running\n");
+ return;
+ }
+ } else {
+ if (!chan->running) {
+ printk(KERN_INFO DEVICE_NAME ": already stopped\n");
+ return;
+ }
+ }
+
+ if (dev->card_info->switch_ctrl)
+ dev->card_info->switch_ctrl(chan, 1, state ^ 1);
+
+ if (state) {
+ spin_lock_irq(&chan->state_lock);
+
+ /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ ngreadl(0x9310)); */
+ dvb_ringbuffer_flush(&dev->tsout_rbuf);
+ control = 0x80;
+ if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+ chan->Capture1Length = 512 * 188;
+ mode = SMODE_TRANSPORT_STREAM;
+ }
+ if (chan->mode & NGENE_IO_TSOUT) {
+ chan->pBufferExchange = tsout_exchange;
+ /* 0x66666666 = 50MHz *2^33 /250MHz */
+ chan->AudioDTOValue = 0x80000000;
+ chan->AudioDTOUpdated = 1;
+ }
+ if (chan->mode & NGENE_IO_TSIN)
+ chan->pBufferExchange = tsin_exchange;
+ spin_unlock_irq(&chan->state_lock);
+ } else
+ ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ ngreadl(0x9310)); */
+
+ ret = ngene_command_stream_control(dev, chan->number,
+ control, mode, flags);
+ if (!ret)
+ chan->running = state;
+ else
+ printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
+ state);
+ if (!state) {
+ spin_lock_irq(&chan->state_lock);
+ chan->pBufferExchange = NULL;
+ dvb_ringbuffer_flush(&dev->tsout_rbuf);
+ spin_unlock_irq(&chan->state_lock);
+ }
+}
+
+
+/****************************************************************************/
+/* nGene hardware init and release functions ********************************/
+/****************************************************************************/
+
+static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
+{
+ struct SBufferHeader *Cur = rb->Head;
+ u32 j;
+
+ if (!Cur)
+ return;
+
+ for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
+ if (Cur->Buffer1)
+ pci_free_consistent(dev->pci_dev,
+ rb->Buffer1Length,
+ Cur->Buffer1,
+ Cur->scList1->Address);
+
+ if (Cur->Buffer2)
+ pci_free_consistent(dev->pci_dev,
+ rb->Buffer2Length,
+ Cur->Buffer2,
+ Cur->scList2->Address);
+ }
+
+ if (rb->SCListMem)
+ pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
+ rb->SCListMem, rb->PASCListMem);
+
+ pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
+}
+
+static void free_idlebuffer(struct ngene *dev,
+ struct SRingBufferDescriptor *rb,
+ struct SRingBufferDescriptor *tb)
+{
+ int j;
+ struct SBufferHeader *Cur = tb->Head;
+
+ if (!rb->Head)
+ return;
+ free_ringbuffer(dev, rb);
+ for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
+ Cur->Buffer2 = NULL;
+ Cur->scList2 = NULL;
+ Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
+ Cur->ngeneBuffer.Number_of_entries_2 = 0;
+ }
+}
+
+static void free_common_buffers(struct ngene *dev)
+{
+ u32 i;
+ struct ngene_channel *chan;
+
+ for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+ chan = &dev->channel[i];
+ free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
+ free_ringbuffer(dev, &chan->RingBuffer);
+ free_ringbuffer(dev, &chan->TSRingBuffer);
+ }
+
+ if (dev->OverflowBuffer)
+ pci_free_consistent(dev->pci_dev,
+ OVERFLOW_BUFFER_SIZE,
+ dev->OverflowBuffer, dev->PAOverflowBuffer);
+
+ if (dev->FWInterfaceBuffer)
+ pci_free_consistent(dev->pci_dev,
+ 4096,
+ dev->FWInterfaceBuffer,
+ dev->PAFWInterfaceBuffer);
+}
+
+/****************************************************************************/
+/* Ring buffer handling *****************************************************/
+/****************************************************************************/
+
+static int create_ring_buffer(struct pci_dev *pci_dev,
+ struct SRingBufferDescriptor *descr, u32 NumBuffers)
+{
+ dma_addr_t tmp;
+ struct SBufferHeader *Head;
+ u32 i;
+ u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
+ u64 PARingBufferHead;
+ u64 PARingBufferCur;
+ u64 PARingBufferNext;
+ struct SBufferHeader *Cur, *Next;
+
+ descr->Head = NULL;
+ descr->MemSize = 0;
+ descr->PAHead = 0;
+ descr->NumBuffers = 0;
+
+ if (MemSize < 4096)
+ MemSize = 4096;
+
+ Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
+ PARingBufferHead = tmp;
+
+ if (!Head)
+ return -ENOMEM;
+
+ memset(Head, 0, MemSize);
+
+ PARingBufferCur = PARingBufferHead;
+ Cur = Head;
+
+ for (i = 0; i < NumBuffers - 1; i++) {
+ Next = (struct SBufferHeader *)
+ (((u8 *) Cur) + SIZEOF_SBufferHeader);
+ PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
+ Cur->Next = Next;
+ Cur->ngeneBuffer.Next = PARingBufferNext;
+ Cur = Next;
+ PARingBufferCur = PARingBufferNext;
+ }
+ /* Last Buffer points back to first one */
+ Cur->Next = Head;
+ Cur->ngeneBuffer.Next = PARingBufferHead;
+
+ descr->Head = Head;
+ descr->MemSize = MemSize;
+ descr->PAHead = PARingBufferHead;
+ descr->NumBuffers = NumBuffers;
+
+ return 0;
+}
+
+static int AllocateRingBuffers(struct pci_dev *pci_dev,
+ dma_addr_t of,
+ struct SRingBufferDescriptor *pRingBuffer,
+ u32 Buffer1Length, u32 Buffer2Length)
+{
+ dma_addr_t tmp;
+ u32 i, j;
+ int status = 0;
+ u32 SCListMemSize = pRingBuffer->NumBuffers
+ * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
+ NUM_SCATTER_GATHER_ENTRIES)
+ * sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+ u64 PASCListMem;
+ struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
+ u64 PASCListEntry;
+ struct SBufferHeader *Cur;
+ void *SCListMem;
+
+ if (SCListMemSize < 4096)
+ SCListMemSize = 4096;
+
+ SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
+
+ PASCListMem = tmp;
+ if (SCListMem == NULL)
+ return -ENOMEM;
+
+ memset(SCListMem, 0, SCListMemSize);
+
+ pRingBuffer->SCListMem = SCListMem;
+ pRingBuffer->PASCListMem = PASCListMem;
+ pRingBuffer->SCListMemSize = SCListMemSize;
+ pRingBuffer->Buffer1Length = Buffer1Length;
+ pRingBuffer->Buffer2Length = Buffer2Length;
+
+ SCListEntry = SCListMem;
+ PASCListEntry = PASCListMem;
+ Cur = pRingBuffer->Head;
+
+ for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
+ u64 PABuffer;
+
+ void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
+ &tmp);
+ PABuffer = tmp;
+
+ if (Buffer == NULL)
+ return -ENOMEM;
+
+ Cur->Buffer1 = Buffer;
+
+ SCListEntry->Address = PABuffer;
+ SCListEntry->Length = Buffer1Length;
+
+ Cur->scList1 = SCListEntry;
+ Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
+ Cur->ngeneBuffer.Number_of_entries_1 =
+ NUM_SCATTER_GATHER_ENTRIES;
+
+ SCListEntry += 1;
+ PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+ for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
+ SCListEntry->Address = of;
+ SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+ SCListEntry += 1;
+ PASCListEntry +=
+ sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+ }
+#endif
+
+ if (!Buffer2Length)
+ continue;
+
+ Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
+ PABuffer = tmp;
+
+ if (Buffer == NULL)
+ return -ENOMEM;
+
+ Cur->Buffer2 = Buffer;
+
+ SCListEntry->Address = PABuffer;
+ SCListEntry->Length = Buffer2Length;
+
+ Cur->scList2 = SCListEntry;
+ Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
+ Cur->ngeneBuffer.Number_of_entries_2 =
+ NUM_SCATTER_GATHER_ENTRIES;
+
+ SCListEntry += 1;
+ PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+ for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
+ SCListEntry->Address = of;
+ SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+ SCListEntry += 1;
+ PASCListEntry +=
+ sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+ }
+#endif
+
+ }
+
+ return status;
+}
+
+static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
+ struct SRingBufferDescriptor *pRingBuffer)
+{
+ int status = 0;
+
+ /* Copy pointer to scatter gather list in TSRingbuffer
+ structure for buffer 2
+ Load number of buffer
+ */
+ u32 n = pRingBuffer->NumBuffers;
+
+ /* Point to first buffer entry */
+ struct SBufferHeader *Cur = pRingBuffer->Head;
+ int i;
+ /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
+ for (i = 0; i < n; i++) {
+ Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
+ Cur->scList2 = pIdleBuffer->Head->scList1;
+ Cur->ngeneBuffer.Address_of_first_entry_2 =
+ pIdleBuffer->Head->ngeneBuffer.
+ Address_of_first_entry_1;
+ Cur->ngeneBuffer.Number_of_entries_2 =
+ pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
+ Cur = Cur->Next;
+ }
+ return status;
+}
+
+static u32 RingBufferSizes[MAX_STREAM] = {
+ RING_SIZE_VIDEO,
+ RING_SIZE_VIDEO,
+ RING_SIZE_AUDIO,
+ RING_SIZE_AUDIO,
+ RING_SIZE_AUDIO,
+};
+
+static u32 Buffer1Sizes[MAX_STREAM] = {
+ MAX_VIDEO_BUFFER_SIZE,
+ MAX_VIDEO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE
+};
+
+static u32 Buffer2Sizes[MAX_STREAM] = {
+ MAX_VBI_BUFFER_SIZE,
+ MAX_VBI_BUFFER_SIZE,
+ 0,
+ 0,
+ 0
+};
+
+
+static int AllocCommonBuffers(struct ngene *dev)
+{
+ int status = 0, i;
+
+ dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
+ &dev->PAFWInterfaceBuffer);
+ if (!dev->FWInterfaceBuffer)
+ return -ENOMEM;
+ dev->hosttongene = dev->FWInterfaceBuffer;
+ dev->ngenetohost = dev->FWInterfaceBuffer + 256;
+ dev->EventBuffer = dev->FWInterfaceBuffer + 512;
+
+ dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
+ OVERFLOW_BUFFER_SIZE,
+ &dev->PAOverflowBuffer);
+ if (!dev->OverflowBuffer)
+ return -ENOMEM;
+ memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
+
+ for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+ int type = dev->card_info->io_type[i];
+
+ dev->channel[i].State = KSSTATE_STOP;
+
+ if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].RingBuffer,
+ RingBufferSizes[i]);
+ if (status < 0)
+ break;
+
+ if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->
+ PAOverflowBuffer,
+ &dev->channel[i].
+ RingBuffer,
+ Buffer1Sizes[i],
+ Buffer2Sizes[i]);
+ if (status < 0)
+ break;
+ } else if (type & NGENE_IO_HDTV) {
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->
+ PAOverflowBuffer,
+ &dev->channel[i].
+ RingBuffer,
+ MAX_HDTV_BUFFER_SIZE,
+ 0);
+ if (status < 0)
+ break;
+ }
+ }
+
+ if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].
+ TSRingBuffer, RING_SIZE_TS);
+ if (status < 0)
+ break;
+
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->PAOverflowBuffer,
+ &dev->channel[i].
+ TSRingBuffer,
+ MAX_TS_BUFFER_SIZE, 0);
+ if (status)
+ break;
+ }
+
+ if (type & NGENE_IO_TSOUT) {
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].
+ TSIdleBuffer, 1);
+ if (status < 0)
+ break;
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->PAOverflowBuffer,
+ &dev->channel[i].
+ TSIdleBuffer,
+ MAX_TS_BUFFER_SIZE, 0);
+ if (status)
+ break;
+ FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
+ &dev->channel[i].TSRingBuffer);
+ }
+ }
+ return status;
+}
+
+static void ngene_release_buffers(struct ngene *dev)
+{
+ if (dev->iomem)
+ iounmap(dev->iomem);
+ free_common_buffers(dev);
+ vfree(dev->tsout_buf);
+ vfree(dev->tsin_buf);
+ vfree(dev->ain_buf);
+ vfree(dev->vin_buf);
+ vfree(dev);
+}
+
+static int ngene_get_buffers(struct ngene *dev)
+{
+ if (AllocCommonBuffers(dev))
+ return -ENOMEM;
+ if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
+ dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
+ if (!dev->tsout_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->tsout_rbuf,
+ dev->tsout_buf, TSOUT_BUF_SIZE);
+ }
+ if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
+ dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
+ if (!dev->tsin_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->tsin_rbuf,
+ dev->tsin_buf, TSIN_BUF_SIZE);
+ }
+ if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
+ dev->ain_buf = vmalloc(AIN_BUF_SIZE);
+ if (!dev->ain_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
+ }
+ if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
+ dev->vin_buf = vmalloc(VIN_BUF_SIZE);
+ if (!dev->vin_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
+ }
+ dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
+ pci_resource_len(dev->pci_dev, 0));
+ if (!dev->iomem)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ngene_init(struct ngene *dev)
+{
+ int i;
+
+ tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
+
+ memset_io(dev->iomem + 0xc000, 0x00, 0x220);
+ memset_io(dev->iomem + 0xc400, 0x00, 0x100);
+
+ for (i = 0; i < MAX_STREAM; i++) {
+ dev->channel[i].dev = dev;
+ dev->channel[i].number = i;
+ }
+
+ dev->fw_interface_version = 0;
+
+ ngwritel(0, NGENE_INT_ENABLE);
+
+ dev->icounts = ngreadl(NGENE_INT_COUNTS);
+
+ dev->device_version = ngreadl(DEV_VER) & 0x0f;
+ printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
+ dev->device_version);
+}
+
+static int ngene_load_firm(struct ngene *dev)
+{
+ u32 size;
+ const struct firmware *fw = NULL;
+ u8 *ngene_fw;
+ char *fw_name;
+ int err, version;
+
+ version = dev->card_info->fw_version;
+
+ switch (version) {
+ default:
+ case 15:
+ version = 15;
+ size = 23466;
+ fw_name = "ngene_15.fw";
+ dev->cmd_timeout_workaround = true;
+ break;
+ case 16:
+ size = 23498;
+ fw_name = "ngene_16.fw";
+ dev->cmd_timeout_workaround = true;
+ break;
+ case 17:
+ size = 24446;
+ fw_name = "ngene_17.fw";
+ dev->cmd_timeout_workaround = true;
+ break;
+ case 18:
+ size = 0;
+ fw_name = "ngene_18.fw";
+ break;
+ }
+
+ if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
+ printk(KERN_ERR DEVICE_NAME
+ ": Could not load firmware file %s.\n", fw_name);
+ printk(KERN_INFO DEVICE_NAME
+ ": Copy %s to your hotplug directory!\n", fw_name);
+ return -1;
+ }
+ if (size == 0)
+ size = fw->size;
+ if (size != fw->size) {
+ printk(KERN_ERR DEVICE_NAME
+ ": Firmware %s has invalid size!", fw_name);
+ err = -1;
+ } else {
+ printk(KERN_INFO DEVICE_NAME
+ ": Loading firmware file %s.\n", fw_name);
+ ngene_fw = (u8 *) fw->data;
+ err = ngene_command_load_firmware(dev, ngene_fw, size);
+ }
+
+ release_firmware(fw);
+
+ return err;
+}
+
+static void ngene_stop(struct ngene *dev)
+{
+ down(&dev->cmd_mutex);
+ i2c_del_adapter(&(dev->channel[0].i2c_adapter));
+ i2c_del_adapter(&(dev->channel[1].i2c_adapter));
+ ngwritel(0, NGENE_INT_ENABLE);
+ ngwritel(0, NGENE_COMMAND);
+ ngwritel(0, NGENE_COMMAND_HI);
+ ngwritel(0, NGENE_STATUS);
+ ngwritel(0, NGENE_STATUS_HI);
+ ngwritel(0, NGENE_EVENT);
+ ngwritel(0, NGENE_EVENT_HI);
+ free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
+}
+
+static int ngene_buffer_config(struct ngene *dev)
+{
+ int stat;
+
+ if (dev->card_info->fw_version >= 17) {
+ u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
+ u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
+ u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
+ u8 *bconf = tsin12_config;
+
+ if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
+ dev->card_info->io_type[3]&NGENE_IO_TSIN) {
+ bconf = tsin1234_config;
+ if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
+ dev->ci.en)
+ bconf = tsio1235_config;
+ }
+ stat = ngene_command_config_free_buf(dev, bconf);
+ } else {
+ int bconf = BUFFER_CONFIG_4422;
+
+ if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+ bconf = BUFFER_CONFIG_3333;
+ stat = ngene_command_config_buf(dev, bconf);
+ }
+ return stat;
+}
+
+
+static int ngene_start(struct ngene *dev)
+{
+ int stat;
+ int i;
+
+ pci_set_master(dev->pci_dev);
+ ngene_init(dev);
+
+ stat = request_irq(dev->pci_dev->irq, irq_handler,
+ IRQF_SHARED, "nGene",
+ (void *)dev);
+ if (stat < 0)
+ return stat;
+
+ init_waitqueue_head(&dev->cmd_wq);
+ init_waitqueue_head(&dev->tx_wq);
+ init_waitqueue_head(&dev->rx_wq);
+ sema_init(&dev->cmd_mutex, 1);
+ sema_init(&dev->stream_mutex, 1);
+ sema_init(&dev->pll_mutex, 1);
+ sema_init(&dev->i2c_switch_mutex, 1);
+ spin_lock_init(&dev->cmd_lock);
+ for (i = 0; i < MAX_STREAM; i++)
+ spin_lock_init(&dev->channel[i].state_lock);
+ ngwritel(1, TIMESTAMPS);
+
+ ngwritel(1, NGENE_INT_ENABLE);
+
+ stat = ngene_load_firm(dev);
+ if (stat < 0)
+ goto fail;
+
+#ifdef CONFIG_PCI_MSI
+ /* enable MSI if kernel and card support it */
+ if (pci_msi_enabled() && dev->card_info->msi_supported) {
+ unsigned long flags;
+
+ ngwritel(0, NGENE_INT_ENABLE);
+ free_irq(dev->pci_dev->irq, dev);
+ stat = pci_enable_msi(dev->pci_dev);
+ if (stat) {
+ printk(KERN_INFO DEVICE_NAME
+ ": MSI not available\n");
+ flags = IRQF_SHARED;
+ } else {
+ flags = 0;
+ dev->msi_enabled = true;
+ }
+ stat = request_irq(dev->pci_dev->irq, irq_handler,
+ flags, "nGene", dev);
+ if (stat < 0)
+ goto fail2;
+ ngwritel(1, NGENE_INT_ENABLE);
+ }
+#endif
+
+ stat = ngene_i2c_init(dev, 0);
+ if (stat < 0)
+ goto fail;
+
+ stat = ngene_i2c_init(dev, 1);
+ if (stat < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ ngwritel(0, NGENE_INT_ENABLE);
+ free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+fail2:
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
+ return stat;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void release_channel(struct ngene_channel *chan)
+{
+ struct dvb_demux *dvbdemux = &chan->demux;
+ struct ngene *dev = chan->dev;
+
+ if (chan->running)
+ set_transfer(chan, 0);
+
+ tasklet_kill(&chan->demux_tasklet);
+
+ if (chan->ci_dev) {
+ dvb_unregister_device(chan->ci_dev);
+ chan->ci_dev = NULL;
+ }
+
+ if (chan->fe2)
+ dvb_unregister_frontend(chan->fe2);
+
+ if (chan->fe) {
+ dvb_unregister_frontend(chan->fe);
+ dvb_frontend_detach(chan->fe);
+ chan->fe = NULL;
+ }
+
+ if (chan->has_demux) {
+ dvb_net_release(&chan->dvbnet);
+ dvbdemux->dmx.close(&dvbdemux->dmx);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+ &chan->hw_frontend);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+ &chan->mem_frontend);
+ dvb_dmxdev_release(&chan->dmxdev);
+ dvb_dmx_release(&chan->demux);
+ chan->has_demux = false;
+ }
+
+ if (chan->has_adapter) {
+ dvb_unregister_adapter(&dev->adapter[chan->number]);
+ chan->has_adapter = false;
+ }
+}
+
+static int init_channel(struct ngene_channel *chan)
+{
+ int ret = 0, nr = chan->number;
+ struct dvb_adapter *adapter = NULL;
+ struct dvb_demux *dvbdemux = &chan->demux;
+ struct ngene *dev = chan->dev;
+ struct ngene_info *ni = dev->card_info;
+ int io = ni->io_type[nr];
+
+ tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
+ chan->users = 0;
+ chan->type = io;
+ chan->mode = chan->type; /* for now only one mode */
+
+ if (io & NGENE_IO_TSIN) {
+ chan->fe = NULL;
+ if (ni->demod_attach[nr]) {
+ ret = ni->demod_attach[nr](chan);
+ if (ret < 0)
+ goto err;
+ }
+ if (chan->fe && ni->tuner_attach[nr]) {
+ ret = ni->tuner_attach[nr](chan);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ if (!dev->ci.en && (io & NGENE_IO_TSOUT))
+ return 0;
+
+ if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+ if (nr >= STREAM_AUDIOIN1)
+ chan->DataFormatFlags = DF_SWAP32;
+
+ if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
+ adapter = &dev->adapter[nr];
+ ret = dvb_register_adapter(adapter, "nGene",
+ THIS_MODULE,
+ &chan->dev->pci_dev->dev,
+ adapter_nr);
+ if (ret < 0)
+ goto err;
+ if (dev->first_adapter == NULL)
+ dev->first_adapter = adapter;
+ chan->has_adapter = true;
+ } else
+ adapter = dev->first_adapter;
+ }
+
+ if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
+ dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
+ set_transfer(chan, 1);
+ chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
+ set_transfer(&chan->dev->channel[2], 1);
+ dvb_register_device(adapter, &chan->ci_dev,
+ &ngene_dvbdev_ci, (void *) chan,
+ DVB_DEVICE_SEC);
+ if (!chan->ci_dev)
+ goto err;
+ }
+
+ if (chan->fe) {
+ if (dvb_register_frontend(adapter, chan->fe) < 0)
+ goto err;
+ chan->has_demux = true;
+ }
+ if (chan->fe2) {
+ if (dvb_register_frontend(adapter, chan->fe2) < 0)
+ goto err;
+ chan->fe2->tuner_priv = chan->fe->tuner_priv;
+ memcpy(&chan->fe2->ops.tuner_ops,
+ &chan->fe->ops.tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ }
+
+ if (chan->has_demux) {
+ ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+ ngene_start_feed,
+ ngene_stop_feed, chan);
+ ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
+ &chan->hw_frontend,
+ &chan->mem_frontend, adapter);
+ ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
+ }
+
+ return ret;
+
+err:
+ if (chan->fe) {
+ dvb_frontend_detach(chan->fe);
+ chan->fe = NULL;
+ }
+ release_channel(chan);
+ return 0;
+}
+
+static int init_channels(struct ngene *dev)
+{
+ int i, j;
+
+ for (i = 0; i < MAX_STREAM; i++) {
+ dev->channel[i].number = i;
+ if (init_channel(&dev->channel[i]) < 0) {
+ for (j = i - 1; j >= 0; j--)
+ release_channel(&dev->channel[j]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static struct cxd2099_cfg cxd_cfg = {
+ .bitrate = 62000,
+ .adr = 0x40,
+ .polarity = 0,
+ .clock_mode = 0,
+};
+
+static void cxd_attach(struct ngene *dev)
+{
+ struct ngene_ci *ci = &dev->ci;
+
+ ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
+ ci->dev = dev;
+ return;
+}
+
+static void cxd_detach(struct ngene *dev)
+{
+ struct ngene_ci *ci = &dev->ci;
+
+ dvb_ca_en50221_release(ci->en);
+ kfree(ci->en);
+ ci->en = 0;
+}
+
+/***********************************/
+/* workaround for shutdown failure */
+/***********************************/
+
+static void ngene_unlink(struct ngene *dev)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_MEM_WRITE;
+ com.cmd.hdr.Length = 3;
+ com.cmd.MemoryWrite.address = 0x910c;
+ com.cmd.MemoryWrite.data = 0xff;
+ com.in_len = 3;
+ com.out_len = 1;
+
+ down(&dev->cmd_mutex);
+ ngwritel(0, NGENE_INT_ENABLE);
+ ngene_command_mutex(dev, &com);
+ up(&dev->cmd_mutex);
+}
+
+void ngene_shutdown(struct pci_dev *pdev)
+{
+ struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+
+ if (!dev || !shutdown_workaround)
+ return;
+
+ printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
+ ngene_unlink(dev);
+ pci_disable_device(pdev);
+}
+
+/****************************************************************************/
+/* device probe/remove calls ************************************************/
+/****************************************************************************/
+
+void __devexit ngene_remove(struct pci_dev *pdev)
+{
+ struct ngene *dev = pci_get_drvdata(pdev);
+ int i;
+
+ tasklet_kill(&dev->event_tasklet);
+ for (i = MAX_STREAM - 1; i >= 0; i--)
+ release_channel(&dev->channel[i]);
+ if (dev->ci.en)
+ cxd_detach(dev);
+ ngene_stop(dev);
+ ngene_release_buffers(dev);
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+}
+
+int __devinit ngene_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ struct ngene *dev;
+ int stat = 0;
+
+ if (pci_enable_device(pci_dev) < 0)
+ return -ENODEV;
+
+ dev = vzalloc(sizeof(struct ngene));
+ if (dev == NULL) {
+ stat = -ENOMEM;
+ goto fail0;
+ }
+
+ dev->pci_dev = pci_dev;
+ dev->card_info = (struct ngene_info *)id->driver_data;
+ printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
+
+ pci_set_drvdata(pci_dev, dev);
+
+ /* Alloc buffers and start nGene */
+ stat = ngene_get_buffers(dev);
+ if (stat < 0)
+ goto fail1;
+ stat = ngene_start(dev);
+ if (stat < 0)
+ goto fail1;
+
+ cxd_attach(dev);
+
+ stat = ngene_buffer_config(dev);
+ if (stat < 0)
+ goto fail1;
+
+
+ dev->i2c_current_bus = -1;
+
+ /* Register DVB adapters and devices for both channels */
+ if (init_channels(dev) < 0)
+ goto fail2;
+
+ return 0;
+
+fail2:
+ ngene_stop(dev);
+fail1:
+ ngene_release_buffers(dev);
+fail0:
+ pci_disable_device(pci_dev);
+ pci_set_drvdata(pci_dev, NULL);
+ return stat;
+}
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index fcb16a615aab..fcb16a615aab 100644
--- a/drivers/media/dvb/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c
index d28554f8ce99..d28554f8ce99 100644
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ b/drivers/media/pci/ngene/ngene-i2c.c
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 5443dc0caea5..5443dc0caea5 100644
--- a/drivers/media/dvb/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/pci/pluto2/Kconfig
index 7d8e6e87bdbb..7d8e6e87bdbb 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/pci/pluto2/Kconfig
diff --git a/drivers/media/pci/pluto2/Makefile b/drivers/media/pci/pluto2/Makefile
new file mode 100644
index 000000000000..524bf841f42b
--- /dev/null
+++ b/drivers/media/pci/pluto2/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c
index f148b19a206a..f148b19a206a 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/pci/pluto2/pluto2.c
diff --git a/drivers/media/dvb/pt1/Kconfig b/drivers/media/pci/pt1/Kconfig
index 24501d5bf70d..24501d5bf70d 100644
--- a/drivers/media/dvb/pt1/Kconfig
+++ b/drivers/media/pci/pt1/Kconfig
diff --git a/drivers/media/pci/pt1/Makefile b/drivers/media/pci/pt1/Makefile
new file mode 100644
index 000000000000..98e391295afe
--- /dev/null
+++ b/drivers/media/pci/pt1/Makefile
@@ -0,0 +1,5 @@
+earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
+
+obj-$(CONFIG_DVB_PT1) += earth-pt1.o
+
+ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb-frontends
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c
index 15b35c4725f1..15b35c4725f1 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/pci/pt1/pt1.c
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c
index d980dfb21e5e..d980dfb21e5e 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.c
+++ b/drivers/media/pci/pt1/va1j5jf8007s.c
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.h b/drivers/media/pci/pt1/va1j5jf8007s.h
index b7d6f05a0e02..b7d6f05a0e02 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.h
+++ b/drivers/media/pci/pt1/va1j5jf8007s.h
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c
index 2db15159d514..2db15159d514 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.c
+++ b/drivers/media/pci/pt1/va1j5jf8007t.c
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.h b/drivers/media/pci/pt1/va1j5jf8007t.h
index 2903be519ef5..2903be519ef5 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.h
+++ b/drivers/media/pci/pt1/va1j5jf8007t.h
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
new file mode 100644
index 000000000000..15b90d6e9130
--- /dev/null
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -0,0 +1,64 @@
+config VIDEO_SAA7134
+ tristate "Philips SAA7134 support"
+ depends on VIDEO_DEV && PCI && I2C
+ select VIDEOBUF_DMA_SG
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select CRC32
+ select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for Philips SAA713x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134.
+
+config VIDEO_SAA7134_ALSA
+ tristate "Philips SAA7134 DMA audio support"
+ depends on VIDEO_SAA7134 && SND
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio in
+ Philips SAA713x based TV cards using ALSA
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-alsa.
+
+config VIDEO_SAA7134_RC
+ bool "Philips SAA7134 Remote Controller support"
+ depends on RC_CORE
+ depends on VIDEO_SAA7134
+ depends on !(RC_CORE=m && VIDEO_SAA7134=y)
+ default y
+ ---help---
+ Enables Remote Controller support on saa7134 driver.
+
+config VIDEO_SAA7134_DVB
+ tristate "DVB/ATSC Support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134 && DVB_CORE
+ select VIDEOBUF_DVB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6405 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10036 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-dvb.
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile
new file mode 100644
index 000000000000..35375480ed4d
--- /dev/null
+++ b/drivers/media/pci/saa7134/Makefile
@@ -0,0 +1,16 @@
+
+saa7134-y += saa7134-cards.o saa7134-core.o saa7134-i2c.o
+saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
+saa7134-y += saa7134-video.o
+saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
+
+obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
+
+obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
+
+obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/pci/saa7134/saa6752hs.c
index f147b05bd860..f147b05bd860 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/pci/saa7134/saa6752hs.c
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index 10460fd3ce39..10460fd3ce39 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index bc08f1dbc293..bc08f1dbc293 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 5fbb4e49495c..5fbb4e49495c 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
new file mode 100644
index 000000000000..b209de40a4f8
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -0,0 +1,1936 @@
+/*
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * Extended 3 / 2005 by Hartmut Hackmann to support various
+ * cards with the tda10046 DVB-T channel decoder
+ *
+ * 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include <media/v4l2-common.h>
+#include "dvb-pll.h"
+#include <dvb_frontend.h>
+
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+#include "nxt200x.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+#include "tda10086.h"
+#include "tda826x.h"
+#include "tda827x.h"
+#include "isl6421.h"
+#include "isl6405.h"
+#include "lnbp21.h"
+#include "tuner-simple.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "lgdt3305.h"
+#include "tda8290.h"
+#include "mb86a20s.h"
+#include "lgs8gxx.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+#include "zl10036.h"
+#include "zl10039.h"
+#include "mt312.h"
+#include "s5h1411.h"
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int antenna_pwr;
+
+module_param(antenna_pwr, int, 0444);
+MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
+static int use_frontend;
+module_param(use_frontend, int, 0644);
+MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(fmt, arg...) do { if (debug) \
+ printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
+
+/* Print a warning */
+#define wprintk(fmt, arg...) \
+ printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
+static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
+{
+ u32 ok;
+
+ if (!on) {
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ return 0;
+ }
+
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
+ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ udelay(10);
+
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28));
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+ udelay(10);
+ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+ udelay(10);
+ ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
+ dprintk("%s %s\n", __func__, ok ? "on" : "off");
+
+ if (!ok)
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ return ok;
+}
+
+static int mt352_pinnacle_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
+ static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 };
+ static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f };
+ static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d };
+ static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
+ struct saa7134_dev *dev= fe->dvb->priv;
+
+ dprintk("%s called\n", __func__);
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+
+ mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg));
+ mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg));
+ mt352_write(fe, irq_cfg, sizeof(irq_cfg));
+
+ return 0;
+}
+
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0xe };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ return 0;
+}
+
+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)};
+
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct v4l2_frequency f;
+
+ /* set frequency (mt2050) */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_DIGITAL_TV;
+ 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);
+ saa_call_all(dev, tuner, s_frequency, &f);
+ msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ pinnacle_antenna_pwr(dev, antenna_pwr);
+
+ /* mt352 setup */
+ return mt352_pinnacle_init(fe);
+}
+
+static struct mt352_config pinnacle_300i = {
+ .demod_address = 0x3c >> 1,
+ .adc_clock = 20333,
+ .if2 = 36150,
+ .no_tuner = 1,
+ .demod_init = mt352_pinnacle_init,
+};
+
+static struct mt352_config avermedia_777 = {
+ .demod_address = 0xf,
+ .demod_init = mt352_aver777_init,
+};
+
+static struct mt352_config avermedia_xc3028_mt352_dev = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .demod_init = mt352_avermedia_xc3028_init,
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .config = 3, /* Use tuner callback for AGC */
+
+};
+
+static const struct mb86a20s_config kworld_mb86a20s_config = {
+ .demod_address = 0x10,
+};
+
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ unsigned char initmsg[] = {0x45, 0x97};
+ unsigned char msg_enable[] = {0x45, 0xc1};
+ unsigned char msg_disable[] = {0x45, 0x81};
+ struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ if (enable)
+ msg.buf = msg_enable;
+ else
+ msg.buf = msg_disable;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
+/* ==================================================================
+ * tda1004x based DVB-T cards, helper functions
+ */
+
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char *name)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ return request_firmware(fw, name, &dev->pci->dev);
+}
+
+/* ------------------------------------------------------------------
+ * these tuners are tu1216, td1316(a)
+ */
+
+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;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
+ sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ /* determine charge pump */
+ tuner_frequency = c->frequency + 36166000;
+ if (tuner_frequency < 87000000)
+ return -EINVAL;
+ else if (tuner_frequency < 130000000)
+ cp = 3;
+ else if (tuner_frequency < 160000000)
+ cp = 5;
+ else if (tuner_frequency < 200000000)
+ cp = 6;
+ else if (tuner_frequency < 290000000)
+ cp = 3;
+ else if (tuner_frequency < 420000000)
+ cp = 5;
+ else if (tuner_frequency < 480000000)
+ cp = 6;
+ else if (tuner_frequency < 620000000)
+ cp = 3;
+ else if (tuner_frequency < 830000000)
+ cp = 5;
+ else if (tuner_frequency < 895000000)
+ cp = 7;
+ else
+ return -EINVAL;
+
+ /* determine band */
+ if (c->frequency < 49000000)
+ return -EINVAL;
+ else if (c->frequency < 161000000)
+ band = 1;
+ else if (c->frequency < 444000000)
+ band = 2;
+ else if (c->frequency < 861000000)
+ band = 4;
+ else
+ return -EINVAL;
+
+ /* setup PLL filter */
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ filter = 0;
+ break;
+
+ case 7000000:
+ filter = 0;
+ break;
+
+ case 8000000:
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* calculate divisor
+ * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+ */
+ tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
+
+ /* setup tuner buffer */
+ tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+ wprintk("could not write to tuner at addr: 0x%02x\n",
+ addr << 1);
+ return -EIO;
+ }
+ msleep(1);
+ return 0;
+}
+
+static int philips_tu1216_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+ /* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config philips_tu1216_60_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tu1216_61_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_td1316_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+ struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_set(fe);
+}
+
+static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+ struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* switch the tuner to analog mode */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 msg[] = { 0x00, 0x40};
+ struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+ if (philips_td1316_tuner_init(fe))
+ return -EIO;
+ msleep(1);
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ static u8 msg[] = { 0x00, 0x14 };
+ struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ if (philips_td1316_tuner_sleep(fe))
+ return -EIO;
+
+ /* switch the board to analog mode */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ if (dev->original_demod_sleep)
+ dev->original_demod_sleep(fe);
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ return 0;
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_POS,
+ .if_freq = TDA10046_FREQ_052,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config medion_cardbus = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_NEG,
+ .if_freq = TDA10046_FREQ_3613,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config technotrend_budget_t3000_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x63,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
+
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ u8 addr = state->config->i2c_gate;
+ static u8 tda8290_close[] = { 0x21, 0xc0};
+ static u8 tda8290_open[] = { 0x21, 0x80};
+ struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
+ if (enable) {
+ tda8290_msg.buf = tda8290_close;
+ } else {
+ tda8290_msg.buf = tda8290_open;
+ }
+ if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) {
+ struct saa7134_dev *dev = fe->dvb->priv;
+ wprintk("could not access tda8290 I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ switch (state->config->antenna_switch) {
+ case 0: break;
+ case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+ saa7134_set_gpio(dev, 21, 0);
+ break;
+ case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ }
+ return 0;
+}
+
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ switch (state->config->antenna_switch) {
+ case 0: break;
+ case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+ saa7134_set_gpio(dev, 21, 0);
+ break;
+ }
+ return 0;
+}
+
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+ struct tda1004x_config *cdec_conf,
+ struct tda827x_config *tuner_conf)
+{
+ struct videobuf_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+
+ fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (cdec_conf->i2c_gate)
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
+ cdec_conf->tuner_address,
+ &dev->i2c_adap, tuner_conf))
+ return 0;
+
+ wprintk("no tda827x tuner found at addr: %02x\n",
+ cdec_conf->tuner_address);
+ }
+ return -EINVAL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda827x_config tda827x_cfg_0 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 0,
+ .switch_addr = 0
+};
+
+static struct tda827x_config tda827x_cfg_1 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 1,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2_sw42 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x42
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config tda827x_lifeview_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_pci_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_s_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config hauppauge_hvr_1110_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_dual_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config lifeview_trio_config = {
+ .demod_address = 0x09,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP00_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config md8800_dvbt_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_4871_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_hybrid_lna_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config kworld_dvb_t_210_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config avermedia_super_007_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x42,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_tiger_3in1_config = {
+ .demod_address = 0x0b,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_ps3_100_config = {
+ .demod_address = 0x0b,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
+
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ philips_tda827x_tuner_init(fe);
+ /* route TDA8275a AGC input to the channel decoder */
+ saa7134_set_gpio(dev, 22, 1);
+ return 0;
+}
+
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* route TDA8275a AGC input to the analog IF chip*/
+ saa7134_set_gpio(dev, 22, 0);
+ philips_tda827x_tuner_sleep(fe);
+ return 0;
+}
+
+static struct tda827x_config ads_duo_cfg = {
+ .init = ads_duo_tuner_init,
+ .sleep = ads_duo_tuner_sleep,
+ .config = 0
+};
+
+static struct tda1004x_config ads_tech_duo_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP00_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct zl10353_config behold_h6_config = {
+ .demod_address = 0x1e>>1,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct xc5000_config behold_x7_tunerconfig = {
+ .i2c_address = 0xc2>>1,
+ .if_khz = 4560,
+ .radio_input = XC5000_RADIO_FM1,
+};
+
+static struct zl10353_config behold_x7_config = {
+ .demod_address = 0x1e>>1,
+ .if2 = 45600,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct zl10353_config videomate_t750_zl10353_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct qt1010_config videomate_t750_qt1010_config = {
+ .i2c_address = 0x62
+};
+
+
+/* ==================================================================
+ * tda10086 based DVB-S cards, helper functions
+ */
+
+static struct tda10086_config flydvbs = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct tda10086_config sd1878_4m = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_4M,
+};
+
+/* ------------------------------------------------------------------
+ * special case: lnb supply is connected to the gated i2c
+ */
+
+static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_voltage)
+ res = dev->original_set_voltage(fe, voltage);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_high_voltage)
+ res = dev->original_set_high_voltage(fe, arg);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 wbuf[2] = { 0x1f, 00 };
+ u8 rbuf;
+ struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
+ { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
+
+ if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
+ return -EIO;
+ /* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
+ if (voltage == SEC_VOLTAGE_18)
+ wbuf[1] = rbuf | 0x10;
+ else
+ wbuf[1] = rbuf & 0xef;
+ msg[0].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 1);
+ return 0;
+}
+
+static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__);
+ return -EIO;
+}
+
+/* ==================================================================
+ * nxt200x based ATSC cards, helper functions
+ */
+
+static struct nxt200x_config avertvhda180 = {
+ .demod_address = 0x0a,
+};
+
+static struct nxt200x_config kworldatsc110 = {
+ .demod_address = 0x0a,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+ .demod_address = 0x0e,
+ .voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+ .tuner_address = 0x60,
+};
+
+static struct mt312_config zl10313_compro_s350_config = {
+ .demod_address = 0x0e,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+ .i2c_addr = 0x0e,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+};
+
+static struct tda10048_config hcw_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .config = 3,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda10048_config zolid_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_config zolid_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct tda10048_config dtv1000s_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3800,
+ .dtv8_if_freq_khz = TDA10048_IF_4300,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_std_map dtv1000s_tda18271_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 dtv1000s_tda18271_config = {
+ .std_map = &dtv1000s_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x1d,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 0,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 4000, /* 4.00 MHz */
+ .if_neg_center = 0,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 3, /* 2.0 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+ .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
+ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
+ int ret;
+ int attach_xc3028 = 0;
+ struct videobuf_dvb_frontend *fe0;
+
+ /* FIXME: add support for multi-frontend */
+ mutex_init(&dev->frontends.lock);
+ INIT_LIST_HEAD(&dev->frontends.felist);
+
+ printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
+ fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
+ if (!fe0) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* init struct videobuf_dvb */
+ dev->ts.nr_bufs = 32;
+ dev->ts.nr_packets = 32*4;
+ fe0->dvb.name = dev->name;
+ videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
+ &dev->pci->dev, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_ALTERNATE,
+ sizeof(struct saa7134_buf),
+ dev, NULL);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+ dprintk("pinnacle 300i dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ dprintk("avertv 777 dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_TD1316);
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ dprintk("AverMedia A16D dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_MD7134:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TOUGH:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_60_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBTDUO:
+ case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &technotrend_budget_t3000_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_61_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_DVBT_210:
+ if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &hcw_tda10048_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,
+ &hcw_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+ &tda827x_cfg_1) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+ &tda827x_cfg_1) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+ &hcw_lgdt3305_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ 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,
+ &hcw_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &lifeview_trio_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
+ 0x08, 0, 0) == NULL) {
+ wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &ads_tech_duo_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
+ ads_tech_duo_config.tuner_address, &dev->i2c_adap,
+ &ads_duo_cfg) == NULL) {
+ wprintk("no tda827x tuner found at addr: %02x\n",
+ ads_tech_duo_config.tuner_address);
+ goto detach_frontend;
+ }
+ } else
+ wprintk("failed to attach tda10046\n");
+ break;
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+ if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ struct dvb_frontend *fe = fe0->dvb.frontend;
+ u8 dev_id = dev->eedata[2];
+ u8 data = 0xc4;
+ struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
+
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: Medion Quadro, no tda826x "
+ "found !\n", __func__);
+ goto detach_frontend;
+ }
+ if (dev_id != 0x08) {
+ /* we need to open the i2c gate (we know it exists) */
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ wprintk("%s: Medion Quadro, no ISL6405 "
+ "found !\n", __func__);
+ goto detach_frontend;
+ }
+ if (dev_id == 0x07) {
+ /* fire up the 2nd section of the LNB supply since
+ we can't do this from the other section */
+ msg.buf = &data;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ } else {
+ fe->ops.set_voltage = md8800_set_voltage2;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
+ NULL, DVB_PLL_TDHU2);
+ break;
+ case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+ case SAA7134_BOARD_KWORLD_ATSC110:
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &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);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: No tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ wprintk("%s: No ISL6421 found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ if (configure_tda827x_fe(dev, &cinergy_ht_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_CINERGY_HT_PCI:
+ if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER_S:
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_ASUS_P7131_4871:
+ if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+ if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+ &tda827x_cfg_2_sw42) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_SNAKE:
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: No tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ wprintk("%s: No lnbp21 found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ break;
+ case SAA7134_BOARD_CREATIX_CTX953:
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ dprintk("AverMedia E506R dvb setup\n");
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_MD7134_BRIDGE_2:
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &sd1878_4m, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ struct dvb_frontend *fe;
+ if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
+ wprintk("%s: MD7134 DVB-S, no SD1878 "
+ "found !\n", __func__);
+ goto detach_frontend;
+ }
+ /* we need to open the i2c gate (we know it exists) */
+ fe = fe0->dvb.frontend;
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ wprintk("%s: MD7134 DVB-S, no ISL6405 "
+ "found !\n", __func__);
+ goto detach_frontend;
+ }
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach,
+ fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: Asus Tiger 3in1, no "
+ "tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ wprintk("%s: Asus Tiger 3in1, no lnbp21"
+ " found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &asus_ps3_100_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach,
+ fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: Asus My Cinema PS3-100, no "
+ "tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
+ " found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_TIGER:
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_BEHOLD_H6:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_h6_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216MEX_MK3);
+ }
+ break;
+ case SAA7134_BOARD_BEHOLD_X7:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_x7_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, &behold_x7_tunerconfig);
+ }
+ break;
+ case SAA7134_BOARD_BEHOLD_H7:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_x7_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, &behold_x7_tunerconfig);
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ /* Zarlink ZL10313 */
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &avertv_a700_mt312, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+ &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+ wprintk("%s: No zl10036 found!\n",
+ __func__);
+ }
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_compro_s350_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ wprintk("%s: No zl10039 found!\n",
+ __func__);
+
+ break;
+ case SAA7134_BOARD_VIDEOMATE_T750:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &videomate_t750_zl10353_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(qt1010_attach,
+ fe0->dvb.frontend,
+ &dev->i2c_adap,
+ &videomate_t750_qt1010_config) == NULL)
+ wprintk("error attaching QT1010\n");
+ }
+ break;
+ case SAA7134_BOARD_ZOLID_HYBRID_PCI:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &zolid_tda10048_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,
+ &zolid_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &dtv1000s_tda10048_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,
+ &dtv1000s_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+ fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
+ &kworld_mb86a20s_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_tda18271_config);
+ }
+
+ /* mb86a20s need to use the I2C gateway */
+ break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &prohdtv_pro2_lgs8g75_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,
+ &prohdtv_pro2_tda18271_config);
+ }
+ break;
+ default:
+ wprintk("Huh? unknown DVB card?\n");
+ break;
+ }
+
+ if (attach_xc3028) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+
+ if (!fe0->dvb.frontend)
+ goto detach_frontend;
+
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->name);
+ goto detach_frontend;
+ }
+ }
+
+ if (NULL == fe0->dvb.frontend) {
+ printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
+ goto detach_frontend;
+ }
+ /* define general-purpose callback pointer */
+ fe0->dvb.frontend->callback = saa7134_tuner_callback;
+
+ /* register everything else */
+ ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr, 0);
+
+ /* this sequence is necessary to make the tda1004x load its firmware
+ * and to enter analog mode of hybrid boards
+ */
+ if (!ret) {
+ if (fe0->dvb.frontend->ops.init)
+ fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.sleep)
+ fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.tuner_ops.sleep)
+ fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
+ }
+ return ret;
+
+detach_frontend:
+ videobuf_dvb_dealloc_frontends(&dev->frontends);
+ return -EINVAL;
+}
+
+static int dvb_fini(struct saa7134_dev *dev)
+{
+ struct videobuf_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ /* FIXME: I suspect that this code is bogus, since the entry for
+ Pinnacle 300I DVB-T PAL already defines the proper init to allow
+ the detection of mt2032 (TDA9887_PORT2_INACTIVE)
+ */
+ if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+ static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &on;
+
+ /* otherwise we don't detect the tuner on next insmod */
+ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+ if ((dev->eedata[2] == 0x07) && use_frontend) {
+ /* turn off the 2nd lnb supply */
+ u8 data = 0x80;
+ struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
+ struct dvb_frontend *fe;
+ fe = fe0->dvb.frontend;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
+ }
+ videobuf_dvb_unregister_bus(&dev->frontends);
+ return 0;
+}
+
+static struct saa7134_mpeg_ops dvb_ops = {
+ .type = SAA7134_MPEG_DVB,
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init dvb_register(void)
+{
+ return saa7134_ts_register(&dvb_ops);
+}
+
+static void __exit dvb_unregister(void)
+{
+ saa7134_ts_unregister(&dvb_ops);
+}
+
+module_init(dvb_register);
+module_exit(dvb_unregister);
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index dde361a9194e..dde361a9194e 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index a176ec3285e0..a176ec3285e0 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
new file mode 100644
index 000000000000..0f78f5e537e2
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -0,0 +1,1041 @@
+/*
+ *
+ * handle saa7134 IR remotes via linux kernel input layer.
+ *
+ * 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
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#define MODULE_NAME "saa7134"
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+static int pinnacle_remote;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
+#define dprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#define i2cdprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
+
+/* Helper function for raw decoding at GPIO16 or GPIO18 */
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
+
+/* -------------------- GPIO generic keycode builder -------------------- */
+
+static int build_key(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir = dev->remote;
+ u32 gpio, data;
+
+ /* here comes the additional handshake steps for some cards */
+ switch (dev->board) {
+ case SAA7134_BOARD_GOTVIEW_7135:
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ break;
+ }
+ /* 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);
+ if (ir->polling) {
+ if (ir->last_gpio == gpio)
+ return 0;
+ ir->last_gpio = gpio;
+ }
+
+ data = ir_extract_bits(gpio, ir->mask_keycode);
+ dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
+ gpio, ir->mask_keycode, data);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ if (data == ir->mask_keycode)
+ rc_keyup(ir->dev);
+ else
+ rc_keydown_notimeout(ir->dev, data, 0);
+ return 0;
+ }
+
+ if (ir->polling) {
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ rc_keydown_notimeout(ir->dev, data, 0);
+ } else {
+ rc_keyup(ir->dev);
+ }
+ }
+ else { /* IRQ driven mode - handle key press and release in one go */
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keyup(ir->dev);
+ }
+ }
+
+ return 0;
+}
+
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ int gpio;
+ int attempt = 0;
+ unsigned char b;
+
+ /* We need this to access GPI Used by the saa_readl macro. */
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+ if (dev == NULL) {
+ i2cdprintk("get_key_flydvb_trio: "
+ "ir->c->adapter->algo_data is NULL!\n");
+ return -EIO;
+ }
+
+ /* rising SAA7134_GPIGPRESCAN 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);
+
+ if (0x40000 & ~gpio)
+ return 0; /* No button press */
+
+ /* No button press - only before first key pressed */
+ if (b == 0xFF)
+ return 0;
+
+ /* poll IR chip */
+ /* weak up the IR chip */
+ b = 0;
+
+ while (1 != i2c_master_send(ir->c, &b, 1)) {
+ if ((attempt++) < 10) {
+ /*
+ * wait a bit for next attempt -
+ * I don't know how make it better
+ */
+ msleep(10);
+ continue;
+ }
+ i2cdprintk("send wake up byte to pic16C505 (IR chip)"
+ "failed %dx\n", attempt);
+ return -EIO;
+ }
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw)
+{
+ unsigned char b;
+ 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_msi_tvanywhere_plus: "
+ "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&0x40 is pulsed low when a button is pressed. Don't do
+ I2C receive if gpio&0x40 is not low. */
+
+ if (gpio & 0x40)
+ 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_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+ *ir_key = b;
+ *ir_raw = b;
+ 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;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ /* no button press */
+ if (b==0)
+ return 0;
+
+ /* repeating */
+ if (b & 0x80)
+ return 1;
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[5];
+
+ /* poll IR chip */
+ if (5 != i2c_master_recv(ir->c, buf, 5))
+ return -EIO;
+
+ /* Check if some key were pressed */
+ if (!(buf[0] & 0x80))
+ return 0;
+
+ /*
+ * 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;
+}
+
+
+static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char data[12];
+ u32 gpio;
+
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+ /* 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);
+
+ if (0x400000 & ~gpio)
+ return 0; /* No button press */
+
+ ir->c->addr = 0x5a >> 1;
+
+ if (12 != i2c_master_recv(ir->c, data, 12)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ if (data[9] != (unsigned char)(~data[8]))
+ return 0;
+
+ *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
+ *ir_key = *ir_raw;
+
+ return 1;
+}
+
+/* Common (grey or coloured) pinnacle PCTV remote handling
+ *
+ */
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int parity_offset, int marker, int code_modulo)
+{
+ unsigned char b[4];
+ unsigned int start = 0,parity = 0,code = 0;
+
+ /* poll IR chip */
+ if (4 != i2c_master_recv(ir->c, b, 4)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ for (start = 0; start < ARRAY_SIZE(b); start++) {
+ if (b[start] == marker) {
+ code=b[(start+parity_offset + 1) % 4];
+ parity=b[(start+parity_offset) % 4];
+ }
+ }
+
+ /* Empty Request */
+ if (parity == 0)
+ return 0;
+
+ /* Repeating... */
+ if (ir->old == parity)
+ return 0;
+
+ ir->old = parity;
+
+ /* drop special codes when a key is held down a long time for the grey controller
+ In this case, the second bit of the code is asserted */
+ if (marker == 0xfe && (code & 0x40))
+ return 0;
+
+ code %= code_modulo;
+
+ *ir_raw = code;
+ *ir_key = code;
+
+ i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+ return 1;
+}
+
+/* The grey pinnacle PCTV remote
+ *
+ * There are one issue with this remote:
+ * - I2c packet does not change when the same key is pressed quickly. The workaround
+ * is to hold down each key for about half a second, so that another code is generated
+ * in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+void saa7134_input_irq(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir;
+
+ if (!dev || !dev->remote)
+ return;
+
+ ir = dev->remote;
+ if (!ir->running)
+ return;
+
+ if (!ir->polling && !ir->raw_decode) {
+ build_key(dev);
+ } else if (ir->raw_decode) {
+ saa7134_raw_decode_irq(dev);
+ }
+}
+
+static void saa7134_input_timer(unsigned long data)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev *)data;
+ struct saa7134_card_ir *ir = dev->remote;
+
+ build_key(dev);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+static void ir_raw_decode_timer_end(unsigned long data)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev *)data;
+
+ ir_raw_event_handle(dev->remote->dev);
+}
+
+static int __saa7134_ir_start(void *priv)
+{
+ struct saa7134_dev *dev = priv;
+ struct saa7134_card_ir *ir;
+
+ if (!dev || !dev->remote)
+ return -EINVAL;
+
+ ir = dev->remote;
+ if (ir->running)
+ return 0;
+
+ /* Moved here from saa7134_input_init1() because the latter
+ * is not called on device resume */
+ switch (dev->board) {
+ case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_M102:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
+ saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
+ break;
+ }
+
+ ir->running = true;
+
+ if (ir->polling) {
+ setup_timer(&ir->timer, saa7134_input_timer,
+ (unsigned long)dev);
+ ir->timer.expires = jiffies + HZ;
+ add_timer(&ir->timer);
+ } else if (ir->raw_decode) {
+ /* set timer_end for code completion */
+ setup_timer(&ir->timer, ir_raw_decode_timer_end,
+ (unsigned long)dev);
+ }
+
+ return 0;
+}
+
+static void __saa7134_ir_stop(void *priv)
+{
+ struct saa7134_dev *dev = priv;
+ struct saa7134_card_ir *ir;
+
+ if (!dev || !dev->remote)
+ return;
+
+ ir = dev->remote;
+ if (!ir->running)
+ return;
+
+ if (ir->polling || ir->raw_decode)
+ del_timer_sync(&ir->timer);
+
+ ir->running = false;
+
+ return;
+}
+
+int saa7134_ir_start(struct saa7134_dev *dev)
+{
+ if (dev->remote->users)
+ return __saa7134_ir_start(dev);
+
+ return 0;
+}
+
+void saa7134_ir_stop(struct saa7134_dev *dev)
+{
+ if (dev->remote->users)
+ __saa7134_ir_stop(dev);
+}
+
+static int saa7134_ir_open(struct rc_dev *rc)
+{
+ struct saa7134_dev *dev = rc->priv;
+
+ dev->remote->users++;
+ return __saa7134_ir_start(dev);
+}
+
+static void saa7134_ir_close(struct rc_dev *rc)
+{
+ struct saa7134_dev *dev = rc->priv;
+
+ dev->remote->users--;
+ if (!dev->remote->users)
+ __saa7134_ir_stop(dev);
+}
+
+int saa7134_input_init1(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir;
+ struct rc_dev *rc;
+ char *ir_codes = NULL;
+ u32 mask_keycode = 0;
+ u32 mask_keydown = 0;
+ u32 mask_keyup = 0;
+ unsigned polling = 0;
+ bool raw_decode = false;
+ int err;
+
+ if (dev->has_remote != SAA7134_REMOTE_GPIO)
+ return -ENODEV;
+ if (disable_ir)
+ return -ENODEV;
+
+ /* detect & configure */
+ switch (dev->board) {
+ case SAA7134_BOARD_FLYVIDEO2000:
+ case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+ ir_codes = RC_MAP_FLYVIDEO;
+ mask_keycode = 0xEC00000;
+ mask_keydown = 0x0040000;
+ break;
+ case SAA7134_BOARD_CINERGY400:
+ case SAA7134_BOARD_CINERGY600:
+ case SAA7134_BOARD_CINERGY600_MK3:
+ ir_codes = RC_MAP_CINERGY;
+ mask_keycode = 0x00003f;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_ECS_TVP3XP:
+ case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+ ir_codes = RC_MAP_EZTV;
+ mask_keycode = 0x00017c;
+ mask_keyup = 0x000002;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_KWORLD_XPERT:
+ case SAA7134_BOARD_AVACSSMARTTV:
+ ir_codes = RC_MAP_PIXELVIEW;
+ mask_keycode = 0x00001F;
+ mask_keyup = 0x000020;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_M102:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ ir_codes = RC_MAP_AVERMEDIA;
+ mask_keycode = 0x0007C8;
+ mask_keydown = 0x000010;
+ polling = 50; // ms
+ /* GPIO stuff moved to __saa7134_ir_start() */
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M135A:
+ ir_codes = RC_MAP_AVERMEDIA_M135A;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ ir_codes = RC_MAP_AVERMEDIA;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; // ms
+ /* GPIO stuff moved to __saa7134_ir_start() */
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ir_codes = RC_MAP_AVERMEDIA_A16D;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; /* ms */
+ /* GPIO stuff moved to __saa7134_ir_start() */
+ break;
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ ir_codes = RC_MAP_PIXELVIEW;
+ mask_keycode = 0x00001f;
+ mask_keyup = 0x000060;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_MANLI_MTV001:
+ case SAA7134_BOARD_MANLI_MTV002:
+ ir_codes = RC_MAP_MANLI;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_409FM:
+ case SAA7134_BOARD_BEHOLD_401:
+ case SAA7134_BOARD_BEHOLD_403:
+ case SAA7134_BOARD_BEHOLD_403FM:
+ case SAA7134_BOARD_BEHOLD_405:
+ case SAA7134_BOARD_BEHOLD_405FM:
+ case SAA7134_BOARD_BEHOLD_407:
+ case SAA7134_BOARD_BEHOLD_407FM:
+ case SAA7134_BOARD_BEHOLD_409:
+ case SAA7134_BOARD_BEHOLD_505FM:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507_9FM:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK5:
+ ir_codes = RC_MAP_MANLI;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ ir_codes = RC_MAP_BEHOLD_COLUMBUS;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ ir_codes = RC_MAP_PCTV_SEDNA;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ ir_codes = RC_MAP_GOTVIEW7135;
+ mask_keycode = 0x0003CC;
+ mask_keydown = 0x000010;
+ polling = 5; /* ms */
+ /* GPIO stuff moved to __saa7134_ir_start() */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
+ case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
+ mask_keycode = 0x00003F;
+ mask_keyup = 0x400000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_PROTEUS_2309:
+ ir_codes = RC_MAP_PROTEUS_2309;
+ mask_keycode = 0x00007F;
+ mask_keyup = 0x000080;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
+ mask_keycode = 0x003F00;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_FLYDVBTDUO:
+ ir_codes = RC_MAP_FLYDVB;
+ mask_keycode = 0x0001F00;
+ mask_keydown = 0x0040000;
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ ir_codes = RC_MAP_ASUS_PC39;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ ir_codes = RC_MAP_ASUS_PS3_100;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ ir_codes = RC_MAP_ENCORE_ENLTV;
+ mask_keycode = 0x00007f;
+ mask_keyup = 0x040000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM3:
+ ir_codes = RC_MAP_ENCORE_ENLTV_FM53;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ ir_codes = RC_MAP_ENCORE_ENLTV;
+ mask_keycode = 0x5f80000;
+ mask_keyup = 0x8000000;
+ polling = 50; //ms
+ break;
+ case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+ ir_codes = RC_MAP_GENIUS_TVGO_A11MCE;
+ mask_keycode = 0xff;
+ mask_keydown = 0xf00000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_REAL_ANGEL_220:
+ ir_codes = RC_MAP_REAL_AUDIO_220_32_KEYS;
+ mask_keycode = 0x3f00;
+ mask_keyup = 0x4000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ ir_codes = RC_MAP_KWORLD_PLUS_TV_ANALOG;
+ mask_keycode = 0x7f;
+ polling = 40; /* ms */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ ir_codes = RC_MAP_VIDEOMATE_S350;
+ mask_keycode = 0x003f00;
+ mask_keydown = 0x040000;
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+ ir_codes = RC_MAP_WINFAST;
+ mask_keycode = 0x5f00;
+ mask_keyup = 0x020000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_M1F:
+ ir_codes = RC_MAP_VIDEOMATE_K100;
+ mask_keycode = 0x0ff00;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ ir_codes = RC_MAP_HAUPPAUGE;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ }
+ if (NULL == ir_codes) {
+ printk("%s: Oops: IR config error [card=%d]\n",
+ dev->name, dev->board);
+ return -ENODEV;
+ }
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ rc = rc_allocate_device();
+ if (!ir || !rc) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+
+ ir->dev = rc;
+ dev->remote = ir;
+
+ /* init hardware-specific stuff */
+ ir->mask_keycode = mask_keycode;
+ ir->mask_keydown = mask_keydown;
+ ir->mask_keyup = mask_keyup;
+ ir->polling = polling;
+ ir->raw_decode = raw_decode;
+
+ /* init input device */
+ snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
+ saa7134_boards[dev->board].name);
+ snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+ pci_name(dev->pci));
+
+ rc->priv = dev;
+ rc->open = saa7134_ir_open;
+ rc->close = saa7134_ir_close;
+ if (raw_decode)
+ rc->driver_type = RC_DRIVER_IR_RAW;
+
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
+ if (dev->pci->subsystem_vendor) {
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
+ } else {
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
+ }
+ rc->dev.parent = &dev->pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
+
+ err = rc_register_device(rc);
+ if (err)
+ goto err_out_free;
+
+ return 0;
+
+err_out_free:
+ rc_free_device(rc);
+ dev->remote = NULL;
+ kfree(ir);
+ return err;
+}
+
+void saa7134_input_fini(struct saa7134_dev *dev)
+{
+ if (NULL == dev->remote)
+ return;
+
+ saa7134_ir_stop(dev);
+ rc_unregister_device(dev->remote->dev);
+ kfree(dev->remote);
+ dev->remote = NULL;
+}
+
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
+{
+ struct i2c_board_info info;
+ struct i2c_msg msg_msi = {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
+ int rc;
+
+ if (disable_ir) {
+ dprintk("IR has been disabled, not probing for i2c remote\n");
+ return;
+ }
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ dev->init_data.name = "Pinnacle PCTV";
+ if (pinnacle_remote == 0) {
+ dev->init_data.get_key = get_key_pinnacle_color;
+ dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR;
+ info.addr = 0x47;
+ } else {
+ dev->init_data.get_key = get_key_pinnacle_grey;
+ dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+ info.addr = 0x47;
+ }
+ break;
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ dev->init_data.name = "Purple TV";
+ dev->init_data.get_key = get_key_purpletv;
+ dev->init_data.ir_codes = RC_MAP_PURPLETV;
+ info.addr = 0x7a;
+ break;
+ case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+ dev->init_data.name = "MSI TV@nywhere Plus";
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+ dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+ /*
+ * MSI TV@nyware Plus requires more frequent polling
+ * otherwise it will miss some keypresses
+ */
+ dev->init_data.polling_interval = 50;
+ 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_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;
+ dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+ info.addr = 0x71;
+ break;
+ case SAA7134_BOARD_BEHOLD_607FM_MK3:
+ case SAA7134_BOARD_BEHOLD_607FM_MK5:
+ case SAA7134_BOARD_BEHOLD_609FM_MK3:
+ case SAA7134_BOARD_BEHOLD_609FM_MK5:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+ case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
+ case SAA7134_BOARD_BEHOLD_H7:
+ case SAA7134_BOARD_BEHOLD_A7:
+ dev->init_data.name = "BeholdTV";
+ dev->init_data.get_key = get_key_beholdm6xx;
+ dev->init_data.ir_codes = RC_MAP_BEHOLD;
+ dev->init_data.type = RC_TYPE_NEC;
+ info.addr = 0x2d;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ info.addr = 0x40;
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ dev->init_data.name = "FlyDVB Trio";
+ dev->init_data.get_key = get_key_flydvb_trio;
+ dev->init_data.ir_codes = RC_MAP_FLYDVB;
+ info.addr = 0x0b;
+ break;
+ default:
+ dprintk("No I2C IR support for board %x\n", dev->board);
+ return;
+ }
+
+ if (dev->init_data.name)
+ info.platform_data = &dev->init_data;
+ i2c_new_device(&dev->i2c_adap, &info);
+}
+
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir = dev->remote;
+ unsigned long timeout;
+ int space;
+
+ /* Generate initial event */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+ ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
+
+ /*
+ * Wait 15 ms from the start of the first IR event before processing
+ * the event. This time is enough for NEC protocol. May need adjustments
+ * to work with other protocols.
+ */
+ smp_mb();
+
+ if (!timer_pending(&ir->timer)) {
+ timeout = jiffies + msecs_to_jiffies(15);
+ mod_timer(&ir->timer, timeout);
+ }
+
+ return 1;
+}
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/pci/saa7134/saa7134-reg.h
index e7e0af101fa7..e7e0af101fa7 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/pci/saa7134/saa7134-reg.h
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 2e3f4b412d8c..2e3f4b412d8c 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index b7a99bee2f98..b7a99bee2f98 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index e9aa94b807f1..e9aa94b807f1 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 6de10b1e7251..6de10b1e7251 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
new file mode 100644
index 000000000000..c24b6512bd8f
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -0,0 +1,855 @@
+/*
+ *
+ * v4l2 device driver for philips saa7134 based TV cards
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * 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.
+ */
+
+#define SAA7134_VERSION "0, 2, 17"
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/kdev_t.h>
+#include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/tuner.h>
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/videobuf-dma-sg.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+
+#define UNSET (-1U)
+
+/* ----------------------------------------------------------- */
+/* enums */
+
+enum saa7134_tvaudio_mode {
+ TVAUDIO_FM_MONO = 1,
+ TVAUDIO_FM_BG_STEREO = 2,
+ TVAUDIO_FM_SAT_STEREO = 3,
+ TVAUDIO_FM_K_STEREO = 4,
+ TVAUDIO_NICAM_AM = 5,
+ TVAUDIO_NICAM_FM = 6,
+};
+
+enum saa7134_audio_in {
+ TV = 1,
+ LINE1 = 2,
+ LINE2 = 3,
+ LINE2_LEFT,
+};
+
+enum saa7134_video_out {
+ CCIR656 = 1,
+};
+
+/* ----------------------------------------------------------- */
+/* static data */
+
+struct saa7134_tvnorm {
+ char *name;
+ v4l2_std_id id;
+
+ /* video decoder */
+ unsigned int sync_control;
+ unsigned int luma_control;
+ unsigned int chroma_ctrl1;
+ unsigned int chroma_gain;
+ unsigned int chroma_ctrl2;
+ unsigned int vgate_misc;
+
+ /* video scaler */
+ unsigned int h_start;
+ unsigned int h_stop;
+ unsigned int video_v_start;
+ unsigned int video_v_stop;
+ unsigned int vbi_v_start_0;
+ unsigned int vbi_v_stop_0;
+ unsigned int src_timing;
+ unsigned int vbi_v_start_1;
+};
+
+struct saa7134_tvaudio {
+ char *name;
+ v4l2_std_id std;
+ enum saa7134_tvaudio_mode mode;
+ int carr1;
+ int carr2;
+};
+
+struct saa7134_format {
+ char *name;
+ unsigned int fourcc;
+ unsigned int depth;
+ unsigned int pm;
+ unsigned int vshift; /* vertical downsampling (for planar yuv) */
+ unsigned int hshift; /* horizontal downsampling (for planar yuv) */
+ unsigned int bswap:1;
+ unsigned int wswap:1;
+ unsigned int yuv:1;
+ unsigned int planar:1;
+ unsigned int uvswap:1;
+};
+
+struct saa7134_card_ir {
+ struct rc_dev *dev;
+
+ char name[32];
+ char phys[32];
+ unsigned users;
+
+ u32 polling;
+ u32 last_gpio;
+ u32 mask_keycode, mask_keydown, mask_keyup;
+
+ bool running;
+
+ struct timer_list timer;
+
+ /* IR core raw decoding */
+ u32 raw_decode;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration */
+
+#define SAA7134_BOARD_NOAUTO UNSET
+#define SAA7134_BOARD_UNKNOWN 0
+#define SAA7134_BOARD_PROTEUS_PRO 1
+#define SAA7134_BOARD_FLYVIDEO3000 2
+#define SAA7134_BOARD_FLYVIDEO2000 3
+#define SAA7134_BOARD_EMPRESS 4
+#define SAA7134_BOARD_MONSTERTV 5
+#define SAA7134_BOARD_MD9717 6
+#define SAA7134_BOARD_TVSTATION_RDS 7
+#define SAA7134_BOARD_CINERGY400 8
+#define SAA7134_BOARD_MD5044 9
+#define SAA7134_BOARD_KWORLD 10
+#define SAA7134_BOARD_CINERGY600 11
+#define SAA7134_BOARD_MD7134 12
+#define SAA7134_BOARD_TYPHOON_90031 13
+#define SAA7134_BOARD_ELSA 14
+#define SAA7134_BOARD_ELSA_500TV 15
+#define SAA7134_BOARD_ASUSTeK_TVFM7134 16
+#define SAA7134_BOARD_VA1000POWER 17
+#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18
+#define SAA7134_BOARD_VIDEOMATE_TV 19
+#define SAA7134_BOARD_CRONOS_PLUS 20
+#define SAA7134_BOARD_10MOONSTVMASTER 21
+#define SAA7134_BOARD_MD2819 22
+#define SAA7134_BOARD_BMK_MPEX_TUNER 23
+#define SAA7134_BOARD_TVSTATION_DVR 24
+#define SAA7134_BOARD_ASUSTEK_TVFM7133 25
+#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26
+#define SAA7134_BOARD_MANLI_MTV002 27
+#define SAA7134_BOARD_MANLI_MTV001 28
+#define SAA7134_BOARD_TG3000TV 29
+#define SAA7134_BOARD_ECS_TVP3XP 30
+#define SAA7134_BOARD_ECS_TVP3XP_4CB5 31
+#define SAA7134_BOARD_AVACSSMARTTV 32
+#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
+#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
+#define SAA7134_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_ITEMS_MTV005 37
+#define SAA7134_BOARD_CINERGY200 38
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
+#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
+#define SAA7134_BOARD_SABRENT_SBTTVFM 42
+#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
+#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_307 45
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
+#define SAA7134_BOARD_CINERGY400_CARDBUS 47
+#define SAA7134_BOARD_CINERGY600_MK3 48
+#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
+#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
+#define SAA7134_BOARD_PROVIDEO_PV952 51
+#define SAA7134_BOARD_AVERMEDIA_305 52
+#define SAA7134_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
+#define SAA7134_BOARD_FLYDVBTDUO 55
+#define SAA7134_BOARD_AVERMEDIA_307 56
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
+#define SAA7134_BOARD_ADS_INSTANT_TV 58
+#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
+#define SAA7134_BOARD_FLYDVBT_DUO_CARDBUS 60
+#define SAA7134_BOARD_PHILIPS_TOUGH 61
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62
+#define SAA7134_BOARD_KWORLD_XPERT 63
+#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
+#define SAA7134_BOARD_KWORLD_TERMINATOR 65
+#define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA 69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER 81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV 89
+#define SAA7134_BOARD_KWORLD_ATSC110 90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2 93
+#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
+#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
+#define SAA7134_BOARD_FLYDVBS_LR300 97
+#define SAA7134_BOARD_PROTEUS_2309 98
+#define SAA7134_BOARD_AVERMEDIA_A16AR 99
+#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+#define SAA7134_BOARD_PINNACLE_PCTV_310i 101
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
+#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
+#define SAA7134_BOARD_ENCORE_ENLTV 106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM 107
+#define SAA7134_BOARD_CINERGY_HT_PCI 108
+#define SAA7134_BOARD_PHILIPS_TIGER_S 109
+#define SAA7134_BOARD_AVERMEDIA_M102 110
+#define SAA7134_BOARD_ASUS_P7131_4871 111
+#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112
+#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
+#define SAA7134_BOARD_KWORLD_DVBT_210 114
+#define SAA7134_BOARD_SABRENT_TV_PCB05 115
+#define SAA7134_BOARD_10MOONSTVMASTER3 116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
+#define SAA7134_BOARD_BEHOLD_401 118
+#define SAA7134_BOARD_BEHOLD_403 119
+#define SAA7134_BOARD_BEHOLD_403FM 120
+#define SAA7134_BOARD_BEHOLD_405 121
+#define SAA7134_BOARD_BEHOLD_405FM 122
+#define SAA7134_BOARD_BEHOLD_407 123
+#define SAA7134_BOARD_BEHOLD_407FM 124
+#define SAA7134_BOARD_BEHOLD_409 125
+#define SAA7134_BOARD_BEHOLD_505FM 126
+#define SAA7134_BOARD_BEHOLD_507_9FM 127
+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
+#define SAA7134_BOARD_BEHOLD_607FM_MK3 129
+#define SAA7134_BOARD_BEHOLD_M6 130
+#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
+#define SAA7134_BOARD_PHILIPS_SNAKE 133
+#define SAA7134_BOARD_CREATIX_CTX953 134
+#define SAA7134_BOARD_MSI_TVANYWHERE_AD11 135
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
+#define SAA7134_BOARD_AVERMEDIA_A16D 137
+#define SAA7134_BOARD_AVERMEDIA_M115 138
+#define SAA7134_BOARD_VIDEOMATE_T750 139
+#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
+#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6 142
+#define SAA7134_BOARD_BEHOLD_M63 143
+#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144
+#define SAA7134_BOARD_AVERMEDIA_M103 145
+#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
+#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1 147
+#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
+#define SAA7134_BOARD_AVERMEDIA_M135A 149
+#define SAA7134_BOARD_REAL_ANGEL_220 150
+#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151
+#define SAA7134_BOARD_ASUSTeK_TIGER 152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
+#define SAA7134_BOARD_BEHOLD_505RDS_MK5 159
+#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160
+#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161
+#define SAA7134_BOARD_BEHOLD_607FM_MK5 162
+#define SAA7134_BOARD_BEHOLD_609FM_MK3 163
+#define SAA7134_BOARD_BEHOLD_609FM_MK5 164
+#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165
+#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166
+#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167
+#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168
+#define SAA7134_BOARD_VIDEOMATE_S350 169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
+#define SAA7134_BOARD_BEHOLD_X7 171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
+#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173
+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174
+#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
+#define SAA7134_BOARD_BEHOLD_505RDS_MK3 176
+#define SAA7134_BOARD_HAWELL_HW_404M7 177
+#define SAA7134_BOARD_BEHOLD_H7 178
+#define SAA7134_BOARD_BEHOLD_A7 179
+#define SAA7134_BOARD_AVERMEDIA_M733A 180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
+#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
+#define SAA7134_BOARD_VIDEOMATE_M1F 183
+#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184
+#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_BOARD_ASUSTeK_PS3_100 190
+
+#define SAA7134_MAXBOARDS 32
+#define SAA7134_INPUT_MAX 8
+
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart */
+
+#define SAA7134_REMOTE_GPIO 1
+#define SAA7134_REMOTE_I2C 2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0)
+#define SET_CLOCK_NOT_DELAYED (1 << 1)
+#define SET_CLOCK_INVERTED (1 << 2)
+#define SET_VSYNC_OFF (1 << 3)
+
+struct saa7134_input {
+ char *name;
+ unsigned int vmux;
+ enum saa7134_audio_in amux;
+ unsigned int gpio;
+ unsigned int tv:1;
+};
+
+enum saa7134_mpeg_type {
+ SAA7134_MPEG_UNUSED,
+ SAA7134_MPEG_EMPRESS,
+ SAA7134_MPEG_DVB,
+};
+
+enum saa7134_mpeg_ts_type {
+ SAA7134_MPEG_TS_PARALLEL = 0,
+ SAA7134_MPEG_TS_SERIAL,
+};
+
+struct saa7134_board {
+ char *name;
+ unsigned int audio_clock;
+
+ /* input switching */
+ unsigned int gpiomask;
+ struct saa7134_input inputs[SAA7134_INPUT_MAX];
+ struct saa7134_input radio;
+ struct saa7134_input mute;
+
+ /* i2c chip info */
+ unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+ unsigned char empress_addr;
+ unsigned char rds_addr;
+
+ unsigned int tda9887_conf;
+ unsigned int tuner_config;
+
+ /* peripheral I/O */
+ enum saa7134_video_out video_out;
+ enum saa7134_mpeg_type mpeg;
+ enum saa7134_mpeg_ts_type ts_type;
+ unsigned int vid_port_opts;
+ unsigned int ts_force_val:1;
+};
+
+#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
+#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
+#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
+#define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg)
+#define card(dev) (saa7134_boards[dev->board])
+#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
+
+/* ----------------------------------------------------------- */
+/* device / file handle status */
+
+#define RESOURCE_OVERLAY 1
+#define RESOURCE_VIDEO 2
+#define RESOURCE_VBI 4
+
+#define INTERLACE_AUTO 0
+#define INTERLACE_ON 1
+#define INTERLACE_OFF 2
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */
+
+struct saa7134_dev;
+struct saa7134_dma;
+
+/* saa7134 page table */
+struct saa7134_pgtable {
+ unsigned int size;
+ __le32 *cpu;
+ dma_addr_t dma;
+};
+
+/* tvaudio thread status */
+struct saa7134_thread {
+ struct task_struct *thread;
+ unsigned int scan1;
+ unsigned int scan2;
+ unsigned int mode;
+ unsigned int stopped;
+};
+
+/* buffer for one video/vbi/ts frame */
+struct saa7134_buf {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ /* saa7134 specific */
+ struct saa7134_format *fmt;
+ unsigned int top_seen;
+ int (*activate)(struct saa7134_dev *dev,
+ struct saa7134_buf *buf,
+ struct saa7134_buf *next);
+
+ /* page tables */
+ struct saa7134_pgtable *pt;
+};
+
+struct saa7134_dmaqueue {
+ struct saa7134_dev *dev;
+ struct saa7134_buf *curr;
+ struct list_head queue;
+ struct timer_list timeout;
+ unsigned int need_two;
+};
+
+/* video filehandle status */
+struct saa7134_fh {
+ struct saa7134_dev *dev;
+ unsigned int radio;
+ enum v4l2_buf_type type;
+ unsigned int resources;
+ enum v4l2_priority prio;
+
+ /* video overlay */
+ struct v4l2_window win;
+ struct v4l2_clip clips[8];
+ unsigned int nclips;
+
+ /* video capture */
+ struct saa7134_format *fmt;
+ unsigned int width,height;
+ struct videobuf_queue cap;
+ struct saa7134_pgtable pt_cap;
+
+ /* vbi capture */
+ struct videobuf_queue vbi;
+ struct saa7134_pgtable pt_vbi;
+};
+
+/* dmasound dsp status */
+struct saa7134_dmasound {
+ struct mutex lock;
+ int minor_mixer;
+ int minor_dsp;
+ unsigned int users_dsp;
+
+ /* mixer */
+ enum saa7134_audio_in input;
+ unsigned int count;
+ unsigned int line1;
+ unsigned int line2;
+
+ /* dsp */
+ unsigned int afmt;
+ unsigned int rate;
+ unsigned int channels;
+ unsigned int recording_on;
+ unsigned int dma_running;
+ unsigned int blocks;
+ unsigned int blksize;
+ unsigned int bufsize;
+ struct saa7134_pgtable pt;
+ struct videobuf_dmabuf dma;
+ unsigned int dma_blk;
+ unsigned int read_offset;
+ unsigned int read_count;
+ void * priv_data;
+ struct snd_pcm_substream *substream;
+};
+
+/* ts/mpeg status */
+struct saa7134_ts {
+ /* TS capture */
+ struct saa7134_pgtable pt_ts;
+ int nr_packets;
+ int nr_bufs;
+};
+
+/* ts/mpeg ops */
+struct saa7134_mpeg_ops {
+ enum saa7134_mpeg_type type;
+ struct list_head next;
+ int (*init)(struct saa7134_dev *dev);
+ int (*fini)(struct saa7134_dev *dev);
+ void (*signal_change)(struct saa7134_dev *dev);
+};
+
+/* global device status */
+struct saa7134_dev {
+ struct list_head devlist;
+ struct mutex lock;
+ spinlock_t slock;
+ struct v4l2_prio_state prio;
+ struct v4l2_device v4l2_dev;
+ /* workstruct for loading modules */
+ struct work_struct request_module_wk;
+
+ /* insmod option/autodetected */
+ int autodetected;
+
+ /* various device info */
+ unsigned int resources;
+ struct video_device *video_dev;
+ struct video_device *radio_dev;
+ struct video_device *vbi_dev;
+ struct saa7134_dmasound dmasound;
+
+ /* infrared remote */
+ int has_remote;
+ struct saa7134_card_ir *remote;
+
+ /* pci i/o */
+ char name[32];
+ int nr;
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+ __u32 __iomem *lmmio;
+ __u8 __iomem *bmmio;
+
+ /* config info */
+ unsigned int board;
+ unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+
+ unsigned int tda9887_conf;
+ unsigned int gpio_value;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+ unsigned char eedata[256];
+ int has_rds;
+
+ /* video overlay */
+ struct v4l2_framebuffer ovbuf;
+ struct saa7134_format *ovfmt;
+ unsigned int ovenable;
+ enum v4l2_field ovfield;
+
+ /* video+ts+vbi capture */
+ struct saa7134_dmaqueue video_q;
+ struct saa7134_dmaqueue vbi_q;
+ unsigned int video_fieldcount;
+ unsigned int vbi_fieldcount;
+
+ /* various v4l controls */
+ struct saa7134_tvnorm *tvnorm; /* video */
+ struct saa7134_tvaudio *tvaudio;
+ unsigned int ctl_input;
+ int ctl_bright;
+ int ctl_contrast;
+ int ctl_hue;
+ int ctl_saturation;
+ int ctl_freq;
+ int ctl_mute; /* audio */
+ int ctl_volume;
+ int ctl_invert; /* private */
+ int ctl_mirror;
+ int ctl_y_odd;
+ int ctl_y_even;
+ int ctl_automute;
+
+ /* crop */
+ struct v4l2_rect crop_bounds;
+ struct v4l2_rect crop_defrect;
+ struct v4l2_rect crop_current;
+
+ /* other global state info */
+ unsigned int automute;
+ struct saa7134_thread thread;
+ struct saa7134_input *input;
+ struct saa7134_input *hw_input;
+ unsigned int hw_mute;
+ int last_carrier;
+ int nosignal;
+ unsigned int insuspend;
+
+ /* I2C keyboard data */
+ struct IR_i2c_init_data init_data;
+
+ /* SAA7134_MPEG_* */
+ struct saa7134_ts ts;
+ struct saa7134_dmaqueue ts_q;
+ int ts_started;
+ struct saa7134_mpeg_ops *mops;
+
+ /* SAA7134_MPEG_EMPRESS only */
+ struct video_device *empress_dev;
+ struct videobuf_queue empress_tsq;
+ atomic_t empress_users;
+ struct work_struct empress_workqueue;
+ int empress_started;
+
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+ /* SAA7134_MPEG_DVB only */
+ struct videobuf_dvb_frontends frontends;
+ int (*original_demod_sleep)(struct dvb_frontend *fe);
+ int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+ int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
+#endif
+ void (*gate_ctrl)(struct saa7134_dev *dev, int open);
+};
+
+/* ----------------------------------------------------------- */
+
+#define saa_readl(reg) readl(dev->lmmio + (reg))
+#define saa_writel(reg,value) writel((value), dev->lmmio + (reg));
+#define saa_andorl(reg,mask,value) \
+ writel((readl(dev->lmmio+(reg)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+(reg))
+#define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit))
+#define saa_clearl(reg,bit) saa_andorl((reg),(bit),0)
+
+#define saa_readb(reg) readb(dev->bmmio + (reg))
+#define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg));
+#define saa_andorb(reg,mask,value) \
+ writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\
+ ((value) & (mask)), dev->bmmio+(reg))
+#define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit))
+#define saa_clearb(reg,bit) saa_andorb((reg),(bit),0)
+
+#define saa_wait(us) { udelay(us); }
+
+#define SAA7134_NORMS (\
+ V4L2_STD_PAL | V4L2_STD_PAL_N | \
+ V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC | V4L2_STD_PAL_M | \
+ V4L2_STD_PAL_60)
+
+#define GRP_EMPRESS (1)
+#define saa_call_all(dev, o, f, args...) do { \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 1); \
+ v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 0); \
+} while (0)
+
+#define saa_call_empress(dev, o, f, args...) ({ \
+ long _rc; \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 1); \
+ _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \
+ GRP_EMPRESS, o, f , ##args); \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 0); \
+ _rc; \
+})
+
+/* ----------------------------------------------------------- */
+/* saa7134-core.c */
+
+extern struct list_head saa7134_devlist;
+extern struct mutex saa7134_devlist_lock;
+extern int saa7134_no_overlay;
+
+void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
+
+#define SAA7134_PGTABLE_SIZE 4096
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
+int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+ struct scatterlist *list, unsigned int length,
+ unsigned int startpage);
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
+
+int saa7134_buffer_count(unsigned int size, unsigned int count);
+int saa7134_buffer_startpage(struct saa7134_buf *buf);
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
+
+int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+ struct saa7134_buf *buf);
+void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+ unsigned int state);
+void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+void saa7134_buffer_timeout(unsigned long data);
+void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
+
+int saa7134_set_dmabits(struct saa7134_dev *dev);
+
+extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-cards.c */
+
+extern struct saa7134_board saa7134_boards[];
+extern const unsigned int saa7134_bcount;
+extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
+
+extern int saa7134_board_init1(struct saa7134_dev *dev);
+extern int saa7134_board_init2(struct saa7134_dev *dev);
+int saa7134_tuner_callback(void *priv, int component, int command, int arg);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-i2c.c */
+
+int saa7134_i2c_register(struct saa7134_dev *dev);
+int saa7134_i2c_unregister(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-video.c */
+
+extern unsigned int video_debug;
+extern struct video_device saa7134_video_template;
+extern struct video_device saa7134_radio_template;
+
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id);
+
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
+
+int saa7134_video_init1(struct saa7134_dev *dev);
+int saa7134_video_init2(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-ts.c */
+
+#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
+
+extern struct videobuf_queue_ops saa7134_ts_qops;
+
+int saa7134_ts_init1(struct saa7134_dev *dev);
+int saa7134_ts_fini(struct saa7134_dev *dev);
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-vbi.c */
+
+extern struct videobuf_queue_ops saa7134_vbi_qops;
+extern struct video_device saa7134_vbi_template;
+
+int saa7134_vbi_init1(struct saa7134_dev *dev);
+int saa7134_vbi_fini(struct saa7134_dev *dev);
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-tvaudio.c */
+
+int saa7134_tvaudio_rx2mode(u32 rx);
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+ struct saa7134_input *in);
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
+
+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);
+
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-oss.c */
+
+extern const struct file_operations saa7134_dsp_fops;
+extern const struct file_operations saa7134_mixer_fops;
+
+int saa7134_oss_init1(struct saa7134_dev *dev);
+int saa7134_oss_fini(struct saa7134_dev *dev);
+void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
+
+/* ----------------------------------------------------------- */
+/* saa7134-input.c */
+
+#if defined(CONFIG_VIDEO_SAA7134_RC)
+int saa7134_input_init1(struct saa7134_dev *dev);
+void saa7134_input_fini(struct saa7134_dev *dev);
+void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
+int saa7134_ir_start(struct saa7134_dev *dev);
+void saa7134_ir_stop(struct saa7134_dev *dev);
+#else
+#define saa7134_input_init1(dev) ((void)0)
+#define saa7134_input_fini(dev) ((void)0)
+#define saa7134_input_irq(dev) ((void)0)
+#define saa7134_probe_i2c_ir(dev) ((void)0)
+#define saa7134_ir_start(dev) ((void)0)
+#define saa7134_ir_stop(dev) ((void)0)
+#endif
diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig
new file mode 100644
index 000000000000..da88b77a916c
--- /dev/null
+++ b/drivers/media/pci/saa7146/Kconfig
@@ -0,0 +1,38 @@
+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.
+
+config VIDEO_MXB
+ tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
+ depends on PCI && VIDEO_V4L2 && I2C
+ select VIDEO_SAA7146_VV
+ select VIDEO_TUNER
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for the 'Multimedia eXtension Board'
+ TV card by Siemens-Nixdorf.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mxb.
diff --git a/drivers/media/pci/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile
new file mode 100644
index 000000000000..f3566a95e4aa
--- /dev/null
+++ b/drivers/media/pci/saa7146/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_MXB) += mxb.o
+obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 366434f5647e..366434f5647e 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index a1eb26d11070..a1eb26d11070 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
diff --git a/drivers/media/video/mxb.c b/drivers/media/pci/saa7146/mxb.c
index b520a45cb3f3..b520a45cb3f3 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig
new file mode 100644
index 000000000000..a53db7d1c96e
--- /dev/null
+++ b/drivers/media/pci/saa7164/Kconfig
@@ -0,0 +1,18 @@
+config VIDEO_SAA7164
+ tristate "NXP SAA7164 support"
+ depends on DVB_CORE && VIDEO_DEV && PCI && I2C
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEOBUF_DVB
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for NXP SAA7164 based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7164
+
diff --git a/drivers/media/pci/saa7164/Makefile b/drivers/media/pci/saa7164/Makefile
new file mode 100644
index 000000000000..ba0e33a1ee24
--- /dev/null
+++ b/drivers/media/pci/saa7164/Makefile
@@ -0,0 +1,12 @@
+saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
+ saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \
+ saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o
+
+obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
new file mode 100644
index 000000000000..eff7135cf0e8
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -0,0 +1,1524 @@
+/*
+ * Driver for the NXP SAA7164 PCIe bridge
+ *
+ * Copyright (c) 2010 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 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/wait.h>
+#include <linux/slab.h>
+
+#include "saa7164.h"
+
+int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
+{
+ int ret;
+
+ if (!(saa_debug & DBGLVL_CPU))
+ return 0;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ i->deviceinst = 0;
+ i->devicespec = 0;
+ i->mode = 0;
+ i->status = 0;
+
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
+
+ return ret;
+}
+
+int saa7164_api_collect_debug(struct saa7164_dev *dev)
+{
+ struct tmComResDebugGetData d;
+ u8 more = 255;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ while (more--) {
+
+ memset(&d, 0, sizeof(d));
+
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n",
+ __func__, ret);
+
+ if (d.dwResult != SAA_OK)
+ break;
+
+ printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr,
+ d.ucDebugData);
+ }
+
+ return 0;
+}
+
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
+{
+ struct tmComResDebugSetLevel lvl;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level);
+
+ /* Retrieve current state */
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
+
+ lvl.dwDebugLevel = level;
+
+ /* set new state */
+ ret = saa7164_cmd_send(dev, 0, SET_CUR,
+ SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_vbi_format(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResProbeCommit fmt, rsp;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__,
+ port->nr, port->hwcfg.unitid);
+
+ fmt.bmHint = 0;
+ fmt.bFormatIndex = 1;
+ fmt.bFrameIndex = 1;
+
+ /* Probe, see if it can support this format */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret);
+
+ /* See of the format change was successful */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret);
+ } else {
+ /* Compare requested vs received, should be same */
+ if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) {
+ dprintk(DBGLVL_API, "SET/PROBE Verified\n");
+
+ /* Ask the device to select the negotiated format */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() commit error, ret = 0x%x\n",
+ __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n",
+ __func__, ret);
+
+ if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) {
+ printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n",
+ __func__, ret);
+ } else
+ dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
+
+ dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
+ dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n",
+ rsp.bFormatIndex);
+ dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n",
+ rsp.bFrameIndex);
+ } else
+ printk(KERN_ERR "%s() compare failed\n", __func__);
+ }
+
+ if (ret == SAA_OK)
+ dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr);
+
+ return ret;
+}
+
+int saa7164_api_set_gop_size(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoGopStructure gs;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ gs.ucRefFrameDist = port->encoder_params.refdist;
+ gs.ucGOPSize = port->encoder_params.gop_size;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_GOP_STRUCTURE_CONTROL,
+ sizeof(gs), &gs);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoBitRate vb;
+ struct tmComResEncAudioBitRate ab;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+ port->hwcfg.sourceid);
+
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+ port->encoder_profile = EU_PROFILE_PS_DVD;
+ else
+ port->encoder_profile = EU_PROFILE_TS_HQ;
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Resolution */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Establish video bitrates */
+ if (port->encoder_params.bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
+ else
+ vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
+ vb.dwVideoBitRate = port->encoder_params.bitrate;
+ vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncVideoBitRate),
+ &vb);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Establish audio bitrates */
+ ab.ucAudioBitRateMode = 0;
+ ab.dwAudioBitRate = 384000;
+ ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_AUDIO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncAudioBitRate),
+ &ab);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+
+ saa7164_api_set_aspect_ratio(port);
+ saa7164_api_set_gop_size(port);
+
+ return ret;
+}
+
+int saa7164_api_get_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoBitRate v;
+ struct tmComResEncAudioBitRate a;
+ struct tmComResEncVideoInputAspectRatio ar;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+ port->hwcfg.sourceid);
+
+ port->encoder_profile = 0;
+ port->video_format = 0;
+ port->video_resolution = 0;
+ port->audio_format = 0;
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8),
+ &port->video_resolution);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Aspect Ratio */
+ ar.width = 0;
+ ar.height = 0;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_INPUT_ASPECT_CONTROL,
+ sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile);
+ dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format);
+ dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format);
+ dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
+ dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n",
+ v.ucVideoBitRateMode);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n",
+ v.dwVideoBitRate);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n",
+ v.dwVideoBitRatePeak);
+ dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n",
+ a.ucAudioBitRateMode);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n",
+ a.dwAudioBitRate);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n",
+ a.dwAudioBitRatePeak);
+ dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n",
+ ar.width, ar.height);
+
+ return ret;
+}
+
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoInputAspectRatio ar;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s(%d)\n", __func__,
+ port->encoder_params.ctl_aspect);
+
+ switch (port->encoder_params.ctl_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_1x1:
+ ar.width = 1;
+ ar.height = 1;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
+ ar.width = 4;
+ ar.height = 3;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
+ ar.width = 16;
+ ar.height = 9;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_221x100:
+ ar.width = 221;
+ ar.height = 100;
+ break;
+ default:
+ BUG();
+ }
+
+ dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__,
+ port->encoder_params.ctl_aspect,
+ ar.width, ar.height);
+
+ /* Aspect Ratio */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_INPUT_ASPECT_CONTROL,
+ sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+ u16 val;
+
+ if (ctl == PU_BRIGHTNESS_CONTROL)
+ val = port->ctl_brightness;
+ else
+ if (ctl == PU_CONTRAST_CONTROL)
+ val = port->ctl_contrast;
+ else
+ if (ctl == PU_HUE_CONTROL)
+ val = port->ctl_hue;
+ else
+ if (ctl == PU_SATURATION_CONTROL)
+ val = port->ctl_saturation;
+ else
+ if (ctl == PU_SHARPNESS_CONTROL)
+ val = port->ctl_sharpness;
+ else
+ return -EINVAL;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n",
+ __func__, port->encunit.vsourceid, ctl, val);
+
+ ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR,
+ ctl, sizeof(u16), &val);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+ u16 val;
+
+ ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR,
+ ctl, sizeof(u16), &val);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+ return ret;
+ }
+
+ dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n",
+ __func__, ctl, val);
+
+ if (ctl == PU_BRIGHTNESS_CONTROL)
+ port->ctl_brightness = val;
+ else
+ if (ctl == PU_CONTRAST_CONTROL)
+ port->ctl_contrast = val;
+ else
+ if (ctl == PU_HUE_CONTROL)
+ port->ctl_hue = val;
+ else
+ if (ctl == PU_SATURATION_CONTROL)
+ port->ctl_saturation = val;
+ else
+ if (ctl == PU_SHARPNESS_CONTROL)
+ port->ctl_sharpness = val;
+
+ return ret;
+}
+
+int saa7164_api_set_videomux(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 };
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n",
+ __func__, port->mux_input, inputs[port->mux_input - 1]);
+
+ /* Audio Mute */
+ ret = saa7164_api_audio_mute(port, 1);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Video Mux */
+ ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Audio Mux */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8),
+ &inputs[port->mux_input - 1]);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Audio UnMute */
+ ret = saa7164_api_audio_mute(port, 0);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute)
+{
+ struct saa7164_dev *dev = port->dev;
+ u8 v = mute;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ MUTE_CONTROL, sizeof(u8), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+/* 0 = silence, 0xff = full */
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
+{
+ struct saa7164_dev *dev = port->dev;
+ s16 v, min, max;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, level);
+
+ /* Obtain the min/max ranges */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN,
+ VOLUME_CONTROL, sizeof(u16), &min);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX,
+ VOLUME_CONTROL, sizeof(u16), &max);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
+
+ v = level;
+ if (v < min)
+ v = min;
+ if (v > max)
+ v = max;
+
+ /* Left */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Right */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
+
+ return ret;
+}
+
+int saa7164_api_set_audio_std(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResAudioDefaults lvl;
+ struct tmComResTunerStandard tvaudio;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ /* Establish default levels */
+ lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+ lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+ lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT;
+ lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT;
+ lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
+ lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults),
+ &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Manually select the appropriate TV audio standard */
+ if (port->encodernorm.id & V4L2_STD_NTSC) {
+ tvaudio.std = TU_STANDARD_NTSC_M;
+ tvaudio.country = 1;
+ } else {
+ tvaudio.std = TU_STANDARD_PAL_I;
+ tvaudio.country = 44;
+ }
+
+ ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+ TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
+ return ret;
+}
+
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResTunerStandardAuto p;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect);
+
+ /* Disable TV Audio autodetect if not already set (buggy) */
+ if (autodetect)
+ p.mode = TU_STANDARD_AUTO;
+ else
+ p.mode = TU_STANDARD_MANUAL;
+ ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+ TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
+ if (ret != SAA_OK)
+ printk(KERN_ERR
+ "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_get_videomux(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_ENC, "%s() v_mux=%d\n",
+ __func__, port->mux_input);
+
+ return ret;
+}
+
+int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ u16 len = 0;
+ u8 buf[256];
+ int ret;
+ u8 mas;
+
+ dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__,
+ port->nr, port->type, val);
+
+ if (port->nr == 0)
+ mas = 0xd0;
+ else
+ mas = 0xe0;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0x00] = 0x04;
+ buf[0x01] = 0x00;
+ buf[0x02] = 0x00;
+ buf[0x03] = 0x00;
+
+ buf[0x04] = 0x04;
+ buf[0x05] = 0x00;
+ buf[0x06] = 0x00;
+ buf[0x07] = 0x00;
+
+ buf[0x08] = reg;
+ buf[0x09] = 0x26;
+ buf[0x0a] = mas;
+ buf[0x0b] = 0xb0;
+
+ buf[0x0c] = val;
+ buf[0x0d] = 0x00;
+ buf[0x0e] = 0x00;
+ buf[0x0f] = 0x00;
+
+ ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN,
+ EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+ return -EIO;
+ }
+
+ ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR,
+ EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+#if 0
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf, 16,
+ false);
+#endif
+ return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* Disable the IF block AGC controls */
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+ u8 agc_disable;
+
+ dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
+
+ if (std & V4L2_STD_NTSC) {
+ dprintk(DBGLVL_API, " NTSC\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_I) {
+ dprintk(DBGLVL_API, " PAL-I\n");
+ saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_M) {
+ dprintk(DBGLVL_API, " PAL-M\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_N) {
+ dprintk(DBGLVL_API, " PAL-N\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_Nc) {
+ dprintk(DBGLVL_API, " PAL-Nc\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_B) {
+ dprintk(DBGLVL_API, " PAL-B\n");
+ saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_DK) {
+ dprintk(DBGLVL_API, " PAL-DK\n");
+ saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_SECAM_L) {
+ dprintk(DBGLVL_API, " SECAM-L\n");
+ saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */
+ agc_disable = 0;
+ } else {
+ /* Unknown standard, assume DTV */
+ dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
+ /* Undefinded Video Standard */
+ saa7164_api_set_dif(port, 0x00, 0x80);
+ agc_disable = 1;
+ }
+
+ saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */
+ saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */
+ saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */
+ saa7164_api_set_dif(port, 0x04, 0x01); /* Active */
+ msleep(100);
+ saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
+ msleep(100);
+
+ return ret;
+}
+
+/* Ensure the dif is in the correct state for the operating mode
+ * (analog / dtv). We only configure the diff through the analog encoder
+ * so when we're in digital mode we need to find the appropriate encoder
+ * and use it to configure the DIF.
+ */
+int saa7164_api_initialize_dif(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_port *p = NULL;
+ int ret = -EINVAL;
+ u32 std = 0;
+
+ dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__,
+ port->nr, port->type);
+
+ if (port->type == SAA7164_MPEG_ENCODER) {
+ /* Pick any analog standard to init the diff.
+ * we'll come back during encoder_init'
+ * and set the correct standard if requried.
+ */
+ std = V4L2_STD_NTSC;
+ } else
+ if (port->type == SAA7164_MPEG_DVB) {
+ if (port->nr == SAA7164_PORT_TS1)
+ p = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ p = &dev->ports[SAA7164_PORT_ENC2];
+ } else
+ if (port->type == SAA7164_MPEG_VBI) {
+ std = V4L2_STD_NTSC;
+ if (port->nr == SAA7164_PORT_VBI1)
+ p = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ p = &dev->ports[SAA7164_PORT_ENC2];
+ } else
+ BUG();
+
+ if (p)
+ ret = saa7164_api_configure_dif(p, std);
+
+ return ret;
+}
+
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n",
+ __func__, port->nr, port->hwcfg.unitid, mode);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
+ SAA_STATE_CONTROL, sizeof(mode), &mode);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n",
+ __func__, port->nr, port->hwcfg.unitid, ret);
+
+ return ret;
+}
+
+int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version)
+{
+ int ret;
+
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_FW_VERSION_CONTROL, sizeof(u32), version);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
+{
+ u8 reg[] = { 0x0f, 0x00 };
+
+ if (buflen < 128)
+ return -ENOMEM;
+
+ /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
+ /* TODO: Pull the details from the boards struct */
+ return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
+ &reg[0], 128, buf);
+}
+
+int saa7164_api_configure_port_vbi(struct saa7164_dev *dev,
+ struct saa7164_port *port)
+{
+ struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc;
+
+ dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+ dprintk(DBGLVL_API, " VideoStandard = 0x%x\n", fmt->VideoStandard);
+ dprintk(DBGLVL_API, " StartLine = %d\n", fmt->StartLine);
+ dprintk(DBGLVL_API, " EndLine = %d\n", fmt->EndLine);
+ dprintk(DBGLVL_API, " FieldRate = %d\n", fmt->FieldRate);
+ dprintk(DBGLVL_API, " bNumLines = %d\n", fmt->bNumLines);
+
+ /* Cache the hardware configuration in the port */
+
+ port->bufcounter = port->hwcfg.BARLocation;
+ port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+ port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+ port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+ port->bufptr32l = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+ port->bufptr32h = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ port->bufptr64 = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
+ port->hwcfg.BARLocation);
+
+ dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n",
+ port->nr);
+
+ return 0;
+}
+
+int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
+ struct saa7164_port *port,
+ struct tmComResTSFormatDescrHeader *tsfmt)
+{
+ dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
+ dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset);
+ dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength);
+ dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength);
+ dprintk(DBGLVL_API, " bguid = (....)\n");
+
+ /* Cache the hardware configuration in the port */
+
+ port->bufcounter = port->hwcfg.BARLocation;
+ port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+ port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+ port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+ port->bufptr32l = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+ port->bufptr32h = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ port->bufptr64 = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
+ port->hwcfg.BARLocation);
+
+ dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n",
+ port->nr);
+
+ return 0;
+}
+
+int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
+ struct saa7164_port *port,
+ struct tmComResPSFormatDescrHeader *fmt)
+{
+ dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+ dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength);
+ dprintk(DBGLVL_API, " wPackLength= 0x%x\n", fmt->wPackLength);
+ dprintk(DBGLVL_API, " bPackDataType= 0x%x\n", fmt->bPackDataType);
+
+ /* Cache the hardware configuration in the port */
+ /* TODO: CHECK THIS in the port config */
+ port->bufcounter = port->hwcfg.BARLocation;
+ port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+ port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+ port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+ port->bufptr32l = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+ port->bufptr32h = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ port->bufptr64 = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
+ port->hwcfg.BARLocation);
+
+ dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n",
+ port->nr);
+
+ return 0;
+}
+
+int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
+{
+ struct saa7164_port *tsport = NULL;
+ struct saa7164_port *encport = NULL;
+ struct saa7164_port *vbiport = NULL;
+ u32 idx, next_offset;
+ int i;
+ struct tmComResDescrHeader *hdr, *t;
+ struct tmComResExtDevDescrHeader *exthdr;
+ struct tmComResPathDescrHeader *pathhdr;
+ struct tmComResAntTermDescrHeader *anttermhdr;
+ struct tmComResTunerDescrHeader *tunerunithdr;
+ struct tmComResDMATermDescrHeader *vcoutputtermhdr;
+ struct tmComResTSFormatDescrHeader *tsfmt;
+ struct tmComResPSFormatDescrHeader *psfmt;
+ struct tmComResSelDescrHeader *psel;
+ struct tmComResProcDescrHeader *pdh;
+ struct tmComResAFeatureDescrHeader *afd;
+ struct tmComResEncoderDescrHeader *edh;
+ struct tmComResVBIFormatDescrHeader *vbifmt;
+ u32 currpath = 0;
+
+ dprintk(DBGLVL_API,
+ "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n",
+ __func__, len, (u32)sizeof(struct tmComResDescrHeader));
+
+ for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) {
+
+ hdr = (struct tmComResDescrHeader *)(buf + idx);
+
+ if (hdr->type != CS_INTERFACE)
+ return SAA_ERR_NOT_SUPPORTED;
+
+ dprintk(DBGLVL_API, "@ 0x%x =\n", idx);
+ switch (hdr->subtype) {
+ case GENERAL_REQUEST:
+ dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
+ break;
+ case VC_TUNER_PATH:
+ dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
+ pathhdr = (struct tmComResPathDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " pathid = 0x%x\n",
+ pathhdr->pathid);
+ currpath = pathhdr->pathid;
+ break;
+ case VC_INPUT_TERMINAL:
+ dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
+ anttermhdr =
+ (struct tmComResAntTermDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " terminalid = 0x%x\n",
+ anttermhdr->terminalid);
+ dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
+ anttermhdr->terminaltype);
+ switch (anttermhdr->terminaltype) {
+ case ITT_ANTENNA:
+ dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
+ break;
+ case LINE_CONNECTOR:
+ dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
+ break;
+ case SPDIF_CONNECTOR:
+ dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
+ break;
+ case COMPOSITE_CONNECTOR:
+ dprintk(DBGLVL_API,
+ " = COMPOSITE_CONNECTOR\n");
+ break;
+ case SVIDEO_CONNECTOR:
+ dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
+ break;
+ case COMPONENT_CONNECTOR:
+ dprintk(DBGLVL_API,
+ " = COMPONENT_CONNECTOR\n");
+ break;
+ case STANDARD_DMA:
+ dprintk(DBGLVL_API, " = STANDARD_DMA\n");
+ break;
+ default:
+ dprintk(DBGLVL_API, " = undefined (0x%x)\n",
+ anttermhdr->terminaltype);
+ }
+ dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
+ anttermhdr->assocterminal);
+ dprintk(DBGLVL_API, " iterminal = 0x%x\n",
+ anttermhdr->iterminal);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ anttermhdr->controlsize);
+ break;
+ case VC_OUTPUT_TERMINAL:
+ dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
+ vcoutputtermhdr =
+ (struct tmComResDMATermDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ vcoutputtermhdr->unitid);
+ dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
+ vcoutputtermhdr->terminaltype);
+ switch (vcoutputtermhdr->terminaltype) {
+ case ITT_ANTENNA:
+ dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
+ break;
+ case LINE_CONNECTOR:
+ dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
+ break;
+ case SPDIF_CONNECTOR:
+ dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
+ break;
+ case COMPOSITE_CONNECTOR:
+ dprintk(DBGLVL_API,
+ " = COMPOSITE_CONNECTOR\n");
+ break;
+ case SVIDEO_CONNECTOR:
+ dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
+ break;
+ case COMPONENT_CONNECTOR:
+ dprintk(DBGLVL_API,
+ " = COMPONENT_CONNECTOR\n");
+ break;
+ case STANDARD_DMA:
+ dprintk(DBGLVL_API, " = STANDARD_DMA\n");
+ break;
+ default:
+ dprintk(DBGLVL_API, " = undefined (0x%x)\n",
+ vcoutputtermhdr->terminaltype);
+ }
+ dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
+ vcoutputtermhdr->assocterminal);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ vcoutputtermhdr->sourceid);
+ dprintk(DBGLVL_API, " iterminal = 0x%x\n",
+ vcoutputtermhdr->iterminal);
+ dprintk(DBGLVL_API, " BARLocation = 0x%x\n",
+ vcoutputtermhdr->BARLocation);
+ dprintk(DBGLVL_API, " flags = 0x%x\n",
+ vcoutputtermhdr->flags);
+ dprintk(DBGLVL_API, " interruptid = 0x%x\n",
+ vcoutputtermhdr->interruptid);
+ dprintk(DBGLVL_API, " buffercount = 0x%x\n",
+ vcoutputtermhdr->buffercount);
+ dprintk(DBGLVL_API, " metadatasize = 0x%x\n",
+ vcoutputtermhdr->metadatasize);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ vcoutputtermhdr->controlsize);
+ dprintk(DBGLVL_API, " numformats = 0x%x\n",
+ vcoutputtermhdr->numformats);
+
+ t = (struct tmComResDescrHeader *)
+ ((struct tmComResDMATermDescrHeader *)(buf + idx));
+ next_offset = idx + (vcoutputtermhdr->len);
+ for (i = 0; i < vcoutputtermhdr->numformats; i++) {
+ t = (struct tmComResDescrHeader *)
+ (buf + next_offset);
+ switch (t->subtype) {
+ case VS_FORMAT_MPEG2TS:
+ tsfmt =
+ (struct tmComResTSFormatDescrHeader *)t;
+ if (currpath == 1)
+ tsport = &dev->ports[SAA7164_PORT_TS1];
+ else
+ tsport = &dev->ports[SAA7164_PORT_TS2];
+ memcpy(&tsport->hwcfg, vcoutputtermhdr,
+ sizeof(*vcoutputtermhdr));
+ saa7164_api_configure_port_mpeg2ts(dev,
+ tsport, tsfmt);
+ break;
+ case VS_FORMAT_MPEG2PS:
+ psfmt =
+ (struct tmComResPSFormatDescrHeader *)t;
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->hwcfg, vcoutputtermhdr,
+ sizeof(*vcoutputtermhdr));
+ saa7164_api_configure_port_mpeg2ps(dev,
+ encport, psfmt);
+ break;
+ case VS_FORMAT_VBI:
+ vbifmt =
+ (struct tmComResVBIFormatDescrHeader *)t;
+ if (currpath == 1)
+ vbiport = &dev->ports[SAA7164_PORT_VBI1];
+ else
+ vbiport = &dev->ports[SAA7164_PORT_VBI2];
+ memcpy(&vbiport->hwcfg, vcoutputtermhdr,
+ sizeof(*vcoutputtermhdr));
+ memcpy(&vbiport->vbi_fmt_ntsc, vbifmt,
+ sizeof(*vbifmt));
+ saa7164_api_configure_port_vbi(dev,
+ vbiport);
+ break;
+ case VS_FORMAT_RDS:
+ dprintk(DBGLVL_API,
+ " = VS_FORMAT_RDS\n");
+ break;
+ case VS_FORMAT_UNCOMPRESSED:
+ dprintk(DBGLVL_API,
+ " = VS_FORMAT_UNCOMPRESSED\n");
+ break;
+ case VS_FORMAT_TYPE:
+ dprintk(DBGLVL_API,
+ " = VS_FORMAT_TYPE\n");
+ break;
+ default:
+ dprintk(DBGLVL_API,
+ " = undefined (0x%x)\n",
+ t->subtype);
+ }
+ next_offset += t->len;
+ }
+
+ break;
+ case TUNER_UNIT:
+ dprintk(DBGLVL_API, " TUNER_UNIT\n");
+ tunerunithdr =
+ (struct tmComResTunerDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ tunerunithdr->unitid);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ tunerunithdr->sourceid);
+ dprintk(DBGLVL_API, " iunit = 0x%x\n",
+ tunerunithdr->iunit);
+ dprintk(DBGLVL_API, " tuningstandards = 0x%x\n",
+ tunerunithdr->tuningstandards);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ tunerunithdr->controlsize);
+ dprintk(DBGLVL_API, " controls = 0x%x\n",
+ tunerunithdr->controls);
+
+ if (tunerunithdr->unitid == tunerunithdr->iunit) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->tunerunit, tunerunithdr,
+ sizeof(struct tmComResTunerDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d] tuner)\n",
+ encport->nr);
+ }
+ break;
+ case VC_SELECTOR_UNIT:
+ psel = (struct tmComResSelDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ psel->unitid);
+ dprintk(DBGLVL_API, " nrinpins = 0x%x\n",
+ psel->nrinpins);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ psel->sourceid);
+ break;
+ case VC_PROCESSING_UNIT:
+ pdh = (struct tmComResProcDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ pdh->unitid);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ pdh->sourceid);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ pdh->controlsize);
+ if (pdh->controlsize == 0x04) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->vidproc, pdh,
+ sizeof(struct tmComResProcDescrHeader));
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
+ break;
+ case FEATURE_UNIT:
+ afd = (struct tmComResAFeatureDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " FEATURE_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ afd->unitid);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ afd->sourceid);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ afd->controlsize);
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->audfeat, afd,
+ sizeof(struct tmComResAFeatureDescrHeader));
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
+ break;
+ case ENCODER_UNIT:
+ edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " ENCODER_UNIT\n");
+ dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype);
+ dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid);
+ dprintk(DBGLVL_API, " vsourceid = 0x%x\n",
+ edh->vsourceid);
+ dprintk(DBGLVL_API, " asourceid = 0x%x\n",
+ edh->asourceid);
+ dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit);
+ if (edh->iunit == edh->unitid) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->encunit, edh,
+ sizeof(struct tmComResEncoderDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
+ break;
+ case EXTENSION_UNIT:
+ dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
+ exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx);
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ exthdr->unitid);
+ dprintk(DBGLVL_API, " deviceid = 0x%x\n",
+ exthdr->deviceid);
+ dprintk(DBGLVL_API, " devicetype = 0x%x\n",
+ exthdr->devicetype);
+ if (exthdr->devicetype & 0x1)
+ dprintk(DBGLVL_API, " = Decoder Device\n");
+ if (exthdr->devicetype & 0x2)
+ dprintk(DBGLVL_API, " = GPIO Source\n");
+ if (exthdr->devicetype & 0x4)
+ dprintk(DBGLVL_API, " = Video Decoder\n");
+ if (exthdr->devicetype & 0x8)
+ dprintk(DBGLVL_API, " = Audio Decoder\n");
+ if (exthdr->devicetype & 0x20)
+ dprintk(DBGLVL_API, " = Crossbar\n");
+ if (exthdr->devicetype & 0x40)
+ dprintk(DBGLVL_API, " = Tuner\n");
+ if (exthdr->devicetype & 0x80)
+ dprintk(DBGLVL_API, " = IF PLL\n");
+ if (exthdr->devicetype & 0x100)
+ dprintk(DBGLVL_API, " = Demodulator\n");
+ if (exthdr->devicetype & 0x200)
+ dprintk(DBGLVL_API, " = RDS Decoder\n");
+ if (exthdr->devicetype & 0x400)
+ dprintk(DBGLVL_API, " = Encoder\n");
+ if (exthdr->devicetype & 0x800)
+ dprintk(DBGLVL_API, " = IR Decoder\n");
+ if (exthdr->devicetype & 0x1000)
+ dprintk(DBGLVL_API, " = EEPROM\n");
+ if (exthdr->devicetype & 0x2000)
+ dprintk(DBGLVL_API,
+ " = VBI Decoder\n");
+ if (exthdr->devicetype & 0x10000)
+ dprintk(DBGLVL_API,
+ " = Streaming Device\n");
+ if (exthdr->devicetype & 0x20000)
+ dprintk(DBGLVL_API,
+ " = DRM Device\n");
+ if (exthdr->devicetype & 0x40000000)
+ dprintk(DBGLVL_API,
+ " = Generic Device\n");
+ if (exthdr->devicetype & 0x80000000)
+ dprintk(DBGLVL_API,
+ " = Config Space Device\n");
+ dprintk(DBGLVL_API, " numgpiopins = 0x%x\n",
+ exthdr->numgpiopins);
+ dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n",
+ exthdr->numgpiogroups);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ exthdr->controlsize);
+ if (exthdr->devicetype & 0x80) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->ifunit, exthdr,
+ sizeof(struct tmComResExtDevDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
+ break;
+ case PVC_INFRARED_UNIT:
+ dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
+ break;
+ case DRM_UNIT:
+ dprintk(DBGLVL_API, " DRM_UNIT\n");
+ break;
+ default:
+ dprintk(DBGLVL_API, "default %d\n", hdr->subtype);
+ }
+
+ dprintk(DBGLVL_API, " 1.%x\n", hdr->len);
+ dprintk(DBGLVL_API, " 2.%x\n", hdr->type);
+ dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype);
+ dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid);
+
+ idx += hdr->len;
+ }
+
+ return 0;
+}
+
+int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
+{
+ int ret;
+ u32 buflen = 0;
+ u8 *buf;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ /* Get the total descriptor length */
+ ret = saa7164_cmd_send(dev, 0, GET_LEN,
+ GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n",
+ __func__, buflen);
+
+ /* Allocate enough storage for all of the descs */
+ buf = kzalloc(buflen, GFP_KERNEL);
+ if (!buf)
+ return SAA_ERR_NO_RESOURCES;
+
+ /* Retrieve them */
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_DESCRIPTORS_CONTROL, buflen, buf);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+ goto out;
+ }
+
+ if (saa_debug & DBGLVL_API)
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+ buflen & ~15, false);
+
+ saa7164_api_dump_subdevs(dev, buf, buflen);
+
+out:
+ kfree(buf);
+ return ret;
+}
+
+int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
+ u32 datalen, u8 *data)
+{
+ struct saa7164_dev *dev = bus->dev;
+ u16 len = 0;
+ int unitid;
+ u8 buf[256];
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ if (reglen > 4)
+ return -EIO;
+
+ /* Prepare the send buffer */
+ /* Bytes 00-03 source register length
+ * 04-07 source bytes to read
+ * 08... register address
+ */
+ memset(buf, 0, sizeof(buf));
+ memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen);
+ *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
+ *((u32 *)(buf + 1 * sizeof(u32))) = datalen;
+
+ unitid = saa7164_i2caddr_to_unitid(bus, addr);
+ if (unitid < 0) {
+ printk(KERN_ERR
+ "%s() error, cannot translate regaddr 0x%x to unitid\n",
+ __func__, addr);
+ return -EIO;
+ }
+
+ ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
+ EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+ return -EIO;
+ }
+
+ dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
+
+ if (saa_debug & DBGLVL_I2C)
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+ 32, false);
+
+ ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
+ EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+ else {
+ if (saa_debug & DBGLVL_I2C)
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ buf, sizeof(buf), false);
+ memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
+ }
+
+ return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* For a given 8 bit i2c address device, write the buffer */
+int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
+ u8 *data)
+{
+ struct saa7164_dev *dev = bus->dev;
+ u16 len = 0;
+ int unitid;
+ int reglen;
+ u8 buf[256];
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ if ((datalen == 0) || (datalen > 232))
+ return -EIO;
+
+ memset(buf, 0, sizeof(buf));
+
+ unitid = saa7164_i2caddr_to_unitid(bus, addr);
+ if (unitid < 0) {
+ printk(KERN_ERR
+ "%s() error, cannot translate regaddr 0x%x to unitid\n",
+ __func__, addr);
+ return -EIO;
+ }
+
+ reglen = saa7164_i2caddr_to_reglen(bus, addr);
+ if (reglen < 0) {
+ printk(KERN_ERR
+ "%s() error, cannot translate regaddr to reglen\n",
+ __func__);
+ return -EIO;
+ }
+
+ ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
+ EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+ return -EIO;
+ }
+
+ dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
+
+ /* Prepare the send buffer */
+ /* Bytes 00-03 dest register length
+ * 04-07 dest bytes to write
+ * 08... register address
+ */
+ *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
+ *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen;
+ memcpy((buf + 2 * sizeof(u32)), data, datalen);
+
+ if (saa_debug & DBGLVL_I2C)
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ buf, sizeof(buf), false);
+
+ ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
+ EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+
+ return ret == SAA_OK ? 0 : -EIO;
+}
+
+int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
+ u8 pin, u8 state)
+{
+ int ret;
+ struct tmComResGPIO t;
+
+ dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
+ __func__, unitid, pin, state);
+
+ if ((pin > 7) || (state > 2))
+ return SAA_ERR_BAD_PARAMETER;
+
+ t.pin = pin;
+ t.state = state;
+
+ ret = saa7164_cmd_send(dev, unitid, SET_CUR,
+ EXU_GPIO_CONTROL, sizeof(t), &t);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid,
+ u8 pin)
+{
+ return saa7164_api_modify_gpio(dev, unitid, pin, 1);
+}
+
+int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
+ u8 pin)
+{
+ return saa7164_api_modify_gpio(dev, unitid, pin, 0);
+}
+
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c
index 66696fa8341d..66696fa8341d 100644
--- a/drivers/media/video/saa7164/saa7164-buffer.c
+++ b/drivers/media/pci/saa7164/saa7164-buffer.c
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c
index a7f58a998752..a7f58a998752 100644
--- a/drivers/media/video/saa7164/saa7164-bus.c
+++ b/drivers/media/pci/saa7164/saa7164-bus.c
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c
index 5b72da5ce418..5b72da5ce418 100644
--- a/drivers/media/video/saa7164/saa7164-cards.c
+++ b/drivers/media/pci/saa7164/saa7164-cards.c
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c
index 62fac7f9d04e..62fac7f9d04e 100644
--- a/drivers/media/video/saa7164/saa7164-cmd.c
+++ b/drivers/media/pci/saa7164/saa7164-cmd.c
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
new file mode 100644
index 000000000000..2c9ad878bef3
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -0,0 +1,1488 @@
+/*
+ * Driver for the NXP SAA7164 PCIe bridge
+ *
+ * Copyright (c) 2010 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 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/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+#include "saa7164.h"
+
+MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>");
+MODULE_LICENSE("GPL");
+
+/*
+ * 1 Basic
+ * 2
+ * 4 i2c
+ * 8 api
+ * 16 cmd
+ * 32 bus
+ */
+
+unsigned int saa_debug;
+module_param_named(debug, saa_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+unsigned int fw_debug;
+module_param(fw_debug, int, 0644);
+MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
+
+unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
+module_param(encoder_buffers, int, 0644);
+MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS;
+module_param(vbi_buffers, int, 0644);
+MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int waitsecs = 10;
+module_param(waitsecs, int, 0644);
+MODULE_PARM_DESC(waitsecs, "timeout on firmware messages");
+
+static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+unsigned int print_histogram = 64;
+module_param(print_histogram, int, 0644);
+MODULE_PARM_DESC(print_histogram, "print histogram values once");
+
+unsigned int crc_checking = 1;
+module_param(crc_checking, int, 0644);
+MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
+
+unsigned int guard_checking = 1;
+module_param(guard_checking, int, 0644);
+MODULE_PARM_DESC(guard_checking,
+ "enable dma sanity checking for buffer overruns");
+
+static unsigned int saa7164_devcount;
+
+static DEFINE_MUTEX(devlist);
+LIST_HEAD(saa7164_devlist);
+
+#define INT_SIZE 16
+
+static void saa7164_pack_verifier(struct saa7164_buffer *buf)
+{
+ u8 *p = (u8 *)buf->cpu;
+ int i;
+
+ for (i = 0; i < buf->actual_size; i += 2048) {
+
+ if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
+ (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
+ printk(KERN_ERR "No pack at 0x%x\n", i);
+#if 0
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ p + 1, 32, false);
+#endif
+ }
+ }
+}
+
+#define FIXED_VIDEO_PID 0xf1
+#define FIXED_AUDIO_PID 0xf2
+
+static void saa7164_ts_verifier(struct saa7164_buffer *buf)
+{
+ struct saa7164_port *port = buf->port;
+ u32 i;
+ u8 cc, a;
+ u16 pid;
+ u8 __iomem *bufcpu = (u8 *)buf->cpu;
+
+ port->sync_errors = 0;
+ port->v_cc_errors = 0;
+ port->a_cc_errors = 0;
+
+ for (i = 0; i < buf->actual_size; i += 188) {
+ if (*(bufcpu + i) != 0x47)
+ port->sync_errors++;
+
+ /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
+ pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
+ cc = *(bufcpu + i + 3) & 0x0f;
+
+ if (pid == FIXED_VIDEO_PID) {
+ a = ((port->last_v_cc + 1) & 0x0f);
+ if (a != cc) {
+ printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
+ port->last_v_cc, cc, i);
+ port->v_cc_errors++;
+ }
+
+ port->last_v_cc = cc;
+ } else
+ if (pid == FIXED_AUDIO_PID) {
+ a = ((port->last_a_cc + 1) & 0x0f);
+ if (a != cc) {
+ printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
+ port->last_a_cc, cc, i);
+ port->a_cc_errors++;
+ }
+
+ port->last_a_cc = cc;
+ }
+
+ }
+
+ /* Only report errors if we've been through this function atleast
+ * once already and the cached cc values are primed. First time through
+ * always generates errors.
+ */
+ if (port->v_cc_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
+
+ if (port->a_cc_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors);
+
+ if (port->sync_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "sync_errors = %d\n", port->sync_errors);
+
+ if (port->done_first_interrupt == 1)
+ port->done_first_interrupt++;
+}
+
+static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
+{
+ int i;
+
+ memset(hg, 0, sizeof(struct saa7164_histogram));
+ strcpy(hg->name, name);
+
+ /* First 30ms x 1ms */
+ for (i = 0; i < 30; i++)
+ hg->counter1[0 + i].val = i;
+
+ /* 30 - 200ms x 10ms */
+ for (i = 0; i < 18; i++)
+ hg->counter1[30 + i].val = 30 + (i * 10);
+
+ /* 200 - 2000ms x 100ms */
+ for (i = 0; i < 15; i++)
+ hg->counter1[48 + i].val = 200 + (i * 200);
+
+ /* Catch all massive value (2secs) */
+ hg->counter1[55].val = 2000;
+
+ /* Catch all massive value (4secs) */
+ hg->counter1[56].val = 4000;
+
+ /* Catch all massive value (8secs) */
+ hg->counter1[57].val = 8000;
+
+ /* Catch all massive value (15secs) */
+ hg->counter1[58].val = 15000;
+
+ /* Catch all massive value (30secs) */
+ hg->counter1[59].val = 30000;
+
+ /* Catch all massive value (60secs) */
+ hg->counter1[60].val = 60000;
+
+ /* Catch all massive value (5mins) */
+ hg->counter1[61].val = 300000;
+
+ /* Catch all massive value (15mins) */
+ hg->counter1[62].val = 900000;
+
+ /* Catch all massive values (1hr) */
+ hg->counter1[63].val = 3600000;
+}
+
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
+{
+ int i;
+ for (i = 0; i < 64; i++) {
+ if (val <= hg->counter1[i].val) {
+ hg->counter1[i].count++;
+ hg->counter1[i].update_time = jiffies;
+ break;
+ }
+ }
+}
+
+static void saa7164_histogram_print(struct saa7164_port *port,
+ struct saa7164_histogram *hg)
+{
+ u32 entries = 0;
+ int i;
+
+ printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name);
+ for (i = 0; i < 64; i++) {
+ if (hg->counter1[i].count == 0)
+ continue;
+
+ printk(KERN_ERR " %4d %12d %Ld\n",
+ hg->counter1[i].val,
+ hg->counter1[i].count,
+ hg->counter1[i].update_time);
+
+ entries++;
+ }
+ printk(KERN_ERR "Total: %d\n", entries);
+}
+
+static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf = NULL;
+ struct saa7164_user_buffer *ubuf = NULL;
+ struct list_head *c, *n;
+ int i = 0;
+ u8 __iomem *p;
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+
+ buf = list_entry(c, struct saa7164_buffer, list);
+ if (i++ > port->hwcfg.buffercount) {
+ printk(KERN_ERR "%s() illegal i count %d\n",
+ __func__, i);
+ break;
+ }
+
+ if (buf->idx == bufnr) {
+
+ /* Found the buffer, deal with it */
+ dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr);
+
+ if (crc_checking) {
+ /* Throw a new checksum on the dma buffer */
+ buf->crc = crc32(0, buf->cpu, buf->actual_size);
+ }
+
+ if (guard_checking) {
+ p = (u8 *)buf->cpu;
+ if ((*(p + buf->actual_size + 0) != 0xff) ||
+ (*(p + buf->actual_size + 1) != 0xff) ||
+ (*(p + buf->actual_size + 2) != 0xff) ||
+ (*(p + buf->actual_size + 3) != 0xff) ||
+ (*(p + buf->actual_size + 0x10) != 0xff) ||
+ (*(p + buf->actual_size + 0x11) != 0xff) ||
+ (*(p + buf->actual_size + 0x12) != 0xff) ||
+ (*(p + buf->actual_size + 0x13) != 0xff)) {
+ printk(KERN_ERR "%s() buf %p guard buffer breach\n",
+ __func__, buf);
+#if 0
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ p + buf->actual_size - 32, 64, false);
+#endif
+ }
+ }
+
+ if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) {
+ /* Validate the incoming buffer content */
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+ saa7164_ts_verifier(buf);
+ else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+ saa7164_pack_verifier(buf);
+ }
+
+ /* find a free user buffer and clone to it */
+ if (!list_empty(&port->list_buf_free.list)) {
+
+ /* Pull the first buffer from the used list */
+ ubuf = list_first_entry(&port->list_buf_free.list,
+ struct saa7164_user_buffer, list);
+
+ if (buf->actual_size <= ubuf->actual_size) {
+
+ memcpy_fromio(ubuf->data, buf->cpu,
+ ubuf->actual_size);
+
+ if (crc_checking) {
+ /* Throw a new checksum on the read buffer */
+ ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size);
+ }
+
+ /* Requeue the buffer on the free list */
+ ubuf->pos = 0;
+
+ list_move_tail(&ubuf->list,
+ &port->list_buf_used.list);
+
+ /* Flag any userland waiters */
+ wake_up_interruptible(&port->wait_read);
+
+ } else {
+ printk(KERN_ERR "buf %p bufsize fails match\n", buf);
+ }
+
+ } else
+ printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
+
+ /* Ensure offset into buffer remains 0, fill buffer
+ * with known bad data. We check for this data at a later point
+ * in time. */
+ saa7164_buffer_zero_offsets(port, bufnr);
+ memset_io(buf->cpu, 0xff, buf->pci_size);
+ if (crc_checking) {
+ /* Throw yet aanother new checksum on the dma buffer */
+ buf->crc = crc32(0, buf->cpu, buf->actual_size);
+ }
+
+ break;
+ }
+ }
+ mutex_unlock(&port->dmaqueue_lock);
+}
+
+static void saa7164_work_enchandler(struct work_struct *w)
+{
+ struct saa7164_port *port =
+ container_of(w, struct saa7164_port, workenc);
+ struct saa7164_dev *dev = port->dev;
+
+ u32 wp, mcb, rp, cnt = 0;
+
+ port->last_svc_msecs_diff = port->last_svc_msecs;
+ port->last_svc_msecs = jiffies_to_msecs(jiffies);
+
+ port->last_svc_msecs_diff = port->last_svc_msecs -
+ port->last_svc_msecs_diff;
+
+ saa7164_histogram_update(&port->svc_interval,
+ port->last_svc_msecs_diff);
+
+ port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+ port->last_irq_msecs;
+
+ saa7164_histogram_update(&port->irq_svc_interval,
+ port->last_irq_svc_msecs_diff);
+
+ dprintk(DBGLVL_IRQ,
+ "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+ __func__,
+ port->last_svc_msecs_diff,
+ port->last_irq_svc_msecs_diff,
+ port->last_svc_wp,
+ port->last_svc_rp
+ );
+
+ /* Current write position */
+ wp = saa7164_readl(port->bufcounter);
+ if (wp > (port->hwcfg.buffercount - 1)) {
+ printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+ return;
+ }
+
+ /* Most current complete buffer */
+ if (wp == 0)
+ mcb = (port->hwcfg.buffercount - 1);
+ else
+ mcb = wp - 1;
+
+ while (1) {
+ if (port->done_first_interrupt == 0) {
+ port->done_first_interrupt++;
+ rp = mcb;
+ } else
+ rp = (port->last_svc_rp + 1) % 8;
+
+ if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+ printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+ break;
+ }
+
+ saa7164_work_enchandler_helper(port, rp);
+ port->last_svc_rp = rp;
+ cnt++;
+
+ if (rp == mcb)
+ break;
+ }
+
+ /* TODO: Convert this into a /proc/saa7164 style readable file */
+ if (print_histogram == port->nr) {
+ saa7164_histogram_print(port, &port->irq_interval);
+ saa7164_histogram_print(port, &port->svc_interval);
+ saa7164_histogram_print(port, &port->irq_svc_interval);
+ saa7164_histogram_print(port, &port->read_interval);
+ saa7164_histogram_print(port, &port->poll_interval);
+ /* TODO: fix this to preserve any previous state */
+ print_histogram = 64 + port->nr;
+ }
+}
+
+static void saa7164_work_vbihandler(struct work_struct *w)
+{
+ struct saa7164_port *port =
+ container_of(w, struct saa7164_port, workenc);
+ struct saa7164_dev *dev = port->dev;
+
+ u32 wp, mcb, rp, cnt = 0;
+
+ port->last_svc_msecs_diff = port->last_svc_msecs;
+ port->last_svc_msecs = jiffies_to_msecs(jiffies);
+ port->last_svc_msecs_diff = port->last_svc_msecs -
+ port->last_svc_msecs_diff;
+
+ saa7164_histogram_update(&port->svc_interval,
+ port->last_svc_msecs_diff);
+
+ port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+ port->last_irq_msecs;
+
+ saa7164_histogram_update(&port->irq_svc_interval,
+ port->last_irq_svc_msecs_diff);
+
+ dprintk(DBGLVL_IRQ,
+ "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+ __func__,
+ port->last_svc_msecs_diff,
+ port->last_irq_svc_msecs_diff,
+ port->last_svc_wp,
+ port->last_svc_rp
+ );
+
+ /* Current write position */
+ wp = saa7164_readl(port->bufcounter);
+ if (wp > (port->hwcfg.buffercount - 1)) {
+ printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+ return;
+ }
+
+ /* Most current complete buffer */
+ if (wp == 0)
+ mcb = (port->hwcfg.buffercount - 1);
+ else
+ mcb = wp - 1;
+
+ while (1) {
+ if (port->done_first_interrupt == 0) {
+ port->done_first_interrupt++;
+ rp = mcb;
+ } else
+ rp = (port->last_svc_rp + 1) % 8;
+
+ if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+ printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+ break;
+ }
+
+ saa7164_work_enchandler_helper(port, rp);
+ port->last_svc_rp = rp;
+ cnt++;
+
+ if (rp == mcb)
+ break;
+ }
+
+ /* TODO: Convert this into a /proc/saa7164 style readable file */
+ if (print_histogram == port->nr) {
+ saa7164_histogram_print(port, &port->irq_interval);
+ saa7164_histogram_print(port, &port->svc_interval);
+ saa7164_histogram_print(port, &port->irq_svc_interval);
+ saa7164_histogram_print(port, &port->read_interval);
+ saa7164_histogram_print(port, &port->poll_interval);
+ /* TODO: fix this to preserve any previous state */
+ print_histogram = 64 + port->nr;
+ }
+}
+
+static void saa7164_work_cmdhandler(struct work_struct *w)
+{
+ struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
+
+ /* Wake up any complete commands */
+ saa7164_irq_dequeue(dev);
+}
+
+static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
+{
+ struct saa7164_port *port = buf->port;
+
+ /* Feed the transport payload into the kernel demux */
+ dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
+ SAA7164_TS_NUMBER_OF_LINES);
+
+}
+
+static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ /* Store old time */
+ port->last_irq_msecs_diff = port->last_irq_msecs;
+
+ /* Collect new stats */
+ port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+ /* Calculate stats */
+ port->last_irq_msecs_diff = port->last_irq_msecs -
+ port->last_irq_msecs_diff;
+
+ saa7164_histogram_update(&port->irq_interval,
+ port->last_irq_msecs_diff);
+
+ dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+ port->last_irq_msecs_diff);
+
+ /* Tis calls the vbi irq handler */
+ schedule_work(&port->workenc);
+ return 0;
+}
+
+static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ /* Store old time */
+ port->last_irq_msecs_diff = port->last_irq_msecs;
+
+ /* Collect new stats */
+ port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+ /* Calculate stats */
+ port->last_irq_msecs_diff = port->last_irq_msecs -
+ port->last_irq_msecs_diff;
+
+ saa7164_histogram_update(&port->irq_interval,
+ port->last_irq_msecs_diff);
+
+ dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+ port->last_irq_msecs_diff);
+
+ schedule_work(&port->workenc);
+ return 0;
+}
+
+static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct list_head *c, *n;
+ int wp, i = 0, rp;
+
+ /* Find the current write point from the hardware */
+ wp = saa7164_readl(port->bufcounter);
+ if (wp > (port->hwcfg.buffercount - 1))
+ BUG();
+
+ /* Find the previous buffer to the current write point */
+ if (wp == 0)
+ rp = (port->hwcfg.buffercount - 1);
+ else
+ rp = wp - 1;
+
+ /* Lookup the WP in the buffer list */
+ /* TODO: turn this into a worker thread */
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ if (i++ > port->hwcfg.buffercount)
+ BUG();
+
+ if (buf->idx == rp) {
+ /* Found the buffer, deal with it */
+ dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
+ __func__, wp, rp);
+ saa7164_buffer_deliver(buf);
+ break;
+ }
+
+ }
+ return 0;
+}
+
+/* Primary IRQ handler and dispatch mechanism */
+static irqreturn_t saa7164_irq(int irq, void *dev_id)
+{
+ struct saa7164_dev *dev = dev_id;
+ struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
+ struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
+ struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
+ struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
+ struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
+ struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
+
+ u32 intid, intstat[INT_SIZE/4];
+ int i, handled = 0, bit;
+
+ if (dev == NULL) {
+ printk(KERN_ERR "%s() No device specified\n", __func__);
+ handled = 0;
+ goto out;
+ }
+
+ /* Check that the hardware is accessible. If the status bytes are
+ * 0xFF then the device is not accessible, the the IRQ belongs
+ * to another driver.
+ * 4 x u32 interrupt registers.
+ */
+ for (i = 0; i < INT_SIZE/4; i++) {
+
+ /* TODO: Convert into saa7164_readl() */
+ /* Read the 4 hardware interrupt registers */
+ intstat[i] = saa7164_readl(dev->int_status + (i * 4));
+
+ if (intstat[i])
+ handled = 1;
+ }
+ if (handled == 0)
+ goto out;
+
+ /* For each of the HW interrupt registers */
+ for (i = 0; i < INT_SIZE/4; i++) {
+
+ if (intstat[i]) {
+ /* Each function of the board has it's own interruptid.
+ * Find the function that triggered then call
+ * it's handler.
+ */
+ for (bit = 0; bit < 32; bit++) {
+
+ if (((intstat[i] >> bit) & 0x00000001) == 0)
+ continue;
+
+ /* Calculate the interrupt id (0x00 to 0x7f) */
+
+ intid = (i * 32) + bit;
+ if (intid == dev->intfdesc.bInterruptId) {
+ /* A response to an cmd/api call */
+ schedule_work(&dev->workcmd);
+ } else if (intid == porta->hwcfg.interruptid) {
+
+ /* Transport path 1 */
+ saa7164_irq_ts(porta);
+
+ } else if (intid == portb->hwcfg.interruptid) {
+
+ /* Transport path 2 */
+ saa7164_irq_ts(portb);
+
+ } else if (intid == portc->hwcfg.interruptid) {
+
+ /* Encoder path 1 */
+ saa7164_irq_encoder(portc);
+
+ } else if (intid == portd->hwcfg.interruptid) {
+
+ /* Encoder path 2 */
+ saa7164_irq_encoder(portd);
+
+ } else if (intid == porte->hwcfg.interruptid) {
+
+ /* VBI path 1 */
+ saa7164_irq_vbi(porte);
+
+ } else if (intid == portf->hwcfg.interruptid) {
+
+ /* VBI path 2 */
+ saa7164_irq_vbi(portf);
+
+ } else {
+ /* Find the function */
+ dprintk(DBGLVL_IRQ,
+ "%s() unhandled interrupt "
+ "reg 0x%x bit 0x%x "
+ "intid = 0x%x\n",
+ __func__, i, bit, intid);
+ }
+ }
+
+ /* Ack it */
+ saa7164_writel(dev->int_ack + (i * 4), intstat[i]);
+
+ }
+ }
+out:
+ return IRQ_RETVAL(handled);
+}
+
+void saa7164_getfirmwarestatus(struct saa7164_dev *dev)
+{
+ struct saa7164_fw_status *s = &dev->fw_status;
+
+ dev->fw_status.status = saa7164_readl(SAA_DEVICE_SYSINIT_STATUS);
+ dev->fw_status.mode = saa7164_readl(SAA_DEVICE_SYSINIT_MODE);
+ dev->fw_status.spec = saa7164_readl(SAA_DEVICE_SYSINIT_SPEC);
+ dev->fw_status.inst = saa7164_readl(SAA_DEVICE_SYSINIT_INST);
+ dev->fw_status.cpuload = saa7164_readl(SAA_DEVICE_SYSINIT_CPULOAD);
+ dev->fw_status.remainheap =
+ saa7164_readl(SAA_DEVICE_SYSINIT_REMAINHEAP);
+
+ dprintk(1, "Firmware status:\n");
+ dprintk(1, " .status = 0x%08x\n", s->status);
+ dprintk(1, " .mode = 0x%08x\n", s->mode);
+ dprintk(1, " .spec = 0x%08x\n", s->spec);
+ dprintk(1, " .inst = 0x%08x\n", s->inst);
+ dprintk(1, " .cpuload = 0x%08x\n", s->cpuload);
+ dprintk(1, " .remainheap = 0x%08x\n", s->remainheap);
+}
+
+u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev)
+{
+ u32 reg;
+
+ reg = saa7164_readl(SAA_DEVICE_VERSION);
+ dprintk(1, "Device running firmware version %d.%d.%d.%d (0x%x)\n",
+ (reg & 0x0000fc00) >> 10,
+ (reg & 0x000003e0) >> 5,
+ (reg & 0x0000001f),
+ (reg & 0xffff0000) >> 16,
+ reg);
+
+ return reg;
+}
+
+/* TODO: Debugging func, remove */
+void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
+{
+ int i;
+
+ dprintk(1, "--------------------> "
+ "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+
+ for (i = 0; i < 0x100; i += 16)
+ dprintk(1, "region0[0x%08x] = "
+ "%02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+ (u8)saa7164_readb(addr + i + 0),
+ (u8)saa7164_readb(addr + i + 1),
+ (u8)saa7164_readb(addr + i + 2),
+ (u8)saa7164_readb(addr + i + 3),
+ (u8)saa7164_readb(addr + i + 4),
+ (u8)saa7164_readb(addr + i + 5),
+ (u8)saa7164_readb(addr + i + 6),
+ (u8)saa7164_readb(addr + i + 7),
+ (u8)saa7164_readb(addr + i + 8),
+ (u8)saa7164_readb(addr + i + 9),
+ (u8)saa7164_readb(addr + i + 10),
+ (u8)saa7164_readb(addr + i + 11),
+ (u8)saa7164_readb(addr + i + 12),
+ (u8)saa7164_readb(addr + i + 13),
+ (u8)saa7164_readb(addr + i + 14),
+ (u8)saa7164_readb(addr + i + 15)
+ );
+}
+
+static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
+{
+ dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
+ &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr));
+
+ dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength);
+ dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType);
+ dprintk(1, " .bDescriptorSubtype = 0x%x\n",
+ dev->hwdesc.bDescriptorSubtype);
+
+ dprintk(1, " .bcdSpecVersion = 0x%x\n", dev->hwdesc.bcdSpecVersion);
+ dprintk(1, " .dwClockFrequency = 0x%x\n", dev->hwdesc.dwClockFrequency);
+ dprintk(1, " .dwClockUpdateRes = 0x%x\n", dev->hwdesc.dwClockUpdateRes);
+ dprintk(1, " .bCapabilities = 0x%x\n", dev->hwdesc.bCapabilities);
+ dprintk(1, " .dwDeviceRegistersLocation = 0x%x\n",
+ dev->hwdesc.dwDeviceRegistersLocation);
+
+ dprintk(1, " .dwHostMemoryRegion = 0x%x\n",
+ dev->hwdesc.dwHostMemoryRegion);
+
+ dprintk(1, " .dwHostMemoryRegionSize = 0x%x\n",
+ dev->hwdesc.dwHostMemoryRegionSize);
+
+ dprintk(1, " .dwHostHibernatMemRegion = 0x%x\n",
+ dev->hwdesc.dwHostHibernatMemRegion);
+
+ dprintk(1, " .dwHostHibernatMemRegionSize = 0x%x\n",
+ dev->hwdesc.dwHostHibernatMemRegionSize);
+}
+
+static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
+{
+ dprintk(1, "@0x%p intfdesc "
+ "sizeof(struct tmComResInterfaceDescr) = %d bytes\n",
+ &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr));
+
+ dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength);
+ dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType);
+ dprintk(1, " .bDescriptorSubtype = 0x%x\n",
+ dev->intfdesc.bDescriptorSubtype);
+
+ dprintk(1, " .bFlags = 0x%x\n", dev->intfdesc.bFlags);
+ dprintk(1, " .bInterfaceType = 0x%x\n", dev->intfdesc.bInterfaceType);
+ dprintk(1, " .bInterfaceId = 0x%x\n", dev->intfdesc.bInterfaceId);
+ dprintk(1, " .bBaseInterface = 0x%x\n", dev->intfdesc.bBaseInterface);
+ dprintk(1, " .bInterruptId = 0x%x\n", dev->intfdesc.bInterruptId);
+ dprintk(1, " .bDebugInterruptId = 0x%x\n",
+ dev->intfdesc.bDebugInterruptId);
+
+ dprintk(1, " .BARLocation = 0x%x\n", dev->intfdesc.BARLocation);
+}
+
+static void saa7164_dump_busdesc(struct saa7164_dev *dev)
+{
+ dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n",
+ &dev->busdesc, (u32)sizeof(struct tmComResBusDescr));
+
+ dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing);
+ dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing);
+ dprintk(1, " .CommandWrite = 0x%x\n", dev->busdesc.CommandWrite);
+ dprintk(1, " .CommandRead = 0x%x\n", dev->busdesc.CommandRead);
+ dprintk(1, " .ResponseWrite = 0x%x\n", dev->busdesc.ResponseWrite);
+ dprintk(1, " .ResponseRead = 0x%x\n", dev->busdesc.ResponseRead);
+}
+
+/* Much of the hardware configuration and PCI registers are configured
+ * dynamically depending on firmware. We have to cache some initial
+ * structures then use these to locate other important structures
+ * from PCI space.
+ */
+static void saa7164_get_descriptors(struct saa7164_dev *dev)
+{
+ memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
+ memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr),
+ sizeof(struct tmComResInterfaceDescr));
+ memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
+ sizeof(struct tmComResBusDescr));
+
+ if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) {
+ printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n");
+ printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength,
+ (u32)sizeof(struct tmComResHWDescr));
+ } else
+ saa7164_dump_hwdesc(dev);
+
+ if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
+ printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
+ printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
+ (u32)sizeof(struct tmComResInterfaceDescr));
+ } else
+ saa7164_dump_intfdesc(dev);
+
+ saa7164_dump_busdesc(dev);
+}
+
+static int saa7164_pci_quirks(struct saa7164_dev *dev)
+{
+ return 0;
+}
+
+static int get_resources(struct saa7164_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, 2),
+ pci_resource_len(dev->pci, 2), dev->name))
+ return 0;
+ }
+
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n",
+ dev->name,
+ (u64)pci_resource_start(dev->pci, 0),
+ (u64)pci_resource_start(dev->pci, 2));
+
+ return -EBUSY;
+}
+
+static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
+{
+ struct saa7164_port *port = NULL;
+
+ if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
+ BUG();
+
+ port = &dev->ports[portnr];
+
+ port->dev = dev;
+ port->nr = portnr;
+
+ if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2))
+ port->type = SAA7164_MPEG_DVB;
+ else
+ if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) {
+ port->type = SAA7164_MPEG_ENCODER;
+
+ /* We need a deferred interrupt handler for cmd handling */
+ INIT_WORK(&port->workenc, saa7164_work_enchandler);
+ } else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
+ port->type = SAA7164_MPEG_VBI;
+
+ /* We need a deferred interrupt handler for cmd handling */
+ INIT_WORK(&port->workenc, saa7164_work_vbihandler);
+ } else
+ BUG();
+
+ /* Init all the critical resources */
+ mutex_init(&port->dvb.lock);
+ INIT_LIST_HEAD(&port->dmaqueue.list);
+ mutex_init(&port->dmaqueue_lock);
+
+ INIT_LIST_HEAD(&port->list_buf_used.list);
+ INIT_LIST_HEAD(&port->list_buf_free.list);
+ init_waitqueue_head(&port->wait_read);
+
+
+ saa7164_histogram_reset(&port->irq_interval, "irq intervals");
+ saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
+ saa7164_histogram_reset(&port->irq_svc_interval,
+ "irq to deferred intervals");
+ saa7164_histogram_reset(&port->read_interval,
+ "encoder/vbi read() intervals");
+ saa7164_histogram_reset(&port->poll_interval,
+ "encoder/vbi poll() intervals");
+
+ return 0;
+}
+
+static int saa7164_dev_setup(struct saa7164_dev *dev)
+{
+ int i;
+
+ mutex_init(&dev->lock);
+ atomic_inc(&dev->refcount);
+ dev->nr = saa7164_devcount++;
+
+ snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
+
+ mutex_lock(&devlist);
+ list_add_tail(&dev->devlist, &saa7164_devlist);
+ mutex_unlock(&devlist);
+
+ /* board config */
+ dev->board = UNSET;
+ if (card[dev->nr] < saa7164_bcount)
+ dev->board = card[dev->nr];
+
+ for (i = 0; UNSET == dev->board && i < saa7164_idcount; i++)
+ if (dev->pci->subsystem_vendor == saa7164_subids[i].subvendor &&
+ dev->pci->subsystem_device ==
+ saa7164_subids[i].subdevice)
+ dev->board = saa7164_subids[i].card;
+
+ if (UNSET == dev->board) {
+ dev->board = SAA7164_BOARD_UNKNOWN;
+ saa7164_card_list(dev);
+ }
+
+ dev->pci_bus = dev->pci->bus->number;
+ dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+
+ /* I2C Defaults / setup */
+ dev->i2c_bus[0].dev = dev;
+ dev->i2c_bus[0].nr = 0;
+ dev->i2c_bus[1].dev = dev;
+ dev->i2c_bus[1].nr = 1;
+ dev->i2c_bus[2].dev = dev;
+ dev->i2c_bus[2].nr = 2;
+
+ /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */
+ saa7164_port_init(dev, SAA7164_PORT_TS1);
+ saa7164_port_init(dev, SAA7164_PORT_TS2);
+ saa7164_port_init(dev, SAA7164_PORT_ENC1);
+ saa7164_port_init(dev, SAA7164_PORT_ENC2);
+ saa7164_port_init(dev, SAA7164_PORT_VBI1);
+ saa7164_port_init(dev, SAA7164_PORT_VBI2);
+
+ if (get_resources(dev) < 0) {
+ printk(KERN_ERR "CORE %s No more PCIe resources for "
+ "subsystem: %04x:%04x\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device);
+
+ saa7164_devcount--;
+ return -ENODEV;
+ }
+
+ /* PCI/e allocations */
+ dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0));
+
+ dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2),
+ pci_resource_len(dev->pci, 2));
+
+ dev->bmmio = (u8 __iomem *)dev->lmmio;
+ dev->bmmio2 = (u8 __iomem *)dev->lmmio2;
+
+ /* Inerrupt and ack register locations offset of bmmio */
+ dev->int_status = 0x183000 + 0xf80;
+ dev->int_ack = 0x183000 + 0xf90;
+
+ printk(KERN_INFO
+ "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, saa7164_boards[dev->board].name,
+ dev->board, card[dev->nr] == dev->board ?
+ "insmod option" : "autodetected");
+
+ saa7164_pci_quirks(dev);
+
+ return 0;
+}
+
+static void saa7164_dev_unregister(struct saa7164_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ release_mem_region(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0));
+
+ release_mem_region(pci_resource_start(dev->pci, 2),
+ pci_resource_len(dev->pci, 2));
+
+ if (!atomic_dec_and_test(&dev->refcount))
+ return;
+
+ iounmap(dev->lmmio);
+ iounmap(dev->lmmio2);
+
+ return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int saa7164_proc_show(struct seq_file *m, void *v)
+{
+ struct saa7164_dev *dev;
+ struct tmComResBusInfo *b;
+ struct list_head *list;
+ int i, c;
+
+ if (saa7164_devcount == 0)
+ return 0;
+
+ list_for_each(list, &saa7164_devlist) {
+ dev = list_entry(list, struct saa7164_dev, devlist);
+ seq_printf(m, "%s = %p\n", dev->name, dev);
+
+ /* Lock the bus from any other access */
+ b = &dev->bus;
+ mutex_lock(&b->lock);
+
+ seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+ seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+ seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+ seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+ c = 0;
+ seq_printf(m, "\n Set Ring:\n");
+ seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+ for (i = 0; i < b->m_dwSizeSetRing; i++) {
+ if (c == 0)
+ seq_printf(m, " %04x:", i);
+
+ seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+
+ if (++c == 16) {
+ seq_printf(m, "\n");
+ c = 0;
+ }
+ }
+
+ c = 0;
+ seq_printf(m, "\n Get Ring:\n");
+ seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+ for (i = 0; i < b->m_dwSizeGetRing; i++) {
+ if (c == 0)
+ seq_printf(m, " %04x:", i);
+
+ seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+
+ if (++c == 16) {
+ seq_printf(m, "\n");
+ c = 0;
+ }
+ }
+
+ mutex_unlock(&b->lock);
+
+ }
+
+ return 0;
+}
+
+static int saa7164_proc_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, saa7164_proc_show, NULL);
+}
+
+static const struct file_operations saa7164_proc_fops = {
+ .open = saa7164_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int saa7164_proc_create(void)
+{
+ struct proc_dir_entry *pe;
+
+ pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops);
+ if (!pe)
+ return -ENOMEM;
+
+ return 0;
+}
+#endif
+
+static int saa7164_thread_function(void *data)
+{
+ struct saa7164_dev *dev = data;
+ struct tmFwInfoStruct fwinfo;
+ u64 last_poll_time = 0;
+
+ dprintk(DBGLVL_THR, "thread started\n");
+
+ set_freezable();
+
+ while (1) {
+ msleep_interruptible(100);
+ if (kthread_should_stop())
+ break;
+ try_to_freeze();
+
+ dprintk(DBGLVL_THR, "thread running\n");
+
+ /* Dump the firmware debug message to console */
+ /* Polling this costs us 1-2% of the arm CPU */
+ /* convert this into a respnde to interrupt 0x7a */
+ saa7164_api_collect_debug(dev);
+
+ /* Monitor CPU load every 1 second */
+ if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
+ saa7164_api_get_load_info(dev, &fwinfo);
+ last_poll_time = jiffies_to_msecs(jiffies);
+ }
+
+ }
+
+ dprintk(DBGLVL_THR, "thread exiting\n");
+ return 0;
+}
+
+static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct saa7164_dev *dev;
+ int err, i;
+ u32 version;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail_free;
+ }
+
+ if (saa7164_dev_setup(dev) < 0) {
+ err = -EINVAL;
+ goto fail_free;
+ }
+
+ /* print pci info */
+ dev->pci_rev = pci_dev->revision;
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%llx\n", dev->name,
+ pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat,
+ (unsigned long long)pci_resource_start(pci_dev, 0));
+
+ pci_set_master(pci_dev);
+ /* TODO */
+ if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+ err = -EIO;
+ goto fail_irq;
+ }
+
+ err = request_irq(pci_dev->irq, saa7164_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
+ pci_dev->irq);
+ err = -EIO;
+ goto fail_irq;
+ }
+
+ pci_set_drvdata(pci_dev, dev);
+
+ /* Init the internal command list */
+ for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
+ dev->cmds[i].seqno = i;
+ dev->cmds[i].inuse = 0;
+ mutex_init(&dev->cmds[i].lock);
+ init_waitqueue_head(&dev->cmds[i].wait);
+ }
+
+ /* We need a deferred interrupt handler for cmd handling */
+ INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler);
+
+ /* Only load the firmware if we know the board */
+ if (dev->board != SAA7164_BOARD_UNKNOWN) {
+
+ err = saa7164_downloadfirmware(dev);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Failed to boot firmware, no features "
+ "registered\n");
+ goto fail_fw;
+ }
+
+ saa7164_get_descriptors(dev);
+ saa7164_dumpregs(dev, 0);
+ saa7164_getcurrentfirmwareversion(dev);
+ saa7164_getfirmwarestatus(dev);
+ err = saa7164_bus_setup(dev);
+ if (err < 0)
+ printk(KERN_ERR
+ "Failed to setup the bus, will continue\n");
+ saa7164_bus_dump(dev);
+
+ /* Ping the running firmware via the command bus and get the
+ * firmware version, this checks the bus is running OK.
+ */
+ version = 0;
+ if (saa7164_api_get_fw_version(dev, &version) == SAA_OK)
+ dprintk(1, "Bus is operating correctly using "
+ "version %d.%d.%d.%d (0x%x)\n",
+ (version & 0x0000fc00) >> 10,
+ (version & 0x000003e0) >> 5,
+ (version & 0x0000001f),
+ (version & 0xffff0000) >> 16,
+ version);
+ else
+ printk(KERN_ERR
+ "Failed to communicate with the firmware\n");
+
+ /* Bring up the I2C buses */
+ saa7164_i2c_register(&dev->i2c_bus[0]);
+ saa7164_i2c_register(&dev->i2c_bus[1]);
+ saa7164_i2c_register(&dev->i2c_bus[2]);
+ saa7164_gpio_setup(dev);
+ saa7164_card_setup(dev);
+
+ /* Parse the dynamic device configuration, find various
+ * media endpoints (MPEG, WMV, PS, TS) and cache their
+ * configuration details into the driver, so we can
+ * reference them later during simething_register() func,
+ * interrupt handlers, deferred work handlers etc.
+ */
+ saa7164_api_enum_subdevs(dev);
+
+ /* Begin to create the video sub-systems and register funcs */
+ if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) {
+ if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
+ printk(KERN_ERR "%s() Failed to register "
+ "dvb adapters on porta\n",
+ __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) {
+ if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "dvb adapters on portb\n",
+ __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) {
+ if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "mpeg encoder\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) {
+ if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "mpeg encoder\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) {
+ if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "vbi device\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) {
+ if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "vbi device\n", __func__);
+ }
+ }
+ saa7164_api_set_debug(dev, fw_debug);
+
+ if (fw_debug) {
+ dev->kthread = kthread_run(saa7164_thread_function, dev,
+ "saa7164 debug");
+ if (!dev->kthread)
+ printk(KERN_ERR "%s() Failed to create "
+ "debug kernel thread\n", __func__);
+ }
+
+ } /* != BOARD_UNKNOWN */
+ else
+ printk(KERN_ERR "%s() Unsupported board detected, "
+ "registering without firmware\n", __func__);
+
+ dprintk(1, "%s() parameter debug = %d\n", __func__, saa_debug);
+ dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs);
+
+fail_fw:
+ return 0;
+
+fail_irq:
+ saa7164_dev_unregister(dev);
+fail_free:
+ kfree(dev);
+ return err;
+}
+
+static void saa7164_shutdown(struct saa7164_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+}
+
+static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
+{
+ struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
+
+ if (dev->board != SAA7164_BOARD_UNKNOWN) {
+ if (fw_debug && dev->kthread) {
+ kthread_stop(dev->kthread);
+ dev->kthread = NULL;
+ }
+ if (dev->firmwareloaded)
+ saa7164_api_set_debug(dev, 0x00);
+ }
+
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].irq_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].svc_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].read_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].poll_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1],
+ &dev->ports[SAA7164_PORT_VBI1].read_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2],
+ &dev->ports[SAA7164_PORT_VBI2].poll_interval);
+
+ saa7164_shutdown(dev);
+
+ if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
+ saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]);
+
+ if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB)
+ saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]);
+
+ if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER)
+ saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]);
+
+ if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER)
+ saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]);
+
+ if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI)
+ saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]);
+
+ if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI)
+ saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]);
+
+ saa7164_i2c_unregister(&dev->i2c_bus[0]);
+ saa7164_i2c_unregister(&dev->i2c_bus[1]);
+ saa7164_i2c_unregister(&dev->i2c_bus[2]);
+
+ pci_disable_device(pci_dev);
+
+ /* unregister stuff */
+ free_irq(pci_dev->irq, dev);
+ pci_set_drvdata(pci_dev, NULL);
+
+ mutex_lock(&devlist);
+ list_del(&dev->devlist);
+ mutex_unlock(&devlist);
+
+ saa7164_dev_unregister(dev);
+ kfree(dev);
+}
+
+static struct pci_device_id saa7164_pci_tbl[] = {
+ {
+ /* SAA7164 */
+ .vendor = 0x1131,
+ .device = 0x7164,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ }, {
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, saa7164_pci_tbl);
+
+static struct pci_driver saa7164_pci_driver = {
+ .name = "saa7164",
+ .id_table = saa7164_pci_tbl,
+ .probe = saa7164_initdev,
+ .remove = __devexit_p(saa7164_finidev),
+ /* TODO */
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+static int __init saa7164_init(void)
+{
+ printk(KERN_INFO "saa7164 driver loaded\n");
+
+#ifdef CONFIG_PROC_FS
+ saa7164_proc_create();
+#endif
+ return pci_register_driver(&saa7164_pci_driver);
+}
+
+static void __exit saa7164_fini(void)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("saa7164", NULL);
+#endif
+ pci_unregister_driver(&saa7164_pci_driver);
+}
+
+module_init(saa7164_init);
+module_exit(saa7164_fini);
+
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index 5c5cc3ebf9bd..5c5cc3ebf9bd 100644
--- a/drivers/media/video/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index a9ed686ad08a..a9ed686ad08a 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c
index a266bf0169e6..a266bf0169e6 100644
--- a/drivers/media/video/saa7164/saa7164-fw.c
+++ b/drivers/media/pci/saa7164/saa7164-fw.c
diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c
index 4f7e3b42263f..4f7e3b42263f 100644
--- a/drivers/media/video/saa7164/saa7164-i2c.c
+++ b/drivers/media/pci/saa7164/saa7164-i2c.c
diff --git a/drivers/media/video/saa7164/saa7164-reg.h b/drivers/media/pci/saa7164/saa7164-reg.h
index 2bbf81583d33..2bbf81583d33 100644
--- a/drivers/media/video/saa7164/saa7164-reg.h
+++ b/drivers/media/pci/saa7164/saa7164-reg.h
diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h
index 1d2140a3eb38..1d2140a3eb38 100644
--- a/drivers/media/video/saa7164/saa7164-types.h
+++ b/drivers/media/pci/saa7164/saa7164-types.h
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index d8e6c8f14079..d8e6c8f14079 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
new file mode 100644
index 000000000000..437284e747c9
--- /dev/null
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -0,0 +1,616 @@
+/*
+ * Driver for the NXP SAA7164 PCIe bridge
+ *
+ * Copyright (c) 2010 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 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.
+ */
+
+/*
+ Driver architecture
+ *******************
+
+ saa7164_core.c/buffer.c/cards.c/i2c.c/dvb.c
+ | : Standard Linux driver framework for creating
+ | : exposing and managing interfaces to the rest
+ | : of the kernel or userland. Also uses _fw.c to load
+ | : firmware direct into the PCIe bus, bypassing layers.
+ V
+ saa7164_api..() : Translate kernel specific functions/features
+ | : into command buffers.
+ V
+ saa7164_cmd..() : Manages the flow of command packets on/off,
+ | : the bus. Deal with bus errors, timeouts etc.
+ V
+ saa7164_bus..() : Manage a read/write memory ring buffer in the
+ | : PCIe Address space.
+ |
+ | saa7164_fw...() : Load any frimware
+ | | : direct into the device
+ V V
+ <- ----------------- PCIe address space -------------------- ->
+*/
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/kdev_t.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "saa7164-reg.h"
+#include "saa7164-types.h"
+
+#define SAA7164_MAXBOARDS 8
+
+#define UNSET (-1U)
+#define SAA7164_BOARD_NOAUTO UNSET
+#define SAA7164_BOARD_UNKNOWN 0
+#define SAA7164_BOARD_UNKNOWN_REV2 1
+#define SAA7164_BOARD_UNKNOWN_REV3 2
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250 3
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200 4
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_2 5
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7
+#define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9
+#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10
+
+#define SAA7164_MAX_UNITS 8
+#define SAA7164_TS_NUMBER_OF_LINES 312
+#define SAA7164_PS_NUMBER_OF_LINES 256
+#define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */
+#define SAA7164_MAX_ENCODER_BUFFERS 64 /* max 5secs of latency at 6Mbps */
+#define SAA7164_MAX_VBI_BUFFERS 64
+
+/* Port related defines */
+#define SAA7164_PORT_TS1 (0)
+#define SAA7164_PORT_TS2 (SAA7164_PORT_TS1 + 1)
+#define SAA7164_PORT_ENC1 (SAA7164_PORT_TS2 + 1)
+#define SAA7164_PORT_ENC2 (SAA7164_PORT_ENC1 + 1)
+#define SAA7164_PORT_VBI1 (SAA7164_PORT_ENC2 + 1)
+#define SAA7164_PORT_VBI2 (SAA7164_PORT_VBI1 + 1)
+#define SAA7164_MAX_PORTS (SAA7164_PORT_VBI2 + 1)
+
+#define DBGLVL_FW 4
+#define DBGLVL_DVB 8
+#define DBGLVL_I2C 16
+#define DBGLVL_API 32
+#define DBGLVL_CMD 64
+#define DBGLVL_BUS 128
+#define DBGLVL_IRQ 256
+#define DBGLVL_BUF 512
+#define DBGLVL_ENC 1024
+#define DBGLVL_VBI 2048
+#define DBGLVL_THR 4096
+#define DBGLVL_CPU 8192
+
+#define SAA7164_NORMS \
+ (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443)
+
+enum port_t {
+ SAA7164_MPEG_UNDEFINED = 0,
+ SAA7164_MPEG_DVB,
+ SAA7164_MPEG_ENCODER,
+ SAA7164_MPEG_VBI,
+};
+
+enum saa7164_i2c_bus_nr {
+ SAA7164_I2C_BUS_0 = 0,
+ SAA7164_I2C_BUS_1,
+ SAA7164_I2C_BUS_2,
+};
+
+enum saa7164_buffer_flags {
+ SAA7164_BUFFER_UNDEFINED = 0,
+ SAA7164_BUFFER_FREE,
+ SAA7164_BUFFER_BUSY,
+ SAA7164_BUFFER_FULL
+};
+
+enum saa7164_unit_type {
+ SAA7164_UNIT_UNDEFINED = 0,
+ SAA7164_UNIT_DIGITAL_DEMODULATOR,
+ SAA7164_UNIT_ANALOG_DEMODULATOR,
+ SAA7164_UNIT_TUNER,
+ SAA7164_UNIT_EEPROM,
+ SAA7164_UNIT_ZILOG_IRBLASTER,
+ SAA7164_UNIT_ENCODER,
+};
+
+/* The PCIe bridge doesn't grant direct access to i2c.
+ * Instead, you address i2c devices using a uniqely
+ * allocated 'unitid' value via a messaging API. This
+ * is a problem. The kernel and existing demod/tuner
+ * drivers expect to talk 'i2c', so we have to maintain
+ * a translation layer, and a series of functions to
+ * convert i2c bus + device address into a unit id.
+ */
+struct saa7164_unit {
+ enum saa7164_unit_type type;
+ u8 id;
+ char *name;
+ enum saa7164_i2c_bus_nr i2c_bus_nr;
+ u8 i2c_bus_addr;
+ u8 i2c_reg_len;
+};
+
+struct saa7164_board {
+ char *name;
+ enum port_t porta, portb, portc,
+ portd, porte, portf;
+ enum {
+ SAA7164_CHIP_UNDEFINED = 0,
+ SAA7164_CHIP_REV2,
+ SAA7164_CHIP_REV3,
+ } chiprev;
+ struct saa7164_unit unit[SAA7164_MAX_UNITS];
+};
+
+struct saa7164_subid {
+ u16 subvendor;
+ u16 subdevice;
+ u32 card;
+};
+
+struct saa7164_encoder_fh {
+ struct saa7164_port *port;
+ atomic_t v4l_reading;
+};
+
+struct saa7164_vbi_fh {
+ struct saa7164_port *port;
+ atomic_t v4l_reading;
+};
+
+struct saa7164_histogram_bucket {
+ u32 val;
+ u32 count;
+ u64 update_time;
+};
+
+struct saa7164_histogram {
+ char name[32];
+ struct saa7164_histogram_bucket counter1[64];
+};
+
+struct saa7164_user_buffer {
+ struct list_head list;
+
+ /* Attributes */
+ u8 *data;
+ u32 pos;
+ u32 actual_size;
+
+ u32 crc;
+};
+
+struct saa7164_fw_status {
+
+ /* RISC Core details */
+ u32 status;
+ u32 mode;
+ u32 spec;
+ u32 inst;
+ u32 cpuload;
+ u32 remainheap;
+
+ /* Firmware version */
+ u32 version;
+ u32 major;
+ u32 sub;
+ u32 rel;
+ u32 buildnr;
+};
+
+struct saa7164_dvb {
+ struct mutex lock;
+ struct dvb_adapter adapter;
+ struct dvb_frontend *frontend;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+ int feeding;
+};
+
+struct saa7164_i2c {
+ struct saa7164_dev *dev;
+
+ enum saa7164_i2c_bus_nr nr;
+
+ /* I2C I/O */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+};
+
+struct saa7164_ctrl {
+ struct v4l2_queryctrl v;
+};
+
+struct saa7164_tvnorm {
+ char *name;
+ v4l2_std_id id;
+};
+
+struct saa7164_encoder_params {
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 is_50hz;
+ u32 bitrate; /* bps */
+ u32 bitrate_peak; /* bps */
+ u32 bitrate_mode;
+ u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+ u32 audio_sampling_freq;
+ u32 ctl_mute;
+ u32 ctl_aspect;
+ u32 refdist;
+ u32 gop_size;
+};
+
+struct saa7164_vbi_params {
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 is_50hz;
+ u32 bitrate; /* bps */
+ u32 bitrate_peak; /* bps */
+ u32 bitrate_mode;
+ u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+ u32 audio_sampling_freq;
+ u32 ctl_mute;
+ u32 ctl_aspect;
+ u32 refdist;
+ u32 gop_size;
+};
+
+struct saa7164_port;
+
+struct saa7164_buffer {
+ struct list_head list;
+
+ /* Note of which h/w buffer list index position we occupy */
+ int idx;
+
+ struct saa7164_port *port;
+
+ /* Hardware Specific */
+ /* PCI Memory allocations */
+ enum saa7164_buffer_flags flags; /* Free, Busy, Full */
+
+ /* A block of page align PCI memory */
+ u32 pci_size; /* PCI allocation size in bytes */
+ u64 __iomem *cpu; /* Virtual address */
+ dma_addr_t dma; /* Physical address */
+ u32 crc; /* Checksum for the entire buffer data */
+
+ /* A page table that splits the block into a number of entries */
+ u32 pt_size; /* PCI allocation size in bytes */
+ u64 __iomem *pt_cpu; /* Virtual address */
+ dma_addr_t pt_dma; /* Physical address */
+
+ /* Encoder fops */
+ u32 pos;
+ u32 actual_size;
+};
+
+struct saa7164_port {
+
+ struct saa7164_dev *dev;
+ enum port_t type;
+ int nr;
+
+ /* --- Generic port attributes --- */
+
+ /* HW stream parameters */
+ struct tmHWStreamParameters hw_streamingparams;
+
+ /* DMA configuration values, is seeded during initialization */
+ struct tmComResDMATermDescrHeader hwcfg;
+
+ /* hardware specific registers */
+ u32 bufcounter;
+ u32 pitch;
+ u32 bufsize;
+ u32 bufoffset;
+ u32 bufptr32l;
+ u32 bufptr32h;
+ u64 bufptr64;
+
+ u32 numpte; /* Number of entries in array, only valid in head */
+
+ struct mutex dmaqueue_lock;
+ struct saa7164_buffer dmaqueue;
+
+ u64 last_irq_msecs, last_svc_msecs;
+ u64 last_irq_msecs_diff, last_svc_msecs_diff;
+ u32 last_svc_wp;
+ u32 last_svc_rp;
+ u64 last_irq_svc_msecs_diff;
+ u64 last_read_msecs, last_read_msecs_diff;
+ u64 last_poll_msecs, last_poll_msecs_diff;
+
+ struct saa7164_histogram irq_interval;
+ struct saa7164_histogram svc_interval;
+ struct saa7164_histogram irq_svc_interval;
+ struct saa7164_histogram read_interval;
+ struct saa7164_histogram poll_interval;
+
+ /* --- DVB Transport Specific --- */
+ struct saa7164_dvb dvb;
+
+ /* --- Encoder/V4L related attributes --- */
+ /* Encoder */
+ /* Defaults established in saa7164-encoder.c */
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 freq;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+ u8 mux_input;
+ u8 encoder_profile;
+ u8 video_format;
+ u8 audio_format;
+ u8 video_resolution;
+ u16 ctl_brightness;
+ u16 ctl_contrast;
+ u16 ctl_hue;
+ u16 ctl_saturation;
+ u16 ctl_sharpness;
+ s8 ctl_volume;
+
+ struct tmComResAFeatureDescrHeader audfeat;
+ struct tmComResEncoderDescrHeader encunit;
+ struct tmComResProcDescrHeader vidproc;
+ struct tmComResExtDevDescrHeader ifunit;
+ struct tmComResTunerDescrHeader tunerunit;
+
+ struct work_struct workenc;
+
+ /* V4L Encoder Video */
+ struct saa7164_encoder_params encoder_params;
+ struct video_device *v4l_device;
+ atomic_t v4l_reader_count;
+
+ struct saa7164_buffer list_buf_used;
+ struct saa7164_buffer list_buf_free;
+ wait_queue_head_t wait_read;
+
+ /* V4L VBI */
+ struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc;
+ struct saa7164_vbi_params vbi_params;
+
+ /* Debug */
+ u32 sync_errors;
+ u32 v_cc_errors;
+ u32 a_cc_errors;
+ u8 last_v_cc;
+ u8 last_a_cc;
+ u32 done_first_interrupt;
+};
+
+struct saa7164_dev {
+ struct list_head devlist;
+ atomic_t refcount;
+
+ /* pci stuff */
+ struct pci_dev *pci;
+ unsigned char pci_rev, pci_lat;
+ int pci_bus, pci_slot;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
+ u32 __iomem *lmmio2;
+ u8 __iomem *bmmio2;
+ int pci_irqmask;
+
+ /* board details */
+ int nr;
+ int hwrevision;
+ u32 board;
+ char name[16];
+
+ /* firmware status */
+ struct saa7164_fw_status fw_status;
+ u32 firmwareloaded;
+
+ struct tmComResHWDescr hwdesc;
+ struct tmComResInterfaceDescr intfdesc;
+ struct tmComResBusDescr busdesc;
+
+ struct tmComResBusInfo bus;
+
+ /* Interrupt status and ack registers */
+ u32 int_status;
+ u32 int_ack;
+
+ struct cmd cmds[SAA_CMD_MAX_MSG_UNITS];
+ struct mutex lock;
+
+ /* I2c related */
+ struct saa7164_i2c i2c_bus[3];
+
+ /* Transport related */
+ struct saa7164_port ports[SAA7164_MAX_PORTS];
+
+ /* Deferred command/api interrupts handling */
+ struct work_struct workcmd;
+
+ /* A kernel thread to monitor the firmware log, used
+ * only in debug mode.
+ */
+ struct task_struct *kthread;
+
+};
+
+extern struct list_head saa7164_devlist;
+extern unsigned int waitsecs;
+extern unsigned int encoder_buffers;
+extern unsigned int vbi_buffers;
+
+/* ----------------------------------------------------------- */
+/* saa7164-core.c */
+void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
+void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
+u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
+
+/* ----------------------------------------------------------- */
+/* saa7164-fw.c */
+int saa7164_downloadfirmware(struct saa7164_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7164-i2c.c */
+extern int saa7164_i2c_register(struct saa7164_i2c *bus);
+extern int saa7164_i2c_unregister(struct saa7164_i2c *bus);
+extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
+ unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* saa7164-bus.c */
+int saa7164_bus_setup(struct saa7164_dev *dev);
+void saa7164_bus_dump(struct saa7164_dev *dev);
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf);
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf, int peekonly);
+
+/* ----------------------------------------------------------- */
+/* saa7164-cmd.c */
+int saa7164_cmd_send(struct saa7164_dev *dev,
+ u8 id, enum tmComResCmd command, u16 controlselector,
+ u16 size, void *buf);
+void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
+int saa7164_irq_dequeue(struct saa7164_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7164-api.c */
+int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version);
+int saa7164_api_enum_subdevs(struct saa7164_dev *dev);
+int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
+ u32 datalen, u8 *data);
+int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr,
+ u32 datalen, u8 *data);
+int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr,
+ u32 datalen, u8 *data);
+int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen);
+int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
+int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode);
+int saa7164_api_initialize_dif(struct saa7164_port *port);
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std);
+int saa7164_api_set_encoder(struct saa7164_port *port);
+int saa7164_api_get_encoder(struct saa7164_port *port);
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port);
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_set_videomux(struct saa7164_port *port);
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute);
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level);
+int saa7164_api_set_audio_std(struct saa7164_port *port);
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect);
+int saa7164_api_get_videomux(struct saa7164_port *port);
+int saa7164_api_set_vbi_format(struct saa7164_port *port);
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
+int saa7164_api_collect_debug(struct saa7164_dev *dev);
+int saa7164_api_get_load_info(struct saa7164_dev *dev,
+ struct tmFwInfoStruct *i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-cards.c */
+extern struct saa7164_board saa7164_boards[];
+extern const unsigned int saa7164_bcount;
+
+extern struct saa7164_subid saa7164_subids[];
+extern const unsigned int saa7164_idcount;
+
+extern void saa7164_card_list(struct saa7164_dev *dev);
+extern void saa7164_gpio_setup(struct saa7164_dev *dev);
+extern void saa7164_card_setup(struct saa7164_dev *dev);
+
+extern int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr);
+extern int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr);
+extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid);
+
+/* ----------------------------------------------------------- */
+/* saa7164-dvb.c */
+extern int saa7164_dvb_register(struct saa7164_port *port);
+extern int saa7164_dvb_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-buffer.c */
+extern struct saa7164_buffer *saa7164_buffer_alloc(
+ struct saa7164_port *port, u32 len);
+extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
+extern void saa7164_buffer_display(struct saa7164_buffer *buf);
+extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
+extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
+extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
+ struct saa7164_dev *dev, u32 len);
+extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf);
+extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-encoder.c */
+int saa7164_encoder_register(struct saa7164_port *port);
+void saa7164_encoder_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-vbi.c */
+int saa7164_vbi_register(struct saa7164_port *port);
+void saa7164_vbi_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+
+extern unsigned int crc_checking;
+
+extern unsigned int saa_debug;
+#define dprintk(level, fmt, arg...)\
+ do { if (saa_debug & level)\
+ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
+ } while (0)
+
+#define log_warn(fmt, arg...)\
+ do { \
+ printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\
+ } while (0)
+
+#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
+#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
+
+#define saa7164_readb(reg) readl(dev->bmmio + (reg))
+#define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg))
+
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
new file mode 100644
index 000000000000..6749f67cab8a
--- /dev/null
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -0,0 +1,12 @@
+config STA2X11_VIP
+ tristate "STA2X11 VIP Video For Linux"
+ depends on STA2X11
+ select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEOBUF_DMA_CONTIG
+ depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+ help
+ Say Y for support for STA2X11 VIP (Video Input Port) capture
+ device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sta2x11_vip.
diff --git a/drivers/media/pci/sta2x11/Makefile b/drivers/media/pci/sta2x11/Makefile
new file mode 100644
index 000000000000..d6c471d1d1b4
--- /dev/null
+++ b/drivers/media/pci/sta2x11/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 4c10205264d4..4c10205264d4 100644
--- a/drivers/media/video/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
diff --git a/drivers/media/video/sta2x11_vip.h b/drivers/media/pci/sta2x11/sta2x11_vip.h
index 4f81a13666eb..4f81a13666eb 100644
--- a/drivers/media/video/sta2x11_vip.h
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.h
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
new file mode 100644
index 000000000000..314e417addae
--- /dev/null
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -0,0 +1,159 @@
+config TTPCI_EEPROM
+ tristate
+ depends on I2C
+ default n
+
+config DVB_AV7110
+ tristate "AV7110 cards"
+ depends on DVB_CORE && PCI && I2C
+ select TTPCI_EEPROM
+ select VIDEO_SAA7146_VV
+ depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
+ select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for SAA7146 and AV7110 based DVB cards as produced
+ by Fujitsu-Siemens, Technotrend, Hauppauge and others.
+
+ This driver only supports the fullfeatured cards with
+ onboard MPEG2 decoder.
+
+ This driver needs an external firmware. Please use the script
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+ Alternatively, you can download the file and use the kernel's
+ EXTRA_FIRMWARE configuration option to build it into your
+ kernel image by adding the filename to the EXTRA_FIRMWARE
+ configuration option string.
+
+ Say Y if you own such a card and want to use it.
+
+config DVB_AV7110_OSD
+ bool "AV7110 OSD support"
+ depends on DVB_AV7110
+ default y if DVB_AV7110=y || DVB_AV7110=m
+ help
+ The AV7110 firmware provides some code to generate an OnScreenDisplay
+ on the video output. This is kind of nonstandard and not guaranteed to
+ be maintained.
+
+ Anyway, some popular DVB software like VDR uses this OSD to render
+ its menus, so say Y if you want to use this software.
+
+ All other people say N.
+
+config DVB_BUDGET_CORE
+ tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
+ depends on DVB_CORE && PCI && I2C
+ select VIDEO_SAA7146
+ select TTPCI_EEPROM
+ help
+ Support for simple SAA7146 based DVB cards
+ (so called Budget- or Nova-PCI cards) without onboard
+ MPEG2 decoder.
+
+config DVB_BUDGET
+ tristate "Budget cards"
+ depends on DVB_BUDGET_CORE && I2C
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for simple SAA7146 based DVB cards (so called Budget-
+ or Nova-PCI cards) without onboard MPEG2 decoder, and without
+ analog inputs or an onboard Common Interface connector.
+
+ Say Y if you own such a card and want to use it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called budget.
+
+config DVB_BUDGET_CI
+ tristate "Budget cards with onboard CI connector"
+ depends on DVB_BUDGET_CORE && I2C
+ select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
+ depends on RC_CORE
+ help
+ Support for simple SAA7146 based DVB cards
+ (so called Budget- or Nova-PCI cards) without onboard
+ MPEG2 decoder, but with onboard Common Interface connector.
+
+ Note: The Common Interface is not yet supported by this driver
+ due to lack of information from the vendor.
+
+ Say Y if you own such a card and want to use it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called budget-ci.
+
+config DVB_BUDGET_AV
+ tristate "Budget cards with analog video inputs"
+ depends on DVB_BUDGET_CORE && I2C
+ select VIDEO_SAA7146_VV
+ depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8261 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUA6100 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for simple SAA7146 based DVB cards
+ (so called Budget- or Nova-PCI cards) without onboard
+ MPEG2 decoder, but with one or more analog video inputs.
+
+ Say Y if you own such a card and want to use it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called budget-av.
+
+config DVB_BUDGET_PATCH
+ tristate "AV7110 cards with Budget Patch"
+ depends on DVB_BUDGET_CORE && I2C
+ depends on DVB_AV7110
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for Budget Patch (full TS) modification on
+ SAA7146+AV7110 based cards (DVB-S cards). This
+ driver doesn't use onboard MPEG2 decoder. The
+ card is driven in Budget-only mode. Card is
+ required to have loaded firmware to tune properly.
+ Firmware can be loaded by insertion and removal of
+ standard AV7110 driver prior to loading this
+ driver.
+
+ Say Y if you own such a card and want to use it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called budget-patch.
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
new file mode 100644
index 000000000000..98905963ff08
--- /dev/null
+++ b/drivers/media/pci/ttpci/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile for the kernel SAA7146 FULL TS DVB device driver
+# and the AV7110 DVB device driver
+#
+
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
+
+ifdef CONFIG_INPUT_EVDEV
+dvb-ttpci-objs += av7110_ir.o
+endif
+
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
+obj-$(CONFIG_DVB_BUDGET) += budget.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 4bd8bd56befc..4bd8bd56befc 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index 88b3b2d6cc0e..88b3b2d6cc0e 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 952b33dbac4f..952b33dbac4f 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/pci/ttpci/av7110_av.h
index 5f02ef85e47d..5f02ef85e47d 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/pci/ttpci/av7110_av.h
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
index 9fc1dd0ba4c3..9fc1dd0ba4c3 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/pci/ttpci/av7110_ca.c
diff --git a/drivers/media/dvb/ttpci/av7110_ca.h b/drivers/media/pci/ttpci/av7110_ca.h
index 70ee855ece1b..70ee855ece1b 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.h
+++ b/drivers/media/pci/ttpci/av7110_ca.h
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c
index f1cbfe526989..f1cbfe526989 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/pci/ttpci/av7110_hw.c
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/pci/ttpci/av7110_hw.h
index 1634aba5cb84..1634aba5cb84 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/pci/ttpci/av7110_hw.h
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/pci/ttpci/av7110_ipack.c
index 699ef8b5b99a..699ef8b5b99a 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/pci/ttpci/av7110_ipack.c
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.h b/drivers/media/pci/ttpci/av7110_ipack.h
index becf94d3fdfa..becf94d3fdfa 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.h
+++ b/drivers/media/pci/ttpci/av7110_ipack.h
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c
index 908f272fe26c..908f272fe26c 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/pci/ttpci/av7110_ir.c
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
index 1b2d15140a1d..1b2d15140a1d 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 12ddb53c58dc..12ddb53c58dc 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 98e524178765..98e524178765 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index 37d02fe09137..37d02fe09137 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c
index 2cb35c23d2ac..2cb35c23d2ac 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/pci/ttpci/budget-patch.c
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
new file mode 100644
index 000000000000..7e6e43ae5c51
--- /dev/null
+++ b/drivers/media/pci/ttpci/budget.c
@@ -0,0 +1,871 @@
+/*
+ * budget.c: driver for the SAA7146 based Budget DVB cards
+ *
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ *
+ * 26feb2004 Support for FS Activy Card (Grundig tuner) by
+ * Michael Dreher <michael@5dot1.de>,
+ * Oliver Endriss <o.endriss@gmx.de> and
+ * Andreas 'randy' Weinberger
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org/
+ */
+
+#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
+#include "s5h1420.h"
+#include "tda10086.h"
+#include "tda826x.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+#include "bsbe1.h"
+#include "tdhd1.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
+#include "lnbh24.h"
+
+
+static int diseqc_method;
+module_param(diseqc_method, int, 0444);
+MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void Set22K (struct budget *budget, int state)
+{
+ struct saa7146_dev *dev=budget->dev;
+ dprintk(2, "budget: %p\n", budget);
+ saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
+}
+
+/* Diseqc functions only for TT Budget card */
+/* taken from the Skyvision DVB driver by
+ Ralph Metzler <rjkm@metzlerbros.de> */
+
+static void DiseqcSendBit (struct budget *budget, int data)
+{
+ struct saa7146_dev *dev=budget->dev;
+ dprintk(2, "budget: %p\n", budget);
+
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+ udelay(data ? 500 : 1000);
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+ udelay(data ? 1000 : 500);
+}
+
+static void DiseqcSendByte (struct budget *budget, int data)
+{
+ int i, par=1, d;
+
+ dprintk(2, "budget: %p\n", budget);
+
+ for (i=7; i>=0; i--) {
+ d = (data>>i)&1;
+ par ^= d;
+ DiseqcSendBit(budget, d);
+ }
+
+ DiseqcSendBit(budget, par);
+}
+
+static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
+{
+ struct saa7146_dev *dev=budget->dev;
+ int i;
+
+ dprintk(2, "budget: %p\n", budget);
+
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+ mdelay(16);
+
+ for (i=0; i<len; i++)
+ DiseqcSendByte(budget, msg[i]);
+
+ mdelay(16);
+
+ if (burst!=-1) {
+ if (burst)
+ DiseqcSendByte(budget, 0xff);
+ else {
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+ mdelay(12);
+ udelay(500);
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+ }
+ msleep(20);
+ }
+
+ return 0;
+}
+
+/*
+ * Routines for the Fujitsu Siemens Activy budget card
+ * 22 kHz tone and DiSEqC are handled by the frontend.
+ * Voltage must be set here.
+ * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
+ */
+static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
+{
+ struct saa7146_dev *dev=budget->dev;
+
+ dprintk(2, "budget: %p\n", budget);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
+ saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
+ break;
+ case SEC_VOLTAGE_18:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
+ saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+ break;
+ case SEC_VOLTAGE_OFF:
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ return SetVoltage_Activy (budget, voltage);
+}
+
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ Set22K (budget, 1);
+ break;
+
+ case SEC_TONE_OFF:
+ Set22K (budget, 0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+
+ return 0;
+}
+
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+ return 0;
+}
+
+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 = (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;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config =
+{
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+};
+
+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 = (c->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+};
+
+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;
+ u8 cfg, cpump, band_select;
+ u8 data[4];
+ struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if (tuner_addr)
+ msg.addr = *tuner_addr;
+ else
+ msg.addr = 0x61;
+
+ div = (36125000 + c->frequency) / 166666;
+
+ cfg = 0x88;
+
+ 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 (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;
+ data[2] = ((div >> 10) & 0x60) | cfg;
+ data[3] = (cpump << 6) | band_select;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+ .demod_address = 0x55,
+};
+
+static struct l64781_config grundig_29504_401_config_activy = {
+ .demod_address = 0x54,
+};
+
+static u8 tuner_address_grundig_29504_401_activy = 0x60;
+
+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 = c->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+};
+
+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 = c->frequency / 1000;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0xc2;
+
+ if (div < 1450)
+ data[3] = 0x00;
+ else if (div < 1850)
+ data[3] = 0x40;
+ else if (div < 2000)
+ data[3] = 0x80;
+ else
+ data[3] = 0xc0;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ return 0;
+}
+
+static struct s5h1420_config s5h1420_config = {
+ .demod_address = 0x53,
+ .invert = 1,
+ .cdclk_polarity = 1,
+};
+
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 1,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0299_config alps_bsru6_config_activy = {
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .op0_off = 1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+};
+
+static struct stv0299_config alps_bsbe1_config_activy = {
+ .demod_address = 0x68,
+ .inittab = alps_bsbe1_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .op0_off = 1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsbe1_set_symbol_rate,
+};
+
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
+{
+ struct budget *budget = (struct budget *)fe->dvb->priv;
+
+ return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+
+static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
+{
+ u8 val;
+ struct i2c_msg msg[] = {
+ { .addr = adr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ };
+
+ return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;
+}
+
+static u8 read_pwm(struct budget* budget)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static struct stv090x_config tt1600_stv090x_config = {
+ .device = STV0903,
+ .demod_mode = STV090x_SINGLE,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 13500000,
+ .address = 0x68,
+
+ .ts1_mode = STV090x_TSMODE_DVBCI,
+ .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .tuner_init = NULL,
+ .tuner_sleep = NULL,
+ .tuner_set_mode = NULL,
+ .tuner_set_frequency = NULL,
+ .tuner_get_frequency = NULL,
+ .tuner_set_bandwidth = NULL,
+ .tuner_get_bandwidth = NULL,
+ .tuner_set_bbgain = NULL,
+ .tuner_get_bbgain = NULL,
+ .tuner_set_refclk = NULL,
+ .tuner_get_status = NULL,
+};
+
+static struct stv6110x_config tt1600_stv6110x_config = {
+ .addr = 0x60,
+ .refclk = 27000000,
+ .clk_div = 2,
+};
+
+static struct isl6423_config tt1600_isl6423_config = {
+ .current_max = SEC_CURRENT_515m,
+ .curlim = SEC_CURRENT_LIM_ON,
+ .mod_extern = 1,
+ .addr = 0x08,
+};
+
+static void frontend_init(struct budget *budget)
+{
+ (void)alps_bsbe1_config; /* avoid warning */
+
+ switch(budget->dev->pci->subsystem_device) {
+ case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+ case 0x1013:
+ // try the ALPS BSRV2 first of all
+ budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
+ }
+ break;
+ }
+ break;
+
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+ budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
+ break;
+
+ case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = NULL;
+ break;
+ }
+ break;
+
+ case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
+ {
+ int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
+
+ if (subtype < 0)
+ break;
+ /* fixme: find a better way to identify the card */
+ if (subtype < 0x36) {
+ /* assume ALPS BSRU6 */
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ break;
+ }
+ } else {
+ /* assume ALPS BSBE1 */
+ /* reset tuner */
+ saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);
+ msleep(50);
+ saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);
+ msleep(250);
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
+ budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ }
+ break;
+
+ case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
+ budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ }
+ break;
+
+ case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
+ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ }
+ break;
+
+ case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+ budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ printk("%s: No LNBP21 found!\n", __func__);
+ goto error_out;
+ }
+ break;
+ }
+
+ case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
+ // gpio2 is connected to CLB - reset it + leave it high
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+ msleep(1);
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+ msleep(1);
+
+ budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
+ printk("%s: No tda826x found!\n", __func__);
+ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ printk("%s: No LNBP21 found!\n", __func__);
+ goto error_out;
+ }
+ break;
+ }
+
+ case 0x101c: { /* TT S2-1600 */
+ struct stv6110x_devctl *ctl;
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+ msleep(50);
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+ msleep(250);
+
+ budget->dvb_frontend = dvb_attach(stv090x_attach,
+ &tt1600_stv090x_config,
+ &budget->i2c_adap,
+ STV090x_DEMODULATOR_0);
+
+ if (budget->dvb_frontend) {
+
+ ctl = dvb_attach(stv6110x_attach,
+ budget->dvb_frontend,
+ &tt1600_stv6110x_config,
+ &budget->i2c_adap);
+
+ if (ctl) {
+ tt1600_stv090x_config.tuner_init = ctl->tuner_init;
+ tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep;
+ tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
+ tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+ tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+ tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
+ tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
+ tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
+ tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status;
+
+ /* call the init function once to initialize
+ tuner's clock output divider and demod's
+ master clock */
+ if (budget->dvb_frontend->ops.init)
+ budget->dvb_frontend->ops.init(budget->dvb_frontend);
+
+ if (dvb_attach(isl6423_attach,
+ budget->dvb_frontend,
+ &budget->i2c_adap,
+ &tt1600_isl6423_config) == NULL) {
+ printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);
+ goto error_out;
+ }
+ } else {
+ printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+ goto error_out;
+ }
+ }
+ }
+ break;
+
+ case 0x1020: { /* Omicom S2 */
+ struct stv6110x_devctl *ctl;
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+ msleep(50);
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+ msleep(250);
+
+ budget->dvb_frontend = dvb_attach(stv090x_attach,
+ &tt1600_stv090x_config,
+ &budget->i2c_adap,
+ STV090x_DEMODULATOR_0);
+
+ if (budget->dvb_frontend) {
+ printk(KERN_INFO "budget: Omicom S2 detected\n");
+
+ ctl = dvb_attach(stv6110x_attach,
+ budget->dvb_frontend,
+ &tt1600_stv6110x_config,
+ &budget->i2c_adap);
+
+ if (ctl) {
+ tt1600_stv090x_config.tuner_init = ctl->tuner_init;
+ tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep;
+ tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
+ tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+ tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+ tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
+ tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
+ tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
+ tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status;
+
+ /* call the init function once to initialize
+ tuner's clock output divider and demod's
+ master clock */
+ if (budget->dvb_frontend->ops.init)
+ budget->dvb_frontend->ops.init(budget->dvb_frontend);
+
+ if (dvb_attach(lnbh24_attach,
+ budget->dvb_frontend,
+ &budget->i2c_adap,
+ LNBH24_PCL | LNBH24_TTX,
+ LNBH24_TEN, 0x14>>1) == NULL) {
+ printk(KERN_ERR
+ "No LNBH24 found!\n");
+ goto error_out;
+ }
+ } else {
+ printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+ goto error_out;
+ }
+ }
+ }
+ break;
+ }
+
+ if (budget->dvb_frontend == NULL) {
+ printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+ budget->dev->pci->vendor,
+ budget->dev->pci->device,
+ budget->dev->pci->subsystem_vendor,
+ budget->dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
+ goto error_out;
+ }
+ return;
+
+error_out:
+ printk("budget: Frontend registration failed!\n");
+ dvb_frontend_detach(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ return;
+}
+
+static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
+{
+ struct budget *budget = NULL;
+ int err;
+
+ budget = kmalloc(sizeof(struct budget), GFP_KERNEL);
+ if( NULL == budget ) {
+ return -ENOMEM;
+ }
+
+ dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
+
+ dev->ext_priv = budget;
+
+ err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+ if (err) {
+ printk("==> failed\n");
+ kfree (budget);
+ return err;
+ }
+
+ budget->dvb_adapter.priv = budget;
+ frontend_init(budget);
+
+ ttpci_budget_init_hooks(budget);
+
+ return 0;
+}
+
+static int budget_detach (struct saa7146_dev* dev)
+{
+ struct budget *budget = (struct budget*) dev->ext_priv;
+ int err;
+
+ if (budget->dvb_frontend) {
+ dvb_unregister_frontend(budget->dvb_frontend);
+ dvb_frontend_detach(budget->dvb_frontend);
+ }
+
+ err = ttpci_budget_deinit (budget);
+
+ kfree (budget);
+ dev->ext_priv = NULL;
+
+ return err;
+}
+
+static struct saa7146_extension budget_extension;
+
+MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT);
+
+static struct pci_device_id pci_tbl[] = {
+ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
+ MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
+ MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
+ MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
+ MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+ MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
+ MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
+ MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+ MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
+ MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
+ MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020),
+ {
+ .vendor = 0,
+ }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct saa7146_extension budget_extension = {
+ .name = "budget dvb",
+ .flags = SAA7146_USE_I2C_IRQ,
+
+ .module = THIS_MODULE,
+ .pci_tbl = pci_tbl,
+ .attach = budget_attach,
+ .detach = budget_detach,
+
+ .irq_mask = MASK_10,
+ .irq_func = ttpci_budget_irq10_handler,
+};
+
+static int __init budget_init(void)
+{
+ return saa7146_register_extension(&budget_extension);
+}
+
+static void __exit budget_exit(void)
+{
+ saa7146_unregister_extension(&budget_extension);
+}
+
+module_init(budget_init);
+module_exit(budget_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
+MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
+ "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index 3d8a806c20bb..3d8a806c20bb 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c
index 32d43156c548..32d43156c548 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/pci/ttpci/ttpci-eeprom.c
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/pci/ttpci/ttpci-eeprom.h
index dcc33d5a5cb1..dcc33d5a5cb1 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
+++ b/drivers/media/pci/ttpci/ttpci-eeprom.h
diff --git a/drivers/media/pci/zoran/Kconfig b/drivers/media/pci/zoran/Kconfig
new file mode 100644
index 000000000000..a9b231808413
--- /dev/null
+++ b/drivers/media/pci/zoran/Kconfig
@@ -0,0 +1,74 @@
+config VIDEO_ZORAN
+ tristate "Zoran ZR36057/36067 Video For Linux"
+ depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
+ help
+ Say Y for support for MJPEG capture cards based on the Zoran
+ 36057/36067 PCI controller chipset. This includes the Iomega
+ Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
+ a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
+ more information, check <file:Documentation/video4linux/Zoran>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called zr36067.
+
+config VIDEO_ZORAN_DC30
+ tristate "Pinnacle/Miro DC30(+) support"
+ depends on VIDEO_ZORAN
+ select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+ card. This also supports really old DC10 cards based on the
+ zr36050 MJPEG codec and zr36016 VFE.
+
+config VIDEO_ZORAN_ZR36060
+ tristate "Zoran ZR36060"
+ depends on VIDEO_ZORAN
+ help
+ Say Y to support Zoran boards based on 36060 chips.
+ This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
+ and 33 R10 and AverMedia 6 boards.
+
+config VIDEO_ZORAN_BUZ
+ tristate "Iomega Buz support"
+ depends on VIDEO_ZORAN_ZR36060
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the Iomega Buz MJPEG capture/playback card.
+
+config VIDEO_ZORAN_DC10
+ tristate "Pinnacle/Miro DC10(+) support"
+ depends on VIDEO_ZORAN_ZR36060
+ select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+ card.
+
+config VIDEO_ZORAN_LML33
+ tristate "Linux Media Labs LML33 support"
+ depends on VIDEO_ZORAN_ZR36060
+ select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the Linux Media Labs LML33 MJPEG capture/playback
+ card.
+
+config VIDEO_ZORAN_LML33R10
+ tristate "Linux Media Labs LML33R10 support"
+ depends on VIDEO_ZORAN_ZR36060
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ support for the Linux Media Labs LML33R10 MJPEG capture/playback
+ card.
+
+config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+ depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
+ select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_KS0127 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/drivers/media/video/zoran/Makefile b/drivers/media/pci/zoran/Makefile
index 44cc13352c88..44cc13352c88 100644
--- a/drivers/media/video/zoran/Makefile
+++ b/drivers/media/pci/zoran/Makefile
diff --git a/drivers/media/video/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c
index c01071635290..c01071635290 100644
--- a/drivers/media/video/zoran/videocodec.c
+++ b/drivers/media/pci/zoran/videocodec.c
diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/pci/zoran/videocodec.h
index def55585ad23..def55585ad23 100644
--- a/drivers/media/video/zoran/videocodec.h
+++ b/drivers/media/pci/zoran/videocodec.h
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h
index ca2754a3cd63..ca2754a3cd63 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/pci/zoran/zoran.h
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
index c3602d6cd48e..c3602d6cd48e 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/pci/zoran/zoran_card.c
diff --git a/drivers/media/video/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h
index 4936fead73e8..4936fead73e8 100644
--- a/drivers/media/video/zoran/zoran_card.h
+++ b/drivers/media/pci/zoran/zoran_card.h
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index a4cd504b8eee..a4cd504b8eee 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
diff --git a/drivers/media/video/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h
index 07f2c23ff740..07f2c23ff740 100644
--- a/drivers/media/video/zoran/zoran_device.h
+++ b/drivers/media/pci/zoran/zoran_device.h
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index c6ccdeb6d8d6..c6ccdeb6d8d6 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
diff --git a/drivers/media/video/zoran/zoran_procfs.c b/drivers/media/pci/zoran/zoran_procfs.c
index f1423b777db1..f1423b777db1 100644
--- a/drivers/media/video/zoran/zoran_procfs.c
+++ b/drivers/media/pci/zoran/zoran_procfs.c
diff --git a/drivers/media/video/zoran/zoran_procfs.h b/drivers/media/pci/zoran/zoran_procfs.h
index f2d5b1ba448f..f2d5b1ba448f 100644
--- a/drivers/media/video/zoran/zoran_procfs.h
+++ b/drivers/media/pci/zoran/zoran_procfs.h
diff --git a/drivers/media/video/zoran/zr36016.c b/drivers/media/pci/zoran/zr36016.c
index b87ddba8608f..b87ddba8608f 100644
--- a/drivers/media/video/zoran/zr36016.c
+++ b/drivers/media/pci/zoran/zr36016.c
diff --git a/drivers/media/video/zoran/zr36016.h b/drivers/media/pci/zoran/zr36016.h
index 8c79229f69d1..8c79229f69d1 100644
--- a/drivers/media/video/zoran/zr36016.h
+++ b/drivers/media/pci/zoran/zr36016.h
diff --git a/drivers/media/video/zoran/zr36050.c b/drivers/media/pci/zoran/zr36050.c
index e1985609af4b..e1985609af4b 100644
--- a/drivers/media/video/zoran/zr36050.c
+++ b/drivers/media/pci/zoran/zr36050.c
diff --git a/drivers/media/video/zoran/zr36050.h b/drivers/media/pci/zoran/zr36050.h
index 9f52f0cdde50..9f52f0cdde50 100644
--- a/drivers/media/video/zoran/zr36050.h
+++ b/drivers/media/pci/zoran/zr36050.h
diff --git a/drivers/media/video/zoran/zr36057.h b/drivers/media/pci/zoran/zr36057.h
index 54c9362aa980..54c9362aa980 100644
--- a/drivers/media/video/zoran/zr36057.h
+++ b/drivers/media/pci/zoran/zr36057.h
diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/pci/zoran/zr36060.c
index f08546fe2234..f08546fe2234 100644
--- a/drivers/media/video/zoran/zr36060.c
+++ b/drivers/media/pci/zoran/zr36060.c
diff --git a/drivers/media/video/zoran/zr36060.h b/drivers/media/pci/zoran/zr36060.h
index 914ffa4ad8d3..914ffa4ad8d3 100644
--- a/drivers/media/video/zoran/zr36060.h
+++ b/drivers/media/pci/zoran/zr36060.h
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
new file mode 100644
index 000000000000..d4c034d2bd8d
--- /dev/null
+++ b/drivers/media/platform/Kconfig
@@ -0,0 +1,214 @@
+#
+# Platform drivers
+# All drivers here are currently for webcam support
+
+menuconfig V4L_PLATFORM_DRIVERS
+ bool "V4L platform devices"
+ depends on MEDIA_CAMERA_SUPPORT
+ default n
+ ---help---
+ Say Y here to enable support for platform-specific V4L drivers.
+
+if V4L_PLATFORM_DRIVERS
+
+source "drivers/media/platform/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/platform/davinci/Kconfig"
+
+source "drivers/media/platform/omap/Kconfig"
+
+source "drivers/media/platform/blackfin/Kconfig"
+
+config VIDEO_SH_VOU
+ tristate "SuperH VOU video output driver"
+ depends on MEDIA_CAMERA_SUPPORT
+ 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"
+ depends on VIDEO_V4L2 && I2C && DMADEVICES
+ select DMA_ENGINE
+ select TIMB_DMA
+ select VIDEO_ADV7180
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ Add support for the Video In peripherial of the timberdale FPGA.
+
+config VIDEO_VINO
+ tristate "SGI Vino Video For Linux"
+ depends on I2C && SGI_IP22 && VIDEO_V4L2
+ select VIDEO_SAA7191 if MEDIA_SUBDRV_AUTOSELECT
+ 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"
+ depends on M32R && VIDEO_V4L2
+ ---help---
+ This is a video4linux driver for the Renesas AR (Artificial Retina)
+ camera module.
+
+config VIDEO_M32R_AR_M64278
+ tristate "AR device with color module M64278(VGA)"
+ depends on PLAT_M32700UT
+ select VIDEO_M32R_AR
+ ---help---
+ This is a video4linux driver for the Renesas AR (Artificial
+ Retina) with M64278E-800 camera module.
+ This module supports VGA(640x480 pixels) resolutions.
+
+ To compile this driver as a module, choose M here: the
+ module will be called arv.
+
+config VIDEO_OMAP2
+ tristate "OMAP2 Camera Capture Interface driver"
+ depends on VIDEO_DEV && ARCH_OMAP2
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP2 camera capture interface
+
+config VIDEO_OMAP3
+ tristate "OMAP 3 Camera support (EXPERIMENTAL)"
+ depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
+ ---help---
+ Driver for an OMAP 3 camera controller.
+
+config VIDEO_OMAP3_DEBUG
+ bool "OMAP 3 Camera debug messages"
+ depends on VIDEO_OMAP3
+ ---help---
+ Enable debug messages on OMAP 3 camera controller driver.
+
+source "drivers/media/platform/soc_camera/Kconfig"
+source "drivers/media/platform/s5p-fimc/Kconfig"
+source "drivers/media/platform/s5p-tv/Kconfig"
+
+endif # V4L_PLATFORM_DRIVERS
+
+menuconfig V4L_MEM2MEM_DRIVERS
+ bool "Memory-to-memory multimedia devices"
+ depends on VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ default n
+ ---help---
+ Say Y here to enable selecting drivers for V4L devices that
+ use system memory for both source and destination buffers, as opposed
+ to capture and output drivers, which use memory buffers for just
+ one of those.
+
+if V4L_MEM2MEM_DRIVERS
+
+config VIDEO_CODA
+ tristate "Chips&Media Coda multi-standard codec IP"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ Coda is a range of video codec IPs that supports
+ H.264, MPEG-4, and other video formats.
+
+config VIDEO_MEM2MEM_DEINTERLACE
+ tristate "Deinterlace support"
+ depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ Generic deinterlacing V4L2 driver.
+
+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"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+ select VIDEOBUF2_DMA_CONTIG
+ default n
+ 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
+
+menuconfig V4L_TEST_DRIVERS
+ bool "Media test drivers"
+ depends on MEDIA_CAMERA_SUPPORT
+
+if V4L_TEST_DRIVERS
+config VIDEO_VIVI
+ tristate "Virtual Video Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+ select FONT_8x16
+ select VIDEOBUF2_VMALLOC
+ default n
+ ---help---
+ Enables a virtual video driver. This device shows a color bar
+ and a timestamp, as a real device would generate by using V4L2
+ api.
+ Say Y here if you want to test video apps or debug V4L devices.
+ In doubt, say N.
+
+config VIDEO_MEM2MEM_TESTDEV
+ tristate "Virtual test device for mem2mem framework"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select VIDEOBUF2_VMALLOC
+ select V4L2_MEM2MEM_DEV
+ default n
+ ---help---
+ This is a virtual test device for the memory-to-memory driver
+ framework.
+endif #V4L_TEST_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
new file mode 100644
index 000000000000..92127773237c
--- /dev/null
+++ b/drivers/media/platform/Makefile
@@ -0,0 +1,49 @@
+#
+# Makefile for the video capture/playback device drivers.
+#
+
+omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
+
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o
+
+obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
+obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
+
+obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
+obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/
+
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
+obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+
+obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
+
+obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
+obj-$(CONFIG_VIDEO_CODA) += coda.o
+
+obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.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
+
+obj-$(CONFIG_SOC_CAMERA) += soc_camera/
+
+obj-y += davinci/
+
+obj-$(CONFIG_ARCH_OMAP) += omap/
+
+ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/video/arv.c b/drivers/media/platform/arv.c
index e346d32d08ce..e346d32d08ce 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/platform/arv.c
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig
index ecd5323768b7..ecd5323768b7 100644
--- a/drivers/media/video/blackfin/Kconfig
+++ b/drivers/media/platform/blackfin/Kconfig
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/platform/blackfin/Makefile
index aa3a0a216387..aa3a0a216387 100644
--- a/drivers/media/video/blackfin/Makefile
+++ b/drivers/media/platform/blackfin/Makefile
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
new file mode 100644
index 000000000000..1677623d8296
--- /dev/null
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -0,0 +1,1068 @@
+/*
+ * 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);
+ int ret;
+
+ if (mutex_lock_interruptible(&bcap_dev->mutex))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&bcap_dev->buffer_queue, vma);
+ mutex_unlock(&bcap_dev->mutex);
+ return ret;
+}
+
+#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);
+ unsigned int res;
+
+ mutex_lock(&bcap_dev->mutex);
+ res = vb2_poll(&bcap_dev->buffer_queue, file, wait);
+ mutex_unlock(&bcap_dev->mutex);
+ return res;
+}
+
+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/platform/blackfin/ppi.c
index d29592186b02..d29592186b02 100644
--- a/drivers/media/video/blackfin/ppi.c
+++ b/drivers/media/platform/blackfin/ppi.c
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
new file mode 100644
index 000000000000..690851400911
--- /dev/null
+++ b/drivers/media/platform/coda.c
@@ -0,0 +1,1849 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ * Javier Martin, <javier.martin@vista-silicon.com>
+ * Xavier Duret
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME "coda"
+
+#define CODA_MAX_INSTANCES 4
+
+#define CODA_FMO_BUF_SIZE 32
+#define CODADX6_WORK_BUF_SIZE (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA7_WORK_BUF_SIZE (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA_PARA_BUF_SIZE (10 * 1024)
+#define CODA_ISRAM_SIZE (2048 * 2)
+
+#define CODA_OUTPUT_BUFS 4
+#define CODA_CAPTURE_BUFS 2
+
+#define MAX_W 720
+#define MAX_H 576
+#define CODA_MAX_FRAME_SIZE 0x90000
+#define FMO_SLICE_SAVE_BUF_SIZE (32)
+#define CODA_DEFAULT_GAMMA 4096
+
+#define MIN_W 176
+#define MIN_H 144
+#define MAX_W 720
+#define MAX_H 576
+
+#define S_ALIGN 1 /* multiple of 2 */
+#define W_ALIGN 1 /* multiple of 2 */
+#define H_ALIGN 1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh)
+
+static int coda_debug;
+module_param(coda_debug, int, 0);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+enum coda_fmt_type {
+ CODA_FMT_ENC,
+ CODA_FMT_RAW,
+};
+
+enum coda_inst_type {
+ CODA_INST_ENCODER,
+ CODA_INST_DECODER,
+};
+
+enum coda_product {
+ CODA_DX6 = 0xf001,
+};
+
+struct coda_fmt {
+ char *name;
+ u32 fourcc;
+ enum coda_fmt_type type;
+};
+
+struct coda_devtype {
+ char *firmware;
+ enum coda_product product;
+ struct coda_fmt *formats;
+ unsigned int num_formats;
+ size_t workbuf_size;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int sizeimage;
+ struct coda_fmt *fmt;
+};
+
+struct coda_aux_buf {
+ void *vaddr;
+ dma_addr_t paddr;
+ u32 size;
+};
+
+struct coda_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+ struct platform_device *plat_dev;
+ const struct coda_devtype *devtype;
+
+ void __iomem *regs_base;
+ struct clk *clk_per;
+ struct clk *clk_ahb;
+
+ struct coda_aux_buf codebuf;
+ struct coda_aux_buf workbuf;
+
+ spinlock_t irqlock;
+ struct mutex dev_mutex;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct vb2_alloc_ctx *alloc_ctx;
+ int instances;
+};
+
+struct coda_params {
+ u8 h264_intra_qp;
+ u8 h264_inter_qp;
+ u8 mpeg4_intra_qp;
+ u8 mpeg4_inter_qp;
+ u8 gop_size;
+ int codec_mode;
+ enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+ u32 framerate;
+ u16 bitrate;
+ u32 slice_max_mb;
+};
+
+struct coda_ctx {
+ struct coda_dev *dev;
+ int aborting;
+ int rawstreamon;
+ int compstreamon;
+ u32 isequence;
+ struct coda_q_data q_data[2];
+ enum coda_inst_type inst_type;
+ enum v4l2_colorspace colorspace;
+ struct coda_params params;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_fh fh;
+ struct vb2_buffer *reference;
+ int gopcounter;
+ char vpu_header[3][64];
+ int vpu_header_size[3];
+ struct coda_aux_buf parabuf;
+ int idx;
+};
+
+static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+ "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+ writel(data, dev->regs_base + reg);
+}
+
+static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+ u32 data;
+ data = readl(dev->regs_base + reg);
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+ "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+ return data;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+ return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+ return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (coda_isbusy(dev)) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+ struct coda_dev *dev = ctx->dev;
+ coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+ coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+ coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+ coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+ struct coda_dev *dev = ctx->dev;
+
+ coda_command_async(ctx, cmd);
+ return coda_wait_timeout(dev);
+}
+
+static struct coda_q_data *get_q_data(struct coda_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;
+}
+
+/*
+ * Add one array of supported formats for each version of Coda:
+ * i.MX27 -> codadx6
+ * i.MX51 -> coda7
+ * i.MX6 -> coda960
+ */
+static struct coda_fmt codadx6_formats[] = {
+ {
+ .name = "YUV 4:2:0 Planar",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .type = CODA_FMT_RAW,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .type = CODA_FMT_ENC,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .type = CODA_FMT_ENC,
+ },
+};
+
+static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f)
+{
+ struct coda_fmt *formats = dev->devtype->formats;
+ int num_formats = dev->devtype->num_formats;
+ unsigned int k;
+
+ for (k = 0; k < num_formats; k++) {
+ if (formats[k].fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == num_formats)
+ return NULL;
+
+ return &formats[k];
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
+ strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
+ enum coda_fmt_type type)
+{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+ struct coda_dev *dev = ctx->dev;
+ struct coda_fmt *formats = dev->devtype->formats;
+ struct coda_fmt *fmt;
+ int num_formats = dev->devtype->num_formats;
+ int i, num = 0;
+
+ for (i = 0; i < num_formats; i++) {
+ if (formats[i].type == type) {
+ if (num == f->index)
+ break;
+ ++num;
+ }
+ }
+
+ if (i < num_formats) {
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ 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(priv, f, CODA_FMT_ENC);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return enum_fmt(priv, f, CODA_FMT_RAW);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct coda_q_data *q_data;
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+
+ 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.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+ f->fmt.pix.width = q_data->width;
+ f->fmt.pix.height = q_data->height;
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+ else /* encoded formats h.264/mpeg4 */
+ f->fmt.pix.bytesperline = 0;
+
+ f->fmt.pix.sizeimage = q_data->sizeimage;
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ return 0;
+}
+
+static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
+{
+ enum v4l2_field field;
+
+ 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, &f->fmt.pix.height,
+ MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ } else { /*encoded formats h.264/mpeg4 */
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+ }
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+ struct coda_fmt *fmt;
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+
+ fmt = find_format(ctx->dev, f);
+ /*
+ * Since decoding support is not implemented yet do not allow
+ * CODA_FMT_RAW formats in the capture interface.
+ */
+ if (!fmt || !(fmt->type == CODA_FMT_ENC))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ ret = vidioc_try_fmt(ctx->dev, f);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+ struct coda_fmt *fmt;
+ int ret;
+
+ fmt = find_format(ctx->dev, f);
+ /*
+ * Since decoding support is not implemented yet do not allow
+ * CODA_FMT formats in the capture interface.
+ */
+ if (!fmt || !(fmt->type == CODA_FMT_RAW))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+ if (!f->fmt.pix.colorspace)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ ret = vidioc_try_fmt(ctx->dev, f);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+ struct coda_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(ctx->dev, f);
+ if (ret)
+ return ret;
+
+ q_data->fmt = find_format(ctx->dev, 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 { /* encoded format h.264/mpeg-4 */
+ q_data->sizeimage = CODA_MAX_FRAME_SIZE;
+ }
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_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(fh_to_ctx(priv), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = vidioc_s_fmt(fh_to_ctx(priv), f);
+ if (ret)
+ ctx->colorspace = f->fmt.pix.colorspace;
+
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct coda_ctx *ctx = fh_to_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 coda_ctx *ctx = fh_to_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 coda_ctx *ctx = fh_to_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 coda_ctx *ctx = fh_to_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 coda_ctx *ctx = fh_to_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 coda_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+ .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,
+ .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,
+};
+
+/*
+ * Mem-to-mem operations.
+ */
+static void coda_device_run(void *m2m_priv)
+{
+ struct coda_ctx *ctx = m2m_priv;
+ struct coda_q_data *q_data_src, *q_data_dst;
+ struct vb2_buffer *src_buf, *dst_buf;
+ struct coda_dev *dev = ctx->dev;
+ int force_ipicture;
+ int quant_param = 0;
+ u32 picture_y, picture_cb, picture_cr;
+ u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+ u32 dst_fourcc;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ dst_fourcc = q_data_dst->fmt->fourcc;
+
+ src_buf->v4l2_buf.sequence = ctx->isequence;
+ dst_buf->v4l2_buf.sequence = ctx->isequence;
+ ctx->isequence++;
+
+ /*
+ * Workaround coda firmware BUG that only marks the first
+ * frame as IDR. This is a problem for some decoders that can't
+ * recover when a frame is lost.
+ */
+ if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+ src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+ } else {
+ src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+ }
+
+ /*
+ * Copy headers at the beginning of the first frame for H.264 only.
+ * In MPEG4 they are already copied by the coda.
+ */
+ if (src_buf->v4l2_buf.sequence == 0) {
+ pic_stream_buffer_addr =
+ vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+ ctx->vpu_header_size[0] +
+ ctx->vpu_header_size[1] +
+ ctx->vpu_header_size[2];
+ pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+ ctx->vpu_header_size[0] -
+ ctx->vpu_header_size[1] -
+ ctx->vpu_header_size[2];
+ memcpy(vb2_plane_vaddr(dst_buf, 0),
+ &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+ memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+ &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+ memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+ ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+ ctx->vpu_header_size[2]);
+ } else {
+ pic_stream_buffer_addr =
+ vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+ }
+
+ if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+ force_ipicture = 1;
+ switch (dst_fourcc) {
+ case V4L2_PIX_FMT_H264:
+ quant_param = ctx->params.h264_intra_qp;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ quant_param = ctx->params.mpeg4_intra_qp;
+ break;
+ default:
+ v4l2_warn(&ctx->dev->v4l2_dev,
+ "cannot set intra qp, fmt not supported\n");
+ break;
+ }
+ } else {
+ force_ipicture = 0;
+ switch (dst_fourcc) {
+ case V4L2_PIX_FMT_H264:
+ quant_param = ctx->params.h264_inter_qp;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ quant_param = ctx->params.mpeg4_inter_qp;
+ break;
+ default:
+ v4l2_warn(&ctx->dev->v4l2_dev,
+ "cannot set inter qp, fmt not supported\n");
+ break;
+ }
+ }
+
+ /* submit */
+ coda_write(dev, 0, CODA_CMD_ENC_PIC_ROT_MODE);
+ coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+ picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ picture_cb = picture_y + q_data_src->width * q_data_src->height;
+ picture_cr = picture_cb + q_data_src->width / 2 *
+ q_data_src->height / 2;
+
+ coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+ coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+ coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+ coda_write(dev, force_ipicture << 1 & 0x2,
+ CODA_CMD_ENC_PIC_OPTION);
+
+ coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+ coda_write(dev, pic_stream_buffer_size / 1024,
+ CODA_CMD_ENC_PIC_BB_SIZE);
+ coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+ struct coda_ctx *ctx = m2m_priv;
+
+ /*
+ * For both 'P' and 'key' frame cases 1 picture
+ * and 1 frame are needed.
+ */
+ if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) ||
+ !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "not ready: not enough video buffers.\n");
+ return 0;
+ }
+
+ /* For P frames a reference picture is needed too */
+ if ((ctx->gopcounter != (ctx->params.gop_size - 1)) &&
+ !ctx->reference) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "not ready: reference picture not available.\n");
+ return 0;
+ }
+
+ if (coda_isbusy(ctx->dev)) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "not ready: coda is still busy.\n");
+ return 0;
+ }
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "job ready\n");
+ return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+ struct coda_ctx *ctx = priv;
+ struct coda_dev *dev = ctx->dev;
+
+ ctx->aborting = 1;
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "Aborting task\n");
+
+ v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void coda_lock(void *m2m_priv)
+{
+ struct coda_ctx *ctx = m2m_priv;
+ struct coda_dev *pcdev = ctx->dev;
+ mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+ struct coda_ctx *ctx = m2m_priv;
+ struct coda_dev *pcdev = ctx->dev;
+ mutex_unlock(&pcdev->dev_mutex);
+}
+
+static struct v4l2_m2m_ops coda_m2m_ops = {
+ .device_run = coda_device_run,
+ .job_ready = coda_job_ready,
+ .job_abort = coda_job_abort,
+ .lock = coda_lock,
+ .unlock = coda_unlock,
+};
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+
+ ctx->params.codec_mode = CODA_MODE_INVALID;
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->params.framerate = 30;
+ ctx->reference = NULL;
+ ctx->aborting = 0;
+
+ /* Default formats for output and input queues */
+ ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0];
+ ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1];
+ ctx->q_data[V4L2_M2M_SRC].width = MAX_W;
+ ctx->q_data[V4L2_M2M_SRC].height = MAX_H;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2;
+ ctx->q_data[V4L2_M2M_DST].width = MAX_W;
+ ctx->q_data[V4L2_M2M_DST].height = MAX_H;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+ unsigned int size;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ *nbuffers = CODA_OUTPUT_BUFS;
+ if (fmt)
+ size = fmt->fmt.pix.width *
+ fmt->fmt.pix.height * 3 / 2;
+ else
+ size = MAX_W *
+ MAX_H * 3 / 2;
+ } else {
+ *nbuffers = CODA_CAPTURE_BUFS;
+ size = CODA_MAX_FRAME_SIZE;
+ }
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+ return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct coda_q_data *q_data;
+
+ q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+ v4l2_warn(&ctx->dev->v4l2_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 coda_buf_queue(struct vb2_buffer *vb)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void coda_wait_prepare(struct vb2_queue *q)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(q);
+ coda_unlock(ctx);
+}
+
+static void coda_wait_finish(struct vb2_queue *q)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(q);
+ coda_lock(ctx);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(q);
+ struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+ u32 bitstream_buf, bitstream_size;
+ struct coda_dev *dev = ctx->dev;
+ struct coda_q_data *q_data_src, *q_data_dst;
+ u32 dst_fourcc;
+ struct vb2_buffer *buf;
+ struct vb2_queue *src_vq;
+ u32 value;
+ int i = 0;
+
+ if (count < 1)
+ return -EINVAL;
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ ctx->rawstreamon = 1;
+ else
+ ctx->compstreamon = 1;
+
+ /* Don't start the coda unless both queues are on */
+ if (!(ctx->rawstreamon & ctx->compstreamon))
+ return 0;
+
+ ctx->gopcounter = ctx->params.gop_size - 1;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ bitstream_size = q_data_dst->sizeimage;
+ dst_fourcc = q_data_dst->fmt->fourcc;
+
+ /* Find out whether coda must encode or decode */
+ if (q_data_src->fmt->type == CODA_FMT_RAW &&
+ q_data_dst->fmt->type == CODA_FMT_ENC) {
+ ctx->inst_type = CODA_INST_ENCODER;
+ } else if (q_data_src->fmt->type == CODA_FMT_ENC &&
+ q_data_dst->fmt->type == CODA_FMT_RAW) {
+ ctx->inst_type = CODA_INST_DECODER;
+ v4l2_err(v4l2_dev, "decoding not supported.\n");
+ return -EINVAL;
+ } else {
+ v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+ return -EINVAL;
+ }
+
+ if (!coda_is_initialized(dev)) {
+ v4l2_err(v4l2_dev, "coda is not initialized.\n");
+ return -EFAULT;
+ }
+ coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+ coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
+ coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
+ switch (dev->devtype->product) {
+ case CODA_DX6:
+ coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+ CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+ break;
+ default:
+ coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+ CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+ }
+
+ /* Configure the coda */
+ coda_write(dev, 0xffff4c00, CODA_REG_BIT_SEARCH_RAM_BASE_ADDR);
+
+ /* Could set rotation here if needed */
+ switch (dev->devtype->product) {
+ case CODA_DX6:
+ value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
+ break;
+ default:
+ value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+ }
+ value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+ coda_write(dev, ctx->params.framerate,
+ CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+ switch (dst_fourcc) {
+ case V4L2_PIX_FMT_MPEG4:
+ if (dev->devtype->product == CODA_DX6)
+ ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4;
+ else
+ ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4;
+
+ coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+ break;
+ case V4L2_PIX_FMT_H264:
+ if (dev->devtype->product == CODA_DX6)
+ ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264;
+ else
+ ctx->params.codec_mode = CODA7_MODE_ENCODE_H264;
+
+ coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
+ break;
+ default:
+ v4l2_err(v4l2_dev,
+ "dst format (0x%08x) invalid.\n", dst_fourcc);
+ return -EINVAL;
+ }
+
+ value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
+ value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
+ if (ctx->params.slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB)
+ value |= 1 & CODA_SLICING_MODE_MASK;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+ value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+ if (ctx->params.bitrate) {
+ /* Rate control enabled */
+ value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
+ value |= 1 & CODA_RATECONTROL_ENABLE_MASK;
+ } else {
+ value = 0;
+ }
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+ coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+ coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+ /* set default gamma */
+ value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
+
+ value = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET;
+ value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+ if (dst_fourcc == V4L2_PIX_FMT_H264) {
+ value = (FMO_SLICE_SAVE_BUF_SIZE << 7);
+ value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET;
+ value |= 0 & CODA_FMOPARAM_SLICENUM_MASK;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_FMO);
+ }
+
+ if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0)
+ return -EFAULT;
+
+ /*
+ * Walk the src buffer list and let the codec know the
+ * addresses of the pictures.
+ */
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ for (i = 0; i < src_vq->num_buffers; i++) {
+ u32 *p;
+
+ buf = src_vq->bufs[i];
+ p = ctx->parabuf.vaddr;
+
+ p[i * 3] = vb2_dma_contig_plane_dma_addr(buf, 0);
+ p[i * 3 + 1] = p[i * 3] + q_data_src->width *
+ q_data_src->height;
+ p[i * 3 + 2] = p[i * 3 + 1] + q_data_src->width / 2 *
+ q_data_src->height / 2;
+ }
+
+ coda_write(dev, src_vq->num_buffers, CODA_CMD_SET_FRAME_BUF_NUM);
+ coda_write(dev, q_data_src->width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+ if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* Save stream headers */
+ buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ switch (dst_fourcc) {
+ case V4L2_PIX_FMT_H264:
+ /*
+ * Get SPS in the first frame and copy it to an
+ * intermediate buffer.
+ */
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE);
+ if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+ return -ETIMEDOUT;
+ }
+ ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+ ctx->vpu_header_size[0]);
+
+ /*
+ * Get PPS in the first frame and copy it to an
+ * intermediate buffer.
+ */
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE);
+ if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+ return -ETIMEDOUT;
+ }
+ ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+ ctx->vpu_header_size[1]);
+ ctx->vpu_header_size[2] = 0;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ /*
+ * Get VOS in the first frame and copy it to an
+ * intermediate buffer
+ */
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE);
+ if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+ return -ETIMEDOUT;
+ }
+ ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+ ctx->vpu_header_size[0]);
+
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE);
+ if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+ return -ETIMEDOUT;
+ }
+ ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+ ctx->vpu_header_size[1]);
+
+ coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+ coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+ coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE);
+ if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+ v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+ return -ETIMEDOUT;
+ }
+ ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0),
+ ctx->vpu_header_size[2]);
+ break;
+ default:
+ /* No more formats need to save headers at the moment */
+ break;
+ }
+
+ return 0;
+}
+
+static int coda_stop_streaming(struct vb2_queue *q)
+{
+ struct coda_ctx *ctx = vb2_get_drv_priv(q);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%s: output\n", __func__);
+ ctx->rawstreamon = 0;
+ } else {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%s: capture\n", __func__);
+ ctx->compstreamon = 0;
+ }
+
+ if (!ctx->rawstreamon && !ctx->compstreamon) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%s: sent command 'SEQ_END' to coda\n", __func__);
+ if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "CODA_COMMAND_SEQ_END failed\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static struct vb2_ops coda_qops = {
+ .queue_setup = coda_queue_setup,
+ .buf_prepare = coda_buf_prepare,
+ .buf_queue = coda_buf_queue,
+ .wait_prepare = coda_wait_prepare,
+ .wait_finish = coda_wait_finish,
+ .start_streaming = coda_start_streaming,
+ .stop_streaming = coda_stop_streaming,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct coda_ctx *ctx =
+ container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctx->params.bitrate = ctrl->val / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctx->params.gop_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ ctx->params.h264_intra_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ ctx->params.h264_inter_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+ ctx->params.mpeg4_intra_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+ ctx->params.mpeg4_inter_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ ctx->params.slice_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ ctx->params.slice_max_mb = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ break;
+ default:
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "Invalid control, id=%d, val=%d\n",
+ ctrl->id, ctrl->val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops coda_ctrl_ops = {
+ .s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+ v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+ v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 0,
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+ v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+
+ if (ctx->ctrls.error) {
+ v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
+ ctx->ctrls.error);
+ return -EINVAL;
+ }
+
+ return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct coda_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 = &coda_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 = &coda_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int coda_open(struct file *file)
+{
+ struct coda_dev *dev = video_drvdata(file);
+ struct coda_ctx *ctx = NULL;
+ int ret = 0;
+
+ if (dev->instances >= CODA_MAX_INSTANCES)
+ return -EBUSY;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+ ctx->dev = dev;
+
+ set_default_params(ctx);
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+ &coda_queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ int ret = PTR_ERR(ctx->m2m_ctx);
+
+ v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+ ret = coda_ctrls_setup(ctx);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+ goto err;
+ }
+
+ ctx->fh.ctrl_handler = &ctx->ctrls;
+
+ ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
+ CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
+ if (!ctx->parabuf.vaddr) {
+ v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ coda_lock(ctx);
+ ctx->idx = dev->instances++;
+ coda_unlock(ctx);
+
+ clk_prepare_enable(dev->clk_per);
+ clk_prepare_enable(dev->clk_ahb);
+
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+ ctx->idx, ctx);
+
+ return 0;
+
+err:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int coda_release(struct file *file)
+{
+ struct coda_dev *dev = video_drvdata(file);
+ struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+ ctx);
+
+ coda_lock(ctx);
+ dev->instances--;
+ coda_unlock(ctx);
+
+ dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
+ ctx->parabuf.vaddr, ctx->parabuf.paddr);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrls);
+ clk_disable_unprepare(dev->clk_per);
+ clk_disable_unprepare(dev->clk_ahb);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int coda_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+ int ret;
+
+ coda_lock(ctx);
+ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+ coda_unlock(ctx);
+ return ret;
+}
+
+static int coda_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations coda_fops = {
+ .owner = THIS_MODULE,
+ .open = coda_open,
+ .release = coda_release,
+ .poll = coda_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = coda_mmap,
+};
+
+static irqreturn_t coda_irq_handler(int irq, void *data)
+{
+ struct vb2_buffer *src_buf, *dst_buf, *tmp_buf;
+ struct coda_dev *dev = data;
+ u32 wr_ptr, start_ptr;
+ struct coda_ctx *ctx;
+
+ /* read status register to attend the IRQ */
+ coda_read(dev, CODA_REG_BIT_INT_STATUS);
+ coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+ CODA_REG_BIT_INT_CLEAR);
+
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (ctx == NULL) {
+ v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+ return IRQ_HANDLED;
+ }
+
+ if (ctx->aborting) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "task has been aborted\n");
+ return IRQ_HANDLED;
+ }
+
+ if (coda_isbusy(ctx->dev)) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "coda is still busy!!!!\n");
+ return IRQ_NONE;
+ }
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+ /* Get results from the coda */
+ coda_read(dev, CODA_RET_ENC_PIC_TYPE);
+ start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+ wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
+ /* Calculate bytesused field */
+ if (dst_buf->v4l2_buf.sequence == 0) {
+ dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr) +
+ ctx->vpu_header_size[0] +
+ ctx->vpu_header_size[1] +
+ ctx->vpu_header_size[2];
+ } else {
+ dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr);
+ }
+
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+ wr_ptr - start_ptr);
+
+ coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+ coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+ if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+ dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+ } else {
+ dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+ }
+
+ /* Free previous reference picture if available */
+ if (ctx->reference) {
+ v4l2_m2m_buf_done(ctx->reference, VB2_BUF_STATE_DONE);
+ ctx->reference = NULL;
+ }
+
+ /*
+ * For the last frame of the gop we don't need to save
+ * a reference picture.
+ */
+ v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ tmp_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ if (ctx->gopcounter == 0)
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ else
+ ctx->reference = tmp_buf;
+
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+ ctx->gopcounter--;
+ if (ctx->gopcounter < 0)
+ ctx->gopcounter = ctx->params.gop_size - 1;
+
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+ "job finished: encoding frame (%d) (%s)\n",
+ dst_buf->v4l2_buf.sequence,
+ (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+ "KEYFRAME" : "PFRAME");
+
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
+
+ return IRQ_HANDLED;
+}
+
+static u32 coda_supported_firmwares[] = {
+ CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+ if (vernum == coda_supported_firmwares[i])
+ return true;
+ return false;
+}
+
+static char *coda_product_name(int product)
+{
+ static char buf[9];
+
+ switch (product) {
+ case CODA_DX6:
+ return "CodaDx6";
+ default:
+ snprintf(buf, sizeof(buf), "(0x%04x)", product);
+ return buf;
+ }
+}
+
+static int coda_hw_init(struct coda_dev *dev, const struct firmware *fw)
+{
+ u16 product, major, minor, release;
+ u32 data;
+ u16 *p;
+ int i;
+
+ clk_prepare_enable(dev->clk_per);
+ clk_prepare_enable(dev->clk_ahb);
+
+ /* Copy the whole firmware image to the code buffer */
+ memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+ /*
+ * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+ * This memory seems to be big-endian here, which is weird, since
+ * the internal ARM processor of the coda is little endian.
+ * Data in this SRAM survives a reboot.
+ */
+ p = (u16 *)fw->data;
+ for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
+ data = CODA_DOWN_ADDRESS_SET(i) |
+ CODA_DOWN_DATA_SET(p[i ^ 1]);
+ coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+ }
+ release_firmware(fw);
+
+ /* Tell the BIT where to find everything it needs */
+ coda_write(dev, dev->workbuf.paddr,
+ CODA_REG_BIT_WORK_BUF_ADDR);
+ coda_write(dev, dev->codebuf.paddr,
+ CODA_REG_BIT_CODE_BUF_ADDR);
+ coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+ /* Set default values */
+ switch (dev->devtype->product) {
+ case CODA_DX6:
+ coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+ break;
+ default:
+ coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+ }
+ coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+ coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+ CODA_REG_BIT_INT_ENABLE);
+
+ /* Reset VPU and start processor */
+ data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+ data |= CODA_REG_RESET_ENABLE;
+ coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+ udelay(10);
+ data &= ~CODA_REG_RESET_ENABLE;
+ coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+ coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+ /* Load firmware */
+ coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+ coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+ coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+ coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+ coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+ if (coda_wait_timeout(dev)) {
+ clk_disable_unprepare(dev->clk_per);
+ clk_disable_unprepare(dev->clk_ahb);
+ v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+ return -EIO;
+ }
+
+ /* Check we are compatible with the loaded firmware */
+ data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+ product = CODA_FIRMWARE_PRODUCT(data);
+ major = CODA_FIRMWARE_MAJOR(data);
+ minor = CODA_FIRMWARE_MINOR(data);
+ release = CODA_FIRMWARE_RELEASE(data);
+
+ clk_disable_unprepare(dev->clk_per);
+ clk_disable_unprepare(dev->clk_ahb);
+
+ if (product != dev->devtype->product) {
+ v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
+ " Version: %u.%u.%u\n",
+ coda_product_name(dev->devtype->product),
+ coda_product_name(product), major, minor, release);
+ return -EINVAL;
+ }
+
+ v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+ coda_product_name(product));
+
+ if (coda_firmware_supported(data)) {
+ v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+ major, minor, release);
+ } else {
+ v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
+ "%u.%u.%u\n", major, minor, release);
+ }
+
+ return 0;
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+ struct coda_dev *dev = context;
+ struct platform_device *pdev = dev->plat_dev;
+ int ret;
+
+ if (!fw) {
+ v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+ return;
+ }
+
+ /* allocate auxiliary per-device code buffer for the BIT processor */
+ dev->codebuf.size = fw->size;
+ dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
+ &dev->codebuf.paddr,
+ GFP_KERNEL);
+ if (!dev->codebuf.vaddr) {
+ dev_err(&pdev->dev, "failed to allocate code buffer\n");
+ return;
+ }
+
+ ret = coda_hw_init(dev, fw);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+ return;
+ }
+
+ dev->vfd.fops = &coda_fops,
+ dev->vfd.ioctl_ops = &coda_ioctl_ops;
+ dev->vfd.release = video_device_release_empty,
+ dev->vfd.lock = &dev->dev_mutex;
+ dev->vfd.v4l2_dev = &dev->v4l2_dev;
+ snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
+ video_set_drvdata(&dev->vfd, dev);
+
+ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(dev->alloc_ctx)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+ return;
+ }
+
+ dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+ goto rel_ctx;
+ }
+
+ ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto rel_m2m;
+ }
+ v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
+ dev->vfd.num);
+
+ return;
+
+rel_m2m:
+ v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+ char *fw = dev->devtype->firmware;
+
+ dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+ coda_product_name(dev->devtype->product));
+
+ return request_firmware_nowait(THIS_MODULE, true,
+ fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+ CODA_IMX27,
+};
+
+static const struct coda_devtype coda_devdata[] = {
+ [CODA_IMX27] = {
+ .firmware = "v4l-codadx6-imx27.bin",
+ .product = CODA_DX6,
+ .formats = codadx6_formats,
+ .num_formats = ARRAY_SIZE(codadx6_formats),
+ },
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+ { .name = "coda-imx27", .driver_data = CODA_IMX27 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+ { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int __devinit coda_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+ const struct platform_device_id *pdev_id;
+ struct coda_dev *dev;
+ struct resource *res;
+ int ret, irq;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Not enough memory for %s\n",
+ CODA_NAME);
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&dev->irqlock);
+
+ dev->plat_dev = pdev;
+ dev->clk_per = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(dev->clk_per)) {
+ dev_err(&pdev->dev, "Could not get per clock\n");
+ return PTR_ERR(dev->clk_per);
+ }
+
+ dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(dev->clk_ahb)) {
+ dev_err(&pdev->dev, "Could not get ahb clock\n");
+ return PTR_ERR(dev->clk_ahb);
+ }
+
+ /* Get memory for physical registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ if (devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), CODA_NAME) == NULL) {
+ dev_err(&pdev->dev, "failed to request memory region\n");
+ return -ENOENT;
+ }
+ dev->regs_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!dev->regs_base) {
+ dev_err(&pdev->dev, "failed to ioremap address region\n");
+ return -ENOENT;
+ }
+
+ /* IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ return -ENOENT;
+ }
+
+ if (devm_request_irq(&pdev->dev, irq, coda_irq_handler,
+ 0, CODA_NAME, dev) < 0) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return -ENOENT;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ return ret;
+
+ mutex_init(&dev->dev_mutex);
+
+ pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+ if (of_id) {
+ dev->devtype = of_id->data;
+ } else if (pdev_id) {
+ dev->devtype = &coda_devdata[pdev_id->driver_data];
+ } else {
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return -EINVAL;
+ }
+
+ /* allocate auxiliary per-device buffers for the BIT processor */
+ switch (dev->devtype->product) {
+ case CODA_DX6:
+ dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
+ break;
+ default:
+ dev->workbuf.size = CODA7_WORK_BUF_SIZE;
+ }
+ dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
+ &dev->workbuf.paddr,
+ GFP_KERNEL);
+ if (!dev->workbuf.vaddr) {
+ dev_err(&pdev->dev, "failed to allocate work buffer\n");
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+ struct coda_dev *dev = platform_get_drvdata(pdev);
+
+ video_unregister_device(&dev->vfd);
+ if (dev->m2m_dev)
+ v4l2_m2m_release(dev->m2m_dev);
+ if (dev->alloc_ctx)
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ if (dev->codebuf.vaddr)
+ dma_free_coherent(&pdev->dev, dev->codebuf.size,
+ &dev->codebuf.vaddr, dev->codebuf.paddr);
+ if (dev->workbuf.vaddr)
+ dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr,
+ dev->workbuf.paddr);
+ return 0;
+}
+
+static struct platform_driver coda_driver = {
+ .probe = coda_probe,
+ .remove = __devexit_p(coda_remove),
+ .driver = {
+ .name = CODA_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(coda_dt_ids),
+ },
+ .id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
new file mode 100644
index 000000000000..3fbb315c8fbe
--- /dev/null
+++ b/drivers/media/platform/coda.h
@@ -0,0 +1,216 @@
+/*
+ * linux/drivers/media/platform/coda/coda_regs.h
+ *
+ * Copyright (C) 2012 Vista Silicon SL
+ * Javier Martin <javier.martin@vista-silicon.com>
+ * Xavier Duret
+ *
+ * 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.
+ */
+
+#ifndef _REGS_CODA_H_
+#define _REGS_CODA_H_
+
+/* HW registers */
+#define CODA_REG_BIT_CODE_RUN 0x000
+#define CODA_REG_RUN_ENABLE (1 << 0)
+#define CODA_REG_BIT_CODE_DOWN 0x004
+#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16)
+#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff)
+#define CODA_REG_BIT_HOST_IN_REQ 0x008
+#define CODA_REG_BIT_INT_CLEAR 0x00c
+#define CODA_REG_BIT_INT_CLEAR_SET 0x1
+#define CODA_REG_BIT_INT_STATUS 0x010
+#define CODA_REG_BIT_CODE_RESET 0x014
+#define CODA_REG_RESET_ENABLE (1 << 0)
+#define CODA_REG_BIT_CUR_PC 0x018
+
+/* Static SW registers */
+#define CODA_REG_BIT_CODE_BUF_ADDR 0x100
+#define CODA_REG_BIT_WORK_BUF_ADDR 0x104
+#define CODA_REG_BIT_PARA_BUF_ADDR 0x108
+#define CODA_REG_BIT_STREAM_CTRL 0x10c
+#define CODA7_STREAM_BUF_PIC_RESET (1 << 4)
+#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3)
+#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3)
+#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2)
+#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5)
+#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4)
+#define CODA_STREAM_CHKDIS_OFFSET (1 << 1)
+#define CODA_STREAM_ENDIAN_SELECT (1 << 0)
+#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110
+#define CODA_IMAGE_ENDIAN_SELECT (1 << 0)
+#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x))
+#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x))
+#define CODA_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140
+#define CODA_REG_BIT_BUSY 0x160
+#define CODA_REG_BIT_BUSY_FLAG 1
+#define CODA_REG_BIT_RUN_COMMAND 0x164
+#define CODA_COMMAND_SEQ_INIT 1
+#define CODA_COMMAND_SEQ_END 2
+#define CODA_COMMAND_PIC_RUN 3
+#define CODA_COMMAND_SET_FRAME_BUF 4
+#define CODA_COMMAND_ENCODE_HEADER 5
+#define CODA_COMMAND_ENC_PARA_SET 6
+#define CODA_COMMAND_DEC_PARA_SET 7
+#define CODA_COMMAND_DEC_BUF_FLUSH 8
+#define CODA_COMMAND_RC_CHANGE_PARAMETER 9
+#define CODA_COMMAND_FIRMWARE_GET 0xf
+#define CODA_REG_BIT_RUN_INDEX 0x168
+#define CODA_INDEX_SET(x) ((x) & 0x3)
+#define CODA_REG_BIT_RUN_COD_STD 0x16c
+#define CODADX6_MODE_DECODE_MP4 0
+#define CODADX6_MODE_ENCODE_MP4 1
+#define CODADX6_MODE_DECODE_H264 2
+#define CODADX6_MODE_ENCODE_H264 3
+#define CODA7_MODE_DECODE_H264 0
+#define CODA7_MODE_DECODE_VC1 1
+#define CODA7_MODE_DECODE_MP2 2
+#define CODA7_MODE_DECODE_MP4 3
+#define CODA7_MODE_DECODE_DV3 3
+#define CODA7_MODE_DECODE_RV 4
+#define CODA7_MODE_DECODE_MJPG 5
+#define CODA7_MODE_ENCODE_H264 8
+#define CODA7_MODE_ENCODE_MP4 11
+#define CODA7_MODE_ENCODE_MJPG 13
+#define CODA_MODE_INVALID 0xffff
+#define CODA_REG_BIT_INT_ENABLE 0x170
+#define CODA_INT_INTERRUPT_ENABLE (1 << 3)
+
+/*
+ * Commands' mailbox:
+ * registers with offsets in the range 0x180-0x1d0
+ * have different meaning depending on the command being
+ * issued.
+ */
+
+/* Encoder Sequence Initialization */
+#define CODA_CMD_ENC_SEQ_BB_START 0x180
+#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184
+#define CODA_CMD_ENC_SEQ_OPTION 0x188
+#define CODA_OPTION_GAMMA_OFFSET 7
+#define CODA_OPTION_GAMMA_MASK 0x01
+#define CODA_OPTION_LIMITQP_OFFSET 6
+#define CODA_OPTION_LIMITQP_MASK 0x01
+#define CODA_OPTION_RCINTRAQP_OFFSET 5
+#define CODA_OPTION_RCINTRAQP_MASK 0x01
+#define CODA_OPTION_FMO_OFFSET 4
+#define CODA_OPTION_FMO_MASK 0x01
+#define CODA_OPTION_SLICEREPORT_OFFSET 1
+#define CODA_OPTION_SLICEREPORT_MASK 0x01
+#define CODA_CMD_ENC_SEQ_COD_STD 0x18c
+#define CODA_STD_MPEG4 0
+#define CODA_STD_H263 1
+#define CODA_STD_H264 2
+#define CODA_STD_MJPG 3
+#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190
+#define CODA7_PICWIDTH_OFFSET 16
+#define CODA7_PICWIDTH_MASK 0xffff
+#define CODADX6_PICWIDTH_OFFSET 10
+#define CODADX6_PICWIDTH_MASK 0x3ff
+#define CODA_PICHEIGHT_OFFSET 0
+#define CODA_PICHEIGHT_MASK 0x3ff
+#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194
+#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198
+#define CODA_MP4PARAM_VERID_OFFSET 6
+#define CODA_MP4PARAM_VERID_MASK 0x01
+#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2
+#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07
+#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1
+#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01
+#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0
+#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01
+#define CODA_CMD_ENC_SEQ_263_PARA 0x19c
+#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2
+#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01
+#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1
+#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01
+#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0
+#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01
+#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0
+#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12
+#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f
+#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8
+#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f
+#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6
+#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01
+#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5
+#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01
+#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0
+#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f
+#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4
+#define CODA_SLICING_SIZE_OFFSET 2
+#define CODA_SLICING_SIZE_MASK 0x3fffffff
+#define CODA_SLICING_UNIT_OFFSET 1
+#define CODA_SLICING_UNIT_MASK 0x01
+#define CODA_SLICING_MODE_OFFSET 0
+#define CODA_SLICING_MODE_MASK 0x01
+#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8
+#define CODA_GOP_SIZE_OFFSET 0
+#define CODA_GOP_SIZE_MASK 0x3f
+#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac
+#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31
+#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01
+#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16
+#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f
+#define CODA_RATECONTROL_BITRATE_OFFSET 1
+#define CODA_RATECONTROL_BITRATE_MASK 0x7f
+#define CODA_RATECONTROL_ENABLE_OFFSET 0
+#define CODA_RATECONTROL_ENABLE_MASK 0x01
+#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0
+#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4
+#define CODA_CMD_ENC_SEQ_FMO 0x1b8
+#define CODA_FMOPARAM_TYPE_OFFSET 4
+#define CODA_FMOPARAM_TYPE_MASK 1
+#define CODA_FMOPARAM_SLICENUM_OFFSET 0
+#define CODA_FMOPARAM_SLICENUM_MASK 0x0f
+#define CODA_CMD_ENC_SEQ_RC_QP_MAX 0x1c8
+#define CODA_QPMAX_OFFSET 0
+#define CODA_QPMAX_MASK 0x3f
+#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc
+#define CODA_GAMMA_OFFSET 0
+#define CODA_GAMMA_MASK 0xffff
+#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0
+
+/* Encoder Picture Run */
+#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188
+#define CODA_CMD_ENC_PIC_QS 0x18c
+#define CODA_CMD_ENC_PIC_ROT_MODE 0x190
+#define CODA_CMD_ENC_PIC_OPTION 0x194
+#define CODA_CMD_ENC_PIC_BB_START 0x198
+#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c
+#define CODA_RET_ENC_PIC_TYPE 0x1c4
+#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc
+#define CODA_RET_ENC_PIC_FLAG 0x1d0
+
+/* Set Frame Buffer */
+#define CODA_CMD_SET_FRAME_BUF_NUM 0x180
+#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184
+
+/* Encoder Header */
+#define CODA_CMD_ENC_HEADER_CODE 0x180
+#define CODA_GAMMA_OFFSET 0
+#define CODA_HEADER_H264_SPS 0
+#define CODA_HEADER_H264_PPS 1
+#define CODA_HEADER_MP4V_VOL 0
+#define CODA_HEADER_MP4V_VOS 1
+#define CODA_HEADER_MP4V_VIS 2
+#define CODA_CMD_ENC_HEADER_BB_START 0x184
+#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188
+
+/* Get Version */
+#define CODA_CMD_FIRMWARE_VERNUM 0x1c0
+#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff)
+#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f)
+#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f)
+#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff)
+#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \
+ ((product) << 16 | ((major) << 12) | \
+ ((minor) << 8) | (release))
+
+#endif
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
new file mode 100644
index 000000000000..78e26d24f637
--- /dev/null
+++ b/drivers/media/platform/davinci/Kconfig
@@ -0,0 +1,121 @@
+config VIDEO_DAVINCI_VPIF_DISPLAY
+ tristate "DM646x/DA850/OMAPL138 EVM Video Display"
+ depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Enables Davinci VPIF module used for display devices.
+ This module is common for following DM6467/DA850/OMAPL138
+ based display devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_display.
+
+config VIDEO_DAVINCI_VPIF_CAPTURE
+ tristate "DM646x/DA850/OMAPL138 EVM Video Capture"
+ depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ help
+ Enables Davinci VPIF module used for captur devices.
+ This module is common for following DM6467/DA850/OMAPL138
+ based capture devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+ tristate "DaVinci VPIF Driver"
+ depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE
+ help
+ Support for DaVinci VPIF Driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+ tristate "VPSS System module driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+ tristate "VPFE Video Capture Driver"
+ depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+ depends on I2C
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for DMx/AMx VPFE based frame grabber. This is the
+ common V4L2 module for following DMx/AMx SoCs from Texas
+ Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+ tristate "DM6446 CCDC HW module"
+ depends on VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from slave decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+ tristate "DM355 CCDC HW module"
+ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from a slave decoders
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_ISIF
+ tristate "ISIF HW module"
+ depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables ISIF hw module. This is the hardware module for
+ configuring ISIF in VPFE to capture Raw Bayer RGB data from
+ a image sensor or YUV data from a YUV source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM644X_VPBE
+ tristate "DM644X VPBE HW module"
+ depends on ARCH_DAVINCI_DM644x
+ select VIDEO_VPSS_SYSTEM
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Enables VPBE modules used for display on a DM644x
+ SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpbe.
+
+
+config VIDEO_VPBE_DISPLAY
+ tristate "VPBE V4L2 Display driver"
+ depends on ARCH_DAVINCI_DM644x
+ select VIDEO_DM644X_VPBE
+ help
+ Enables VPBE V4L2 Display driver on a DM644x device
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpbe_display.
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/platform/davinci/Makefile
index 74ed92d09257..74ed92d09257 100644
--- a/drivers/media/video/davinci/Makefile
+++ b/drivers/media/platform/davinci/Makefile
diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/platform/davinci/ccdc_hw_device.h
index 86b9b3518965..86b9b3518965 100644
--- a/drivers/media/video/davinci/ccdc_hw_device.h
+++ b/drivers/media/platform/davinci/ccdc_hw_device.h
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
new file mode 100644
index 000000000000..ce0e4131c067
--- /dev/null
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * CCDC hardware module for DM355
+ * ------------------------------
+ *
+ * This module is for configuring DM355 CCD controller of VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application include dm355_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 2) Split module parameter structure to module specific ioctl structs
+ * 3) add support for lense shading correction
+ * 4) investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <media/davinci/dm355_ccdc.h>
+#include <media/davinci/vpss.h>
+
+#include "dm355_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM355");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct ccdc_oper_config {
+ struct device *dev;
+ /* CCDC interface type */
+ enum vpfe_hw_if_type if_type;
+ /* Raw Bayer configuration */
+ struct ccdc_params_raw bayer;
+ /* YCbCr configuration */
+ struct ccdc_params_ycbcr ycbcr;
+ /* Master clock */
+ struct clk *mclk;
+ /* slave clock */
+ struct clk *sclk;
+ /* ccdc base address */
+ void __iomem *base_addr;
+} ccdc_cfg = {
+ /* Raw configurations */
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = 256,
+ .gb_g = 256,
+ .gr_cy = 256,
+ .b_mg = 256
+ },
+ .config_params = {
+ .datasft = 2,
+ .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
+ .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
+ .alaw = {
+ .gama_wd = 2,
+ },
+ .blk_clamp = {
+ .sample_pixel = 1,
+ .dc_sub = 25
+ },
+ .col_pat_field0 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ .col_pat_field1 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ },
+ },
+ /* YCbCr configuration */
+ .ycbcr = {
+ .win = CCDC_WIN_PAL,
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+ },
+};
+
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_cfg.base_addr + offset);
+}
+
+static void ccdc_enable(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
+ temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_enable_output_to_sdram(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~(CCDC_SYNCEN_WEN_MASK));
+ temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_config_gain_offset(void)
+{
+ /* configure gain */
+ regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
+ regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
+ regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
+ regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
+ /* configure offset */
+ regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function restore power on defaults in the ccdc registers
+ */
+static int ccdc_restore_defaults(void)
+{
+ int i;
+
+ dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
+ /* set all registers to zero */
+ for (i = 0; i <= CCDC_REG_LAST; i += 4)
+ regw(0, i);
+
+ /* now override the values with power on defaults in registers */
+ regw(MODESET_DEFAULT, MODESET);
+ /* no culling support */
+ regw(CULH_DEFAULT, CULH);
+ regw(CULV_DEFAULT, CULV);
+ /* Set default Gain and Offset */
+ ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
+ ccdc_config_gain_offset();
+ regw(OUTCLIP_DEFAULT, OUTCLIP);
+ regw(LSCCFG2_DEFAULT, LSCCFG2);
+ /* select ccdc input */
+ if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
+ dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
+ return -EFAULT;
+ }
+ /* select ccdc clock */
+ if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
+ dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
+ return -EFAULT;
+ }
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
+ return 0;
+}
+
+static int ccdc_open(struct device *device)
+{
+ return ccdc_restore_defaults();
+}
+
+static int ccdc_close(struct device *device)
+{
+ /* disable clock */
+ vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
+ /* do nothing for now */
+ return 0;
+}
+/*
+ * ccdc_setwin()
+ * This function will configure the window size to
+ * be capture in CCDC reg.
+ */
+static void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt, int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int mid_img = 0;
+
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
+
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+ /* Writing the horizontal info into the registers */
+ regw(horz_start, SPH);
+ regw(horz_nr_pixels, NPH);
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 and VDINT1 */
+ regw(vert_start, VDINT0);
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /* configure VDINT0 and VDINT1 */
+ mid_img = vert_start + (image_win->height / 2);
+ regw(vert_start, VDINT0);
+ regw(mid_img, VDINT1);
+ }
+ regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
+ regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
+ regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
+ ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
+ dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
+ ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
+ dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
+ ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
+ dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n");
+ return -EINVAL;
+ }
+
+ if ((ccdcparam->med_filt_thres < 0) ||
+ (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of median filter threshold\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
+ ccdcparam->data_sz > CCDC_DATA_8BITS) {
+ dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->alaw.enable) {
+ if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
+ ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
+ dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
+ return -EINVAL;
+ }
+ }
+
+ if (ccdcparam->blk_clamp.b_clamp_enable) {
+ if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
+ ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of sample pixel\n");
+ return -EINVAL;
+ }
+ if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
+ ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of sample lines\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ /* only raw module parameters can be set through the IOCTL */
+ if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc"
+ "params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ memcpy(&ccdc_cfg.bayer.config_params,
+ &ccdc_raw_params,
+ sizeof(ccdc_raw_params));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* This function will configure CCDC for YCbCr video capture */
+static void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
+ u32 temp;
+
+ /* first set the CCDC power on defaults values in all registers */
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
+ ccdc_restore_defaults();
+
+ /* configure pixel format & video frame format */
+ temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
+ CCDC_INPUT_MODE_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
+ CCDC_FRM_FMT_SHIFT));
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, REC656IF);
+ /*
+ * configure the FID, VD, HD pin polarity fld,hd pol positive,
+ * vd negative, 8-bit pack mode
+ */
+ temp |= CCDC_VD_POL_NEGATIVE;
+ } else { /* y/c external sync mode */
+ temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+
+ /* pack the data to 8-bit */
+ temp |= CCDC_DATA_PACK_ENABLE;
+
+ regw(temp, MODESET);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /* configure the order of y cb cr in SD-RAM */
+ temp = (params->pix_order << CCDC_Y8POS_SHIFT);
+ temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
+ regw(temp, CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This is done by rounding up
+ * width to a multiple of 16 pixels and multiply by two to account for
+ * y:cb:cr 4:2:2 data
+ */
+ regw(((params->win.width * 2 + 31) >> 5), HSIZE);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
+ }
+
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+/*
+ * ccdc_config_black_clamp()
+ * configure parameters for Optical Black Clamp
+ */
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->b_clamp_enable) {
+ /* configure DCSub */
+ regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
+ regw(0x0000, CLAMP);
+ return;
+ }
+ /* Enable the Black clamping, set sample lines and pixels */
+ val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
+ regw(val, CLAMP);
+
+ /* If Black clamping is enable then make dcsub 0 */
+ val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
+ << CCDC_NUM_LINE_CALC_SHIFT;
+ regw(val, DCSUB);
+}
+
+/*
+ * ccdc_config_black_compense()
+ * configure parameters for Black Compensation
+ */
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = (bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT);
+ regw(val, BLKCMP1);
+
+ val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT);
+ regw(val, BLKCMP0);
+}
+
+/*
+ * ccdc_write_dfc_entry()
+ * write an entry in the dfc table.
+ */
+int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+{
+/* TODO This is to be re-visited and adjusted */
+#define DFC_WRITE_WAIT_COUNT 1000
+ u32 val, count = DFC_WRITE_WAIT_COUNT;
+
+ regw(dfc->dft_corr_vert[index], DFCMEM0);
+ regw(dfc->dft_corr_horz[index], DFCMEM1);
+ regw(dfc->dft_corr_sub1[index], DFCMEM2);
+ regw(dfc->dft_corr_sub2[index], DFCMEM3);
+ regw(dfc->dft_corr_sub3[index], DFCMEM4);
+ /* set WR bit to write */
+ val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
+ regw(val, DFCMEMCTL);
+
+ /*
+ * Assume, it is very short. If we get an error, we need to
+ * adjust this value
+ */
+ while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
+ count--;
+ /*
+ * TODO We expect the count to be non-zero to be successful. Adjust
+ * the count if write requires more time
+ */
+
+ if (count) {
+ dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * ccdc_config_vdfc()
+ * configure parameters for Vertical Defect Correction
+ */
+static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
+{
+ u32 val;
+ int i;
+
+ /* Configure General Defect Correction. The table used is from IPIPE */
+ val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
+
+ /* Configure Vertical Defect Correction if needed */
+ if (!dfc->ver_dft_en) {
+ /* Enable only General Defect Correction */
+ regw(val, DFCCTL);
+ return 0;
+ }
+
+ if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
+ return -EINVAL;
+
+ val |= CCDC_DFCCTL_VDFC_DISABLE;
+ val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
+ CCDC_DFCCTL_VDFCSL_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
+ CCDC_DFCCTL_VDFCUDA_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
+ CCDC_DFCCTL_VDFLSFT_SHIFT;
+ regw(val , DFCCTL);
+
+ /* clear address ptr to offset 0 */
+ val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
+
+ /* write defect table entries */
+ for (i = 0; i < dfc->table_size; i++) {
+ /* increment address for non zero index */
+ if (i != 0)
+ val = CCDC_DFCMEMCTL_INC_ADDR;
+ regw(val, DFCMEMCTL);
+ if (ccdc_write_dfc_entry(i, dfc) < 0)
+ return -EFAULT;
+ }
+
+ /* update saturation level and enable dfc */
+ regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
+ val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
+ CCDC_DFCCTL_VDFCEN_SHIFT);
+ regw(val, DFCCTL);
+ return 0;
+}
+
+/*
+ * ccdc_config_csc()
+ * configure parameters for color space conversion
+ * Each register CSCM0-7 has two values in S8Q5 format.
+ */
+static void ccdc_config_csc(struct ccdc_csc *csc)
+{
+ u32 val1, val2;
+ int i;
+
+ if (!csc->enable)
+ return;
+
+ /* Enable the CSC sub-module */
+ regw(CCDC_CSC_ENABLE, CSCCTL);
+
+ /* Converting the co-eff as per the format of the register */
+ for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
+ if ((i % 2) == 0) {
+ /* CSCM - LSB */
+ val1 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ /*
+ * convert decimal part to binary. Use 2 decimal
+ * precision, user values range from .00 - 0.99
+ */
+ val1 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ } else {
+
+ /* CSCM - MSB */
+ val2 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ val2 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ val2 <<= CCDC_CSCM_MSB_SHIFT;
+ val2 |= val1;
+ regw(val2, (CSCM0 + ((i - 1) << 1)));
+ }
+ }
+}
+
+/*
+ * ccdc_config_color_patterns()
+ * configure parameters for color patterns
+ */
+static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
+ struct ccdc_col_pat *pat1)
+{
+ u32 val;
+
+ val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
+ (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
+ (pat1->elop << 12) | (pat1->elep << 14));
+ regw(val, COLPTN);
+}
+
+/* This function will configure CCDC for Raw mode image capture */
+static int ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_cfg.bayer;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int val;
+
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
+
+ /* restore power on defaults to register */
+ ccdc_restore_defaults();
+
+ /* CCDCFG register:
+ * set CCD Not to swap input since input is RAW data
+ * set FID detection function to Latch at V-Sync
+ * set WENLOG - ccdc valid area to AND
+ * set TRGSEL to WENBIT
+ * set EXTRG to DISABLE
+ * disable latching function on VSYNC - shadowed registers
+ */
+ regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
+ CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
+ CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
+
+ /*
+ * Set VDHD direction to input, input type to raw input
+ * normal data polarity, do not use external WEN
+ */
+ val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
+ CCDC_EXWEN_DISABLE);
+
+ /*
+ * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
+ * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
+ * frame format(progressive or interlace), & pixel format (Input mode)
+ */
+ val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
+
+ /* set pack for alaw compression */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ val |= CCDC_DATA_PACK_ENABLE;
+
+ /* Configure for LPF */
+ if (config_params->lpf_enable)
+ val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
+ CCDC_LPF_SHIFT;
+
+ /* Configure the data shift */
+ val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
+ CCDC_DATASFT_SHIFT;
+ regw(val , MODESET);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
+
+ /* Configure the Median Filter threshold */
+ regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
+
+ /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
+ val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
+ CCDC_CFA_MOSAIC;
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val |= (CCDC_ALAW_ENABLE |
+ ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) <<
+ CCDC_GAMMAWD_INPUT_SHIFT));
+ }
+
+ /* Configure Median filter1 & filter2 */
+ val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
+ (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
+
+ regw(val, GAMMAWD);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 1);
+
+ /* Optical Clamp Averaging */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Vertical Defect Correction if needed */
+ if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
+ return -EFAULT;
+
+ /* color space conversion */
+ ccdc_config_csc(&config_params->csc);
+
+ /* color pattern */
+ ccdc_config_color_patterns(&config_params->col_pat_field0,
+ &config_params->col_pat_field1);
+
+ /* Configure the Gain & offset control */
+ ccdc_config_gain_offset();
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
+
+ /* Configure DATAOFST register */
+ val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_H_SHIFT;
+ val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_V_SHIFT;
+ regw(val, DATAOFST);
+
+ /* configuring HSIZE register */
+ val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
+ CCDC_HSIZE_FLIP_SHIFT;
+
+ /* If pack 8 is enable then 1 pixel will take 1 byte */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable) {
+ val |= (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ /* adjust to multiple of 32 */
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ } else {
+ /* else one pixel will take 2 byte */
+ val |= (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ }
+ regw(val, HSIZE);
+
+ /* Configure SDOFST register */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For interlace inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_INVERSE);
+ } else {
+ /* For interlace non inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_NORMAL);
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ if (params->image_invert_enable) {
+ /* For progessive inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_INVERSE);
+ } else {
+ /* For progessive non inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_NORMAL);
+ }
+ }
+ dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
+ return 0;
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.buf_type = buf_type;
+ else
+ ccdc_cfg.ycbcr.buf_type = buf_type;
+ return 0;
+}
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.buf_type;
+ return ccdc_cfg.ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ alaw->enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.win = *win;
+ else
+ ccdc_cfg.ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ *win = ccdc_cfg.bayer.win;
+ else
+ *win = ccdc_cfg.ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int len;
+
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_cfg.bayer.win.width;
+ else
+ len = ccdc_cfg.bayer.win.width * 2;
+ } else
+ len = ccdc_cfg.ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.frm_fmt = frm_fmt;
+ else
+ ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.frm_fmt;
+ else
+ return ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(MODESET) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw((addr >> 21) & 0x007f, STADRH);
+ regw((addr >> 5) & 0x0ffff, STADRL);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_cfg.if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+ ccdc_cfg.ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM355 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .enable = ccdc_enable,
+ .enable_out_to_sdram = ccdc_enable_output_to_sdram,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int __devinit dm355_ccdc_probe(struct platform_device *pdev)
+{
+ void (*setup_pinmux)(void);
+ struct resource *res;
+ int status = 0;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+ if (status < 0)
+ return status;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nores;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nores;
+ }
+
+ ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ if (!ccdc_cfg.base_addr) {
+ status = -ENOMEM;
+ goto fail_nomem;
+ }
+
+ /* Get and enable Master clock */
+ ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(ccdc_cfg.mclk)) {
+ status = PTR_ERR(ccdc_cfg.mclk);
+ goto fail_nomap;
+ }
+ if (clk_enable(ccdc_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Get and enable Slave clock */
+ ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+ if (IS_ERR(ccdc_cfg.sclk)) {
+ status = PTR_ERR(ccdc_cfg.sclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(ccdc_cfg.sclk)) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+
+ /* Platform data holds setup_pinmux function ptr */
+ if (NULL == pdev->dev.platform_data) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+ setup_pinmux = pdev->dev.platform_data;
+ /*
+ * setup Mux configuration for ccdc which may be different for
+ * different SoCs using this CCDC
+ */
+ setup_pinmux();
+ ccdc_cfg.dev = &pdev->dev;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
+ return 0;
+fail_sclk:
+ clk_put(ccdc_cfg.sclk);
+fail_mclk:
+ clk_put(ccdc_cfg.mclk);
+fail_nomap:
+ iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+ release_mem_region(res->start, resource_size(res));
+fail_nores:
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return status;
+}
+
+static int dm355_ccdc_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ clk_put(ccdc_cfg.mclk);
+ clk_put(ccdc_cfg.sclk);
+ iounmap(ccdc_cfg.base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return 0;
+}
+
+static struct platform_driver dm355_ccdc_driver = {
+ .driver = {
+ .name = "dm355_ccdc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(dm355_ccdc_remove),
+ .probe = dm355_ccdc_probe,
+};
+
+module_platform_driver(dm355_ccdc_driver);
diff --git a/drivers/media/video/davinci/dm355_ccdc_regs.h b/drivers/media/platform/davinci/dm355_ccdc_regs.h
index d6d2ef0533b5..d6d2ef0533b5 100644
--- a/drivers/media/video/davinci/dm355_ccdc_regs.h
+++ b/drivers/media/platform/davinci/dm355_ccdc_regs.h
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
new file mode 100644
index 000000000000..ee7942b1996e
--- /dev/null
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * CCDC hardware module for DM6446
+ * ------------------------------
+ *
+ * This module is for configuring CCD controller of DM6446 VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters. This file is named DM644x so that other
+ * variants such DM6443 may be supported using the same module.
+ *
+ * TODO: Test Raw bayer parameter settings and bayer capture
+ * Split module parameter structure to module specific ioctl structs
+ * investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <linux/gfp.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <media/davinci/dm644x_ccdc.h>
+#include <media/davinci/vpss.h>
+
+#include "dm644x_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM6446");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct ccdc_oper_config {
+ struct device *dev;
+ /* CCDC interface type */
+ enum vpfe_hw_if_type if_type;
+ /* Raw Bayer configuration */
+ struct ccdc_params_raw bayer;
+ /* YCbCr configuration */
+ struct ccdc_params_ycbcr ycbcr;
+ /* Master clock */
+ struct clk *mclk;
+ /* slave clock */
+ struct clk *sclk;
+ /* ccdc base address */
+ void __iomem *base_addr;
+} ccdc_cfg = {
+ /* Raw configurations */
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .config_params = {
+ .data_sz = CCDC_DATA_10BITS,
+ },
+ },
+ .ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = CCDC_WIN_PAL,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+ },
+};
+
+#define CCDC_MAX_RAW_YUV_FORMATS 2
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* CCDC Save/Restore context */
+static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_cfg.base_addr + offset);
+}
+
+static void ccdc_enable(int flag)
+{
+ regw(flag, CCDC_PCR);
+}
+
+static void ccdc_enable_vport(int flag)
+{
+ if (flag)
+ /* enable video port */
+ regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
+ else
+ regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
+}
+
+/*
+ * ccdc_setwin()
+ * This function will configure the window size
+ * to be capture in CCDC reg
+ */
+void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt,
+ int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int val = 0, mid_img = 0;
+
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
+ regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
+ CCDC_HORZ_INFO);
+
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 */
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
+ regw(val, CCDC_VDINT);
+
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /*
+ * configure VDINT0 and VDINT1. VDINT1 will be at half
+ * of image height
+ */
+ mid_img = vert_start + (image_win->height / 2);
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
+ (mid_img & CCDC_VDINT_VDINT1_MASK);
+ regw(val, CCDC_VDINT);
+
+ }
+ regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
+ CCDC_VERT_START);
+ regw(vert_nr_lines, CCDC_VERT_LINES);
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
+}
+
+static void ccdc_readregs(void)
+{
+ unsigned int val = 0;
+
+ val = regr(CCDC_ALAW);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
+ val = regr(CCDC_CLAMP);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
+ val = regr(CCDC_DCSUB);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
+ val = regr(CCDC_BLKCMP);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
+ val = regr(CCDC_FPC_ADDR);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
+ val = regr(CCDC_FPC);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
+ val = regr(CCDC_FMTCFG);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
+ val = regr(CCDC_COLPTN);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
+ val = regr(CCDC_FMT_HORZ);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
+ val = regr(CCDC_FMT_VERT);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
+ val = regr(CCDC_HSIZE_OFF);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
+ val = regr(CCDC_SDOFST);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
+ val = regr(CCDC_VP_OUT);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
+ val = regr(CCDC_SYN_MODE);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
+ val = regr(CCDC_HORZ_INFO);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
+ val = regr(CCDC_VERT_START);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
+ val = regr(CCDC_VERT_LINES);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->alaw.enable) {
+ if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
+ (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
+ (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
+ dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int *fpc_virtaddr = NULL;
+ unsigned int *fpc_physaddr = NULL;
+
+ memcpy(config_params, raw_params, sizeof(*raw_params));
+ /*
+ * allocate memory for fault pixel table and copy the user
+ * values to the table
+ */
+ if (!config_params->fault_pxl.enable)
+ return 0;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+ fpc_virtaddr = (unsigned int *)phys_to_virt(
+ (unsigned long)fpc_physaddr);
+ /*
+ * Allocate memory for FPC table if current
+ * FPC table buffer is not big enough to
+ * accommodate FPC Number requested
+ */
+ if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
+ if (fpc_physaddr != NULL) {
+ free_pages((unsigned long)fpc_physaddr,
+ get_order
+ (config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+
+ /* Allocate memory for FPC table */
+ fpc_virtaddr =
+ (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
+ get_order(raw_params->
+ fault_pxl.fp_num *
+ FP_NUM_BYTES));
+
+ if (fpc_virtaddr == NULL) {
+ dev_dbg(ccdc_cfg.dev,
+ "\nUnable to allocate memory for FPC");
+ return -EFAULT;
+ }
+ fpc_physaddr =
+ (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
+ }
+
+ /* Copy number of fault pixels and FPC table */
+ config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
+ if (copy_from_user(fpc_virtaddr,
+ (void __user *)raw_params->fault_pxl.fpc_table_addr,
+ config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
+ dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
+ return -EFAULT;
+ }
+ config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+ return 0;
+}
+
+static int ccdc_close(struct device *dev)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+
+ if (fpc_physaddr != NULL) {
+ fpc_virtaddr = (unsigned int *)
+ phys_to_virt((unsigned long)fpc_physaddr);
+ free_pages((unsigned long)fpc_virtaddr,
+ get_order(config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+ return 0;
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function will write defaults to all CCDC registers
+ */
+static void ccdc_restore_defaults(void)
+{
+ int i;
+
+ /* disable CCDC */
+ ccdc_enable(0);
+ /* set all registers to default value */
+ for (i = 4; i <= 0x94; i += 4)
+ regw(0, i);
+ regw(CCDC_NO_CULLING, CCDC_CULLING);
+ regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
+}
+
+static int ccdc_open(struct device *device)
+{
+ ccdc_restore_defaults();
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_enable_vport(1);
+ return 0;
+}
+
+static void ccdc_sbl_reset(void)
+{
+ vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"
+ "ccdc params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ if (!ccdc_update_raw_params(&ccdc_raw_params))
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * ccdc_config_ycbcr()
+ * This function will configure CCDC for YCbCr video capture
+ */
+void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
+ u32 syn_mode;
+
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
+ /*
+ * first restore the CCDC registers to default values
+ * This is important since we assume default values to be set in
+ * a lot of registers that we didn't touch
+ */
+ ccdc_restore_defaults();
+
+ /*
+ * configure pixel format, frame format, configure video frame
+ * format, enable output to SDRAM, enable internal timing generator
+ * and 8bit pack mode
+ */
+ syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
+ CCDC_SYN_MODE_INPMOD_SHIFT) |
+ ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
+ CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
+ CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
+
+ /*
+ * configure the FID, VD, HD pin polarity,
+ * fld,hd pol positive, vd negative, 8-bit data
+ */
+ syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
+ if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+ syn_mode |= CCDC_SYN_MODE_10BITS;
+ else
+ syn_mode |= CCDC_SYN_MODE_8BITS;
+ } else {
+ /* y/c external sync mode */
+ syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+ regw(syn_mode, CCDC_SYN_MODE);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /*
+ * configure the order of y cb cr in SDRAM, and disable latch
+ * internal register on vsync
+ */
+ if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
+ regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+ CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
+ CCDC_CCDCFG);
+ else
+ regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+ CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This should be a
+ * on 32 byte boundary. So clear LSB 5 bits
+ */
+ regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
+
+ ccdc_sbl_reset();
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->enable) {
+ /* configure DCSub */
+ val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
+ regw(val, CCDC_DCSUB);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
+ regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
+ return;
+ }
+ /*
+ * Configure gain, Start pixel, No of line to be avg,
+ * No of pixel/line to be avg, & Enable the Black clamping
+ */
+ val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
+ ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
+ CCDC_BLK_ST_PXL_SHIFT) |
+ ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
+ CCDC_BLK_SAMPLE_LINE_SHIFT) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
+ regw(val, CCDC_CLAMP);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
+ /* If Black clamping is enable then make dcsub 0 */
+ regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
+}
+
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT) |
+ ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT));
+ regw(val, CCDC_BLKCMP);
+}
+
+static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
+{
+ u32 val;
+
+ /* Initially disable FPC */
+ val = CCDC_FPC_DISABLE;
+ regw(val, CCDC_FPC);
+
+ if (!fpc->enable)
+ return;
+
+ /* Configure Fault pixel if needed */
+ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
+ (fpc->fpc_table_addr));
+ /* Write the FPC params with FPC disable */
+ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
+ regw(val, CCDC_FPC);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
+ /* read the FPC register */
+ val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
+ regw(val, CCDC_FPC);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
+}
+
+/*
+ * ccdc_config_raw()
+ * This function will configure CCDC for Raw capture mode
+ */
+void ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_cfg.bayer;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int syn_mode = 0;
+ unsigned int val;
+
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
+
+ /* Reset CCDC */
+ ccdc_restore_defaults();
+
+ /* Disable latching function registers on VSYNC */
+ regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(SYN_MODE.VDPOL),
+ * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
+ * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
+ * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
+ * SDRAM, enable internal timing generator
+ */
+ syn_mode =
+ (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
+ CCDC_DATA_SZ_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
+ CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val = ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
+ regw(val, CCDC_ALAW);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
+ }
+
+ /* Configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
+
+ /* Configure Black Clamp */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Configure Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Configure Fault Pixel Correction */
+ ccdc_config_fpc(&config_params->fault_pxl);
+
+ /* If data size is 8 bit then pack the data */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ syn_mode |= CCDC_DATA_PACK_ENABLE;
+
+#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
+ /* enable video port */
+ val = CCDC_ENABLE_VIDEO_PORT;
+#else
+ /* disable video port */
+ val = CCDC_DISABLE_VIDEO_PORT;
+#endif
+
+ if (config_params->data_sz == CCDC_DATA_8BITS)
+ val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ else
+ val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ /* Write value in FMTCFG */
+ regw(val, CCDC_FMTCFG);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
+ /* Configure the color pattern according to mt9t001 sensor */
+ regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
+ /*
+ * Configure Data formatter(Video port) pixel selection
+ * (FMT_HORZ, FMT_VERT)
+ */
+ val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
+ CCDC_FMT_HORZ_FMTSPH_SHIFT) |
+ (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
+ regw(val, CCDC_FMT_HORZ);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
+ val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
+ << CCDC_FMT_VERT_FMTSLV_SHIFT;
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
+ else
+ val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
+
+ dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n",
+ params->win.height);
+ regw(val, CCDC_FMT_VERT);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
+
+ dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
+
+ /*
+ * Configure Horizontal offset register. If pack 8 is enabled then
+ * 1 pixel will take 1 byte
+ */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
+ CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
+ else
+ /* else one pixel will take 2 byte */
+ regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
+ CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
+ CCDC_HSIZE_OFF);
+
+ /* Set value for SDOFST */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For intelace inverse mode */
+ regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
+ }
+
+ else {
+ /* For intelace non inverse mode */
+ regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
+ }
+
+ /*
+ * Configure video port pixel selection (VPOUT)
+ * Here -1 is to make the height value less than FMT_VERT.FMTLNV
+ */
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
+ << CCDC_VP_OUT_VERT_NUM_SHIFT;
+ else
+ val =
+ ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
+ 1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
+ CCDC_VP_OUT_VERT_NUM_SHIFT;
+
+ val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
+ << CCDC_VP_OUT_HORZ_NUM_SHIFT;
+ val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
+ regw(val, CCDC_VP_OUT);
+
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
+ regw(syn_mode, CCDC_SYN_MODE);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
+
+ ccdc_sbl_reset();
+ dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
+ ccdc_readregs();
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.buf_type = buf_type;
+ else
+ ccdc_cfg.ycbcr.buf_type = buf_type;
+ return 0;
+}
+
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.buf_type;
+ return ccdc_cfg.ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ ccdc_cfg.bayer.config_params.alaw.enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.win = *win;
+ else
+ ccdc_cfg.ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ *win = ccdc_cfg.bayer.win;
+ else
+ *win = ccdc_cfg.ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_cfg.bayer.config_params;
+ unsigned int len;
+
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_cfg.bayer.win.width;
+ else
+ len = ccdc_cfg.bayer.win.width * 2;
+ } else
+ len = ccdc_cfg.ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.frm_fmt = frm_fmt;
+ else
+ ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.frm_fmt;
+ else
+ return ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(CCDC_SYN_MODE) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_cfg.if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ case VPFE_BT656_10BIT:
+ ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+ ccdc_cfg.ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void ccdc_save_context(void)
+{
+ ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
+ ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
+ ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
+ ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
+ ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
+ ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
+ ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
+ ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
+ ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
+ ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
+ ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
+ ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
+ ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
+ ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
+ ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
+ ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
+ ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
+ ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
+ ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
+ ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
+ ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
+ ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
+ ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
+ ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
+ ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
+ ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
+ ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
+ ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
+ ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
+ ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
+ ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
+ ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
+ ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
+ ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
+ ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
+ ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
+ ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
+}
+
+static void ccdc_restore_context(void)
+{
+ regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
+ regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
+ regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
+ regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
+ regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
+ regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
+ regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
+ regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
+ regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
+ regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
+ regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
+ regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
+ regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
+ regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
+ regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
+ regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
+ regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
+ regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
+ regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
+ regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
+ regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
+ regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
+ regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
+ regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
+ regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
+ regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
+ regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
+ regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
+ regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
+ regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
+ regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
+ regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
+ regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
+ regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
+ regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
+ regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
+ regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
+}
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM6446 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .reset = ccdc_sbl_reset,
+ .enable = ccdc_enable,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int __devinit dm644x_ccdc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int status = 0;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+ if (status < 0)
+ return status;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nores;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nores;
+ }
+
+ ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ if (!ccdc_cfg.base_addr) {
+ status = -ENOMEM;
+ goto fail_nomem;
+ }
+
+ /* Get and enable Master clock */
+ ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(ccdc_cfg.mclk)) {
+ status = PTR_ERR(ccdc_cfg.mclk);
+ goto fail_nomap;
+ }
+ if (clk_enable(ccdc_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Get and enable Slave clock */
+ ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+ if (IS_ERR(ccdc_cfg.sclk)) {
+ status = PTR_ERR(ccdc_cfg.sclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(ccdc_cfg.sclk)) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+ ccdc_cfg.dev = &pdev->dev;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
+ return 0;
+fail_sclk:
+ clk_put(ccdc_cfg.sclk);
+fail_mclk:
+ clk_put(ccdc_cfg.mclk);
+fail_nomap:
+ iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+ release_mem_region(res->start, resource_size(res));
+fail_nores:
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return status;
+}
+
+static int dm644x_ccdc_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ clk_put(ccdc_cfg.mclk);
+ clk_put(ccdc_cfg.sclk);
+ iounmap(ccdc_cfg.base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return 0;
+}
+
+static int dm644x_ccdc_suspend(struct device *dev)
+{
+ /* Save CCDC context */
+ ccdc_save_context();
+ /* Disable CCDC */
+ ccdc_enable(0);
+ /* Disable both master and slave clock */
+ clk_disable(ccdc_cfg.mclk);
+ clk_disable(ccdc_cfg.sclk);
+
+ return 0;
+}
+
+static int dm644x_ccdc_resume(struct device *dev)
+{
+ /* Enable both master and slave clock */
+ clk_enable(ccdc_cfg.mclk);
+ clk_enable(ccdc_cfg.sclk);
+ /* Restore CCDC context */
+ ccdc_restore_context();
+
+ return 0;
+}
+
+static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
+ .suspend = dm644x_ccdc_suspend,
+ .resume = dm644x_ccdc_resume,
+};
+
+static struct platform_driver dm644x_ccdc_driver = {
+ .driver = {
+ .name = "dm644x_ccdc",
+ .owner = THIS_MODULE,
+ .pm = &dm644x_ccdc_pm_ops,
+ },
+ .remove = __devexit_p(dm644x_ccdc_remove),
+ .probe = dm644x_ccdc_probe,
+};
+
+module_platform_driver(dm644x_ccdc_driver);
diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
index 90370e414e2c..90370e414e2c 100644
--- a/drivers/media/video/davinci/dm644x_ccdc_regs.h
+++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
new file mode 100644
index 000000000000..b99d5423e3a8
--- /dev/null
+++ b/drivers/media/platform/davinci/isif.c
@@ -0,0 +1,1162 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * Image Sensor Interface (ISIF) driver
+ *
+ * This driver is for configuring the ISIF IP available on DM365 or any other
+ * TI SoCs. This is used for capturing yuv or bayer video or image data
+ * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
+ * and DM6446, but with enhanced or additional ip blocks. The driver
+ * configures the ISIF upon commands from the vpfe bridge driver through
+ * ccdc_hw_device interface.
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 2) Add support for control ioctl
+ */
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <mach/mux.h>
+
+#include <media/davinci/isif.h>
+#include <media/davinci/vpss.h>
+
+#include "isif_regs.h"
+#include "ccdc_hw_device.h"
+
+/* Defaults for module configuration parameters */
+static struct isif_config_params_raw isif_config_defaults = {
+ .linearize = {
+ .en = 0,
+ .corr_shft = ISIF_NO_SHIFT,
+ .scale_fact = {1, 0},
+ },
+ .df_csc = {
+ .df_or_csc = 0,
+ .csc = {
+ .en = 0,
+ },
+ },
+ .dfc = {
+ .en = 0,
+ },
+ .bclamp = {
+ .en = 0,
+ },
+ .gain_offset = {
+ .gain = {
+ .r_ye = {1, 0},
+ .gr_cy = {1, 0},
+ .gb_g = {1, 0},
+ .b_mg = {1, 0},
+ },
+ },
+ .culling = {
+ .hcpat_odd = 0xff,
+ .hcpat_even = 0xff,
+ .vcpat = 0xff,
+ },
+ .compress = {
+ .alg = ISIF_ALAW,
+ },
+};
+
+/* ISIF operation configuration */
+static struct isif_oper_config {
+ struct device *dev;
+ enum vpfe_hw_if_type if_type;
+ struct isif_ycbcr_config ycbcr;
+ struct isif_params_raw bayer;
+ enum isif_data_pack data_pack;
+ /* Master clock */
+ struct clk *mclk;
+ /* ISIF base address */
+ void __iomem *base_addr;
+ /* ISIF Linear Table 0 */
+ void __iomem *linear_tbl0_addr;
+ /* ISIF Linear Table 1 */
+ void __iomem *linear_tbl1_addr;
+} isif_cfg = {
+ .ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = ISIF_WIN_NTSC,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
+ },
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = ISIF_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = {1, 0},
+ .gr_cy = {1, 0},
+ .gb_g = {1, 0},
+ .b_mg = {1, 0},
+ },
+ .cfa_pat = ISIF_CFA_PAT_MOSAIC,
+ .data_msb = ISIF_BIT_MSB_11,
+ .config_params = {
+ .data_shift = ISIF_NO_SHIFT,
+ .col_pat_field0 = {
+ .olop = ISIF_GREEN_BLUE,
+ .olep = ISIF_BLUE,
+ .elop = ISIF_RED,
+ .elep = ISIF_GREEN_RED,
+ },
+ .col_pat_field1 = {
+ .olop = ISIF_GREEN_BLUE,
+ .olep = ISIF_BLUE,
+ .elop = ISIF_RED,
+ .elep = ISIF_GREEN_RED,
+ },
+ .test_pat_gen = 0,
+ },
+ },
+ .data_pack = ISIF_DATA_PACK8,
+};
+
+/* Raw Bayer formats */
+static const u32 isif_raw_bayer_pix_formats[] = {
+ V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static const u32 isif_raw_yuv_pix_formats[] = {
+ V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(isif_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, isif_cfg.base_addr + offset);
+}
+
+/* reg_modify() - read, modify and write register */
+static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
+{
+ u32 new_val = (regr(offset) & ~mask) | (val & mask);
+
+ regw(new_val, offset);
+ return new_val;
+}
+
+static inline void regw_lin_tbl(u32 val, u32 offset, int i)
+{
+ if (!i)
+ __raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
+ else
+ __raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
+}
+
+static void isif_disable_all_modules(void)
+{
+ /* disable BC */
+ regw(0, CLAMPCFG);
+ /* disable vdfc */
+ regw(0, DFCCTL);
+ /* disable CSC */
+ regw(0, CSCCTL);
+ /* disable linearization */
+ regw(0, LINCFG0);
+ /* disable other modules here as they are supported */
+}
+
+static void isif_enable(int en)
+{
+ if (!en) {
+ /* Before disable isif, disable all ISIF modules */
+ isif_disable_all_modules();
+ /*
+ * wait for next VD. Assume lowest scan rate is 12 Hz. So
+ * 100 msec delay is good enough
+ */
+ msleep(100);
+ }
+ reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
+}
+
+static void isif_enable_output_to_sdram(int en)
+{
+ reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
+}
+
+static void isif_config_culling(struct isif_cul *cul)
+{
+ u32 val;
+
+ /* Horizontal pattern */
+ val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
+ regw(val, CULH);
+
+ /* vertical pattern */
+ regw(cul->vcpat, CULV);
+
+ /* LPF */
+ reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
+ cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
+}
+
+static void isif_config_gain_offset(void)
+{
+ struct isif_gain_offsets_adj *gain_off_p =
+ &isif_cfg.bayer.config_params.gain_offset;
+ u32 val;
+
+ val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
+ (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
+ (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
+ (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
+ (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
+ (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
+
+ reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
+
+ val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.r_ye.decimal;
+ regw(val, CRGAIN);
+
+ val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.gr_cy.decimal;
+ regw(val, CGRGAIN);
+
+ val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.gb_g.decimal;
+ regw(val, CGBGAIN);
+
+ val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.b_mg.decimal;
+ regw(val, CBGAIN);
+
+ regw(gain_off_p->offset, COFSTA);
+}
+
+static void isif_restore_defaults(void)
+{
+ enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
+
+ dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
+ isif_cfg.bayer.config_params = isif_config_defaults;
+ /* Enable clock to ISIF, IPIPEIF and BL */
+ vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
+ vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
+ vpss_enable_clock(VPSS_BL_CLOCK, 1);
+ /* Set default offset and gain */
+ isif_config_gain_offset();
+ vpss_select_ccdc_source(source);
+ dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
+}
+
+static int isif_open(struct device *device)
+{
+ isif_restore_defaults();
+ return 0;
+}
+
+/* This function will configure the window size to be capture in ISIF reg */
+static void isif_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt, int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int mid_img = 0;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+ /* Writing the horizontal info into the registers */
+ regw(horz_start & START_PX_HOR_MASK, SPH);
+ regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* To account for VD since line 0 doesn't have any data */
+ vert_start += 1;
+ } else {
+ /* To account for VD since line 0 doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /* configure VDINT0 and VDINT1 */
+ mid_img = vert_start + (image_win->height / 2);
+ regw(mid_img, VDINT1);
+ }
+
+ regw(0, VDINT0);
+ regw(vert_start & START_VER_ONE_MASK, SLV0);
+ regw(vert_start & START_VER_TWO_MASK, SLV1);
+ regw(vert_nr_lines & NUM_LINES_VER, LNV);
+}
+
+static void isif_config_bclamp(struct isif_black_clamp *bc)
+{
+ u32 val;
+
+ /*
+ * DC Offset is always added to image data irrespective of bc enable
+ * status
+ */
+ regw(bc->dc_offset, CLDCOFST);
+
+ if (bc->en) {
+ val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
+
+ /* Enable BC and horizontal clamp caculation paramaters */
+ val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
+
+ regw(val, CLAMPCFG);
+
+ if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
+ /*
+ * Window count for calculation
+ * Base window selection
+ * pixel limit
+ * Horizontal size of window
+ * vertical size of the window
+ * Horizontal start position of the window
+ * Vertical start position of the window
+ */
+ val = bc->horz.win_count_calc |
+ ((!!bc->horz.base_win_sel_calc) <<
+ ISIF_HORZ_BC_WIN_SEL_SHIFT) |
+ ((!!bc->horz.clamp_pix_limit) <<
+ ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
+ (bc->horz.win_h_sz_calc <<
+ ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
+ (bc->horz.win_v_sz_calc <<
+ ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
+ regw(val, CLHWIN0);
+
+ regw(bc->horz.win_start_h_calc, CLHWIN1);
+ regw(bc->horz.win_start_v_calc, CLHWIN2);
+ }
+
+ /* vertical clamp caculation paramaters */
+
+ /* Reset clamp value sel for previous line */
+ val |=
+ (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
+ (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
+ regw(val, CLVWIN0);
+
+ /* Optical Black horizontal start position */
+ regw(bc->vert.ob_start_h, CLVWIN1);
+ /* Optical Black vertical start position */
+ regw(bc->vert.ob_start_v, CLVWIN2);
+ /* Optical Black vertical size for calculation */
+ regw(bc->vert.ob_v_sz_calc, CLVWIN3);
+ /* Vertical start position for BC subtraction */
+ regw(bc->vert_start_sub, CLSV);
+ }
+}
+
+static void isif_config_linearization(struct isif_linearize *linearize)
+{
+ u32 val, i;
+
+ if (!linearize->en) {
+ regw(0, LINCFG0);
+ return;
+ }
+
+ /* shift value for correction & enable linearization (set lsb) */
+ val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
+ regw(val, LINCFG0);
+
+ /* Scale factor */
+ val = ((!!linearize->scale_fact.integer) <<
+ ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
+ linearize->scale_fact.decimal;
+ regw(val, LINCFG1);
+
+ for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
+ if (i % 2)
+ regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
+ else
+ regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
+ }
+}
+
+static int isif_config_dfc(struct isif_dfc *vdfc)
+{
+ /* initialize retries to loop for max ~ 250 usec */
+ u32 val, count, retries = loops_per_jiffy / (4000/HZ);
+ int i;
+
+ if (!vdfc->en)
+ return 0;
+
+ /* Correction mode */
+ val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
+
+ /* Correct whole line or partial */
+ if (vdfc->corr_whole_line)
+ val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
+
+ /* level shift value */
+ val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
+
+ regw(val, DFCCTL);
+
+ /* Defect saturation level */
+ regw(vdfc->def_sat_level, VDFSATLV);
+
+ regw(vdfc->table[0].pos_vert, DFCMEM0);
+ regw(vdfc->table[0].pos_horz, DFCMEM1);
+ if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+ vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+ regw(vdfc->table[0].level_at_pos, DFCMEM2);
+ regw(vdfc->table[0].level_up_pixels, DFCMEM3);
+ regw(vdfc->table[0].level_low_pixels, DFCMEM4);
+ }
+
+ /* set DFCMARST and set DFCMWR */
+ val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
+ regw(val, DFCMEMCTL);
+
+ count = retries;
+ while (count && (regr(DFCMEMCTL) & 0x1))
+ count--;
+
+ if (!count) {
+ dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
+ return -1;
+ }
+
+ for (i = 1; i < vdfc->num_vdefects; i++) {
+ regw(vdfc->table[i].pos_vert, DFCMEM0);
+ regw(vdfc->table[i].pos_horz, DFCMEM1);
+ if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+ vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+ regw(vdfc->table[i].level_at_pos, DFCMEM2);
+ regw(vdfc->table[i].level_up_pixels, DFCMEM3);
+ regw(vdfc->table[i].level_low_pixels, DFCMEM4);
+ }
+ val = regr(DFCMEMCTL);
+ /* clear DFCMARST and set DFCMWR */
+ val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
+ val |= 1;
+ regw(val, DFCMEMCTL);
+
+ count = retries;
+ while (count && (regr(DFCMEMCTL) & 0x1))
+ count--;
+
+ if (!count) {
+ dev_err(isif_cfg.dev,
+ "defect table write timeout !!!\n");
+ return -1;
+ }
+ }
+ if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
+ /* Extra cycle needed */
+ regw(0, DFCMEM0);
+ regw(0x1FFF, DFCMEM1);
+ regw(1, DFCMEMCTL);
+ }
+
+ /* enable VDFC */
+ reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
+ DFCCTL);
+ return 0;
+}
+
+static void isif_config_csc(struct isif_df_csc *df_csc)
+{
+ u32 val1 = 0, val2 = 0, i;
+
+ if (!df_csc->csc.en) {
+ regw(0, CSCCTL);
+ return;
+ }
+ for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
+ if ((i % 2) == 0) {
+ /* CSCM - LSB */
+ val1 = (df_csc->csc.coeff[i].integer <<
+ ISIF_CSC_COEF_INTEG_SHIFT) |
+ df_csc->csc.coeff[i].decimal;
+ } else {
+
+ /* CSCM - MSB */
+ val2 = (df_csc->csc.coeff[i].integer <<
+ ISIF_CSC_COEF_INTEG_SHIFT) |
+ df_csc->csc.coeff[i].decimal;
+ val2 <<= ISIF_CSCM_MSB_SHIFT;
+ val2 |= val1;
+ regw(val2, (CSCM0 + ((i - 1) << 1)));
+ }
+ }
+
+ /* program the active area */
+ regw(df_csc->start_pix, FMTSPH);
+ /*
+ * one extra pixel as required for CSC. Actually number of
+ * pixel - 1 should be configured in this register. So we
+ * need to subtract 1 before writing to FMTSPH, but we will
+ * not do this since csc requires one extra pixel
+ */
+ regw(df_csc->num_pixels, FMTLNH);
+ regw(df_csc->start_line, FMTSLV);
+ /*
+ * one extra line as required for CSC. See reason documented for
+ * num_pixels
+ */
+ regw(df_csc->num_lines, FMTLNV);
+
+ /* Enable CSC */
+ regw(1, CSCCTL);
+}
+
+static int isif_config_raw(void)
+{
+ struct isif_params_raw *params = &isif_cfg.bayer;
+ struct isif_config_params_raw *module_params =
+ &isif_cfg.bayer.config_params;
+ struct vpss_pg_frame_size frame_size;
+ struct vpss_sync_pol sync;
+ u32 val;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
+
+ /*
+ * Configure CCDCFG register:-
+ * Set CCD Not to swap input since input is RAW data
+ * Set FID detection function to Latch at V-Sync
+ * Set WENLOG - isif valid area
+ * Set TRGSEL
+ * Set EXTRG
+ * Packed to 8 or 16 bits
+ */
+
+ val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
+ ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
+ ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
+
+ dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
+ regw(val, CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(MODESET.VDPOL)
+ * Configure the horizontal sync polarity (MODESET.HDPOL)
+ * Configure frame id polarity (MODESET.FLDPOL)
+ * Configure data polarity
+ * Configure External WEN Selection
+ * Configure frame format(progressive or interlace)
+ * Configure pixel format (Input mode)
+ * Configure the data shift
+ */
+
+ val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
+ (params->hd_pol << ISIF_HD_POL_SHIFT) |
+ (params->fid_pol << ISIF_FID_POL_SHIFT) |
+ (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
+ (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
+ (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+ (params->pix_fmt << ISIF_INPUT_SHIFT) |
+ (params->config_params.data_shift << ISIF_DATASFT_SHIFT);
+
+ regw(val, MODESET);
+ dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
+
+ /*
+ * Configure GAMMAWD register
+ * CFA pattern setting
+ */
+ val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
+
+ /* Gamma msb */
+ if (module_params->compress.alg == ISIF_ALAW)
+ val |= ISIF_ALAW_ENABLE;
+
+ val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
+ regw(val, CGAMMAWD);
+
+ /* Configure DPCM compression settings */
+ if (module_params->compress.alg == ISIF_DPCM) {
+ val = BIT(ISIF_DPCM_EN_SHIFT) |
+ (module_params->compress.pred <<
+ ISIF_DPCM_PREDICTOR_SHIFT);
+ }
+
+ regw(val, MISC);
+
+ /* Configure Gain & Offset */
+ isif_config_gain_offset();
+
+ /* Configure Color pattern */
+ val = (params->config_params.col_pat_field0.olop) |
+ (params->config_params.col_pat_field0.olep << 2) |
+ (params->config_params.col_pat_field0.elop << 4) |
+ (params->config_params.col_pat_field0.elep << 6) |
+ (params->config_params.col_pat_field1.olop << 8) |
+ (params->config_params.col_pat_field1.olep << 10) |
+ (params->config_params.col_pat_field1.elop << 12) |
+ (params->config_params.col_pat_field1.elep << 14);
+ regw(val, CCOLP);
+ dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
+
+ /* Configure HSIZE register */
+ val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
+
+ /* calculate line offset in 32 bytes based on pack value */
+ if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+ val |= ((params->win.width + 31) >> 5);
+ else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+ val |= (((params->win.width +
+ (params->win.width >> 2)) + 31) >> 5);
+ else
+ val |= (((params->win.width * 2) + 31) >> 5);
+ regw(val, HSIZE);
+
+ /* Configure SDOFST register */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_en) {
+ /* For interlace inverse mode */
+ regw(0x4B6D, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
+ } else {
+ /* For interlace non inverse mode */
+ regw(0x0B6D, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ if (params->image_invert_en) {
+ /* For progressive inverse mode */
+ regw(0x4000, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
+ } else {
+ /* For progressive non inverse mode */
+ regw(0x0000, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
+ }
+ }
+
+ /* Configure video window */
+ isif_setwin(&params->win, params->frm_fmt, 1);
+
+ /* Configure Black Clamp */
+ isif_config_bclamp(&module_params->bclamp);
+
+ /* Configure Vertical Defection Pixel Correction */
+ if (isif_config_dfc(&module_params->dfc) < 0)
+ return -EFAULT;
+
+ if (!module_params->df_csc.df_or_csc)
+ /* Configure Color Space Conversion */
+ isif_config_csc(&module_params->df_csc);
+
+ isif_config_linearization(&module_params->linearize);
+
+ /* Configure Culling */
+ isif_config_culling(&module_params->culling);
+
+ /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
+ regw(module_params->horz_offset, DATAHOFST);
+ regw(module_params->vert_offset, DATAVOFST);
+
+ /* Setup test pattern if enabled */
+ if (params->config_params.test_pat_gen) {
+ /* Use the HD/VD pol settings from user */
+ sync.ccdpg_hdpol = params->hd_pol;
+ sync.ccdpg_vdpol = params->vd_pol;
+ dm365_vpss_set_sync_pol(sync);
+ frame_size.hlpfr = isif_cfg.bayer.win.width;
+ frame_size.pplen = isif_cfg.bayer.win.height;
+ dm365_vpss_set_pg_frame_size(frame_size);
+ vpss_select_ccdc_source(VPSS_PGLPBK);
+ }
+
+ dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
+ return 0;
+}
+
+static int isif_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ isif_cfg.bayer.buf_type = buf_type;
+ else
+ isif_cfg.ycbcr.buf_type = buf_type;
+
+ return 0;
+
+}
+static enum ccdc_buftype isif_get_buftype(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_cfg.bayer.buf_type;
+
+ return isif_cfg.ycbcr.buf_type;
+}
+
+static int isif_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
+ *pix = isif_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
+ *pix = isif_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int isif_set_pixel_format(unsigned int pixfmt)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
+ if ((isif_cfg.bayer.config_params.compress.alg !=
+ ISIF_ALAW) &&
+ (isif_cfg.bayer.config_params.compress.alg !=
+ ISIF_DPCM)) {
+ dev_dbg(isif_cfg.dev,
+ "Either configure A-Law or DPCM\n");
+ return -EINVAL;
+ }
+ isif_cfg.data_pack = ISIF_PACK_8BIT;
+ } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
+ isif_cfg.bayer.config_params.compress.alg =
+ ISIF_NO_COMPRESSION;
+ isif_cfg.data_pack = ISIF_PACK_16BIT;
+ } else
+ return -EINVAL;
+ isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ isif_cfg.data_pack = ISIF_PACK_8BIT;
+ }
+ return 0;
+}
+
+static u32 isif_get_pixel_format(void)
+{
+ u32 pixfmt;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
+ isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+
+static int isif_set_image_window(struct v4l2_rect *win)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ isif_cfg.bayer.win.top = win->top;
+ isif_cfg.bayer.win.left = win->left;
+ isif_cfg.bayer.win.width = win->width;
+ isif_cfg.bayer.win.height = win->height;
+ } else {
+ isif_cfg.ycbcr.win.top = win->top;
+ isif_cfg.ycbcr.win.left = win->left;
+ isif_cfg.ycbcr.win.width = win->width;
+ isif_cfg.ycbcr.win.height = win->height;
+ }
+ return 0;
+}
+
+static void isif_get_image_window(struct v4l2_rect *win)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ *win = isif_cfg.bayer.win;
+ else
+ *win = isif_cfg.ycbcr.win;
+}
+
+static unsigned int isif_get_line_length(void)
+{
+ unsigned int len;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+ len = ((isif_cfg.bayer.win.width));
+ else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+ len = (((isif_cfg.bayer.win.width * 2) +
+ (isif_cfg.bayer.win.width >> 2)));
+ else
+ len = (((isif_cfg.bayer.win.width * 2)));
+ } else
+ len = (((isif_cfg.ycbcr.win.width * 2)));
+ return ALIGN(len, 32);
+}
+
+static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ isif_cfg.bayer.frm_fmt = frm_fmt;
+ else
+ isif_cfg.ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+static enum ccdc_frmfmt isif_get_frame_format(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_cfg.bayer.frm_fmt;
+ return isif_cfg.ycbcr.frm_fmt;
+}
+
+static int isif_getfid(void)
+{
+ return (regr(MODESET) >> 15) & 0x1;
+}
+
+/* misc operations */
+static void isif_setfbaddr(unsigned long addr)
+{
+ regw((addr >> 21) & 0x07ff, CADU);
+ regw((addr >> 5) & 0x0ffff, CADL);
+}
+
+static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ isif_cfg.if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_BT656_10BIT:
+ case VPFE_YCBCR_SYNC_8:
+ isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ break;
+ case VPFE_BT1120:
+ case VPFE_YCBCR_SYNC_16:
+ isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ break;
+ case VPFE_RAW_BAYER:
+ isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ break;
+ default:
+ dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* This function will configure ISIF for YCbCr parameters. */
+static int isif_config_ycbcr(void)
+{
+ struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
+ struct vpss_pg_frame_size frame_size;
+ u32 modeset = 0, ccdcfg = 0;
+ struct vpss_sync_pol sync;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
+
+ /* configure pixel format or input mode */
+ modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
+ (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+ (params->fid_pol << ISIF_FID_POL_SHIFT) |
+ (params->hd_pol << ISIF_HD_POL_SHIFT) |
+ (params->vd_pol << ISIF_VD_POL_SHIFT);
+
+ /* pack the data to 8-bit ISIFCFG */
+ switch (isif_cfg.if_type) {
+ case VPFE_BT656:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
+ regw(3, REC656IF);
+ ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
+ break;
+ case VPFE_BT656_10BIT:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ /* setup BT.656, embedded sync */
+ regw(3, REC656IF);
+ /* enable 10 bit mode in ccdcfg */
+ ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
+ ISIF_BW656_ENABLE;
+ break;
+ case VPFE_BT1120:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ regw(3, REC656IF);
+ break;
+
+ case VPFE_YCBCR_SYNC_8:
+ ccdcfg |= ISIF_DATA_PACK8;
+ ccdcfg |= ISIF_YCINSWP_YCBCR;
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ break;
+ case VPFE_YCBCR_SYNC_16:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ /* should never come here */
+ dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+ return -EINVAL;
+ }
+
+ regw(modeset, MODESET);
+
+ /* Set up pix order */
+ ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
+
+ regw(ccdcfg, CCDCFG);
+
+ /* configure video window */
+ if ((isif_cfg.if_type == VPFE_BT1120) ||
+ (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
+ isif_setwin(&params->win, params->frm_fmt, 1);
+ else
+ isif_setwin(&params->win, params->frm_fmt, 2);
+
+ /*
+ * configure the horizontal line offset
+ * this is done by rounding up width to a multiple of 16 pixels
+ * and multiply by two to account for y:cb:cr 4:2:2 data
+ */
+ regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
+
+ /* configure the memory line offset */
+ if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
+ (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
+ /* two fields are interleaved in memory */
+ regw(0x00000249, SDOFST);
+
+ /* Setup test pattern if enabled */
+ if (isif_cfg.bayer.config_params.test_pat_gen) {
+ sync.ccdpg_hdpol = params->hd_pol;
+ sync.ccdpg_vdpol = params->vd_pol;
+ dm365_vpss_set_sync_pol(sync);
+ dm365_vpss_set_pg_frame_size(frame_size);
+ }
+ return 0;
+}
+
+static int isif_configure(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_config_raw();
+ return isif_config_ycbcr();
+}
+
+static int isif_close(struct device *device)
+{
+ /* copy defaults to module params */
+ isif_cfg.bayer.config_params = isif_config_defaults;
+ return 0;
+}
+
+static struct ccdc_hw_device isif_hw_dev = {
+ .name = "ISIF",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = isif_open,
+ .close = isif_close,
+ .enable = isif_enable,
+ .enable_out_to_sdram = isif_enable_output_to_sdram,
+ .set_hw_if_params = isif_set_hw_if_params,
+ .configure = isif_configure,
+ .set_buftype = isif_set_buftype,
+ .get_buftype = isif_get_buftype,
+ .enum_pix = isif_enum_pix,
+ .set_pixel_format = isif_set_pixel_format,
+ .get_pixel_format = isif_get_pixel_format,
+ .set_frame_format = isif_set_frame_format,
+ .get_frame_format = isif_get_frame_format,
+ .set_image_window = isif_set_image_window,
+ .get_image_window = isif_get_image_window,
+ .get_line_length = isif_get_line_length,
+ .setfbaddr = isif_setfbaddr,
+ .getfid = isif_getfid,
+ },
+};
+
+static int __devinit isif_probe(struct platform_device *pdev)
+{
+ void (*setup_pinmux)(void);
+ struct resource *res;
+ void *__iomem addr;
+ int status = 0, i;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&isif_hw_dev);
+ if (status < 0)
+ return status;
+
+ /* Get and enable Master clock */
+ isif_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(isif_cfg.mclk)) {
+ status = PTR_ERR(isif_cfg.mclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(isif_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Platform data holds setup_pinmux function ptr */
+ if (NULL == pdev->dev.platform_data) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+ setup_pinmux = pdev->dev.platform_data;
+ /*
+ * setup Mux configuration for ccdc which may be different for
+ * different SoCs using this CCDC
+ */
+ setup_pinmux();
+
+ i = 0;
+ /* Get the ISIF base address, linearization table0 and table1 addr. */
+ while (i < 3) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nobase_res;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nobase_res;
+ }
+ addr = ioremap_nocache(res->start, resource_size(res));
+ if (!addr) {
+ status = -ENOMEM;
+ goto fail_base_iomap;
+ }
+ switch (i) {
+ case 0:
+ /* ISIF base address */
+ isif_cfg.base_addr = addr;
+ break;
+ case 1:
+ /* ISIF linear tbl0 address */
+ isif_cfg.linear_tbl0_addr = addr;
+ break;
+ default:
+ /* ISIF linear tbl0 address */
+ isif_cfg.linear_tbl1_addr = addr;
+ break;
+ }
+ i++;
+ }
+ isif_cfg.dev = &pdev->dev;
+
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ isif_hw_dev.name);
+ return 0;
+fail_base_iomap:
+ release_mem_region(res->start, resource_size(res));
+ i--;
+fail_nobase_res:
+ if (isif_cfg.base_addr)
+ iounmap(isif_cfg.base_addr);
+ if (isif_cfg.linear_tbl0_addr)
+ iounmap(isif_cfg.linear_tbl0_addr);
+
+ while (i >= 0) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ release_mem_region(res->start, resource_size(res));
+ i--;
+ }
+fail_mclk:
+ clk_put(isif_cfg.mclk);
+ vpfe_unregister_ccdc_device(&isif_hw_dev);
+ return status;
+}
+
+static int isif_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ int i = 0;
+
+ iounmap(isif_cfg.base_addr);
+ iounmap(isif_cfg.linear_tbl0_addr);
+ iounmap(isif_cfg.linear_tbl1_addr);
+ while (i < 3) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ i++;
+ }
+ vpfe_unregister_ccdc_device(&isif_hw_dev);
+ return 0;
+}
+
+static struct platform_driver isif_driver = {
+ .driver = {
+ .name = "isif",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(isif_remove),
+ .probe = isif_probe,
+};
+
+module_platform_driver(isif_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/platform/davinci/isif_regs.h
index aa69a463c122..aa69a463c122 100644
--- a/drivers/media/video/davinci/isif_regs.h
+++ b/drivers/media/platform/davinci/isif_regs.h
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index c4a82a1a8a97..c4a82a1a8a97 100644
--- a/drivers/media/video/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
new file mode 100644
index 000000000000..9a05c817462c
--- /dev/null
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -0,0 +1,1838 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <mach/cputype.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_display.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_osd.h>
+#include "vpbe_venc_regs.h"
+
+#define VPBE_DISPLAY_DRIVER "vpbe-v4l2"
+
+static int debug;
+
+#define VPBE_DEFAULT_NUM_BUFS 3
+
+module_param(debug, int, 0644);
+
+static int venc_is_second_field(struct vpbe_display *disp_dev)
+{
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ int ret;
+ int val;
+
+ ret = v4l2_subdev_call(vpbe_dev->venc,
+ core,
+ ioctl,
+ VENC_GET_FLD,
+ &val);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in getting Field ID 0\n");
+ }
+ return val;
+}
+
+static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
+ struct vpbe_layer *layer)
+{
+ struct timespec timevalue;
+
+ if (layer->cur_frm == layer->next_frm)
+ return;
+ ktime_get_ts(&timevalue);
+ layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
+ layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
+ layer->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&layer->cur_frm->done);
+ /* Make cur_frm pointing to next_frm */
+ layer->cur_frm = layer->next_frm;
+}
+
+static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
+ struct vpbe_layer *layer)
+{
+ struct osd_state *osd_device = disp_obj->osd_device;
+ unsigned long addr;
+
+ spin_lock(&disp_obj->dma_queue_lock);
+ if (list_empty(&layer->dma_queue) ||
+ (layer->cur_frm != layer->next_frm)) {
+ spin_unlock(&disp_obj->dma_queue_lock);
+ return;
+ }
+ /*
+ * one field is displayed configure
+ * the next frame if it is available
+ * otherwise hold on current frame
+ * Get next from the buffer queue
+ */
+ layer->next_frm = list_entry(
+ layer->dma_queue.next,
+ struct videobuf_buffer,
+ queue);
+ /* Remove that from the buffer queue */
+ list_del(&layer->next_frm->queue);
+ spin_unlock(&disp_obj->dma_queue_lock);
+ /* Mark state of the frame to active */
+ layer->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = videobuf_to_dma_contig(layer->next_frm);
+ osd_device->ops.start_layer(osd_device,
+ layer->layer_info.id,
+ addr,
+ disp_obj->cbcr_ofst);
+}
+
+/* interrupt service routine */
+static irqreturn_t venc_isr(int irq, void *arg)
+{
+ struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
+ struct vpbe_layer *layer;
+ static unsigned last_event;
+ unsigned event = 0;
+ int fid;
+ int i;
+
+ if ((NULL == arg) || (NULL == disp_dev->dev[0]))
+ return IRQ_HANDLED;
+
+ if (venc_is_second_field(disp_dev))
+ event |= VENC_SECOND_FIELD;
+ else
+ event |= VENC_FIRST_FIELD;
+
+ if (event == (last_event & ~VENC_END_OF_FRAME)) {
+ /*
+ * If the display is non-interlaced, then we need to flag the
+ * end-of-frame event at every interrupt regardless of the
+ * value of the FIDST bit. We can conclude that the display is
+ * non-interlaced if the value of the FIDST bit is unchanged
+ * from the previous interrupt.
+ */
+ event |= VENC_END_OF_FRAME;
+ } else if (event == VENC_SECOND_FIELD) {
+ /* end-of-frame for interlaced display */
+ event |= VENC_END_OF_FRAME;
+ }
+ last_event = event;
+
+ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ layer = disp_dev->dev[i];
+ /* If streaming is started in this layer */
+ if (!layer->started)
+ continue;
+
+ if (layer->layer_first_int) {
+ layer->layer_first_int = 0;
+ continue;
+ }
+ /* Check the field format */
+ if ((V4L2_FIELD_NONE == layer->pix_fmt.field) &&
+ (event & VENC_END_OF_FRAME)) {
+ /* Progressive mode */
+
+ vpbe_isr_even_field(disp_dev, layer);
+ vpbe_isr_odd_field(disp_dev, layer);
+ } else {
+ /* Interlaced mode */
+
+ layer->field_id ^= 1;
+ if (event & VENC_FIRST_FIELD)
+ fid = 0;
+ else
+ fid = 1;
+
+ /*
+ * If field id does not match with store
+ * field id
+ */
+ if (fid != layer->field_id) {
+ /* Make them in sync */
+ layer->field_id = fid;
+ continue;
+ }
+ /*
+ * device field id and local field id are
+ * in sync. If this is even field
+ */
+ if (0 == fid)
+ vpbe_isr_even_field(disp_dev, layer);
+ else /* odd field */
+ vpbe_isr_odd_field(disp_dev, layer);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * vpbe_buffer_prepare()
+ * This is the callback function called from videobuf_qbuf() function
+ * the buffer is prepared and user space virtual address is converted into
+ * physical address
+ */
+static int vpbe_buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpbe_fh *fh = q->priv_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ unsigned long addr;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "vpbe_buffer_prepare\n");
+
+ /* If buffer is not initialized, initialize it */
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = layer->pix_fmt.width;
+ vb->height = layer->pix_fmt.height;
+ vb->size = layer->pix_fmt.sizeimage;
+ vb->field = field;
+
+ ret = videobuf_iolock(q, vb, NULL);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
+ user address\n");
+ return -EINVAL;
+ }
+
+ addr = videobuf_to_dma_contig(vb);
+
+ if (q->streaming) {
+ if (!IS_ALIGNED(addr, 8)) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "buffer_prepare:offset is \
+ not aligned to 32 bytes\n");
+ return -EINVAL;
+ }
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ }
+ return 0;
+}
+
+/*
+ * vpbe_buffer_setup()
+ * This function allocates memory for the buffers
+ */
+static int vpbe_buffer_setup(struct videobuf_queue *q,
+ unsigned int *count,
+ unsigned int *size)
+{
+ /* Get the file handle object and layer object */
+ struct vpbe_fh *fh = q->priv_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
+
+ *size = layer->pix_fmt.sizeimage;
+
+ /* Store number of buffers allocated in numbuffer member */
+ if (*count < VPBE_DEFAULT_NUM_BUFS)
+ *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
+
+ return 0;
+}
+
+/*
+ * vpbe_buffer_queue()
+ * This function adds the buffer to DMA queue
+ */
+static void vpbe_buffer_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ /* Get the file handle object and layer object */
+ struct vpbe_fh *fh = q->priv_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_display *disp = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "vpbe_buffer_queue\n");
+
+ /* add the buffer to the DMA queue */
+ spin_lock_irqsave(&disp->dma_queue_lock, flags);
+ list_add_tail(&vb->queue, &layer->dma_queue);
+ spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
+ /* Change state of the buffer */
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpbe_buffer_release()
+ * This function is called from the videobuf layer to free memory allocated to
+ * the buffers
+ */
+static void vpbe_buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ /* Get the file handle object and layer object */
+ struct vpbe_fh *fh = q->priv_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "vpbe_buffer_release\n");
+
+ if (V4L2_MEMORY_USERPTR != layer->memory)
+ videobuf_dma_contig_free(q, vb);
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops video_qops = {
+ .buf_setup = vpbe_buffer_setup,
+ .buf_prepare = vpbe_buffer_prepare,
+ .buf_queue = vpbe_buffer_queue,
+ .buf_release = vpbe_buffer_release,
+};
+
+static
+struct vpbe_layer*
+_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev,
+ struct vpbe_layer *layer)
+{
+ enum vpbe_display_device_id thiswin, otherwin;
+ thiswin = layer->device_id;
+
+ otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ?
+ VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0;
+ return disp_dev->dev[otherwin];
+}
+
+static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
+ struct vpbe_layer *layer)
+{
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct osd_state *osd_device = disp_dev->osd_device;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ unsigned long addr;
+ int ret;
+
+ addr = videobuf_to_dma_contig(layer->cur_frm);
+ /* Set address in the display registers */
+ osd_device->ops.start_layer(osd_device,
+ layer->layer_info.id,
+ addr,
+ disp_dev->cbcr_ofst);
+
+ ret = osd_device->ops.enable_layer(osd_device,
+ layer->layer_info.id, 0);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in enabling osd window layer 0\n");
+ return -1;
+ }
+
+ /* Enable the window */
+ layer->layer_info.enable = 1;
+ if (cfg->pixfmt == PIXFMT_NV12) {
+ struct vpbe_layer *otherlayer =
+ _vpbe_display_get_other_win_layer(disp_dev, layer);
+
+ ret = osd_device->ops.enable_layer(osd_device,
+ otherlayer->layer_info.id, 1);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in enabling osd window layer 1\n");
+ return -1;
+ }
+ otherlayer->layer_info.enable = 1;
+ }
+ return 0;
+}
+
+static void
+vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
+ struct vpbe_layer *layer,
+ int expected_xsize, int expected_ysize)
+{
+ struct display_layer_info *layer_info = &layer->layer_info;
+ struct v4l2_pix_format *pixfmt = &layer->pix_fmt;
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ int calculated_xsize;
+ int h_exp = 0;
+ int v_exp = 0;
+ int h_scale;
+ int v_scale;
+
+ v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id;
+
+ /*
+ * Application initially set the image format. Current display
+ * size is obtained from the vpbe display controller. expected_xsize
+ * and expected_ysize are set through S_CROP ioctl. Based on this,
+ * driver will calculate the scale factors for vertical and
+ * horizontal direction so that the image is displayed scaled
+ * and expanded. Application uses expansion to display the image
+ * in a square pixel. Otherwise it is displayed using displays
+ * pixel aspect ratio.It is expected that application chooses
+ * the crop coordinates for cropped or scaled display. if crop
+ * size is less than the image size, it is displayed cropped or
+ * it is displayed scaled and/or expanded.
+ *
+ * to begin with, set the crop window same as expected. Later we
+ * will override with scaled window size
+ */
+
+ cfg->xsize = pixfmt->width;
+ cfg->ysize = pixfmt->height;
+ layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */
+ layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */
+ layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */
+ layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */
+
+ if (pixfmt->width < expected_xsize) {
+ h_scale = vpbe_dev->current_timings.xres / pixfmt->width;
+ if (h_scale < 2)
+ h_scale = 1;
+ else if (h_scale >= 4)
+ h_scale = 4;
+ else
+ h_scale = 2;
+ cfg->xsize *= h_scale;
+ if (cfg->xsize < expected_xsize) {
+ if ((standard_id & V4L2_STD_525_60) ||
+ (standard_id & V4L2_STD_625_50)) {
+ calculated_xsize = (cfg->xsize *
+ VPBE_DISPLAY_H_EXP_RATIO_N) /
+ VPBE_DISPLAY_H_EXP_RATIO_D;
+ if (calculated_xsize <= expected_xsize) {
+ h_exp = 1;
+ cfg->xsize = calculated_xsize;
+ }
+ }
+ }
+ if (h_scale == 2)
+ layer_info->h_zoom = ZOOM_X2;
+ else if (h_scale == 4)
+ layer_info->h_zoom = ZOOM_X4;
+ if (h_exp)
+ layer_info->h_exp = H_EXP_9_OVER_8;
+ } else {
+ /* no scaling, only cropping. Set display area to crop area */
+ cfg->xsize = expected_xsize;
+ }
+
+ if (pixfmt->height < expected_ysize) {
+ v_scale = expected_ysize / pixfmt->height;
+ if (v_scale < 2)
+ v_scale = 1;
+ else if (v_scale >= 4)
+ v_scale = 4;
+ else
+ v_scale = 2;
+ cfg->ysize *= v_scale;
+ if (cfg->ysize < expected_ysize) {
+ if ((standard_id & V4L2_STD_625_50)) {
+ calculated_xsize = (cfg->ysize *
+ VPBE_DISPLAY_V_EXP_RATIO_N) /
+ VPBE_DISPLAY_V_EXP_RATIO_D;
+ if (calculated_xsize <= expected_ysize) {
+ v_exp = 1;
+ cfg->ysize = calculated_xsize;
+ }
+ }
+ }
+ if (v_scale == 2)
+ layer_info->v_zoom = ZOOM_X2;
+ else if (v_scale == 4)
+ layer_info->v_zoom = ZOOM_X4;
+ if (v_exp)
+ layer_info->h_exp = V_EXP_6_OVER_5;
+ } else {
+ /* no scaling, only cropping. Set display area to crop area */
+ cfg->ysize = expected_ysize;
+ }
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "crop display xsize = %d, ysize = %d\n",
+ cfg->xsize, cfg->ysize);
+}
+
+static void vpbe_disp_adj_position(struct vpbe_display *disp_dev,
+ struct vpbe_layer *layer,
+ int top, int left)
+{
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+ cfg->xpos = min((unsigned int)left,
+ vpbe_dev->current_timings.xres - cfg->xsize);
+ cfg->ypos = min((unsigned int)top,
+ vpbe_dev->current_timings.yres - cfg->ysize);
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "new xpos = %d, ypos = %d\n",
+ cfg->xpos, cfg->ypos);
+}
+
+static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev,
+ struct v4l2_rect *c)
+{
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+ if ((c->width == 0) ||
+ ((c->width + c->left) > vpbe_dev->current_timings.xres))
+ c->width = vpbe_dev->current_timings.xres - c->left;
+
+ if ((c->height == 0) || ((c->height + c->top) >
+ vpbe_dev->current_timings.yres))
+ c->height = vpbe_dev->current_timings.yres - c->top;
+
+ /* window height must be even for interlaced display */
+ if (vpbe_dev->current_timings.interlaced)
+ c->height &= (~0x01);
+
+}
+
+/**
+ * vpbe_try_format()
+ * If user application provides width and height, and have bytesperline set
+ * to zero, driver calculates bytesperline and sizeimage based on hardware
+ * limits.
+ */
+static int vpbe_try_format(struct vpbe_display *disp_dev,
+ struct v4l2_pix_format *pixfmt, int check)
+{
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ int min_height = 1;
+ int min_width = 32;
+ int max_height;
+ int max_width;
+ int bpp;
+
+ if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) &&
+ (pixfmt->pixelformat != V4L2_PIX_FMT_NV12))
+ /* choose default as V4L2_PIX_FMT_UYVY */
+ pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ /* Check the field format */
+ if ((pixfmt->field != V4L2_FIELD_INTERLACED) &&
+ (pixfmt->field != V4L2_FIELD_NONE)) {
+ if (vpbe_dev->current_timings.interlaced)
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ else
+ pixfmt->field = V4L2_FIELD_NONE;
+ }
+
+ if (pixfmt->field == V4L2_FIELD_INTERLACED)
+ min_height = 2;
+
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+ bpp = 1;
+ else
+ bpp = 2;
+
+ max_width = vpbe_dev->current_timings.xres;
+ max_height = vpbe_dev->current_timings.yres;
+
+ min_width /= bpp;
+
+ if (!pixfmt->width || (pixfmt->width < min_width) ||
+ (pixfmt->width > max_width)) {
+ pixfmt->width = vpbe_dev->current_timings.xres;
+ }
+
+ if (!pixfmt->height || (pixfmt->height < min_height) ||
+ (pixfmt->height > max_height)) {
+ pixfmt->height = vpbe_dev->current_timings.yres;
+ }
+
+ if (pixfmt->bytesperline < (pixfmt->width * bpp))
+ pixfmt->bytesperline = pixfmt->width * bpp;
+
+ /* Make the bytesperline 32 byte aligned */
+ pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31);
+
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height +
+ (pixfmt->bytesperline * pixfmt->height >> 1);
+ else
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+ return 0;
+}
+
+static int vpbe_display_g_priority(struct file *file, void *priv,
+ enum v4l2_priority *p)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+
+ *p = v4l2_prio_max(&layer->prio);
+
+ return 0;
+}
+
+static int vpbe_display_s_priority(struct file *file, void *priv,
+ enum v4l2_priority p)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ int ret;
+
+ ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
+
+ return ret;
+}
+
+static int vpbe_display_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ cap->version = VPBE_DISPLAY_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver));
+ strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
+
+ return 0;
+}
+
+static int vpbe_display_s_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct osd_state *osd_device = disp_dev->osd_device;
+ struct v4l2_rect *rect = &crop->c;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_S_CROP, layer id = %d\n", layer->device_id);
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ if (rect->top < 0)
+ rect->top = 0;
+ if (rect->left < 0)
+ rect->left = 0;
+
+ vpbe_disp_check_window_params(disp_dev, rect);
+
+ osd_device->ops.get_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+
+ vpbe_disp_calculate_scale_factor(disp_dev, layer,
+ rect->width,
+ rect->height);
+ vpbe_disp_adj_position(disp_dev, layer, rect->top,
+ rect->left);
+ ret = osd_device->ops.set_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in set layer config:\n");
+ return -EINVAL;
+ }
+
+ /* apply zooming and h or v expansion */
+ osd_device->ops.set_zoom(osd_device,
+ layer->layer_info.id,
+ layer->layer_info.h_zoom,
+ layer->layer_info.v_zoom);
+ ret = osd_device->ops.set_vid_expansion(osd_device,
+ layer->layer_info.h_exp,
+ layer->layer_info.v_exp);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in set vid expansion:\n");
+ return -EINVAL;
+ }
+
+ if ((layer->layer_info.h_zoom != ZOOM_X1) ||
+ (layer->layer_info.v_zoom != ZOOM_X1) ||
+ (layer->layer_info.h_exp != H_EXP_OFF) ||
+ (layer->layer_info.v_exp != V_EXP_OFF))
+ /* Enable expansion filter */
+ osd_device->ops.set_interpolation_filter(osd_device, 1);
+ else
+ osd_device->ops.set_interpolation_filter(osd_device, 0);
+
+ return 0;
+}
+
+static int vpbe_display_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct osd_state *osd_device = fh->disp_dev->osd_device;
+ struct v4l2_rect *rect = &crop->c;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_G_CROP, layer id = %d\n",
+ layer->device_id);
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+ ret = -EINVAL;
+ }
+ osd_device->ops.get_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+ rect->top = cfg->ypos;
+ rect->left = cfg->xpos;
+ rect->width = cfg->xsize;
+ rect->height = cfg->ysize;
+
+ return 0;
+}
+
+static int vpbe_display_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cropcap)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
+
+ cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ cropcap->bounds.left = 0;
+ cropcap->bounds.top = 0;
+ cropcap->bounds.width = vpbe_dev->current_timings.xres;
+ cropcap->bounds.height = vpbe_dev->current_timings.yres;
+ cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+}
+
+static int vpbe_display_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_G_FMT, layer id = %d\n",
+ layer->device_id);
+
+ /* If buffer type is video output */
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+ return -EINVAL;
+ }
+ /* Fill in the information about format */
+ fmt->fmt.pix = layer->pix_fmt;
+
+ return 0;
+}
+
+static int vpbe_display_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ unsigned int index = 0;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_ENUM_FMT, layer id = %d\n",
+ layer->device_id);
+ if (fmt->index > 1) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n");
+ return -EINVAL;
+ }
+
+ /* Fill in the information about format */
+ index = fmt->index;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = index;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ if (index == 0) {
+ strcpy(fmt->description, "YUV 4:2:2 - UYVY");
+ fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+ } else {
+ strcpy(fmt->description, "Y/CbCr 4:2:0");
+ fmt->pixelformat = V4L2_PIX_FMT_NV12;
+ }
+
+ return 0;
+}
+
+static int vpbe_display_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ struct osd_state *osd_device = disp_dev->osd_device;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_S_FMT, layer id = %d\n",
+ layer->device_id);
+
+ /* If streaming is started, return error */
+ if (layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
+ return -EINVAL;
+ }
+ /* Check for valid pixel format */
+ ret = vpbe_try_format(disp_dev, pixfmt, 1);
+ if (ret)
+ return ret;
+
+ /* YUV420 is requested, check availability of the
+ other video window */
+
+ layer->pix_fmt = *pixfmt;
+
+ /* Get osd layer config */
+ osd_device->ops.get_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+ /* Store the pixel format in the layer object */
+ cfg->xsize = pixfmt->width;
+ cfg->ysize = pixfmt->height;
+ cfg->line_length = pixfmt->bytesperline;
+ cfg->ypos = 0;
+ cfg->xpos = 0;
+ cfg->interlaced = vpbe_dev->current_timings.interlaced;
+
+ if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
+ cfg->pixfmt = PIXFMT_YCbCrI;
+
+ /* Change of the default pixel format for both video windows */
+ if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
+ struct vpbe_layer *otherlayer;
+ cfg->pixfmt = PIXFMT_NV12;
+ otherlayer = _vpbe_display_get_other_win_layer(disp_dev,
+ layer);
+ otherlayer->layer_info.config.pixfmt = PIXFMT_NV12;
+ }
+
+ /* Set the layer config in the osd window */
+ ret = osd_device->ops.set_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+ if (ret < 0) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Error in S_FMT params:\n");
+ return -EINVAL;
+ }
+
+ /* Readback and fill the local copy of current pix format */
+ osd_device->ops.get_layer_config(osd_device,
+ layer->layer_info.id, cfg);
+
+ return 0;
+}
+
+static int vpbe_display_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+ return -EINVAL;
+ }
+
+ /* Check for valid field format */
+ return vpbe_try_format(disp_dev, pixfmt, 0);
+
+}
+
+/**
+ * vpbe_display_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_display_s_std(struct file *file, void *priv,
+ v4l2_std_id *std_id)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
+
+ /* If streaming is started, return error */
+ if (layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+ if (NULL != vpbe_dev->ops.s_std) {
+ ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
+ if (ret) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Failed to set standard for sub devices\n");
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vpbe_display_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_display_g_std(struct file *file, void *priv,
+ v4l2_std_id *std_id)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n");
+
+ /* Get the standard from the current encoder */
+ if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) {
+ *std_id = vpbe_dev->current_timings.timings.std_id;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * vpbe_display_enum_output - enumerate outputs
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_display_enum_output(struct file *file, void *priv,
+ struct v4l2_output *output)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n");
+
+ /* Enumerate outputs */
+
+ if (NULL == vpbe_dev->ops.enum_outputs)
+ return -EINVAL;
+
+ ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output);
+ if (ret) {
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "Failed to enumerate outputs\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vpbe_display_s_output - Set output to
+ * the output specified by the index
+ */
+static int vpbe_display_s_output(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n");
+ /* If streaming is started, return error */
+ if (layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+ if (NULL == vpbe_dev->ops.set_output)
+ return -EINVAL;
+
+ ret = vpbe_dev->ops.set_output(vpbe_dev, i);
+ if (ret) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Failed to set output for sub devices\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vpbe_display_g_output - Get output from subdevice
+ * for a given by the index
+ */
+static int vpbe_display_g_output(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
+ /* Get the standard from the current encoder */
+ *i = vpbe_dev->current_out_index;
+
+ return 0;
+}
+
+/**
+ * vpbe_display_enum_dv_presets - Enumerate the dv presets
+ *
+ * enum the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n");
+
+ /* Enumerate outputs */
+ if (NULL == vpbe_dev->ops.enum_dv_presets)
+ return -EINVAL;
+
+ ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset);
+ if (ret) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Failed to enumerate dv presets info\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vpbe_display_s_dv_preset - Set the dv presets
+ *
+ * Set the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n");
+
+
+ /* If streaming is started, return error */
+ if (layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+
+ /* Set the given standard in the encoder */
+ if (!vpbe_dev->ops.s_dv_preset)
+ return -EINVAL;
+
+ ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset);
+ if (ret) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Failed to set the dv presets info\n");
+ return -EINVAL;
+ }
+ /* set the current norm to zero to be consistent. If STD is used
+ * v4l2 layer will set the norm properly on successful s_std call
+ */
+ layer->video_dev.current_norm = 0;
+
+ return 0;
+}
+
+/**
+ * vpbe_display_g_dv_preset - Set the dv presets
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *dv_preset)
+{
+ struct vpbe_fh *fh = priv;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n");
+
+ /* Get the given standard in the encoder */
+
+ if (vpbe_dev->current_timings.timings_type &
+ VPBE_ENC_DV_PRESET) {
+ dv_preset->preset =
+ vpbe_dev->current_timings.timings.dv_preset;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vpbe_display_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct osd_state *osd_device = fh->disp_dev->osd_device;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_STREAMOFF,layer id = %d\n",
+ layer->device_id);
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ /* If io is allowed for this file handle, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If streaming is not started, return error */
+ if (!layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
+ " id = %d\n", layer->device_id);
+ return -EINVAL;
+ }
+
+ osd_device->ops.disable_layer(osd_device,
+ layer->layer_info.id);
+ layer->started = 0;
+ ret = videobuf_streamoff(&layer->buffer_queue);
+
+ return ret;
+}
+
+static int vpbe_display_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct osd_state *osd_device = disp_dev->osd_device;
+ int ret;
+
+ osd_device->ops.disable_layer(osd_device,
+ layer->layer_info.id);
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
+ layer->device_id);
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ /* If file handle is not allowed IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+ return -EACCES;
+ }
+ /* If Streaming is already started, return error */
+ if (layer->started) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Call videobuf_streamon to start streaming
+ * in videobuf
+ */
+ ret = videobuf_streamon(&layer->buffer_queue);
+ if (ret) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "error in videobuf_streamon\n");
+ return ret;
+ }
+ /* If buffer queue is empty, return error */
+ if (list_empty(&layer->dma_queue)) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
+ goto streamoff;
+ }
+ /* Get the next frame from the buffer queue */
+ layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
+ struct videobuf_buffer, queue);
+ /* Remove buffer from the buffer queue */
+ list_del(&layer->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ layer->cur_frm->state = VIDEOBUF_ACTIVE;
+ /* Initialize field_id and started member */
+ layer->field_id = 0;
+
+ /* Set parameters in OSD and VENC */
+ ret = vpbe_set_osd_display_params(disp_dev, layer);
+ if (ret < 0)
+ goto streamoff;
+
+ /*
+ * if request format is yuv420 semiplanar, need to
+ * enable both video windows
+ */
+ layer->started = 1;
+
+ layer->layer_first_int = 1;
+
+ return ret;
+streamoff:
+ ret = videobuf_streamoff(&layer->buffer_queue);
+ return ret;
+}
+
+static int vpbe_display_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_DQBUF, layer id = %d\n",
+ layer->device_id);
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+ /* If this file handle is not allowed to do IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+ return -EACCES;
+ }
+ if (file->f_flags & O_NONBLOCK)
+ /* Call videobuf_dqbuf for non blocking mode */
+ ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
+ else
+ /* Call videobuf_dqbuf for blocking mode */
+ ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
+
+ return ret;
+}
+
+static int vpbe_display_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_QBUF, layer id = %d\n",
+ layer->device_id);
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ /* If this file handle is not allowed to do IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+ return -EACCES;
+ }
+
+ return videobuf_qbuf(&layer->buffer_queue, p);
+}
+
+static int vpbe_display_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "VIDIOC_QUERYBUF, layer id = %d\n",
+ layer->device_id);
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ /* Call videobuf_querybuf to get information */
+ ret = videobuf_querybuf(&layer->buffer_queue, buf);
+
+ return ret;
+}
+
+static int vpbe_display_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ /* If io users of the layer is not zero, return error */
+ if (0 != layer->io_usrs) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
+ return -EBUSY;
+ }
+ /* Initialize videobuf queue as per the buffer type */
+ videobuf_queue_dma_contig_init(&layer->buffer_queue,
+ &video_qops,
+ vpbe_dev->pdev,
+ &layer->irqlock,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ layer->pix_fmt.field,
+ sizeof(struct videobuf_buffer),
+ fh, NULL);
+
+ /* Set io allowed member of file handle to TRUE */
+ fh->io_allowed = 1;
+ /* Increment io usrs member of layer object to 1 */
+ layer->io_usrs = 1;
+ /* Store type of memory requested in layer object */
+ layer->memory = req_buf->memory;
+ /* Initialize buffer queue */
+ INIT_LIST_HEAD(&layer->dma_queue);
+ /* Allocate buffers */
+ ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
+
+ return ret;
+}
+
+/*
+ * vpbe_display_mmap()
+ * It is used to map kernel space buffers into user spaces
+ */
+static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ /* Get the layer object and file handle object */
+ struct vpbe_fh *fh = filep->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
+
+ if (mutex_lock_interruptible(&layer->opslock))
+ return -ERESTARTSYS;
+ ret = videobuf_mmap_mapper(&layer->buffer_queue, vma);
+ mutex_unlock(&layer->opslock);
+ return ret;
+}
+
+/* vpbe_display_poll(): It is used for select/poll system call
+ */
+static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
+{
+ struct vpbe_fh *fh = filep->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ unsigned int err = 0;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
+ if (layer->started) {
+ mutex_lock(&layer->opslock);
+ err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
+ mutex_unlock(&layer->opslock);
+ }
+ return err;
+}
+
+/*
+ * vpbe_display_open()
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpbe_display_open(struct file *file)
+{
+ struct vpbe_fh *fh = NULL;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_display *disp_dev = layer->disp_dev;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ struct osd_state *osd_device = disp_dev->osd_device;
+ int err;
+
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
+ if (fh == NULL) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "vpbe display open plane = %d\n",
+ layer->device_id);
+
+ /* store pointer to fh in private_data member of filep */
+ file->private_data = fh;
+ fh->layer = layer;
+ fh->disp_dev = disp_dev;
+
+ if (!layer->usrs) {
+ if (mutex_lock_interruptible(&layer->opslock))
+ return -ERESTARTSYS;
+ /* First claim the layer for this device */
+ err = osd_device->ops.request_layer(osd_device,
+ layer->layer_info.id);
+ mutex_unlock(&layer->opslock);
+ if (err < 0) {
+ /* Couldn't get layer */
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "Display Manager failed to allocate layer\n");
+ kfree(fh);
+ return -EINVAL;
+ }
+ }
+ /* Increment layer usrs counter */
+ layer->usrs++;
+ /* Set io_allowed member to false */
+ fh->io_allowed = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&layer->prio, &fh->prio);
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+ "vpbe display device opened successfully\n");
+ return 0;
+}
+
+/*
+ * vpbe_display_release()
+ * This function deletes buffer queue, frees the buffers and the davinci
+ * display file * handle
+ */
+static int vpbe_display_release(struct file *file)
+{
+ /* Get the layer object and file handle object */
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_layer *layer = fh->layer;
+ struct osd_layer_config *cfg = &layer->layer_info.config;
+ struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ struct osd_state *osd_device = disp_dev->osd_device;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
+
+ mutex_lock(&layer->opslock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed) {
+ /* Reset io_usrs member of layer object */
+ layer->io_usrs = 0;
+
+ osd_device->ops.disable_layer(osd_device,
+ layer->layer_info.id);
+ layer->started = 0;
+ /* Free buffers allocated */
+ videobuf_queue_cancel(&layer->buffer_queue);
+ videobuf_mmap_free(&layer->buffer_queue);
+ }
+
+ /* Decrement layer usrs counter */
+ layer->usrs--;
+ /* If this file handle has initialize encoder device, reset it */
+ if (!layer->usrs) {
+ if (cfg->pixfmt == PIXFMT_NV12) {
+ struct vpbe_layer *otherlayer;
+ otherlayer =
+ _vpbe_display_get_other_win_layer(disp_dev, layer);
+ osd_device->ops.disable_layer(osd_device,
+ otherlayer->layer_info.id);
+ osd_device->ops.release_layer(osd_device,
+ otherlayer->layer_info.id);
+ }
+ osd_device->ops.disable_layer(osd_device,
+ layer->layer_info.id);
+ osd_device->ops.release_layer(osd_device,
+ layer->layer_info.id);
+ }
+ /* Close the priority */
+ v4l2_prio_close(&layer->prio, fh->prio);
+ file->private_data = NULL;
+ mutex_unlock(&layer->opslock);
+
+ /* Free memory allocated to file handle object */
+ kfree(fh);
+
+ disp_dev->cbcr_ofst = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vpbe_display_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct v4l2_dbg_match *match = &reg->match;
+ struct vpbe_fh *fh = file->private_data;
+ struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+ if (match->type >= 2) {
+ v4l2_subdev_call(vpbe_dev->venc,
+ core,
+ g_register,
+ reg);
+ }
+
+ return 0;
+}
+
+static int vpbe_display_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ return 0;
+}
+#endif
+
+/* vpbe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
+ .vidioc_querycap = vpbe_display_querycap,
+ .vidioc_g_fmt_vid_out = vpbe_display_g_fmt,
+ .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
+ .vidioc_s_fmt_vid_out = vpbe_display_s_fmt,
+ .vidioc_try_fmt_vid_out = vpbe_display_try_fmt,
+ .vidioc_reqbufs = vpbe_display_reqbufs,
+ .vidioc_querybuf = vpbe_display_querybuf,
+ .vidioc_qbuf = vpbe_display_qbuf,
+ .vidioc_dqbuf = vpbe_display_dqbuf,
+ .vidioc_streamon = vpbe_display_streamon,
+ .vidioc_streamoff = vpbe_display_streamoff,
+ .vidioc_cropcap = vpbe_display_cropcap,
+ .vidioc_g_crop = vpbe_display_g_crop,
+ .vidioc_s_crop = vpbe_display_s_crop,
+ .vidioc_g_priority = vpbe_display_g_priority,
+ .vidioc_s_priority = vpbe_display_s_priority,
+ .vidioc_s_std = vpbe_display_s_std,
+ .vidioc_g_std = vpbe_display_g_std,
+ .vidioc_enum_output = vpbe_display_enum_output,
+ .vidioc_s_output = vpbe_display_s_output,
+ .vidioc_g_output = vpbe_display_g_output,
+ .vidioc_s_dv_preset = vpbe_display_s_dv_preset,
+ .vidioc_g_dv_preset = vpbe_display_g_dv_preset,
+ .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpbe_display_g_register,
+ .vidioc_s_register = vpbe_display_s_register,
+#endif
+};
+
+static struct v4l2_file_operations vpbe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpbe_display_open,
+ .release = vpbe_display_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpbe_display_mmap,
+ .poll = vpbe_display_poll
+};
+
+static int vpbe_device_get(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vpbe_display *vpbe_disp = data;
+
+ if (strcmp("vpbe_controller", pdev->name) == 0)
+ vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
+
+ if (strcmp("vpbe-osd", pdev->name) == 0)
+ vpbe_disp->osd_device = platform_get_drvdata(pdev);
+
+ return 0;
+}
+
+static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
+ struct platform_device *pdev)
+{
+ struct vpbe_layer *vpbe_display_layer = NULL;
+ struct video_device *vbd = NULL;
+
+ /* Allocate memory for four plane display objects */
+
+ disp_dev->dev[i] =
+ kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL);
+
+ /* If memory allocation fails, return error */
+ if (!disp_dev->dev[i]) {
+ printk(KERN_ERR "ran out of memory\n");
+ return -ENOMEM;
+ }
+ spin_lock_init(&disp_dev->dev[i]->irqlock);
+ mutex_init(&disp_dev->dev[i]->opslock);
+
+ /* Get the pointer to the layer object */
+ vpbe_display_layer = disp_dev->dev[i];
+ vbd = &vpbe_display_layer->video_dev;
+ /* Initialize field of video device */
+ vbd->release = video_device_release_empty;
+ vbd->fops = &vpbe_fops;
+ vbd->ioctl_ops = &vpbe_ioctl_ops;
+ vbd->minor = -1;
+ vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev;
+ vbd->lock = &vpbe_display_layer->opslock;
+
+ if (disp_dev->vpbe_dev->current_timings.timings_type &
+ VPBE_ENC_STD) {
+ vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
+ vbd->current_norm =
+ disp_dev->vpbe_dev->
+ current_timings.timings.std_id;
+ } else
+ vbd->current_norm = 0;
+
+ snprintf(vbd->name, sizeof(vbd->name),
+ "DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
+ (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff,
+ (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff,
+ (VPBE_DISPLAY_VERSION_CODE) & 0xff);
+
+ vpbe_display_layer->device_id = i;
+
+ vpbe_display_layer->layer_info.id =
+ ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
+
+ /* Initialize prio member of layer object */
+ v4l2_prio_init(&vpbe_display_layer->prio);
+
+ return 0;
+}
+
+static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
+ struct vpbe_display *disp_dev,
+ struct platform_device *pdev) {
+ int err;
+
+ v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+ "Trying to register VPBE display device.\n");
+ v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+ "layer=%x,layer->video_dev=%x\n",
+ (int)vpbe_display_layer,
+ (int)&vpbe_display_layer->video_dev);
+
+ err = video_register_device(&vpbe_display_layer->video_dev,
+ VFL_TYPE_GRABBER,
+ -1);
+ if (err)
+ return -ENODEV;
+
+ vpbe_display_layer->disp_dev = disp_dev;
+ /* set the driver data in platform device */
+ platform_set_drvdata(pdev, disp_dev);
+ video_set_drvdata(&vpbe_display_layer->video_dev,
+ vpbe_display_layer);
+
+ return 0;
+}
+
+
+
+/*
+ * vpbe_display_probe()
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each layer objects
+ */
+static __devinit int vpbe_display_probe(struct platform_device *pdev)
+{
+ struct vpbe_layer *vpbe_display_layer;
+ struct vpbe_display *disp_dev;
+ struct resource *res = NULL;
+ int k;
+ int i;
+ int err;
+ int irq;
+
+ printk(KERN_DEBUG "vpbe_display_probe\n");
+ /* Allocate memory for vpbe_display */
+ disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
+ if (!disp_dev) {
+ printk(KERN_ERR "ran out of memory\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&disp_dev->dma_queue_lock);
+ /*
+ * Scan all the platform devices to find the vpbe
+ * controller device and get the vpbe_dev object
+ */
+ err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev,
+ vpbe_device_get);
+ if (err < 0)
+ return err;
+ /* Initialize the vpbe display controller */
+ if (NULL != disp_dev->vpbe_dev->ops.initialize) {
+ err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
+ disp_dev->vpbe_dev);
+ if (err) {
+ v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+ "Error initing vpbe\n");
+ err = -ENOMEM;
+ goto probe_out;
+ }
+ }
+
+ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ if (init_vpbe_layer(i, disp_dev, pdev)) {
+ err = -ENODEV;
+ goto probe_out;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+ "Unable to get VENC interrupt resource\n");
+ err = -ENODEV;
+ goto probe_out;
+ }
+
+ irq = res->start;
+ if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
+ disp_dev)) {
+ v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+ "Unable to request interrupt\n");
+ err = -ENODEV;
+ goto probe_out;
+ }
+
+ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
+ err = -ENODEV;
+ goto probe_out_irq;
+ }
+ }
+
+ printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
+ return 0;
+
+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];
+ /* Unregister video device */
+ if (vpbe_display_layer) {
+ video_unregister_device(
+ &vpbe_display_layer->video_dev);
+ kfree(disp_dev->dev[k]);
+ }
+ }
+ kfree(disp_dev);
+ return err;
+}
+
+/*
+ * vpbe_display_remove()
+ * It un-register hardware layer from V4L2 driver
+ */
+static int vpbe_display_remove(struct platform_device *pdev)
+{
+ struct vpbe_layer *vpbe_display_layer;
+ struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+ struct resource *res;
+ int i;
+
+ v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
+
+ /* unregister irq */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ free_irq(res->start, disp_dev);
+
+ /* deinitialize the vpbe display controller */
+ if (NULL != vpbe_dev->ops.deinitialize)
+ vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
+ /* un-register device */
+ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the layer object */
+ vpbe_display_layer = disp_dev->dev[i];
+ /* Unregister video device */
+ video_unregister_device(&vpbe_display_layer->video_dev);
+
+ }
+ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ kfree(disp_dev->dev[i]);
+ disp_dev->dev[i] = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver vpbe_display_driver = {
+ .driver = {
+ .name = VPBE_DISPLAY_DRIVER,
+ .owner = THIS_MODULE,
+ .bus = &platform_bus_type,
+ },
+ .probe = vpbe_display_probe,
+ .remove = __devexit_p(vpbe_display_remove),
+};
+
+module_platform_driver(vpbe_display_driver);
+
+MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index bba299dbf396..bba299dbf396 100644
--- a/drivers/media/video/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/platform/davinci/vpbe_osd_regs.h
index 584520f3af60..584520f3af60 100644
--- a/drivers/media/video/davinci/vpbe_osd_regs.h
+++ b/drivers/media/platform/davinci/vpbe_osd_regs.h
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index b21ecc8d134d..b21ecc8d134d 100644
--- a/drivers/media/video/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/platform/davinci/vpbe_venc_regs.h
index 947cb1510776..947cb1510776 100644
--- a/drivers/media/video/davinci/vpbe_venc_regs.h
+++ b/drivers/media/platform/davinci/vpbe_venc_regs.h
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
new file mode 100644
index 000000000000..843b138faabe
--- /dev/null
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -0,0 +1,2079 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * Driver name : VPFE Capture driver
+ * VPFE Capture driver allows applications to capture and stream video
+ * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
+ * TVP5146 or Raw Bayer RGB image data from an image sensor
+ * such as Microns' MT9T001, MT9T031 etc.
+ *
+ * These SoCs have, in common, a Video Processing Subsystem (VPSS) that
+ * consists of a Video Processing Front End (VPFE) for capturing
+ * video/raw image data and Video Processing Back End (VPBE) for displaying
+ * YUV data through an in-built analog encoder or Digital LCD port. This
+ * driver is for capture through VPFE. A typical EVM using these SoCs have
+ * following high level configuration.
+ *
+ *
+ * decoder(TVP5146/ YUV/
+ * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
+ * data input | |
+ * V |
+ * SDRAM |
+ * V
+ * Image Processor
+ * |
+ * V
+ * SDRAM
+ * The data flow happens from a decoder connected to the VPFE over a
+ * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
+ * and to the input of VPFE through an optional MUX (if more inputs are
+ * to be interfaced on the EVM). The input data is first passed through
+ * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
+ * does very little or no processing on YUV data and does pre-process Raw
+ * Bayer RGB data through modules such as Defect Pixel Correction (DFC)
+ * Color Space Conversion (CSC), data gain/offset etc. After this, data
+ * can be written to SDRAM or can be connected to the image processing
+ * block such as IPIPE (on DM355 only).
+ *
+ * Features supported
+ * - MMAP IO
+ * - Capture using TVP5146 over BT.656
+ * - support for interfacing decoders using sub device model
+ * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV
+ * data capture to SDRAM.
+ * TODO list
+ * - Support multiple REQBUF after open
+ * - Support for de-allocating buffers through REQBUF
+ * - Support for Raw Bayer RGB capture
+ * - Support for chaining Image Processor
+ * - Support for static allocation of buffers
+ * - Support for USERPTR IO
+ * - Support for STREAMON before QBUF
+ * - Support for control ioctls
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/davinci/vpfe_capture.h>
+#include "ccdc_hw_device.h"
+
+static int debug;
+static u32 numbuffers = 3;
+static u32 bufsize = (720 * 576 * 2);
+
+module_param(numbuffers, uint, S_IRUGO);
+module_param(bufsize, uint, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
+MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/* standard information */
+struct vpfe_standard {
+ v4l2_std_id std_id;
+ unsigned int width;
+ unsigned int height;
+ struct v4l2_fract pixelaspect;
+ /* 0 - progressive, 1 - interlaced */
+ int frame_format;
+};
+
+/* ccdc configuration */
+struct ccdc_config {
+ /* This make sure vpfe is probed and ready to go */
+ int vpfe_probed;
+ /* name of ccdc device */
+ char name[32];
+};
+
+/* data structures */
+static struct vpfe_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers = 3,
+ .min_bufsize = 720 * 480 * 2,
+ .device_bufsize = 720 * 576 * 2,
+};
+
+/* ccdc device registered */
+static struct ccdc_hw_device *ccdc_dev;
+/* lock for accessing ccdc information */
+static DEFINE_MUTEX(ccdc_lock);
+/* ccdc configuration */
+static struct ccdc_config *ccdc_cfg;
+
+const struct vpfe_standard vpfe_standards[] = {
+ {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
+ {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
+};
+
+/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
+static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
+ {
+ .fmtdesc = {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit A-Law compr.",
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb - 16bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit DPCM compr.",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 3,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 4,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved YUYV",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 5,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Y/CbCr 4:2:0 - Semi planar",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+ .bpp = 1,
+ },
+};
+
+/*
+ * vpfe_lookup_pix_format()
+ * lookup an entry in the vpfe pix format table based on pix_format
+ */
+static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
+ if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
+ return &vpfe_pix_fmts[i];
+ }
+ return NULL;
+}
+
+/*
+ * vpfe_register_ccdc_device. CCDC module calls this to
+ * register with vpfe capture
+ */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
+{
+ int ret = 0;
+ printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
+
+ BUG_ON(!dev->hw_ops.open);
+ BUG_ON(!dev->hw_ops.enable);
+ BUG_ON(!dev->hw_ops.set_hw_if_params);
+ BUG_ON(!dev->hw_ops.configure);
+ BUG_ON(!dev->hw_ops.set_buftype);
+ BUG_ON(!dev->hw_ops.get_buftype);
+ BUG_ON(!dev->hw_ops.enum_pix);
+ BUG_ON(!dev->hw_ops.set_frame_format);
+ BUG_ON(!dev->hw_ops.get_frame_format);
+ BUG_ON(!dev->hw_ops.get_pixel_format);
+ BUG_ON(!dev->hw_ops.set_pixel_format);
+ BUG_ON(!dev->hw_ops.set_image_window);
+ BUG_ON(!dev->hw_ops.get_image_window);
+ BUG_ON(!dev->hw_ops.get_line_length);
+ BUG_ON(!dev->hw_ops.getfid);
+
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_cfg) {
+ /*
+ * TODO. Will this ever happen? if so, we need to fix it.
+ * Proabably we need to add the request to a linked list and
+ * walk through it during vpfe probe
+ */
+ printk(KERN_ERR "vpfe capture not initialized\n");
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (ccdc_dev) {
+ printk(KERN_ERR "ccdc already registered\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ccdc_dev = dev;
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(vpfe_register_ccdc_device);
+
+/*
+ * vpfe_unregister_ccdc_device. CCDC module calls this to
+ * unregister with vpfe capture
+ */
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
+{
+ if (NULL == dev) {
+ printk(KERN_ERR "invalid ccdc device ptr\n");
+ return;
+ }
+
+ printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n",
+ dev->name);
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ return;
+ }
+
+ mutex_lock(&ccdc_lock);
+ ccdc_dev = NULL;
+ mutex_unlock(&ccdc_lock);
+ return;
+}
+EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
+
+/*
+ * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
+ */
+static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_format *f)
+{
+ struct v4l2_rect image_win;
+ enum ccdc_buftype buf_type;
+ enum ccdc_frmfmt frm_fmt;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ f->fmt.pix.width = image_win.width;
+ f->fmt.pix.height = image_win.height;
+ f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height;
+ buf_type = ccdc_dev->hw_ops.get_buftype();
+ f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format();
+ frm_fmt = ccdc_dev->hw_ops.get_frame_format();
+ if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED)
+ f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+ else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n");
+ return -EINVAL;
+ }
+ } else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * vpfe_config_ccdc_image_format()
+ * For a pix format, configure ccdc to setup the capture
+ */
+static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+ int ret = 0;
+
+ if (ccdc_dev->hw_ops.set_pixel_format(
+ vpfe_dev->fmt.fmt.pix.pixelformat) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "couldn't set pix format in ccdc\n");
+ return -EINVAL;
+ }
+ /* configure the image window */
+ ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop);
+
+ switch (vpfe_dev->fmt.fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+ /* do nothing, since it is default */
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_INTERLEAVED);
+ break;
+ case V4L2_FIELD_NONE:
+ frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+ /* buffer type only applicable for interlaced scan */
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_SEPARATED);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set the frame format */
+ if (!ret)
+ ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
+ return ret;
+}
+/*
+ * vpfe_config_image_format()
+ * For a given standard, this functions sets up the default
+ * pix format & crop values in the vpfe device and ccdc. It first
+ * starts with defaults based values from the standard table.
+ * It then checks if sub device support g_mbus_fmt and then override the
+ * values based on that.Sets crop values to match with scan resolution
+ * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
+ * values in ccdc
+ */
+static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
+ const v4l2_std_id *std_id)
+{
+ struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix;
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
+ if (vpfe_standards[i].std_id & *std_id) {
+ vpfe_dev->std_info.active_pixels =
+ vpfe_standards[i].width;
+ vpfe_dev->std_info.active_lines =
+ vpfe_standards[i].height;
+ vpfe_dev->std_info.frame_format =
+ vpfe_standards[i].frame_format;
+ vpfe_dev->std_index = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(vpfe_standards)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n");
+ return -EINVAL;
+ }
+
+ vpfe_dev->crop.top = 0;
+ vpfe_dev->crop.left = 0;
+ vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
+ vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
+ pix->width = vpfe_dev->crop.width;
+ pix->height = vpfe_dev->crop.height;
+
+ /* first field and frame format based on standard frame format */
+ if (vpfe_dev->std_info.frame_format) {
+ pix->field = V4L2_FIELD_INTERLACED;
+ /* assume V4L2_PIX_FMT_UYVY as default */
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ v4l2_fill_mbus_format(&mbus_fmt, pix,
+ V4L2_MBUS_FMT_YUYV10_2X10);
+ } else {
+ pix->field = V4L2_FIELD_NONE;
+ /* assume V4L2_PIX_FMT_SBGGR8 */
+ pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ v4l2_fill_mbus_format(&mbus_fmt, pix,
+ V4L2_MBUS_FMT_SBGGR8_1X8);
+ }
+
+ /* if sub device supports g_mbus_fmt, override the defaults */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt);
+
+ if (ret && ret != -ENOIOCTLCMD) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "error in getting g_mbus_fmt from sub device\n");
+ return ret;
+ }
+ v4l2_fill_pix_format(pix, &mbus_fmt);
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
+
+ /* Sets the values in CCDC */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ if (ret)
+ return ret;
+
+ /* Update the values of sizeimage and bytesperline */
+ if (!ret) {
+ pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+ pix->sizeimage = pix->bytesperline * pix->height;
+ }
+ return ret;
+}
+
+static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
+{
+ int ret = 0;
+
+ /* set first input of current subdevice as the current input */
+ vpfe_dev->current_input = 0;
+
+ /* set default standard */
+ vpfe_dev->std_index = 0;
+
+ /* Configure the default format information */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+ if (ret)
+ return ret;
+
+ /* now open the ccdc device to initialize it */
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_dev) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (!try_module_get(ccdc_dev->owner)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+ ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
+ if (!ret)
+ vpfe_dev->initialized = 1;
+
+ /* Clear all VPFE/CCDC interrupts */
+ if (vpfe_dev->cfg->clr_intr)
+ vpfe_dev->cfg->clr_intr(-1);
+
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+
+/*
+ * vpfe_open : It creates object of file handle structure and
+ * stores it in private_data member of filepointer
+ */
+static int vpfe_open(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
+
+ if (!vpfe_dev->cfg->num_subdevs) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n");
+ return -ENODEV;
+ }
+
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+ /* store pointer to fh in private_data member of file */
+ file->private_data = fh;
+ fh->vpfe_dev = vpfe_dev;
+ mutex_lock(&vpfe_dev->lock);
+ /* If decoder is not initialized. initialize it */
+ if (!vpfe_dev->initialized) {
+ if (vpfe_initialize_device(vpfe_dev)) {
+ mutex_unlock(&vpfe_dev->lock);
+ return -ENODEV;
+ }
+ }
+ /* Increment device usrs counter */
+ vpfe_dev->usrs++;
+ /* Set io_allowed member to false */
+ fh->io_allowed = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
+ mutex_unlock(&vpfe_dev->lock);
+ return 0;
+}
+
+static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
+{
+ unsigned long addr;
+
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vpfe_dev->next_frm->queue);
+ vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+
+ ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
+{
+ unsigned long addr;
+
+ addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+ addr += vpfe_dev->field_off;
+ ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
+{
+ struct timeval timevalue;
+
+ do_gettimeofday(&timevalue);
+ vpfe_dev->cur_frm->ts = timevalue;
+ vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
+ vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ wake_up_interruptible(&vpfe_dev->cur_frm->done);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+}
+
+/* ISR for VINT0*/
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+ enum v4l2_field field;
+ int fid;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
+ field = vpfe_dev->fmt.fmt.pix.field;
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started)
+ goto clear_intr;
+
+ /* only for 6446 this will be applicable */
+ if (NULL != ccdc_dev->hw_ops.reset)
+ ccdc_dev->hw_ops.reset();
+
+ if (field == V4L2_FIELD_NONE) {
+ /* handle progressive frame capture */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "frame format is progressive...\n");
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ goto clear_intr;
+ }
+
+ /* interlaced or TB capture check which field we are in hardware */
+ fid = ccdc_dev->hw_ops.getfid();
+
+ /* switch the software maintained field id */
+ vpfe_dev->field_id ^= 1;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n",
+ fid, vpfe_dev->field_id);
+ if (fid == vpfe_dev->field_id) {
+ /* we are in-sync here,continue */
+ if (fid == 0) {
+ /*
+ * One frame is just being captured. If the next frame
+ * is available, release the current frame and move on
+ */
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ /*
+ * based on whether the two fields are stored
+ * interleavely or separately in memory, reconfigure
+ * the CCDC memory address
+ */
+ if (field == V4L2_FIELD_SEQ_TB) {
+ vpfe_schedule_bottom_field(vpfe_dev);
+ }
+ goto clear_intr;
+ }
+ /*
+ * if one field is just being captured configure
+ * the next frame get the next frame from the empty
+ * queue if no frame is available hold on to the
+ * current buffer
+ */
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if (!list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+ } else if (fid == 0) {
+ /*
+ * out of sync. Recover from any hardware out-of-sync.
+ * May loose one frame
+ */
+ vpfe_dev->field_id = fid;
+ }
+clear_intr:
+ if (vpfe_dev->cfg->clr_intr)
+ vpfe_dev->cfg->clr_intr(irq);
+
+ return IRQ_HANDLED;
+}
+
+/* vdint1_isr - isr handler for VINT1 interrupt */
+static irqreturn_t vdint1_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started) {
+ if (vpfe_dev->cfg->clr_intr)
+ vpfe_dev->cfg->clr_intr(irq);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
+ !list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+
+ if (vpfe_dev->cfg->clr_intr)
+ vpfe_dev->cfg->clr_intr(irq);
+
+ return IRQ_HANDLED;
+}
+
+static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+ free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
+}
+
+static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
+ return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
+ IRQF_DISABLED, "vpfe_capture1",
+ vpfe_dev);
+ }
+ return 0;
+}
+
+/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */
+static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ vpfe_dev->started = 0;
+ ccdc_dev->hw_ops.enable(0);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(0);
+}
+
+/*
+ * vpfe_release : This function deletes buffer queue, frees the
+ * buffers and the vpfe file handle
+ */
+static int vpfe_release(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
+
+ /* Get the device lock */
+ mutex_lock(&vpfe_dev->lock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed) {
+ if (vpfe_dev->started) {
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id,
+ video, s_stream, 0);
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "stream off failed in subdev\n");
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+ videobuf_streamoff(&vpfe_dev->buffer_queue);
+ }
+ vpfe_dev->io_usrs = 0;
+ vpfe_dev->numbuffers = config_params.numbuffers;
+ }
+
+ /* Decrement device usrs counter */
+ vpfe_dev->usrs--;
+ /* Close the priority */
+ v4l2_prio_close(&vpfe_dev->prio, fh->prio);
+ /* If this is the last file handle */
+ if (!vpfe_dev->usrs) {
+ vpfe_dev->initialized = 0;
+ if (ccdc_dev->hw_ops.close)
+ ccdc_dev->hw_ops.close(vpfe_dev->pdev);
+ module_put(ccdc_dev->owner);
+ }
+ mutex_unlock(&vpfe_dev->lock);
+ file->private_data = NULL;
+ /* Free memory allocated to file handle object */
+ kfree(fh);
+ return 0;
+}
+
+/*
+ * vpfe_mmap : It is used to map kernel space buffers
+ * into user spaces
+ */
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* Get the device object and file handle object */
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
+
+ return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma);
+}
+
+/*
+ * vpfe_poll: It is used for select/poll system call
+ */
+static unsigned int vpfe_poll(struct file *file, poll_table *wait)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
+
+ if (vpfe_dev->started)
+ return videobuf_poll_stream(file,
+ &vpfe_dev->buffer_queue, wait);
+ return 0;
+}
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpfe_open,
+ .release = vpfe_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpfe_mmap,
+ .poll = vpfe_poll
+};
+
+/*
+ * vpfe_check_format()
+ * This function adjust the input pixel format as per hardware
+ * capabilities and update the same in pixfmt.
+ * Following algorithm used :-
+ *
+ * If given pixformat is not in the vpfe list of pix formats or not
+ * supported by the hardware, current value of pixformat in the device
+ * is used
+ * If given field is not supported, then current field is used. If field
+ * is different from current, then it is matched with that from sub device.
+ * Minimum height is 2 lines for interlaced or tb field and 1 line for
+ * progressive. Maximum height is clamped to active active lines of scan
+ * Minimum width is 32 bytes in memory and width is clamped to active
+ * pixels of scan.
+ * bytesperline is a multiple of 32.
+ */
+static const struct vpfe_pixel_format *
+ vpfe_check_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_pix_format *pixfmt)
+{
+ u32 min_height = 1, min_width = 32, max_width, max_height;
+ const struct vpfe_pixel_format *vpfe_pix_fmt;
+ u32 pix;
+ int temp, found;
+
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ if (NULL == vpfe_pix_fmt) {
+ /*
+ * use current pixel format in the vpfe device. We
+ * will find this pix format in the table
+ */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check if hw supports it */
+ temp = 0;
+ found = 0;
+ while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
+ if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
+ found = 1;
+ break;
+ }
+ temp++;
+ }
+
+ if (!found) {
+ /* use current pixel format */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ /*
+ * Since this is currently used in the vpfe device, we
+ * will find this pix format in the table
+ */
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check what field format is supported */
+ if (pixfmt->field == V4L2_FIELD_ANY) {
+ /* if field is any, use current value as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ }
+
+ /*
+ * if field is not same as current field in the vpfe device
+ * try matching the field with the sub device field
+ */
+ if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) {
+ /*
+ * If field value is not in the supported fields, use current
+ * field used in the device as default
+ */
+ switch (pixfmt->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ /* if sub device is supporting progressive, use that */
+ if (!vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_NONE;
+ break;
+ case V4L2_FIELD_NONE:
+ if (vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ break;
+
+ default:
+ /* use current field as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ break;
+ }
+ }
+
+ /* Now adjust image resolutions supported */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED ||
+ pixfmt->field == V4L2_FIELD_SEQ_TB)
+ min_height = 2;
+
+ max_width = vpfe_dev->std_info.active_pixels;
+ max_height = vpfe_dev->std_info.active_lines;
+ min_width /= vpfe_pix_fmt->bpp;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp);
+
+ pixfmt->width = clamp((pixfmt->width), min_width, max_width);
+ pixfmt->height = clamp((pixfmt->height), min_height, max_height);
+
+ /* If interlaced, adjust height to be a multiple of 2 */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED)
+ pixfmt->height &= (~1);
+ /*
+ * recalculate bytesperline and sizeimage since width
+ * and height might have changed
+ */
+ pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31)
+ & ~31);
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+ pixfmt->sizeimage =
+ pixfmt->bytesperline * pixfmt->height +
+ ((pixfmt->bytesperline * pixfmt->height) >> 1);
+ else
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height ="
+ " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp,
+ pixfmt->bytesperline, pixfmt->sizeimage);
+ return vpfe_pix_fmt;
+}
+
+static int vpfe_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
+
+ cap->version = VPFE_CAPTURE_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+ strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+ return 0;
+}
+
+static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
+ /* Fill in the information about format */
+ *fmt = vpfe_dev->fmt;
+ return ret;
+}
+
+static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmt;
+ int temp_index;
+ u32 pix;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
+
+ if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ pix_fmt = vpfe_lookup_pix_format(pix);
+ if (NULL != pix_fmt) {
+ temp_index = fmt->index;
+ *fmt = pix_fmt->fmtdesc;
+ fmt->index = temp_index;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
+
+ /* If streaming is started, return error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+
+ /* Check for valid frame format */
+ pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix);
+
+ if (NULL == pix_fmts)
+ return -EINVAL;
+
+ /* store the pixel format in the device object */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /* First detach any IRQ if currently attached */
+ vpfe_detach_irq(vpfe_dev);
+ vpfe_dev->fmt = *fmt;
+ /* set image capture parameters in the ccdc */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n");
+
+ pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix);
+ if (NULL == pix_fmts)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
+ * given app input index
+ */
+static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev,
+ int *subdev_index,
+ int *subdev_input_index,
+ int app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (app_input_index < (j + sdinfo->num_inputs)) {
+ *subdev_index = i;
+ *subdev_input_index = app_input_index - j;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+/*
+ * vpfe_get_app_input - Get app input index for a given subdev input index
+ * driver stores the input index of the current sub device and translate it
+ * when application request the current input
+ */
+static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
+ int *app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
+ if (vpfe_dev->current_input >= sdinfo->num_inputs)
+ return -1;
+ *app_input_index = j + vpfe_dev->current_input;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev, index ;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev,
+ &index,
+ inp->index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "input information not found"
+ " for the subdev\n");
+ return -EINVAL;
+ }
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
+ memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
+ return 0;
+}
+
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
+
+ return vpfe_get_app_input_index(vpfe_dev, index);
+}
+
+
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev_index, inp_index;
+ struct vpfe_route *route;
+ u32 input = 0, output = 0;
+ int ret = -EINVAL;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /*
+ * If streaming is started return device busy
+ * error
+ */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev_index,
+ &inp_index,
+ index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
+ goto unlock_out;
+ }
+
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
+ route = &sdinfo->routes[inp_index];
+ if (route && sdinfo->can_route) {
+ input = route->input;
+ output = route->output;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_routing, input, output, 0);
+
+ if (ret) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "vpfe_doioctl:error in setting input in decoder\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ vpfe_dev->current_subdev = sdinfo;
+ vpfe_dev->current_input = index;
+ vpfe_dev->std_index = 0;
+
+ /* set the bus/interface parameter for the sub device in ccdc */
+ ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
+ if (ret)
+ goto unlock_out;
+
+ /* set the default image parameters in the device */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ sdinfo = vpfe_dev->current_subdev;
+ if (ret)
+ return ret;
+ /* Call querystd function of decoder device */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, querystd, std_id);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
+
+ /* Call decoder driver function to set the standard */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ sdinfo = vpfe_dev->current_subdev;
+ /* If streaming is started, return device busy error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, s_std, *std_id);
+ if (ret < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
+ goto unlock_out;
+ }
+ ret = vpfe_config_image_format(vpfe_dev, std_id);
+
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
+
+ *std_id = vpfe_standards[vpfe_dev->std_index].std_id;
+ return 0;
+}
+/*
+ * Videobuf operations
+ */
+static int vpfe_videobuf_setup(struct videobuf_queue *vq,
+ unsigned int *count,
+ unsigned int *size)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
+ *size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ if (vpfe_dev->memory == V4L2_MEMORY_MMAP &&
+ vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize)
+ *size = config_params.device_bufsize;
+
+ if (*count < config_params.min_numbuffers)
+ *count = config_params.min_numbuffers;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "count=%d, size=%d\n", *count, *size);
+ return 0;
+}
+
+static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long addr;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
+
+ /* If buffer is not initialized, initialize it */
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = vpfe_dev->fmt.fmt.pix.width;
+ vb->height = vpfe_dev->fmt.fmt.pix.height;
+ vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ vb->field = field;
+
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret < 0)
+ return ret;
+
+ addr = videobuf_to_dma_contig(vb);
+ /* Make sure user addresses are aligned to 32 bytes */
+ if (!ALIGN(addr, 32))
+ return -EINVAL;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+ return 0;
+}
+
+static void vpfe_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ /* Get the file handle object and device object */
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n");
+
+ /* add the buffer to the DMA queue */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ list_add_tail(&vb->queue, &vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+
+ /* Change state of the buffer */
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+static void vpfe_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
+
+ /*
+ * We need to flush the buffer from the dma queue since
+ * they are de-allocated
+ */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vpfe_videobuf_qops = {
+ .buf_setup = vpfe_videobuf_setup,
+ .buf_prepare = vpfe_videobuf_prepare,
+ .buf_queue = vpfe_videobuf_queue,
+ .buf_release = vpfe_videobuf_release,
+};
+
+/*
+ * vpfe_reqbufs. currently support REQBUF only once opening
+ * the device.
+ */
+static int vpfe_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (vpfe_dev->io_usrs != 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ vpfe_dev->memory = req_buf->memory;
+ videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
+ &vpfe_videobuf_qops,
+ vpfe_dev->pdev,
+ &vpfe_dev->irqlock,
+ req_buf->type,
+ vpfe_dev->fmt.fmt.pix.field,
+ sizeof(struct videobuf_buffer),
+ fh, NULL);
+
+ fh->io_allowed = 1;
+ vpfe_dev->io_usrs = 1;
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ if (vpfe_dev->memory != V4L2_MEMORY_MMAP) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
+ return -EINVAL;
+ }
+ /* Call videobuf_querybuf to get information */
+ return videobuf_querybuf(&vpfe_dev->buffer_queue, buf);
+}
+
+static int vpfe_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If this file handle is not allowed to do IO,
+ * return error
+ */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+ return videobuf_qbuf(&vpfe_dev->buffer_queue, p);
+}
+
+static int vpfe_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+ return videobuf_dqbuf(&vpfe_dev->buffer_queue,
+ buf, file->f_flags & O_NONBLOCK);
+}
+
+static int vpfe_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+
+ sdinfo = vpfe_dev->current_subdev;
+
+ return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, queryctrl, qctrl);
+
+}
+
+static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+
+ sdinfo = vpfe_dev->current_subdev;
+
+ return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, g_ctrl, ctrl);
+}
+
+static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+
+ sdinfo = vpfe_dev->current_subdev;
+
+ return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, s_ctrl, ctrl);
+}
+
+/*
+ * vpfe_calculate_offsets : This function calculates buffers offset
+ * for top and bottom field
+ */
+static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev)
+{
+ struct v4l2_rect image_win;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n");
+
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ vpfe_dev->field_off = image_win.height * image_win.width;
+}
+
+/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */
+static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ ccdc_dev->hw_ops.enable(1);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(1);
+ vpfe_dev->started = 1;
+}
+
+/*
+ * vpfe_streamon. Assume the DMA queue is not empty.
+ * application is expected to call QBUF before calling
+ * this ioctl. If not, driver returns error
+ */
+static int vpfe_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ unsigned long addr;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If file handle is not allowed IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 1);
+
+ if (ret && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n");
+ return -EINVAL;
+ }
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&vpfe_dev->buffer_queue.stream)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
+ return -EIO;
+ }
+
+ /* Call videobuf_streamon to start streaming * in videobuf */
+ ret = videobuf_streamon(&vpfe_dev->buffer_queue);
+ if (ret)
+ return ret;
+
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ goto streamoff;
+ /* Get the next frame from the buffer queue */
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+ /* Remove buffer from the buffer queue */
+ list_del(&vpfe_dev->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
+ /* Initialize field_id and started member */
+ vpfe_dev->field_id = 0;
+ addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+
+ /* Calculate field offset */
+ vpfe_calculate_offsets(vpfe_dev);
+
+ if (vpfe_attach_irq(vpfe_dev) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in attaching interrupt handle\n");
+ ret = -EFAULT;
+ goto unlock_out;
+ }
+ if (ccdc_dev->hw_ops.configure() < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in configuring ccdc\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr));
+ vpfe_start_ccdc_capture(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+streamoff:
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ return ret;
+}
+
+static int vpfe_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If io is allowed for this file handle, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If streaming is not started, return error */
+ if (!vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "device started\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 0);
+
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n");
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
+
+ if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
+ return -EINVAL;
+
+ memset(crop, 0, sizeof(struct v4l2_cropcap));
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop->bounds.width = crop->defrect.width =
+ vpfe_standards[vpfe_dev->std_index].width;
+ crop->bounds.height = crop->defrect.height =
+ vpfe_standards[vpfe_dev->std_index].height;
+ crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+ return 0;
+}
+
+static int vpfe_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n");
+
+ crop->c = vpfe_dev->crop;
+ return 0;
+}
+
+static int vpfe_s_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n");
+
+ if (vpfe_dev->started) {
+ /* make sure streaming is not started */
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Cannot change crop when streaming is ON\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (crop->c.top < 0 || crop->c.left < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "doesn't support negative values for top & left\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ /* adjust the width to 16 pixel boundary */
+ crop->c.width = ((crop->c.width + 15) & ~0xf);
+
+ /* make sure parameters are valid */
+ if ((crop->c.left + crop->c.width >
+ vpfe_dev->std_info.active_pixels) ||
+ (crop->c.top + crop->c.height >
+ vpfe_dev->std_info.active_lines)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.set_image_window(&crop->c);
+ vpfe_dev->fmt.fmt.pix.width = crop->c.width;
+ vpfe_dev->fmt.fmt.pix.height = crop->c.height;
+ vpfe_dev->fmt.fmt.pix.bytesperline =
+ ccdc_dev->hw_ops.get_line_length();
+ vpfe_dev->fmt.fmt.pix.sizeimage =
+ vpfe_dev->fmt.fmt.pix.bytesperline *
+ vpfe_dev->fmt.fmt.pix.height;
+ vpfe_dev->crop = crop->c;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+static long vpfe_param_handler(struct file *file, void *priv,
+ bool valid_prio, int cmd, void *param)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
+
+ if (vpfe_dev->started) {
+ /* only allowed if streaming is not started */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "device already started\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ switch (cmd) {
+ case VPFE_CMD_S_CCDC_RAW_PARAMS:
+ v4l2_warn(&vpfe_dev->v4l2_dev,
+ "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
+ if (ccdc_dev->hw_ops.set_params) {
+ ret = ccdc_dev->hw_ops.set_params(param);
+ if (ret) {
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "Error setting parameters in CCDC\n");
+ goto unlock_out;
+ }
+ if (vpfe_get_ccdc_image_format(vpfe_dev,
+ &vpfe_dev->fmt) < 0) {
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "Invalid image format at CCDC\n");
+ goto unlock_out;
+ }
+ } else {
+ ret = -EINVAL;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+ .vidioc_querycap = vpfe_querycap,
+ .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap,
+ .vidioc_enum_input = vpfe_enum_input,
+ .vidioc_g_input = vpfe_g_input,
+ .vidioc_s_input = vpfe_s_input,
+ .vidioc_querystd = vpfe_querystd,
+ .vidioc_s_std = vpfe_s_std,
+ .vidioc_g_std = vpfe_g_std,
+ .vidioc_queryctrl = vpfe_queryctrl,
+ .vidioc_g_ctrl = vpfe_g_ctrl,
+ .vidioc_s_ctrl = vpfe_s_ctrl,
+ .vidioc_reqbufs = vpfe_reqbufs,
+ .vidioc_querybuf = vpfe_querybuf,
+ .vidioc_qbuf = vpfe_qbuf,
+ .vidioc_dqbuf = vpfe_dqbuf,
+ .vidioc_streamon = vpfe_streamon,
+ .vidioc_streamoff = vpfe_streamoff,
+ .vidioc_cropcap = vpfe_cropcap,
+ .vidioc_g_crop = vpfe_g_crop,
+ .vidioc_s_crop = vpfe_s_crop,
+ .vidioc_default = vpfe_param_handler,
+};
+
+static struct vpfe_device *vpfe_initialize(void)
+{
+ struct vpfe_device *vpfe_dev;
+
+ /* Default number of buffers should be 3 */
+ if ((numbuffers > 0) &&
+ (numbuffers < config_params.min_numbuffers))
+ numbuffers = config_params.min_numbuffers;
+
+ /*
+ * Set buffer size to min buffers size if invalid buffer size is
+ * given
+ */
+ if (bufsize < config_params.min_bufsize)
+ bufsize = config_params.min_bufsize;
+
+ config_params.numbuffers = numbuffers;
+
+ if (numbuffers)
+ config_params.device_bufsize = bufsize;
+
+ /* Allocate memory for device objects */
+ vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
+
+ return vpfe_dev;
+}
+
+/*
+ * vpfe_probe : This function creates device entries by register
+ * itself to the V4L2 driver and initializes fields of each
+ * device objects
+ */
+static __devinit int vpfe_probe(struct platform_device *pdev)
+{
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_config *vpfe_cfg;
+ struct resource *res1;
+ struct vpfe_device *vpfe_dev;
+ struct i2c_adapter *i2c_adap;
+ struct video_device *vfd;
+ int ret = -ENOMEM, i, j;
+ int num_subdevs = 0;
+
+ /* Get the pointer to the device object */
+ vpfe_dev = vpfe_initialize();
+
+ if (!vpfe_dev) {
+ v4l2_err(pdev->dev.driver,
+ "Failed to allocate memory for vpfe_dev\n");
+ return ret;
+ }
+
+ vpfe_dev->pdev = &pdev->dev;
+
+ if (NULL == pdev->dev.platform_data) {
+ v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
+ ret = -ENODEV;
+ goto probe_free_dev_mem;
+ }
+
+ vpfe_cfg = pdev->dev.platform_data;
+ vpfe_dev->cfg = vpfe_cfg;
+ if (NULL == vpfe_cfg->ccdc ||
+ NULL == vpfe_cfg->card_name ||
+ NULL == vpfe_cfg->sub_devs) {
+ v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
+ ret = -ENOENT;
+ goto probe_free_dev_mem;
+ }
+
+ /* Allocate memory for ccdc configuration */
+ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
+ if (NULL == ccdc_cfg) {
+ v4l2_err(pdev->dev.driver,
+ "Memory allocation failed for ccdc_cfg\n");
+ goto probe_free_lock;
+ }
+
+ mutex_lock(&ccdc_lock);
+
+ strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
+ /* Get VINT0 irq resource */
+ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT0\n");
+ ret = -ENODEV;
+ goto probe_free_ccdc_cfg_mem;
+ }
+ vpfe_dev->ccdc_irq0 = res1->start;
+
+ /* Get VINT1 irq resource */
+ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT1\n");
+ ret = -ENODEV;
+ goto probe_free_ccdc_cfg_mem;
+ }
+ vpfe_dev->ccdc_irq1 = res1->start;
+
+ ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+ "vpfe_capture0", vpfe_dev);
+
+ if (0 != ret) {
+ v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
+ goto probe_free_ccdc_cfg_mem;
+ }
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (NULL == vfd) {
+ ret = -ENOMEM;
+ v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+ goto probe_out_release_irq;
+ }
+
+ /* Initialize field of video device */
+ vfd->release = video_device_release;
+ vfd->fops = &vpfe_fops;
+ vfd->ioctl_ops = &vpfe_ioctl_ops;
+ vfd->tvnorms = 0;
+ vfd->current_norm = V4L2_STD_PAL;
+ vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "%s_V%d.%d.%d",
+ CAPTURE_DRV_NAME,
+ (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE) & 0xff);
+ /* Set video_dev to the video device */
+ vpfe_dev->video_dev = vfd;
+
+ ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register v4l2 device.\n");
+ goto probe_out_video_release;
+ }
+ v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
+ spin_lock_init(&vpfe_dev->irqlock);
+ spin_lock_init(&vpfe_dev->dma_queue_lock);
+ mutex_init(&vpfe_dev->lock);
+
+ /* Initialize field of the device objects */
+ vpfe_dev->numbuffers = config_params.numbuffers;
+
+ /* Initialize prio member of device object */
+ v4l2_prio_init(&vpfe_dev->prio);
+ /* register video device */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "trying to register vpfe device.\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "video_dev=%x\n", (int)&vpfe_dev->video_dev);
+ vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ret = video_register_device(vpfe_dev->video_dev,
+ VFL_TYPE_GRABBER, -1);
+
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register video device.\n");
+ goto probe_out_v4l2_unregister;
+ }
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n");
+ /* set the driver data in platform device */
+ platform_set_drvdata(pdev, vpfe_dev);
+ /* set driver private data */
+ video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
+ i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id);
+ num_subdevs = vpfe_cfg->num_subdevs;
+ vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
+ GFP_KERNEL);
+ if (NULL == vpfe_dev->sd) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for subdevice pointers\n");
+ ret = -ENOMEM;
+ goto probe_out_video_unregister;
+ }
+
+ for (i = 0; i < num_subdevs; i++) {
+ struct v4l2_input *inps;
+
+ sdinfo = &vpfe_cfg->sub_devs[i];
+
+ /* Load up the subdevice */
+ vpfe_dev->sd[i] =
+ v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+ i2c_adap,
+ &sdinfo->board_info,
+ NULL);
+ if (vpfe_dev->sd[i]) {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s registered\n",
+ sdinfo->name);
+ vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
+ /* update tvnorms from the sub devices */
+ for (j = 0; j < sdinfo->num_inputs; j++) {
+ inps = &sdinfo->inputs[j];
+ vfd->tvnorms |= inps->std;
+ }
+ } else {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s register fails\n",
+ sdinfo->name);
+ goto probe_sd_out;
+ }
+ }
+
+ /* set first sub device as current one */
+ vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
+
+ /* We have at least one sub device to work with */
+ mutex_unlock(&ccdc_lock);
+ return 0;
+
+probe_sd_out:
+ kfree(vpfe_dev->sd);
+probe_out_video_unregister:
+ video_unregister_device(vpfe_dev->video_dev);
+probe_out_v4l2_unregister:
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+probe_out_video_release:
+ if (!video_is_registered(vpfe_dev->video_dev))
+ video_device_release(vpfe_dev->video_dev);
+probe_out_release_irq:
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+probe_free_ccdc_cfg_mem:
+ kfree(ccdc_cfg);
+probe_free_lock:
+ mutex_unlock(&ccdc_lock);
+probe_free_dev_mem:
+ kfree(vpfe_dev);
+ return ret;
+}
+
+/*
+ * vpfe_remove : It un-register device from V4L2 driver
+ */
+static int __devexit vpfe_remove(struct platform_device *pdev)
+{
+ struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
+
+ v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+ kfree(vpfe_dev->sd);
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+ video_unregister_device(vpfe_dev->video_dev);
+ kfree(vpfe_dev);
+ kfree(ccdc_cfg);
+ return 0;
+}
+
+static int vpfe_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int vpfe_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops vpfe_dev_pm_ops = {
+ .suspend = vpfe_suspend,
+ .resume = vpfe_resume,
+};
+
+static struct platform_driver vpfe_driver = {
+ .driver = {
+ .name = CAPTURE_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &vpfe_dev_pm_ops,
+ },
+ .probe = vpfe_probe,
+ .remove = __devexit_p(vpfe_remove),
+};
+
+module_platform_driver(vpfe_driver);
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
new file mode 100644
index 000000000000..9bd3caa34a3e
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif.c
@@ -0,0 +1,514 @@
+/*
+ * vpif - Video Port Interface driver
+ * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
+ * that receiveing video byte stream and two channels(2, 3) for video output.
+ * The hardware supports SDTV, HDTV formats, raw data capture.
+ * Currently, the driver supports NTSC and PAL standards.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <mach/hardware.h>
+
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
+MODULE_LICENSE("GPL");
+
+#define VPIF_CH0_MAX_MODES (22)
+#define VPIF_CH1_MAX_MODES (02)
+#define VPIF_CH2_MAX_MODES (15)
+#define VPIF_CH3_MAX_MODES (02)
+
+static resource_size_t res_len;
+static struct resource *res;
+spinlock_t vpif_lock;
+
+void __iomem *vpif_base;
+struct clk *vpif_clk;
+
+/**
+ * ch_params: video standard configuration parameters for vpif
+ * The table must include all presets from supported subdevices.
+ */
+const struct vpif_channel_config_params ch_params[] = {
+ /* HDTV formats */
+ {
+ .name = "480p59_94",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 138-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 43,
+ .l5 = 523,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_480P59_94,
+ },
+ {
+ .name = "576p50",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 144-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 45,
+ .l5 = 621,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_576P50,
+ },
+ {
+ .name = "720p50",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 700-8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P50,
+ },
+ {
+ .name = "720p60",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 370 - 8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P60,
+ },
+ {
+ .name = "1080I50",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 720 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I50,
+ },
+ {
+ .name = "1080I60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I60,
+ },
+ {
+ .name = "1080p60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 42,
+ .l5 = 1122,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080P60,
+ },
+
+ /* SDTV formats */
+ {
+ .name = "NTSC_M",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 268,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 263,
+ .l7 = 266,
+ .l9 = 286,
+ .l11 = 525,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_525_60,
+ },
+ {
+ .name = "PAL_BDGHIK",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 280,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 311,
+ .l7 = 313,
+ .l9 = 336,
+ .l11 = 624,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_625_50,
+ },
+};
+
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+
+static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
+{
+ if (val)
+ vpif_set_bit(reg, bit);
+ else
+ vpif_clr_bit(reg, bit);
+}
+
+/* This structure is used to keep track of VPIF size register's offsets */
+struct vpif_registers {
+ u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
+ u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
+ u32 vanc1_size, width_mask, len_mask;
+ u8 max_modes;
+};
+
+static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
+ /* Channel0 */
+ {
+ VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
+ VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
+ VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH0_MAX_MODES,
+ },
+ /* Channel1 */
+ {
+ VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
+ VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
+ VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH1_MAX_MODES,
+ },
+ /* Channel2 */
+ {
+ VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
+ VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
+ VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
+ VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH2_MAX_MODES
+ },
+ /* Channel3 */
+ {
+ VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
+ VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
+ VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
+ VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH3_MAX_MODES
+ },
+};
+
+/* vpif_set_mode_info:
+ * This function is used to set horizontal and vertical config parameters
+ * As per the standard in the channel, configure the values of L1, L3,
+ * L5, L7 L9, L11 in VPIF Register , also write width and height
+ */
+static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
+ u8 channel_id, u8 config_channel_id)
+{
+ u32 value;
+
+ value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
+ regw(value, vpifregs[channel_id].h_cfg);
+
+ value = (config->l1 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l3 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_00);
+
+ value = (config->l5 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l7 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_01);
+
+ value = (config->l9 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l11 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_02);
+
+ value = (config->vsize & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg);
+}
+
+/* config_vpif_params
+ * Function to set the parameters of a channel
+ * Mainly modifies the channel ciontrol register
+ * It sets frame format, yc mux mode
+ */
+static void config_vpif_params(struct vpif_params *vpifparams,
+ u8 channel_id, u8 found)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ u32 value, ch_nip, reg;
+ u8 start, end;
+ int i;
+
+ start = channel_id;
+ end = channel_id + found;
+
+ for (i = start; i < end; i++) {
+ reg = vpifregs[i].ch_ctrl;
+ if (channel_id < 2)
+ ch_nip = VPIF_CAPTURE_CH_NIP;
+ else
+ ch_nip = VPIF_DISPLAY_CH_NIP;
+
+ vpif_wr_bit(reg, ch_nip, config->frm_fmt);
+ vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
+ vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
+ vpifparams->video_params.storage_mode);
+
+ /* Set raster scanning SDR Format */
+ vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
+ vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
+
+ if (channel_id > 1) /* Set the Pixel enable bit */
+ vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
+ else if (config->capture_format) {
+ /* Set the polarity of various pins */
+ vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
+ vpifparams->iface.fid_pol);
+ vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
+ vpifparams->iface.vd_pol);
+ vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
+ vpifparams->iface.hd_pol);
+
+ value = regr(reg);
+ /* Set data width */
+ value &= ~(0x3u <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ value |= ((vpifparams->params.data_sz) <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ regw(value, reg);
+ }
+
+ /* Write the pitch in the driver */
+ regw((vpifparams->video_params.hpitch),
+ vpifregs[i].line_offset);
+ }
+}
+
+/* vpif_set_video_params
+ * This function is used to set video parameters in VPIF register
+ */
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ int found = 1;
+
+ vpif_set_mode_info(config, channel_id, channel_id);
+ if (!config->ycmux_mode) {
+ /* YC are on separate channels (HDTV formats) */
+ vpif_set_mode_info(config, channel_id + 1, channel_id);
+ found = 2;
+ }
+
+ config_vpif_params(vpifparams, channel_id, found);
+
+ regw(0x80, VPIF_REQ_SIZE);
+ regw(0x01, VPIF_EMULATION_CTRL);
+
+ return found;
+}
+EXPORT_SYMBOL(vpif_set_video_params);
+
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+ u8 channel_id)
+{
+ u32 value;
+
+ value = 0x3F8 & (vbiparams->hstart0);
+ value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_strt);
+
+ value = 0x3F8 & (vbiparams->hstart1);
+ value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_strt);
+
+ value = 0x3F8 & (vbiparams->hsize0);
+ value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_size);
+
+ value = 0x3F8 & (vbiparams->hsize1);
+ value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_size);
+
+}
+EXPORT_SYMBOL(vpif_set_vbi_display_params);
+
+int vpif_channel_getfid(u8 channel_id)
+{
+ return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
+ >> VPIF_CH_FID_SHIFT;
+}
+EXPORT_SYMBOL(vpif_channel_getfid);
+
+static int __devinit vpif_probe(struct platform_device *pdev)
+{
+ int status = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ res_len = resource_size(res);
+
+ res = request_mem_region(res->start, res_len, res->name);
+ if (!res)
+ return -EBUSY;
+
+ vpif_base = ioremap(res->start, res_len);
+ if (!vpif_base) {
+ status = -EBUSY;
+ goto fail;
+ }
+
+ vpif_clk = clk_get(&pdev->dev, "vpif");
+ if (IS_ERR(vpif_clk)) {
+ status = PTR_ERR(vpif_clk);
+ goto clk_fail;
+ }
+ clk_enable(vpif_clk);
+
+ spin_lock_init(&vpif_lock);
+ dev_info(&pdev->dev, "vpif probe success\n");
+ return 0;
+
+clk_fail:
+ iounmap(vpif_base);
+fail:
+ release_mem_region(res->start, res_len);
+ return status;
+}
+
+static int __devexit vpif_remove(struct platform_device *pdev)
+{
+ if (vpif_clk) {
+ clk_disable(vpif_clk);
+ clk_put(vpif_clk);
+ }
+
+ iounmap(vpif_base);
+ release_mem_region(res->start, res_len);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int vpif_suspend(struct device *dev)
+{
+ clk_disable(vpif_clk);
+ return 0;
+}
+
+static int vpif_resume(struct device *dev)
+{
+ clk_enable(vpif_clk);
+ return 0;
+}
+
+static const struct dev_pm_ops vpif_pm = {
+ .suspend = vpif_suspend,
+ .resume = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_pm)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static struct platform_driver vpif_driver = {
+ .driver = {
+ .name = "vpif",
+ .owner = THIS_MODULE,
+ .pm = vpif_pm_ops,
+ },
+ .remove = __devexit_p(vpif_remove),
+ .probe = vpif_probe,
+};
+
+static void vpif_exit(void)
+{
+ platform_driver_unregister(&vpif_driver);
+}
+
+static int __init vpif_init(void)
+{
+ return platform_driver_register(&vpif_driver);
+}
+subsys_initcall(vpif_init);
+module_exit(vpif_exit);
+
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/platform/davinci/vpif.h
index c2ce4d97c279..c2ce4d97c279 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/platform/davinci/vpif.h
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
new file mode 100644
index 000000000000..1b625b065c32
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -0,0 +1,2456 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc
+ *
+ * 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
+ *
+ * TODO : add support for VBI & HBI data service
+ * add static buffer allocation
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "vpif_capture.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_CAPTURE_VERSION);
+
+#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...) \
+ v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch0_numbuffers = 3;
+static u32 ch1_numbuffers = 3;
+static u32 ch0_bufsize = 1920 * 1080 * 2;
+static u32 ch1_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch0_numbuffers, uint, S_IRUGO);
+module_param(ch1_numbuffers, uint, S_IRUGO);
+module_param(ch0_bufsize, uint, S_IRUGO);
+module_param(ch1_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers[0] = 3,
+ .numbuffers[1] = 3,
+ .min_bufsize[0] = 720 * 480 * 2,
+ .min_bufsize[1] = 720 * 480 * 2,
+ .channel_bufsize[0] = 1920 * 1080 * 2,
+ .channel_bufsize[1] = 720 * 576 * 2,
+};
+
+/* global variables */
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+static void vpif_calculate_offsets(struct channel_obj *ch);
+static void vpif_config_addr(struct channel_obj *ch, int muxmode);
+
+/**
+ * buffer_prepare : callback function for buffer prepare
+ * @vb: ptr to vb2_buffer
+ *
+ * This is the callback function for buffer prepare when vb2_qbuf()
+ * function is called. The buffer is prepared and user space virtual address
+ * or user address is converted into physical address
+ */
+static int vpif_buffer_prepare(struct vb2_buffer *vb)
+{
+ /* Get the file handle object and channel object */
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_queue *q = vb->vb2_queue;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned long addr;
+
+ vpif_dbg(2, debug, "vpif_buffer_prepare\n");
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (vb->state != VB2_BUF_STATE_ACTIVE &&
+ vb->state != VB2_BUF_STATE_PREPARED) {
+ vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ goto exit;
+ addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ if (q->streaming) {
+ if (!IS_ALIGNED((addr + common->ytop_off), 8) ||
+ !IS_ALIGNED((addr + common->ybtm_off), 8) ||
+ !IS_ALIGNED((addr + common->ctop_off), 8) ||
+ !IS_ALIGNED((addr + common->cbtm_off), 8))
+ goto exit;
+ }
+ }
+ return 0;
+exit:
+ vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n");
+ return -EINVAL;
+}
+
+/**
+ * vpif_buffer_queue_setup : Callback function for buffer setup.
+ * @vq: vb2_queue ptr
+ * @fmt: v4l2 format
+ * @nbuffers: ptr to number of buffers requested by application
+ * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @sizes[]: contains the size (in bytes) of each plane.
+ * @alloc_ctxs: ptr to allocation context
+ *
+ * This callback function is called when reqbuf() is called to adjust
+ * the buffer count and buffer size
+ */
+static int vpif_buffer_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ /* Get the file handle object and channel object */
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned long size;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vpif_dbg(2, debug, "vpif_buffer_setup\n");
+
+ /* If memory type is not mmap, return */
+ if (V4L2_MEMORY_MMAP == common->memory) {
+ /* Calculate the size of the buffer */
+ size = config_params.channel_bufsize[ch->channel_id];
+ /*
+ * Checking if the buffer size exceeds the available buffer
+ * ycmux_mode = 0 means 1 channel mode HD and
+ * ycmux_mode = 1 means 2 channels mode SD
+ */
+ if (ch->vpifparams.std_info.ycmux_mode == 0) {
+ if (config_params.video_limit[ch->channel_id])
+ while (size * *nbuffers >
+ (config_params.video_limit[0]
+ + config_params.video_limit[1]))
+ (*nbuffers)--;
+ } else {
+ if (config_params.video_limit[ch->channel_id])
+ while (size * *nbuffers >
+ config_params.video_limit[ch->channel_id])
+ (*nbuffers)--;
+ }
+
+ } else {
+ size = common->fmt.fmt.pix.sizeimage;
+ }
+
+ if (*nbuffers < config_params.min_numbuffers)
+ *nbuffers = config_params.min_numbuffers;
+
+ *nplanes = 1;
+ sizes[0] = size;
+ alloc_ctxs[0] = common->alloc_ctx;
+
+ return 0;
+}
+
+/**
+ * vpif_buffer_queue : Callback function to add buffer to DMA queue
+ * @vb: ptr to vb2_buffer
+ */
+static void vpif_buffer_queue(struct vb2_buffer *vb)
+{
+ /* Get the file handle object and channel object */
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct channel_obj *ch = fh->channel;
+ struct vpif_cap_buffer *buf = container_of(vb,
+ struct vpif_cap_buffer, vb);
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vpif_dbg(2, debug, "vpif_buffer_queue\n");
+
+ /* add the buffer to the DMA queue */
+ list_add_tail(&buf->list, &common->dma_queue);
+}
+
+/**
+ * vpif_buf_cleanup : Callback function to free buffer
+ * @vb: ptr to vb2_buffer
+ *
+ * This function is called from the videobuf2 layer to free memory
+ * allocated to the buffers
+ */
+static void vpif_buf_cleanup(struct vb2_buffer *vb)
+{
+ /* Get the file handle object and channel object */
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpif_cap_buffer *buf = container_of(vb,
+ struct vpif_cap_buffer, vb);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned long flags;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ spin_lock_irqsave(&common->irqlock, flags);
+ if (vb->state == VB2_BUF_STATE_ACTIVE)
+ list_del_init(&buf->list);
+ spin_unlock_irqrestore(&common->irqlock, flags);
+
+}
+
+static void vpif_wait_prepare(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_unlock(&common->lock);
+}
+
+static void vpif_wait_finish(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+}
+
+static int vpif_buffer_init(struct vb2_buffer *vb)
+{
+ struct vpif_cap_buffer *buf = container_of(vb,
+ struct vpif_cap_buffer, vb);
+
+ INIT_LIST_HEAD(&buf->list);
+
+ return 0;
+}
+
+static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] =
+ { {1, 1} };
+
+static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vpif_capture_config *vpif_config_data =
+ vpif_dev->platform_data;
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpif = &ch->vpifparams;
+ unsigned long addr = 0;
+ int ret;
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&common->dma_queue)) {
+ vpif_dbg(1, debug, "buffer queue is empty\n");
+ return -EIO;
+ }
+
+ /* Get the next frame from the buffer queue */
+ common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_cap_buffer, list);
+ /* Remove buffer from the buffer queue */
+ list_del(&common->cur_frm->list);
+ /* Mark state of the current frame to active */
+ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+ /* Initialize field_id and started member */
+ ch->field_id = 0;
+ common->started = 1;
+ addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
+
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
+ if ((vpif->std_info.frm_fmt &&
+ ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) &&
+ (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) ||
+ (!vpif->std_info.frm_fmt &&
+ (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+ vpif_dbg(1, debug, "conflict in field format and std format\n");
+ return -EINVAL;
+ }
+
+ /* configure 1 or 2 channel mode */
+ ret = vpif_config_data->setup_input_channel_mode
+ (vpif->std_info.ycmux_mode);
+
+ if (ret < 0) {
+ vpif_dbg(1, debug, "can't set vpif channel mode\n");
+ return ret;
+ }
+
+ /* Call vpif_set_params function to set the parameters and addresses */
+ ret = vpif_set_video_params(vpif, ch->channel_id);
+
+ if (ret < 0) {
+ vpif_dbg(1, debug, "can't set video params\n");
+ return ret;
+ }
+
+ common->started = ret;
+ vpif_config_addr(ch, ret);
+
+ common->set_addr(addr + common->ytop_off,
+ addr + common->ybtm_off,
+ addr + common->ctop_off,
+ addr + common->cbtm_off);
+
+ /**
+ * Set interrupt for both the fields in VPIF Register enable channel in
+ * VPIF register
+ */
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) {
+ channel0_intr_assert();
+ channel0_intr_enable(1);
+ enable_channel0(1);
+ }
+ if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
+ (common->started == 2)) {
+ channel1_intr_assert();
+ channel1_intr_enable(1);
+ enable_channel1(1);
+ }
+ channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+
+ return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int vpif_stop_streaming(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ if (!vb2_is_streaming(vq))
+ return 0;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* release all active buffers */
+ while (!list_empty(&common->dma_queue)) {
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_cap_buffer, list);
+ list_del(&common->next_frm->list);
+ vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ return 0;
+}
+
+static struct vb2_ops video_qops = {
+ .queue_setup = vpif_buffer_queue_setup,
+ .wait_prepare = vpif_wait_prepare,
+ .wait_finish = vpif_wait_finish,
+ .buf_init = vpif_buffer_init,
+ .buf_prepare = vpif_buffer_prepare,
+ .start_streaming = vpif_start_streaming,
+ .stop_streaming = vpif_stop_streaming,
+ .buf_cleanup = vpif_buf_cleanup,
+ .buf_queue = vpif_buffer_queue,
+};
+
+/**
+ * vpif_process_buffer_complete: process a completed buffer
+ * @common: ptr to common channel object
+ *
+ * This function time stamp the buffer and mark it as DONE. It also
+ * wake up any process waiting on the QUEUE and set the next buffer
+ * as current
+ */
+static void vpif_process_buffer_complete(struct common_obj *common)
+{
+ do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&common->cur_frm->vb,
+ VB2_BUF_STATE_DONE);
+ /* Make curFrm pointing to nextFrm */
+ common->cur_frm = common->next_frm;
+}
+
+/**
+ * vpif_schedule_next_buffer: set next buffer address for capture
+ * @common : ptr to common channel object
+ *
+ * This function will get next buffer from the dma queue and
+ * set the buffer address in the vpif register for capture.
+ * the buffer is marked active
+ */
+static void vpif_schedule_next_buffer(struct common_obj *common)
+{
+ unsigned long addr = 0;
+
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_cap_buffer, list);
+ /* Remove that buffer from the buffer queue */
+ list_del(&common->next_frm->list);
+ common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+ addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
+
+ /* Set top and bottom field addresses in VPIF registers */
+ common->set_addr(addr + common->ytop_off,
+ addr + common->ybtm_off,
+ addr + common->ctop_off,
+ addr + common->cbtm_off);
+}
+
+/**
+ * vpif_channel_isr : ISR handler for vpif capture
+ * @irq: irq number
+ * @dev_id: dev_id ptr
+ *
+ * It changes status of the captured buffer, takes next buffer from the queue
+ * and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+ struct vpif_device *dev = &vpif_obj;
+ struct common_obj *common;
+ struct channel_obj *ch;
+ enum v4l2_field field;
+ int channel_id = 0;
+ int fid = -1, i;
+
+ channel_id = *(int *)(dev_id);
+ if (!vpif_intr_status(channel_id))
+ return IRQ_NONE;
+
+ ch = dev->dev[channel_id];
+
+ field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+
+ for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
+ common = &ch->common[i];
+ /* skip If streaming is not started in this channel */
+ if (0 == common->started)
+ continue;
+
+ /* Check the field format */
+ if (1 == ch->vpifparams.std_info.frm_fmt) {
+ /* Progressive mode */
+ if (list_empty(&common->dma_queue))
+ continue;
+
+ if (!channel_first_int[i][channel_id])
+ vpif_process_buffer_complete(common);
+
+ channel_first_int[i][channel_id] = 0;
+
+ vpif_schedule_next_buffer(common);
+
+
+ channel_first_int[i][channel_id] = 0;
+ } else {
+ /**
+ * Interlaced mode. If it is first interrupt, ignore
+ * it
+ */
+ if (channel_first_int[i][channel_id]) {
+ channel_first_int[i][channel_id] = 0;
+ continue;
+ }
+ if (0 == i) {
+ ch->field_id ^= 1;
+ /* Get field id from VPIF registers */
+ fid = vpif_channel_getfid(ch->channel_id);
+ if (fid != ch->field_id) {
+ /**
+ * If field id does not match stored
+ * field id, make them in sync
+ */
+ if (0 == fid)
+ ch->field_id = fid;
+ return IRQ_HANDLED;
+ }
+ }
+ /* device field id and local field id are in sync */
+ if (0 == fid) {
+ /* this is even field */
+ if (common->cur_frm == common->next_frm)
+ continue;
+
+ /* mark the current buffer as done */
+ vpif_process_buffer_complete(common);
+ } else if (1 == fid) {
+ /* odd field */
+ if (list_empty(&common->dma_queue) ||
+ (common->cur_frm != common->next_frm))
+ continue;
+
+ vpif_schedule_next_buffer(common);
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * vpif_update_std_info() - update standard related info
+ * @ch: ptr to channel object
+ *
+ * For a given standard selected by application, update values
+ * in the device data structures
+ */
+static int vpif_update_std_info(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ const struct vpif_channel_config_params *config;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ int index;
+
+ vpif_dbg(2, debug, "vpif_update_std_info\n");
+
+ for (index = 0; index < vpif_ch_params_count; index++) {
+ config = &ch_params[index];
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ }
+ }
+
+ /* standard not found */
+ if (index == vpif_ch_params_count)
+ return -EINVAL;
+
+ common->fmt.fmt.pix.width = std_info->width;
+ common->width = std_info->width;
+ common->fmt.fmt.pix.height = std_info->height;
+ common->height = std_info->height;
+ common->fmt.fmt.pix.bytesperline = std_info->width;
+ vpifparams->video_params.hpitch = std_info->width;
+ vpifparams->video_params.storage_mode = std_info->frm_fmt;
+
+ return 0;
+}
+
+/**
+ * vpif_calculate_offsets : This function calculates buffers offsets
+ * @ch : ptr to channel object
+ *
+ * This function calculates buffer offsets for Y and C in the top and
+ * bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+ unsigned int hpitch, vpitch, sizeimage;
+ struct video_obj *vid_ch = &(ch->video);
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ enum v4l2_field field = common->fmt.fmt.pix.field;
+
+ vpif_dbg(2, debug, "vpif_calculate_offsets\n");
+
+ if (V4L2_FIELD_ANY == field) {
+ if (vpifparams->std_info.frm_fmt)
+ vid_ch->buf_field = V4L2_FIELD_NONE;
+ else
+ vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+ } else
+ vid_ch->buf_field = common->fmt.fmt.pix.field;
+
+ sizeimage = common->fmt.fmt.pix.sizeimage;
+
+ hpitch = common->fmt.fmt.pix.bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+ common->ytop_off = 0;
+ common->ybtm_off = hpitch;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = sizeimage / 2 + hpitch;
+ } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+ /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+ common->ytop_off = 0;
+ common->ybtm_off = sizeimage / 4;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = common->ctop_off + sizeimage / 4;
+ } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+ /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
+ common->ybtm_off = 0;
+ common->ytop_off = sizeimage / 4;
+ common->cbtm_off = sizeimage / 2;
+ common->ctop_off = common->cbtm_off + sizeimage / 4;
+ }
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field))
+ vpifparams->video_params.storage_mode = 1;
+ else
+ vpifparams->video_params.storage_mode = 0;
+
+ if (1 == vpifparams->std_info.frm_fmt)
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ else {
+ if ((field == V4L2_FIELD_ANY)
+ || (field == V4L2_FIELD_INTERLACED))
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline * 2;
+ else
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ }
+
+ ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid;
+}
+
+/**
+ * vpif_config_format: configure default frame format in the device
+ * ch : ptr to channel object
+ */
+static void vpif_config_format(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vpif_dbg(2, debug, "vpif_config_format\n");
+
+ common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+ if (config_params.numbuffers[ch->channel_id] == 0)
+ common->memory = V4L2_MEMORY_USERPTR;
+ else
+ common->memory = V4L2_MEMORY_MMAP;
+
+ common->fmt.fmt.pix.sizeimage
+ = config_params.channel_bufsize[ch->channel_id];
+
+ if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ else
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+ common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+}
+
+/**
+ * vpif_get_default_field() - Get default field type based on interface
+ * @vpif_params - ptr to vpif params
+ */
+static inline enum v4l2_field vpif_get_default_field(
+ struct vpif_interface *iface)
+{
+ return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE :
+ V4L2_FIELD_INTERLACED;
+}
+
+/**
+ * vpif_check_format() - check given pixel format for compatibility
+ * @ch - channel ptr
+ * @pixfmt - Given pixel format
+ * @update - update the values as per hardware requirement
+ *
+ * Check the application pixel format for S_FMT and update the input
+ * values as per hardware limits for TRY_FMT. The default pixel and
+ * field format is selected based on interface type.
+ */
+static int vpif_check_format(struct channel_obj *ch,
+ struct v4l2_pix_format *pixfmt,
+ int update)
+{
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+ struct vpif_params *vpif_params = &ch->vpifparams;
+ enum v4l2_field field = pixfmt->field;
+ u32 sizeimage, hpitch, vpitch;
+ int ret = -EINVAL;
+
+ vpif_dbg(2, debug, "vpif_check_format\n");
+ /**
+ * first check for the pixel format. If if_type is Raw bayer,
+ * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only
+ * V4L2_PIX_FMT_YUV422P is supported
+ */
+ if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) {
+ if (!update) {
+ vpif_dbg(2, debug, "invalid pix format\n");
+ goto exit;
+ }
+ pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ }
+ } else {
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) {
+ if (!update) {
+ vpif_dbg(2, debug, "invalid pixel format\n");
+ goto exit;
+ }
+ pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+ }
+ }
+
+ if (!(VPIF_VALID_FIELD(field))) {
+ if (!update) {
+ vpif_dbg(2, debug, "invalid field format\n");
+ goto exit;
+ }
+ /**
+ * By default use FIELD_NONE for RAW Bayer capture
+ * and FIELD_INTERLACED for other interfaces
+ */
+ field = vpif_get_default_field(&vpif_params->iface);
+ } else if (field == V4L2_FIELD_ANY)
+ /* unsupported field. Use default */
+ field = vpif_get_default_field(&vpif_params->iface);
+
+ /* validate the hpitch */
+ hpitch = pixfmt->bytesperline;
+ if (hpitch < vpif_params->std_info.width) {
+ if (!update) {
+ vpif_dbg(2, debug, "invalid hpitch\n");
+ goto exit;
+ }
+ hpitch = vpif_params->std_info.width;
+ }
+
+ sizeimage = pixfmt->sizeimage;
+
+ vpitch = sizeimage / (hpitch * 2);
+
+ /* validate the vpitch */
+ if (vpitch < vpif_params->std_info.height) {
+ if (!update) {
+ vpif_dbg(2, debug, "Invalid vpitch\n");
+ goto exit;
+ }
+ vpitch = vpif_params->std_info.height;
+ }
+
+ /* Check for 8 byte alignment */
+ if (!ALIGN(hpitch, 8)) {
+ if (!update) {
+ vpif_dbg(2, debug, "invalid pitch alignment\n");
+ goto exit;
+ }
+ /* adjust to next 8 byte boundary */
+ hpitch = (((hpitch + 7) / 8) * 8);
+ }
+ /* if update is set, modify the bytesperline and sizeimage */
+ if (update) {
+ pixfmt->bytesperline = hpitch;
+ pixfmt->sizeimage = hpitch * vpitch * 2;
+ }
+ /**
+ * Image width and height is always based on current standard width and
+ * height
+ */
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+ return 0;
+exit:
+ return ret;
+}
+
+/**
+ * vpif_config_addr() - function to configure buffer address in vpif
+ * @ch - channel ptr
+ * @muxmode - channel mux mode
+ */
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+ struct common_obj *common;
+
+ vpif_dbg(2, debug, "vpif_config_addr\n");
+
+ common = &(ch->common[VPIF_VIDEO_INDEX]);
+
+ if (VPIF_CHANNEL1_VIDEO == ch->channel_id)
+ common->set_addr = ch1_set_videobuf_addr;
+ else if (2 == muxmode)
+ common->set_addr = ch0_set_videobuf_addr_yc_nmux;
+ else
+ common->set_addr = ch0_set_videobuf_addr;
+}
+
+/**
+ * vpif_mmap : It is used to map kernel space buffers into user spaces
+ * @filep: file pointer
+ * @vma: ptr to vm_area_struct
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ /* Get the channel object and file handle object */
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+ int ret;
+
+ vpif_dbg(2, debug, "vpif_mmap\n");
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&common->buffer_queue, vma);
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+/**
+ * vpif_poll: It is used for select/poll system call
+ * @filep: file pointer
+ * @wait: poll table to wait
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table * wait)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *channel = fh->channel;
+ struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
+ unsigned int res = 0;
+
+ vpif_dbg(2, debug, "vpif_poll\n");
+
+ if (common->started) {
+ mutex_lock(&common->lock);
+ res = vb2_poll(&common->buffer_queue, filep, wait);
+ mutex_unlock(&common->lock);
+ }
+ return res;
+}
+
+/**
+ * vpif_open : vpif open handler
+ * @filep: file ptr
+ *
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(filep);
+ struct common_obj *common;
+ struct video_obj *vid_ch;
+ struct channel_obj *ch;
+ struct vpif_fh *fh;
+ int i;
+
+ vpif_dbg(2, debug, "vpif_open\n");
+
+ ch = video_get_drvdata(vdev);
+
+ vid_ch = &ch->video;
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (NULL == ch->curr_subdev_info) {
+ /**
+ * search through the sub device to see a registered
+ * sub device and make it as current sub device
+ */
+ for (i = 0; i < config->subdev_count; i++) {
+ if (vpif_obj.sd[i]) {
+ /* the sub device is registered */
+ ch->curr_subdev_info = &config->subdev_info[i];
+ /* make first input as the current input */
+ vid_ch->input_idx = 0;
+ break;
+ }
+ }
+ if (i == config->subdev_count) {
+ vpif_err("No sub device registered\n");
+ return -ENOENT;
+ }
+ }
+
+ /* Allocate memory for the file handle object */
+ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ vpif_err("unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+
+ if (mutex_lock_interruptible(&common->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ /* store pointer to fh in private_data member of filep */
+ filep->private_data = fh;
+ fh->channel = ch;
+ fh->initialized = 0;
+ /* If decoder is not initialized. initialize it */
+ if (!ch->initialized) {
+ fh->initialized = 1;
+ ch->initialized = 1;
+ memset(&(ch->vpifparams), 0, sizeof(struct vpif_params));
+ }
+ /* Increment channel usrs counter */
+ ch->usrs++;
+ /* Set io_allowed member to false */
+ fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&ch->prio, &fh->prio);
+ mutex_unlock(&common->lock);
+ return 0;
+}
+
+/**
+ * vpif_release : function to clean up file close
+ * @filep: file pointer
+ *
+ * This function deletes buffer queue, frees the buffers and the vpif file
+ * handle
+ */
+static int vpif_release(struct file *filep)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ vpif_dbg(2, debug, "vpif_release\n");
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ mutex_lock(&common->lock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ /* Reset io_usrs member of channel object */
+ common->io_usrs = 0;
+ /* Disable channel as per its device type and channel id */
+ if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
+ enable_channel0(0);
+ channel0_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel1(0);
+ channel1_intr_enable(0);
+ }
+ common->started = 0;
+ /* Free buffers allocated */
+ vb2_queue_release(&common->buffer_queue);
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
+ }
+
+ /* Decrement channel usrs counter */
+ ch->usrs--;
+
+ /* Close the priority */
+ v4l2_prio_close(&ch->prio, fh->prio);
+
+ if (fh->initialized)
+ ch->initialized = 0;
+
+ mutex_unlock(&common->lock);
+ filep->private_data = NULL;
+ kfree(fh);
+ return 0;
+}
+
+/**
+ * vpif_reqbufs() - request buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @reqbuf: request buffer structure ptr
+ */
+static int vpif_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ u8 index = 0;
+ struct vb2_queue *q;
+
+ vpif_dbg(2, debug, "vpif_reqbufs\n");
+
+ /**
+ * This file handle has not initialized the channel,
+ * It is not allowed to do settings
+ */
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev)
+ return -EINVAL;
+
+ index = VPIF_VIDEO_INDEX;
+
+ common = &ch->common[index];
+
+ if (0 != common->io_usrs)
+ return -EBUSY;
+
+ /* Initialize videobuf2 queue as per the buffer type */
+ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+ if (!common->alloc_ctx) {
+ vpif_err("Failed to get the context\n");
+ return -EINVAL;
+ }
+ q = &common->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = fh;
+ q->ops = &video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpif_cap_buffer);
+
+ vb2_queue_init(q);
+
+ /* Set io allowed member of file handle to TRUE */
+ fh->io_allowed[index] = 1;
+ /* Increment io usrs member of channel object to 1 */
+ common->io_usrs = 1;
+ /* Store type of memory requested in channel object */
+ common->memory = reqbuf->memory;
+ INIT_LIST_HEAD(&common->dma_queue);
+
+ /* Allocate buffers */
+ return vb2_reqbufs(&common->buffer_queue, reqbuf);
+}
+
+/**
+ * vpif_querybuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vpif_dbg(2, debug, "vpif_querybuf\n");
+
+ if (common->fmt.type != buf->type)
+ return -EINVAL;
+
+ if (common->memory != V4L2_MEMORY_MMAP) {
+ vpif_dbg(1, debug, "Invalid memory\n");
+ return -EINVAL;
+ }
+
+ return vb2_querybuf(&common->buffer_queue, buf);
+}
+
+/**
+ * vpif_qbuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_buffer tbuf = *buf;
+
+ vpif_dbg(2, debug, "vpif_qbuf\n");
+
+ if (common->fmt.type != tbuf.type) {
+ vpif_err("invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh io not allowed\n");
+ return -EACCES;
+ }
+
+ return vb2_qbuf(&common->buffer_queue, buf);
+}
+
+/**
+ * vpif_dqbuf() - query buffer handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buf: v4l2 buffer structure ptr
+ */
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vpif_dbg(2, debug, "vpif_dqbuf\n");
+
+ return vb2_dqbuf(&common->buffer_queue, buf,
+ (file->f_flags & O_NONBLOCK));
+}
+
+/**
+ * vpif_streamon() - streamon handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buftype: v4l2 buffer type
+ */
+static int vpif_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+ struct vpif_params *vpif;
+ int ret = 0;
+
+ vpif_dbg(2, debug, "vpif_streamon\n");
+
+ vpif = &ch->vpifparams;
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ vpif_dbg(1, debug, "buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ /* If file handle is not allowed IO, return error */
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_dbg(1, debug, "io not allowed\n");
+ return -EACCES;
+ }
+
+ /* If Streaming is already started, return error */
+ if (common->started) {
+ vpif_dbg(1, debug, "channel->started\n");
+ return -EBUSY;
+ }
+
+ if ((ch->channel_id == VPIF_CHANNEL0_VIDEO &&
+ oth_ch->common[VPIF_VIDEO_INDEX].started &&
+ vpif->std_info.ycmux_mode == 0) ||
+ ((ch->channel_id == VPIF_CHANNEL1_VIDEO) &&
+ (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+ vpif_dbg(1, debug, "other channel is being used\n");
+ return -EBUSY;
+ }
+
+ ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0);
+ if (ret)
+ return ret;
+
+ /* Enable streamon on the sub device */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+ s_stream, 1);
+
+ if (ret && (ret != -ENOIOCTLCMD)) {
+ vpif_dbg(1, debug, "stream on failed in subdev\n");
+ return ret;
+ }
+
+ /* Call vb2_streamon to start streaming in videobuf2 */
+ ret = vb2_streamon(&common->buffer_queue, buftype);
+ if (ret) {
+ vpif_dbg(1, debug, "vb2_streamon\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * vpif_streamoff() - streamoff handler
+ * @file: file ptr
+ * @priv: file handle
+ * @buftype: v4l2 buffer type
+ */
+static int vpif_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret;
+
+ vpif_dbg(2, debug, "vpif_streamoff\n");
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ vpif_dbg(1, debug, "buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ /* If io is allowed for this file handle, return error */
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_dbg(1, debug, "io not allowed\n");
+ return -EACCES;
+ }
+
+ /* If streaming is not started, return error */
+ if (!common->started) {
+ vpif_dbg(1, debug, "channel->started\n");
+ return -EINVAL;
+ }
+
+ /* disable channel */
+ if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
+ enable_channel0(0);
+ channel0_intr_enable(0);
+ } else {
+ enable_channel1(0);
+ channel1_intr_enable(0);
+ }
+
+ common->started = 0;
+
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+ s_stream, 0);
+
+ if (ret && (ret != -ENOIOCTLCMD))
+ vpif_dbg(1, debug, "stream off failed in subdev\n");
+
+ return vb2_streamoff(&common->buffer_queue, buftype);
+}
+
+/**
+ * vpif_map_sub_device_to_input() - Maps sub device to input
+ * @ch - ptr to channel
+ * @config - ptr to capture configuration
+ * @input_index - Given input index from application
+ * @sub_device_index - index into sd table
+ *
+ * lookup the sub device information for a given input index.
+ * we report all the inputs to application. inputs table also
+ * has sub device name for the each input
+ */
+static struct vpif_subdev_info *vpif_map_sub_device_to_input(
+ struct channel_obj *ch,
+ struct vpif_capture_config *vpif_cfg,
+ int input_index,
+ int *sub_device_index)
+{
+ struct vpif_capture_chan_config *chan_cfg;
+ struct vpif_subdev_info *subdev_info = NULL;
+ const char *subdev_name = NULL;
+ int i;
+
+ vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n");
+
+ chan_cfg = &vpif_cfg->chan_config[ch->channel_id];
+
+ /**
+ * search through the inputs to find the sub device supporting
+ * the input
+ */
+ for (i = 0; i < chan_cfg->input_count; i++) {
+ /* For each sub device, loop through input */
+ if (i == input_index) {
+ subdev_name = chan_cfg->inputs[i].subdev_name;
+ break;
+ }
+ }
+
+ /* if reached maximum. return null */
+ if (i == chan_cfg->input_count || (NULL == subdev_name))
+ return subdev_info;
+
+ /* loop through the sub device list to get the sub device info */
+ for (i = 0; i < vpif_cfg->subdev_count; i++) {
+ subdev_info = &vpif_cfg->subdev_info[i];
+ if (!strcmp(subdev_info->name, subdev_name))
+ break;
+ }
+
+ if (i == vpif_cfg->subdev_count)
+ return subdev_info;
+
+ /* check if the sub device is registered */
+ if (NULL == vpif_obj.sd[i])
+ return NULL;
+
+ *sub_device_index = i;
+ return subdev_info;
+}
+
+/**
+ * vpif_querystd() - querystd handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ *
+ * This function is called to detect standard at the selected input
+ */
+static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ int ret = 0;
+
+ vpif_dbg(2, debug, "vpif_querystd\n");
+
+ /* Call querystd function of decoder device */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
+ querystd, std_id);
+ if (ret < 0)
+ vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
+
+ return ret;
+}
+
+/**
+ * vpif_g_std() - get STD handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ */
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ vpif_dbg(2, debug, "vpif_g_std\n");
+
+ *std = ch->video.stdid;
+ return 0;
+}
+
+/**
+ * vpif_s_std() - set STD handler
+ * @file: file ptr
+ * @priv: file handle
+ * @std_id: ptr to std id
+ */
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ vpif_dbg(2, debug, "vpif_s_std\n");
+
+ if (common->started) {
+ vpif_err("streaming in progress\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (0 != ret)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ /* set standard in the sub device */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ s_std, *std_id);
+ if (ret < 0)
+ vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
+ return ret;
+}
+
+/**
+ * vpif_enum_input() - ENUMINPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @input: ptr to input structure
+ */
+static int vpif_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct vpif_capture_chan_config *chan_cfg;
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+
+ if (input->index >= chan_cfg->input_count) {
+ vpif_dbg(1, debug, "Invalid input index\n");
+ return -EINVAL;
+ }
+
+ memcpy(input, &chan_cfg->inputs[input->index].input,
+ sizeof(*input));
+ return 0;
+}
+
+/**
+ * vpif_g_input() - Get INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: ptr to input index
+ */
+static int vpif_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ *index = vid_ch->input_idx;
+
+ return 0;
+}
+
+/**
+ * vpif_s_input() - Set INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: input index
+ */
+static int vpif_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct vpif_capture_chan_config *chan_cfg;
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_subdev_info *subdev_info;
+ int ret = 0, sd_index = 0;
+ u32 input = 0, output = 0;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+
+ if (common->started) {
+ vpif_err("Streaming in progress\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (0 != ret)
+ return ret;
+
+ fh->initialized = 1;
+ subdev_info = vpif_map_sub_device_to_input(ch, config, index,
+ &sd_index);
+ if (NULL == subdev_info) {
+ vpif_dbg(1, debug,
+ "couldn't lookup sub device for the input index\n");
+ return -EINVAL;
+ }
+
+ /* first setup input path from sub device to vpif */
+ if (config->setup_input_path) {
+ ret = config->setup_input_path(ch->channel_id,
+ subdev_info->name);
+ if (ret < 0) {
+ vpif_dbg(1, debug, "couldn't setup input path for the"
+ " sub device %s, for input index %d\n",
+ subdev_info->name, index);
+ return ret;
+ }
+ }
+
+ if (subdev_info->can_route) {
+ input = subdev_info->input;
+ output = subdev_info->output;
+ ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing,
+ input, output, 0);
+ if (ret < 0) {
+ vpif_dbg(1, debug, "Failed to set input\n");
+ return ret;
+ }
+ }
+ vid_ch->input_idx = index;
+ ch->curr_subdev_info = subdev_info;
+ ch->curr_sd_index = sd_index;
+ /* copy interface parameters to vpif */
+ ch->vpifparams.iface = subdev_info->vpif_if;
+
+ /* update tvnorms from the sub device input info */
+ ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
+ return ret;
+}
+
+/**
+ * vpif_enum_fmt_vid_cap() - ENUM_FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @index: input index
+ */
+static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ if (fmt->index != 0) {
+ vpif_dbg(1, debug, "Invalid format index\n");
+ return -EINVAL;
+ }
+
+ /* Fill in the information about format */
+ if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb");
+ fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ } else {
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+ fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+ }
+ return 0;
+}
+
+/**
+ * vpif_try_fmt_vid_cap() - TRY_FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ return vpif_check_format(ch, pixfmt, 1);
+}
+
+
+/**
+ * vpif_g_fmt_vid_cap() - Set INPUT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* Check the validity of the buffer type */
+ if (common->fmt.type != fmt->type)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ *fmt = common->fmt;
+ return 0;
+}
+
+/**
+ * vpif_s_fmt_vid_cap() - Set FMT handler
+ * @file: file ptr
+ * @priv: file handle
+ * @fmt: ptr to v4l2 format structure
+ */
+static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_pix_format *pixfmt;
+ int ret = 0;
+
+ vpif_dbg(2, debug, "%s\n", __func__);
+
+ /* If streaming is started, return error */
+ if (common->started) {
+ vpif_dbg(1, debug, "Streaming is started\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (0 != ret)
+ return ret;
+
+ fh->initialized = 1;
+
+ pixfmt = &fmt->fmt.pix;
+ /* Check for valid field format */
+ ret = vpif_check_format(ch, pixfmt, 0);
+
+ if (ret)
+ return ret;
+ /* store the format in the channel object */
+ common->fmt = *fmt;
+ return 0;
+}
+
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
+static int vpif_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));
+ strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+ return 0;
+}
+
+/**
+ * vpif_g_priority() - get priority handler
+ * @file: file ptr
+ * @priv: file handle
+ * @prio: ptr to v4l2_priority structure
+ */
+static int vpif_g_priority(struct file *file, void *priv,
+ enum v4l2_priority *prio)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *prio = v4l2_prio_max(&ch->prio);
+
+ return 0;
+}
+
+/**
+ * vpif_s_priority() - set priority handler
+ * @file: file ptr
+ * @priv: file handle
+ * @prio: ptr to v4l2_priority structure
+ */
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/**
+ * vpif_cropcap() - cropcap handler
+ * @file: file ptr
+ * @priv: file handle
+ * @crop: ptr to v4l2_cropcap structure
+ */
+static int vpif_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type)
+ return -EINVAL;
+
+ crop->bounds.left = 0;
+ crop->bounds.top = 0;
+ crop->bounds.height = common->height;
+ crop->bounds.width = common->width;
+ crop->defrect = crop->bounds;
+ return 0;
+}
+
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_query_dv_presets() - QUERY_DV_PRESET handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_query_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, query_dv_preset, preset);
+}
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_std_info(ch)) {
+ vpif_dbg(1, debug, "Error getting the standard info\n");
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ 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) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
+/* vpif capture ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+ .vidioc_querycap = vpif_querycap,
+ .vidioc_g_priority = vpif_g_priority,
+ .vidioc_s_priority = vpif_s_priority,
+ .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap,
+ .vidioc_enum_input = vpif_enum_input,
+ .vidioc_s_input = vpif_s_input,
+ .vidioc_g_input = vpif_g_input,
+ .vidioc_reqbufs = vpif_reqbufs,
+ .vidioc_querybuf = vpif_querybuf,
+ .vidioc_querystd = vpif_querystd,
+ .vidioc_s_std = vpif_s_std,
+ .vidioc_g_std = vpif_g_std,
+ .vidioc_qbuf = vpif_qbuf,
+ .vidioc_dqbuf = vpif_dqbuf,
+ .vidioc_streamon = vpif_streamon,
+ .vidioc_streamoff = vpif_streamoff,
+ .vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_query_dv_preset = vpif_query_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
+};
+
+/* vpif file operations */
+static struct v4l2_file_operations vpif_fops = {
+ .owner = THIS_MODULE,
+ .open = vpif_open,
+ .release = vpif_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpif_mmap,
+ .poll = vpif_poll
+};
+
+/* vpif video template */
+static struct video_device vpif_video_template = {
+ .name = "vpif",
+ .fops = &vpif_fops,
+ .minor = -1,
+ .ioctl_ops = &vpif_ioctl_ops,
+};
+
+/**
+ * initialize_vpif() - Initialize vpif data structures
+ *
+ * Allocate memory for data structures and initialize them
+ */
+static int initialize_vpif(void)
+{
+ int err = 0, i, j;
+ int free_channel_objects_index;
+
+ /* Default number of buffers should be 3 */
+ if ((ch0_numbuffers > 0) &&
+ (ch0_numbuffers < config_params.min_numbuffers))
+ ch0_numbuffers = config_params.min_numbuffers;
+ if ((ch1_numbuffers > 0) &&
+ (ch1_numbuffers < config_params.min_numbuffers))
+ ch1_numbuffers = config_params.min_numbuffers;
+
+ /* Set buffer size to min buffers size if it is invalid */
+ if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO])
+ ch0_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL0_VIDEO];
+ if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO])
+ ch1_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL1_VIDEO];
+
+ config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers;
+ config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers;
+ if (ch0_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO]
+ = ch0_bufsize;
+ }
+ if (ch1_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO]
+ = ch1_bufsize;
+ }
+
+ /* Allocate memory for six channel objects */
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+ vpif_obj.dev[i] =
+ kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL);
+ /* If memory allocation fails, return error */
+ if (!vpif_obj.dev[i]) {
+ free_channel_objects_index = i;
+ err = -ENOMEM;
+ goto vpif_init_free_channel_objects;
+ }
+ }
+ return 0;
+
+vpif_init_free_channel_objects:
+ for (j = 0; j < free_channel_objects_index; j++)
+ kfree(vpif_obj.dev[j]);
+ return err;
+}
+
+/**
+ * vpif_probe : This function probes the vpif capture driver
+ * @pdev: platform device pointer
+ *
+ * This creates device entries by register itself to the V4L2 driver and
+ * initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+ struct vpif_subdev_info *subdevdata;
+ struct vpif_capture_config *config;
+ int i, j, k, m, q, err;
+ struct i2c_adapter *i2c_adap;
+ struct channel_obj *ch;
+ struct common_obj *common;
+ struct video_device *vfd;
+ struct resource *res;
+ int subdev_count;
+ size_t size;
+
+ vpif_dev = &pdev->dev;
+
+ err = initialize_vpif();
+ if (err) {
+ v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
+ 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++) {
+ if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
+ "VPIF_Capture",
+ (void *)(&vpif_obj.dev[k]->channel_id))) {
+ err = -EBUSY;
+ i--;
+ goto vpif_int_err;
+ }
+ }
+ k++;
+ }
+
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (NULL == vfd) {
+ for (j = 0; j < i; j++) {
+ ch = vpif_obj.dev[j];
+ video_device_release(ch->video_dev);
+ }
+ err = -ENOMEM;
+ goto vpif_dev_alloc_err;
+ }
+
+ /* Initialize field of video device */
+ *vfd = vpif_video_template;
+ vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "VPIF_Capture_DRIVER_V%s",
+ VPIF_CAPTURE_VERSION);
+ /* Set video_dev to the video device */
+ ch->video_dev = vfd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ size = resource_size(res);
+ /* The resources are divided into two equal memory and when we
+ * have HD output we can add them together
+ */
+ for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ ch->channel_id = j;
+ /* only enabled if second resource exists */
+ config_params.video_limit[ch->channel_id] = 0;
+ if (size)
+ config_params.video_limit[ch->channel_id] =
+ size/2;
+ }
+ }
+
+ for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ ch->channel_id = j;
+ common = &(ch->common[VPIF_VIDEO_INDEX]);
+ spin_lock_init(&common->irqlock);
+ mutex_init(&common->lock);
+ ch->video_dev->lock = &common->lock;
+ /* Initialize prio member of channel object */
+ v4l2_prio_init(&ch->prio);
+ err = video_register_device(ch->video_dev,
+ VFL_TYPE_GRABBER, (j ? 1 : 0));
+ if (err)
+ goto probe_out;
+
+ video_set_drvdata(ch->video_dev, ch);
+
+ }
+
+ i2c_adap = i2c_get_adapter(1);
+ config = pdev->dev.platform_data;
+
+ subdev_count = config->subdev_count;
+ vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ GFP_KERNEL);
+ if (vpif_obj.sd == NULL) {
+ vpif_err("unable to allocate memory for subdevice pointers\n");
+ err = -ENOMEM;
+ goto probe_out;
+ }
+
+ for (i = 0; i < subdev_count; i++) {
+ subdevdata = &config->subdev_info[i];
+ vpif_obj.sd[i] =
+ v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+ i2c_adap,
+ &subdevdata->board_info,
+ NULL);
+
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+ goto probe_subdev_out;
+ }
+ v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
+ subdevdata->name);
+
+ if (vpif_obj.sd[i])
+ vpif_obj.sd[i]->grp_id = 1 << i;
+ }
+
+ v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
+ return 0;
+
+probe_subdev_out:
+ /* free sub devices memory */
+ kfree(vpif_obj.sd);
+
+ j = VPIF_CAPTURE_MAX_DEVICES;
+probe_out:
+ for (k = 0; k < j; k++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[k];
+ /* Unregister video device */
+ video_unregister_device(ch->video_dev);
+ }
+
+vpif_dev_alloc_err:
+ k = VPIF_CAPTURE_MAX_DEVICES-1;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+ i = res->end;
+
+vpif_int_err:
+ for (q = k; q >= 0; q--) {
+ for (m = i; m >= (int)res->start; m--)
+ free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1);
+ if (res)
+ i = res->end;
+ }
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ return err;
+}
+
+/**
+ * vpif_remove() - driver remove handler
+ * @device: ptr to platform device structure
+ *
+ * The vidoe device is unregistered
+ */
+static int vpif_remove(struct platform_device *device)
+{
+ int i;
+ struct channel_obj *ch;
+
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+ /* un-register device */
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ /* Unregister video device */
+ video_unregister_device(ch->video_dev);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * vpif_suspend: vpif device suspend
+ */
+static int vpif_suspend(struct device *dev)
+{
+
+ struct common_obj *common;
+ struct channel_obj *ch;
+ int i;
+
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+ if (ch->usrs && common->io_usrs) {
+ /* Disable channel */
+ if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+ enable_channel0(0);
+ channel0_intr_enable(0);
+ }
+ if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+ common->started == 2) {
+ enable_channel1(0);
+ channel1_intr_enable(0);
+ }
+ }
+ mutex_unlock(&common->lock);
+ }
+
+ return 0;
+}
+
+/*
+ * vpif_resume: vpif device suspend
+ */
+static int vpif_resume(struct device *dev)
+{
+ struct common_obj *common;
+ struct channel_obj *ch;
+ int i;
+
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+ if (ch->usrs && common->io_usrs) {
+ /* Disable channel */
+ if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+ enable_channel0(1);
+ channel0_intr_enable(1);
+ }
+ if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+ common->started == 2) {
+ enable_channel1(1);
+ channel1_intr_enable(1);
+ }
+ }
+ mutex_unlock(&common->lock);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops vpif_dev_pm_ops = {
+ .suspend = vpif_suspend,
+ .resume = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_dev_pm_ops)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static __refdata struct platform_driver vpif_driver = {
+ .driver = {
+ .name = "vpif_capture",
+ .owner = THIS_MODULE,
+ .pm = vpif_pm_ops,
+ },
+ .probe = vpif_probe,
+ .remove = vpif_remove,
+};
+
+/**
+ * vpif_init: initialize the vpif driver
+ *
+ * This function registers device and driver to the kernel, requests irq
+ * handler and allocates memory
+ * for channel objects
+ */
+static __init int vpif_init(void)
+{
+ return platform_driver_register(&vpif_driver);
+}
+
+/**
+ * vpif_cleanup : This function clean up the vpif capture resources
+ *
+ * This will un-registers device and driver to the kernel, frees
+ * requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ int irq_num;
+ int i = 0;
+
+ pdev = container_of(vpif_dev, struct platform_device, dev);
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num,
+ (void *)(&vpif_obj.dev[i]->channel_id));
+ i++;
+ }
+
+ platform_driver_unregister(&vpif_driver);
+
+ kfree(vpif_obj.sd);
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
+ kfree(vpif_obj.dev[i]);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
index 3511510f43ee..3511510f43ee 100644
--- a/drivers/media/video/davinci/vpif_capture.h
+++ b/drivers/media/platform/davinci/vpif_capture.h
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
new file mode 100644
index 000000000000..4a24848c1a66
--- /dev/null
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -0,0 +1,2010 @@
+/*
+ * vpif-display - VPIF display driver
+ * Display driver for TI DaVinci VPIF
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "vpif_display.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_DISPLAY_VERSION);
+
+#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
+
+#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...) \
+ v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch2_numbuffers = 3;
+static u32 ch3_numbuffers = 3;
+static u32 ch2_bufsize = 1920 * 1080 * 2;
+static u32 ch3_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch2_numbuffers, uint, S_IRUGO);
+module_param(ch3_numbuffers, uint, S_IRUGO);
+module_param(ch2_bufsize, uint, S_IRUGO);
+module_param(ch3_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers[0] = 3,
+ .numbuffers[1] = 3,
+ .min_bufsize[0] = 720 * 480 * 2,
+ .min_bufsize[1] = 720 * 480 * 2,
+ .channel_bufsize[0] = 1920 * 1080 * 2,
+ .channel_bufsize[1] = 720 * 576 * 2,
+};
+
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+static void vpif_calculate_offsets(struct channel_obj *ch);
+static void vpif_config_addr(struct channel_obj *ch, int muxmode);
+
+/*
+ * buffer_prepare: This is the callback function called from vb2_qbuf()
+ * function the buffer is prepared and user space virtual address is converted
+ * into physical address
+ */
+static int vpif_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_queue *q = vb->vb2_queue;
+ struct common_obj *common;
+ unsigned long addr;
+
+ common = &fh->channel->common[VPIF_VIDEO_INDEX];
+ if (vb->state != VB2_BUF_STATE_ACTIVE &&
+ vb->state != VB2_BUF_STATE_PREPARED) {
+ vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ goto buf_align_exit;
+
+ addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (q->streaming &&
+ (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
+ if (!ISALIGNED(addr + common->ytop_off) ||
+ !ISALIGNED(addr + common->ybtm_off) ||
+ !ISALIGNED(addr + common->ctop_off) ||
+ !ISALIGNED(addr + common->cbtm_off))
+ goto buf_align_exit;
+ }
+ }
+ return 0;
+
+buf_align_exit:
+ vpif_err("buffer offset not aligned to 8 bytes\n");
+ return -EINVAL;
+}
+
+/*
+ * vpif_buffer_queue_setup: This function allocates memory for the buffers
+ */
+static int vpif_buffer_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ unsigned long size;
+
+ if (V4L2_MEMORY_MMAP == common->memory) {
+ size = config_params.channel_bufsize[ch->channel_id];
+ /*
+ * Checking if the buffer size exceeds the available buffer
+ * ycmux_mode = 0 means 1 channel mode HD and
+ * ycmux_mode = 1 means 2 channels mode SD
+ */
+ if (ch->vpifparams.std_info.ycmux_mode == 0) {
+ if (config_params.video_limit[ch->channel_id])
+ while (size * *nbuffers >
+ (config_params.video_limit[0]
+ + config_params.video_limit[1]))
+ (*nbuffers)--;
+ } else {
+ if (config_params.video_limit[ch->channel_id])
+ while (size * *nbuffers >
+ config_params.video_limit[ch->channel_id])
+ (*nbuffers)--;
+ }
+ } else {
+ size = common->fmt.fmt.pix.sizeimage;
+ }
+
+ if (*nbuffers < config_params.min_numbuffers)
+ *nbuffers = config_params.min_numbuffers;
+
+ *nplanes = 1;
+ sizes[0] = size;
+ alloc_ctxs[0] = common->alloc_ctx;
+ return 0;
+}
+
+/*
+ * vpif_buffer_queue: This function adds the buffer to DMA queue
+ */
+static void vpif_buffer_queue(struct vb2_buffer *vb)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpif_disp_buffer *buf = container_of(vb,
+ struct vpif_disp_buffer, vb);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* add the buffer to the DMA queue */
+ list_add_tail(&buf->list, &common->dma_queue);
+}
+
+/*
+ * vpif_buf_cleanup: This function is called from the videobuf2 layer to
+ * free memory allocated to the buffers
+ */
+static void vpif_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpif_disp_buffer *buf = container_of(vb,
+ struct vpif_disp_buffer, vb);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned long flags;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ spin_lock_irqsave(&common->irqlock, flags);
+ if (vb->state == VB2_BUF_STATE_ACTIVE)
+ list_del_init(&buf->list);
+ spin_unlock_irqrestore(&common->irqlock, flags);
+}
+
+static void vpif_wait_prepare(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_unlock(&common->lock);
+}
+
+static void vpif_wait_finish(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+}
+
+static int vpif_buffer_init(struct vb2_buffer *vb)
+{
+ struct vpif_disp_buffer *buf = container_of(vb,
+ struct vpif_disp_buffer, vb);
+
+ INIT_LIST_HEAD(&buf->list);
+
+ return 0;
+}
+
+static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
+
+static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vpif_display_config *vpif_config_data =
+ vpif_dev->platform_data;
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpif = &ch->vpifparams;
+ unsigned long addr = 0;
+ int ret;
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&common->dma_queue)) {
+ vpif_err("buffer queue is empty\n");
+ return -EIO;
+ }
+
+ /* Get the next frame from the buffer queue */
+ common->next_frm = common->cur_frm =
+ list_entry(common->dma_queue.next,
+ struct vpif_disp_buffer, list);
+
+ list_del(&common->cur_frm->list);
+ /* Mark state of the current frame to active */
+ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+ /* Initialize field_id and started member */
+ ch->field_id = 0;
+ common->started = 1;
+ addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
+ if ((ch->vpifparams.std_info.frm_fmt &&
+ ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
+ && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
+ || (!ch->vpifparams.std_info.frm_fmt
+ && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+ vpif_err("conflict in field format and std format\n");
+ return -EINVAL;
+ }
+
+ /* clock settings */
+ ret =
+ vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
+ ch->vpifparams.std_info.hd_sd);
+ if (ret < 0) {
+ vpif_err("can't set clock\n");
+ return ret;
+ }
+
+ /* set the parameters and addresses */
+ ret = vpif_set_video_params(vpif, ch->channel_id + 2);
+ if (ret < 0)
+ return ret;
+
+ common->started = ret;
+ vpif_config_addr(ch, ret);
+ common->set_addr((addr + common->ytop_off),
+ (addr + common->ybtm_off),
+ (addr + common->ctop_off),
+ (addr + common->cbtm_off));
+
+ /* Set interrupt for both the fields in VPIF
+ Register enable channel in VPIF register */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ channel2_intr_assert();
+ channel2_intr_enable(1);
+ enable_channel2(1);
+ if (vpif_config_data->ch2_clip_en)
+ channel2_clipping_enable(1);
+ }
+
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
+ || (common->started == 2)) {
+ channel3_intr_assert();
+ channel3_intr_enable(1);
+ enable_channel3(1);
+ if (vpif_config_data->ch3_clip_en)
+ channel3_clipping_enable(1);
+ }
+ channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+
+ return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int vpif_stop_streaming(struct vb2_queue *vq)
+{
+ struct vpif_fh *fh = vb2_get_drv_priv(vq);
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+
+ if (!vb2_is_streaming(vq))
+ return 0;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* release all active buffers */
+ while (!list_empty(&common->dma_queue)) {
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_disp_buffer, list);
+ list_del(&common->next_frm->list);
+ vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ return 0;
+}
+
+static struct vb2_ops video_qops = {
+ .queue_setup = vpif_buffer_queue_setup,
+ .wait_prepare = vpif_wait_prepare,
+ .wait_finish = vpif_wait_finish,
+ .buf_init = vpif_buffer_init,
+ .buf_prepare = vpif_buffer_prepare,
+ .start_streaming = vpif_start_streaming,
+ .stop_streaming = vpif_stop_streaming,
+ .buf_cleanup = vpif_buf_cleanup,
+ .buf_queue = vpif_buffer_queue,
+};
+
+static void process_progressive_mode(struct common_obj *common)
+{
+ unsigned long addr = 0;
+
+ /* Get the next buffer from buffer queue */
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_disp_buffer, list);
+ /* Remove that buffer from the buffer queue */
+ list_del(&common->next_frm->list);
+ /* Mark status of the buffer as active */
+ common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+ /* Set top and bottom field addrs in VPIF registers */
+ addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
+ common->set_addr(addr + common->ytop_off,
+ addr + common->ybtm_off,
+ addr + common->ctop_off,
+ addr + common->cbtm_off);
+}
+
+static void process_interlaced_mode(int fid, struct common_obj *common)
+{
+ /* device field id and local field id are in sync */
+ /* If this is even field */
+ if (0 == fid) {
+ if (common->cur_frm == common->next_frm)
+ return;
+
+ /* one frame is displayed If next frame is
+ * available, release cur_frm and move on */
+ /* Copy frame display time */
+ do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+ /* Change status of the cur_frm */
+ vb2_buffer_done(&common->cur_frm->vb,
+ VB2_BUF_STATE_DONE);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+
+ } else if (1 == fid) { /* odd field */
+ if (list_empty(&common->dma_queue)
+ || (common->cur_frm != common->next_frm)) {
+ return;
+ }
+ /* one field is displayed configure the next
+ * frame if it is available else hold on current
+ * frame */
+ /* Get next from the buffer queue */
+ process_progressive_mode(common);
+
+ }
+}
+
+/*
+ * vpif_channel_isr: It changes status of the displayed buffer, takes next
+ * buffer from the queue and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+ struct vpif_device *dev = &vpif_obj;
+ struct channel_obj *ch;
+ struct common_obj *common;
+ enum v4l2_field field;
+ int fid = -1, i;
+ int channel_id = 0;
+
+ channel_id = *(int *)(dev_id);
+ if (!vpif_intr_status(channel_id + 2))
+ return IRQ_NONE;
+
+ ch = dev->dev[channel_id];
+ field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+ for (i = 0; i < VPIF_NUMOBJECTS; i++) {
+ common = &ch->common[i];
+ /* If streaming is started in this channel */
+ if (0 == common->started)
+ continue;
+
+ if (1 == ch->vpifparams.std_info.frm_fmt) {
+ if (list_empty(&common->dma_queue))
+ continue;
+
+ /* Progressive mode */
+ if (!channel_first_int[i][channel_id]) {
+ /* Mark status of the cur_frm to
+ * done and unlock semaphore on it */
+ do_gettimeofday(&common->cur_frm->vb.
+ v4l2_buf.timestamp);
+ vb2_buffer_done(&common->cur_frm->vb,
+ VB2_BUF_STATE_DONE);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+ }
+
+ channel_first_int[i][channel_id] = 0;
+ process_progressive_mode(common);
+ } else {
+ /* Interlaced mode */
+ /* If it is first interrupt, ignore it */
+
+ if (channel_first_int[i][channel_id]) {
+ channel_first_int[i][channel_id] = 0;
+ continue;
+ }
+
+ if (0 == i) {
+ ch->field_id ^= 1;
+ /* Get field id from VPIF registers */
+ fid = vpif_channel_getfid(ch->channel_id + 2);
+ /* If fid does not match with stored field id */
+ if (fid != ch->field_id) {
+ /* Make them in sync */
+ if (0 == fid)
+ ch->field_id = fid;
+
+ return IRQ_HANDLED;
+ }
+ }
+ process_interlaced_mode(fid, common);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int vpif_update_std_info(struct channel_obj *ch)
+{
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ const struct vpif_channel_config_params *config;
+
+ int i;
+
+ for (i = 0; i < vpif_ch_params_count; i++) {
+ config = &ch_params[i];
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ }
+ }
+
+ if (i == vpif_ch_params_count) {
+ vpif_dbg(1, debug, "Format not found\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vpif_update_resolution(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+
+ if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
+ return -EINVAL;
+
+ if (vid_ch->stdid || vid_ch->dv_preset) {
+ if (vpif_update_std_info(ch))
+ return -EINVAL;
+ }
+
+ common->fmt.fmt.pix.width = std_info->width;
+ common->fmt.fmt.pix.height = std_info->height;
+ vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
+ common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
+
+ /* Set height and width paramateres */
+ common->height = std_info->height;
+ common->width = std_info->width;
+
+ return 0;
+}
+
+/*
+ * vpif_calculate_offsets: This function calculates buffers offset for Y and C
+ * in the top and bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ enum v4l2_field field = common->fmt.fmt.pix.field;
+ struct video_obj *vid_ch = &ch->video;
+ unsigned int hpitch, vpitch, sizeimage;
+
+ if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
+ if (ch->vpifparams.std_info.frm_fmt)
+ vid_ch->buf_field = V4L2_FIELD_NONE;
+ else
+ vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+ } else {
+ vid_ch->buf_field = common->fmt.fmt.pix.field;
+ }
+
+ sizeimage = common->fmt.fmt.pix.sizeimage;
+
+ hpitch = common->fmt.fmt.pix.bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ common->ytop_off = 0;
+ common->ybtm_off = hpitch;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = sizeimage / 2 + hpitch;
+ } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+ common->ytop_off = 0;
+ common->ybtm_off = sizeimage / 4;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = common->ctop_off + sizeimage / 4;
+ } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+ common->ybtm_off = 0;
+ common->ytop_off = sizeimage / 4;
+ common->cbtm_off = sizeimage / 2;
+ common->ctop_off = common->cbtm_off + sizeimage / 4;
+ }
+
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ vpifparams->video_params.storage_mode = 1;
+ } else {
+ vpifparams->video_params.storage_mode = 0;
+ }
+
+ if (ch->vpifparams.std_info.frm_fmt == 1) {
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ } else {
+ if ((field == V4L2_FIELD_ANY) ||
+ (field == V4L2_FIELD_INTERLACED))
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline * 2;
+ else
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ }
+
+ ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
+}
+
+static void vpif_config_format(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+ if (config_params.numbuffers[ch->channel_id] == 0)
+ common->memory = V4L2_MEMORY_USERPTR;
+ else
+ common->memory = V4L2_MEMORY_MMAP;
+
+ common->fmt.fmt.pix.sizeimage =
+ config_params.channel_bufsize[ch->channel_id];
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+ common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+}
+
+static int vpif_check_format(struct channel_obj *ch,
+ struct v4l2_pix_format *pixfmt)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ enum v4l2_field field = pixfmt->field;
+ u32 sizeimage, hpitch, vpitch;
+
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+ goto invalid_fmt_exit;
+
+ if (!(VPIF_VALID_FIELD(field)))
+ goto invalid_fmt_exit;
+
+ if (pixfmt->bytesperline <= 0)
+ goto invalid_pitch_exit;
+
+ sizeimage = pixfmt->sizeimage;
+
+ if (vpif_update_resolution(ch))
+ return -EINVAL;
+
+ hpitch = pixfmt->bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+
+ /* Check for valid value of pitch */
+ if ((hpitch < ch->vpifparams.std_info.width) ||
+ (vpitch < ch->vpifparams.std_info.height))
+ goto invalid_pitch_exit;
+
+ /* Check for 8 byte alignment */
+ if (!ISALIGNED(hpitch)) {
+ vpif_err("invalid pitch alignment\n");
+ return -EINVAL;
+ }
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+
+ return 0;
+
+invalid_fmt_exit:
+ vpif_err("invalid field format\n");
+ return -EINVAL;
+
+invalid_pitch_exit:
+ vpif_err("invalid pitch\n");
+ return -EINVAL;
+}
+
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {
+ common->set_addr = ch3_set_videobuf_addr;
+ } else {
+ if (2 == muxmode)
+ common->set_addr = ch2_set_videobuf_addr_yc_nmux;
+ else
+ common->set_addr = ch2_set_videobuf_addr;
+ }
+}
+
+/*
+ * vpif_mmap: It is used to map kernel space buffers into user spaces
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+ int ret;
+
+ vpif_dbg(2, debug, "vpif_mmap\n");
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&common->buffer_queue, vma);
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+/*
+ * vpif_poll: It is used for select/poll system call
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table *wait)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ unsigned int res = 0;
+
+ if (common->started) {
+ mutex_lock(&common->lock);
+ res = vb2_poll(&common->buffer_queue, filep, wait);
+ mutex_unlock(&common->lock);
+ }
+
+ return res;
+}
+
+/*
+ * vpif_open: It creates object of file handle structure and stores it in
+ * private_data member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+ struct video_device *vdev = video_devdata(filep);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_fh *fh;
+
+ /* Allocate memory for the file handle object */
+ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ if (fh == NULL) {
+ vpif_err("unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+
+ if (mutex_lock_interruptible(&common->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ /* store pointer to fh in private_data member of filep */
+ filep->private_data = fh;
+ fh->channel = ch;
+ fh->initialized = 0;
+ if (!ch->initialized) {
+ fh->initialized = 1;
+ ch->initialized = 1;
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+ }
+
+ /* Increment channel usrs counter */
+ atomic_inc(&ch->usrs);
+ /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
+ fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&ch->prio, &fh->prio);
+ mutex_unlock(&common->lock);
+
+ return 0;
+}
+
+/*
+ * vpif_release: This function deletes buffer queue, frees the buffers and
+ * the vpif file handle
+ */
+static int vpif_release(struct file *filep)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ mutex_lock(&common->lock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ /* Reset io_usrs member of channel object */
+ common->io_usrs = 0;
+ /* Disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ common->started = 0;
+
+ /* Free buffers allocated */
+ vb2_queue_release(&common->buffer_queue);
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
+
+ common->numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ }
+
+ /* Decrement channel usrs counter */
+ atomic_dec(&ch->usrs);
+ /* If this file handle has initialize encoder device, reset it */
+ if (fh->initialized)
+ ch->initialized = 0;
+
+ /* Close the priority */
+ v4l2_prio_close(&ch->prio, fh->prio);
+ filep->private_data = NULL;
+ fh->initialized = 0;
+ mutex_unlock(&common->lock);
+ kfree(fh);
+
+ return 0;
+}
+
+/* functions implementing ioctls */
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
+static int vpif_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpif_display_config *config = vpif_dev->platform_data;
+
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
+ strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+ return 0;
+}
+
+static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index != 0) {
+ vpif_err("Invalid format index\n");
+ return -EINVAL;
+ }
+
+ /* Fill in the information about format */
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+ fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+
+ return 0;
+}
+
+static int vpif_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* Check the validity of the buffer type */
+ if (common->fmt.type != fmt->type)
+ return -EINVAL;
+
+ if (vpif_update_resolution(ch))
+ return -EINVAL;
+ *fmt = common->fmt;
+ return 0;
+}
+
+static int vpif_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct v4l2_pix_format *pixfmt;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+
+ /* Check for the priority */
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (0 != ret)
+ return ret;
+ fh->initialized = 1;
+ }
+
+ if (common->started) {
+ vpif_dbg(1, debug, "Streaming in progress\n");
+ return -EBUSY;
+ }
+
+ pixfmt = &fmt->fmt.pix;
+ /* Check for valid field format */
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret)
+ return ret;
+
+ /* store the pix format in the channel object */
+ common->fmt.fmt.pix = *pixfmt;
+ /* store the format in the channel object */
+ common->fmt = *fmt;
+ return 0;
+}
+
+static int vpif_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ int ret = 0;
+
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret) {
+ *pixfmt = common->fmt.fmt.pix;
+ pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
+ }
+
+ return ret;
+}
+
+static int vpif_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ enum v4l2_field field;
+ struct vb2_queue *q;
+ u8 index = 0;
+
+ /* This file handle has not initialized the channel,
+ It is not allowed to do settings */
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_err("Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
+ return -EINVAL;
+
+ index = VPIF_VIDEO_INDEX;
+
+ common = &ch->common[index];
+
+ if (common->fmt.type != reqbuf->type || !vpif_dev)
+ return -EINVAL;
+ if (0 != common->io_usrs)
+ return -EBUSY;
+
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_INTERLACED;
+ else
+ field = common->fmt.fmt.pix.field;
+ } else {
+ field = V4L2_VBI_INTERLACED;
+ }
+ /* Initialize videobuf2 queue as per the buffer type */
+ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+ if (!common->alloc_ctx) {
+ vpif_err("Failed to get the context\n");
+ return -EINVAL;
+ }
+ q = &common->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = fh;
+ q->ops = &video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpif_disp_buffer);
+
+ vb2_queue_init(q);
+
+ /* Set io allowed member of file handle to TRUE */
+ fh->io_allowed[index] = 1;
+ /* Increment io usrs member of channel object to 1 */
+ common->io_usrs = 1;
+ /* Store type of memory requested in channel object */
+ common->memory = reqbuf->memory;
+ INIT_LIST_HEAD(&common->dma_queue);
+ /* Allocate buffers */
+ return vb2_reqbufs(&common->buffer_queue, reqbuf);
+}
+
+static int vpif_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *tbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (common->fmt.type != tbuf->type)
+ return -EINVAL;
+
+ return vb2_querybuf(&common->buffer_queue, tbuf);
+}
+
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct vpif_fh *fh = NULL;
+ struct channel_obj *ch = NULL;
+ struct common_obj *common = NULL;
+
+ if (!buf || !priv)
+ return -EINVAL;
+
+ fh = priv;
+ ch = fh->channel;
+ if (!ch)
+ return -EINVAL;
+
+ common = &(ch->common[VPIF_VIDEO_INDEX]);
+ if (common->fmt.type != buf->type)
+ return -EINVAL;
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ return vb2_qbuf(&common->buffer_queue, buf);
+}
+
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (!(*std_id & VPIF_V4L2_STD))
+ return -EINVAL;
+
+ if (common->started) {
+ vpif_err("streaming in progress\n");
+ return -EBUSY;
+ }
+
+ /* Call encoder subdevice function to set the standard */
+ ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_resolution(ch))
+ return -EINVAL;
+
+ if ((ch->vpifparams.std_info.width *
+ ch->vpifparams.std_info.height * 2) >
+ config_params.channel_bufsize[ch->channel_id]) {
+ vpif_err("invalid std for this size\n");
+ return -EINVAL;
+ }
+
+ common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_std_output, *std_id);
+ if (ret < 0) {
+ vpif_err("Failed to set output standard\n");
+ return ret;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
+ s_std, *std_id);
+ if (ret < 0)
+ vpif_err("Failed to set standard for sub devices\n");
+ return ret;
+}
+
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *std = ch->video.stdid;
+ return 0;
+}
+
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ return vb2_dqbuf(&common->buffer_queue, p,
+ (file->f_flags & O_NONBLOCK));
+}
+
+static int vpif_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+ int ret = 0;
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If Streaming is already started, return error */
+ if (common->started) {
+ vpif_err("channel->started\n");
+ return -EBUSY;
+ }
+
+ if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
+ && oth_ch->common[VPIF_VIDEO_INDEX].started &&
+ ch->vpifparams.std_info.ycmux_mode == 0)
+ || ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
+ && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+ vpif_err("other channel is using\n");
+ return -EBUSY;
+ }
+
+ ret = vpif_check_format(ch, &common->fmt.fmt.pix);
+ if (ret < 0)
+ return ret;
+
+ /* Call vb2_streamon to start streaming in videobuf2 */
+ ret = vb2_streamon(&common->buffer_queue, buftype);
+ if (ret < 0) {
+ vpif_err("vb2_streamon\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int vpif_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_display_config *vpif_config_data =
+ vpif_dev->platform_data;
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ if (!common->started) {
+ vpif_err("channel->started\n");
+ return -EINVAL;
+ }
+
+ if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ /* disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ if (vpif_config_data->ch2_clip_en)
+ channel2_clipping_enable(0);
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ if (vpif_config_data->ch3_clip_en)
+ channel3_clipping_enable(0);
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ }
+
+ common->started = 0;
+ return vb2_streamoff(&common->buffer_queue, buftype);
+}
+
+static int vpif_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
+ return -EINVAL;
+
+ crop->bounds.left = crop->bounds.top = 0;
+ crop->defrect.left = crop->defrect.top = 0;
+ crop->defrect.height = crop->bounds.height = common->height;
+ crop->defrect.width = crop->bounds.width = common->width;
+
+ return 0;
+}
+
+static int vpif_enum_output(struct file *file, void *fh,
+ struct v4l2_output *output)
+{
+
+ struct vpif_display_config *config = vpif_dev->platform_data;
+
+ if (output->index >= config->output_count) {
+ vpif_dbg(1, debug, "Invalid output index\n");
+ return -EINVAL;
+ }
+
+ strcpy(output->name, config->output[output->index]);
+ output->type = V4L2_OUTPUT_TYPE_ANALOG;
+ output->std = VPIF_V4L2_STD;
+
+ return 0;
+}
+
+static int vpif_s_output(struct file *file, void *priv, unsigned int i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (common->started) {
+ vpif_err("Streaming in progress\n");
+ return -EBUSY;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_routing, 0, i, 0);
+
+ if (ret < 0)
+ vpif_err("Failed to set output standard\n");
+
+ vid_ch->output_id = i;
+ return ret;
+}
+
+static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ *i = vid_ch->output_id;
+
+ return 0;
+}
+
+static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *p = v4l2_prio_max(&ch->prio);
+
+ return 0;
+}
+
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret != 0)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_resolution(ch)) {
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120",
+ VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ 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) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
+/* vpif display ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+ .vidioc_querycap = vpif_querycap,
+ .vidioc_g_priority = vpif_g_priority,
+ .vidioc_s_priority = vpif_s_priority,
+ .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
+ .vidioc_reqbufs = vpif_reqbufs,
+ .vidioc_querybuf = vpif_querybuf,
+ .vidioc_qbuf = vpif_qbuf,
+ .vidioc_dqbuf = vpif_dqbuf,
+ .vidioc_streamon = vpif_streamon,
+ .vidioc_streamoff = vpif_streamoff,
+ .vidioc_s_std = vpif_s_std,
+ .vidioc_g_std = vpif_g_std,
+ .vidioc_enum_output = vpif_enum_output,
+ .vidioc_s_output = vpif_s_output,
+ .vidioc_g_output = vpif_g_output,
+ .vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
+};
+
+static const struct v4l2_file_operations vpif_fops = {
+ .owner = THIS_MODULE,
+ .open = vpif_open,
+ .release = vpif_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpif_mmap,
+ .poll = vpif_poll
+};
+
+static struct video_device vpif_video_template = {
+ .name = "vpif",
+ .fops = &vpif_fops,
+ .ioctl_ops = &vpif_ioctl_ops,
+ .tvnorms = VPIF_V4L2_STD,
+ .current_norm = V4L2_STD_625_50,
+
+};
+
+/*Configure the channels, buffer sizei, request irq */
+static int initialize_vpif(void)
+{
+ int free_channel_objects_index;
+ int free_buffer_channel_index;
+ int free_buffer_index;
+ int err = 0, i, j;
+
+ /* Default number of buffers should be 3 */
+ if ((ch2_numbuffers > 0) &&
+ (ch2_numbuffers < config_params.min_numbuffers))
+ ch2_numbuffers = config_params.min_numbuffers;
+ if ((ch3_numbuffers > 0) &&
+ (ch3_numbuffers < config_params.min_numbuffers))
+ ch3_numbuffers = config_params.min_numbuffers;
+
+ /* Set buffer size to min buffers size if invalid buffer size is
+ * given */
+ if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
+ ch2_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
+ if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
+ ch3_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
+
+ config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
+
+ if (ch2_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
+ ch2_bufsize;
+ }
+ config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
+
+ if (ch3_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
+ ch3_bufsize;
+ }
+
+ /* Allocate memory for six channel objects */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ vpif_obj.dev[i] =
+ kzalloc(sizeof(struct channel_obj), GFP_KERNEL);
+ /* If memory allocation fails, return error */
+ if (!vpif_obj.dev[i]) {
+ free_channel_objects_index = i;
+ err = -ENOMEM;
+ goto vpif_init_free_channel_objects;
+ }
+ }
+
+ free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
+ free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
+ free_buffer_index = config_params.numbuffers[i - 1];
+
+ return 0;
+
+vpif_init_free_channel_objects:
+ for (j = 0; j < free_channel_objects_index; j++)
+ kfree(vpif_obj.dev[j]);
+ return err;
+}
+
+/*
+ * vpif_probe: This function creates device entries by register itself to the
+ * V4L2 driver and initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+ struct vpif_subdev_info *subdevdata;
+ struct vpif_display_config *config;
+ int i, j = 0, k, q, m, err = 0;
+ struct i2c_adapter *i2c_adap;
+ struct common_obj *common;
+ struct channel_obj *ch;
+ struct video_device *vfd;
+ struct resource *res;
+ int subdev_count;
+ size_t size;
+
+ vpif_dev = &pdev->dev;
+ err = initialize_vpif();
+
+ if (err) {
+ v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
+ 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++) {
+ if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
+ "VPIF_Display",
+ (void *)(&vpif_obj.dev[k]->channel_id))) {
+ err = -EBUSY;
+ goto vpif_int_err;
+ }
+ }
+ k++;
+ }
+
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (vfd == NULL) {
+ for (j = 0; j < i; j++) {
+ ch = vpif_obj.dev[j];
+ video_device_release(ch->video_dev);
+ }
+ err = -ENOMEM;
+ goto vpif_int_err;
+ }
+
+ /* Initialize field of video device */
+ *vfd = vpif_video_template;
+ vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "VPIF_Display_DRIVER_V%s",
+ VPIF_DISPLAY_VERSION);
+
+ /* Set video_dev to the video device */
+ ch->video_dev = vfd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ size = resource_size(res);
+ /* The resources are divided into two equal memory and when
+ * we have HD output we can add them together
+ */
+ for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ ch->channel_id = j;
+
+ /* only enabled if second resource exists */
+ config_params.video_limit[ch->channel_id] = 0;
+ if (size)
+ config_params.video_limit[ch->channel_id] =
+ size/2;
+ }
+ }
+
+ for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ /* Initialize field of the channel objects */
+ atomic_set(&ch->usrs, 0);
+ for (k = 0; k < VPIF_NUMOBJECTS; k++) {
+ ch->common[k].numbuffers = 0;
+ common = &ch->common[k];
+ common->io_usrs = 0;
+ common->started = 0;
+ spin_lock_init(&common->irqlock);
+ mutex_init(&common->lock);
+ common->numbuffers = 0;
+ common->set_addr = NULL;
+ common->ytop_off = common->ybtm_off = 0;
+ common->ctop_off = common->cbtm_off = 0;
+ common->cur_frm = common->next_frm = NULL;
+ memset(&common->fmt, 0, sizeof(common->fmt));
+ common->numbuffers = config_params.numbuffers[k];
+
+ }
+ ch->initialized = 0;
+ ch->channel_id = j;
+ if (j < 2)
+ ch->common[VPIF_VIDEO_INDEX].numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ else
+ ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
+
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+
+ /* Initialize prio member of channel object */
+ v4l2_prio_init(&ch->prio);
+ ch->common[VPIF_VIDEO_INDEX].fmt.type =
+ V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ch->video_dev->lock = &common->lock;
+
+ /* register video device */
+ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
+ (int)ch, (int)&ch->video_dev);
+
+ err = video_register_device(ch->video_dev,
+ VFL_TYPE_GRABBER, (j ? 3 : 2));
+ if (err < 0)
+ goto probe_out;
+
+ video_set_drvdata(ch->video_dev, ch);
+ }
+
+ i2c_adap = i2c_get_adapter(1);
+ config = pdev->dev.platform_data;
+ subdev_count = config->subdev_count;
+ subdevdata = config->subdevinfo;
+ vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ GFP_KERNEL);
+ if (vpif_obj.sd == NULL) {
+ vpif_err("unable to allocate memory for subdevice pointers\n");
+ err = -ENOMEM;
+ goto probe_out;
+ }
+
+ for (i = 0; i < subdev_count; i++) {
+ vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+ i2c_adap,
+ &subdevdata[i].board_info,
+ NULL);
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+ goto probe_subdev_out;
+ }
+
+ if (vpif_obj.sd[i])
+ vpif_obj.sd[i]->grp_id = 1 << i;
+ }
+
+ v4l2_info(&vpif_obj.v4l2_dev,
+ " VPIF display driver initialized\n");
+ return 0;
+
+probe_subdev_out:
+ kfree(vpif_obj.sd);
+probe_out:
+ for (k = 0; k < j; k++) {
+ ch = vpif_obj.dev[k];
+ video_unregister_device(ch->video_dev);
+ video_device_release(ch->video_dev);
+ ch->video_dev = NULL;
+ }
+vpif_int_err:
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ vpif_err("VPIF IRQ request failed\n");
+ for (q = k; k >= 0; k--) {
+ for (m = i; m >= res->start; m--)
+ free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
+ m = res->end;
+ }
+
+ return err;
+}
+
+/*
+ * vpif_remove: It un-register channels from V4L2 driver
+ */
+static int vpif_remove(struct platform_device *device)
+{
+ struct channel_obj *ch;
+ int i;
+
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+ /* un-register device */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ /* Unregister video device */
+ video_unregister_device(ch->video_dev);
+
+ ch->video_dev = NULL;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int vpif_suspend(struct device *dev)
+{
+ struct common_obj *common;
+ struct channel_obj *ch;
+ int i;
+
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+ if (atomic_read(&ch->usrs) && common->io_usrs) {
+ /* Disable channel */
+ if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+ common->started == 2) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ }
+ mutex_unlock(&common->lock);
+ }
+
+ return 0;
+}
+
+static int vpif_resume(struct device *dev)
+{
+
+ struct common_obj *common;
+ struct channel_obj *ch;
+ int i;
+
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
+ mutex_lock(&common->lock);
+ if (atomic_read(&ch->usrs) && common->io_usrs) {
+ /* Enable channel */
+ if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+ enable_channel2(1);
+ channel2_intr_enable(1);
+ }
+ if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+ common->started == 2) {
+ enable_channel3(1);
+ channel3_intr_enable(1);
+ }
+ }
+ mutex_unlock(&common->lock);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops vpif_pm = {
+ .suspend = vpif_suspend,
+ .resume = vpif_resume,
+};
+
+#define vpif_pm_ops (&vpif_pm)
+#else
+#define vpif_pm_ops NULL
+#endif
+
+static __refdata struct platform_driver vpif_driver = {
+ .driver = {
+ .name = "vpif_display",
+ .owner = THIS_MODULE,
+ .pm = vpif_pm_ops,
+ },
+ .probe = vpif_probe,
+ .remove = vpif_remove,
+};
+
+static __init int vpif_init(void)
+{
+ return platform_driver_register(&vpif_driver);
+}
+
+/*
+ * vpif_cleanup: This function un-registers device and driver to the kernel,
+ * frees requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ int irq_num;
+ int i = 0;
+
+ pdev = container_of(vpif_dev, struct platform_device, dev);
+
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num,
+ (void *)(&vpif_obj.dev[i]->channel_id));
+ i++;
+ }
+
+ platform_driver_unregister(&vpif_driver);
+ kfree(vpif_obj.sd);
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
+ kfree(vpif_obj.dev[i]);
+}
+
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h
index 8967ffb44058..8967ffb44058 100644
--- a/drivers/media/video/davinci/vpif_display.h
+++ b/drivers/media/platform/davinci/vpif_display.h
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
new file mode 100644
index 000000000000..146e4b01ac17
--- /dev/null
+++ b/drivers/media/platform/davinci/vpss.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * 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.
+ *
+ * common vpss system module platform driver for all video drivers.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <media/davinci/vpss.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPSS Driver");
+MODULE_AUTHOR("Texas Instruments");
+
+/* DM644x defines */
+#define DM644X_SBL_PCR_VPSS (4)
+
+#define DM355_VPSSBL_INTSEL 0x10
+#define DM355_VPSSBL_EVTSEL 0x14
+/* vpss BL register offsets */
+#define DM355_VPSSBL_CCDCMUX 0x1c
+/* vpss CLK register offsets */
+#define DM355_VPSSCLK_CLKCTRL 0x04
+/* masks and shifts */
+#define VPSS_HSSISEL_SHIFT 4
+/*
+ * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4,
+ * IPIPE_INT1_SDR - vpss_int5
+ */
+#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10
+/* VENCINT - vpss_int8 */
+#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4
+
+#define DM365_ISP5_PCCR 0x04
+#define DM365_ISP5_INTSEL1 0x10
+#define DM365_ISP5_INTSEL2 0x14
+#define DM365_ISP5_INTSEL3 0x18
+#define DM365_ISP5_CCDCMUX 0x20
+#define DM365_ISP5_PG_FRAME_SIZE 0x28
+#define DM365_VPBE_CLK_CTRL 0x00
+/*
+ * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
+ * AF - vpss_int3
+ */
+#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100
+/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */
+#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f
+/* VENC - vpss_int8 */
+#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015
+
+/* masks and shifts for DM365*/
+#define DM365_CCDC_PG_VD_POL_SHIFT 0
+#define DM365_CCDC_PG_HD_POL_SHIFT 1
+
+#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4))
+#define CCD_SRC_SEL_SHIFT 4
+
+/* Different SoC platforms supported by this driver */
+enum vpss_platform_type {
+ DM644X,
+ DM355,
+ DM365,
+};
+
+/*
+ * vpss operations. Depends on platform. Not all functions are available
+ * on all platforms. The api, first check if a functio is available before
+ * invoking it. In the probe, the function ptrs are initialized based on
+ * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
+ */
+struct vpss_hw_ops {
+ /* enable clock */
+ int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
+ /* select input to ccdc */
+ void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
+ /* clear wbl overflow bit */
+ int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+};
+
+/* vpss configuration */
+struct vpss_oper_config {
+ __iomem void *vpss_regs_base0;
+ __iomem void *vpss_regs_base1;
+ enum vpss_platform_type platform;
+ spinlock_t vpss_lock;
+ struct vpss_hw_ops hw_ops;
+};
+
+static struct vpss_oper_config oper_cfg;
+
+/* register access routines */
+static inline u32 bl_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
+}
+
+static inline void bl_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
+}
+
+static inline u32 vpss_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base1 + offset);
+}
+
+static inline void vpss_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base1 + offset);
+}
+
+/* For DM365 only */
+static inline u32 isp5_read(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
+}
+
+/* For DM365 only */
+static inline void isp5_write(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
+}
+
+static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK;
+
+ /* if we are using pattern generator, enable it */
+ if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG)
+ temp |= 0x08;
+
+ temp |= (src_sel << CCD_SRC_SEL_SHIFT);
+ isp5_write(temp, DM365_ISP5_CCDCMUX);
+}
+
+static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
+}
+
+int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ if (!oper_cfg.hw_ops.select_ccdc_source)
+ return -EINVAL;
+
+ oper_cfg.hw_ops.select_ccdc_source(src_sel);
+ return 0;
+}
+EXPORT_SYMBOL(vpss_select_ccdc_source);
+
+static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ u32 mask = 1, val;
+
+ if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
+ wbl_sel > VPSS_PCR_CCDC_WBL_O)
+ return -EINVAL;
+
+ /* writing a 0 clear the overflow */
+ mask = ~(mask << wbl_sel);
+ val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
+ bl_regw(val, DM644X_SBL_PCR_VPSS);
+ return 0;
+}
+
+int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ if (!oper_cfg.hw_ops.clear_wbl_overflow)
+ return -EINVAL;
+
+ return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
+}
+EXPORT_SYMBOL(vpss_clear_wbl_overflow);
+
+/*
+ * dm355_enable_clock - Enable VPSS Clock
+ * @clock_sel: CLock to be enabled/disabled
+ * @en: enable/disable flag
+ *
+ * This is called to enable or disable a vpss clock
+ */
+static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ unsigned long flags;
+ u32 utemp, mask = 0x1, shift = 0;
+
+ switch (clock_sel) {
+ case VPSS_VPBE_CLOCK:
+ /* nothing since lsb */
+ break;
+ case VPSS_VENC_CLOCK_SEL:
+ shift = 2;
+ break;
+ case VPSS_CFALD_CLOCK:
+ shift = 3;
+ break;
+ case VPSS_H3A_CLOCK:
+ shift = 4;
+ break;
+ case VPSS_IPIPE_CLOCK:
+ shift = 5;
+ break;
+ case VPSS_CCDC_CLOCK:
+ shift = 6;
+ break;
+ default:
+ printk(KERN_ERR "dm355_enable_clock:"
+ " Invalid selector: %d\n", clock_sel);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+ utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
+ if (!en)
+ utemp &= ~(mask << shift);
+ else
+ utemp |= (mask << shift);
+
+ vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
+ spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+ return 0;
+}
+
+static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ unsigned long flags;
+ u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR;
+ u32 (*read)(u32 offset) = isp5_read;
+ void(*write)(u32 val, u32 offset) = isp5_write;
+
+ switch (clock_sel) {
+ case VPSS_BL_CLOCK:
+ break;
+ case VPSS_CCDC_CLOCK:
+ shift = 1;
+ break;
+ case VPSS_H3A_CLOCK:
+ shift = 2;
+ break;
+ case VPSS_RSZ_CLOCK:
+ shift = 3;
+ break;
+ case VPSS_IPIPE_CLOCK:
+ shift = 4;
+ break;
+ case VPSS_IPIPEIF_CLOCK:
+ shift = 5;
+ break;
+ case VPSS_PCLK_INTERNAL:
+ shift = 6;
+ break;
+ case VPSS_PSYNC_CLOCK_SEL:
+ shift = 7;
+ break;
+ case VPSS_VPBE_CLOCK:
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_VENC_CLOCK_SEL:
+ shift = 2;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_LDC_CLOCK:
+ shift = 3;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_FDIF_CLOCK:
+ shift = 4;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_OSD_CLOCK_SEL:
+ shift = 6;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_LDC_CLOCK_SEL:
+ shift = 7;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ default:
+ printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n",
+ clock_sel);
+ return -1;
+ }
+
+ spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+ utemp = read(offset);
+ if (!en) {
+ mask = ~mask;
+ utemp &= (mask << shift);
+ } else
+ utemp |= (mask << shift);
+
+ write(utemp, offset);
+ spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+
+ return 0;
+}
+
+int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ if (!oper_cfg.hw_ops.enable_clock)
+ return -EINVAL;
+
+ return oper_cfg.hw_ops.enable_clock(clock_sel, en);
+}
+EXPORT_SYMBOL(vpss_enable_clock);
+
+void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
+{
+ int val = 0;
+ val = isp5_read(DM365_ISP5_CCDCMUX);
+
+ val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT);
+ val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT);
+
+ isp5_write(val, DM365_ISP5_CCDCMUX);
+}
+EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
+
+void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
+{
+ int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
+
+ current_reg |= (frame_size.pplen - 1);
+ isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE);
+}
+EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
+
+static int __devinit vpss_probe(struct platform_device *pdev)
+{
+ struct resource *r1, *r2;
+ char *platform_name;
+ int status;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENOENT;
+ }
+
+ platform_name = pdev->dev.platform_data;
+ if (!strcmp(platform_name, "dm355_vpss"))
+ oper_cfg.platform = DM355;
+ else if (!strcmp(platform_name, "dm365_vpss"))
+ oper_cfg.platform = DM365;
+ else if (!strcmp(platform_name, "dm644x_vpss"))
+ oper_cfg.platform = DM644X;
+ else {
+ dev_err(&pdev->dev, "vpss driver not supported on"
+ " this platform\n");
+ return -ENODEV;
+ }
+
+ dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
+ r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r1)
+ return -ENOENT;
+
+ r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
+ if (!r1)
+ return -EBUSY;
+
+ oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
+ if (!oper_cfg.vpss_regs_base0) {
+ status = -EBUSY;
+ goto fail1;
+ }
+
+ if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+ r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!r2) {
+ status = -ENOENT;
+ goto fail2;
+ }
+ r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
+ if (!r2) {
+ status = -EBUSY;
+ goto fail2;
+ }
+
+ oper_cfg.vpss_regs_base1 = ioremap(r2->start,
+ resource_size(r2));
+ if (!oper_cfg.vpss_regs_base1) {
+ status = -EBUSY;
+ goto fail3;
+ }
+ }
+
+ if (oper_cfg.platform == DM355) {
+ oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
+ oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
+ /* Setup vpss interrupts */
+ bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL);
+ bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL);
+ } else if (oper_cfg.platform == DM365) {
+ oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
+ oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
+ /* Setup vpss interrupts */
+ isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
+ isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
+ isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
+ } else
+ oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
+
+ spin_lock_init(&oper_cfg.vpss_lock);
+ dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
+ return 0;
+
+fail3:
+ release_mem_region(r2->start, resource_size(r2));
+fail2:
+ iounmap(oper_cfg.vpss_regs_base0);
+fail1:
+ release_mem_region(r1->start, resource_size(r1));
+ return status;
+}
+
+static int __devexit vpss_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ iounmap(oper_cfg.vpss_regs_base0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+ if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+ iounmap(oper_cfg.vpss_regs_base1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(res->start, resource_size(res));
+ }
+ return 0;
+}
+
+static struct platform_driver vpss_driver = {
+ .driver = {
+ .name = "vpss",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(vpss_remove),
+ .probe = vpss_probe,
+};
+
+static void vpss_exit(void)
+{
+ platform_driver_unregister(&vpss_driver);
+}
+
+static int __init vpss_init(void)
+{
+ return platform_driver_register(&vpss_driver);
+}
+subsys_initcall(vpss_init);
+module_exit(vpss_exit);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
new file mode 100644
index 000000000000..20f981008faf
--- /dev/null
+++ b/drivers/media/platform/fsl-viu.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale VIU video driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Porting to 2.6.35 by DENX Software Engineering,
+ * Anatolij Gustschin <agust@denx.de>
+ *
+ * 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/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME "fsl_viu"
+#define VIU_VERSION "0.5.1"
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR 0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+ .flags = 0,
+ }
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (level <= info_level) \
+ printk(KERN_DEBUG "viu: " fmt , ## arg); \
+ } while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+ char name[32];
+ u32 fourcc; /* v4l2 format id */
+ u32 pixelformat;
+ int depth;
+};
+
+static struct viu_fmt formats[] = {
+ {
+ .name = "RGB-16 (5/B-6/G-5/R)",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ }, {
+ .name = "RGB-32 (A-R-G-B)",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ }
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+ struct viu_dev *dev;
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+};
+
+struct viu_status {
+ u32 field_irq;
+ u32 vsync_irq;
+ u32 hsync_irq;
+ u32 vstart_irq;
+ u32 dma_end_irq;
+ u32 error_irq;
+};
+
+struct viu_reg {
+ u32 status_cfg;
+ u32 luminance;
+ u32 chroma_r;
+ u32 chroma_g;
+ u32 chroma_b;
+ u32 field_base_addr;
+ u32 dma_inc;
+ u32 picture_count;
+ u32 req_alarm;
+ u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+ struct v4l2_device v4l2_dev;
+ struct mutex lock;
+ spinlock_t slock;
+ int users;
+
+ struct device *dev;
+ /* various device info */
+ struct video_device *vdev;
+ struct viu_dmaqueue vidq;
+ enum v4l2_field capfield;
+ int field;
+ int first;
+ int dma_done;
+
+ /* Hardware register area */
+ struct viu_reg *vr;
+
+ /* Interrupt vector */
+ int irq;
+ struct viu_status irqs;
+
+ /* video overlay */
+ struct v4l2_framebuffer ovbuf;
+ struct viu_fmt *ovfmt;
+ unsigned int ovenable;
+ enum v4l2_field ovfield;
+
+ /* crop */
+ struct v4l2_rect crop_current;
+
+ /* clock pointer */
+ struct clk *clk;
+
+ /* decoder */
+ struct v4l2_subdev *decoder;
+
+ v4l2_std_id std;
+};
+
+struct viu_fh {
+ struct viu_dev *dev;
+
+ /* video capture */
+ struct videobuf_queue vb_vidq;
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+
+ /* video overlay */
+ struct v4l2_window win;
+ struct v4l2_clip clips[1];
+
+ /* video capture */
+ struct viu_fmt *fmt;
+ int width, height, sizeimage;
+ enum v4l2_buf_type type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+ SOFT_RST = 1 << 0,
+
+ ERR_MASK = 0x0f << 4, /* Error code mask */
+ ERR_NO = 0x00, /* No error */
+ ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
+ ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
+ ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
+ ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
+ ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
+ ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
+ ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
+ ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
+ ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
+ ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
+
+ INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
+ INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
+ INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
+ INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
+ INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
+ INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
+ INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
+
+ INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */
+ INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */
+ INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */
+ INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */
+ INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */
+ INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */
+
+ DMA_ACT = 0x01 << 27, /* Enable DMA transfer */
+ FIELD_NO = 0x01 << 28, /* Field number */
+ DITHER_ON = 0x01 << 29, /* Dithering is on */
+ ROUND_ON = 0x01 << 30, /* Round is on */
+ MODE_32BIT = 0x01 << 31, /* Data in RGBa888,
+ * 0 in RGB565
+ */
+};
+
+#define norm_maxw() 720
+#define norm_maxh() 576
+
+#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+ INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+ INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == fourcc)
+ return formats + i;
+ }
+
+ dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+
+ dev->field = 0;
+
+ /* Enable DMA operation */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+ int cnt = 100;
+ u32 status_cfg;
+
+ out_be32(&vr->status_cfg, 0);
+
+ /* Clear pending interrupts */
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & 0x3f0000)
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+ if (status_cfg & DMA_ACT) {
+ do {
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & INT_DMA_END_STATUS)
+ break;
+ } while (cnt--);
+
+ if (cnt < 0) {
+ /* timed out, issue soft reset */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, 0);
+ } else {
+ /* clear DMA_END and other pending irqs */
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+ }
+ }
+
+ dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+ struct viu_buf *buf, *prev;
+
+ dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+
+ viu_stop_dma(vidq->dev);
+
+ /* cancel all outstanding capture requests */
+ list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ }
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ return 0;
+ }
+
+ prev = NULL;
+ for (;;) {
+ if (list_empty(&vidq->queued))
+ return 0;
+ buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+ if (prev == NULL) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+ dprintk(1, "Restarting video dma\n");
+ viu_stop_dma(vidq->dev);
+ viu_start_dma(vidq->dev);
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] restart_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] restart_queue - move to active\n",
+ buf, buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+ struct viu_dev *dev = (struct viu_dev *)data;
+ struct viu_buf *buf;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+
+ while (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+ }
+
+ restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct viu_fh *fh = vq->priv_data;
+
+ *size = fh->width * fh->height * fh->fmt->depth >> 3;
+ if (*count == 0)
+ *count = 32;
+
+ while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+ (*count)--;
+
+ dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+ void *vaddr = NULL;
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(vq, &buf->vb, 0, 0);
+
+ if (vq->int_ops && vq->int_ops->vaddr)
+ vaddr = vq->int_ops->vaddr(vb);
+
+ if (vaddr)
+ videobuf_dma_contig_free(vq, &buf->vb);
+
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+ struct viu_reg *vr = dev->vr;
+ int bpp;
+
+ /* setup the DMA base address */
+ reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+ dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+ buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+ /* interlace is on by default, set horizontal DMA increment */
+ reg_val.status_cfg = 0;
+ bpp = buf->fmt->depth >> 3;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 4;
+ break;
+ default:
+ dprintk(0, "doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ /* setup picture_count register */
+ reg_val.picture_count = (buf->vb.height / 2) << 16 |
+ buf->vb.width;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dev->capfield = buf->vb.field;
+
+ /* reset dma increment if needed */
+ if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+ reg_val.dma_inc = 0;
+
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ int rc;
+
+ BUG_ON(fh->fmt == NULL);
+
+ if (fh->width < 48 || fh->width > norm_maxw() ||
+ fh->height < 32 || fh->height > norm_maxh())
+ return -EINVAL;
+ buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ if (buf->fmt != fh->fmt ||
+ buf->vb.width != fh->width ||
+ buf->vb.height != fh->height ||
+ buf->vb.field != field) {
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ }
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ buf->fmt = fh->fmt;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = fh->dev;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_buf *prev;
+
+ if (!list_empty(&vidq->queued)) {
+ dprintk(1, "adding vb queue=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+ vidq, &vidq->queued);
+ dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+ dev, &vidq->queued, vidq->queued.next,
+ vidq->queued.prev);
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+ buf, buf->vb.i);
+ } else if (list_empty(&vidq->active)) {
+ dprintk(1, "adding vb active=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] buffer_queue - first active\n",
+ buf, buf->vb.i);
+
+ buffer_activate(dev, buf);
+ } else {
+ dprintk(1, "adding vb queue2=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+ if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.i);
+ } else {
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+ buf, buf->vb.i);
+ }
+ }
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+
+ viu_stop_dma(dev);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "viu");
+ strcpy(cap->card, "viu");
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+
+ if (f->index > NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[index].name, sizeof(f->description));
+ f->pixelformat = formats[index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->pixelformat;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = fh->sizeimage;
+ return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dprintk(1, "Fourcc format (0x%08x) invalid.",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = V4L2_FIELD_INTERLACED;
+ } else if (field != V4L2_FIELD_INTERLACED) {
+ dprintk(1, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ maxw = norm_maxw();
+ maxh = norm_maxh();
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ int ret;
+
+ ret = vidioc_try_fmt_cap(file, fh, f);
+ if (ret < 0)
+ return ret;
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->sizeimage = f->fmt.pix.sizeimage;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+ dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+ return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.win = fh->win;
+ return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+ enum v4l2_field field;
+ int maxw, maxh;
+
+ if (dev->ovbuf.base == NULL)
+ return -EINVAL;
+ if (dev->ovfmt == NULL)
+ return -EINVAL;
+ if (win->w.width < 48 || win->w.height < 32)
+ return -EINVAL;
+
+ field = win->field;
+ maxw = dev->crop_current.width;
+ maxh = dev->crop_current.height;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = (win->w.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_TOP;
+ }
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ win->field = field;
+ if (win->w.width > maxw)
+ win->w.width = maxw;
+ if (win->w.height > maxh)
+ win->w.height = maxh;
+ return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+ int bpp;
+
+ dprintk(1, "%s %dx%d %s\n", __func__,
+ fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+ reg_val.status_cfg = 0;
+
+ /* setup window */
+ reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+ fh->win.w.width;
+
+ /* setup color depth and dma increment */
+ bpp = dev->ovfmt->depth / 8;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 4;
+ break;
+ default:
+ dprintk(0, "device doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ dev->ovfield = fh->win.field;
+ if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+ reg_val.dma_inc = 0;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ /* setup the base address of the overlay buffer */
+ reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+ int err;
+
+ err = verify_preview(dev, &f->fmt.win);
+ if (err)
+ return err;
+
+ fh->win = f->fmt.win;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_setup_preview(dev, fh);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+
+ if (on) {
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_activate_overlay(dev->vr);
+ dev->ovenable = 1;
+
+ /* start dma */
+ viu_start_dma(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ } else {
+ viu_stop_dma(dev);
+ dev->ovenable = 0;
+ }
+
+ return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+
+ *fb = dev->ovbuf;
+ fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+ struct viu_fmt *fmt;
+
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* check args */
+ fmt = format_by_fourcc(fb->fmt.pixelformat);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ /* ok, accept it */
+ dev->ovbuf = *fb;
+ dev->ovfmt = fmt;
+ if (dev->ovbuf.fmt.bytesperline == 0) {
+ dev->ovbuf.fmt.bytesperline =
+ dev->ovbuf.fmt.width * fmt->depth / 8;
+ }
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
+ viu_start_dma(fh->dev);
+
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ viu_stop_dma(fh->dev);
+
+ return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+ v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ decoder_call(fh->dev, video, querystd, std_id);
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct viu_fh *fh = priv;
+
+ fh->dev->std = *id;
+ decoder_call(fh->dev, core, s_std, *id);
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ *std_id = fh->dev->std;
+ return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct viu_fh *fh = priv;
+
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = fh->dev->vdev->tvnorms;
+ strcpy(inp->name, "Camera");
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct viu_fh *fh = priv;
+
+ if (i > 1)
+ return -EINVAL;
+
+ decoder_call(fh->dev, video, s_routing, i, 0, 0);
+ return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (qc->id && qc->id == viu_qctrl[i].id) {
+ memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ ctrl->value = qctl_regs[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ if (ctrl->value < viu_qctrl[i].minimum
+ || ctrl->value > viu_qctrl[i].maximum)
+ return -ERANGE;
+ qctl_regs[i] = ctrl->value;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+ struct viu_dmaqueue *viuq)
+{
+ struct viu_dmaqueue *vidq = viuq;
+ struct viu_buf *buf;
+
+ /* launch another DMA operation for an active/queued buffer */
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf,
+ vb.queue);
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ buffer_activate(dev, buf);
+ } else if (!list_empty(&vidq->queued)) {
+ buf = list_entry(vidq->queued.next, struct viu_buf,
+ vb.queue);
+ list_del(&buf->vb.queue);
+
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ buffer_activate(dev, buf);
+ }
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->luminance, 0x9512A254);
+ out_be32(&vr->chroma_r, 0x03310000);
+ out_be32(&vr->chroma_g, 0x06600F38);
+ out_be32(&vr->chroma_b, 0x00000409);
+ out_be32(&vr->alpha, 0x000000ff);
+ out_be32(&vr->req_alarm, 0x00000090);
+ dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+ in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_reg *vr = dev->vr;
+
+ if (status & INT_DMA_END_STATUS)
+ dev->dma_done = 1;
+
+ if (status & INT_FIELD_STATUS) {
+ if (dev->dma_done) {
+ u32 addr = reg_val.field_base_addr;
+
+ dev->dma_done = 0;
+ if (status & FIELD_NO)
+ addr += reg_val.dma_inc;
+
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ } else if (status & INT_VSYNC_STATUS) {
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ }
+ }
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_reg *vr = dev->vr;
+ struct viu_buf *buf;
+ int field_num;
+ int need_two;
+ int dma_done = 0;
+
+ field_num = status & FIELD_NO;
+ need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+ if (status & INT_DMA_END_STATUS) {
+ dma_done = 1;
+ if (((field_num == 0) && (dev->field == 0)) ||
+ (field_num && (dev->field == 1)))
+ dev->field++;
+ }
+
+ if (status & INT_FIELD_STATUS) {
+ dprintk(1, "irq: field %d, done %d\n",
+ !!field_num, dma_done);
+ if (unlikely(dev->first)) {
+ if (field_num == 0) {
+ dev->first = 0;
+ dprintk(1, "activate first buf\n");
+ viu_activate_next_buf(dev, vidq);
+ } else
+ dprintk(1, "wait field 0\n");
+ return;
+ }
+
+ /* setup buffer address for next dma operation */
+ if (!list_empty(&vidq->active)) {
+ u32 addr = reg_val.field_base_addr;
+
+ if (field_num && need_two) {
+ addr += reg_val.dma_inc;
+ dprintk(1, "field 1, 0x%lx, dev field %d\n",
+ (unsigned long)addr, dev->field);
+ }
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ return;
+ }
+ }
+
+ if (dma_done && field_num && (dev->field == 2)) {
+ dev->field = 0;
+ buf = list_entry(vidq->active.next,
+ struct viu_buf, vb.queue);
+ dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+ buf, buf->vb.i,
+ (unsigned long)videobuf_to_dma_contig(&buf->vb),
+ (unsigned long)in_be32(&vr->field_base_addr));
+
+ if (waitqueue_active(&buf->vb.done)) {
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ wake_up(&buf->vb.done);
+ }
+ /* activate next dma buffer */
+ viu_activate_next_buf(dev, vidq);
+ }
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+ struct viu_dev *dev = (struct viu_dev *)dev_id;
+ struct viu_reg *vr = dev->vr;
+ u32 status;
+ u32 error;
+
+ status = in_be32(&vr->status_cfg);
+
+ if (status & INT_ERROR_STATUS) {
+ dev->irqs.error_irq++;
+ error = status & ERR_MASK;
+ if (error)
+ dprintk(1, "Err: error(%d), times:%d!\n",
+ error >> 4, dev->irqs.error_irq);
+ /* Clear interrupt error bit and error flags */
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | INT_ERROR_STATUS);
+ }
+
+ if (status & INT_DMA_END_STATUS) {
+ dev->irqs.dma_end_irq++;
+ dev->dma_done = 1;
+ dprintk(2, "VIU DMA end interrupt times: %d\n",
+ dev->irqs.dma_end_irq);
+ }
+
+ if (status & INT_HSYNC_STATUS)
+ dev->irqs.hsync_irq++;
+
+ if (status & INT_FIELD_STATUS) {
+ dev->irqs.field_irq++;
+ dprintk(2, "VIU field interrupt times: %d\n",
+ dev->irqs.field_irq);
+ }
+
+ if (status & INT_VSTART_STATUS)
+ dev->irqs.vstart_irq++;
+
+ if (status & INT_VSYNC_STATUS) {
+ dev->irqs.vsync_irq++;
+ dprintk(2, "VIU vsync interrupt times: %d\n",
+ dev->irqs.vsync_irq);
+ }
+
+ /* clear all pending irqs */
+ status = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+ if (dev->ovenable) {
+ viu_overlay_intr(dev, status);
+ return IRQ_HANDLED;
+ }
+
+ /* Capture mode */
+ viu_capture_intr(dev, status);
+ return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct viu_dev *dev = video_get_drvdata(vdev);
+ struct viu_fh *fh;
+ struct viu_reg *vr;
+ int minor = vdev->minor;
+ u32 status_cfg;
+ int i;
+
+ dprintk(1, "viu: open (minor=%d)\n", minor);
+
+ dev->users++;
+ if (dev->users > 1) {
+ dev->users--;
+ return -EBUSY;
+ }
+
+ vr = dev->vr;
+
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+ if (mutex_lock_interruptible(&dev->lock)) {
+ dev->users--;
+ return -ERESTARTSYS;
+ }
+
+ /* allocate and initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh) {
+ dev->users--;
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+ fh->width = norm_maxw();
+ fh->height = norm_maxh();
+ dev->crop_current.width = fh->width;
+ dev->crop_current.height = fh->height;
+
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+ qctl_regs[i] = viu_qctrl[i].default_value;
+
+ dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&dev->vidq);
+ dprintk(1, "Open: list_empty queued=%d\n",
+ list_empty(&dev->vidq.queued));
+ dprintk(1, "Open: list_empty active=%d\n",
+ list_empty(&dev->vidq.active));
+
+ viu_default_settings(vr);
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+ INT_FIELD_EN | INT_VSTART_EN |
+ INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+ spin_lock_init(&fh->vbq_lock);
+ videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+ dev->dev, &fh->vbq_lock,
+ fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct viu_buf), fh,
+ &fh->dev->lock);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+ loff_t *ppos)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int ret = 0;
+
+ dprintk(2, "%s\n", __func__);
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ viu_start_dma(dev);
+ ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+ ppos, 0, file->f_flags & O_NONBLOCK);
+ mutex_unlock(&dev->lock);
+ return ret;
+ }
+ return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct viu_fh *fh = file->private_data;
+ struct videobuf_queue *q = &fh->vb_vidq;
+ struct viu_dev *dev = fh->dev;
+ unsigned int res;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ mutex_lock(&dev->lock);
+ res = videobuf_poll_stream(file, q, wait);
+ mutex_unlock(&dev->lock);
+ return res;
+}
+
+static int viu_release(struct file *file)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int minor = video_devdata(file)->minor;
+
+ mutex_lock(&dev->lock);
+ viu_stop_dma(dev);
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+ mutex_unlock(&dev->lock);
+
+ kfree(fh);
+
+ dev->users--;
+ dprintk(1, "close (minor=%d, users=%d)\n",
+ minor, dev->users);
+ return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+ out_be32(&reg->status_cfg, 0);
+ out_be32(&reg->luminance, 0x9512a254);
+ out_be32(&reg->chroma_r, 0x03310000);
+ out_be32(&reg->chroma_g, 0x06600f38);
+ out_be32(&reg->chroma_b, 0x00000409);
+ out_be32(&reg->field_base_addr, 0);
+ out_be32(&reg->dma_inc, 0);
+ out_be32(&reg->picture_count, 0x01e002d0);
+ out_be32(&reg->req_alarm, 0x00000090);
+ out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int ret;
+
+ dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ mutex_unlock(&dev->lock);
+
+ dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ ret);
+
+ return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+ .owner = THIS_MODULE,
+ .open = viu_open,
+ .release = viu_release,
+ .read = viu_read,
+ .poll = viu_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+ .vidioc_overlay = vidioc_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+ .vidioc_s_fbuf = vidioc_s_fbuf,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_querystd = vidioc_querystd,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+ .name = "FSL viu",
+ .fops = &viu_fops,
+ .minor = -1,
+ .ioctl_ops = &viu_ioctl_ops,
+ .release = video_device_release,
+
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct platform_device *op)
+{
+ struct viu_dev *viu_dev;
+ struct video_device *vdev;
+ struct resource r;
+ struct viu_reg __iomem *viu_regs;
+ struct i2c_adapter *ad;
+ int ret, viu_irq;
+
+ ret = of_address_to_resource(op->dev.of_node, 0, &r);
+ if (ret) {
+ dev_err(&op->dev, "Can't parse device node resource\n");
+ return -ENODEV;
+ }
+
+ viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (viu_irq == NO_IRQ) {
+ dev_err(&op->dev, "Error while mapping the irq\n");
+ return -EINVAL;
+ }
+
+ /* request mem region */
+ if (!devm_request_mem_region(&op->dev, r.start,
+ sizeof(struct viu_reg), DRV_NAME)) {
+ dev_err(&op->dev, "Error while requesting mem region\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* remap registers */
+ viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+ if (!viu_regs) {
+ dev_err(&op->dev, "Can't map register set\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Prepare our private structure */
+ viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+ if (!viu_dev) {
+ dev_err(&op->dev, "Can't allocate private structure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ viu_dev->vr = viu_regs;
+ viu_dev->irq = viu_irq;
+ viu_dev->dev = &op->dev;
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&viu_dev->vidq.active);
+ INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+ snprintf(viu_dev->v4l2_dev.name,
+ sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+ ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+ goto err;
+ }
+
+ ad = i2c_get_adapter(0);
+ viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+ "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+ viu_dev->vidq.timeout.function = viu_vid_timeout;
+ viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
+ init_timer(&viu_dev->vidq.timeout);
+ viu_dev->first = 1;
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ memcpy(vdev, &viu_template, sizeof(viu_template));
+
+ vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+ viu_dev->vdev = vdev;
+
+ /* initialize locks */
+ mutex_init(&viu_dev->lock);
+ viu_dev->vdev->lock = &viu_dev->lock;
+ spin_lock_init(&viu_dev->slock);
+
+ video_set_drvdata(viu_dev->vdev, viu_dev);
+
+ mutex_lock(&viu_dev->lock);
+
+ ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ video_device_release(viu_dev->vdev);
+ goto err_vdev;
+ }
+
+ /* enable VIU clock */
+ viu_dev->clk = clk_get(&op->dev, "viu_clk");
+ if (IS_ERR(viu_dev->clk)) {
+ dev_err(&op->dev, "failed to find the clock module!\n");
+ ret = -ENODEV;
+ goto err_clk;
+ } else {
+ clk_enable(viu_dev->clk);
+ }
+
+ /* reset VIU module */
+ viu_reset(viu_dev->vr);
+
+ /* install interrupt handler */
+ if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+ dev_err(&op->dev, "Request VIU IRQ failed.\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+
+ mutex_unlock(&viu_dev->lock);
+
+ dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+ return ret;
+
+err_irq:
+ clk_disable(viu_dev->clk);
+ clk_put(viu_dev->clk);
+err_clk:
+ video_unregister_device(viu_dev->vdev);
+err_vdev:
+ mutex_unlock(&viu_dev->lock);
+ i2c_put_adapter(ad);
+ v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+ irq_dispose_mapping(viu_irq);
+ return ret;
+}
+
+static int __devexit viu_of_remove(struct platform_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+ struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+ free_irq(dev->irq, (void *)dev);
+ irq_dispose_mapping(dev->irq);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+
+ video_unregister_device(dev->vdev);
+ i2c_put_adapter(client->adapter);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct platform_device *op, pm_message_t state)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_disable(dev->clk);
+ return 0;
+}
+
+static int viu_resume(struct platform_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_enable(dev->clk);
+ return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+ {
+ .compatible = "fsl,mpc5121-viu",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct platform_driver viu_of_platform_driver = {
+ .probe = viu_of_probe,
+ .remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+ .suspend = viu_suspend,
+ .resume = viu_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mpc512x_viu_of_match,
+ },
+};
+
+module_platform_driver(viu_of_platform_driver);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VIU_VERSION);
diff --git a/drivers/media/video/indycam.c b/drivers/media/platform/indycam.c
index 548236333cce..548236333cce 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/platform/indycam.c
diff --git a/drivers/media/video/indycam.h b/drivers/media/platform/indycam.h
index 881f21c474c4..881f21c474c4 100644
--- a/drivers/media/video/indycam.h
+++ b/drivers/media/platform/indycam.h
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
new file mode 100644
index 000000000000..a38c15201d1d
--- /dev/null
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -0,0 +1,1120 @@
+/*
+ * V4L2 deinterlacing support.
+ *
+ * Copyright (c) 2012 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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.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>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-deinterlace"
+
+MODULE_DESCRIPTION("mem2mem device which supports deinterlacing using dmaengine");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug = true;
+module_param(debug, bool, 0644);
+
+/* 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-deinterlace"
+
+#define dprintk(dev, fmt, arg...) \
+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+struct deinterlace_fmt {
+ char *name;
+ u32 fourcc;
+ /* Types the format can be used for */
+ u32 types;
+};
+
+static struct deinterlace_fmt formats[] = {
+ {
+ .name = "YUV 4:2:0 Planar",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ },
+ {
+ .name = "YUYV 4:2:2",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct deinterlace_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int sizeimage;
+ struct deinterlace_fmt *fmt;
+ enum v4l2_field field;
+};
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+enum {
+ YUV420_DMA_Y_ODD,
+ YUV420_DMA_Y_EVEN,
+ YUV420_DMA_U_ODD,
+ YUV420_DMA_U_EVEN,
+ YUV420_DMA_V_ODD,
+ YUV420_DMA_V_EVEN,
+ YUV420_DMA_Y_ODD_DOUBLING,
+ YUV420_DMA_U_ODD_DOUBLING,
+ YUV420_DMA_V_ODD_DOUBLING,
+ YUYV_DMA_ODD,
+ YUYV_DMA_EVEN,
+ YUYV_DMA_EVEN_DOUBLING,
+};
+
+/* Source and destination queue data */
+static struct deinterlace_q_data q_data[2];
+
+static struct deinterlace_q_data *get_q_data(enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ return &q_data[V4L2_M2M_SRC];
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return &q_data[V4L2_M2M_DST];
+ default:
+ BUG();
+ }
+ return NULL;
+}
+
+static struct deinterlace_fmt *find_format(struct v4l2_format *f)
+{
+ struct deinterlace_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < NUM_FORMATS; k++) {
+ fmt = &formats[k];
+ if ((fmt->types & f->type) &&
+ (fmt->fourcc == f->fmt.pix.pixelformat))
+ break;
+ }
+
+ if (k == NUM_FORMATS)
+ return NULL;
+
+ return &formats[k];
+}
+
+struct deinterlace_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd;
+
+ atomic_t busy;
+ struct mutex dev_mutex;
+ spinlock_t irqlock;
+
+ struct dma_chan *dma_chan;
+
+ struct v4l2_m2m_dev *m2m_dev;
+ struct vb2_alloc_ctx *alloc_ctx;
+};
+
+struct deinterlace_ctx {
+ struct deinterlace_dev *dev;
+
+ /* Abort requested by m2m */
+ int aborting;
+ enum v4l2_colorspace colorspace;
+ dma_cookie_t cookie;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct dma_interleaved_template *xt;
+};
+
+/*
+ * mem2mem callbacks
+ */
+static int deinterlace_job_ready(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_dev *pcdev = ctx->dev;
+
+ if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0)
+ && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0)
+ && (atomic_read(&ctx->dev->busy) == 0)) {
+ dprintk(pcdev, "Task ready\n");
+ return 1;
+ }
+
+ dprintk(pcdev, "Task not ready to run\n");
+
+ return 0;
+}
+
+static void deinterlace_job_abort(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_dev *pcdev = ctx->dev;
+
+ ctx->aborting = 1;
+
+ dprintk(pcdev, "Aborting task\n");
+
+ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void deinterlace_lock(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_dev *pcdev = ctx->dev;
+ mutex_lock(&pcdev->dev_mutex);
+}
+
+static void deinterlace_unlock(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_dev *pcdev = ctx->dev;
+ mutex_unlock(&pcdev->dev_mutex);
+}
+
+static void dma_callback(void *data)
+{
+ struct deinterlace_ctx *curr_ctx = data;
+ struct deinterlace_dev *pcdev = curr_ctx->dev;
+ struct vb2_buffer *src_vb, *dst_vb;
+
+ atomic_set(&pcdev->busy, 0);
+
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+
+ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+
+ dprintk(pcdev, "dma transfers completed.\n");
+}
+
+static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
+ int do_callback)
+{
+ struct deinterlace_q_data *s_q_data, *d_q_data;
+ struct vb2_buffer *src_buf, *dst_buf;
+ struct deinterlace_dev *pcdev = ctx->dev;
+ struct dma_chan *chan = pcdev->dma_chan;
+ struct dma_device *dmadev = chan->device;
+ struct dma_async_tx_descriptor *tx;
+ unsigned int s_width, s_height;
+ unsigned int d_width, d_height;
+ unsigned int d_size, s_size;
+ dma_addr_t p_in, p_out;
+ enum dma_ctrl_flags flags;
+
+ 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(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ s_width = s_q_data->width;
+ s_height = s_q_data->height;
+ s_size = s_width * s_height;
+
+ d_q_data = get_q_data(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 = (dma_addr_t)vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ p_out = (dma_addr_t)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;
+ }
+
+ switch (op) {
+ case YUV420_DMA_Y_ODD:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width;
+ ctx->xt->sgl[0].icg = s_width;
+ ctx->xt->src_start = p_in;
+ ctx->xt->dst_start = p_out;
+ break;
+ case YUV420_DMA_Y_EVEN:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width;
+ ctx->xt->sgl[0].icg = s_width;
+ ctx->xt->src_start = p_in + s_size / 2;
+ ctx->xt->dst_start = p_out + s_width;
+ break;
+ case YUV420_DMA_U_ODD:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + s_size;
+ ctx->xt->dst_start = p_out + s_size;
+ break;
+ case YUV420_DMA_U_EVEN:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + (9 * s_size) / 8;
+ ctx->xt->dst_start = p_out + s_size + s_width / 2;
+ break;
+ case YUV420_DMA_V_ODD:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + (5 * s_size) / 4;
+ ctx->xt->dst_start = p_out + (5 * s_size) / 4;
+ break;
+ case YUV420_DMA_V_EVEN:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + (11 * s_size) / 8;
+ ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+ break;
+ case YUV420_DMA_Y_ODD_DOUBLING:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width;
+ ctx->xt->sgl[0].icg = s_width;
+ ctx->xt->src_start = p_in;
+ ctx->xt->dst_start = p_out + s_width;
+ break;
+ case YUV420_DMA_U_ODD_DOUBLING:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + s_size;
+ ctx->xt->dst_start = p_out + s_size + s_width / 2;
+ break;
+ case YUV420_DMA_V_ODD_DOUBLING:
+ ctx->xt->numf = s_height / 4;
+ ctx->xt->sgl[0].size = s_width / 2;
+ ctx->xt->sgl[0].icg = s_width / 2;
+ ctx->xt->src_start = p_in + (5 * s_size) / 4;
+ ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+ break;
+ case YUYV_DMA_ODD:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width * 2;
+ ctx->xt->sgl[0].icg = s_width * 2;
+ ctx->xt->src_start = p_in;
+ ctx->xt->dst_start = p_out;
+ break;
+ case YUYV_DMA_EVEN:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width * 2;
+ ctx->xt->sgl[0].icg = s_width * 2;
+ ctx->xt->src_start = p_in + s_size;
+ ctx->xt->dst_start = p_out + s_width * 2;
+ break;
+ case YUYV_DMA_EVEN_DOUBLING:
+ default:
+ ctx->xt->numf = s_height / 2;
+ ctx->xt->sgl[0].size = s_width * 2;
+ ctx->xt->sgl[0].icg = s_width * 2;
+ ctx->xt->src_start = p_in;
+ ctx->xt->dst_start = p_out + s_width * 2;
+ break;
+ }
+
+ /* Common parameters for al transfers */
+ ctx->xt->frame_size = 1;
+ ctx->xt->dir = DMA_MEM_TO_MEM;
+ ctx->xt->src_sgl = false;
+ ctx->xt->dst_sgl = true;
+ flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT |
+ DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP;
+
+ tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
+ if (tx == NULL) {
+ v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep error\n");
+ return;
+ }
+
+ if (do_callback) {
+ tx->callback = dma_callback;
+ tx->callback_param = ctx;
+ }
+
+ ctx->cookie = dmaengine_submit(tx);
+ if (dma_submit_error(ctx->cookie)) {
+ v4l2_warn(&pcdev->v4l2_dev,
+ "DMA submit error %d with src=0x%x dst=0x%x len=0x%x\n",
+ ctx->cookie, (unsigned)p_in, (unsigned)p_out,
+ s_size * 3/2);
+ return;
+ }
+
+ dma_async_issue_pending(chan);
+}
+
+static void deinterlace_device_run(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_q_data *dst_q_data;
+
+ atomic_set(&ctx->dev->busy, 1);
+
+ dprintk(ctx->dev, "%s: DMA try issue.\n", __func__);
+
+ dst_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ /*
+ * 4 possible field conversions are possible at the moment:
+ * V4L2_FIELD_SEQ_TB --> V4L2_FIELD_INTERLACED_TB:
+ * two separate fields in the same input buffer are interlaced
+ * in the output buffer using weaving. Top field comes first.
+ * V4L2_FIELD_SEQ_TB --> V4L2_FIELD_NONE:
+ * top field from the input buffer is copied to the output buffer
+ * using line doubling. Bottom field from the input buffer is discarded.
+ * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_INTERLACED_BT:
+ * two separate fields in the same input buffer are interlaced
+ * in the output buffer using weaving. Bottom field comes first.
+ * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_NONE:
+ * bottom field from the input buffer is copied to the output buffer
+ * using line doubling. Top field from the input buffer is discarded.
+ */
+ switch (dst_q_data->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ switch (dst_q_data->field) {
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ dprintk(ctx->dev, "%s: yuv420 interlaced tb.\n",
+ __func__);
+ deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_Y_EVEN, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_U_EVEN, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_V_EVEN, 1);
+ break;
+ case V4L2_FIELD_NONE:
+ default:
+ dprintk(ctx->dev, "%s: yuv420 interlaced line doubling.\n",
+ __func__);
+ deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD_DOUBLING, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD_DOUBLING, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+ deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD_DOUBLING, 1);
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ switch (dst_q_data->field) {
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ dprintk(ctx->dev, "%s: yuyv interlaced_tb.\n",
+ __func__);
+ deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+ deinterlace_issue_dma(ctx, YUYV_DMA_EVEN, 1);
+ break;
+ case V4L2_FIELD_NONE:
+ default:
+ dprintk(ctx->dev, "%s: yuyv interlaced line doubling.\n",
+ __func__);
+ deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+ deinterlace_issue_dma(ctx, YUYV_DMA_EVEN_DOUBLING, 1);
+ break;
+ }
+ break;
+ }
+
+ dprintk(ctx->dev, "%s: DMA issue done.\n", __func__);
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+ strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num;
+ struct deinterlace_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));
+ 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 deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct deinterlace_q_data *q_data;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(f->type);
+
+ f->fmt.pix.width = q_data->width;
+ f->fmt.pix.height = q_data->height;
+ f->fmt.pix.field = q_data->field;
+ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+
+ switch (q_data->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ f->fmt.pix.bytesperline = q_data->width * 2;
+ }
+
+ f->fmt.pix.sizeimage = q_data->sizeimage;
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ 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, struct deinterlace_fmt *fmt)
+{
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ 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 deinterlace_fmt *fmt;
+ struct deinterlace_ctx *ctx = priv;
+
+ fmt = find_format(f);
+ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB &&
+ f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT &&
+ f->fmt.pix.field != V4L2_FIELD_NONE)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct deinterlace_fmt *fmt;
+
+ fmt = find_format(f);
+ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+ if (!f->fmt.pix.colorspace)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ if (f->fmt.pix.field != V4L2_FIELD_SEQ_TB &&
+ f->fmt.pix.field != V4L2_FIELD_SEQ_BT)
+ f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+ struct deinterlace_q_data *q_data;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(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;
+ }
+
+ q_data->fmt = find_format(f);
+ if (!q_data->fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Couldn't set format type %d, wxh: %dx%d. fmt: %d, field: %d\n",
+ f->type, f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.pixelformat, f->fmt.pix.field);
+ return -EINVAL;
+ }
+
+ q_data->width = f->fmt.pix.width;
+ q_data->height = f->fmt.pix.height;
+ q_data->field = f->fmt.pix.field;
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+ q_data->sizeimage = (q_data->width * q_data->height * 3) / 2;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ q_data->sizeimage = q_data->width * q_data->height * 2;
+ }
+
+ dprintk(ctx->dev,
+ "Setting format for type %d, wxh: %dx%d, fmt: %d, field: %d\n",
+ f->type, q_data->width, q_data->height, q_data->fmt->fourcc,
+ q_data->field);
+
+ 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)
+{
+ struct deinterlace_ctx *ctx = priv;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = vidioc_s_fmt(priv, f);
+ if (!ret)
+ ctx->colorspace = f->fmt.pix.colorspace;
+
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct deinterlace_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 deinterlace_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 deinterlace_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 deinterlace_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 deinterlace_q_data *s_q_data, *d_q_data;
+ struct deinterlace_ctx *ctx = priv;
+
+ s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ /* Check that src and dst queues have the same pix format */
+ if (s_q_data->fmt->fourcc != d_q_data->fmt->fourcc) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "src and dst formats don't match.\n");
+ return -EINVAL;
+ }
+
+ /* Check that input and output deinterlacing types are compatible */
+ switch (s_q_data->field) {
+ case V4L2_FIELD_SEQ_BT:
+ if (d_q_data->field != V4L2_FIELD_NONE &&
+ d_q_data->field != V4L2_FIELD_INTERLACED_BT) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "src and dst field conversion [(%d)->(%d)] not supported.\n",
+ s_q_data->field, d_q_data->field);
+ return -EINVAL;
+ }
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ if (d_q_data->field != V4L2_FIELD_NONE &&
+ d_q_data->field != V4L2_FIELD_INTERLACED_TB) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "src and dst field conversion [(%d)->(%d)] not supported.\n",
+ s_q_data->field, d_q_data->field);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct deinterlace_ctx *ctx = priv;
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops deinterlace_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
+ */
+struct vb2_dc_conf {
+ struct device *dev;
+};
+
+static int deinterlace_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+ struct deinterlace_q_data *q_data;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(vq->type);
+
+ switch (q_data->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ size = q_data->width * q_data->height * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ size = q_data->width * q_data->height * 2;
+ }
+
+ *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 deinterlace_buf_prepare(struct vb2_buffer *vb)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct deinterlace_q_data *q_data;
+
+ dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+ q_data = get_q_data(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 deinterlace_buf_queue(struct vb2_buffer *vb)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops deinterlace_qops = {
+ .queue_setup = deinterlace_queue_setup,
+ .buf_prepare = deinterlace_buf_prepare,
+ .buf_queue = deinterlace_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct deinterlace_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 = &deinterlace_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ q_data[V4L2_M2M_SRC].fmt = &formats[0];
+ q_data[V4L2_M2M_SRC].width = 640;
+ q_data[V4L2_M2M_SRC].height = 480;
+ q_data[V4L2_M2M_SRC].sizeimage = (640 * 480 * 3) / 2;
+ q_data[V4L2_M2M_SRC].field = V4L2_FIELD_SEQ_TB;
+
+ 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 = &deinterlace_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ q_data[V4L2_M2M_DST].fmt = &formats[0];
+ q_data[V4L2_M2M_DST].width = 640;
+ q_data[V4L2_M2M_DST].height = 480;
+ q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2;
+ q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int deinterlace_open(struct file *file)
+{
+ struct deinterlace_dev *pcdev = video_drvdata(file);
+ struct deinterlace_ctx *ctx = NULL;
+
+ 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;
+ }
+
+ ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
+ sizeof(struct data_chunk), GFP_KERNEL);
+ if (!ctx->xt) {
+ int ret = PTR_ERR(ctx->xt);
+
+ kfree(ctx);
+ return ret;
+ }
+
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+ return 0;
+}
+
+static int deinterlace_release(struct file *file)
+{
+ struct deinterlace_dev *pcdev = video_drvdata(file);
+ struct deinterlace_ctx *ctx = file->private_data;
+
+ dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ kfree(ctx->xt);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int deinterlace_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct deinterlace_ctx *ctx = file->private_data;
+ int ret;
+
+ deinterlace_lock(ctx);
+ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+ deinterlace_unlock(ctx);
+
+ return ret;
+}
+
+static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct deinterlace_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations deinterlace_fops = {
+ .owner = THIS_MODULE,
+ .open = deinterlace_open,
+ .release = deinterlace_release,
+ .poll = deinterlace_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = deinterlace_mmap,
+};
+
+static struct video_device deinterlace_videodev = {
+ .name = MEM2MEM_NAME,
+ .fops = &deinterlace_fops,
+ .ioctl_ops = &deinterlace_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = deinterlace_device_run,
+ .job_ready = deinterlace_job_ready,
+ .job_abort = deinterlace_job_abort,
+ .lock = deinterlace_lock,
+ .unlock = deinterlace_unlock,
+};
+
+static int deinterlace_probe(struct platform_device *pdev)
+{
+ struct deinterlace_dev *pcdev;
+ struct video_device *vfd;
+ dma_cap_mask_t mask;
+ int ret = 0;
+
+ pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+ if (!pcdev)
+ return -ENOMEM;
+
+ spin_lock_init(&pcdev->irqlock);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_INTERLEAVE, mask);
+ pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev);
+ if (!pcdev->dma_chan)
+ goto free_dev;
+
+ if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) {
+ v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n");
+ goto rel_dma;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+ if (ret)
+ goto rel_dma;
+
+ atomic_set(&pcdev->busy, 0);
+ 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 = deinterlace_videodev;
+ vfd->lock = &pcdev->dev_mutex;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+ goto rel_vdev;
+ }
+
+ video_set_drvdata(vfd, pcdev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name);
+ pcdev->vfd = vfd;
+ v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+ " Device registered as /dev/video%d\n", vfd->num);
+
+ platform_set_drvdata(pdev, pcdev);
+
+ 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 err_ctx;
+ }
+
+ 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 err_m2m;
+ }
+
+ return 0;
+
+ v4l2_m2m_release(pcdev->m2m_dev);
+err_m2m:
+ video_unregister_device(pcdev->vfd);
+err_ctx:
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+ video_device_release(vfd);
+unreg_dev:
+ v4l2_device_unregister(&pcdev->v4l2_dev);
+rel_dma:
+ dma_release_channel(pcdev->dma_chan);
+free_dev:
+ kfree(pcdev);
+
+ return ret;
+}
+
+static int deinterlace_remove(struct platform_device *pdev)
+{
+ struct deinterlace_dev *pcdev =
+ (struct deinterlace_dev *)platform_get_drvdata(pdev);
+
+ v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+ v4l2_m2m_release(pcdev->m2m_dev);
+ video_unregister_device(pcdev->vfd);
+ v4l2_device_unregister(&pcdev->v4l2_dev);
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+ dma_release_channel(pcdev->dma_chan);
+ kfree(pcdev);
+
+ return 0;
+}
+
+static struct platform_driver deinterlace_pdrv = {
+ .probe = deinterlace_probe,
+ .remove = deinterlace_remove,
+ .driver = {
+ .name = MEM2MEM_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static void __exit deinterlace_exit(void)
+{
+ platform_driver_unregister(&deinterlace_pdrv);
+}
+
+static int __init deinterlace_init(void)
+{
+ return platform_driver_register(&deinterlace_pdrv);
+}
+
+module_init(deinterlace_init);
+module_exit(deinterlace_exit);
+
diff --git a/drivers/media/video/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
index bf739e3b3398..bf739e3b3398 100644
--- a/drivers/media/video/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
diff --git a/drivers/media/video/marvell-ccic/Makefile b/drivers/media/platform/marvell-ccic/Makefile
index 05a792c579a2..05a792c579a2 100644
--- a/drivers/media/video/marvell-ccic/Makefile
+++ b/drivers/media/platform/marvell-ccic/Makefile
diff --git a/drivers/media/video/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index d030f9beae88..d030f9beae88 100644
--- a/drivers/media/video/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index ce2b7b4788d6..ce2b7b4788d6 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
index bd6acba9fb37..bd6acba9fb37 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.h
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index c4c17fe76c0d..c4c17fe76c0d 100644
--- a/drivers/media/video/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
new file mode 100644
index 000000000000..0b496f39a65f
--- /dev/null
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -0,0 +1,1130 @@
+/*
+ * A virtual v4l2-mem2mem example device.
+ *
+ * This is a virtual device driver for testing mem-to-mem videobuf framework.
+ * It simulates a device that uses memory buffers for both source and
+ * destination, processes the data and issues an "irq" (simulated by a timer).
+ * The device is capable of multi-instance, multi-buffer-per-transaction
+ * operation (via the mem2mem framework).
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@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/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
+
+MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
+MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.1");
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 640
+#define MAX_H 480
+#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
+
+/* 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-testdev"
+
+/* Per queue */
+#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
+
+/* Default transaction time in msec */
+#define MEM2MEM_DEF_TRANSTIME 1000
+/* Default number of buffers per transaction */
+#define MEM2MEM_DEF_TRANSLEN 1
+#define MEM2MEM_COLOR_STEP (0xff >> 4)
+#define MEM2MEM_NUM_TILES 8
+
+/* Flags that indicate processing mode */
+#define MEM2MEM_HFLIP (1 << 0)
+#define MEM2MEM_VFLIP (1 << 1)
+
+#define dprintk(dev, fmt, arg...) \
+ v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+
+void m2mtest_dev_release(struct device *dev)
+{}
+
+static struct platform_device m2mtest_pdev = {
+ .name = MEM2MEM_NAME,
+ .dev.release = m2mtest_dev_release,
+};
+
+struct m2mtest_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+ /* Types the format can be used for */
+ u32 types;
+};
+
+static struct m2mtest_fmt formats[] = {
+ {
+ .name = "RGB565 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .depth = 16,
+ /* Both capture and output format */
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ },
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ /* Output-only format */
+ .types = MEM2MEM_OUTPUT,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct m2mtest_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int sizeimage;
+ struct m2mtest_fmt *fmt;
+};
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000)
+#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001)
+
+static struct m2mtest_fmt *find_format(struct v4l2_format *f)
+{
+ struct m2mtest_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 m2mtest_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd;
+
+ atomic_t num_inst;
+ struct mutex dev_mutex;
+ spinlock_t irqlock;
+
+ struct timer_list timer;
+
+ struct v4l2_m2m_dev *m2m_dev;
+};
+
+struct m2mtest_ctx {
+ struct v4l2_fh fh;
+ struct m2mtest_dev *dev;
+
+ struct v4l2_ctrl_handler hdl;
+
+ /* Processed buffers in this transaction */
+ u8 num_processed;
+
+ /* Transaction length (i.e. how many buffers per transaction) */
+ u32 translen;
+ /* Transaction time (i.e. simulated processing time) in milliseconds */
+ u32 transtime;
+
+ /* Abort requested by m2m */
+ int aborting;
+
+ /* Processing mode */
+ int mode;
+
+ enum v4l2_colorspace colorspace;
+
+ struct v4l2_m2m_ctx *m2m_ctx;
+
+ /* Source and destination queue data */
+ struct m2mtest_q_data q_data[2];
+};
+
+static inline struct m2mtest_ctx *file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct m2mtest_ctx, fh);
+}
+
+static struct m2mtest_q_data *get_q_data(struct m2mtest_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;
+}
+
+
+static int device_process(struct m2mtest_ctx *ctx,
+ struct vb2_buffer *in_vb,
+ struct vb2_buffer *out_vb)
+{
+ struct m2mtest_dev *dev = ctx->dev;
+ struct m2mtest_q_data *q_data;
+ u8 *p_in, *p_out;
+ int x, y, t, w;
+ int tile_w, bytes_left;
+ int width, height, bytesperline;
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ width = q_data->width;
+ height = q_data->height;
+ bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
+
+ p_in = vb2_plane_vaddr(in_vb, 0);
+ p_out = vb2_plane_vaddr(out_vb, 0);
+ if (!p_in || !p_out) {
+ v4l2_err(&dev->v4l2_dev,
+ "Acquiring kernel pointers to buffers failed\n");
+ return -EFAULT;
+ }
+
+ if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
+ v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
+ return -EINVAL;
+ }
+
+ tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
+ / MEM2MEM_NUM_TILES;
+ bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
+ w = 0;
+
+ switch (ctx->mode) {
+ case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
+ p_out += bytesperline * height - bytes_left;
+ for (y = 0; y < height; ++y) {
+ for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+ if (w & 0x1) {
+ for (x = 0; x < tile_w; ++x)
+ *--p_out = *p_in++ +
+ MEM2MEM_COLOR_STEP;
+ } else {
+ for (x = 0; x < tile_w; ++x)
+ *--p_out = *p_in++ -
+ MEM2MEM_COLOR_STEP;
+ }
+ ++w;
+ }
+ p_in += bytes_left;
+ p_out -= bytes_left;
+ }
+ break;
+
+ case MEM2MEM_HFLIP:
+ for (y = 0; y < height; ++y) {
+ p_out += MEM2MEM_NUM_TILES * tile_w;
+ for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+ if (w & 0x01) {
+ for (x = 0; x < tile_w; ++x)
+ *--p_out = *p_in++ +
+ MEM2MEM_COLOR_STEP;
+ } else {
+ for (x = 0; x < tile_w; ++x)
+ *--p_out = *p_in++ -
+ MEM2MEM_COLOR_STEP;
+ }
+ ++w;
+ }
+ p_in += bytes_left;
+ p_out += bytesperline;
+ }
+ break;
+
+ case MEM2MEM_VFLIP:
+ p_out += bytesperline * (height - 1);
+ for (y = 0; y < height; ++y) {
+ for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+ if (w & 0x1) {
+ for (x = 0; x < tile_w; ++x)
+ *p_out++ = *p_in++ +
+ MEM2MEM_COLOR_STEP;
+ } else {
+ for (x = 0; x < tile_w; ++x)
+ *p_out++ = *p_in++ -
+ MEM2MEM_COLOR_STEP;
+ }
+ ++w;
+ }
+ p_in += bytes_left;
+ p_out += bytes_left - 2 * bytesperline;
+ }
+ break;
+
+ default:
+ for (y = 0; y < height; ++y) {
+ for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+ if (w & 0x1) {
+ for (x = 0; x < tile_w; ++x)
+ *p_out++ = *p_in++ +
+ MEM2MEM_COLOR_STEP;
+ } else {
+ for (x = 0; x < tile_w; ++x)
+ *p_out++ = *p_in++ -
+ MEM2MEM_COLOR_STEP;
+ }
+ ++w;
+ }
+ p_in += bytes_left;
+ p_out += bytes_left;
+ }
+ }
+
+ return 0;
+}
+
+static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
+{
+ dprintk(dev, "Scheduling a simulated irq\n");
+ mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+/**
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+static int job_ready(void *priv)
+{
+ struct m2mtest_ctx *ctx = priv;
+
+ if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
+ || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
+ dprintk(ctx->dev, "Not enough buffers available\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void job_abort(void *priv)
+{
+ struct m2mtest_ctx *ctx = priv;
+
+ /* Will cancel the transaction in the next interrupt handler */
+ ctx->aborting = 1;
+}
+
+static void m2mtest_lock(void *priv)
+{
+ struct m2mtest_ctx *ctx = priv;
+ struct m2mtest_dev *dev = ctx->dev;
+ mutex_lock(&dev->dev_mutex);
+}
+
+static void m2mtest_unlock(void *priv)
+{
+ struct m2mtest_ctx *ctx = priv;
+ struct m2mtest_dev *dev = ctx->dev;
+ mutex_unlock(&dev->dev_mutex);
+}
+
+
+/* device_run() - prepares and starts the device
+ *
+ * This simulates all the immediate preparations required before starting
+ * a device. This will be called by the framework when it decides to schedule
+ * a particular instance.
+ */
+static void device_run(void *priv)
+{
+ struct m2mtest_ctx *ctx = priv;
+ struct m2mtest_dev *dev = ctx->dev;
+ struct vb2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+ device_process(ctx, src_buf, dst_buf);
+
+ /* Run a timer, which simulates a hardware irq */
+ schedule_irq(dev, ctx->transtime);
+}
+
+static void device_isr(unsigned long priv)
+{
+ struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
+ struct m2mtest_ctx *curr_ctx;
+ struct vb2_buffer *src_vb, *dst_vb;
+ unsigned long flags;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
+
+ if (NULL == curr_ctx) {
+ printk(KERN_ERR
+ "Instance released before the end of transaction\n");
+ return;
+ }
+
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+ curr_ctx->num_processed++;
+
+ spin_lock_irqsave(&m2mtest_dev->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(&m2mtest_dev->irqlock, flags);
+
+ if (curr_ctx->num_processed == curr_ctx->translen
+ || curr_ctx->aborting) {
+ dprintk(curr_ctx->dev, "Finishing transaction\n");
+ curr_ctx->num_processed = 0;
+ v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
+ } else {
+ device_run(curr_ctx);
+ }
+}
+
+/*
+ * 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);
+ strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num;
+ struct m2mtest_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];
+ strncpy(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 m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct m2mtest_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;
+ f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = q_data->sizeimage;
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
+{
+ enum v4l2_field field;
+
+ 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.height < MIN_H)
+ f->fmt.pix.height = MIN_H;
+ else if (f->fmt.pix.height > MAX_H)
+ f->fmt.pix.height = MAX_H;
+
+ if (f->fmt.pix.width < MIN_W)
+ f->fmt.pix.width = MIN_W;
+ else if (f->fmt.pix.width > MAX_W)
+ f->fmt.pix.width = MAX_W;
+
+ f->fmt.pix.width &= ~DIM_ALIGN_MASK;
+ 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_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct m2mtest_fmt *fmt;
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ 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;
+ }
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct m2mtest_fmt *fmt;
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ 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;
+ }
+ if (!f->fmt.pix.colorspace)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+{
+ struct m2mtest_q_data *q_data;
+ struct vb2_queue *vq;
+
+ 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;
+ }
+
+ q_data->fmt = find_format(f);
+ q_data->width = f->fmt.pix.width;
+ q_data->height = f->fmt.pix.height;
+ q_data->sizeimage = q_data->width * q_data->height
+ * q_data->fmt->depth >> 3;
+
+ 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(file2ctx(file), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = vidioc_s_fmt(file2ctx(file), f);
+ if (!ret)
+ ctx->colorspace = f->fmt.pix.colorspace;
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct m2mtest_ctx *ctx =
+ container_of(ctrl->handler, struct m2mtest_ctx, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ ctx->mode |= MEM2MEM_HFLIP;
+ else
+ ctx->mode &= ~MEM2MEM_HFLIP;
+ break;
+
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ ctx->mode |= MEM2MEM_VFLIP;
+ else
+ ctx->mode &= ~MEM2MEM_VFLIP;
+ break;
+
+ case V4L2_CID_TRANS_TIME_MSEC:
+ ctx->transtime = ctrl->val;
+ break;
+
+ case V4L2_CID_TRANS_NUM_BUFS:
+ ctx->translen = ctrl->val;
+ break;
+
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = {
+ .s_ctrl = m2mtest_s_ctrl,
+};
+
+
+static const struct v4l2_ioctl_ops m2mtest_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,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+
+/*
+ * Queue operations
+ */
+
+static int m2mtest_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
+ struct m2mtest_q_data *q_data;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(ctx, vq->type);
+
+ size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
+
+ while (size * count > MEM2MEM_VID_MEM_LIMIT)
+ (count)--;
+
+ *nplanes = 1;
+ *nbuffers = count;
+ sizes[0] = size;
+
+ /*
+ * videobuf2-vmalloc allocator is context-less so no need to set
+ * alloc_ctxs array.
+ */
+
+ dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+ return 0;
+}
+
+static int m2mtest_buf_prepare(struct vb2_buffer *vb)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct m2mtest_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 m2mtest_buf_queue(struct vb2_buffer *vb)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void m2mtest_wait_prepare(struct vb2_queue *q)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+ m2mtest_unlock(ctx);
+}
+
+static void m2mtest_wait_finish(struct vb2_queue *q)
+{
+ struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+ m2mtest_lock(ctx);
+}
+
+static struct vb2_ops m2mtest_qops = {
+ .queue_setup = m2mtest_queue_setup,
+ .buf_prepare = m2mtest_buf_prepare,
+ .buf_queue = m2mtest_buf_queue,
+ .wait_prepare = m2mtest_wait_prepare,
+ .wait_finish = m2mtest_wait_finish,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct m2mtest_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 = &m2mtest_qops;
+ src_vq->mem_ops = &vb2_vmalloc_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 = &m2mtest_qops;
+ dst_vq->mem_ops = &vb2_vmalloc_memops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
+ .ops = &m2mtest_ctrl_ops,
+ .id = V4L2_CID_TRANS_TIME_MSEC,
+ .name = "Transaction Time (msec)",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 1001,
+ .min = 1,
+ .max = 10001,
+ .step = 100,
+};
+
+static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
+ .ops = &m2mtest_ctrl_ops,
+ .id = V4L2_CID_TRANS_NUM_BUFS,
+ .name = "Buffers Per Transaction",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 1,
+ .min = 1,
+ .max = MEM2MEM_DEF_NUM_BUFS,
+ .step = 1,
+};
+
+/*
+ * File operations
+ */
+static int m2mtest_open(struct file *file)
+{
+ struct m2mtest_dev *dev = video_drvdata(file);
+ struct m2mtest_ctx *ctx = NULL;
+ struct v4l2_ctrl_handler *hdl;
+ int rc = 0;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto open_unlock;
+ }
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+ hdl = &ctx->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL);
+ v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL);
+ if (hdl->error) {
+ rc = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ goto open_unlock;
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+
+ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
+ ctx->q_data[V4L2_M2M_SRC].width = 640;
+ ctx->q_data[V4L2_M2M_SRC].height = 480;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage =
+ ctx->q_data[V4L2_M2M_SRC].width *
+ ctx->q_data[V4L2_M2M_SRC].height *
+ (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
+ ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
+ if (IS_ERR(ctx->m2m_ctx)) {
+ rc = PTR_ERR(ctx->m2m_ctx);
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(ctx);
+ goto open_unlock;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+ atomic_inc(&dev->num_inst);
+
+ dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+open_unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return rc;
+}
+
+static int m2mtest_release(struct file *file)
+{
+ struct m2mtest_dev *dev = video_drvdata(file);
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ dprintk(dev, "Releasing instance %p\n", ctx);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ mutex_lock(&dev->dev_mutex);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ mutex_unlock(&dev->dev_mutex);
+ kfree(ctx);
+
+ atomic_dec(&dev->num_inst);
+
+ return 0;
+}
+
+static unsigned int m2mtest_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct m2mtest_ctx *ctx = file2ctx(file);
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct m2mtest_dev *dev = video_drvdata(file);
+ struct m2mtest_ctx *ctx = file2ctx(file);
+ int res;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+ res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+ mutex_unlock(&dev->dev_mutex);
+ return res;
+}
+
+static const struct v4l2_file_operations m2mtest_fops = {
+ .owner = THIS_MODULE,
+ .open = m2mtest_open,
+ .release = m2mtest_release,
+ .poll = m2mtest_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = m2mtest_mmap,
+};
+
+static struct video_device m2mtest_videodev = {
+ .name = MEM2MEM_NAME,
+ .fops = &m2mtest_fops,
+ .ioctl_ops = &m2mtest_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = device_run,
+ .job_ready = job_ready,
+ .job_abort = job_abort,
+ .lock = m2mtest_lock,
+ .unlock = m2mtest_unlock,
+};
+
+static int m2mtest_probe(struct platform_device *pdev)
+{
+ struct m2mtest_dev *dev;
+ struct video_device *vfd;
+ int ret;
+
+ dev = kzalloc(sizeof *dev, GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ spin_lock_init(&dev->irqlock);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto free_dev;
+
+ atomic_set(&dev->num_inst, 0);
+ mutex_init(&dev->dev_mutex);
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto unreg_dev;
+ }
+
+ *vfd = m2mtest_videodev;
+ vfd->lock = &dev->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", m2mtest_videodev.name);
+ dev->vfd = vfd;
+ v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+ "Device registered as /dev/video%d\n", vfd->num);
+
+ setup_timer(&dev->timer, device_isr, (long)dev);
+ platform_set_drvdata(pdev, dev);
+
+ dev->m2m_dev = v4l2_m2m_init(&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 err_m2m;
+ }
+
+ return 0;
+
+ v4l2_m2m_release(dev->m2m_dev);
+err_m2m:
+ video_unregister_device(dev->vfd);
+rel_vdev:
+ video_device_release(vfd);
+unreg_dev:
+ v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+ kfree(dev);
+
+ return ret;
+}
+
+static int m2mtest_remove(struct platform_device *pdev)
+{
+ struct m2mtest_dev *dev =
+ (struct m2mtest_dev *)platform_get_drvdata(pdev);
+
+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+ v4l2_m2m_release(dev->m2m_dev);
+ del_timer_sync(&dev->timer);
+ video_unregister_device(dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver m2mtest_pdrv = {
+ .probe = m2mtest_probe,
+ .remove = m2mtest_remove,
+ .driver = {
+ .name = MEM2MEM_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static void __exit m2mtest_exit(void)
+{
+ platform_driver_unregister(&m2mtest_pdrv);
+ platform_device_unregister(&m2mtest_pdev);
+}
+
+static int __init m2mtest_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&m2mtest_pdev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&m2mtest_pdrv);
+ if (ret)
+ platform_device_unregister(&m2mtest_pdev);
+
+ return 0;
+}
+
+module_init(m2mtest_init);
+module_exit(m2mtest_exit);
+
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
new file mode 100644
index 000000000000..dab380a8d1c6
--- /dev/null
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -0,0 +1,1030 @@
+/*
+ * 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_ahb, *clk_emma_ipg;
+ 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);
+ /*
+ * This is only a mem-to-mem video device. The capture and output
+ * device capability flags are left only for backward compatibility
+ * and are scheduled for removal.
+ */
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_M2M | 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 | VB2_USERPTR;
+ 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 | VB2_USERPTR;
+ 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;
+
+ if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
+ kfree(ctx);
+ return -ERESTARTSYS;
+ }
+
+ 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);
+
+ mutex_unlock(&pcdev->dev_mutex);
+ kfree(ctx);
+ return ret;
+ }
+
+ clk_prepare_enable(pcdev->clk_emma_ipg);
+ clk_prepare_enable(pcdev->clk_emma_ahb);
+ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
+ ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+ mutex_unlock(&pcdev->dev_mutex);
+
+ 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);
+
+ mutex_lock(&pcdev->dev_mutex);
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ mutex_unlock(&pcdev->dev_mutex);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int emmaprp_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct emmaprp_dev *pcdev = video_drvdata(file);
+ struct emmaprp_ctx *ctx = file->private_data;
+ unsigned int res;
+
+ mutex_lock(&pcdev->dev_mutex);
+ res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+ mutex_unlock(&pcdev->dev_mutex);
+ return res;
+}
+
+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct emmaprp_dev *pcdev = video_drvdata(file);
+ struct emmaprp_ctx *ctx = file->private_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&pcdev->dev_mutex))
+ return -ERESTARTSYS;
+ ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+ mutex_unlock(&pcdev->dev_mutex);
+ return ret;
+}
+
+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 = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
+ if (!pcdev)
+ return -ENOMEM;
+
+ spin_lock_init(&pcdev->irqlock);
+
+ pcdev->clk_emma_ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(pcdev->clk_emma_ipg)) {
+ return PTR_ERR(pcdev->clk_emma_ipg);
+ }
+
+ pcdev->clk_emma_ahb = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(pcdev->clk_emma_ipg)) {
+ return PTR_ERR(pcdev->clk_emma_ahb);
+ }
+
+ 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");
+ return -ENODEV;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+ if (ret)
+ return ret;
+
+ 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);
+
+ pcdev->base_emma = devm_request_and_ioremap(&pdev->dev, res_emma);
+ if (!pcdev->base_emma) {
+ ret = -ENXIO;
+ 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) {
+ ret = -ENODEV;
+ 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);
+
+ 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);
+
+ 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/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 390ab094f9f2..390ab094f9f2 100644
--- a/drivers/media/video/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
diff --git a/drivers/media/platform/omap/Makefile b/drivers/media/platform/omap/Makefile
new file mode 100644
index 000000000000..d80df41fde28
--- /dev/null
+++ b/drivers/media/platform/omap/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the omap video device drivers.
+#
+
+# OMAP2/3 Display driver
+omap-vout-y += omap_vout.o omap_voutlib.o
+omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
+obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 88cf9d952631..88cf9d952631 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index 4be26abf6cea..4be26abf6cea 100644
--- a/drivers/media/video/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
diff --git a/drivers/media/video/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
index ffde741e0590..ffde741e0590 100644
--- a/drivers/media/video/omap/omap_vout_vrfb.h
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h
index 27a95d23b913..27a95d23b913 100644
--- a/drivers/media/video/omap/omap_voutdef.h
+++ b/drivers/media/platform/omap/omap_voutdef.h
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c
index 115408b9274f..115408b9274f 100644
--- a/drivers/media/video/omap/omap_voutlib.c
+++ b/drivers/media/platform/omap/omap_voutlib.c
diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/platform/omap/omap_voutlib.h
index e51750a597e3..e51750a597e3 100644
--- a/drivers/media/video/omap/omap_voutlib.h
+++ b/drivers/media/platform/omap/omap_voutlib.h
diff --git a/drivers/media/platform/omap24xxcam-dma.c b/drivers/media/platform/omap24xxcam-dma.c
new file mode 100644
index 000000000000..9c00776d6583
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam-dma.c
@@ -0,0 +1,601 @@
+/*
+ * drivers/media/platform/omap24xxcam-dma.c
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com> and
+ * David Cohen <david.cohen@indt.org.br>.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#include "omap24xxcam.h"
+
+/*
+ *
+ * DMA hardware.
+ *
+ */
+
+/* Ack all interrupt on CSR and IRQSTATUS_L0 */
+static void omap24xxcam_dmahw_ack_all(void __iomem *base)
+{
+ u32 csr;
+ int i;
+
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
+ }
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
+}
+
+/* Ack dmach on CSR and IRQSTATUS_L0 */
+static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
+{
+ u32 csr;
+
+ csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
+ /* ack interrupt in CSR */
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
+ /* ack interrupt in IRQSTATUS */
+ omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+
+ return csr;
+}
+
+static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
+{
+ return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
+}
+
+static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
+ dma_addr_t start, u32 len)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_WR_ACTIVE
+ | CAMDMA_CCR_RD_ACTIVE
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
+ omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
+ omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
+ CAMDMA_CSDP_WRITE_MODE_POSTED
+ | CAMDMA_CSDP_DST_BURST_EN_32
+ | CAMDMA_CSDP_DST_PACKED
+ | CAMDMA_CSDP_SRC_BURST_EN_32
+ | CAMDMA_CSDP_SRC_PACKED
+ | CAMDMA_CSDP_DATA_TYPE_8BITS);
+ omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
+ omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+ omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
+ omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
+ CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR
+ | CAMDMA_CSR_BLOCK
+ | CAMDMA_CSR_DROP);
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
+ CAMDMA_CICR_MISALIGNED_ERR_IE
+ | CAMDMA_CICR_SECURE_ERR_IE
+ | CAMDMA_CICR_TRANS_ERR_IE
+ | CAMDMA_CICR_BLOCK_IE
+ | CAMDMA_CICR_DROP_IE);
+}
+
+static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
+{
+ omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+}
+
+static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
+ int free_dmach)
+{
+ int prev_dmach, ch;
+
+ if (dmach == 0)
+ prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+ else
+ prev_dmach = dmach - 1;
+ omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
+ CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+ /* Did we chain the DMA transfer before the previous one
+ * finished?
+ */
+ ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
+ while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
+ & CAMDMA_CCR_ENABLE)) {
+ if (ch == dmach) {
+ /* The previous transfer has ended and this one
+ * hasn't started, so we must not have chained
+ * to the previous one in time. We'll have to
+ * start it now.
+ */
+ omap24xxcam_dmahw_transfer_start(base, dmach);
+ break;
+ } else
+ ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+ }
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
+{
+ /* mask all interrupts from this channel */
+ omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
+ /* unlink this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
+ CAMDMA_CLNK_CTRL_ENABLE_LNK);
+ /* disable this channel */
+ omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+}
+
+static void omap24xxcam_dmahw_init(void __iomem *base)
+{
+ omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
+ CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
+ | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+ | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
+ CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+
+ omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
+}
+
+/*
+ *
+ * Individual DMA channel handling.
+ *
+ */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
+ u32 len, dma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ int dmach;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
+ spin_unlock_irqrestore(&dma->lock, flags);
+ return -EBUSY;
+ }
+
+ dmach = dma->next_dmach;
+
+ dma->ch_state[dmach].callback = callback;
+ dma->ch_state[dmach].arg = arg;
+
+ omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
+
+ /* We're ready to start the DMA transfer. */
+
+ if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ /* A transfer is already in progress, so try to chain to it. */
+ omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
+ dma->free_dmach);
+ } else {
+ /* No transfer is in progress, so we'll just start this one
+ * now.
+ */
+ omap24xxcam_dmahw_transfer_start(dma->base, dmach);
+ }
+
+ dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+ dma->free_dmach--;
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+
+ return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
+{
+ unsigned long flags;
+ int dmach, i, free_dmach;
+ dma_callback_t callback;
+ void *arg;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ /* stop any DMA transfers in progress */
+ dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+ omap24xxcam_dmahw_abort_ch(dma->base, dmach);
+ dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+ }
+
+ /* We have to be careful here because the callback routine
+ * might start a new DMA transfer, and we only want to abort
+ * transfers that were started before this routine was called.
+ */
+ free_dmach = dma->free_dmach;
+ while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
+ (free_dmach < NUM_CAMDMA_CHANNELS)) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ free_dmach++;
+ if (callback) {
+ /* leave interrupts disabled during callback */
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. If the completion
+ * routines attempt to start a new DMA transfer it will fail, so the
+ * DMA controller will be idle after this routine completes.
+ */
+static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
+{
+ atomic_inc(&dma->dma_stop);
+ omap24xxcam_dma_abort(dma, csr);
+ atomic_dec(&dma->dma_stop);
+}
+
+/* Camera DMA interrupt service routine. */
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
+{
+ int dmach;
+ dma_callback_t callback;
+ void *arg;
+ u32 csr;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&dma->lock);
+
+ if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
+ /* A camera DMA interrupt occurred while all channels
+ * are idle, so we'll acknowledge the interrupt in the
+ * IRQSTATUS register and exit.
+ */
+ omap24xxcam_dmahw_ack_all(dma->base);
+ spin_unlock(&dma->lock);
+ return;
+ }
+
+ while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+ dmach = (dma->next_dmach + dma->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ if (omap24xxcam_dmahw_running(dma->base, dmach)) {
+ /* This buffer hasn't finished yet, so we're done. */
+ break;
+ }
+ csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
+ if (csr & csr_error) {
+ /* A DMA error occurred, so stop all DMA
+ * transfers in progress.
+ */
+ spin_unlock(&dma->lock);
+ omap24xxcam_dma_stop(dma, csr);
+ return;
+ } else {
+ callback = dma->ch_state[dmach].callback;
+ arg = dma->ch_state[dmach].arg;
+ dma->free_dmach++;
+ if (callback) {
+ spin_unlock(&dma->lock);
+ (*callback) (dma, csr, arg);
+ spin_lock(&dma->lock);
+ }
+ }
+ }
+
+ spin_unlock(&dma->lock);
+
+ omap24xxcam_sgdma_process(
+ container_of(dma, struct omap24xxcam_sgdma, dma));
+}
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dma->lock, flags);
+
+ omap24xxcam_dmahw_init(dma->base);
+
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
+ void __iomem *base)
+{
+ int ch;
+
+ /* group all channels on DMA IRQ0 and unmask irq */
+ spin_lock_init(&dma->lock);
+ dma->base = base;
+ dma->free_dmach = NUM_CAMDMA_CHANNELS;
+ dma->next_dmach = 0;
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+ dma->ch_state[ch].callback = NULL;
+ dma->ch_state[ch].arg = NULL;
+ }
+}
+
+/*
+ *
+ * Scatter-gather DMA.
+ *
+ * High-level DMA construct for transferring whole picture frames to
+ * memory that is discontinuous.
+ *
+ */
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
+ void *arg)
+{
+ struct omap24xxcam_sgdma *sgdma =
+ container_of(dma, struct omap24xxcam_sgdma, dma);
+ int sgslot = (int)arg;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&sgdma->lock);
+
+ /* We got an interrupt, we can remove the timer */
+ del_timer(&sgdma->reset_timer);
+
+ sg_state = sgdma->sg_state + sgslot;
+ if (!sg_state->queued_sglist) {
+ spin_unlock(&sgdma->lock);
+ printk(KERN_ERR "%s: sgdma completed when none queued!\n",
+ __func__);
+ return;
+ }
+
+ sg_state->csr |= csr;
+ if (!--sg_state->queued_sglist) {
+ /* Queue for this sglist is empty, so check to see if we're
+ * done.
+ */
+ if ((sg_state->next_sglist == sg_state->sglen)
+ || (sg_state->csr & csr_error)) {
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ u32 sg_csr = sg_state->csr;
+ /* All done with this sglist */
+ sgdma->free_sgdma++;
+ if (callback) {
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, sg_csr, arg);
+ return;
+ }
+ }
+ }
+
+ spin_unlock(&sgdma->lock);
+}
+
+/* Start queued scatter-gather DMA transfers. */
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sg_state;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sg_state = sgdma->sg_state + sgslot;
+ while ((sg_state->next_sglist < sg_state->sglen) &&
+ !(sg_state->csr & csr_error)) {
+ const struct scatterlist *sglist;
+ unsigned int len;
+
+ sglist = sg_state->sglist + sg_state->next_sglist;
+ /* try to start the next DMA transfer */
+ if (sg_state->next_sglist + 1 == sg_state->sglen) {
+ /*
+ * On the last sg, we handle the case where
+ * cam->img.pix.sizeimage % PAGE_ALIGN != 0
+ */
+ len = sg_state->len - sg_state->bytes_read;
+ } else {
+ len = sg_dma_len(sglist);
+ }
+
+ if (omap24xxcam_dma_start(&sgdma->dma,
+ sg_dma_address(sglist),
+ len,
+ omap24xxcam_sgdma_callback,
+ (void *)sgslot)) {
+ /* DMA start failed */
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return;
+ } else {
+ unsigned long expires;
+ /* DMA start was successful */
+ sg_state->next_sglist++;
+ sg_state->bytes_read += len;
+ sg_state->queued_sglist++;
+
+ /* We start the reset timer */
+ expires = jiffies + HZ;
+ mod_timer(&sgdma->reset_timer, expires);
+ }
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+/*
+ * Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or non-zero
+ * if all of the scatter-gather slots are already in use.
+ */
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg)
+{
+ unsigned long flags;
+ struct sgdma_state *sg_state;
+
+ if ((sglen < 0) || ((sglen > 0) && !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (!sgdma->free_sgdma) {
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return -EBUSY;
+ }
+
+ sg_state = sgdma->sg_state + sgdma->next_sgdma;
+
+ sg_state->sglist = sglist;
+ sg_state->sglen = sglen;
+ sg_state->next_sglist = 0;
+ sg_state->bytes_read = 0;
+ sg_state->len = len;
+ sg_state->queued_sglist = 0;
+ sg_state->csr = 0;
+ sg_state->callback = callback;
+ sg_state->arg = arg;
+
+ sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
+ sgdma->free_sgdma--;
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+
+ omap24xxcam_sgdma_process(sgdma);
+
+ return 0;
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
+{
+ unsigned long flags;
+ int sgslot;
+ struct sgdma_state *sg_state;
+ u32 csr = CAMDMA_CSR_TRANS_ERR;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(&sgdma->dma, csr);
+
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (sgdma->free_sgdma < NUM_SG_DMA) {
+ sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ sg_state = sgdma->sg_state + sgslot;
+ if (sg_state->next_sglist != 0) {
+ /* This DMA transfer was in progress, so abort it. */
+ sgdma_callback_t callback = sg_state->callback;
+ void *arg = sg_state->arg;
+ sgdma->free_sgdma++;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&sgdma->lock);
+ (*callback) (sgdma, csr, arg);
+ spin_lock(&sgdma->lock);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ void __iomem *base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data)
+{
+ int sg;
+
+ spin_lock_init(&sgdma->lock);
+ sgdma->free_sgdma = NUM_SG_DMA;
+ sgdma->next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ sgdma->sg_state[sg].sglen = 0;
+ sgdma->sg_state[sg].next_sglist = 0;
+ sgdma->sg_state[sg].bytes_read = 0;
+ sgdma->sg_state[sg].queued_sglist = 0;
+ sgdma->sg_state[sg].csr = 0;
+ sgdma->sg_state[sg].callback = NULL;
+ sgdma->sg_state[sg].arg = NULL;
+ }
+
+ omap24xxcam_dma_init(&sgdma->dma, base);
+ setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
+}
diff --git a/drivers/media/platform/omap24xxcam.c b/drivers/media/platform/omap24xxcam.c
new file mode 100644
index 000000000000..fde2e66f6f33
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam.c
@@ -0,0 +1,1881 @@
+/*
+ * drivers/media/platform/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007-2008 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.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/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION "0.0.1"
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* module parameters */
+static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
+/*
+ * Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+ if (cam->ick != NULL && !IS_ERR(cam->ick))
+ clk_put(cam->ick);
+ if (cam->fck != NULL && !IS_ERR(cam->fck))
+ clk_put(cam->fck);
+
+ cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+ int rval = 0;
+
+ cam->fck = clk_get(cam->dev, "fck");
+ if (IS_ERR(cam->fck)) {
+ dev_err(cam->dev, "can't get camera fck");
+ rval = PTR_ERR(cam->fck);
+ omap24xxcam_clock_put(cam);
+ return rval;
+ }
+
+ cam->ick = clk_get(cam->dev, "ick");
+ if (IS_ERR(cam->ick)) {
+ dev_err(cam->dev, "can't get camera ick");
+ rval = PTR_ERR(cam->ick);
+ omap24xxcam_clock_put(cam);
+ }
+
+ return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+ clk_enable(cam->fck);
+ clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+ clk_disable(cam->fck);
+ clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+ u32 xclk)
+{
+ if (xclk) {
+ u32 divisor = CAM_MCLK / xclk;
+
+ if (divisor == 1)
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK,
+ CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, divisor);
+ } else
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+ CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+ /*
+ * Setting the camera core AUTOIDLE bit causes problems with frame
+ * synchronization, so we will clear the AUTOIDLE bit instead.
+ */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+ CC_SYSCONFIG_AUTOIDLE);
+
+ /* program the camera interface DMA packet size */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+ CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+ CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ
+ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+ CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+ u32 cc_irqstatus;
+ const u32 cc_irqstatus_err =
+ CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ
+ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_UF_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+ CC_IRQSTATUS);
+ omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+ cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err
+ && !atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+ cc_irqstatus);
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ size_t alloc_size;
+ struct page *page;
+ int i;
+
+ if (dma->sglist == NULL)
+ return;
+
+ i = dma->sglen;
+ while (i) {
+ i--;
+ alloc_size = sg_dma_len(&dma->sglist[i]);
+ page = sg_page(&dma->sglist[i]);
+ do {
+ ClearPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ __free_pages(sg_page(&dma->sglist[i]),
+ get_order(sg_dma_len(&dma->sglist[i])));
+ }
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+ int i;
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == vbq->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+ continue;
+ vbq->ops->buf_release(vbq, vbq->bufs[i]);
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ kfree(vbq->bufs[i]);
+ vbq->bufs[i] = NULL;
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+ unsigned int order;
+ size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+ struct page *page;
+ int max_pages, err = 0, i = 0;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /*
+ * allocate maximum size scatter-gather list. Note this is
+ * overhead. We may not use as many entries as we allocate
+ */
+ max_pages = vb->bsize >> PAGE_SHIFT;
+ dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+ if (dma->sglist == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ while (size) {
+ order = get_order(size);
+ /*
+ * do not over-allocate even if we would get larger
+ * contiguous chunk that way
+ */
+ if ((PAGE_SIZE << order) > size)
+ order--;
+
+ /* try to allocate as many contiguous pages as possible */
+ page = alloc_pages(GFP_KERNEL, order);
+ /* if allocation fails, try to allocate smaller amount */
+ while (page == NULL) {
+ order--;
+ page = alloc_pages(GFP_KERNEL, order);
+ if (page == NULL && !order) {
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ size -= (PAGE_SIZE << order);
+
+ /* append allocated chunk of pages into scatter-gather list */
+ sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+ dma->sglen++;
+ i++;
+
+ alloc_size = (PAGE_SIZE << order);
+
+ /* clear pages before giving them to user space */
+ memset(page_address(page), 0, alloc_size);
+
+ /* mark allocated pages reserved */
+ do {
+ SetPageReserved(page++);
+ } while (alloc_size -= PAGE_SIZE);
+ }
+ /*
+ * REVISIT: not fully correct to assign nr_pages == sglen but
+ * video-buf is passing nr_pages for e.g. unmap_sg calls
+ */
+ dma->nr_pages = dma->sglen;
+ dma->direction = PCI_DMA_FROMDEVICE;
+
+ return 0;
+
+out:
+ omap24xxcam_vbq_free_mmap_buffer(vb);
+ return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+ unsigned int count)
+{
+ int i, err = 0;
+ struct omap24xxcam_fh *fh =
+ container_of(vbq, struct omap24xxcam_fh, vbq);
+
+ mutex_lock(&vbq->vb_lock);
+
+ for (i = 0; i < count; i++) {
+ err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+ if (err)
+ goto out;
+ dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+ videobuf_to_dma(vbq->bufs[i])->sglen, i);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return 0;
+out:
+ while (i) {
+ i--;
+ omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+ }
+
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+ u32 csr, void *arg)
+{
+ struct omap24xxcam_device *cam =
+ container_of(sgdma, struct omap24xxcam_device, sgdma);
+ struct omap24xxcam_fh *fh = cam->streaming->private_data;
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (--cam->sgdma_in_queue == 0)
+ omap24xxcam_core_disable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = atomic_add_return(2, &fh->field_count);
+ if (csr & csr_error) {
+ vb->state = VIDEOBUF_ERROR;
+ if (!atomic_read(&fh->cam->in_reset)) {
+ dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+ omap24xxcam_reset(cam);
+ }
+ } else
+ vb->state = VIDEOBUF_DONE;
+ wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ /* wait for buffer, especially to get out of the sgdma queue */
+ videobuf_waiton(vbq, vb, 0, 0);
+ if (vb->memory == V4L2_MEMORY_MMAP) {
+ dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+ dma->direction);
+ dma->direction = DMA_NONE;
+ } else {
+ videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ }
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ *size = fh->pix.sizeimage;
+
+ /* accessing fh->cam->capture_mem is ok, it's constant */
+ if (*size * *cnt > fh->cam->capture_mem)
+ *cnt = fh->cam->capture_mem / *size;
+
+ return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+ struct videobuf_dmabuf *dma)
+{
+ int err = 0;
+
+ dma->direction = PCI_DMA_FROMDEVICE;
+ if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ int err = 0;
+
+ /*
+ * Accessing pix here is okay since it's constant while
+ * streaming is on (and we only get called then).
+ */
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (fh->pix.sizeimage > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = fh->pix.sizeimage;
+ } else {
+ if (vb->state != VIDEOBUF_NEEDS_INIT) {
+ /*
+ * We have a kernel bounce buffer that has
+ * already been allocated.
+ */
+ if (fh->pix.sizeimage > vb->size) {
+ /*
+ * The image size has been changed to
+ * a larger size since this buffer was
+ * allocated, so we need to free and
+ * reallocate it.
+ */
+ omap24xxcam_vbq_release(vbq, vb);
+ vb->size = fh->pix.sizeimage;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = fh->pix.sizeimage;
+ }
+ }
+
+ if (err)
+ return err;
+
+ vb->width = fh->pix.width;
+ vb->height = fh->pix.height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ if (vb->memory == V4L2_MEMORY_MMAP)
+ /*
+ * we have built the scatter-gather list by ourself so
+ * do the scatter-gather mapping as well
+ */
+ err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+ else
+ err = videobuf_iolock(vbq, vb, NULL);
+ }
+
+ if (!err)
+ vb->state = VIDEOBUF_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ unsigned long flags;
+ int err;
+
+ /*
+ * FIXME: We're marking the buffer active since we have no
+ * pretty way of marking it active exactly when the
+ * scatter-gather transfer starts.
+ */
+ vb->state = VIDEOBUF_ACTIVE;
+
+ err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+ videobuf_to_dma(vb)->sglist,
+ videobuf_to_dma(vb)->sglen, vb->size,
+ omap24xxcam_vbq_complete, vb);
+
+ if (!err) {
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+ if (++cam->sgdma_in_queue == 1
+ && !atomic_read(&cam->in_reset))
+ omap24xxcam_core_enable(cam);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ } else {
+ /*
+ * Oops. We're not supposed to get any errors here.
+ * The only way we could get an error is if we ran out
+ * of scatter-gather DMA slots, but we are supposed to
+ * have at least as many scatter-gather DMA slots as
+ * video buffers so that can't happen.
+ */
+ dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+ dev_err(cam->dev, "likely a bug in the driver!\n");
+ vb->state = state;
+ }
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+ .buf_setup = omap24xxcam_vbq_setup,
+ .buf_prepare = omap24xxcam_vbq_prepare,
+ .buf_queue = omap24xxcam_vbq_queue,
+ .buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam)
+{
+ int max_loop = RESET_TIMEOUT_NS;
+
+ /* Reset whole camera subsystem */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAM_SYSCONFIG,
+ CAM_SYSCONFIG_SOFTRESET);
+
+ /* Wait till it's finished */
+ while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE)
+ && --max_loop) {
+ ndelay(1);
+ }
+
+ if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+ & CAM_SYSSTATUS_RESETDONE))
+ dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_poweron_reset(cam);
+
+ /* set the camera subsystem autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+ CAM_SYSCONFIG_AUTOIDLE);
+
+ /* set the camera MMU autoidle bit */
+ omap24xxcam_reg_out(cam->mmio_base,
+ CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+ CAMMMU_SYSCONFIG_AUTOIDLE);
+
+ omap24xxcam_core_hwinit(cam);
+
+ omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+ if (!atomic_read(&cam->in_reset)) {
+ dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+ omap24xxcam_reset(cam);
+ }
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_inc_return(&cam->in_reset) != 1) {
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+ return;
+ }
+
+ omap24xxcam_core_disable(cam);
+
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+ omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+ if (atomic_read(&cam->in_reset) != 1)
+ goto out;
+
+ omap24xxcam_hwinit(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ omap24xxcam_sgdma_process(&cam->sgdma);
+
+ if (cam->sgdma_in_queue)
+ omap24xxcam_core_enable(cam);
+
+out:
+ atomic_dec(&cam->in_reset);
+ spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_capture_stop(cam);
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ u32 irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(&cam->sgdma.dma);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_core_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+ struct v4l2_ifparm p;
+
+ rval = vidioc_int_g_ifparm(cam->sdev, &p);
+ if (rval) {
+ dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+ return rval;
+ }
+
+ cam->if_type = p.if_type;
+
+ cam->cc_ctrl = CC_CTRL_CC_EN;
+
+ switch (p.if_type) {
+ case V4L2_IF_TYPE_BT656:
+ if (p.u.bt656.frame_start_on_rising_vs)
+ cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+ if (p.u.bt656.bt_sync_correct)
+ cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+ if (p.u.bt656.swap)
+ cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+ if (p.u.bt656.latch_clk_inv)
+ cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+ if (p.u.bt656.nobt_hs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+ if (p.u.bt656.nobt_vs_inv)
+ cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+ switch (p.u.bt656.mode) {
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+ break;
+ case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+ cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+ break;
+ default:
+ dev_err(cam->dev,
+ "bt656 interface mode %d not supported\n",
+ p.u.bt656.mode);
+ return -EINVAL;
+ }
+ /*
+ * The clock rate that the sensor wants has changed.
+ * We have to adjust the xclk from OMAP 2 side to
+ * match the sensor's wish as closely as possible.
+ */
+ if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+ u32 xclk = p.u.bt656.clock_curr;
+ u32 divisor;
+
+ if (xclk == 0)
+ return -EINVAL;
+
+ if (xclk > CAM_MCLK)
+ xclk = CAM_MCLK;
+
+ divisor = CAM_MCLK / xclk;
+ if (divisor * xclk < CAM_MCLK)
+ divisor++;
+ if (CAM_MCLK / divisor < p.u.bt656.clock_min
+ && divisor > 1)
+ divisor--;
+ if (divisor > 30)
+ divisor = 30;
+
+ xclk = CAM_MCLK / divisor;
+
+ if (xclk < p.u.bt656.clock_min
+ || xclk > p.u.bt656.clock_max)
+ return -EINVAL;
+
+ cam->if_u.bt656.xclk = xclk;
+ }
+ omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+ break;
+ default:
+ /* FIXME: how about other interfaces? */
+ dev_err(cam->dev, "interface type %d not supported\n",
+ p.if_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+ switch (cam->if_type) {
+ case V4L2_IF_TYPE_BT656:
+ omap24xxcam_core_xclk_set(cam, 0);
+ break;
+ }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+ int err = 0;
+ struct v4l2_int_device *sdev = cam->sdev;
+
+ omap24xxcam_clock_on(cam);
+ err = omap24xxcam_sensor_if_enable(cam);
+ if (err) {
+ dev_err(cam->dev, "sensor interface could not be enabled at "
+ "initialisation, %d\n", err);
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ /* power up sensor during sensor initialization */
+ vidioc_int_s_power(sdev, 1);
+
+ err = vidioc_int_dev_init(sdev);
+ if (err) {
+ dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+ /* Sensor init failed --- it's nonexistent to us! */
+ cam->sdev = NULL;
+ goto out;
+ }
+
+ dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+
+ vidioc_int_s_power(sdev, 0);
+
+ return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+ if (cam->sdev)
+ vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+ omap24xxcam_sensor_if_disable(cam);
+ omap24xxcam_clock_off(cam);
+ vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+ int rval;
+
+ omap24xxcam_clock_on(cam);
+
+ omap24xxcam_sensor_if_enable(cam);
+
+ rval = vidioc_int_s_power(cam->sdev, 1);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_init(cam->sdev);
+ if (rval)
+ goto out;
+
+ return 0;
+
+out:
+ omap24xxcam_sensor_disable(cam);
+
+ return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+ struct omap24xxcam_device *cam =
+ container_of(work, struct omap24xxcam_device,
+ sensor_reset_work);
+
+ if (atomic_read(&cam->reset_disable))
+ return;
+
+ omap24xxcam_capture_stop(cam);
+
+ if (vidioc_int_reset(cam->sdev) == 0) {
+ vidioc_int_init(cam->sdev);
+ } else {
+ /* Can't reset it by vidioc_int_reset. */
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_sensor_enable(cam);
+ }
+
+ omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+ return rval;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ if (!rval) {
+ mutex_lock(&ofh->vbq.vb_lock);
+ ofh->pix = f->fmt.pix;
+ mutex_unlock(&ofh->vbq.vb_lock);
+ }
+
+ memset(f, 0, sizeof(*f));
+ vidioc_g_fmt_vid_cap(file, fh, f);
+
+ return rval;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+ mutex_unlock(&cam->mutex);
+
+ rval = videobuf_reqbufs(&ofh->vbq, b);
+
+ /*
+ * Either videobuf_reqbufs failed or the buffers are not
+ * memory-mapped (which would need special attention).
+ */
+ if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+ goto out;
+
+ rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+ if (rval)
+ omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+ return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_buffer *vb;
+ int rval;
+
+videobuf_dqbuf_again:
+ rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+ if (rval)
+ goto out;
+
+ vb = ofh->vbq.bufs[b->index];
+
+ mutex_lock(&cam->mutex);
+ /* _needs_reset returns -EIO if reset is required. */
+ rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+ mutex_unlock(&cam->mutex);
+ if (rval == -EIO)
+ schedule_work(&cam->sensor_reset_work);
+ else
+ rval = 0;
+
+out:
+ /*
+ * This is a hack. We don't want to show -EIO to the user
+ * space. Requeue the buffer and try again if we're not doing
+ * this in non-blocking mode.
+ */
+ if (rval == -EIO) {
+ videobuf_qbuf(&ofh->vbq, b);
+ if (!(file->f_flags & O_NONBLOCK))
+ goto videobuf_dqbuf_again;
+ /*
+ * We don't have a videobuf_buffer now --- maybe next
+ * time...
+ */
+ rval = -EAGAIN;
+ }
+
+ return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ if (rval) {
+ dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+ goto out;
+ }
+
+ rval = videobuf_streamon(&ofh->vbq);
+ if (!rval) {
+ cam->streaming = file;
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct videobuf_queue *q = &ofh->vbq;
+ int rval;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_work_sync(&cam->sensor_reset_work);
+
+ rval = videobuf_streamoff(q);
+ if (!rval) {
+ mutex_lock(&cam->mutex);
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ rval = vidioc_int_queryctrl(cam->sdev, a);
+
+ return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_s_ctrl(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a) {
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_parm(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct omap24xxcam_fh *ofh = fh;
+ struct omap24xxcam_device *cam = ofh->cam;
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_s_parm(cam->sdev, a);
+ if (rval)
+ goto out;
+
+ rval = omap24xxcam_sensor_if_enable(cam);
+ /*
+ * Revert to old streaming parameters if enabling sensor
+ * interface with the new ones failed.
+ */
+ if (rval)
+ vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+ mutex_unlock(&cam->mutex);
+
+ return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming != file) {
+ mutex_unlock(&cam->mutex);
+ return POLLERR;
+ }
+ mutex_unlock(&cam->mutex);
+
+ mutex_lock(&fh->vbq.vb_lock);
+ if (list_empty(&fh->vbq.stream)) {
+ mutex_unlock(&fh->vbq.vb_lock);
+ return POLLERR;
+ }
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+ mutex_unlock(&fh->vbq.vb_lock);
+
+ poll_wait(file, &vb->done, wait);
+
+ if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_queue *vbq = &fh->vbq;
+ unsigned int first, last, size, i, j;
+ int err = 0;
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ mutex_unlock(&cam->mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&cam->mutex);
+ mutex_lock(&vbq->vb_lock);
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == vbq->bufs[first])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+ continue;
+ if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == vbq->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+ continue;
+ size += vbq->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+
+ size = 0;
+ for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) {
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+ for (j = 0; j < dma->sglen; j++) {
+ err = remap_pfn_range(
+ vma, vma->vm_start + size,
+ page_to_pfn(sg_page(&dma->sglist[j])),
+ sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+ if (err)
+ goto out;
+ size += sg_dma_len(&dma->sglist[j]);
+ }
+ }
+
+out:
+ mutex_unlock(&vbq->vb_lock);
+
+ return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ int rval;
+
+ /* let the video-buf mapper check arguments and set-up structures */
+ rval = videobuf_mmap_mapper(&fh->vbq, vma);
+ if (rval)
+ return rval;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* do mapping to our allocated buffers */
+ rval = omap24xxcam_mmap_buffers(file, vma);
+ /*
+ * In case of error, free vma->vm_private_data allocated by
+ * videobuf_mmap_mapper.
+ */
+ if (rval)
+ kfree(vma->vm_private_data);
+
+ return rval;
+}
+
+static int omap24xxcam_open(struct file *file)
+{
+ struct omap24xxcam_device *cam = omap24xxcam.priv;
+ struct omap24xxcam_fh *fh;
+ struct v4l2_format format;
+
+ if (!cam || !cam->vfd)
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cam->mutex);
+ if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+ mutex_unlock(&cam->mutex);
+ goto out_try_module_get;
+ }
+
+ if (atomic_inc_return(&cam->users) == 1) {
+ omap24xxcam_hwinit(cam);
+ if (omap24xxcam_sensor_enable(cam)) {
+ mutex_unlock(&cam->mutex);
+ goto out_omap24xxcam_sensor_enable;
+ }
+ }
+ mutex_unlock(&cam->mutex);
+
+ fh->cam = cam;
+ mutex_lock(&cam->mutex);
+ vidioc_int_g_fmt_cap(cam->sdev, &format);
+ mutex_unlock(&cam->mutex);
+ /* FIXME: how about fh->pix when there are more users? */
+ fh->pix = format.fmt.pix;
+
+ file->private_data = fh;
+
+ spin_lock_init(&fh->vbq_lock);
+
+ videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+ &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh, NULL);
+
+ return 0;
+
+out_omap24xxcam_sensor_enable:
+ omap24xxcam_poweron_reset(cam);
+ module_put(cam->sdev->module);
+
+out_try_module_get:
+ kfree(fh);
+
+ return -ENODEV;
+}
+
+static int omap24xxcam_release(struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ atomic_inc(&cam->reset_disable);
+
+ flush_work_sync(&cam->sensor_reset_work);
+
+ /* stop streaming capture */
+ videobuf_streamoff(&fh->vbq);
+
+ mutex_lock(&cam->mutex);
+ if (cam->streaming == file) {
+ cam->streaming = NULL;
+ mutex_unlock(&cam->mutex);
+ sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+ } else {
+ mutex_unlock(&cam->mutex);
+ }
+
+ atomic_dec(&cam->reset_disable);
+
+ omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+ /*
+ * Make sure the reset work we might have scheduled is not
+ * pending! It may be run *only* if we have users. (And it may
+ * not be scheduled anymore since streaming is already
+ * disabled.)
+ */
+ flush_work_sync(&cam->sensor_reset_work);
+
+ mutex_lock(&cam->mutex);
+ if (atomic_dec_return(&cam->users) == 0) {
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+ }
+ mutex_unlock(&cam->mutex);
+
+ file->private_data = NULL;
+
+ module_put(cam->sdev->module);
+ kfree(fh);
+
+ return 0;
+}
+
+static struct v4l2_file_operations omap24xxcam_fops = {
+ .ioctl = video_ioctl2,
+ .poll = omap24xxcam_poll,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_stop(cam);
+
+ omap24xxcam_sensor_disable(cam);
+ omap24xxcam_poweron_reset(cam);
+
+ return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (atomic_read(&cam->users) == 0)
+ return 0;
+
+ omap24xxcam_hwinit(cam);
+ omap24xxcam_sensor_enable(cam);
+
+ if (!atomic_read(&cam->reset_disable))
+ omap24xxcam_capture_cont(cam);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
+ .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_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .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_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+};
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+ struct video_device *vfd;
+ int rval;
+
+ /* We already have a slave. */
+ if (cam->sdev)
+ return -EBUSY;
+
+ cam->sdev = s;
+
+ if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+ dev_err(cam->dev, "could not register sysfs entry\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev, "could not allocate video device struct\n");
+ rval = -ENOMEM;
+ goto err;
+ }
+ vfd->release = video_device_release;
+
+ vfd->parent = cam->dev;
+
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->fops = &omap24xxcam_fops;
+ vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
+
+ omap24xxcam_hwinit(cam);
+
+ rval = omap24xxcam_sensor_init(cam);
+ if (rval)
+ goto err;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ dev_err(cam->dev, "could not register V4L device\n");
+ rval = -EBUSY;
+ goto err;
+ }
+
+ omap24xxcam_poweron_reset(cam);
+
+ dev_info(cam->dev, "registered device %s\n",
+ video_device_node_name(vfd));
+
+ return 0;
+
+err:
+ omap24xxcam_device_unregister(s);
+
+ return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+ struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+ omap24xxcam_sensor_exit(cam);
+
+ if (cam->vfd) {
+ if (!video_is_registered(cam->vfd)) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(cam->vfd);
+ } else {
+ /*
+ * The unregister function will release the
+ * video_device struct as well as
+ * unregistering it.
+ */
+ video_unregister_device(cam->vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ device_remove_file(cam->dev, &dev_attr_streaming);
+
+ cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+ .attach = omap24xxcam_device_register,
+ .detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+ .module = THIS_MODULE,
+ .name = CAM_NAME,
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &omap24xxcam_master
+ },
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __devinit omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct resource *mem;
+ int irq;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+
+ /*
+ * Impose a lower limit on the amount of memory allocated for
+ * capture. We require at least enough memory to double-buffer
+ * QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+ cam->capture_mem = capture_mem;
+
+ /* request the mem region for the camera registers */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(cam->dev, "no mem resource?\n");
+ goto err;
+ }
+ if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+ dev_err(cam->dev,
+ "cannot reserve camera register I/O region\n");
+ goto err;
+ }
+ cam->mmio_base_phys = mem->start;
+ cam->mmio_size = resource_size(mem);
+
+ /* map the region */
+ cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ if (!cam->mmio_base) {
+ dev_err(cam->dev, "cannot map camera register I/O region\n");
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(cam->dev, "no irq for camera?\n");
+ goto err;
+ }
+
+ /* install the interrupt service routine */
+ if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ dev_err(cam->dev,
+ "could not install interrupt service routine\n");
+ goto err;
+ }
+ cam->irq = irq;
+
+ if (omap24xxcam_clock_get(cam))
+ goto err;
+
+ INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+ mutex_init(&cam->mutex);
+ spin_lock_init(&cam->core_enable_disable_lock);
+
+ omap24xxcam_sgdma_init(&cam->sgdma,
+ cam->mmio_base + CAMDMA_REG_OFFSET,
+ omap24xxcam_stalled_dma_reset,
+ (unsigned long)cam);
+
+ omap24xxcam.priv = cam;
+
+ if (v4l2_int_device_register(&omap24xxcam))
+ goto err;
+
+ return 0;
+
+err:
+ omap24xxcam_remove(pdev);
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ if (!cam)
+ return 0;
+
+ if (omap24xxcam.priv != NULL)
+ v4l2_int_device_unregister(&omap24xxcam);
+ omap24xxcam.priv = NULL;
+
+ omap24xxcam_clock_put(cam);
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ if (cam->mmio_base) {
+ iounmap((void *)cam->mmio_base);
+ cam->mmio_base = 0;
+ }
+
+ if (cam->mmio_base_phys) {
+ release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base_phys = 0;
+ }
+
+ kfree(cam);
+
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#endif
+ .driver = {
+ .name = CAM_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(omap24xxcam_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(OMAP24XXCAM_VERSION);
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
+ "buffers (default 4800kiB)");
diff --git a/drivers/media/platform/omap24xxcam.h b/drivers/media/platform/omap24xxcam.h
new file mode 100644
index 000000000000..c4395956a493
--- /dev/null
+++ b/drivers/media/platform/omap24xxcam.h
@@ -0,0 +1,593 @@
+/*
+ * drivers/media/platform/omap24xxcam.h
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.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 OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+/*
+ *
+ * General driver related definitions.
+ *
+ */
+
+#define CAM_NAME "omap24xxcam"
+
+#define CAM_MCLK 96000000
+
+/* number of bytes transferred per DMA request */
+#define DMA_THRESHOLD 32
+
+/*
+ * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
+ * the camera DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS 4
+
+/*
+ * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
+ * be queued. (We don't have any overlay sglists now.)
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME)
+
+/*
+ *
+ * Register definitions.
+ *
+ */
+
+/* subsystem register block offsets */
+#define CC_REG_OFFSET 0x00000400
+#define CAMDMA_REG_OFFSET 0x00000800
+#define CAMMMU_REG_OFFSET 0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION 0x000
+#define CAM_SYSCONFIG 0x010
+#define CAM_SYSSTATUS 0x014
+#define CAM_IRQSTATUS 0x018
+#define CAM_GPO 0x040
+#define CAM_GPI 0x050
+
+/* define camera core register offsets */
+#define CC_REVISION 0x000
+#define CC_SYSCONFIG 0x010
+#define CC_SYSSTATUS 0x014
+#define CC_IRQSTATUS 0x018
+#define CC_IRQENABLE 0x01C
+#define CC_CTRL 0x040
+#define CC_CTRL_DMA 0x044
+#define CC_CTRL_XCLK 0x048
+#define CC_FIFODATA 0x04C
+#define CC_TEST 0x050
+#define CC_GENPAR 0x054
+#define CC_CCPFSCR 0x058
+#define CC_CCPFECR 0x05C
+#define CC_CCPLSCR 0x060
+#define CC_CCPLECR 0x064
+#define CC_CCPDFR 0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION 0x000
+#define CAMDMA_IRQSTATUS_L0 0x008
+#define CAMDMA_IRQSTATUS_L1 0x00C
+#define CAMDMA_IRQSTATUS_L2 0x010
+#define CAMDMA_IRQSTATUS_L3 0x014
+#define CAMDMA_IRQENABLE_L0 0x018
+#define CAMDMA_IRQENABLE_L1 0x01C
+#define CAMDMA_IRQENABLE_L2 0x020
+#define CAMDMA_IRQENABLE_L3 0x024
+#define CAMDMA_SYSSTATUS 0x028
+#define CAMDMA_OCP_SYSCONFIG 0x02C
+#define CAMDMA_CAPS_0 0x064
+#define CAMDMA_CAPS_2 0x06C
+#define CAMDMA_CAPS_3 0x070
+#define CAMDMA_CAPS_4 0x074
+#define CAMDMA_GCR 0x078
+#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION 0x000
+#define CAMMMU_SYSCONFIG 0x010
+#define CAMMMU_SYSSTATUS 0x014
+#define CAMMMU_IRQSTATUS 0x018
+#define CAMMMU_IRQENABLE 0x01C
+#define CAMMMU_WALKING_ST 0x040
+#define CAMMMU_CNTL 0x044
+#define CAMMMU_FAULT_AD 0x048
+#define CAMMMU_TTB 0x04C
+#define CAMMMU_LOCK 0x050
+#define CAMMMU_LD_TLB 0x054
+#define CAMMMU_CAM 0x058
+#define CAMMMU_RAM 0x05C
+#define CAMMMU_GFLUSH 0x060
+#define CAMMMU_FLUSH_ENTRY 0x064
+#define CAMMMU_READ_CAM 0x068
+#define CAMMMU_READ_RAM 0x06C
+#define CAMMMU_EMU_FAULT_AD 0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT 4
+#define CAM_REVISION_MINOR (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT 0
+
+#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAM_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
+#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
+#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
+#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
+#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
+
+#define CAM_GPO_CAM_S_P_EN (1 << 1)
+#define CAM_GPO_CAM_CCP_MODE (1 << 0)
+
+#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY (1 << 21)
+#define CAP_GPI_CAM_WAIT (1 << 20)
+#define CAP_GPI_CAM_S_DATA (1 << 17)
+#define CAP_GPI_CAM_S_CLK (1 << 16)
+#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT 3
+#define CAP_GPI_CAM_P_VS (1 << 2)
+#define CAP_GPI_CAM_P_HS (1 << 1)
+#define CAP_GPI_CAM_P_CLK (1 << 0)
+
+#define CC_REVISION_MAJOR (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT 4
+#define CC_REVISION_MINOR (15 << 0)
+#define CC_REVISION_MINOR_SHIFT 0
+
+#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CC_SYSCONFIG_SOFTRESET (1 << 1)
+#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CC_IRQSTATUS_FS_IRQ (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
+
+#define CC_IRQENABLE_FS_IRQ (1 << 19)
+#define CC_IRQENABLE_LE_IRQ (1 << 18)
+#define CC_IRQENABLE_LS_IRQ (1 << 17)
+#define CC_IRQENABLE_FE_IRQ (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
+
+#define CC_CTRL_CC_ONE_SHOT (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
+#define CC_CTRL_CC_RST (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
+#define CC_CTRL_CC_EN (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
+#define CC_CTRL_BT_CORRECT (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM (1 << 11)
+#define CC_CTRL_PAR_CLK_POL (1 << 10)
+#define CC_CTRL_NOBT_HS_POL (1 << 9)
+#define CC_CTRL_NOBT_VS_POL (1 << 8)
+#define CC_CTRL_PAR_MODE (7 << 1)
+#define CC_CTRL_PAR_MODE_SHIFT 1
+#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
+#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
+#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
+#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
+#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
+#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
+#define CC_CTRL_CCP_MODE (1 << 0)
+
+#define CC_CTRL_DMA_EN (1 << 8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
+
+#define CC_CTRL_XCLK_DIV (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
+#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
+#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
+#define CC_TEST_FIFO_LEVEL (0xFF << 8)
+#define CC_TEST_FIFO_LEVEL_SHIFT 8
+#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
+
+#define CC_GENPAR_FIFO_DEPTH (7 << 0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
+
+#define CC_CCPDFR_ALPHA (0xFF << 8)
+#define CC_CCPDFR_ALPHA_SHIFT 8
+#define CC_CCPDFR_DATAFORMAT (15 << 0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT 0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
+
+#define CAMDMA_REVISION_MAJOR (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT 4
+#define CAMDMA_REVISION_MINOR (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT 0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define CAMDMA_CCR_PREFETCH (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR (1 << 22)
+#define CAMDMA_CCR_SECURE (1 << 21)
+#define CAMDMA_CCR_BS (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
+#define CAMDMA_CCR_DST_AMODE (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
+#define CAMDMA_CCR_ENABLE (1 << 7)
+#define CAMDMA_CCR_PRIO (1 << 6)
+#define CAMDMA_CCR_FS (1 << 5)
+#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
+#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
+#define CAMDMA_CICR_PACKET_IE (1 << 7)
+#define CAMDMA_CICR_BLOCK_IE (1 << 5)
+#define CAMDMA_CICR_LAST_IE (1 << 4)
+#define CAMDMA_CICR_FRAME_IE (1 << 3)
+#define CAMDMA_CICR_HALF_IE (1 << 2)
+#define CAMDMA_CICR_DROP_IE (1 << 1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR (1 << 9)
+#define CAMDMA_CSR_TRANS_ERR (1 << 8)
+#define CAMDMA_CSR_PACKET (1 << 7)
+#define CAMDMA_CSR_SYNC (1 << 6)
+#define CAMDMA_CSR_BLOCK (1 << 5)
+#define CAMDMA_CSR_LAST (1 << 4)
+#define CAMDMA_CSR_FRAME (1 << 3)
+#define CAMDMA_CSR_HALF (1 << 2)
+#define CAMDMA_CSR_DROP (1 << 1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
+#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
+#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
+#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
+
+/*
+ *
+ * Declarations.
+ *
+ */
+
+/* forward declarations */
+struct omap24xxcam_sgdma;
+struct omap24xxcam_dma;
+
+typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
+ u32 status, void *arg);
+typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
+ u32 status, void *arg);
+
+struct channel_state {
+ dma_callback_t callback;
+ void *arg;
+};
+
+/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
+struct sgdma_state {
+ const struct scatterlist *sglist;
+ int sglen; /* number of sglist entries */
+ int next_sglist; /* index of next sglist entry to process */
+ unsigned int bytes_read; /* number of bytes read */
+ unsigned int len; /* total length of sglist (excluding
+ * bytes due to page alignment) */
+ int queued_sglist; /* number of sglist entries queued for DMA */
+ u32 csr; /* DMA return code */
+ sgdma_callback_t callback;
+ void *arg;
+};
+
+/* physical DMA channel management */
+struct omap24xxcam_dma {
+ spinlock_t lock; /* Lock for the whole structure. */
+
+ void __iomem *base; /* base address for dma controller */
+
+ /* While dma_stop!=0, an attempt to start a new DMA transfer will
+ * fail.
+ */
+ atomic_t dma_stop;
+ int free_dmach; /* number of dma channels free */
+ int next_dmach; /* index of next dma channel to use */
+ struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
+};
+
+/* scatter-gather DMA (scatterlist stuff) management */
+struct omap24xxcam_sgdma {
+ struct omap24xxcam_dma dma;
+
+ spinlock_t lock; /* Lock for the fields below. */
+ int free_sgdma; /* number of free sg dma slots */
+ int next_sgdma; /* index of next sg dma slot to use */
+ struct sgdma_state sg_state[NUM_SG_DMA];
+
+ /* Reset timer data */
+ struct timer_list reset_timer;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+ /*** mutex ***/
+ /*
+ * mutex serialises access to this structure. Also camera
+ * opening and releasing is synchronised by this.
+ */
+ struct mutex mutex;
+
+ /*** general driver state information ***/
+ atomic_t users;
+ /*
+ * Lock to serialise core enabling and disabling and access to
+ * sgdma_in_queue.
+ */
+ spinlock_t core_enable_disable_lock;
+ /*
+ * Number or sgdma requests in scatter-gather queue, protected
+ * by the lock above.
+ */
+ int sgdma_in_queue;
+ /*
+ * Sensor interface parameters: interface type, CC_CTRL
+ * register value and interface specific data.
+ */
+ int if_type;
+ union {
+ struct parallel {
+ u32 xclk;
+ } bt656;
+ } if_u;
+ u32 cc_ctrl;
+
+ /*** subsystem structures ***/
+ struct omap24xxcam_sgdma sgdma;
+
+ /*** hardware resources ***/
+ unsigned int irq;
+ void __iomem *mmio_base;
+ unsigned long mmio_base_phys;
+ unsigned long mmio_size;
+
+ /*** interfaces and device ***/
+ struct v4l2_int_device *sdev;
+ struct device *dev;
+ struct video_device *vfd;
+
+ /*** camera and sensor reset related stuff ***/
+ struct work_struct sensor_reset_work;
+ /*
+ * We're in the middle of a reset. Don't enable core if this
+ * is non-zero! This exists to help decisionmaking in a case
+ * where videobuf_qbuf is called while we are in the middle of
+ * a reset.
+ */
+ atomic_t in_reset;
+ /*
+ * Non-zero if we don't want any resets for now. Used to
+ * prevent reset work to run when we're about to stop
+ * streaming.
+ */
+ atomic_t reset_disable;
+
+ /*** video device parameters ***/
+ int capture_mem;
+
+ /*** camera module clocks ***/
+ struct clk *fck;
+ struct clk *ick;
+
+ /*** capture data ***/
+ /* file handle, if streaming is on */
+ struct file *streaming;
+};
+
+/* Per-file handle data. */
+struct omap24xxcam_fh {
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+ struct videobuf_queue vbq;
+ struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
+ atomic_t field_count; /* field counter for videobuf_buffer */
+ /* accessing cam here doesn't need serialisation: it's constant */
+ struct omap24xxcam_device *cam;
+};
+
+/*
+ *
+ * Register I/O functions.
+ *
+ */
+
+static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
+ u32 val)
+{
+ writel(val, base + offset);
+ return val;
+}
+
+static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 __iomem *addr = base + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+/* dma prototypes */
+
+void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma);
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
+
+/* sgdma prototypes */
+
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+ const struct scatterlist *sglist, int sglen,
+ int len, sgdma_callback_t callback, void *arg);
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+ void __iomem *base,
+ void (*reset_callback)(unsigned long data),
+ unsigned long reset_callback_data);
+void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
+
+#endif
diff --git a/drivers/media/video/omap3isp/Makefile b/drivers/media/platform/omap3isp/Makefile
index e8847e79e31a..e8847e79e31a 100644
--- a/drivers/media/video/omap3isp/Makefile
+++ b/drivers/media/platform/omap3isp/Makefile
diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h
new file mode 100644
index 000000000000..c84df0706f3e
--- /dev/null
+++ b/drivers/media/platform/omap3isp/cfa_coef_table.h
@@ -0,0 +1,61 @@
+/*
+ * cfa_coef_table.h
+ *
+ * TI OMAP3 ISP - CFA coefficients table
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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
+ */
+
+{ 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
+247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
+244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
+247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
+244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
+247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248 },
+{ 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
+ 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
+ 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
+ 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
+ 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
+ 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
+ 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
+ 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
+ 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0 },
+{ 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
+ 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
+ 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
+ 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
+ 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
+ 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
+ 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
+ 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
+ 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0 },
+{ 244,12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
+250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
+244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
+250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
+244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
+248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
+250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248 },
diff --git a/drivers/media/video/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h
index 78deebf7d965..78deebf7d965 100644
--- a/drivers/media/video/omap3isp/gamma_table.h
+++ b/drivers/media/platform/omap3isp/gamma_table.h
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
new file mode 100644
index 000000000000..e0096e07dbdc
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -0,0 +1,2241 @@
+/*
+ * isp.c
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * Contributors:
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ * David Cohen <dacohen@gmail.com>
+ * Stanimir Varbanov <svarbanov@mm-sol.com>
+ * Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
+ * Tuukka Toivonen <tuukkat76@gmail.com>
+ * Sergio Aguirre <saaguirre@ti.com>
+ * Antti Koskipaa <akoskipa@gmail.com>
+ * Ivan T. Ivanov <iivanov@mm-sol.com>
+ * RaniSuneela <r-m@ti.com>
+ * Atanas Filipov <afilipov@mm-sol.com>
+ * Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
+ * Hiroshi DOYU <hiroshi.doyu@nokia.com>
+ * Nayden Kanchev <nkanchev@mm-sol.com>
+ * Phil Carmody <ext-phil.2.carmody@nokia.com>
+ * Artem Bityutskiy <artem.bityutskiy@nokia.com>
+ * Dominic Curran <dcurran@ti.com>
+ * Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
+ * Pallavi Kulkarni <p-kulkarni@ti.com>
+ * Vaibhav Hiremath <hvaibhav@ti.com>
+ * Mohit Jalori <mjalori@ti.com>
+ * Sameer Venkatraman <sameerv@ti.com>
+ * Senthilvadivu Guruswamy <svadivu@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ * Toni Leinonen <toni.leinonen@nokia.com>
+ * Troy Laramy <t-laramy@ti.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 <asm/cacheflush.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+#include "isppreview.h"
+#include "ispresizer.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+#include "isph3a.h"
+#include "isphist.h"
+
+static unsigned int autoidle;
+module_param(autoidle, int, 0444);
+MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
+
+static void isp_save_ctx(struct isp_device *isp);
+
+static void isp_restore_ctx(struct isp_device *isp);
+
+static const struct isp_res_mapping isp_res_maps[] = {
+ {
+ .isp_rev = ISP_REVISION_2_0,
+ .map = 1 << OMAP3_ISP_IOMEM_MAIN |
+ 1 << OMAP3_ISP_IOMEM_CCP2 |
+ 1 << OMAP3_ISP_IOMEM_CCDC |
+ 1 << OMAP3_ISP_IOMEM_HIST |
+ 1 << OMAP3_ISP_IOMEM_H3A |
+ 1 << OMAP3_ISP_IOMEM_PREV |
+ 1 << OMAP3_ISP_IOMEM_RESZ |
+ 1 << OMAP3_ISP_IOMEM_SBL |
+ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+ 1 << OMAP3_ISP_IOMEM_CSIPHY2,
+ },
+ {
+ .isp_rev = ISP_REVISION_15_0,
+ .map = 1 << OMAP3_ISP_IOMEM_MAIN |
+ 1 << OMAP3_ISP_IOMEM_CCP2 |
+ 1 << OMAP3_ISP_IOMEM_CCDC |
+ 1 << OMAP3_ISP_IOMEM_HIST |
+ 1 << OMAP3_ISP_IOMEM_H3A |
+ 1 << OMAP3_ISP_IOMEM_PREV |
+ 1 << OMAP3_ISP_IOMEM_RESZ |
+ 1 << OMAP3_ISP_IOMEM_SBL |
+ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+ 1 << OMAP3_ISP_IOMEM_CSIPHY2 |
+ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
+ 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
+ 1 << OMAP3_ISP_IOMEM_CSIPHY1 |
+ 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2,
+ },
+};
+
+/* Structure for saving/restoring ISP module registers */
+static struct isp_reg isp_reg_list[] = {
+ {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
+ {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0},
+ {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0},
+ {0, ISP_TOK_TERM, 0}
+};
+
+/*
+ * omap3isp_flush - Post pending L3 bus writes by doing a register readback
+ * @isp: OMAP3 ISP device
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ */
+void omap3isp_flush(struct isp_device *isp)
+{
+ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+}
+
+/*
+ * isp_enable_interrupts - Enable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_enable_interrupts(struct isp_device *isp)
+{
+ static const u32 irq = IRQ0ENABLE_CSIA_IRQ
+ | IRQ0ENABLE_CSIB_IRQ
+ | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ
+ | IRQ0ENABLE_CCDC_LSC_DONE_IRQ
+ | IRQ0ENABLE_CCDC_VD0_IRQ
+ | IRQ0ENABLE_CCDC_VD1_IRQ
+ | IRQ0ENABLE_HS_VS_IRQ
+ | IRQ0ENABLE_HIST_DONE_IRQ
+ | IRQ0ENABLE_H3A_AWB_DONE_IRQ
+ | IRQ0ENABLE_H3A_AF_DONE_IRQ
+ | IRQ0ENABLE_PRV_DONE_IRQ
+ | IRQ0ENABLE_RSZ_DONE_IRQ;
+
+ isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/*
+ * isp_disable_interrupts - Disable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_interrupts(struct isp_device *isp)
+{
+ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/**
+ * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @isp: OMAP3 ISP device
+ * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
+ * @xclksel: XCLK to configure (0 = A, 1 = B).
+ *
+ * Configures the specified MCLK divisor in the ISP timing control register
+ * (TCTRL_CTRL) to generate the desired xclk clock value.
+ *
+ * Divisor = cam_mclk_hz / xclk
+ *
+ * Returns the final frequency that is actually being generated
+ **/
+static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
+{
+ u32 divisor;
+ u32 currentxclk;
+ unsigned long mclk_hz;
+
+ if (!omap3isp_get(isp))
+ return 0;
+
+ mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+
+ if (xclk >= mclk_hz) {
+ divisor = ISPTCTRL_CTRL_DIV_BYPASS;
+ currentxclk = mclk_hz;
+ } else if (xclk >= 2) {
+ divisor = mclk_hz / xclk;
+ if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
+ divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+ currentxclk = mclk_hz / divisor;
+ } else {
+ divisor = xclk;
+ currentxclk = 0;
+ }
+
+ switch (xclksel) {
+ case ISP_XCLK_A:
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ ISPTCTRL_CTRL_DIVA_MASK,
+ divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
+ dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
+ currentxclk);
+ break;
+ case ISP_XCLK_B:
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ ISPTCTRL_CTRL_DIVB_MASK,
+ divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
+ dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
+ currentxclk);
+ break;
+ case ISP_XCLK_NONE:
+ default:
+ omap3isp_put(isp);
+ dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
+ "xclk. Must be 0 (A) or 1 (B).\n");
+ return -EINVAL;
+ }
+
+ /* Do we go from stable whatever to clock? */
+ if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
+ omap3isp_get(isp);
+ /* Stopping the clock. */
+ else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
+ omap3isp_put(isp);
+
+ isp->xclk_divisor[xclksel - 1] = divisor;
+
+ omap3isp_put(isp);
+
+ return currentxclk;
+}
+
+/*
+ * isp_core_init - ISP core settings
+ * @isp: OMAP3 ISP device
+ * @idle: Consider idle state.
+ *
+ * Set the power settings for the ISP and SBL bus and cConfigure the HS/VS
+ * interrupt source.
+ *
+ * We need to configure the HS/VS interrupt source before interrupts get
+ * enabled, as the sensor might be free-running and the ISP default setting
+ * (HS edge) would put an unnecessary burden on the CPU.
+ */
+static void isp_core_init(struct isp_device *isp, int idle)
+{
+ isp_reg_writel(isp,
+ ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
+ ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) <<
+ ISP_SYSCONFIG_MIDLEMODE_SHIFT) |
+ ((isp->revision == ISP_REVISION_15_0) ?
+ ISP_SYSCONFIG_AUTOIDLE : 0),
+ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+
+ isp_reg_writel(isp,
+ (isp->autoidle ? ISPCTRL_SBL_AUTOIDLE : 0) |
+ ISPCTRL_SYNC_DETECT_VSRISE,
+ OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+}
+
+/*
+ * Configure the bridge and lane shifter. Valid inputs are
+ *
+ * CCDC_INPUT_PARALLEL: Parallel interface
+ * CCDC_INPUT_CSI2A: CSI2a receiver
+ * CCDC_INPUT_CCP2B: CCP2b receiver
+ * CCDC_INPUT_CSI2C: CSI2c receiver
+ *
+ * The bridge and lane shifter are configured according to the selected input
+ * and the ISP platform data.
+ */
+void omap3isp_configure_bridge(struct isp_device *isp,
+ enum ccdc_input_entity input,
+ const struct isp_parallel_platform_data *pdata,
+ unsigned int shift, unsigned int bridge)
+{
+ u32 ispctrl_val;
+
+ ispctrl_val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ ispctrl_val &= ~ISPCTRL_SHIFT_MASK;
+ ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
+ ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
+ ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
+ ispctrl_val |= bridge;
+
+ switch (input) {
+ case CCDC_INPUT_PARALLEL:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
+ ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
+ shift += pdata->data_lane_shift * 2;
+ break;
+
+ case CCDC_INPUT_CSI2A:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA;
+ break;
+
+ case CCDC_INPUT_CCP2B:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
+ break;
+
+ case CCDC_INPUT_CSI2C:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC;
+ break;
+
+ default:
+ return;
+ }
+
+ ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
+
+ isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+}
+
+void omap3isp_hist_dma_done(struct isp_device *isp)
+{
+ if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
+ omap3isp_stat_pcr_busy(&isp->isp_hist)) {
+ /* Histogram cannot be enabled in this frame anymore */
+ atomic_set(&isp->isp_hist.buf_err, 1);
+ dev_dbg(isp->dev, "hist: Out of synchronization with "
+ "CCDC. Ignoring next buffer.\n");
+ }
+}
+
+static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
+{
+ static const char *name[] = {
+ "CSIA_IRQ",
+ "res1",
+ "res2",
+ "CSIB_LCM_IRQ",
+ "CSIB_IRQ",
+ "res5",
+ "res6",
+ "res7",
+ "CCDC_VD0_IRQ",
+ "CCDC_VD1_IRQ",
+ "CCDC_VD2_IRQ",
+ "CCDC_ERR_IRQ",
+ "H3A_AF_DONE_IRQ",
+ "H3A_AWB_DONE_IRQ",
+ "res14",
+ "res15",
+ "HIST_DONE_IRQ",
+ "CCDC_LSC_DONE",
+ "CCDC_LSC_PREFETCH_COMPLETED",
+ "CCDC_LSC_PREFETCH_ERROR",
+ "PRV_DONE_IRQ",
+ "CBUFF_IRQ",
+ "res22",
+ "res23",
+ "RSZ_DONE_IRQ",
+ "OVF_IRQ",
+ "res26",
+ "res27",
+ "MMU_ERR_IRQ",
+ "OCP_ERR_IRQ",
+ "SEC_ERR_IRQ",
+ "HS_VS_IRQ",
+ };
+ int i;
+
+ dev_dbg(isp->dev, "ISP IRQ: ");
+
+ for (i = 0; i < ARRAY_SIZE(name); i++) {
+ if ((1 << i) & irqstatus)
+ printk(KERN_CONT "%s ", name[i]);
+ }
+ printk(KERN_CONT "\n");
+}
+
+static void isp_isr_sbl(struct isp_device *isp)
+{
+ struct device *dev = isp->dev;
+ struct isp_pipeline *pipe;
+ u32 sbl_pcr;
+
+ /*
+ * Handle shared buffer logic overflows for video buffers.
+ * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
+ */
+ sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+ isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+ sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
+
+ if (sbl_pcr)
+ dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
+
+ 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) {
+ 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)) {
+ 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);
+
+ if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF)
+ omap3isp_stat_sbl_overflow(&isp->isp_aewb);
+}
+
+/*
+ * isp_isr - Interrupt Service Routine for Camera ISP module.
+ * @irq: Not used currently.
+ * @_isp: Pointer to the OMAP3 ISP device
+ *
+ * Handles the corresponding callback if plugged in.
+ *
+ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
+ * IRQ wasn't handled.
+ */
+static irqreturn_t isp_isr(int irq, void *_isp)
+{
+ static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ |
+ IRQ0STATUS_CCDC_LSC_DONE_IRQ |
+ IRQ0STATUS_CCDC_VD0_IRQ |
+ IRQ0STATUS_CCDC_VD1_IRQ |
+ IRQ0STATUS_HS_VS_IRQ;
+ struct isp_device *isp = _isp;
+ u32 irqstatus;
+
+ 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)
+ omap3isp_csi2_isr(&isp->isp_csi2a);
+
+ 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)
+ omap3isp_preview_isr_frame_sync(&isp->isp_prev);
+ if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
+ omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+ omap3isp_stat_isr_frame_sync(&isp->isp_aewb);
+ omap3isp_stat_isr_frame_sync(&isp->isp_af);
+ omap3isp_stat_isr_frame_sync(&isp->isp_hist);
+ }
+
+ if (irqstatus & ccdc_events)
+ omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events);
+
+ if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) {
+ if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER)
+ omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+ omap3isp_preview_isr(&isp->isp_prev);
+ }
+
+ if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ)
+ omap3isp_resizer_isr(&isp->isp_res);
+
+ if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ)
+ omap3isp_stat_isr(&isp->isp_aewb);
+
+ if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ)
+ omap3isp_stat_isr(&isp->isp_af);
+
+ if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ)
+ omap3isp_stat_isr(&isp->isp_hist);
+
+ omap3isp_flush(isp);
+
+#if defined(DEBUG) && defined(ISP_ISR_DEBUG)
+ isp_isr_dbg(isp, irqstatus);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline power management
+ *
+ * Entities must be powered up when part of a pipeline that contains at least
+ * one open video device node.
+ *
+ * To achieve this use the entity use_count field to track the number of users.
+ * For entities corresponding to video device nodes the use_count field stores
+ * the users count of the node. For entities corresponding to subdevs the
+ * use_count field stores the total number of users of all video device nodes
+ * in the pipeline.
+ *
+ * The omap3isp_pipeline_pm_use() function must be called in the open() and
+ * close() handlers of video device nodes. It increments or decrements the use
+ * count of all subdev entities in the pipeline.
+ *
+ * To react to link management on powered pipelines, the link setup notification
+ * callback updates the use count of all entities in the source and sink sides
+ * of the link.
+ */
+
+/*
+ * isp_pipeline_pm_use_count - Count the number of users of a pipeline
+ * @entity: The entity
+ *
+ * Return the total number of users of all video device nodes in the pipeline.
+ */
+static int isp_pipeline_pm_use_count(struct media_entity *entity)
+{
+ struct media_entity_graph graph;
+ int use = 0;
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ use += entity->use_count;
+ }
+
+ return use;
+}
+
+/*
+ * isp_pipeline_pm_power_one - Apply power change to an entity
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Change the entity use count by @change. If the entity is a subdev update its
+ * power state by calling the core::s_power operation when the use count goes
+ * from 0 to != 0 or from != 0 to 0.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
+{
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+ ? media_entity_to_v4l2_subdev(entity) : NULL;
+
+ if (entity->use_count == 0 && change > 0 && subdev != NULL) {
+ ret = v4l2_subdev_call(subdev, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ entity->use_count += change;
+ WARN_ON(entity->use_count < 0);
+
+ if (entity->use_count == 0 && change < 0 && subdev != NULL)
+ v4l2_subdev_call(subdev, core, s_power, 0);
+
+ return 0;
+}
+
+/*
+ * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Walk the pipeline to update the use count and the power state of all non-node
+ * entities.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power(struct media_entity *entity, int change)
+{
+ struct media_entity_graph graph;
+ struct media_entity *first = entity;
+ int ret = 0;
+
+ if (!change)
+ return 0;
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+ if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ ret = isp_pipeline_pm_power_one(entity, change);
+
+ if (!ret)
+ return 0;
+
+ media_entity_graph_walk_start(&graph, first);
+
+ while ((first = media_entity_graph_walk_next(&graph))
+ && first != entity)
+ if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+ isp_pipeline_pm_power_one(first, -change);
+
+ return ret;
+}
+
+/*
+ * omap3isp_pipeline_pm_use - Update the use count of an entity
+ * @entity: The entity
+ * @use: Use (1) or stop using (0) the entity
+ *
+ * Update the use count of all entities in the pipeline and power entities on or
+ * off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. No failure can occur when the use parameter is
+ * set to 0.
+ */
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
+{
+ int change = use ? 1 : -1;
+ int ret;
+
+ mutex_lock(&entity->parent->graph_mutex);
+
+ /* Apply use count to node. */
+ entity->use_count += change;
+ WARN_ON(entity->use_count < 0);
+
+ /* Apply power change to connected non-nodes. */
+ ret = isp_pipeline_pm_power(entity, change);
+ if (ret < 0)
+ entity->use_count -= change;
+
+ mutex_unlock(&entity->parent->graph_mutex);
+
+ return ret;
+}
+
+/*
+ * isp_pipeline_link_notify - Link management notification callback
+ * @source: Pad at the start of the link
+ * @sink: Pad at the end of the link
+ * @flags: New link flags that will be applied
+ *
+ * React to link management on powered pipelines by updating the use count of
+ * all entities in the source and sink sides of the link. Entities are powered
+ * on or off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. This function will not fail for disconnection
+ * events.
+ */
+static int isp_pipeline_link_notify(struct media_pad *source,
+ struct media_pad *sink, u32 flags)
+{
+ int source_use = isp_pipeline_pm_use_count(source->entity);
+ int sink_use = isp_pipeline_pm_use_count(sink->entity);
+ int ret;
+
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ /* Powering off entities is assumed to never fail. */
+ isp_pipeline_pm_power(source->entity, -sink_use);
+ isp_pipeline_pm_power(sink->entity, -source_use);
+ return 0;
+ }
+
+ ret = isp_pipeline_pm_power(source->entity, sink_use);
+ if (ret < 0)
+ return ret;
+
+ ret = isp_pipeline_pm_power(sink->entity, source_use);
+ if (ret < 0)
+ isp_pipeline_pm_power(source->entity, -sink_use);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline stream management
+ */
+
+/*
+ * isp_pipeline_enable - Enable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @mode: Stream mode (single shot or continuous)
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int isp_pipeline_enable(struct isp_pipeline *pipe,
+ enum isp_pipeline_stream_state mode)
+{
+ struct isp_device *isp = pipe->output->isp;
+ struct media_entity *entity;
+ struct media_pad *pad;
+ struct v4l2_subdev *subdev;
+ unsigned long flags;
+ int ret;
+
+ /* If the preview engine crashed it might not respond to read/write
+ * operations on the L4 bus. This would result in a bus fault and a
+ * kernel oops. Refuse to start streaming in that case. This check must
+ * be performed before the loop below to avoid starting entities if the
+ * pipeline won't start anyway (those entities would then likely fail to
+ * stop, making the problem worse).
+ */
+ if ((pipe->entities & isp->crashed) &
+ (1U << isp->isp_prev.subdev.entity.id))
+ return -EIO;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ pipe->do_propagation = false;
+
+ entity = &pipe->output->video.entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ if (subdev == &isp->isp_ccdc.subdev) {
+ v4l2_subdev_call(&isp->isp_aewb.subdev, video,
+ s_stream, mode);
+ v4l2_subdev_call(&isp->isp_af.subdev, video,
+ s_stream, mode);
+ v4l2_subdev_call(&isp->isp_hist.subdev, video,
+ s_stream, mode);
+ pipe->do_propagation = true;
+ }
+ }
+
+ return 0;
+}
+
+static int isp_pipeline_wait_resizer(struct isp_device *isp)
+{
+ return omap3isp_resizer_busy(&isp->isp_res);
+}
+
+static int isp_pipeline_wait_preview(struct isp_device *isp)
+{
+ return omap3isp_preview_busy(&isp->isp_prev);
+}
+
+static int isp_pipeline_wait_ccdc(struct isp_device *isp)
+{
+ return omap3isp_stat_busy(&isp->isp_af)
+ || omap3isp_stat_busy(&isp->isp_aewb)
+ || omap3isp_stat_busy(&isp->isp_hist)
+ || omap3isp_ccdc_busy(&isp->isp_ccdc);
+}
+
+#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000)
+
+static int isp_pipeline_wait(struct isp_device *isp,
+ int(*busy)(struct isp_device *isp))
+{
+ unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
+
+ while (!time_after(jiffies, timeout)) {
+ if (!busy(isp))
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * isp_pipeline_disable - Disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
+ *
+ * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
+ * can't be stopped (in which case a software reset of the ISP is probably
+ * necessary).
+ */
+static int isp_pipeline_disable(struct isp_pipeline *pipe)
+{
+ struct isp_device *isp = pipe->output->isp;
+ struct media_entity *entity;
+ struct media_pad *pad;
+ struct v4l2_subdev *subdev;
+ int failure = 0;
+ int ret;
+
+ /*
+ * We need to stop all the modules after CCDC first or they'll
+ * never stop since they may not get a full frame from CCDC.
+ */
+ entity = &pipe->output->video.entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ if (subdev == &isp->isp_ccdc.subdev) {
+ v4l2_subdev_call(&isp->isp_aewb.subdev,
+ video, s_stream, 0);
+ v4l2_subdev_call(&isp->isp_af.subdev,
+ video, s_stream, 0);
+ v4l2_subdev_call(&isp->isp_hist.subdev,
+ video, s_stream, 0);
+ }
+
+ v4l2_subdev_call(subdev, video, s_stream, 0);
+
+ if (subdev == &isp->isp_res.subdev)
+ ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+ else if (subdev == &isp->isp_prev.subdev)
+ ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+ else if (subdev == &isp->isp_ccdc.subdev)
+ ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
+ else
+ ret = 0;
+
+ if (ret) {
+ dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
+ /* If the entity failed to stopped, assume it has
+ * crashed. Mark it as such, the ISP will be reset when
+ * applications will release it.
+ */
+ isp->crashed |= 1U << subdev->entity.id;
+ failure = -ETIMEDOUT;
+ }
+ }
+
+ return failure;
+}
+
+/*
+ * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @state: Stream state (stopped, single shot or continuous)
+ *
+ * Set the pipeline to the given stream state. Pipelines can be started in
+ * single-shot or continuous mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. The pipeline state is not updated when the operation
+ * fails, except when stopping the pipeline.
+ */
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+ enum isp_pipeline_stream_state state)
+{
+ int ret;
+
+ if (state == ISP_PIPELINE_STREAM_STOPPED)
+ ret = isp_pipeline_disable(pipe);
+ else
+ ret = isp_pipeline_enable(pipe, state);
+
+ if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED)
+ pipe->stream_state = state;
+
+ return ret;
+}
+
+/*
+ * isp_pipeline_resume - Resume streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Resume video output and input and re-enable pipeline.
+ */
+static void isp_pipeline_resume(struct isp_pipeline *pipe)
+{
+ int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT;
+
+ omap3isp_video_resume(pipe->output, !singleshot);
+ if (singleshot)
+ omap3isp_video_resume(pipe->input, 0);
+ isp_pipeline_enable(pipe, pipe->stream_state);
+}
+
+/*
+ * isp_pipeline_suspend - Suspend streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Suspend pipeline.
+ */
+static void isp_pipeline_suspend(struct isp_pipeline *pipe)
+{
+ isp_pipeline_disable(pipe);
+}
+
+/*
+ * isp_pipeline_is_last - Verify if entity has an enabled link to the output
+ * video node
+ * @me: ISP module's media entity
+ *
+ * Returns 1 if the entity has an enabled link to the output video node or 0
+ * otherwise. It's true only while pipeline can have no more than one output
+ * node.
+ */
+static int isp_pipeline_is_last(struct media_entity *me)
+{
+ struct isp_pipeline *pipe;
+ struct media_pad *pad;
+
+ if (!me->pipe)
+ return 0;
+ pipe = to_isp_pipeline(me);
+ if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+ pad = media_entity_remote_source(&pipe->output->pad);
+ return pad->entity == me;
+}
+
+/*
+ * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Suspend the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_suspend_module_pipeline(struct media_entity *me)
+{
+ if (isp_pipeline_is_last(me))
+ isp_pipeline_suspend(to_isp_pipeline(me));
+}
+
+/*
+ * isp_resume_module_pipeline - Resume pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Resume the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_resume_module_pipeline(struct media_entity *me)
+{
+ if (isp_pipeline_is_last(me))
+ isp_pipeline_resume(to_isp_pipeline(me));
+}
+
+/*
+ * isp_suspend_modules - Suspend ISP submodules.
+ * @isp: OMAP3 ISP device
+ *
+ * Returns 0 if suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to suspend the submodules.
+ */
+static int isp_suspend_modules(struct isp_device *isp)
+{
+ unsigned long timeout;
+
+ omap3isp_stat_suspend(&isp->isp_aewb);
+ omap3isp_stat_suspend(&isp->isp_af);
+ omap3isp_stat_suspend(&isp->isp_hist);
+ isp_suspend_module_pipeline(&isp->isp_res.subdev.entity);
+ isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity);
+ isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity);
+ isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity);
+ isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity);
+
+ timeout = jiffies + ISP_STOP_TIMEOUT;
+ while (omap3isp_stat_busy(&isp->isp_af)
+ || omap3isp_stat_busy(&isp->isp_aewb)
+ || omap3isp_stat_busy(&isp->isp_hist)
+ || omap3isp_preview_busy(&isp->isp_prev)
+ || omap3isp_resizer_busy(&isp->isp_res)
+ || omap3isp_ccdc_busy(&isp->isp_ccdc)) {
+ if (time_after(jiffies, timeout)) {
+ dev_info(isp->dev, "can't stop modules.\n");
+ return 1;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * isp_resume_modules - Resume ISP submodules.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_resume_modules(struct isp_device *isp)
+{
+ omap3isp_stat_resume(&isp->isp_aewb);
+ omap3isp_stat_resume(&isp->isp_af);
+ omap3isp_stat_resume(&isp->isp_hist);
+ isp_resume_module_pipeline(&isp->isp_res.subdev.entity);
+ isp_resume_module_pipeline(&isp->isp_prev.subdev.entity);
+ isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity);
+ isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity);
+ isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity);
+}
+
+/*
+ * isp_reset - Reset ISP with a timeout wait for idle.
+ * @isp: OMAP3 ISP device
+ */
+static int isp_reset(struct isp_device *isp)
+{
+ unsigned long timeout = 0;
+
+ isp_reg_writel(isp,
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
+ | ISP_SYSCONFIG_SOFTRESET,
+ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+ while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN,
+ ISP_SYSSTATUS) & 0x1)) {
+ if (timeout++ > 10000) {
+ dev_alert(isp->dev, "cannot reset ISP\n");
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ isp->crashed = 0;
+ return 0;
+}
+
+/*
+ * isp_save_context - Saves the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ * modify on OMAP.
+ */
+static void
+isp_save_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+ struct isp_reg *next = reg_list;
+
+ for (; next->reg != ISP_TOK_TERM; next++)
+ next->val = isp_reg_readl(isp, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_restore_context - Restores the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ * modify on OMAP.
+ */
+static void
+isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+ struct isp_reg *next = reg_list;
+
+ for (; next->reg != ISP_TOK_TERM; next++)
+ isp_reg_writel(isp, next->val, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for saving the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_save_ctx(struct isp_device *isp)
+{
+ isp_save_context(isp, isp_reg_list);
+ omap_iommu_save_ctx(isp->dev);
+}
+
+/*
+ * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for restoring the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_restore_ctx(struct isp_device *isp)
+{
+ isp_restore_context(isp, isp_reg_list);
+ omap_iommu_restore_ctx(isp->dev);
+ omap3isp_ccdc_restore_context(isp);
+ omap3isp_preview_restore_context(isp);
+}
+
+/* -----------------------------------------------------------------------------
+ * SBL resources management
+ */
+#define OMAP3_ISP_SBL_READ (OMAP3_ISP_SBL_CSI1_READ | \
+ OMAP3_ISP_SBL_CCDC_LSC_READ | \
+ OMAP3_ISP_SBL_PREVIEW_READ | \
+ OMAP3_ISP_SBL_RESIZER_READ)
+#define OMAP3_ISP_SBL_WRITE (OMAP3_ISP_SBL_CSI1_WRITE | \
+ OMAP3_ISP_SBL_CSI2A_WRITE | \
+ OMAP3_ISP_SBL_CSI2C_WRITE | \
+ OMAP3_ISP_SBL_CCDC_WRITE | \
+ OMAP3_ISP_SBL_PREVIEW_WRITE)
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+ u32 sbl = 0;
+
+ isp->sbl_resources |= res;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)
+ sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)
+ sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)
+ sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)
+ sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE)
+ sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+ if (isp->sbl_resources & OMAP3_ISP_SBL_READ)
+ sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+ u32 sbl = 0;
+
+ isp->sbl_resources &= ~res;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ))
+ sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ))
+ sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE))
+ sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE))
+ sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE))
+ sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+ if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ))
+ sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+/*
+ * isp_module_sync_idle - Helper to sync module with its idle state
+ * @me: ISP submodule's media entity
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule needs to wait for next interrupt. If
+ * yes, makes the caller to sleep while waiting for such event.
+ */
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+ atomic_t *stopping)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(me);
+
+ if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED ||
+ (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+ !isp_pipeline_ready(pipe)))
+ return 0;
+
+ /*
+ * atomic_set() doesn't include memory barrier on ARM platform for SMP
+ * scenario. We'll call it here to avoid race conditions.
+ */
+ atomic_set(stopping, 1);
+ smp_mb();
+
+ /*
+ * If module is the last one, it's writing to memory. In this case,
+ * it's necessary to check if the module is already paused due to
+ * DMA queue underrun or if it has to wait for next interrupt to be
+ * idle.
+ * If it isn't the last one, the function won't sleep but *stopping
+ * will still be set to warn next submodule caller's interrupt the
+ * module wants to be idle.
+ */
+ if (isp_pipeline_is_last(me)) {
+ struct isp_video *video = pipe->output;
+ unsigned long flags;
+ spin_lock_irqsave(&video->queue->irqlock, flags);
+ if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+ spin_unlock_irqrestore(&video->queue->irqlock, flags);
+ atomic_set(stopping, 0);
+ smp_mb();
+ return 0;
+ }
+ spin_unlock_irqrestore(&video->queue->irqlock, flags);
+ if (!wait_event_timeout(*wait, !atomic_read(stopping),
+ msecs_to_jiffies(1000))) {
+ atomic_set(stopping, 0);
+ smp_mb();
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule was stopping. In case of yes, it
+ * notices the caller by setting stopping to 0 and waking up the wait queue.
+ * Returns 1 if it was stopping or 0 otherwise.
+ */
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+ atomic_t *stopping)
+{
+ if (atomic_cmpxchg(stopping, 1, 0)) {
+ wake_up(wait);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Clock management
+ */
+
+#define ISPCTRL_CLKS_MASK (ISPCTRL_H3A_CLK_EN | \
+ ISPCTRL_HIST_CLK_EN | \
+ ISPCTRL_RSZ_CLK_EN | \
+ (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \
+ (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN))
+
+static void __isp_subclk_update(struct isp_device *isp)
+{
+ u32 clk = 0;
+
+ /* AEWB and AF share the same clock. */
+ if (isp->subclk_resources &
+ (OMAP3_ISP_SUBCLK_AEWB | OMAP3_ISP_SUBCLK_AF))
+ clk |= ISPCTRL_H3A_CLK_EN;
+
+ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
+ clk |= ISPCTRL_HIST_CLK_EN;
+
+ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER)
+ clk |= ISPCTRL_RSZ_CLK_EN;
+
+ /* NOTE: For CCDC & Preview submodules, we need to affect internal
+ * RAM as well.
+ */
+ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
+ clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
+
+ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW)
+ clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN;
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+ ISPCTRL_CLKS_MASK, clk);
+}
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+ enum isp_subclk_resource res)
+{
+ isp->subclk_resources |= res;
+
+ __isp_subclk_update(isp);
+}
+
+void omap3isp_subclk_disable(struct isp_device *isp,
+ enum isp_subclk_resource res)
+{
+ isp->subclk_resources &= ~res;
+
+ __isp_subclk_update(isp);
+}
+
+/*
+ * isp_enable_clocks - Enable ISP clocks
+ * @isp: OMAP3 ISP device
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ */
+static int isp_enable_clocks(struct isp_device *isp)
+{
+ int r;
+ unsigned long rate;
+ int divisor;
+
+ /*
+ * cam_mclk clock chain:
+ * dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk
+ *
+ * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are
+ * set to the same value. Hence the rate set for dpll4_m5
+ * has to be twice of what is set on OMAP3430 to get
+ * the required value for cam_mclk
+ */
+ if (cpu_is_omap3630())
+ divisor = 1;
+ else
+ divisor = 2;
+
+ r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]);
+ if (r) {
+ dev_err(isp->dev, "clk_enable cam_ick failed\n");
+ goto out_clk_enable_ick;
+ }
+ r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK],
+ CM_CAM_MCLK_HZ/divisor);
+ if (r) {
+ dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n");
+ goto out_clk_enable_mclk;
+ }
+ r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]);
+ if (r) {
+ dev_err(isp->dev, "clk_enable cam_mclk failed\n");
+ goto out_clk_enable_mclk;
+ }
+ rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+ if (rate != CM_CAM_MCLK_HZ)
+ dev_warn(isp->dev, "unexpected cam_mclk rate:\n"
+ " expected : %d\n"
+ " actual : %ld\n", CM_CAM_MCLK_HZ, rate);
+ r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]);
+ if (r) {
+ dev_err(isp->dev, "clk_enable csi2_fck failed\n");
+ goto out_clk_enable_csi2_fclk;
+ }
+ return 0;
+
+out_clk_enable_csi2_fclk:
+ clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+out_clk_enable_mclk:
+ clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+out_clk_enable_ick:
+ return r;
+}
+
+/*
+ * isp_disable_clocks - Disable ISP clocks
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_clocks(struct isp_device *isp)
+{
+ clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+ clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+ clk_disable(isp->clock[ISP_CLK_CSI2_FCK]);
+}
+
+static const char *isp_clocks[] = {
+ "cam_ick",
+ "cam_mclk",
+ "dpll4_m5_ck",
+ "csi2_96m_fck",
+ "l3_ick",
+};
+
+static void isp_put_clocks(struct isp_device *isp)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+ if (isp->clock[i]) {
+ clk_put(isp->clock[i]);
+ isp->clock[i] = NULL;
+ }
+ }
+}
+
+static int isp_get_clocks(struct isp_device *isp)
+{
+ struct clk *clk;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+ clk = clk_get(isp->dev, isp_clocks[i]);
+ if (IS_ERR(clk)) {
+ dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
+ isp_put_clocks(isp);
+ return PTR_ERR(clk);
+ }
+
+ isp->clock[i] = clk;
+ }
+
+ return 0;
+}
+
+/*
+ * omap3isp_get - Acquire the ISP resource.
+ *
+ * Initializes the clocks for the first acquire.
+ *
+ * Increment the reference count on the ISP. If the first reference is taken,
+ * enable clocks and power-up all submodules.
+ *
+ * Return a pointer to the ISP device structure, or NULL if an error occurred.
+ */
+static struct isp_device *__omap3isp_get(struct isp_device *isp, bool irq)
+{
+ struct isp_device *__isp = isp;
+
+ if (isp == NULL)
+ return NULL;
+
+ mutex_lock(&isp->isp_mutex);
+ if (isp->ref_count > 0)
+ goto out;
+
+ if (isp_enable_clocks(isp) < 0) {
+ __isp = NULL;
+ goto out;
+ }
+
+ /* We don't want to restore context before saving it! */
+ if (isp->has_context)
+ isp_restore_ctx(isp);
+
+ if (irq)
+ isp_enable_interrupts(isp);
+
+out:
+ if (__isp != NULL)
+ isp->ref_count++;
+ mutex_unlock(&isp->isp_mutex);
+
+ return __isp;
+}
+
+struct isp_device *omap3isp_get(struct isp_device *isp)
+{
+ return __omap3isp_get(isp, true);
+}
+
+/*
+ * omap3isp_put - Release the ISP
+ *
+ * Decrement the reference count on the ISP. If the last reference is released,
+ * power-down all submodules, disable clocks and free temporary buffers.
+ */
+void omap3isp_put(struct isp_device *isp)
+{
+ if (isp == NULL)
+ return;
+
+ mutex_lock(&isp->isp_mutex);
+ BUG_ON(isp->ref_count == 0);
+ if (--isp->ref_count == 0) {
+ isp_disable_interrupts(isp);
+ if (isp->domain) {
+ isp_save_ctx(isp);
+ isp->has_context = 1;
+ }
+ /* Reset the ISP if an entity has failed to stop. This is the
+ * only way to recover from such conditions.
+ */
+ if (isp->crashed)
+ isp_reset(isp);
+ isp_disable_clocks(isp);
+ }
+ mutex_unlock(&isp->isp_mutex);
+}
+
+/* --------------------------------------------------------------------------
+ * Platform device driver
+ */
+
+/*
+ * omap3isp_print_status - Prints the values of the ISP Control Module registers
+ * @isp: OMAP3 ISP device
+ */
+#define ISP_PRINT_REGISTER(isp, name)\
+ dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name))
+#define SBL_PRINT_REGISTER(isp, name)\
+ dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name))
+
+void omap3isp_print_status(struct isp_device *isp)
+{
+ dev_dbg(isp->dev, "-------------ISP Register dump--------------\n");
+
+ ISP_PRINT_REGISTER(isp, SYSCONFIG);
+ ISP_PRINT_REGISTER(isp, SYSSTATUS);
+ ISP_PRINT_REGISTER(isp, IRQ0ENABLE);
+ ISP_PRINT_REGISTER(isp, IRQ0STATUS);
+ ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH);
+ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY);
+ ISP_PRINT_REGISTER(isp, CTRL);
+ ISP_PRINT_REGISTER(isp, TCTRL_CTRL);
+ ISP_PRINT_REGISTER(isp, TCTRL_FRAME);
+ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY);
+ ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY);
+ ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY);
+ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH);
+ ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH);
+ ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH);
+
+ SBL_PRINT_REGISTER(isp, PCR);
+ SBL_PRINT_REGISTER(isp, SDR_REQ_EXP);
+
+ dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Power management support.
+ *
+ * As the ISP can't properly handle an input video stream interruption on a non
+ * frame boundary, the ISP pipelines need to be stopped before sensors get
+ * suspended. However, as suspending the sensors can require a running clock,
+ * which can be provided by the ISP, the ISP can't be completely suspended
+ * before the sensor.
+ *
+ * To solve this problem power management support is split into prepare/complete
+ * and suspend/resume operations. The pipelines are stopped in prepare() and the
+ * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in
+ * resume(), and the the pipelines are restarted in complete().
+ *
+ * TODO: PM dependencies between the ISP and sensors are not modeled explicitly
+ * yet.
+ */
+static int isp_pm_prepare(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ int reset;
+
+ WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+ if (isp->ref_count == 0)
+ return 0;
+
+ reset = isp_suspend_modules(isp);
+ isp_disable_interrupts(isp);
+ isp_save_ctx(isp);
+ if (reset)
+ isp_reset(isp);
+
+ return 0;
+}
+
+static int isp_pm_suspend(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+ if (isp->ref_count)
+ isp_disable_clocks(isp);
+
+ return 0;
+}
+
+static int isp_pm_resume(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ if (isp->ref_count == 0)
+ return 0;
+
+ return isp_enable_clocks(isp);
+}
+
+static void isp_pm_complete(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ if (isp->ref_count == 0)
+ return;
+
+ isp_restore_ctx(isp);
+ isp_enable_interrupts(isp);
+ isp_resume_modules(isp);
+}
+
+#else
+
+#define isp_pm_prepare NULL
+#define isp_pm_suspend NULL
+#define isp_pm_resume NULL
+#define isp_pm_complete NULL
+
+#endif /* CONFIG_PM */
+
+static void isp_unregister_entities(struct isp_device *isp)
+{
+ omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
+ omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
+ omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
+ omap3isp_preview_unregister_entities(&isp->isp_prev);
+ omap3isp_resizer_unregister_entities(&isp->isp_res);
+ omap3isp_stat_unregister_entities(&isp->isp_aewb);
+ omap3isp_stat_unregister_entities(&isp->isp_af);
+ omap3isp_stat_unregister_entities(&isp->isp_hist);
+
+ v4l2_device_unregister(&isp->v4l2_dev);
+ media_device_unregister(&isp->media_dev);
+}
+
+/*
+ * isp_register_subdev_group - Register a group of subdevices
+ * @isp: OMAP3 ISP device
+ * @board_info: I2C subdevs board information array
+ *
+ * Register all I2C subdevices in the board_info array. The array must be
+ * terminated by a NULL entry, and the first entry must be the sensor.
+ *
+ * Return a pointer to the sensor media entity if it has been successfully
+ * registered, or NULL otherwise.
+ */
+static struct v4l2_subdev *
+isp_register_subdev_group(struct isp_device *isp,
+ struct isp_subdev_i2c_board_info *board_info)
+{
+ struct v4l2_subdev *sensor = NULL;
+ unsigned int first;
+
+ if (board_info->board_info == NULL)
+ return NULL;
+
+ for (first = 1; board_info->board_info; ++board_info, first = 0) {
+ struct v4l2_subdev *subdev;
+ struct i2c_adapter *adapter;
+
+ adapter = i2c_get_adapter(board_info->i2c_adapter_id);
+ if (adapter == NULL) {
+ printk(KERN_ERR "%s: Unable to get I2C adapter %d for "
+ "device %s\n", __func__,
+ board_info->i2c_adapter_id,
+ board_info->board_info->type);
+ continue;
+ }
+
+ subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
+ board_info->board_info, NULL);
+ if (subdev == NULL) {
+ printk(KERN_ERR "%s: Unable to register subdev %s\n",
+ __func__, board_info->board_info->type);
+ continue;
+ }
+
+ if (first)
+ sensor = subdev;
+ }
+
+ return sensor;
+}
+
+static int isp_register_entities(struct isp_device *isp)
+{
+ struct isp_platform_data *pdata = isp->pdata;
+ struct isp_v4l2_subdevs_group *subdevs;
+ int ret;
+
+ isp->media_dev.dev = isp->dev;
+ strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
+ sizeof(isp->media_dev.model));
+ isp->media_dev.hw_revision = isp->revision;
+ isp->media_dev.link_notify = isp_pipeline_link_notify;
+ ret = media_device_register(&isp->media_dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: Media device registration failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ isp->v4l2_dev.mdev = &isp->media_dev;
+ ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
+ __func__, ret);
+ goto done;
+ }
+
+ /* Register internal entities */
+ ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_preview_register_entities(&isp->isp_prev,
+ &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ /* Register external entities */
+ for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
+ struct v4l2_subdev *sensor;
+ struct media_entity *input;
+ unsigned int flags;
+ unsigned int pad;
+
+ sensor = isp_register_subdev_group(isp, subdevs->subdevs);
+ if (sensor == NULL)
+ continue;
+
+ sensor->host_priv = subdevs;
+
+ /* Connect the sensor to the correct interface module. Parallel
+ * sensors are connected directly to the CCDC, while serial
+ * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
+ * through CSIPHY1 or CSIPHY2.
+ */
+ switch (subdevs->interface) {
+ case ISP_INTERFACE_PARALLEL:
+ input = &isp->isp_ccdc.subdev.entity;
+ pad = CCDC_PAD_SINK;
+ flags = 0;
+ break;
+
+ case ISP_INTERFACE_CSI2A_PHY2:
+ input = &isp->isp_csi2a.subdev.entity;
+ pad = CSI2_PAD_SINK;
+ flags = MEDIA_LNK_FL_IMMUTABLE
+ | MEDIA_LNK_FL_ENABLED;
+ break;
+
+ case ISP_INTERFACE_CCP2B_PHY1:
+ case ISP_INTERFACE_CCP2B_PHY2:
+ input = &isp->isp_ccp2.subdev.entity;
+ pad = CCP2_PAD_SINK;
+ flags = 0;
+ break;
+
+ case ISP_INTERFACE_CSI2C_PHY1:
+ input = &isp->isp_csi2c.subdev.entity;
+ pad = CSI2_PAD_SINK;
+ flags = MEDIA_LNK_FL_IMMUTABLE
+ | MEDIA_LNK_FL_ENABLED;
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid interface type %u\n",
+ __func__, subdevs->interface);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = media_entity_create_link(&sensor->entity, 0, input, pad,
+ flags);
+ if (ret < 0)
+ goto done;
+ }
+
+ ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+
+done:
+ if (ret < 0)
+ isp_unregister_entities(isp);
+
+ return ret;
+}
+
+static void isp_cleanup_modules(struct isp_device *isp)
+{
+ omap3isp_h3a_aewb_cleanup(isp);
+ omap3isp_h3a_af_cleanup(isp);
+ omap3isp_hist_cleanup(isp);
+ omap3isp_resizer_cleanup(isp);
+ omap3isp_preview_cleanup(isp);
+ omap3isp_ccdc_cleanup(isp);
+ omap3isp_ccp2_cleanup(isp);
+ omap3isp_csi2_cleanup(isp);
+}
+
+static int isp_initialize_modules(struct isp_device *isp)
+{
+ int ret;
+
+ ret = omap3isp_csiphy_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "CSI PHY initialization failed\n");
+ goto error_csiphy;
+ }
+
+ ret = omap3isp_csi2_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "CSI2 initialization failed\n");
+ goto error_csi2;
+ }
+
+ ret = omap3isp_ccp2_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "CCP2 initialization failed\n");
+ goto error_ccp2;
+ }
+
+ ret = omap3isp_ccdc_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "CCDC initialization failed\n");
+ goto error_ccdc;
+ }
+
+ ret = omap3isp_preview_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "Preview initialization failed\n");
+ goto error_preview;
+ }
+
+ ret = omap3isp_resizer_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "Resizer initialization failed\n");
+ goto error_resizer;
+ }
+
+ ret = omap3isp_hist_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "Histogram initialization failed\n");
+ goto error_hist;
+ }
+
+ ret = omap3isp_h3a_aewb_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "H3A AEWB initialization failed\n");
+ goto error_h3a_aewb;
+ }
+
+ ret = omap3isp_h3a_af_init(isp);
+ if (ret < 0) {
+ dev_err(isp->dev, "H3A AF initialization failed\n");
+ goto error_h3a_af;
+ }
+
+ /* Connect the submodules. */
+ ret = media_entity_create_link(
+ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_aewb.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_af.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_hist.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ goto error_link;
+
+ return 0;
+
+error_link:
+ omap3isp_h3a_af_cleanup(isp);
+error_h3a_af:
+ omap3isp_h3a_aewb_cleanup(isp);
+error_h3a_aewb:
+ omap3isp_hist_cleanup(isp);
+error_hist:
+ omap3isp_resizer_cleanup(isp);
+error_resizer:
+ omap3isp_preview_cleanup(isp);
+error_preview:
+ omap3isp_ccdc_cleanup(isp);
+error_ccdc:
+ omap3isp_ccp2_cleanup(isp);
+error_ccp2:
+ omap3isp_csi2_cleanup(isp);
+error_csi2:
+error_csiphy:
+ return ret;
+}
+
+/*
+ * isp_remove - Remove ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Always returns 0.
+ */
+static int __devexit isp_remove(struct platform_device *pdev)
+{
+ struct isp_device *isp = platform_get_drvdata(pdev);
+ int i;
+
+ isp_unregister_entities(isp);
+ isp_cleanup_modules(isp);
+
+ __omap3isp_get(isp, false);
+ iommu_detach_device(isp->domain, &pdev->dev);
+ iommu_domain_free(isp->domain);
+ isp->domain = NULL;
+ omap3isp_put(isp);
+
+ free_irq(isp->irq_num, isp);
+ isp_put_clocks(isp);
+
+ for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+ if (isp->mmio_base[i]) {
+ iounmap(isp->mmio_base[i]);
+ isp->mmio_base[i] = NULL;
+ }
+
+ if (isp->mmio_base_phys[i]) {
+ release_mem_region(isp->mmio_base_phys[i],
+ isp->mmio_size[i]);
+ isp->mmio_base_phys[i] = 0;
+ }
+ }
+
+ regulator_put(isp->isp_csiphy1.vdd);
+ regulator_put(isp->isp_csiphy2.vdd);
+ kfree(isp);
+
+ return 0;
+}
+
+static int isp_map_mem_resource(struct platform_device *pdev,
+ struct isp_device *isp,
+ enum isp_mem_resources res)
+{
+ struct resource *mem;
+
+ /* request the mem region for the camera registers */
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
+ if (!mem) {
+ dev_err(isp->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+ dev_err(isp->dev,
+ "cannot reserve camera register I/O region\n");
+ return -ENODEV;
+ }
+ isp->mmio_base_phys[res] = mem->start;
+ isp->mmio_size[res] = resource_size(mem);
+
+ /* map the region */
+ isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
+ isp->mmio_size[res]);
+ if (!isp->mmio_base[res]) {
+ dev_err(isp->dev, "cannot map camera register I/O region\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Returns 0 if successful,
+ * -ENOMEM if no memory available,
+ * -ENODEV if no platform device resources found
+ * or no space for remapping registers,
+ * -EINVAL if couldn't install ISR,
+ * or clk_get return error value.
+ */
+static int __devinit isp_probe(struct platform_device *pdev)
+{
+ struct isp_platform_data *pdata = pdev->dev.platform_data;
+ struct isp_device *isp;
+ int ret;
+ int i, m;
+
+ if (pdata == NULL)
+ return -EINVAL;
+
+ isp = kzalloc(sizeof(*isp), GFP_KERNEL);
+ if (!isp) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ return -ENOMEM;
+ }
+
+ isp->autoidle = autoidle;
+ isp->platform_cb.set_xclk = isp_set_xclk;
+
+ mutex_init(&isp->isp_mutex);
+ spin_lock_init(&isp->stat_lock);
+
+ isp->dev = &pdev->dev;
+ isp->pdata = pdata;
+ isp->ref_count = 0;
+
+ isp->raw_dmamask = DMA_BIT_MASK(32);
+ isp->dev->dma_mask = &isp->raw_dmamask;
+ isp->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ platform_set_drvdata(pdev, isp);
+
+ /* Regulators */
+ isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
+ isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
+
+ /* Clocks */
+ ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
+ if (ret < 0)
+ goto error;
+
+ ret = isp_get_clocks(isp);
+ if (ret < 0)
+ goto error;
+
+ if (__omap3isp_get(isp, false) == NULL)
+ goto error;
+
+ ret = isp_reset(isp);
+ if (ret < 0)
+ goto error_isp;
+
+ /* Memory resources */
+ isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+ dev_info(isp->dev, "Revision %d.%d found\n",
+ (isp->revision & 0xf0) >> 4, isp->revision & 0x0f);
+
+ for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
+ if (isp->revision == isp_res_maps[m].isp_rev)
+ break;
+
+ if (m == ARRAY_SIZE(isp_res_maps)) {
+ dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n",
+ (isp->revision & 0xf0) >> 4, isp->revision & 0xf);
+ ret = -ENODEV;
+ goto error_isp;
+ }
+
+ for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
+ if (isp_res_maps[m].map & 1 << i) {
+ ret = isp_map_mem_resource(pdev, isp, i);
+ if (ret)
+ goto error_isp;
+ }
+ }
+
+ isp->domain = iommu_domain_alloc(pdev->dev.bus);
+ if (!isp->domain) {
+ dev_err(isp->dev, "can't alloc iommu domain\n");
+ ret = -ENOMEM;
+ goto error_isp;
+ }
+
+ ret = iommu_attach_device(isp->domain, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
+ goto free_domain;
+ }
+
+ /* Interrupt */
+ isp->irq_num = platform_get_irq(pdev, 0);
+ if (isp->irq_num <= 0) {
+ dev_err(isp->dev, "No IRQ resource\n");
+ ret = -ENODEV;
+ goto detach_dev;
+ }
+
+ if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
+ dev_err(isp->dev, "Unable to request IRQ\n");
+ ret = -EINVAL;
+ goto detach_dev;
+ }
+
+ /* Entities */
+ ret = isp_initialize_modules(isp);
+ if (ret < 0)
+ goto error_irq;
+
+ ret = isp_register_entities(isp);
+ if (ret < 0)
+ goto error_modules;
+
+ isp_core_init(isp, 1);
+ omap3isp_put(isp);
+
+ return 0;
+
+error_modules:
+ isp_cleanup_modules(isp);
+error_irq:
+ free_irq(isp->irq_num, isp);
+detach_dev:
+ iommu_detach_device(isp->domain, &pdev->dev);
+free_domain:
+ iommu_domain_free(isp->domain);
+error_isp:
+ omap3isp_put(isp);
+error:
+ isp_put_clocks(isp);
+
+ for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+ if (isp->mmio_base[i]) {
+ iounmap(isp->mmio_base[i]);
+ isp->mmio_base[i] = NULL;
+ }
+
+ if (isp->mmio_base_phys[i]) {
+ release_mem_region(isp->mmio_base_phys[i],
+ isp->mmio_size[i]);
+ isp->mmio_base_phys[i] = 0;
+ }
+ }
+ regulator_put(isp->isp_csiphy2.vdd);
+ regulator_put(isp->isp_csiphy1.vdd);
+ platform_set_drvdata(pdev, NULL);
+
+ mutex_destroy(&isp->isp_mutex);
+ kfree(isp);
+
+ return ret;
+}
+
+static const struct dev_pm_ops omap3isp_pm_ops = {
+ .prepare = isp_pm_prepare,
+ .suspend = isp_pm_suspend,
+ .resume = isp_pm_resume,
+ .complete = isp_pm_complete,
+};
+
+static struct platform_device_id omap3isp_id_table[] = {
+ { "omap3isp", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
+
+static struct platform_driver omap3isp_driver = {
+ .probe = isp_probe,
+ .remove = __devexit_p(isp_remove),
+ .id_table = omap3isp_id_table,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "omap3isp",
+ .pm = &omap3isp_pm_ops,
+ },
+};
+
+module_platform_driver(omap3isp_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("TI OMAP3 ISP driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION);
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
new file mode 100644
index 000000000000..8be7487c326f
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -0,0 +1,352 @@
+/*
+ * isp.h
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 OMAP3_ISP_CORE_H
+#define OMAP3_ISP_CORE_H
+
+#include <media/omap3isp.h>
+#include <media/v4l2-device.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/iommu.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+
+#include "ispstat.h"
+#include "ispccdc.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+#include "isppreview.h"
+#include "ispcsiphy.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+#define ISP_TOK_TERM 0xFFFFFFFF /*
+ * terminating token for ISP
+ * modules reg list
+ */
+#define to_isp_device(ptr_module) \
+ container_of(ptr_module, struct isp_device, isp_##ptr_module)
+#define to_device(ptr_module) \
+ (to_isp_device(ptr_module)->dev)
+
+enum isp_mem_resources {
+ OMAP3_ISP_IOMEM_MAIN,
+ OMAP3_ISP_IOMEM_CCP2,
+ OMAP3_ISP_IOMEM_CCDC,
+ OMAP3_ISP_IOMEM_HIST,
+ OMAP3_ISP_IOMEM_H3A,
+ OMAP3_ISP_IOMEM_PREV,
+ OMAP3_ISP_IOMEM_RESZ,
+ OMAP3_ISP_IOMEM_SBL,
+ OMAP3_ISP_IOMEM_CSI2A_REGS1,
+ OMAP3_ISP_IOMEM_CSIPHY2,
+ OMAP3_ISP_IOMEM_CSI2A_REGS2,
+ OMAP3_ISP_IOMEM_CSI2C_REGS1,
+ OMAP3_ISP_IOMEM_CSIPHY1,
+ OMAP3_ISP_IOMEM_CSI2C_REGS2,
+ OMAP3_ISP_IOMEM_LAST
+};
+
+enum isp_sbl_resource {
+ OMAP3_ISP_SBL_CSI1_READ = 0x1,
+ OMAP3_ISP_SBL_CSI1_WRITE = 0x2,
+ OMAP3_ISP_SBL_CSI2A_WRITE = 0x4,
+ OMAP3_ISP_SBL_CSI2C_WRITE = 0x8,
+ OMAP3_ISP_SBL_CCDC_LSC_READ = 0x10,
+ OMAP3_ISP_SBL_CCDC_WRITE = 0x20,
+ OMAP3_ISP_SBL_PREVIEW_READ = 0x40,
+ OMAP3_ISP_SBL_PREVIEW_WRITE = 0x80,
+ OMAP3_ISP_SBL_RESIZER_READ = 0x100,
+ OMAP3_ISP_SBL_RESIZER_WRITE = 0x200,
+};
+
+enum isp_subclk_resource {
+ OMAP3_ISP_SUBCLK_CCDC = (1 << 0),
+ OMAP3_ISP_SUBCLK_AEWB = (1 << 1),
+ OMAP3_ISP_SUBCLK_AF = (1 << 2),
+ OMAP3_ISP_SUBCLK_HIST = (1 << 3),
+ OMAP3_ISP_SUBCLK_PREVIEW = (1 << 4),
+ OMAP3_ISP_SUBCLK_RESIZER = (1 << 5),
+};
+
+/* ISP: OMAP 34xx ES 1.0 */
+#define ISP_REVISION_1_0 0x10
+/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */
+#define ISP_REVISION_2_0 0x20
+/* ISP2P: OMAP 36xx */
+#define ISP_REVISION_15_0 0xF0
+
+/*
+ * struct isp_res_mapping - Map ISP io resources to ISP revision.
+ * @isp_rev: ISP_REVISION_x_x
+ * @map: bitmap for enum isp_mem_resources
+ */
+struct isp_res_mapping {
+ u32 isp_rev;
+ u32 map;
+};
+
+/*
+ * struct isp_reg - Structure for ISP register values.
+ * @reg: 32-bit Register address.
+ * @val: 32-bit Register value.
+ */
+struct isp_reg {
+ enum isp_mem_resources mmio_range;
+ u32 reg;
+ u32 val;
+};
+
+struct isp_platform_callback {
+ u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
+ int (*csiphy_config)(struct isp_csiphy *phy,
+ struct isp_csiphy_dphy_cfg *dphy,
+ struct isp_csiphy_lanes_cfg *lanes);
+};
+
+/*
+ * struct isp_device - ISP device structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @revision: Stores current ISP module revision.
+ * @irq_num: Currently used IRQ number.
+ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
+ * regions.
+ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
+ * regions.
+ * @mmio_size: Array with ISP register regions size in bytes.
+ * @raw_dmamask: Raw DMA mask
+ * @stat_lock: Spinlock for handling statistics
+ * @isp_mutex: Mutex for serializing requests to ISP.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ * @has_context: Context has been saved at least once and can be restored.
+ * @ref_count: Reference count for handling multiple ISP requests.
+ * @cam_ick: Pointer to camera interface clock structure.
+ * @cam_mclk: Pointer to camera functional clock structure.
+ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
+ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @irq: Currently attached ISP ISR callbacks information structure.
+ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
+ * White Balance SCM.
+ * @isp_res: Pointer to current settings for ISP Resizer.
+ * @isp_prev: Pointer to current settings for ISP Preview.
+ * @isp_ccdc: Pointer to current settings for ISP CCDC.
+ * @iommu: Pointer to requested IOMMU instance for ISP.
+ * @platform_cb: ISP driver callback function pointers for platform code
+ *
+ * This structure is used to store the OMAP ISP Information.
+ */
+struct isp_device {
+ struct v4l2_device v4l2_dev;
+ struct media_device media_dev;
+ struct device *dev;
+ u32 revision;
+
+ /* platform HW resources */
+ struct isp_platform_data *pdata;
+ unsigned int irq_num;
+
+ void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
+ unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
+ resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
+
+ u64 raw_dmamask;
+
+ /* ISP Obj */
+ spinlock_t stat_lock; /* common lock for statistic drivers */
+ struct mutex isp_mutex; /* For handling ref_count field */
+ u32 crashed;
+ int has_context;
+ int ref_count;
+ unsigned int autoidle;
+ u32 xclk_divisor[2]; /* Two clocks, a and b. */
+#define ISP_CLK_CAM_ICK 0
+#define ISP_CLK_CAM_MCLK 1
+#define ISP_CLK_DPLL4_M5_CK 2
+#define ISP_CLK_CSI2_FCK 3
+#define ISP_CLK_L3_ICK 4
+ struct clk *clock[5];
+
+ /* ISP modules */
+ struct ispstat isp_af;
+ struct ispstat isp_aewb;
+ struct ispstat isp_hist;
+ struct isp_res_device isp_res;
+ struct isp_prev_device isp_prev;
+ struct isp_ccdc_device isp_ccdc;
+ struct isp_csi2_device isp_csi2a;
+ struct isp_csi2_device isp_csi2c;
+ struct isp_ccp2_device isp_ccp2;
+ struct isp_csiphy isp_csiphy1;
+ struct isp_csiphy isp_csiphy2;
+
+ unsigned int sbl_resources;
+ unsigned int subclk_resources;
+
+ struct iommu_domain *domain;
+
+ struct isp_platform_callback platform_cb;
+};
+
+#define v4l2_dev_to_isp_device(dev) \
+ container_of(dev, struct isp_device, v4l2_dev)
+
+void omap3isp_hist_dma_done(struct isp_device *isp);
+
+void omap3isp_flush(struct isp_device *isp);
+
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+ atomic_t *stopping);
+
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+ atomic_t *stopping);
+
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+ enum isp_pipeline_stream_state state);
+void omap3isp_configure_bridge(struct isp_device *isp,
+ enum ccdc_input_entity input,
+ const struct isp_parallel_platform_data *pdata,
+ unsigned int shift, unsigned int bridge);
+
+struct isp_device *omap3isp_get(struct isp_device *isp);
+void omap3isp_put(struct isp_device *isp);
+
+void omap3isp_print_status(struct isp_device *isp);
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res);
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res);
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+ enum isp_subclk_resource res);
+void omap3isp_subclk_disable(struct isp_device *isp,
+ enum isp_subclk_resource res);
+
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
+
+int omap3isp_register_entities(struct platform_device *pdev,
+ struct v4l2_device *v4l2_dev);
+void omap3isp_unregister_entities(struct platform_device *pdev);
+
+/*
+ * isp_reg_readl - Read value of an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to read from.
+ *
+ * Returns an unsigned 32 bit value with the required register contents.
+ */
+static inline
+u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
+ u32 reg_offset)
+{
+ return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_writel - Write value to an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @reg_value: 32 bit value to write to the register.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to write into.
+ */
+static inline
+void isp_reg_writel(struct isp_device *isp, u32 reg_value,
+ enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+{
+ __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_and - Clear individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ */
+static inline
+void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
+ u32 reg, u32 clr_bits)
+{
+ u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+ isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_set - Set individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @set_bits: 32 bit value which would be set in the register.
+ */
+static inline
+void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+ u32 reg, u32 set_bits)
+{
+ u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+ isp_reg_writel(isp, v | set_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ * @set_bits: 32 bit value which would be set in the register.
+ *
+ * The clear operation is done first, and then the set operation.
+ */
+static inline
+void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+ u32 reg, u32 clr_bits, u32 set_bits)
+{
+ u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+ isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg);
+}
+
+static inline enum v4l2_buf_type
+isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad)
+{
+ if (pad >= subdev->entity.num_pads)
+ return 0;
+
+ if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK)
+ return V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ else
+ return V4L2_BUF_TYPE_VIDEO_CAPTURE;
+}
+
+#endif /* OMAP3_ISP_CORE_H */
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
new file mode 100644
index 000000000000..aa9df9d71a7b
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -0,0 +1,2583 @@
+/*
+ * ispccdc.c
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/v4l2-event.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+
+#define CCDC_MIN_WIDTH 32
+#define CCDC_MIN_HEIGHT 32
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which);
+
+static const unsigned int ccdc_fmts[] = {
+ V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y12_1X12,
+ V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_MBUS_FMT_SGRBG10_1X10,
+ V4L2_MBUS_FMT_SRGGB10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_SGBRG10_1X10,
+ V4L2_MBUS_FMT_SGRBG12_1X12,
+ V4L2_MBUS_FMT_SRGGB12_1X12,
+ V4L2_MBUS_FMT_SBGGR12_1X12,
+ V4L2_MBUS_FMT_SGBRG12_1X12,
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+/*
+ * ccdc_print_status - Print current CCDC Module register values.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Also prints other debug information stored in the CCDC module.
+ */
+#define CCDC_PRINT_REGISTER(isp, name)\
+ dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
+
+static void ccdc_print_status(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
+
+ CCDC_PRINT_REGISTER(isp, PCR);
+ CCDC_PRINT_REGISTER(isp, SYN_MODE);
+ CCDC_PRINT_REGISTER(isp, HD_VD_WID);
+ CCDC_PRINT_REGISTER(isp, PIX_LINES);
+ CCDC_PRINT_REGISTER(isp, HORZ_INFO);
+ CCDC_PRINT_REGISTER(isp, VERT_START);
+ CCDC_PRINT_REGISTER(isp, VERT_LINES);
+ CCDC_PRINT_REGISTER(isp, CULLING);
+ CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
+ CCDC_PRINT_REGISTER(isp, SDOFST);
+ CCDC_PRINT_REGISTER(isp, SDR_ADDR);
+ CCDC_PRINT_REGISTER(isp, CLAMP);
+ CCDC_PRINT_REGISTER(isp, DCSUB);
+ CCDC_PRINT_REGISTER(isp, COLPTN);
+ CCDC_PRINT_REGISTER(isp, BLKCMP);
+ CCDC_PRINT_REGISTER(isp, FPC);
+ CCDC_PRINT_REGISTER(isp, FPC_ADDR);
+ CCDC_PRINT_REGISTER(isp, VDINT);
+ CCDC_PRINT_REGISTER(isp, ALAW);
+ CCDC_PRINT_REGISTER(isp, REC656IF);
+ CCDC_PRINT_REGISTER(isp, CFG);
+ CCDC_PRINT_REGISTER(isp, FMTCFG);
+ CCDC_PRINT_REGISTER(isp, FMT_HORZ);
+ CCDC_PRINT_REGISTER(isp, FMT_VERT);
+ CCDC_PRINT_REGISTER(isp, PRGEVEN0);
+ CCDC_PRINT_REGISTER(isp, PRGEVEN1);
+ CCDC_PRINT_REGISTER(isp, PRGODD0);
+ CCDC_PRINT_REGISTER(isp, PRGODD1);
+ CCDC_PRINT_REGISTER(isp, VP_OUT);
+ CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
+ CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
+ CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
+ CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
+
+ dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * omap3isp_ccdc_busy - Get busy state of the CCDC.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
+ ISPCCDC_PCR_BUSY;
+}
+
+/* -----------------------------------------------------------------------------
+ * Lens Shading Compensation
+ */
+
+/*
+ * ccdc_lsc_validate_config - Check that LSC configuration is valid.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @lsc_cfg: the LSC configuration to check.
+ *
+ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
+ */
+static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
+ struct omap3isp_ccdc_lsc_config *lsc_cfg)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ struct v4l2_mbus_framefmt *format;
+ unsigned int paxel_width, paxel_height;
+ unsigned int paxel_shift_x, paxel_shift_y;
+ unsigned int min_width, min_height, min_size;
+ unsigned int input_width, input_height;
+
+ paxel_shift_x = lsc_cfg->gain_mode_m;
+ paxel_shift_y = lsc_cfg->gain_mode_n;
+
+ if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
+ (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
+ dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
+ return -EINVAL;
+ }
+
+ if (lsc_cfg->offset & 3) {
+ dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
+ "4\n");
+ return -EINVAL;
+ }
+
+ if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
+ dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
+ return -EINVAL;
+ }
+
+ format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+ V4L2_SUBDEV_FORMAT_ACTIVE);
+ input_width = format->width;
+ input_height = format->height;
+
+ /* Calculate minimum bytesize for validation */
+ paxel_width = 1 << paxel_shift_x;
+ min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
+ >> paxel_shift_x) + 1;
+
+ paxel_height = 1 << paxel_shift_y;
+ min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
+ >> paxel_shift_y) + 1;
+
+ min_size = 4 * min_width * min_height;
+ if (min_size > lsc_cfg->size) {
+ dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
+ return -EINVAL;
+ }
+ if (lsc_cfg->offset < (min_width * 4)) {
+ dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
+ return -EINVAL;
+ }
+ if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
+ dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
+{
+ isp_reg_writel(to_isp_device(ccdc), addr,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
+}
+
+/*
+ * ccdc_lsc_setup_regs - Configures the lens shading compensation module
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
+ struct omap3isp_ccdc_lsc_config *cfg)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ int reg;
+
+ isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_TABLE_OFFSET);
+
+ reg = 0;
+ reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
+ reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
+ reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
+ isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
+
+ reg = 0;
+ reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
+ reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
+ reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
+ reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
+ isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_INITIAL);
+}
+
+static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ unsigned int wait;
+
+ isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+ /* timeout 1 ms */
+ for (wait = 0; wait < 1000; wait++) {
+ if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
+ IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
+ isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ return 0;
+ }
+
+ rmb();
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables LSC, 1 Enables LSC.
+ */
+static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ const struct v4l2_mbus_framefmt *format =
+ __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+ V4L2_SUBDEV_FORMAT_ACTIVE);
+
+ if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
+ (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
+ (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
+ (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
+ return -EINVAL;
+
+ if (enable)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+ ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
+
+ if (enable) {
+ if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
+ ccdc->lsc.state = LSC_STATE_STOPPED;
+ dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
+ return -ETIMEDOUT;
+ }
+ ccdc->lsc.state = LSC_STATE_RUNNING;
+ } else {
+ ccdc->lsc.state = LSC_STATE_STOPPING;
+ }
+
+ return 0;
+}
+
+static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
+ ISPCCDC_LSC_BUSY;
+}
+
+/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
+ * @ccdc: Pointer to ISP CCDC device
+ * @req: New configuration request
+ *
+ * context: in_interrupt()
+ */
+static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
+ struct ispccdc_lsc_config_req *req)
+{
+ if (!req->enable)
+ return -EINVAL;
+
+ if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
+ dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
+ return -EINVAL;
+ }
+
+ if (ccdc_lsc_busy(ccdc))
+ return -EBUSY;
+
+ ccdc_lsc_setup_regs(ccdc, &req->config);
+ ccdc_lsc_program_table(ccdc, req->table);
+ return 0;
+}
+
+/*
+ * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Disables LSC, and defers enablement to shadow registers update time.
+ */
+static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ /*
+ * From OMAP3 TRM: When this event is pending, the module
+ * goes into transparent mode (output =input). Normal
+ * operation can be resumed at the start of the next frame
+ * after:
+ * 1) Clearing this event
+ * 2) Disabling the LSC module
+ * 3) Enabling it
+ */
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+ ISPCCDC_LSC_ENABLE);
+ ccdc->lsc.state = LSC_STATE_STOPPED;
+}
+
+static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
+ struct ispccdc_lsc_config_req *req)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ if (req == NULL)
+ return;
+
+ if (req->iovm)
+ dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
+ req->iovm->sgt->nents, DMA_TO_DEVICE);
+ if (req->table)
+ omap_iommu_vfree(isp->domain, isp->dev, req->table);
+ kfree(req);
+}
+
+static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
+ struct list_head *queue)
+{
+ struct ispccdc_lsc_config_req *req, *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+ list_for_each_entry_safe(req, n, queue, list) {
+ list_del(&req->list);
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+ ccdc_lsc_free_request(ccdc, req);
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+ }
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static void ccdc_lsc_free_table_work(struct work_struct *work)
+{
+ struct isp_ccdc_device *ccdc;
+ struct ispccdc_lsc *lsc;
+
+ lsc = container_of(work, struct ispccdc_lsc, table_work);
+ ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
+
+ ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
+}
+
+/*
+ * ccdc_lsc_config - Configure the LSC module from a userspace request
+ *
+ * Store the request LSC configuration in the LSC engine request pointer. The
+ * configuration will be applied to the hardware when the CCDC will be enabled,
+ * or at the next LSC interrupt if the CCDC is already running.
+ */
+static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
+ struct omap3isp_ccdc_update_config *config)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ struct ispccdc_lsc_config_req *req;
+ unsigned long flags;
+ void *table;
+ u16 update;
+ int ret;
+
+ update = config->update &
+ (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
+ if (!update)
+ return 0;
+
+ if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
+ dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
+ "need to be supplied\n", __func__);
+ return -EINVAL;
+ }
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (req == NULL)
+ return -ENOMEM;
+
+ if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
+ if (copy_from_user(&req->config, config->lsc_cfg,
+ sizeof(req->config))) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req->enable = 1;
+
+ req->table = omap_iommu_vmalloc(isp->domain, isp->dev, 0,
+ req->config.size, IOMMU_FLAG);
+ if (IS_ERR_VALUE(req->table)) {
+ req->table = 0;
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->iovm = omap_find_iovm_area(isp->dev, req->table);
+ if (req->iovm == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
+ req->iovm->sgt->nents, DMA_TO_DEVICE)) {
+ ret = -ENOMEM;
+ req->iovm = NULL;
+ goto done;
+ }
+
+ dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
+ req->iovm->sgt->nents, DMA_TO_DEVICE);
+
+ table = omap_da_to_va(isp->dev, req->table);
+ if (copy_from_user(table, config->lsc, req->config.size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
+ req->iovm->sgt->nents, DMA_TO_DEVICE);
+ }
+
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+ if (ccdc->lsc.request) {
+ list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+ schedule_work(&ccdc->lsc.table_work);
+ }
+ ccdc->lsc.request = req;
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+ ret = 0;
+
+done:
+ if (ret < 0)
+ ccdc_lsc_free_request(ccdc, req);
+
+ return ret;
+}
+
+static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+ if (ccdc->lsc.active) {
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+ return 0;
+}
+
+static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
+{
+ struct ispccdc_lsc *lsc = &ccdc->lsc;
+
+ if (lsc->state != LSC_STATE_STOPPED)
+ return -EINVAL;
+
+ if (lsc->active) {
+ list_add_tail(&lsc->active->list, &lsc->free_queue);
+ lsc->active = NULL;
+ }
+
+ if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
+ omap3isp_sbl_disable(to_isp_device(ccdc),
+ OMAP3_ISP_SBL_CCDC_LSC_READ);
+ list_add_tail(&lsc->request->list, &lsc->free_queue);
+ lsc->request = NULL;
+ goto done;
+ }
+
+ lsc->active = lsc->request;
+ lsc->request = NULL;
+ __ccdc_lsc_enable(ccdc, 1);
+
+done:
+ if (!list_empty(&lsc->free_queue))
+ schedule_work(&lsc->table_work);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Parameters configuration
+ */
+
+/*
+ * ccdc_configure_clamp - Configure optical-black or digital clamping
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * The CCDC performs either optical-black or digital clamp. Configure and enable
+ * the selected clamp method.
+ */
+static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ u32 clamp;
+
+ if (ccdc->obclamp) {
+ clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
+ clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
+ clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
+ clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
+ isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
+ } else {
+ isp_reg_writel(isp, ccdc->clamp.dcsubval,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
+ }
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
+ ISPCCDC_CLAMP_CLAMPEN,
+ ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
+}
+
+/*
+ * ccdc_configure_fpc - Configure Faulty Pixel Correction
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
+
+ if (!ccdc->fpc_en)
+ return;
+
+ isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FPC_ADDR);
+ /* The FPNUM field must be set before enabling FPC. */
+ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
+ ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+}
+
+/*
+ * ccdc_configure_black_comp - Configure Black Level Compensation.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ u32 blcomp;
+
+ blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
+ blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
+ blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
+ blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
+
+ isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
+}
+
+/*
+ * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
+ ISPCCDC_SYN_MODE_LPF,
+ ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
+}
+
+/*
+ * ccdc_configure_alaw - Configure A-law compression.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ const struct isp_format_info *info;
+ u32 alaw = 0;
+
+ info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+ switch (info->width) {
+ case 8:
+ return;
+
+ case 10:
+ alaw = ISPCCDC_ALAW_GWDI_9_0;
+ break;
+ case 11:
+ alaw = ISPCCDC_ALAW_GWDI_10_1;
+ break;
+ case 12:
+ alaw = ISPCCDC_ALAW_GWDI_11_2;
+ break;
+ case 13:
+ alaw = ISPCCDC_ALAW_GWDI_12_3;
+ break;
+ }
+
+ if (ccdc->alaw)
+ alaw |= ISPCCDC_ALAW_CCDTBL;
+
+ isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
+}
+
+/*
+ * ccdc_config_imgattr - Configure sensor image specific attributes.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @colptn: Color pattern of the sensor.
+ */
+static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
+}
+
+/*
+ * ccdc_config - Set CCDC configuration from userspace
+ * @ccdc: Pointer to ISP CCDC device.
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ */
+static int ccdc_config(struct isp_ccdc_device *ccdc,
+ struct omap3isp_ccdc_update_config *ccdc_struct)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccdc->lock, flags);
+ ccdc->shadow_update = 1;
+ spin_unlock_irqrestore(&ccdc->lock, flags);
+
+ if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
+ ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
+ ccdc->update |= OMAP3ISP_CCDC_ALAW;
+ }
+
+ if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
+ ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
+ ccdc->update |= OMAP3ISP_CCDC_LPF;
+ }
+
+ if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
+ if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
+ sizeof(ccdc->clamp))) {
+ ccdc->shadow_update = 0;
+ return -EFAULT;
+ }
+
+ ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
+ ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
+ }
+
+ if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
+ if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
+ sizeof(ccdc->blcomp))) {
+ ccdc->shadow_update = 0;
+ return -EFAULT;
+ }
+
+ ccdc->update |= OMAP3ISP_CCDC_BCOMP;
+ }
+
+ ccdc->shadow_update = 0;
+
+ if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
+ u32 table_old = 0;
+ u32 table_new;
+ u32 size;
+
+ if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+ return -EBUSY;
+
+ ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
+
+ if (ccdc->fpc_en) {
+ if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
+ sizeof(ccdc->fpc)))
+ return -EFAULT;
+
+ /*
+ * table_new must be 64-bytes aligned, but it's
+ * already done by omap_iommu_vmalloc().
+ */
+ size = ccdc->fpc.fpnum * 4;
+ table_new = omap_iommu_vmalloc(isp->domain, isp->dev,
+ 0, size, IOMMU_FLAG);
+ if (IS_ERR_VALUE(table_new))
+ return -ENOMEM;
+
+ if (copy_from_user(omap_da_to_va(isp->dev, table_new),
+ (__force void __user *)
+ ccdc->fpc.fpcaddr, size)) {
+ omap_iommu_vfree(isp->domain, isp->dev,
+ table_new);
+ return -EFAULT;
+ }
+
+ table_old = ccdc->fpc.fpcaddr;
+ ccdc->fpc.fpcaddr = table_new;
+ }
+
+ ccdc_configure_fpc(ccdc);
+ if (table_old != 0)
+ omap_iommu_vfree(isp->domain, isp->dev, table_old);
+ }
+
+ return ccdc_lsc_config(ccdc, ccdc_struct);
+}
+
+static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
+{
+ if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
+ ccdc_configure_alaw(ccdc);
+ ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
+ }
+
+ if (ccdc->update & OMAP3ISP_CCDC_LPF) {
+ ccdc_configure_lpf(ccdc);
+ ccdc->update &= ~OMAP3ISP_CCDC_LPF;
+ }
+
+ if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
+ ccdc_configure_clamp(ccdc);
+ ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
+ }
+
+ if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
+ ccdc_configure_black_comp(ccdc);
+ ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
+ }
+}
+
+/*
+ * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
+ * @dev: Pointer to ISP device
+ */
+void omap3isp_ccdc_restore_context(struct isp_device *isp)
+{
+ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
+
+ ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
+ | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
+ ccdc_apply_controls(ccdc);
+ ccdc_configure_fpc(ccdc);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+/*
+ * ccdc_config_vp - Configure the Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+ struct isp_device *isp = to_isp_device(ccdc);
+ const struct isp_format_info *info;
+ unsigned long l3_ick = pipe->l3_ick;
+ unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
+ unsigned int div = 0;
+ u32 fmtcfg_vp;
+
+ fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
+ & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+
+ info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+ switch (info->width) {
+ case 8:
+ case 10:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+ break;
+ case 11:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+ break;
+ case 12:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+ break;
+ case 13:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+ break;
+ }
+
+ if (pipe->input)
+ div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
+ else if (pipe->external_rate)
+ div = l3_ick / pipe->external_rate;
+
+ div = clamp(div, 2U, max_div);
+ fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+
+ isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+}
+
+/*
+ * ccdc_enable_vp - Enable Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables VP, 1 Enables VP
+ *
+ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
+ */
+static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
+ ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+}
+
+/*
+ * ccdc_config_outlineoffset - Configure memory saving output line offset
+ * @ccdc: Pointer to ISP CCDC device.
+ * @offset: Address offset to start a new line. Must be twice the
+ * Output width and aligned on 32 byte boundary
+ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
+ * output.
+ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ *
+ * - Configures the output line offset when stored in memory
+ * - Sets the odd/even line pattern to store the output
+ * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
+ * - Configures the number of even and odd line fields in case of rearranging
+ * the lines.
+ */
+static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
+ u32 offset, u8 oddeven, u8 numlines)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_writel(isp, offset & 0xffff,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ ISPCCDC_SDOFST_FINV);
+
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ ISPCCDC_SDOFST_FOFST_4L);
+
+ switch (oddeven) {
+ case EVENEVEN:
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
+ break;
+ case ODDEVEN:
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
+ break;
+ case EVENODD:
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
+ break;
+ case ODDODD:
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * ccdc_set_outaddr - Set memory address to save output image
+ * @ccdc: Pointer to ISP CCDC device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ */
+static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
+}
+
+/*
+ * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_rate: Maximum calculated data rate.
+ *
+ * Returns in *max_rate less value between calculated and passed
+ */
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+ unsigned int *max_rate)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+ unsigned int rate;
+
+ if (pipe == NULL)
+ return;
+
+ /*
+ * TRM says that for parallel sensors the maximum data rate
+ * should be 90% form L3/2 clock, otherwise just L3/2.
+ */
+ if (ccdc->input == CCDC_INPUT_PARALLEL)
+ rate = pipe->l3_ick / 2 * 9 / 10;
+ else
+ rate = pipe->l3_ick / 2;
+
+ *max_rate = min(*max_rate, rate);
+}
+
+/*
+ * ccdc_config_sync_if - Set CCDC sync interface configuration
+ * @ccdc: Pointer to ISP CCDC device.
+ * @pdata: Parallel interface platform data (may be NULL)
+ * @data_size: Data size
+ */
+static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
+ struct isp_parallel_platform_data *pdata,
+ unsigned int data_size)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ const struct v4l2_mbus_framefmt *format;
+ u32 syn_mode = ISPCCDC_SYN_MODE_VDHDEN;
+
+ format = &ccdc->formats[CCDC_PAD_SINK];
+
+ if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ /* The bridge is enabled for YUV8 formats. Configure the input
+ * mode accordingly.
+ */
+ syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+ }
+
+ switch (data_size) {
+ case 8:
+ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
+ break;
+ case 10:
+ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
+ break;
+ case 11:
+ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
+ break;
+ case 12:
+ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
+ break;
+ }
+
+ if (pdata && pdata->data_pol)
+ syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
+
+ if (pdata && pdata->hs_pol)
+ syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
+
+ if (pdata && pdata->vs_pol)
+ syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
+
+ isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+ /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
+ * hardware seems to ignore it in all other input modes.
+ */
+ if (format->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_Y8POS);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_Y8POS);
+
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+ ISPCCDC_REC656IF_R656ON);
+}
+
+/* CCDC formats descriptions */
+static const u32 ccdc_sgrbg_pattern =
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_srggb_pattern =
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sbggr_pattern =
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sgbrg_pattern =
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static void ccdc_configure(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+ struct isp_parallel_platform_data *pdata = NULL;
+ struct v4l2_subdev *sensor;
+ struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
+ const struct isp_format_info *fmt_info;
+ struct v4l2_subdev_format fmt_src;
+ unsigned int depth_out;
+ unsigned int depth_in = 0;
+ struct media_pad *pad;
+ unsigned long flags;
+ unsigned int bridge;
+ unsigned int shift;
+ u32 syn_mode;
+ u32 ccdc_pattern;
+
+ pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+ sensor = media_entity_to_v4l2_subdev(pad->entity);
+ if (ccdc->input == CCDC_INPUT_PARALLEL)
+ pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
+ ->bus.parallel;
+
+ /* Compute the lane shifter shift value and enable the bridge when the
+ * input format is YUV.
+ */
+ fmt_src.pad = pad->index;
+ fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
+ fmt_info = omap3isp_video_format_info(fmt_src.format.code);
+ depth_in = fmt_info->width;
+ }
+
+ fmt_info = omap3isp_video_format_info
+ (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+ depth_out = fmt_info->width;
+ shift = depth_in - depth_out;
+
+ if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+ bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
+ else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
+ else
+ bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+
+ omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
+
+ ccdc_config_sync_if(ccdc, pdata, depth_out);
+
+ syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+ /* Use the raw, unprocessed data when writing to memory. The H3A and
+ * histogram modules are still fed with lens shading corrected data.
+ */
+ syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+
+ if (ccdc->output & CCDC_OUTPUT_MEMORY)
+ syn_mode |= ISPCCDC_SYN_MODE_WEN;
+ else
+ syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+
+ if (ccdc->output & CCDC_OUTPUT_RESIZER)
+ syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+ else
+ syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+
+ /* CCDC_PAD_SINK */
+ format = &ccdc->formats[CCDC_PAD_SINK];
+
+ /* Mosaic filter */
+ switch (format->code) {
+ case V4L2_MBUS_FMT_SRGGB10_1X10:
+ case V4L2_MBUS_FMT_SRGGB12_1X12:
+ ccdc_pattern = ccdc_srggb_pattern;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case V4L2_MBUS_FMT_SBGGR12_1X12:
+ ccdc_pattern = ccdc_sbggr_pattern;
+ break;
+ case V4L2_MBUS_FMT_SGBRG10_1X10:
+ case V4L2_MBUS_FMT_SGBRG12_1X12:
+ ccdc_pattern = ccdc_sgbrg_pattern;
+ break;
+ default:
+ /* Use GRBG */
+ ccdc_pattern = ccdc_sgrbg_pattern;
+ break;
+ }
+ ccdc_config_imgattr(ccdc, ccdc_pattern);
+
+ /* Generate VD0 on the last line of the image and VD1 on the
+ * 2/3 height line.
+ */
+ isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
+ ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
+
+ /* CCDC_PAD_SOURCE_OF */
+ format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
+ crop = &ccdc->crop;
+
+ isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+ ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
+ isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
+ isp_reg_writel(isp, (crop->height - 1)
+ << ISPCCDC_VERT_LINES_NLV_SHIFT,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
+
+ ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+
+ /* The CCDC outputs data in UYVY order by default. Swap bytes to get
+ * YUYV.
+ */
+ if (format->code == V4L2_MBUS_FMT_YUYV8_1X16)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_BSWD);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_BSWD);
+
+ /* Use PACK8 mode for 1byte per pixel formats. */
+ if (omap3isp_video_format_info(format->code)->width <= 8)
+ syn_mode |= ISPCCDC_SYN_MODE_PACK8;
+ else
+ syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
+
+ isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+ /* CCDC_PAD_SOURCE_VP */
+ format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+ isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+ (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+ isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+ ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
+
+ isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+ (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+
+ /* Lens shading correction. */
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+ if (ccdc->lsc.request == NULL)
+ goto unlock;
+
+ WARN_ON(ccdc->lsc.active);
+
+ /* Get last good LSC configuration. If it is not supported for
+ * the current active resolution discard it.
+ */
+ if (ccdc->lsc.active == NULL &&
+ __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
+ ccdc->lsc.active = ccdc->lsc.request;
+ } else {
+ list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+ schedule_work(&ccdc->lsc.table_work);
+ }
+
+ ccdc->lsc.request = NULL;
+
+unlock:
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+ ccdc_apply_controls(ccdc);
+}
+
+static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
+ ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+}
+
+static int ccdc_disable(struct isp_ccdc_device *ccdc)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ccdc->lock, flags);
+ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+ ccdc->stopping = CCDC_STOP_REQUEST;
+ spin_unlock_irqrestore(&ccdc->lock, flags);
+
+ ret = wait_event_timeout(ccdc->wait,
+ ccdc->stopping == CCDC_STOP_FINISHED,
+ msecs_to_jiffies(2000));
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
+ }
+
+ omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+ mutex_lock(&ccdc->ioctl_lock);
+ ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+ ccdc->lsc.request = ccdc->lsc.active;
+ ccdc->lsc.active = NULL;
+ cancel_work_sync(&ccdc->lsc.table_work);
+ ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+ mutex_unlock(&ccdc->ioctl_lock);
+
+ ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+ return ret > 0 ? 0 : ret;
+}
+
+static void ccdc_enable(struct isp_ccdc_device *ccdc)
+{
+ if (ccdc_lsc_is_configured(ccdc))
+ __ccdc_lsc_enable(ccdc, 1);
+ __ccdc_enable(ccdc, 1);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Returns zero if the CCDC is idle and the image has been written to
+ * memory, too.
+ */
+static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
+{
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ return omap3isp_ccdc_busy(ccdc)
+ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
+ ISPSBL_CCDC_WR_0_DATA_READY)
+ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
+ ISPSBL_CCDC_WR_0_DATA_READY)
+ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
+ ISPSBL_CCDC_WR_0_DATA_READY)
+ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
+ ISPSBL_CCDC_WR_0_DATA_READY);
+}
+
+/*
+ * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_wait: Max retry count in us for wait for idle/busy transition.
+ */
+static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
+ unsigned int max_wait)
+{
+ unsigned int wait = 0;
+
+ if (max_wait == 0)
+ max_wait = 10000; /* 10 ms */
+
+ for (wait = 0; wait <= max_wait; wait++) {
+ if (!ccdc_sbl_busy(ccdc))
+ return 0;
+
+ rmb();
+ udelay(1);
+ }
+
+ return -EBUSY;
+}
+
+/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+ * @ccdc: Pointer to ISP CCDC device.
+ * @event: Pointing which event trigger handler
+ *
+ * Return 1 when the event and stopping request combination is satisfied,
+ * zero otherwise.
+ */
+static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+{
+ int rval = 0;
+
+ switch ((ccdc->stopping & 3) | event) {
+ case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
+ if (ccdc->lsc.state != LSC_STATE_STOPPED)
+ __ccdc_lsc_enable(ccdc, 0);
+ __ccdc_enable(ccdc, 0);
+ ccdc->stopping = CCDC_STOP_EXECUTED;
+ return 1;
+
+ case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
+ ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
+ if (ccdc->lsc.state == LSC_STATE_STOPPED)
+ ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+ rval = 1;
+ break;
+
+ case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
+ ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+ rval = 1;
+ break;
+
+ case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
+ return 1;
+ }
+
+ if (ccdc->stopping == CCDC_STOP_FINISHED) {
+ wake_up(&ccdc->wait);
+ rval = 1;
+ }
+
+ return rval;
+}
+
+static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+ struct video_device *vdev = ccdc->subdev.devnode;
+ struct v4l2_event event;
+
+ /* Frame number propagation */
+ atomic_inc(&pipe->frame_number);
+
+ memset(&event, 0, sizeof(event));
+ event.type = V4L2_EVENT_FRAME_SYNC;
+ event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
+
+ v4l2_event_queue(vdev, &event);
+}
+
+/*
+ * ccdc_lsc_isr - Handle LSC events
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: LSC events
+ */
+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);
+ pipe->error = true;
+ dev_dbg(to_device(ccdc), "lsc prefetch error\n");
+ }
+
+ if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
+ return;
+
+ /* LSC_DONE interrupt occur, there are two cases
+ * 1. stopping for reconfiguration
+ * 2. stopping because of STREAM OFF command
+ */
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+ if (ccdc->lsc.state == LSC_STATE_STOPPING)
+ ccdc->lsc.state = LSC_STATE_STOPPED;
+
+ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+ goto done;
+
+ if (ccdc->lsc.state != LSC_STATE_RECONFIG)
+ goto done;
+
+ /* LSC is in STOPPING state, change to the new state */
+ ccdc->lsc.state = LSC_STATE_STOPPED;
+
+ /* This is an exception. Start of frame and LSC_DONE interrupt
+ * have been received on the same time. Skip this event and wait
+ * for better times.
+ */
+ if (events & IRQ0STATUS_HS_VS_IRQ)
+ goto done;
+
+ /* The LSC engine is stopped at this point. Enable it if there's a
+ * pending request.
+ */
+ if (ccdc->lsc.request == NULL)
+ goto done;
+
+ ccdc_lsc_enable(ccdc);
+
+done:
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+ struct isp_device *isp = to_isp_device(ccdc);
+ struct isp_buffer *buffer;
+ int restart = 0;
+
+ /* The CCDC generates VD0 interrupts even when disabled (the datasheet
+ * doesn't explicitly state if that's supposed to happen or not, so it
+ * can be considered as a hardware bug or as a feature, but we have to
+ * deal with it anyway). Disabling the CCDC when no buffer is available
+ * would thus not be enough, we need to handle the situation explicitly.
+ */
+ if (list_empty(&ccdc->video_out.dmaqueue))
+ goto done;
+
+ /* We're in continuous mode, and memory writes were disabled due to a
+ * buffer underrun. Reenable them now that we have a buffer. The buffer
+ * address has been set in ccdc_video_queue.
+ */
+ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
+ restart = 1;
+ ccdc->underrun = 0;
+ goto done;
+ }
+
+ if (ccdc_sbl_wait_idle(ccdc, 1000)) {
+ dev_info(isp->dev, "CCDC won't become idle!\n");
+ goto done;
+ }
+
+ buffer = omap3isp_video_buffer_next(&ccdc->video_out);
+ if (buffer != NULL) {
+ ccdc_set_outaddr(ccdc, buffer->isp_addr);
+ restart = 1;
+ }
+
+ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+ if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+ isp_pipeline_ready(pipe))
+ omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_SINGLESHOT);
+
+done:
+ return restart;
+}
+
+/*
+ * ccdc_vd0_isr - Handle VD0 event
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ */
+static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
+{
+ unsigned long flags;
+ int restart = 0;
+
+ if (ccdc->output & CCDC_OUTPUT_MEMORY)
+ restart = ccdc_isr_buffer(ccdc);
+
+ spin_lock_irqsave(&ccdc->lock, flags);
+ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+ spin_unlock_irqrestore(&ccdc->lock, flags);
+ return;
+ }
+
+ if (!ccdc->shadow_update)
+ ccdc_apply_controls(ccdc);
+ spin_unlock_irqrestore(&ccdc->lock, flags);
+
+ if (restart)
+ ccdc_enable(ccdc);
+}
+
+/*
+ * ccdc_vd1_isr - Handle VD1 event
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+ /*
+ * Depending on the CCDC pipeline state, CCDC stopping should be
+ * handled differently. In SINGLESHOT we emulate an internal CCDC
+ * stopping because the CCDC hw works only in continuous mode.
+ * When CONTINUOUS pipeline state is used and the CCDC writes it's
+ * data to memory the CCDC and LSC are stopped immediately but
+ * without change the CCDC stopping state machine. The CCDC
+ * stopping state machine should be used only when user request
+ * for stopping is received (SINGLESHOT is an exeption).
+ */
+ switch (ccdc->state) {
+ case ISP_PIPELINE_STREAM_SINGLESHOT:
+ ccdc->stopping = CCDC_STOP_REQUEST;
+ break;
+
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ if (ccdc->output & CCDC_OUTPUT_MEMORY) {
+ if (ccdc->lsc.state != LSC_STATE_STOPPED)
+ __ccdc_lsc_enable(ccdc, 0);
+ __ccdc_enable(ccdc, 0);
+ }
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ break;
+ }
+
+ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+ goto done;
+
+ if (ccdc->lsc.request == NULL)
+ goto done;
+
+ /*
+ * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
+ * do the appropriate changes in registers
+ */
+ if (ccdc->lsc.state == LSC_STATE_RUNNING) {
+ __ccdc_lsc_enable(ccdc, 0);
+ ccdc->lsc.state = LSC_STATE_RECONFIG;
+ goto done;
+ }
+
+ /* LSC has been in STOPPED state, enable it */
+ if (ccdc->lsc.state == LSC_STATE_STOPPED)
+ ccdc_lsc_enable(ccdc);
+
+done:
+ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+/*
+ * omap3isp_ccdc_isr - Configure CCDC during interframe time.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: CCDC events
+ */
+int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
+{
+ if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+
+ if (events & IRQ0STATUS_CCDC_VD1_IRQ)
+ ccdc_vd1_isr(ccdc);
+
+ ccdc_lsc_isr(ccdc, events);
+
+ if (events & IRQ0STATUS_CCDC_VD0_IRQ)
+ ccdc_vd0_isr(ccdc);
+
+ if (events & IRQ0STATUS_HS_VS_IRQ)
+ ccdc_hs_vs_isr(ccdc);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+ struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+
+ if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
+ return -ENODEV;
+
+ ccdc_set_outaddr(ccdc, buffer->isp_addr);
+
+ /* We now have a buffer queued on the output, restart the pipeline
+ * on the next CCDC interrupt if running in continuous mode (or when
+ * starting the stream).
+ */
+ ccdc->underrun = 1;
+
+ return 0;
+}
+
+static const struct isp_video_operations ccdc_video_ops = {
+ .queue = ccdc_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * ccdc_ioctl - CCDC module private ioctl's
+ * @sd: ISP CCDC V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ int ret;
+
+ switch (cmd) {
+ case VIDIOC_OMAP3ISP_CCDC_CFG:
+ mutex_lock(&ccdc->ioctl_lock);
+ ret = ccdc_config(ccdc, arg);
+ mutex_unlock(&ccdc->ioctl_lock);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ if (sub->type != V4L2_EVENT_FRAME_SYNC)
+ return -EINVAL;
+
+ /* line number is zero at frame start */
+ if (sub->id != 0)
+ return -EINVAL;
+
+ return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
+}
+
+static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+/*
+ * ccdc_set_stream - Enable/Disable streaming on the CCDC module
+ * @sd: ISP CCDC V4L2 subdevice
+ * @enable: Enable/disable stream
+ *
+ * When writing to memory, the CCDC hardware can't be enabled without a memory
+ * buffer to write to. As the s_stream operation is called in response to a
+ * STREAMON call without any buffer queued yet, just update the enabled field
+ * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
+ *
+ * When not writing to memory enable the CCDC immediately.
+ */
+static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct isp_device *isp = to_isp_device(ccdc);
+ int ret = 0;
+
+ if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
+ if (enable == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+
+ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_VDLC);
+
+ ccdc_configure(ccdc);
+
+ /* TODO: Don't configure the video port if all of its output
+ * links are inactive.
+ */
+ ccdc_config_vp(ccdc);
+ ccdc_enable_vp(ccdc, 1);
+ ccdc_print_status(ccdc);
+ }
+
+ switch (enable) {
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ if (ccdc->output & CCDC_OUTPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+ if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
+ ccdc_enable(ccdc);
+
+ ccdc->underrun = 0;
+ break;
+
+ case ISP_PIPELINE_STREAM_SINGLESHOT:
+ if (ccdc->output & CCDC_OUTPUT_MEMORY &&
+ ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+ ccdc_enable(ccdc);
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ ret = ccdc_disable(ccdc);
+ if (ccdc->output & CCDC_OUTPUT_MEMORY)
+ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
+ ccdc->underrun = 0;
+ break;
+ }
+
+ ccdc->state = enable;
+ return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &ccdc->formats[pad];
+}
+
+static struct v4l2_rect *
+__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
+ else
+ return &ccdc->crop;
+}
+
+/*
+ * ccdc_try_format - Try video format on a pad
+ * @ccdc: ISP CCDC device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ const struct isp_format_info *info;
+ enum v4l2_mbus_pixelcode pixelcode;
+ unsigned int width = fmt->width;
+ unsigned int height = fmt->height;
+ struct v4l2_rect *crop;
+ unsigned int i;
+
+ switch (pad) {
+ case CCDC_PAD_SINK:
+ for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
+ if (fmt->code == ccdc_fmts[i])
+ break;
+ }
+
+ /* If not found, use SGRBG10 as default */
+ if (i >= ARRAY_SIZE(ccdc_fmts))
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ /* Clamp the input size. */
+ fmt->width = clamp_t(u32, width, 32, 4096);
+ fmt->height = clamp_t(u32, height, 32, 4096);
+ break;
+
+ case CCDC_PAD_SOURCE_OF:
+ pixelcode = fmt->code;
+ *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+
+ /* YUV formats are converted from 2X8 to 1X16 by the bridge and
+ * can be byte-swapped.
+ */
+ if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ /* Use the user requested format if YUV. */
+ if (pixelcode == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ pixelcode == V4L2_MBUS_FMT_UYVY8_2X8 ||
+ pixelcode == V4L2_MBUS_FMT_YUYV8_1X16 ||
+ pixelcode == V4L2_MBUS_FMT_UYVY8_1X16)
+ fmt->code = pixelcode;
+
+ if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8)
+ fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ else if (fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ }
+
+ /* Hardcode the output size to the crop rectangle size. */
+ crop = __ccdc_get_crop(ccdc, fh, which);
+ fmt->width = crop->width;
+ fmt->height = crop->height;
+ break;
+
+ case CCDC_PAD_SOURCE_VP:
+ *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+
+ /* The video port interface truncates the data to 10 bits. */
+ info = omap3isp_video_format_info(fmt->code);
+ fmt->code = info->truncated;
+
+ /* YUV formats are not supported by the video port. */
+ if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ fmt->code = 0;
+
+ /* The number of lines that can be clocked out from the video
+ * port output must be at least one line less than the number
+ * of input lines.
+ */
+ fmt->width = clamp_t(u32, width, 32, fmt->width);
+ fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
+ break;
+ }
+
+ /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
+ * stored on 2 bytes.
+ */
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * ccdc_try_crop - Validate a crop rectangle
+ * @ccdc: ISP CCDC device
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ */
+static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
+ const struct v4l2_mbus_framefmt *sink,
+ struct v4l2_rect *crop)
+{
+ const struct isp_format_info *info;
+ unsigned int max_width;
+
+ /* For Bayer formats, restrict left/top and width/height to even values
+ * to keep the Bayer pattern.
+ */
+ info = omap3isp_video_format_info(sink->code);
+ if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ crop->left &= ~1;
+ crop->top &= ~1;
+ }
+
+ crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
+ crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
+
+ /* The data formatter truncates the number of horizontal output pixels
+ * to a multiple of 16. To avoid clipping data, allow callers to request
+ * an output size bigger than the input size up to the nearest multiple
+ * of 16.
+ */
+ max_width = (sink->width - crop->left + 15) & ~15;
+ crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
+ & ~15;
+ crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
+ sink->height - crop->top);
+
+ /* Odd width/height values don't make sense for Bayer formats. */
+ if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ crop->width &= ~1;
+ crop->height &= ~1;
+ }
+}
+
+/*
+ * ccdc_enum_mbus_code - Handle pixel format enumeration
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ switch (code->pad) {
+ case CCDC_PAD_SINK:
+ if (code->index >= ARRAY_SIZE(ccdc_fmts))
+ return -EINVAL;
+
+ code->code = ccdc_fmts[code->index];
+ break;
+
+ case CCDC_PAD_SOURCE_OF:
+ format = __ccdc_get_format(ccdc, fh, code->pad,
+ V4L2_SUBDEV_FORMAT_TRY);
+
+ if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ /* In YUV mode the CCDC can swap bytes. */
+ if (code->index == 0)
+ code->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ else if (code->index == 1)
+ code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ else
+ return -EINVAL;
+ } else {
+ /* In raw mode, no configurable format confversion is
+ * available.
+ */
+ if (code->index == 0)
+ code->code = format->code;
+ else
+ return -EINVAL;
+ }
+ break;
+
+ case CCDC_PAD_SOURCE_VP:
+ /* The CCDC supports no configurable format conversion
+ * compatible with the video port. Enumerate a single output
+ * format code.
+ */
+ if (code->index != 0)
+ return -EINVAL;
+
+ format = __ccdc_get_format(ccdc, fh, code->pad,
+ V4L2_SUBDEV_FORMAT_TRY);
+
+ /* A pixel code equal to 0 means that the video port doesn't
+ * support the input format. Don't enumerate any pixel code.
+ */
+ if (format->code == 0)
+ return -EINVAL;
+
+ code->code = format->code;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt format;
+
+ if (fse->index != 0)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = 1;
+ format.height = 1;
+ ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->min_width = format.width;
+ fse->min_height = format.height;
+
+ if (format.code != fse->code)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = -1;
+ format.height = -1;
+ ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->max_width = format.width;
+ fse->max_height = format.height;
+
+ return 0;
+}
+
+/*
+ * ccdc_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the output formatter
+ * source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->pad != CCDC_PAD_SOURCE_OF)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ ccdc_try_crop(ccdc, format, &sel->r);
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * ccdc_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the output
+ * formatter source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->target != V4L2_SEL_TGT_CROP ||
+ sel->pad != CCDC_PAD_SOURCE_OF)
+ return -EINVAL;
+
+ /* The crop rectangle can't be changed while streaming. */
+ if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+ return -EBUSY;
+
+ /* Modifying the crop rectangle always changes the format on the source
+ * pad. If the KEEP_CONFIG flag is set, just return the current crop
+ * rectangle.
+ */
+ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
+ sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ return 0;
+ }
+
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ ccdc_try_crop(ccdc, format, &sel->r);
+ *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
+
+ /* Update the source format. */
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
+ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
+
+ return 0;
+}
+
+/*
+ * ccdc_get_format - Retrieve the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+/*
+ * ccdc_set_format - Set the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+
+ /* Propagate the format from sink to source */
+ if (fmt->pad == CCDC_PAD_SINK) {
+ /* Reset the crop rectangle. */
+ crop = __ccdc_get_crop(ccdc, fh, fmt->which);
+ crop->left = 0;
+ crop->top = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+
+ ccdc_try_crop(ccdc, &fmt->format, crop);
+
+ /* Update the source formats. */
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
+ fmt->which);
+ *format = fmt->format;
+ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
+ fmt->which);
+
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
+ fmt->which);
+ *format = fmt->format;
+ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
+ fmt->which);
+ }
+
+ return 0;
+}
+
+/*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
+ enum v4l2_mbus_pixelcode out,
+ unsigned int additional_shift)
+{
+ const struct isp_format_info *in_info, *out_info;
+
+ if (in == out)
+ return true;
+
+ in_info = omap3isp_video_format_info(in);
+ out_info = omap3isp_video_format_info(out);
+
+ if ((in_info->flavor == 0) || (out_info->flavor == 0))
+ return false;
+
+ if (in_info->flavor != out_info->flavor)
+ return false;
+
+ return in_info->width - out_info->width + additional_shift <= 6;
+}
+
+static int ccdc_link_validate(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ unsigned long parallel_shift;
+
+ /* Check if the two ends match */
+ if (source_fmt->format.width != sink_fmt->format.width ||
+ source_fmt->format.height != sink_fmt->format.height)
+ return -EPIPE;
+
+ /* We've got a parallel sensor here. */
+ if (ccdc->input == CCDC_INPUT_PARALLEL) {
+ struct isp_parallel_platform_data *pdata =
+ &((struct isp_v4l2_subdevs_group *)
+ media_entity_to_v4l2_subdev(link->source->entity)
+ ->host_priv)->bus.parallel;
+ parallel_shift = pdata->data_lane_shift * 2;
+ } else {
+ parallel_shift = 0;
+ }
+
+ /* Lane shifter may be used to drop bits on CCDC sink pad */
+ if (!ccdc_is_shiftable(source_fmt->format.code,
+ sink_fmt->format.code, parallel_shift))
+ return -EPIPE;
+
+ return 0;
+}
+
+/*
+ * ccdc_init_formats - Initialize formats on all pads
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+ format.pad = CCDC_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.width = 4096;
+ format.format.height = 4096;
+ ccdc_set_format(sd, fh, &format);
+
+ return 0;
+}
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
+ .ioctl = ccdc_ioctl,
+ .subscribe_event = ccdc_subscribe_event,
+ .unsubscribe_event = ccdc_unsubscribe_event,
+};
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
+ .s_stream = ccdc_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
+ .enum_mbus_code = ccdc_enum_mbus_code,
+ .enum_frame_size = ccdc_enum_frame_size,
+ .get_fmt = ccdc_get_format,
+ .set_fmt = ccdc_set_format,
+ .get_selection = ccdc_get_selection,
+ .set_selection = ccdc_set_selection,
+ .link_validate = ccdc_link_validate,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
+ .core = &ccdc_v4l2_core_ops,
+ .video = &ccdc_v4l2_video_ops,
+ .pad = &ccdc_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
+ .open = ccdc_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ccdc_link_setup - Setup CCDC connections
+ * @entity: CCDC media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int ccdc_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct isp_device *isp = to_isp_device(ccdc);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* Read from the sensor (parallel interface), CCP2, CSI2a or
+ * CSI2c.
+ */
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ ccdc->input = CCDC_INPUT_NONE;
+ break;
+ }
+
+ if (ccdc->input != CCDC_INPUT_NONE)
+ return -EBUSY;
+
+ if (remote->entity == &isp->isp_ccp2.subdev.entity)
+ ccdc->input = CCDC_INPUT_CCP2B;
+ else if (remote->entity == &isp->isp_csi2a.subdev.entity)
+ ccdc->input = CCDC_INPUT_CSI2A;
+ else if (remote->entity == &isp->isp_csi2c.subdev.entity)
+ ccdc->input = CCDC_INPUT_CSI2C;
+ else
+ ccdc->input = CCDC_INPUT_PARALLEL;
+
+ break;
+
+ /*
+ * The ISP core doesn't support pipelines with multiple video outputs.
+ * Revisit this when it will be implemented, and return -EBUSY for now.
+ */
+
+ case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* Write to preview engine, histogram and H3A. When none of
+ * those links are active, the video port can be disabled.
+ */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
+ return -EBUSY;
+ ccdc->output |= CCDC_OUTPUT_PREVIEW;
+ } else {
+ ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
+ }
+ break;
+
+ case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
+ /* Write to memory */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
+ return -EBUSY;
+ ccdc->output |= CCDC_OUTPUT_MEMORY;
+ } else {
+ ccdc->output &= ~CCDC_OUTPUT_MEMORY;
+ }
+ break;
+
+ case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* Write to resizer */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
+ return -EBUSY;
+ ccdc->output |= CCDC_OUTPUT_RESIZER;
+ } else {
+ ccdc->output &= ~CCDC_OUTPUT_RESIZER;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ccdc_media_ops = {
+ .link_setup = ccdc_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
+{
+ v4l2_device_unregister_subdev(&ccdc->subdev);
+ omap3isp_video_unregister(&ccdc->video_out);
+}
+
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+ struct v4l2_device *vdev)
+{
+ int ret;
+
+ /* Register the subdev and video node. */
+ ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&ccdc->video_out, vdev);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ omap3isp_ccdc_unregister_entities(ccdc);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CCDC initialisation and cleanup
+ */
+
+/*
+ * ccdc_init_entities - Initialize V4L2 subdev and media entity
+ * @ccdc: ISP CCDC module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
+{
+ struct v4l2_subdev *sd = &ccdc->subdev;
+ struct media_pad *pads = ccdc->pads;
+ struct media_entity *me = &sd->entity;
+ int ret;
+
+ ccdc->input = CCDC_INPUT_NONE;
+
+ v4l2_subdev_init(sd, &ccdc_v4l2_ops);
+ sd->internal_ops = &ccdc_v4l2_internal_ops;
+ strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
+ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
+ v4l2_set_subdevdata(sd, ccdc);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
+ pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
+
+ me->ops = &ccdc_media_ops;
+ ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
+ if (ret < 0)
+ return ret;
+
+ ccdc_init_formats(sd, NULL);
+
+ ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ccdc->video_out.ops = &ccdc_video_ops;
+ ccdc->video_out.isp = to_isp_device(ccdc);
+ ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+ ccdc->video_out.bpl_alignment = 32;
+
+ ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
+ if (ret < 0)
+ goto error_video;
+
+ /* Connect the CCDC subdev to the video node. */
+ ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
+ &ccdc->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ goto error_link;
+
+ return 0;
+
+error_link:
+ omap3isp_video_cleanup(&ccdc->video_out);
+error_video:
+ media_entity_cleanup(me);
+ return ret;
+}
+
+/*
+ * omap3isp_ccdc_init - CCDC module initialization.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap3isp_ccdc_init(struct isp_device *isp)
+{
+ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+ int ret;
+
+ spin_lock_init(&ccdc->lock);
+ init_waitqueue_head(&ccdc->wait);
+ mutex_init(&ccdc->ioctl_lock);
+
+ ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+ INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
+ ccdc->lsc.state = LSC_STATE_STOPPED;
+ INIT_LIST_HEAD(&ccdc->lsc.free_queue);
+ spin_lock_init(&ccdc->lsc.req_lock);
+
+ ccdc->clamp.oblen = 0;
+ ccdc->clamp.dcsubval = 0;
+
+ ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
+ ccdc_apply_controls(ccdc);
+
+ ret = ccdc_init_entities(ccdc);
+ if (ret < 0) {
+ mutex_destroy(&ccdc->ioctl_lock);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * omap3isp_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ */
+void omap3isp_ccdc_cleanup(struct isp_device *isp)
+{
+ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+ omap3isp_video_cleanup(&ccdc->video_out);
+ media_entity_cleanup(&ccdc->subdev.entity);
+
+ /* Free LSC requests. As the CCDC is stopped there's no active request,
+ * so only the pending request and the free queue need to be handled.
+ */
+ ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+ cancel_work_sync(&ccdc->lsc.table_work);
+ ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+
+ if (ccdc->fpc.fpcaddr != 0)
+ omap_iommu_vfree(isp->domain, isp->dev, ccdc->fpc.fpcaddr);
+
+ mutex_destroy(&ccdc->ioctl_lock);
+}
diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h
new file mode 100644
index 000000000000..a5da9e19edbf
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispccdc.h
@@ -0,0 +1,172 @@
+/*
+ * ispccdc.h
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 OMAP3_ISP_CCDC_H
+#define OMAP3_ISP_CCDC_H
+
+#include <linux/omap3isp.h>
+#include <linux/workqueue.h>
+
+#include "ispvideo.h"
+
+enum ccdc_input_entity {
+ CCDC_INPUT_NONE,
+ CCDC_INPUT_PARALLEL,
+ CCDC_INPUT_CSI2A,
+ CCDC_INPUT_CCP2B,
+ CCDC_INPUT_CSI2C
+};
+
+#define CCDC_OUTPUT_MEMORY (1 << 0)
+#define CCDC_OUTPUT_PREVIEW (1 << 1)
+#define CCDC_OUTPUT_RESIZER (1 << 2)
+
+#define OMAP3ISP_CCDC_NEVENTS 16
+
+enum ispccdc_lsc_state {
+ LSC_STATE_STOPPED = 0,
+ LSC_STATE_STOPPING = 1,
+ LSC_STATE_RUNNING = 2,
+ LSC_STATE_RECONFIG = 3,
+};
+
+struct ispccdc_lsc_config_req {
+ struct list_head list;
+ struct omap3isp_ccdc_lsc_config config;
+ unsigned char enable;
+ u32 table;
+ struct iovm_struct *iovm;
+};
+
+/*
+ * ispccdc_lsc - CCDC LSC parameters
+ * @update_config: Set when user changes config
+ * @request_enable: Whether LSC is requested to be enabled
+ * @config: LSC config set by user
+ * @update_table: Set when user provides a new LSC table to table_new
+ * @table_new: LSC table set by user, ISP address
+ * @table_inuse: LSC table currently in use, ISP address
+ */
+struct ispccdc_lsc {
+ enum ispccdc_lsc_state state;
+ struct work_struct table_work;
+
+ /* LSC queue of configurations */
+ spinlock_t req_lock;
+ struct ispccdc_lsc_config_req *request; /* requested configuration */
+ struct ispccdc_lsc_config_req *active; /* active configuration */
+ struct list_head free_queue; /* configurations for freeing */
+};
+
+#define CCDC_STOP_NOT_REQUESTED 0x00
+#define CCDC_STOP_REQUEST 0x01
+#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST)
+#define CCDC_STOP_CCDC_FINISHED 0x04
+#define CCDC_STOP_LSC_FINISHED 0x08
+#define CCDC_STOP_FINISHED \
+ (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
+
+#define CCDC_EVENT_VD1 0x10
+#define CCDC_EVENT_VD0 0x20
+#define CCDC_EVENT_LSC_DONE 0x40
+
+/* Sink and source CCDC pads */
+#define CCDC_PAD_SINK 0
+#define CCDC_PAD_SOURCE_OF 1
+#define CCDC_PAD_SOURCE_VP 2
+#define CCDC_PADS_NUM 3
+
+/*
+ * struct isp_ccdc_device - Structure for the CCDC module to store its own
+ * information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @crop: Active crop rectangle on the OF source pad
+ * @input: Active input
+ * @output: Active outputs
+ * @video_out: Output video node
+ * @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)
+ * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
+ * @blcomp: Black level compensation configuration
+ * @clamp: Optical-black or digital clamp configuration
+ * @fpc: Faulty pixels correction configuration
+ * @lsc: Lens shading compensation configuration
+ * @update: Bitmask of controls to update during the next interrupt
+ * @shadow_update: Controls update in progress by userspace
+ * @underrun: A buffer underrun occurred and a new buffer has been queued
+ * @state: Streaming state
+ * @lock: Serializes shadow_update with interrupt handler
+ * @wait: Wait queue used to stop the module
+ * @stopping: Stopping state
+ * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
+ */
+struct isp_ccdc_device {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[CCDC_PADS_NUM];
+ struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
+ struct v4l2_rect crop;
+
+ enum ccdc_input_entity input;
+ unsigned int output;
+ struct isp_video video_out;
+
+ unsigned int alaw:1,
+ lpf:1,
+ obclamp:1,
+ fpc_en:1;
+ struct omap3isp_ccdc_blcomp blcomp;
+ struct omap3isp_ccdc_bclamp clamp;
+ struct omap3isp_ccdc_fpc fpc;
+ struct ispccdc_lsc lsc;
+ unsigned int update;
+ unsigned int shadow_update;
+
+ unsigned int underrun:1;
+ enum isp_pipeline_stream_state state;
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ unsigned int stopping;
+ struct mutex ioctl_lock;
+};
+
+struct isp_device;
+
+int omap3isp_ccdc_init(struct isp_device *isp);
+void omap3isp_ccdc_cleanup(struct isp_device *isp);
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+ struct v4l2_device *vdev);
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
+
+int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
+int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
+void omap3isp_ccdc_restore_context(struct isp_device *isp);
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+ unsigned int *max_rate);
+
+#endif /* OMAP3_ISP_CCDC_H */
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 85f0de85f37c..85f0de85f37c 100644
--- a/drivers/media/video/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h
index 76d65f4576ef..76d65f4576ef 100644
--- a/drivers/media/video/omap3isp/ispccp2.h
+++ b/drivers/media/platform/omap3isp/ispccp2.h
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
new file mode 100644
index 000000000000..6a3ff792af7d
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -0,0 +1,1328 @@
+/*
+ * ispcsi2.c
+ *
+ * TI OMAP3 ISP - CSI2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 <media/v4l2-common.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/mm.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsi2.h"
+
+/*
+ * csi2_if_enable - Enable CSI2 Receiver interface.
+ * @enable: enable flag
+ *
+ */
+static void csi2_if_enable(struct isp_device *isp,
+ struct isp_csi2_device *csi2, u8 enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
+
+ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN,
+ enable ? ISPCSI2_CTRL_IF_EN : 0);
+
+ currctrl->if_enable = enable;
+}
+
+/*
+ * csi2_recv_config - CSI2 receiver module configuration.
+ * @currctrl: isp_csi2_ctrl_cfg structure
+ *
+ */
+static void csi2_recv_config(struct isp_device *isp,
+ struct isp_csi2_device *csi2,
+ struct isp_csi2_ctrl_cfg *currctrl)
+{
+ u32 reg;
+
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL);
+
+ if (currctrl->frame_mode)
+ reg |= ISPCSI2_CTRL_FRAME;
+ else
+ reg &= ~ISPCSI2_CTRL_FRAME;
+
+ if (currctrl->vp_clk_enable)
+ reg |= ISPCSI2_CTRL_VP_CLK_EN;
+ else
+ reg &= ~ISPCSI2_CTRL_VP_CLK_EN;
+
+ if (currctrl->vp_only_enable)
+ reg |= ISPCSI2_CTRL_VP_ONLY_EN;
+ else
+ reg &= ~ISPCSI2_CTRL_VP_ONLY_EN;
+
+ reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
+ reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
+
+ if (currctrl->ecc_enable)
+ reg |= ISPCSI2_CTRL_ECC_EN;
+ else
+ reg &= ~ISPCSI2_CTRL_ECC_EN;
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL);
+}
+
+static const unsigned int csi2_input_fmts[] = {
+ V4L2_MBUS_FMT_SGRBG10_1X10,
+ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SRGGB10_1X10,
+ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SGBRG10_1X10,
+ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+ V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+/* To set the format on the CSI2 requires a mapping function that takes
+ * the following inputs:
+ * - 3 different formats (at this time)
+ * - 2 destinations (mem, vp+mem) (vp only handled separately)
+ * - 2 decompression options (on, off)
+ * - 2 isp revisions (certain format must be handled differently on OMAP3630)
+ * Output should be CSI2 frame format code
+ * Array indices as follows: [format][dest][decompr][is_3630]
+ * Not all combinations are valid. 0 means invalid.
+ */
+static const u16 __csi2_fmt_map[3][2][2][2] = {
+ /* RAW10 formats */
+ {
+ /* Output to memory */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 },
+ /* DPCM decompression */
+ { 0, 0 },
+ },
+ /* Output to both */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_RAW10_EXP16_VP,
+ CSI2_PIX_FMT_RAW10_EXP16_VP },
+ /* DPCM decompression */
+ { 0, 0 },
+ },
+ },
+ /* RAW10 DPCM8 formats */
+ {
+ /* Output to memory */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 },
+ /* DPCM decompression */
+ { CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
+ CSI2_USERDEF_8BIT_DATA1_DPCM10 },
+ },
+ /* Output to both */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_RAW8_VP,
+ CSI2_PIX_FMT_RAW8_VP },
+ /* DPCM decompression */
+ { CSI2_PIX_FMT_RAW8_DPCM10_VP,
+ CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
+ },
+ },
+ /* YUYV8 2X8 formats */
+ {
+ /* Output to memory */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_YUV422_8BIT,
+ CSI2_PIX_FMT_YUV422_8BIT },
+ /* DPCM decompression */
+ { 0, 0 },
+ },
+ /* Output to both */
+ {
+ /* No DPCM decompression */
+ { CSI2_PIX_FMT_YUV422_8BIT_VP,
+ CSI2_PIX_FMT_YUV422_8BIT_VP },
+ /* DPCM decompression */
+ { 0, 0 },
+ },
+ },
+};
+
+/*
+ * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
+ * @csi2: ISP CSI2 device
+ *
+ * Returns CSI2 physical format id
+ */
+static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
+{
+ const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
+ int fmtidx, destidx, is_3630;
+
+ switch (fmt->code) {
+ case V4L2_MBUS_FMT_SGRBG10_1X10:
+ case V4L2_MBUS_FMT_SRGGB10_1X10:
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case V4L2_MBUS_FMT_SGBRG10_1X10:
+ fmtidx = 0;
+ break;
+ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+ fmtidx = 1;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ fmtidx = 2;
+ break;
+ default:
+ WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
+ fmt->code);
+ return 0;
+ }
+
+ if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
+ !(csi2->output & CSI2_OUTPUT_MEMORY)) {
+ /* Neither output enabled is a valid combination */
+ return CSI2_PIX_FMT_OTHERS;
+ }
+
+ /* If we need to skip frames at the beginning of the stream disable the
+ * video port to avoid sending the skipped frames to the CCDC.
+ */
+ destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
+ is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
+
+ return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630];
+}
+
+/*
+ * csi2_set_outaddr - Set memory address to save output image
+ * @csi2: Pointer to ISP CSI2a device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ */
+static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
+{
+ struct isp_device *isp = csi2->isp;
+ struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
+
+ ctx->ping_addr = addr;
+ ctx->pong_addr = addr;
+ isp_reg_writel(isp, ctx->ping_addr,
+ csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+ isp_reg_writel(isp, ctx->pong_addr,
+ csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
+ * be enabled by CSI2.
+ * @format_id: mapped format id
+ *
+ */
+static inline int is_usr_def_mapping(u32 format_id)
+{
+ return (format_id & 0x40) ? 1 : 0;
+}
+
+/*
+ * csi2_ctx_enable - Enable specified CSI2 context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @enable: enable
+ *
+ */
+static void csi2_ctx_enable(struct isp_device *isp,
+ struct isp_csi2_device *csi2, u8 ctxnum, u8 enable)
+{
+ struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
+ unsigned int skip = 0;
+ u32 reg;
+
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+
+ if (enable) {
+ if (csi2->frame_skip)
+ skip = csi2->frame_skip;
+ else if (csi2->output & CSI2_OUTPUT_MEMORY)
+ skip = 1;
+
+ reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK;
+ reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK
+ | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
+ | ISPCSI2_CTX_CTRL1_CTX_EN;
+ } else {
+ reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN;
+ }
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+ ctx->enabled = enable;
+}
+
+/*
+ * csi2_ctx_config - CSI2 context configuration.
+ * @ctx: context configuration
+ *
+ */
+static void csi2_ctx_config(struct isp_device *isp,
+ struct isp_csi2_device *csi2,
+ struct isp_csi2_ctx_cfg *ctx)
+{
+ u32 reg;
+
+ /* Set up CSI2_CTx_CTRL1 */
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+ if (ctx->eof_enabled)
+ reg |= ISPCSI2_CTX_CTRL1_EOF_EN;
+ else
+ reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN;
+
+ if (ctx->eol_enabled)
+ reg |= ISPCSI2_CTX_CTRL1_EOL_EN;
+ else
+ reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN;
+
+ if (ctx->checksum_enabled)
+ reg |= ISPCSI2_CTX_CTRL1_CS_EN;
+ else
+ reg &= ~ISPCSI2_CTX_CTRL1_CS_EN;
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+ /* Set up CSI2_CTx_CTRL2 */
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+ reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
+ reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+
+ reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
+ reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT;
+
+ if (ctx->dpcm_decompress) {
+ if (ctx->dpcm_predictor)
+ reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED;
+ else
+ reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED;
+ }
+
+ if (is_usr_def_mapping(ctx->format_id)) {
+ reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK;
+ reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
+ }
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+ /* Set up CSI2_CTx_CTRL3 */
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+ reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
+ reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+
+ /* Set up CSI2_CTx_DAT_OFST */
+ reg = isp_reg_readl(isp, csi2->regs1,
+ ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+ reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
+ reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
+ isp_reg_writel(isp, reg, csi2->regs1,
+ ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+
+ isp_reg_writel(isp, ctx->ping_addr,
+ csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+
+ isp_reg_writel(isp, ctx->pong_addr,
+ csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * csi2_timing_config - CSI2 timing configuration.
+ * @timing: csi2_timing_cfg structure
+ */
+static void csi2_timing_config(struct isp_device *isp,
+ struct isp_csi2_device *csi2,
+ struct isp_csi2_timing_cfg *timing)
+{
+ u32 reg;
+
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING);
+
+ if (timing->force_rx_mode)
+ reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+ else
+ reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+
+ if (timing->stop_state_16x)
+ reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+ else
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+
+ if (timing->stop_state_4x)
+ reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+ else
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum);
+ reg |= timing->stop_state_counter <<
+ ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum);
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING);
+}
+
+/*
+ * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
+ * @enable: Enable/disable CSI2 Context interrupts
+ */
+static void csi2_irq_ctx_set(struct isp_device *isp,
+ struct isp_csi2_device *csi2, int enable)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1,
+ ISPCSI2_CTX_IRQSTATUS(i));
+ if (enable)
+ isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+ ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
+ else
+ isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+ ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
+ }
+}
+
+/*
+ * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
+ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
+ */
+static void csi2_irq_complexio1_set(struct isp_device *isp,
+ struct isp_csi2_device *csi2, int enable)
+{
+ u32 reg;
+ reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT |
+ ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER |
+ ISPCSI2_PHY_IRQENABLE_STATEULPM5 |
+ ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 |
+ ISPCSI2_PHY_IRQENABLE_ERRESC5 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 |
+ ISPCSI2_PHY_IRQENABLE_STATEULPM4 |
+ ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 |
+ ISPCSI2_PHY_IRQENABLE_ERRESC4 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 |
+ ISPCSI2_PHY_IRQENABLE_STATEULPM3 |
+ ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 |
+ ISPCSI2_PHY_IRQENABLE_ERRESC3 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 |
+ ISPCSI2_PHY_IRQENABLE_STATEULPM2 |
+ ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 |
+ ISPCSI2_PHY_IRQENABLE_ERRESC2 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 |
+ ISPCSI2_PHY_IRQENABLE_STATEULPM1 |
+ ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 |
+ ISPCSI2_PHY_IRQENABLE_ERRESC1 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 |
+ ISPCSI2_PHY_IRQENABLE_ERRSOTHS1;
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+ if (enable)
+ reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+ else
+ reg = 0;
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+}
+
+/*
+ * csi2_irq_status_set - Enables CSI2 Status IRQs.
+ * @enable: Enable/disable CSI2 Status interrupts
+ */
+static void csi2_irq_status_set(struct isp_device *isp,
+ struct isp_csi2_device *csi2, int enable)
+{
+ u32 reg;
+ reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
+ ISPCSI2_IRQSTATUS_CONTEXT(0);
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS);
+ if (enable)
+ reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE);
+ else
+ reg = 0;
+
+ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE);
+}
+
+/*
+ * omap3isp_csi2_reset - Resets the CSI2 module.
+ *
+ * Must be called with the phy lock held.
+ *
+ * Returns 0 if successful, or -EBUSY if power command didn't respond.
+ */
+int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
+{
+ struct isp_device *isp = csi2->isp;
+ u8 soft_reset_retries = 0;
+ u32 reg;
+ int i;
+
+ if (!csi2->available)
+ return -ENODEV;
+
+ if (csi2->phy->phy_in_use)
+ return -EBUSY;
+
+ isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+ ISPCSI2_SYSCONFIG_SOFT_RESET);
+
+ do {
+ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) &
+ ISPCSI2_SYSSTATUS_RESET_DONE;
+ if (reg == ISPCSI2_SYSSTATUS_RESET_DONE)
+ break;
+ soft_reset_retries++;
+ if (soft_reset_retries < 5)
+ udelay(100);
+ } while (soft_reset_retries < 5);
+
+ if (soft_reset_retries == 5) {
+ printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
+ return -EBUSY;
+ }
+
+ if (isp->revision == ISP_REVISION_15_0)
+ isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG,
+ ISPCSI2_PHY_CFG_RESET_CTRL);
+
+ i = 100;
+ do {
+ reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1)
+ & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK;
+ if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK)
+ break;
+ udelay(100);
+ } while (--i > 0);
+
+ if (i == 0) {
+ printk(KERN_ERR
+ "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+ return -EBUSY;
+ }
+
+ if (isp->autoidle)
+ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+ ISPCSI2_SYSCONFIG_AUTO_IDLE,
+ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART |
+ ((isp->revision == ISP_REVISION_15_0) ?
+ ISPCSI2_SYSCONFIG_AUTO_IDLE : 0));
+ else
+ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+ ISPCSI2_SYSCONFIG_AUTO_IDLE,
+ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO);
+
+ return 0;
+}
+
+static int csi2_configure(struct isp_csi2_device *csi2)
+{
+ const struct isp_v4l2_subdevs_group *pdata;
+ struct isp_device *isp = csi2->isp;
+ struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
+ struct v4l2_subdev *sensor;
+ struct media_pad *pad;
+
+ /*
+ * CSI2 fields that can be updated while the context has
+ * been enabled or the interface has been enabled are not
+ * updated dynamically currently. So we do not allow to
+ * reconfigure if either has been enabled
+ */
+ if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
+ return -EBUSY;
+
+ pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
+ sensor = media_entity_to_v4l2_subdev(pad->entity);
+ pdata = sensor->host_priv;
+
+ csi2->frame_skip = 0;
+ v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
+
+ csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
+ csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
+ csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
+
+ timing->ionum = 1;
+ timing->force_rx_mode = 1;
+ timing->stop_state_16x = 1;
+ timing->stop_state_4x = 1;
+ timing->stop_state_counter = 0x1FF;
+
+ /*
+ * The CSI2 receiver can't do any format conversion except DPCM
+ * decompression, so every set_format call configures both pads
+ * and enables DPCM decompression as a special case:
+ */
+ if (csi2->formats[CSI2_PAD_SINK].code !=
+ csi2->formats[CSI2_PAD_SOURCE].code)
+ csi2->dpcm_decompress = true;
+ else
+ csi2->dpcm_decompress = false;
+
+ csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
+
+ if (csi2->video_out.bpl_padding == 0)
+ csi2->contexts[0].data_offset = 0;
+ else
+ csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
+
+ /*
+ * Enable end of frame and end of line signals generation for
+ * context 0. These signals are generated from CSI2 receiver to
+ * qualify the last pixel of a frame and the last pixel of a line.
+ * Without enabling the signals CSI2 receiver writes data to memory
+ * beyond buffer size and/or data line offset is not handled correctly.
+ */
+ csi2->contexts[0].eof_enabled = 1;
+ csi2->contexts[0].eol_enabled = 1;
+
+ csi2_irq_complexio1_set(isp, csi2, 1);
+ csi2_irq_ctx_set(isp, csi2, 1);
+ csi2_irq_status_set(isp, csi2, 1);
+
+ /* Set configuration (timings, format and links) */
+ csi2_timing_config(isp, csi2, timing);
+ csi2_recv_config(isp, csi2, &csi2->ctrl);
+ csi2_ctx_config(isp, csi2, &csi2->contexts[0]);
+
+ return 0;
+}
+
+/*
+ * csi2_print_status - Prints CSI2 debug information.
+ */
+#define CSI2_PRINT_REGISTER(isp, regs, name)\
+ dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \
+ isp_reg_readl(isp, regs, ISPCSI2_##name))
+
+static void csi2_print_status(struct isp_csi2_device *csi2)
+{
+ struct isp_device *isp = csi2->isp;
+
+ if (!csi2->available)
+ return;
+
+ dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n");
+
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING);
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0));
+ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0));
+
+ dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * csi2_isr_buffer - Does buffer handling at end-of-frame
+ * when writing to memory.
+ */
+static void csi2_isr_buffer(struct isp_csi2_device *csi2)
+{
+ struct isp_device *isp = csi2->isp;
+ struct isp_buffer *buffer;
+
+ csi2_ctx_enable(isp, csi2, 0, 0);
+
+ buffer = omap3isp_video_buffer_next(&csi2->video_out);
+
+ /*
+ * Let video queue operation restart engine if there is an underrun
+ * condition.
+ */
+ if (buffer == NULL)
+ return;
+
+ csi2_set_outaddr(csi2, buffer->isp_addr);
+ csi2_ctx_enable(isp, csi2, 0, 1);
+}
+
+static void csi2_isr_ctx(struct isp_csi2_device *csi2,
+ struct isp_csi2_ctx_cfg *ctx)
+{
+ struct isp_device *isp = csi2->isp;
+ unsigned int n = ctx->ctxnum;
+ u32 status;
+
+ status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+ isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+
+ if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
+ return;
+
+ /* Skip interrupts until we reach the frame skip count. The CSI2 will be
+ * automatically disabled, as the frame skip count has been programmed
+ * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
+ *
+ * It would have been nice to rely on the FRAME_NUMBER interrupt instead
+ * but it turned out that the interrupt is only generated when the CSI2
+ * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
+ * correctly and reaches 0 when data is forwarded to the video port only
+ * but no interrupt arrives). Maybe a CSI2 hardware bug.
+ */
+ if (csi2->frame_skip) {
+ csi2->frame_skip--;
+ if (csi2->frame_skip == 0) {
+ ctx->format_id = csi2_ctx_map_format(csi2);
+ csi2_ctx_config(isp, csi2, ctx);
+ csi2_ctx_enable(isp, csi2, n, 1);
+ }
+ return;
+ }
+
+ if (csi2->output & CSI2_OUTPUT_MEMORY)
+ csi2_isr_buffer(csi2);
+}
+
+/*
+ * omap3isp_csi2_isr - CSI2 interrupt handling.
+ */
+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;
+
+ if (!csi2->available)
+ return;
+
+ csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
+ isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
+
+ /* Failure Cases */
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
+ cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1,
+ ISPCSI2_PHY_IRQSTATUS);
+ isp_reg_writel(isp, cpxio1_irqstatus,
+ csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+ dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
+ "%x\n", cpxio1_irqstatus);
+ pipe->error = true;
+ }
+
+ if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
+ dev_dbg(isp->dev, "CSI2 Err:"
+ " OCP:%d,"
+ " Short_pack:%d,"
+ " ECC:%d,"
+ " CPXIO2:%d,"
+ " FIFO_OVF:%d,"
+ "\n",
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
+ pipe->error = true;
+ }
+
+ if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+ return;
+
+ /* Successful cases */
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
+ csi2_isr_ctx(csi2, &csi2->contexts[0]);
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
+ dev_dbg(isp->dev, "CSI2: ECC correction done\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+/*
+ * csi2_queue - Queues the first buffer when using memory output
+ * @video: The video node
+ * @buffer: buffer to queue
+ */
+static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+ struct isp_device *isp = video->isp;
+ struct isp_csi2_device *csi2 = &isp->isp_csi2a;
+
+ csi2_set_outaddr(csi2, buffer->isp_addr);
+
+ /*
+ * If streaming was enabled before there was a buffer queued
+ * or underrun happened in the ISR, the hardware was not enabled
+ * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set.
+ * Enable it now.
+ */
+ if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+ /* Enable / disable context 0 and IRQs */
+ csi2_if_enable(isp, csi2, 1);
+ csi2_ctx_enable(isp, csi2, 0, 1);
+ isp_video_dmaqueue_flags_clr(&csi2->video_out);
+ }
+
+ return 0;
+}
+
+static const struct isp_video_operations csi2_ispvideo_ops = {
+ .queue = csi2_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &csi2->formats[pad];
+}
+
+static void
+csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+ unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ enum v4l2_mbus_pixelcode pixelcode;
+ struct v4l2_mbus_framefmt *format;
+ const struct isp_format_info *info;
+ unsigned int i;
+
+ switch (pad) {
+ case CSI2_PAD_SINK:
+ /* Clamp the width and height to valid range (1-8191). */
+ for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
+ if (fmt->code == csi2_input_fmts[i])
+ break;
+ }
+
+ /* If not found, use SGRBG10 as default */
+ if (i >= ARRAY_SIZE(csi2_input_fmts))
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ fmt->width = clamp_t(u32, fmt->width, 1, 8191);
+ fmt->height = clamp_t(u32, fmt->height, 1, 8191);
+ break;
+
+ case CSI2_PAD_SOURCE:
+ /* Source format same as sink format, except for DPCM
+ * compression.
+ */
+ pixelcode = fmt->code;
+ format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
+ memcpy(fmt, format, sizeof(*fmt));
+
+ /*
+ * Only Allow DPCM decompression, and check that the
+ * pattern is preserved
+ */
+ info = omap3isp_video_format_info(fmt->code);
+ if (info->uncompressed == pixelcode)
+ fmt->code = pixelcode;
+ break;
+ }
+
+ /* RGB, non-interlaced */
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * csi2_enum_mbus_code - Handle pixel format enumeration
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+ const struct isp_format_info *info;
+
+ if (code->pad == CSI2_PAD_SINK) {
+ if (code->index >= ARRAY_SIZE(csi2_input_fmts))
+ return -EINVAL;
+
+ code->code = csi2_input_fmts[code->index];
+ } else {
+ format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
+ V4L2_SUBDEV_FORMAT_TRY);
+ switch (code->index) {
+ case 0:
+ /* Passthrough sink pad code */
+ code->code = format->code;
+ break;
+ case 1:
+ /* Uncompressed code */
+ info = omap3isp_video_format_info(format->code);
+ if (info->uncompressed == format->code)
+ return -EINVAL;
+
+ code->code = info->uncompressed;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int csi2_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt format;
+
+ if (fse->index != 0)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = 1;
+ format.height = 1;
+ csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->min_width = format.width;
+ fse->min_height = format.height;
+
+ if (format.code != fse->code)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = -1;
+ format.height = -1;
+ csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->max_width = format.width;
+ fse->max_height = format.height;
+
+ return 0;
+}
+
+/*
+ * csi2_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+/*
+ * csi2_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+
+ /* Propagate the format from sink to source */
+ if (fmt->pad == CSI2_PAD_SINK) {
+ format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
+ fmt->which);
+ *format = fmt->format;
+ csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
+ }
+
+ return 0;
+}
+
+/*
+ * csi2_init_formats - Initialize formats on all pads
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+ format.pad = CSI2_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.width = 4096;
+ format.format.height = 4096;
+ csi2_set_format(sd, fh, &format);
+
+ return 0;
+}
+
+/*
+ * csi2_set_stream - Enable/Disable streaming on the CSI2 module
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @enable: ISP pipeline stream state
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct isp_device *isp = csi2->isp;
+ struct isp_video *video_out = &csi2->video_out;
+
+ switch (enable) {
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ if (omap3isp_csiphy_acquire(csi2->phy) < 0)
+ return -ENODEV;
+ if (csi2->output & CSI2_OUTPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+ csi2_configure(csi2);
+ csi2_print_status(csi2);
+
+ /*
+ * When outputting to memory with no buffer available, let the
+ * buffer queue handler start the hardware. A DMA queue flag
+ * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+ * a buffer available.
+ */
+ if (csi2->output & CSI2_OUTPUT_MEMORY &&
+ !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED))
+ break;
+ /* Enable context 0 and IRQs */
+ atomic_set(&csi2->stopping, 0);
+ csi2_ctx_enable(isp, csi2, 0, 1);
+ csi2_if_enable(isp, csi2, 1);
+ isp_video_dmaqueue_flags_clr(video_out);
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ if (csi2->state == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+ if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait,
+ &csi2->stopping))
+ dev_dbg(isp->dev, "%s: module stop timeout.\n",
+ sd->name);
+ csi2_ctx_enable(isp, csi2, 0, 0);
+ csi2_if_enable(isp, csi2, 0);
+ csi2_irq_ctx_set(isp, csi2, 0);
+ omap3isp_csiphy_release(csi2->phy);
+ isp_video_dmaqueue_flags_clr(video_out);
+ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+ break;
+ }
+
+ csi2->state = enable;
+ return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops csi2_video_ops = {
+ .s_stream = csi2_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
+ .enum_mbus_code = csi2_enum_mbus_code,
+ .enum_frame_size = csi2_enum_frame_size,
+ .get_fmt = csi2_get_format,
+ .set_fmt = csi2_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops csi2_ops = {
+ .video = &csi2_video_ops,
+ .pad = &csi2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+ .open = csi2_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * csi2_link_setup - Setup CSI2 connections.
+ * @entity : Pointer to media entity structure
+ * @local : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags : Link flags
+ * return -EINVAL or zero on success
+ */
+static int csi2_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+ struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+
+ /*
+ * The ISP core doesn't support pipelines with multiple video outputs.
+ * Revisit this when it will be implemented, and return -EBUSY for now.
+ */
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (csi2->output & ~CSI2_OUTPUT_MEMORY)
+ return -EBUSY;
+ csi2->output |= CSI2_OUTPUT_MEMORY;
+ } else {
+ csi2->output &= ~CSI2_OUTPUT_MEMORY;
+ }
+ break;
+
+ case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (csi2->output & ~CSI2_OUTPUT_CCDC)
+ return -EBUSY;
+ csi2->output |= CSI2_OUTPUT_CCDC;
+ } else {
+ csi2->output &= ~CSI2_OUTPUT_CCDC;
+ }
+ break;
+
+ default:
+ /* Link from camera to CSI2 is fixed... */
+ return -EINVAL;
+ }
+
+ ctrl->vp_only_enable =
+ (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true;
+ ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC);
+
+ return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations csi2_media_ops = {
+ .link_setup = csi2_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
+{
+ v4l2_device_unregister_subdev(&csi2->subdev);
+ omap3isp_video_unregister(&csi2->video_out);
+}
+
+int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
+ struct v4l2_device *vdev)
+{
+ int ret;
+
+ /* Register the subdev and video nodes. */
+ ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&csi2->video_out, vdev);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ omap3isp_csi2_unregister_entities(csi2);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CSI2 initialisation and cleanup
+ */
+
+/*
+ * csi2_init_entities - Initialize subdev and media entity.
+ * @csi2: Pointer to csi2 structure.
+ * return -ENOMEM or zero on success
+ */
+static int csi2_init_entities(struct isp_csi2_device *csi2)
+{
+ struct v4l2_subdev *sd = &csi2->subdev;
+ struct media_pad *pads = csi2->pads;
+ struct media_entity *me = &sd->entity;
+ int ret;
+
+ v4l2_subdev_init(sd, &csi2_ops);
+ sd->internal_ops = &csi2_internal_ops;
+ strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
+
+ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
+ v4l2_set_subdevdata(sd, csi2);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+ me->ops = &csi2_media_ops;
+ ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+ if (ret < 0)
+ return ret;
+
+ csi2_init_formats(sd, NULL);
+
+ /* Video device node */
+ csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ csi2->video_out.ops = &csi2_ispvideo_ops;
+ csi2->video_out.bpl_alignment = 32;
+ csi2->video_out.bpl_zero_padding = 1;
+ csi2->video_out.bpl_max = 0x1ffe0;
+ csi2->video_out.isp = csi2->isp;
+ csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+ ret = omap3isp_video_init(&csi2->video_out, "CSI2a");
+ if (ret < 0)
+ goto error_video;
+
+ /* Connect the CSI2 subdev to the video node. */
+ ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
+ &csi2->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ goto error_link;
+
+ return 0;
+
+error_link:
+ omap3isp_video_cleanup(&csi2->video_out);
+error_video:
+ media_entity_cleanup(&csi2->subdev.entity);
+ return ret;
+}
+
+/*
+ * omap3isp_csi2_init - Routine for module driver init
+ */
+int omap3isp_csi2_init(struct isp_device *isp)
+{
+ struct isp_csi2_device *csi2a = &isp->isp_csi2a;
+ struct isp_csi2_device *csi2c = &isp->isp_csi2c;
+ int ret;
+
+ csi2a->isp = isp;
+ csi2a->available = 1;
+ csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1;
+ csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2;
+ csi2a->phy = &isp->isp_csiphy2;
+ csi2a->state = ISP_PIPELINE_STREAM_STOPPED;
+ init_waitqueue_head(&csi2a->wait);
+
+ ret = csi2_init_entities(csi2a);
+ if (ret < 0)
+ return ret;
+
+ if (isp->revision == ISP_REVISION_15_0) {
+ csi2c->isp = isp;
+ csi2c->available = 1;
+ csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1;
+ csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2;
+ csi2c->phy = &isp->isp_csiphy1;
+ csi2c->state = ISP_PIPELINE_STREAM_STOPPED;
+ init_waitqueue_head(&csi2c->wait);
+ }
+
+ return 0;
+}
+
+/*
+ * omap3isp_csi2_cleanup - Routine for module driver cleanup
+ */
+void omap3isp_csi2_cleanup(struct isp_device *isp)
+{
+ struct isp_csi2_device *csi2a = &isp->isp_csi2a;
+
+ omap3isp_video_cleanup(&csi2a->video_out);
+ media_entity_cleanup(&csi2a->subdev.entity);
+}
diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h
index c57729b7e86e..c57729b7e86e 100644
--- a/drivers/media/video/omap3isp/ispcsi2.h
+++ b/drivers/media/platform/omap3isp/ispcsi2.h
diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index 348f67ebbbc9..348f67ebbbc9 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h
index e93a661e65d9..e93a661e65d9 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.h
+++ b/drivers/media/platform/omap3isp/ispcsiphy.h
diff --git a/drivers/media/video/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h
index fb09fd4ca755..fb09fd4ca755 100644
--- a/drivers/media/video/omap3isp/isph3a.h
+++ b/drivers/media/platform/omap3isp/isph3a.h
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
new file mode 100644
index 000000000000..036e9961d027
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -0,0 +1,368 @@
+/*
+ * isph3a.c
+ *
+ * TI OMAP3 ISP - H3A module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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/slab.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+/*
+ * h3a_aewb_update_regs - Helper function to update h3a registers.
+ */
+static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
+{
+ struct omap3isp_h3a_aewb_config *conf = priv;
+ u32 pcr;
+ u32 win1;
+ u32 start;
+ u32 blk;
+ u32 subwin;
+
+ if (aewb->state == ISPSTAT_DISABLED)
+ return;
+
+ isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
+
+ if (!aewb->update)
+ return;
+
+ /* Converting config metadata into reg values */
+ pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
+ pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
+
+ win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
+ win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
+ win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
+ win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
+
+ start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
+ start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
+
+ blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
+ blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
+
+ subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
+ ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
+ subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
+ ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
+
+ isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
+ isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWINSTART);
+ isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
+ isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWSUBWIN);
+ isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ISPH3A_PCR_AEW_MASK, pcr);
+
+ aewb->update = 0;
+ aewb->config_counter += aewb->inc_config;
+ aewb->inc_config = 0;
+ aewb->buf_size = conf->buf_size;
+}
+
+static void h3a_aewb_enable(struct ispstat *aewb, int enable)
+{
+ if (enable) {
+ isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ISPH3A_PCR_AEW_EN);
+ omap3isp_subclk_enable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
+ } else {
+ isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ISPH3A_PCR_AEW_EN);
+ omap3isp_subclk_disable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
+ }
+}
+
+static int h3a_aewb_busy(struct ispstat *aewb)
+{
+ return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+ & ISPH3A_PCR_BUSYAEAWB;
+}
+
+static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
+{
+ /* Number of configured windows + extra row for black data */
+ u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
+
+ /*
+ * Unsaturated block counts for each 8 windows.
+ * 1 extra for the last (win_count % 8) windows if win_count is not
+ * divisible by 8.
+ */
+ win_count += (win_count + 7) / 8;
+
+ return win_count * AEWB_PACKET_SIZE;
+}
+
+static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
+{
+ struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+ u32 buf_size;
+
+ if (unlikely(user_cfg->saturation_limit >
+ OMAP3ISP_AEWB_MAX_SATURATION_LIM))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+ user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+ user_cfg->win_height & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
+ user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
+ user_cfg->win_width & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
+ user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
+ user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+ user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+ user_cfg->blk_win_height & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+ user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+ user_cfg->subsample_ver_inc & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+ user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+ user_cfg->subsample_hor_inc & 0x01))
+ return -EINVAL;
+
+ buf_size = h3a_aewb_get_buf_size(user_cfg);
+ if (buf_size > user_cfg->buf_size)
+ user_cfg->buf_size = buf_size;
+ else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
+ user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
+
+ return 0;
+}
+
+/*
+ * h3a_aewb_set_params - Helper function to check & store user given params.
+ * @new_conf: Pointer to AE and AWB parameters struct.
+ *
+ * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
+ * program them during ISR.
+ */
+static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
+{
+ struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+ struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
+ int update = 0;
+
+ if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
+ cur_cfg->saturation_limit = user_cfg->saturation_limit;
+ update = 1;
+ }
+ if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+ cur_cfg->alaw_enable = user_cfg->alaw_enable;
+ update = 1;
+ }
+ if (cur_cfg->win_height != user_cfg->win_height) {
+ cur_cfg->win_height = user_cfg->win_height;
+ update = 1;
+ }
+ if (cur_cfg->win_width != user_cfg->win_width) {
+ cur_cfg->win_width = user_cfg->win_width;
+ update = 1;
+ }
+ if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
+ cur_cfg->ver_win_count = user_cfg->ver_win_count;
+ update = 1;
+ }
+ if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
+ cur_cfg->hor_win_count = user_cfg->hor_win_count;
+ update = 1;
+ }
+ if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
+ cur_cfg->ver_win_start = user_cfg->ver_win_start;
+ update = 1;
+ }
+ if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
+ cur_cfg->hor_win_start = user_cfg->hor_win_start;
+ update = 1;
+ }
+ if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
+ cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
+ update = 1;
+ }
+ if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
+ cur_cfg->blk_win_height = user_cfg->blk_win_height;
+ update = 1;
+ }
+ if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
+ cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
+ update = 1;
+ }
+ if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
+ cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
+ update = 1;
+ }
+
+ if (update || !aewb->configured) {
+ aewb->inc_config++;
+ aewb->update = 1;
+ cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
+ }
+}
+
+static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+ switch (cmd) {
+ case VIDIOC_OMAP3ISP_AEWB_CFG:
+ return omap3isp_stat_config(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_REQ:
+ return omap3isp_stat_request_statistics(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_EN: {
+ unsigned long *en = arg;
+ return omap3isp_stat_enable(stat, !!*en);
+ }
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static const struct ispstat_ops h3a_aewb_ops = {
+ .validate_params = h3a_aewb_validate_params,
+ .set_params = h3a_aewb_set_params,
+ .setup_regs = h3a_aewb_setup_regs,
+ .enable = h3a_aewb_enable,
+ .busy = h3a_aewb_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
+ .ioctl = h3a_aewb_ioctl,
+ .subscribe_event = omap3isp_stat_subscribe_event,
+ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
+ .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
+ .core = &h3a_aewb_subdev_core_ops,
+ .video = &h3a_aewb_subdev_video_ops,
+};
+
+/*
+ * omap3isp_h3a_aewb_init - Module Initialisation.
+ */
+int omap3isp_h3a_aewb_init(struct isp_device *isp)
+{
+ struct ispstat *aewb = &isp->isp_aewb;
+ struct omap3isp_h3a_aewb_config *aewb_cfg;
+ struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
+ int ret;
+
+ aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
+ if (!aewb_cfg)
+ return -ENOMEM;
+
+ memset(aewb, 0, sizeof(*aewb));
+ aewb->ops = &h3a_aewb_ops;
+ aewb->priv = aewb_cfg;
+ aewb->dma_ch = -1;
+ aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
+ aewb->isp = isp;
+
+ /* Set recover state configuration */
+ aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
+ if (!aewb_recover_cfg) {
+ dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
+ "recover configuration.\n");
+ ret = -ENOMEM;
+ goto err_recover_alloc;
+ }
+
+ aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
+ aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+ aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
+ aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
+ aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
+ aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
+ aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
+ aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+ aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+ aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+
+ if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
+ dev_err(aewb->isp->dev, "AEWB: recover configuration is "
+ "invalid.\n");
+ ret = -EINVAL;
+ goto err_conf;
+ }
+
+ aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
+ aewb->recover_priv = aewb_recover_cfg;
+
+ ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
+ if (ret)
+ goto err_conf;
+
+ return 0;
+
+err_conf:
+ kfree(aewb_recover_cfg);
+err_recover_alloc:
+ kfree(aewb_cfg);
+
+ return ret;
+}
+
+/*
+ * omap3isp_h3a_aewb_cleanup - Module exit.
+ */
+void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
+{
+ kfree(isp->isp_aewb.priv);
+ kfree(isp->isp_aewb.recover_priv);
+ omap3isp_stat_cleanup(&isp->isp_aewb);
+}
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
new file mode 100644
index 000000000000..42ccce318d5d
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -0,0 +1,423 @@
+/*
+ * isph3a_af.c
+ *
+ * TI OMAP3 ISP - H3A AF module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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
+ */
+
+/* Linux specific include files */
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+#define IS_OUT_OF_BOUNDS(value, min, max) \
+ (((value) < (min)) || ((value) > (max)))
+
+static void h3a_af_setup_regs(struct ispstat *af, void *priv)
+{
+ struct omap3isp_h3a_af_config *conf = priv;
+ u32 pcr;
+ u32 pax1;
+ u32 pax2;
+ u32 paxstart;
+ u32 coef;
+ u32 base_coef_set0;
+ u32 base_coef_set1;
+ int index;
+
+ if (af->state == ISPSTAT_DISABLED)
+ return;
+
+ isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AFBUFST);
+
+ if (!af->update)
+ return;
+
+ /* Configure Hardware Registers */
+ pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;
+ /* Set height in AFPAX1 */
+ pax1 |= (conf->paxel.height >> 1) - 1;
+ isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
+
+ /* Configure AFPAX2 Register */
+ /* Set Line Increment in AFPAX2 Register */
+ pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;
+ /* Set Vertical Count */
+ pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;
+ /* Set Horizontal Count */
+ pax2 |= (conf->paxel.h_cnt - 1);
+ isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
+
+ /* Configure PAXSTART Register */
+ /*Configure Horizontal Start */
+ paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;
+ /* Configure Vertical Start */
+ paxstart |= conf->paxel.v_start;
+ isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AFPAXSTART);
+
+ /*SetIIRSH Register */
+ isp_reg_writel(af->isp, conf->iir.h_start,
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
+
+ base_coef_set0 = ISPH3A_AFCOEF010;
+ base_coef_set1 = ISPH3A_AFCOEF110;
+ for (index = 0; index <= 8; index += 2) {
+ /*Set IIR Filter0 Coefficients */
+ coef = 0;
+ coef |= conf->iir.coeff_set0[index];
+ coef |= conf->iir.coeff_set0[index + 1] <<
+ AF_COEF_SHIFT;
+ isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+ base_coef_set0);
+ base_coef_set0 += AFCOEF_OFFSET;
+
+ /*Set IIR Filter1 Coefficients */
+ coef = 0;
+ coef |= conf->iir.coeff_set1[index];
+ coef |= conf->iir.coeff_set1[index + 1] <<
+ AF_COEF_SHIFT;
+ isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+ base_coef_set1);
+ base_coef_set1 += AFCOEF_OFFSET;
+ }
+ /* set AFCOEF0010 Register */
+ isp_reg_writel(af->isp, conf->iir.coeff_set0[10],
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
+ /* set AFCOEF1010 Register */
+ isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
+
+ /* PCR Register */
+ /* Set RGB Position */
+ pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;
+ /* Set Accumulator Mode */
+ if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)
+ pcr |= AF_FVMODE;
+ /* Set A-law */
+ if (conf->alaw_enable)
+ pcr |= AF_ALAW_EN;
+ /* HMF Configurations */
+ if (conf->hmf.enable) {
+ /* Enable HMF */
+ pcr |= AF_MED_EN;
+ /* Set Median Threshold */
+ pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;
+ }
+ /* Set PCR Register */
+ isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ AF_PCR_MASK, pcr);
+
+ af->update = 0;
+ af->config_counter += af->inc_config;
+ af->inc_config = 0;
+ af->buf_size = conf->buf_size;
+}
+
+static void h3a_af_enable(struct ispstat *af, int enable)
+{
+ if (enable) {
+ isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ISPH3A_PCR_AF_EN);
+ omap3isp_subclk_enable(af->isp, OMAP3_ISP_SUBCLK_AF);
+ } else {
+ isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ISPH3A_PCR_AF_EN);
+ omap3isp_subclk_disable(af->isp, OMAP3_ISP_SUBCLK_AF);
+ }
+}
+
+static int h3a_af_busy(struct ispstat *af)
+{
+ return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+ & ISPH3A_PCR_BUSYAF;
+}
+
+static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)
+{
+ return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;
+}
+
+/* Function to check paxel parameters */
+static int h3a_af_validate_params(struct ispstat *af, void *new_conf)
+{
+ struct omap3isp_h3a_af_config *user_cfg = new_conf;
+ struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;
+ struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;
+ int index;
+ u32 buf_size;
+
+ /* Check horizontal Count */
+ if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,
+ OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,
+ OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))
+ return -EINVAL;
+
+ /* Check Vertical Count */
+ if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
+ OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,
+ OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))
+ return -EINVAL;
+
+ if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,
+ OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||
+ paxel_cfg->height % 2)
+ return -EINVAL;
+
+ /* Check width */
+ if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,
+ OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||
+ paxel_cfg->width % 2)
+ return -EINVAL;
+
+ /* Check Line Increment */
+ if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
+ OMAP3ISP_AF_PAXEL_INCREMENT_MIN,
+ OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||
+ paxel_cfg->line_inc % 2)
+ return -EINVAL;
+
+ /* Check Horizontal Start */
+ if ((paxel_cfg->h_start < iir_cfg->h_start) ||
+ IS_OUT_OF_BOUNDS(paxel_cfg->h_start,
+ OMAP3ISP_AF_PAXEL_HZSTART_MIN,
+ OMAP3ISP_AF_PAXEL_HZSTART_MAX))
+ return -EINVAL;
+
+ /* Check IIR */
+ for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+ if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)
+ return -EINVAL;
+
+ if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)
+ return -EINVAL;
+ }
+
+ if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,
+ OMAP3ISP_AF_IIRSH_MAX))
+ return -EINVAL;
+
+ /* Hack: If paxel size is 12, the 10th AF window may be corrupted */
+ if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&
+ (paxel_cfg->width * paxel_cfg->height == 12))
+ return -EINVAL;
+
+ buf_size = h3a_af_get_buf_size(user_cfg);
+ if (buf_size > user_cfg->buf_size)
+ /* User buf_size request wasn't enough */
+ user_cfg->buf_size = buf_size;
+ else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)
+ user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;
+
+ return 0;
+}
+
+/* Update local parameters */
+static void h3a_af_set_params(struct ispstat *af, void *new_conf)
+{
+ struct omap3isp_h3a_af_config *user_cfg = new_conf;
+ struct omap3isp_h3a_af_config *cur_cfg = af->priv;
+ int update = 0;
+ int index;
+
+ /* alaw */
+ if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+ update = 1;
+ goto out;
+ }
+
+ /* hmf */
+ if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {
+ update = 1;
+ goto out;
+ }
+ if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {
+ update = 1;
+ goto out;
+ }
+
+ /* rgbpos */
+ if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {
+ update = 1;
+ goto out;
+ }
+
+ /* iir */
+ if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {
+ update = 1;
+ goto out;
+ }
+ for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+ if (cur_cfg->iir.coeff_set0[index] !=
+ user_cfg->iir.coeff_set0[index]) {
+ update = 1;
+ goto out;
+ }
+ if (cur_cfg->iir.coeff_set1[index] !=
+ user_cfg->iir.coeff_set1[index]) {
+ update = 1;
+ goto out;
+ }
+ }
+
+ /* paxel */
+ if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||
+ (cur_cfg->paxel.height != user_cfg->paxel.height) ||
+ (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||
+ (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||
+ (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||
+ (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||
+ (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {
+ update = 1;
+ goto out;
+ }
+
+ /* af_mode */
+ if (cur_cfg->fvmode != user_cfg->fvmode)
+ update = 1;
+
+out:
+ if (update || !af->configured) {
+ memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));
+ af->inc_config++;
+ af->update = 1;
+ /*
+ * User might be asked for a bigger buffer than necessary for
+ * this configuration. In order to return the right amount of
+ * data during buffer request, let's calculate the size here
+ * instead of stick with user_cfg->buf_size.
+ */
+ cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);
+ }
+}
+
+static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+ switch (cmd) {
+ case VIDIOC_OMAP3ISP_AF_CFG:
+ return omap3isp_stat_config(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_REQ:
+ return omap3isp_stat_request_statistics(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_EN: {
+ int *en = arg;
+ return omap3isp_stat_enable(stat, !!*en);
+ }
+ }
+
+ return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops h3a_af_ops = {
+ .validate_params = h3a_af_validate_params,
+ .set_params = h3a_af_set_params,
+ .setup_regs = h3a_af_setup_regs,
+ .enable = h3a_af_enable,
+ .busy = h3a_af_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {
+ .ioctl = h3a_af_ioctl,
+ .subscribe_event = omap3isp_stat_subscribe_event,
+ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {
+ .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_af_subdev_ops = {
+ .core = &h3a_af_subdev_core_ops,
+ .video = &h3a_af_subdev_video_ops,
+};
+
+/* Function to register the AF character device driver. */
+int omap3isp_h3a_af_init(struct isp_device *isp)
+{
+ struct ispstat *af = &isp->isp_af;
+ struct omap3isp_h3a_af_config *af_cfg;
+ struct omap3isp_h3a_af_config *af_recover_cfg;
+ int ret;
+
+ af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
+ if (af_cfg == NULL)
+ return -ENOMEM;
+
+ memset(af, 0, sizeof(*af));
+ af->ops = &h3a_af_ops;
+ af->priv = af_cfg;
+ af->dma_ch = -1;
+ af->event_type = V4L2_EVENT_OMAP3ISP_AF;
+ af->isp = isp;
+
+ /* Set recover state configuration */
+ af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
+ if (!af_recover_cfg) {
+ dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
+ "configuration.\n");
+ ret = -ENOMEM;
+ goto err_recover_alloc;
+ }
+
+ af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
+ af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;
+ af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;
+ af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;
+ af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;
+ af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;
+ if (h3a_af_validate_params(af, af_recover_cfg)) {
+ dev_err(af->isp->dev, "AF: recover configuration is "
+ "invalid.\n");
+ ret = -EINVAL;
+ goto err_conf;
+ }
+
+ af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
+ af->recover_priv = af_recover_cfg;
+
+ ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
+ if (ret)
+ goto err_conf;
+
+ return 0;
+
+err_conf:
+ kfree(af_recover_cfg);
+err_recover_alloc:
+ kfree(af_cfg);
+
+ return ret;
+}
+
+void omap3isp_h3a_af_cleanup(struct isp_device *isp)
+{
+ kfree(isp->isp_af.priv);
+ kfree(isp->isp_af.recover_priv);
+ omap3isp_stat_cleanup(&isp->isp_af);
+}
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
new file mode 100644
index 000000000000..d1a8dee5e1ca
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -0,0 +1,518 @@
+/*
+ * isphist.c
+ *
+ * TI OMAP3 ISP - Histogram module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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/slab.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isphist.h"
+
+#define HIST_CONFIG_DMA 1
+
+#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
+
+/*
+ * hist_reset_mem - clear Histogram memory before start stats engine.
+ */
+static void hist_reset_mem(struct ispstat *hist)
+{
+ struct isp_device *isp = hist->isp;
+ struct omap3isp_hist_config *conf = hist->priv;
+ unsigned int i;
+
+ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+ /*
+ * By setting it, the histogram internal buffer is being cleared at the
+ * same time it's being read. This bit must be cleared afterwards.
+ */
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+ /*
+ * We'll clear 4 words at each iteration for optimization. It avoids
+ * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
+ */
+ for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) {
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ }
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+ hist->wait_acc_frames = conf->num_acc_frames;
+}
+
+static void hist_dma_config(struct ispstat *hist)
+{
+ hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
+ hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ hist->dma_config.frame_count = 1;
+ hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
+ hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
+ hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
+ hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+}
+
+/*
+ * hist_setup_regs - Helper function to update Histogram registers.
+ */
+static void hist_setup_regs(struct ispstat *hist, void *priv)
+{
+ struct isp_device *isp = hist->isp;
+ struct omap3isp_hist_config *conf = priv;
+ int c;
+ u32 cnt;
+ u32 wb_gain;
+ u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS];
+ u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS];
+
+ if (!hist->update || hist->state == ISPSTAT_DISABLED ||
+ hist->state == ISPSTAT_DISABLING)
+ return;
+
+ cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT;
+
+ wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT;
+ wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT;
+ wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT;
+ if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER)
+ wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT;
+
+ /* Regions size and position */
+ for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
+ if (c < conf->num_regions) {
+ reg_hor[c] = conf->region[c].h_start <<
+ ISPHIST_REG_START_SHIFT;
+ reg_hor[c] = conf->region[c].h_end <<
+ ISPHIST_REG_END_SHIFT;
+ reg_ver[c] = conf->region[c].v_start <<
+ ISPHIST_REG_START_SHIFT;
+ reg_ver[c] = conf->region[c].v_end <<
+ ISPHIST_REG_END_SHIFT;
+ } else {
+ reg_hor[c] = 0;
+ reg_ver[c] = 0;
+ }
+ }
+
+ cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT;
+ switch (conf->hist_bins) {
+ case OMAP3ISP_HIST_BINS_256:
+ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) <<
+ ISPHIST_CNT_SHIFT_SHIFT;
+ break;
+ case OMAP3ISP_HIST_BINS_128:
+ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) <<
+ ISPHIST_CNT_SHIFT_SHIFT;
+ break;
+ case OMAP3ISP_HIST_BINS_64:
+ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) <<
+ ISPHIST_CNT_SHIFT_SHIFT;
+ break;
+ default: /* OMAP3ISP_HIST_BINS_32 */
+ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) <<
+ ISPHIST_CNT_SHIFT_SHIFT;
+ break;
+ }
+
+ hist_reset_mem(hist);
+
+ isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
+ isp_reg_writel(isp, wb_gain, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
+ isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ);
+ isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT);
+ isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ);
+ isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT);
+ isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ);
+ isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT);
+ isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ);
+ isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT);
+
+ hist->update = 0;
+ hist->config_counter += hist->inc_config;
+ hist->inc_config = 0;
+ hist->buf_size = conf->buf_size;
+}
+
+static void hist_enable(struct ispstat *hist, int enable)
+{
+ if (enable) {
+ isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+ ISPHIST_PCR_ENABLE);
+ omap3isp_subclk_enable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
+ } else {
+ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+ ISPHIST_PCR_ENABLE);
+ omap3isp_subclk_disable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
+ }
+}
+
+static int hist_busy(struct ispstat *hist)
+{
+ return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
+ & ISPHIST_PCR_BUSY;
+}
+
+static void hist_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct ispstat *hist = data;
+
+ if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
+ dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
+ ch_status);
+ omap_stop_dma(lch);
+ hist_reset_mem(hist);
+ atomic_set(&hist->buf_err, 1);
+ }
+ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ISPHIST_CNT_CLEAR);
+
+ omap3isp_stat_dma_isr(hist);
+ if (hist->state != ISPSTAT_DISABLED)
+ omap3isp_hist_dma_done(hist->isp);
+}
+
+static int hist_buf_dma(struct ispstat *hist)
+{
+ dma_addr_t dma_addr = hist->active_buf->dma_addr;
+
+ if (unlikely(!dma_addr)) {
+ dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
+ hist_reset_mem(hist);
+ return STAT_NO_BUF;
+ }
+
+ isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+ isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ISPHIST_CNT_CLEAR);
+ omap3isp_flush(hist->isp);
+ hist->dma_config.dst_start = dma_addr;
+ hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
+ omap_set_dma_params(hist->dma_ch, &hist->dma_config);
+
+ omap_start_dma(hist->dma_ch);
+
+ return STAT_BUF_WAITING_DMA;
+}
+
+static int hist_buf_pio(struct ispstat *hist)
+{
+ struct isp_device *isp = hist->isp;
+ u32 *buf = hist->active_buf->virt_addr;
+ unsigned int i;
+
+ if (!buf) {
+ dev_dbg(isp->dev, "hist: invalid PIO buffer address\n");
+ hist_reset_mem(hist);
+ return STAT_NO_BUF;
+ }
+
+ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+ /*
+ * By setting it, the histogram internal buffer is being cleared at the
+ * same time it's being read. This bit must be cleared just after all
+ * data is acquired.
+ */
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+ /*
+ * We'll read 4 times a 4-bytes-word at each iteration for
+ * optimization. It avoids 3/4 of the jumps. We also know buf_size is
+ * divisible by 16.
+ */
+ for (i = hist->buf_size / 16; i > 0; i--) {
+ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ }
+ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ISPHIST_CNT_CLEAR);
+
+ return STAT_BUF_DONE;
+}
+
+/*
+ * hist_buf_process - Callback from ISP driver for HIST interrupt.
+ */
+static int hist_buf_process(struct ispstat *hist)
+{
+ struct omap3isp_hist_config *user_cfg = hist->priv;
+ int ret;
+
+ if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) {
+ hist_reset_mem(hist);
+ return STAT_NO_BUF;
+ }
+
+ if (--(hist->wait_acc_frames))
+ return STAT_NO_BUF;
+
+ if (HIST_USING_DMA(hist))
+ ret = hist_buf_dma(hist);
+ else
+ ret = hist_buf_pio(hist);
+
+ hist->wait_acc_frames = user_cfg->num_acc_frames;
+
+ return ret;
+}
+
+static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
+{
+ return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions;
+}
+
+/*
+ * hist_validate_params - Helper function to check user given params.
+ * @user_cfg: Pointer to user configuration structure.
+ *
+ * Returns 0 on success configuration.
+ */
+static int hist_validate_params(struct ispstat *hist, void *new_conf)
+{
+ struct omap3isp_hist_config *user_cfg = new_conf;
+ int c;
+ u32 buf_size;
+
+ if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3)
+ return -EINVAL;
+
+ /* Regions size and position */
+
+ if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) ||
+ (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS))
+ return -EINVAL;
+
+ /* Regions */
+ for (c = 0; c < user_cfg->num_regions; c++) {
+ if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK)
+ return -EINVAL;
+ if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK)
+ return -EINVAL;
+ if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK)
+ return -EINVAL;
+ if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK)
+ return -EINVAL;
+ if (user_cfg->region[c].h_start > user_cfg->region[c].h_end)
+ return -EINVAL;
+ if (user_cfg->region[c].v_start > user_cfg->region[c].v_end)
+ return -EINVAL;
+ }
+
+ switch (user_cfg->num_regions) {
+ case 1:
+ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256)
+ return -EINVAL;
+ break;
+ case 2:
+ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128)
+ return -EINVAL;
+ break;
+ default: /* 3 or 4 */
+ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64)
+ return -EINVAL;
+ break;
+ }
+
+ buf_size = hist_get_buf_size(user_cfg);
+ if (buf_size > user_cfg->buf_size)
+ /* User's buf_size request wasn't enoght */
+ user_cfg->buf_size = buf_size;
+ else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
+ user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
+
+ return 0;
+}
+
+static int hist_comp_params(struct ispstat *hist,
+ struct omap3isp_hist_config *user_cfg)
+{
+ struct omap3isp_hist_config *cur_cfg = hist->priv;
+ int c;
+
+ if (cur_cfg->cfa != user_cfg->cfa)
+ return 1;
+
+ if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
+ return 1;
+
+ if (cur_cfg->hist_bins != user_cfg->hist_bins)
+ return 1;
+
+ for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) {
+ if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3)
+ break;
+ else if (cur_cfg->wg[c] != user_cfg->wg[c])
+ return 1;
+ }
+
+ if (cur_cfg->num_regions != user_cfg->num_regions)
+ return 1;
+
+ /* Regions */
+ for (c = 0; c < user_cfg->num_regions; c++) {
+ if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start)
+ return 1;
+ if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end)
+ return 1;
+ if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start)
+ return 1;
+ if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * hist_update_params - Helper function to check and store user given params.
+ * @new_conf: Pointer to user configuration structure.
+ */
+static void hist_set_params(struct ispstat *hist, void *new_conf)
+{
+ struct omap3isp_hist_config *user_cfg = new_conf;
+ struct omap3isp_hist_config *cur_cfg = hist->priv;
+
+ if (!hist->configured || hist_comp_params(hist, user_cfg)) {
+ memcpy(cur_cfg, user_cfg, sizeof(*user_cfg));
+ if (user_cfg->num_acc_frames == 0)
+ user_cfg->num_acc_frames = 1;
+ hist->inc_config++;
+ hist->update = 1;
+ /*
+ * User might be asked for a bigger buffer than necessary for
+ * this configuration. In order to return the right amount of
+ * data during buffer request, let's calculate the size here
+ * instead of stick with user_cfg->buf_size.
+ */
+ cur_cfg->buf_size = hist_get_buf_size(cur_cfg);
+
+ }
+}
+
+static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+ switch (cmd) {
+ case VIDIOC_OMAP3ISP_HIST_CFG:
+ return omap3isp_stat_config(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_REQ:
+ return omap3isp_stat_request_statistics(stat, arg);
+ case VIDIOC_OMAP3ISP_STAT_EN: {
+ int *en = arg;
+ return omap3isp_stat_enable(stat, !!*en);
+ }
+ }
+
+ return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops hist_ops = {
+ .validate_params = hist_validate_params,
+ .set_params = hist_set_params,
+ .setup_regs = hist_setup_regs,
+ .enable = hist_enable,
+ .busy = hist_busy,
+ .buf_process = hist_buf_process,
+};
+
+static const struct v4l2_subdev_core_ops hist_subdev_core_ops = {
+ .ioctl = hist_ioctl,
+ .subscribe_event = omap3isp_stat_subscribe_event,
+ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops hist_subdev_video_ops = {
+ .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops hist_subdev_ops = {
+ .core = &hist_subdev_core_ops,
+ .video = &hist_subdev_video_ops,
+};
+
+/*
+ * omap3isp_hist_init - Module Initialization.
+ */
+int omap3isp_hist_init(struct isp_device *isp)
+{
+ struct ispstat *hist = &isp->isp_hist;
+ struct omap3isp_hist_config *hist_cfg;
+ int ret = -1;
+
+ hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
+ if (hist_cfg == NULL)
+ return -ENOMEM;
+
+ memset(hist, 0, sizeof(*hist));
+ if (HIST_CONFIG_DMA)
+ ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
+ hist_dma_cb, hist, &hist->dma_ch);
+ if (ret) {
+ if (HIST_CONFIG_DMA)
+ dev_warn(isp->dev, "hist: DMA request channel failed. "
+ "Using PIO only.\n");
+ hist->dma_ch = -1;
+ } else {
+ dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
+ hist_dma_config(hist);
+ omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+ }
+
+ hist->ops = &hist_ops;
+ hist->priv = hist_cfg;
+ hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
+ hist->isp = isp;
+
+ ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
+ if (ret) {
+ kfree(hist_cfg);
+ if (HIST_USING_DMA(hist))
+ omap_free_dma(hist->dma_ch);
+ }
+
+ return ret;
+}
+
+/*
+ * omap3isp_hist_cleanup - Module cleanup.
+ */
+void omap3isp_hist_cleanup(struct isp_device *isp)
+{
+ if (HIST_USING_DMA(&isp->isp_hist))
+ omap_free_dma(isp->isp_hist.dma_ch);
+ kfree(isp->isp_hist.priv);
+ omap3isp_stat_cleanup(&isp->isp_hist);
+}
diff --git a/drivers/media/video/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h
index 0b2a38ec94c4..0b2a38ec94c4 100644
--- a/drivers/media/video/omap3isp/isphist.h
+++ b/drivers/media/platform/omap3isp/isphist.h
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
new file mode 100644
index 000000000000..1ae1c0909ed1
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -0,0 +1,2348 @@
+/*
+ * isppreview.c
+ *
+ * TI OMAP3 ISP driver - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isppreview.h"
+
+/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
+static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
+ { /* RGB-RGB Matrix */
+ {0x01E2, 0x0F30, 0x0FEE},
+ {0x0F9B, 0x01AC, 0x0FB9},
+ {0x0FE0, 0x0EC0, 0x0260}
+ }, /* RGB Offset */
+ {0x0000, 0x0000, 0x0000}
+};
+
+/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
+static struct omap3isp_prev_csc flr_prev_csc = {
+ { /* CSC Coef Matrix */
+ {66, 129, 25},
+ {-38, -75, 112},
+ {112, -94 , -18}
+ }, /* CSC Offset */
+ {0x0, 0x0, 0x0}
+};
+
+/* Default values in Office Fluorescent Light for CFA Gradient*/
+#define FLR_CFA_GRADTHRS_HORZ 0x28
+#define FLR_CFA_GRADTHRS_VERT 0x28
+
+/* Default values in Office Fluorescent Light for Chroma Suppression*/
+#define FLR_CSUP_GAIN 0x0D
+#define FLR_CSUP_THRES 0xEB
+
+/* Default values in Office Fluorescent Light for Noise Filter*/
+#define FLR_NF_STRGTH 0x03
+
+/* Default values for White Balance */
+#define FLR_WBAL_DGAIN 0x100
+#define FLR_WBAL_COEF 0x20
+
+/* Default values in Office Fluorescent Light for Black Adjustment*/
+#define FLR_BLKADJ_BLUE 0x0
+#define FLR_BLKADJ_GREEN 0x0
+#define FLR_BLKADJ_RED 0x0
+
+#define DEF_DETECT_CORRECT_VAL 0xe
+
+/*
+ * Margins and image size limits.
+ *
+ * The preview engine crops several rows and columns internally depending on
+ * which filters are enabled. To avoid format changes when the filters are
+ * enabled or disabled (which would prevent them from being turned on or off
+ * during streaming), the driver assumes all the filters are enabled when
+ * computing sink crop and source format limits.
+ *
+ * If a filter is disabled, additional cropping is automatically added at the
+ * preview engine input by the driver to avoid overflow at line and frame end.
+ * This is completely transparent for applications.
+ *
+ * Median filter 4 pixels
+ * Noise filter,
+ * Faulty pixels correction 4 pixels, 4 lines
+ * CFA filter 4 pixels, 4 lines in Bayer mode
+ * 2 lines in other modes
+ * Color suppression 2 pixels
+ * or luma enhancement
+ * -------------------------------------------------------------
+ * Maximum total 14 pixels, 8 lines
+ *
+ * The color suppression and luma enhancement filters are applied after bayer to
+ * YUV conversion. They thus can crop one pixel on the left and one pixel on the
+ * right side of the image without changing the color pattern. When both those
+ * filters are disabled, the driver must crop the two pixels on the same side of
+ * the image to avoid changing the bayer pattern. The left margin is thus set to
+ * 8 pixels and the right margin to 6 pixels.
+ */
+
+#define PREV_MARGIN_LEFT 8
+#define PREV_MARGIN_RIGHT 6
+#define PREV_MARGIN_TOP 4
+#define PREV_MARGIN_BOTTOM 4
+
+#define PREV_MIN_IN_WIDTH 64
+#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_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.
+ * Array is initialised with the values from.the tables text file.
+ */
+
+/*
+ * CFA Filter Coefficient Table
+ *
+ */
+static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
+#include "cfa_coef_table.h"
+};
+
+/*
+ * Default Gamma Correction Table - All components
+ */
+static u32 gamma_table[] = {
+#include "gamma_table.h"
+};
+
+/*
+ * Noise Filter Threshold table
+ */
+static u32 noise_filter_table[] = {
+#include "noise_filter_table.h"
+};
+
+/*
+ * Luminance Enhancement Table
+ */
+static u32 luma_enhance_table[] = {
+#include "luma_enhance_table.h"
+};
+
+/*
+ * preview_config_luma_enhancement - Configure the Luminance Enhancement table
+ */
+static void
+preview_config_luma_enhancement(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_luma *yt = &params->luma;
+ unsigned int i;
+
+ isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+ for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
+ isp_reg_writel(isp, yt->table[i],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+ }
+}
+
+/*
+ * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
+ */
+static void
+preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_YNENHEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_YNENHEN);
+}
+
+/*
+ * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
+ */
+static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+}
+
+/*
+ * preview_config_hmed - Configure the Horizontal Median Filter
+ */
+static void preview_config_hmed(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_hmed *hmed = &params->hmed;
+
+ isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
+ (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
+ (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
+}
+
+/*
+ * preview_enable_hmed - Enable/disable the Horizontal Median Filter
+ */
+static void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_HMEDEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_HMEDEN);
+}
+
+/*
+ * preview_config_cfa - Configure CFA Interpolation for Bayer formats
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
+ */
+static void preview_config_cfa(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ static const unsigned int cfa_coef_order[4][4] = {
+ { 0, 1, 2, 3 }, /* GRBG */
+ { 1, 0, 3, 2 }, /* RGGB */
+ { 2, 3, 0, 1 }, /* BGGR */
+ { 3, 2, 1, 0 }, /* GBRG */
+ };
+ const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
+ const struct omap3isp_prev_cfa *cfa = &params->cfa;
+ struct isp_device *isp = to_isp_device(prev);
+ unsigned int i;
+ unsigned int j;
+
+ isp_reg_writel(isp,
+ (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
+ (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
+
+ isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+
+ for (i = 0; i < 4; ++i) {
+ const __u32 *block = cfa->table[order[i]];
+
+ for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
+ isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_SET_TBL_DATA);
+ }
+}
+
+/*
+ * preview_config_chroma_suppression - Configure Chroma Suppression
+ */
+static void
+preview_config_chroma_suppression(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_csup *cs = &params->csup;
+
+ isp_reg_writel(isp,
+ cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
+ (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
+}
+
+/*
+ * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
+ */
+static void
+preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SUPEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SUPEN);
+}
+
+/*
+ * preview_config_whitebalance - Configure White Balance parameters
+ *
+ * Coefficient matrix always with default values.
+ */
+static void
+preview_config_whitebalance(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_wbal *wbal = &params->wbal;
+ u32 val;
+
+ isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
+
+ val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
+ val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
+ val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
+ val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
+
+ isp_reg_writel(isp,
+ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
+ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
+ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
+ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
+ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
+ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
+ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
+ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
+ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
+ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
+ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
+ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
+ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
+ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
+ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
+ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
+}
+
+/*
+ * preview_config_blkadj - Configure Black Adjustment
+ */
+static void
+preview_config_blkadj(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
+
+ isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
+ (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
+ (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
+}
+
+/*
+ * preview_config_rgb_blending - Configure RGB-RGB Blending
+ */
+static void
+preview_config_rgb_blending(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
+ u32 val;
+
+ val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
+ val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
+
+ val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
+ val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
+
+ val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
+ val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
+
+ val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
+ val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
+
+ val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
+
+ val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
+ val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
+
+ val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
+}
+
+/*
+ * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
+ */
+static void
+preview_config_csc(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_csc *csc = &params->csc;
+ u32 val;
+
+ val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
+ val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
+ val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
+
+ val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
+ val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
+ val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
+
+ val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
+ val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
+ val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
+
+ val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
+ val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
+ val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
+}
+
+/*
+ * preview_config_yc_range - Configure the max and min Y and C values
+ */
+static void
+preview_config_yc_range(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_yclimit *yc = &params->yclimit;
+
+ isp_reg_writel(isp,
+ yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+ yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
+ yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
+ yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
+}
+
+/*
+ * preview_config_dcor - Configure Couplet Defect Correction
+ */
+static void
+preview_config_dcor(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_dcor *dcor = &params->dcor;
+
+ isp_reg_writel(isp, dcor->detect_correct[0],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
+ isp_reg_writel(isp, dcor->detect_correct[1],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
+ isp_reg_writel(isp, dcor->detect_correct[2],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
+ isp_reg_writel(isp, dcor->detect_correct[3],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DCCOUP,
+ dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
+}
+
+/*
+ * preview_enable_dcor - Enable/disable Couplet Defect Correction
+ */
+static void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DCOREN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DCOREN);
+}
+
+/*
+ * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
+ */
+static void
+preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DRKFCAP);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DRKFCAP);
+}
+
+/*
+ * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
+ */
+static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DRKFEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DRKFEN);
+}
+
+/*
+ * preview_config_noisefilter - Configure the Noise Filter
+ */
+static void
+preview_config_noisefilter(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_nf *nf = &params->nf;
+ unsigned int i;
+
+ isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
+ isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+ for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
+ isp_reg_writel(isp, nf->table[i],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+ }
+}
+
+/*
+ * preview_enable_noisefilter - Enable/disable the Noise Filter
+ */
+static void
+preview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_NFEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_NFEN);
+}
+
+/*
+ * preview_config_gammacorrn - Configure the Gamma Correction tables
+ */
+static void
+preview_config_gammacorrn(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ const struct omap3isp_prev_gtables *gt = &params->gamma;
+ unsigned int i;
+
+ isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+ isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_SET_TBL_DATA);
+
+ isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+ isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_SET_TBL_DATA);
+
+ isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+ isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_SET_TBL_DATA);
+}
+
+/*
+ * preview_enable_gammacorrn - Enable/disable Gamma Correction
+ *
+ * When gamma correction is disabled, the module is bypassed and its output is
+ * the 8 MSB of the 10-bit input .
+ */
+static void
+preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (enable)
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_GAMMA_BYPASS);
+ else
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_GAMMA_BYPASS);
+}
+
+/*
+ * preview_config_contrast - Configure the Contrast
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_config_contrast(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+ 0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
+ params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
+}
+
+/*
+ * preview_config_brightness - Configure the Brightness
+ */
+static void
+preview_config_brightness(struct isp_prev_device *prev,
+ const struct prev_params *params)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+ 0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
+ params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
+}
+
+/*
+ * preview_update_contrast - Updates the contrast.
+ * @contrast: Pointer to hold the current programmed contrast value.
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
+{
+ struct prev_params *params;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
+ ? &prev->params.params[0] : &prev->params.params[1];
+
+ if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
+ params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
+ params->update |= OMAP3ISP_PREV_CONTRAST;
+ }
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/*
+ * preview_update_brightness - Updates the brightness in preview module.
+ * @brightness: Pointer to hold the current programmed brightness value.
+ *
+ */
+static void
+preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
+{
+ struct prev_params *params;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
+ ? &prev->params.params[0] : &prev->params.params[1];
+
+ if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
+ params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
+ params->update |= OMAP3ISP_PREV_BRIGHTNESS;
+ }
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+static u32
+preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+ u32 active = prev->params.active;
+
+ if (shadow) {
+ /* Mark all shadow parameters we are going to touch as busy. */
+ prev->params.params[0].busy |= ~active & update;
+ prev->params.params[1].busy |= active & update;
+ } else {
+ /* Mark all active parameters we are going to touch as busy. */
+ update = (prev->params.params[0].update & active)
+ | (prev->params.params[1].update & ~active);
+
+ prev->params.params[0].busy |= active & update;
+ prev->params.params[1].busy |= ~active & update;
+ }
+
+ return update;
+}
+
+static void
+preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+ u32 active = prev->params.active;
+
+ if (shadow) {
+ /* Set the update flag for shadow parameters that have been
+ * updated and clear the busy flag for all shadow parameters.
+ */
+ prev->params.params[0].update |= (~active & update);
+ prev->params.params[1].update |= (active & update);
+ prev->params.params[0].busy &= active;
+ prev->params.params[1].busy &= ~active;
+ } else {
+ /* Clear the update flag for active parameters that have been
+ * applied and the busy flag for all active parameters.
+ */
+ prev->params.params[0].update &= ~(active & update);
+ prev->params.params[1].update &= ~(~active & update);
+ prev->params.params[0].busy &= ~active;
+ prev->params.params[1].busy &= active;
+ }
+}
+
+static void preview_params_switch(struct isp_prev_device *prev)
+{
+ u32 to_switch;
+
+ /* Switch active parameters with updated shadow parameters when the
+ * shadow parameter has been updated and neither the active not the
+ * shadow parameter is busy.
+ */
+ to_switch = (prev->params.params[0].update & ~prev->params.active)
+ | (prev->params.params[1].update & prev->params.active);
+ to_switch &= ~(prev->params.params[0].busy |
+ prev->params.params[1].busy);
+ if (to_switch == 0)
+ return;
+
+ prev->params.active ^= to_switch;
+
+ /* Remove the update flag for the shadow copy of parameters we have
+ * switched.
+ */
+ prev->params.params[0].update &= ~(~prev->params.active & to_switch);
+ prev->params.params[1].update &= ~(prev->params.active & to_switch);
+}
+
+/* preview parameters update structure */
+struct preview_update {
+ void (*config)(struct isp_prev_device *, const struct prev_params *);
+ void (*enable)(struct isp_prev_device *, bool);
+ unsigned int param_offset;
+ unsigned int param_size;
+ unsigned int config_offset;
+ bool skip;
+};
+
+/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
+static const struct preview_update update_attrs[] = {
+ /* OMAP3ISP_PREV_LUMAENH */ {
+ preview_config_luma_enhancement,
+ preview_enable_luma_enhancement,
+ offsetof(struct prev_params, luma),
+ FIELD_SIZEOF(struct prev_params, luma),
+ offsetof(struct omap3isp_prev_update_config, luma),
+ }, /* OMAP3ISP_PREV_INVALAW */ {
+ NULL,
+ preview_enable_invalaw,
+ }, /* OMAP3ISP_PREV_HRZ_MED */ {
+ preview_config_hmed,
+ preview_enable_hmed,
+ offsetof(struct prev_params, hmed),
+ FIELD_SIZEOF(struct prev_params, hmed),
+ offsetof(struct omap3isp_prev_update_config, hmed),
+ }, /* OMAP3ISP_PREV_CFA */ {
+ preview_config_cfa,
+ NULL,
+ offsetof(struct prev_params, cfa),
+ FIELD_SIZEOF(struct prev_params, cfa),
+ offsetof(struct omap3isp_prev_update_config, cfa),
+ }, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
+ preview_config_chroma_suppression,
+ preview_enable_chroma_suppression,
+ offsetof(struct prev_params, csup),
+ FIELD_SIZEOF(struct prev_params, csup),
+ offsetof(struct omap3isp_prev_update_config, csup),
+ }, /* OMAP3ISP_PREV_WB */ {
+ preview_config_whitebalance,
+ NULL,
+ offsetof(struct prev_params, wbal),
+ FIELD_SIZEOF(struct prev_params, wbal),
+ offsetof(struct omap3isp_prev_update_config, wbal),
+ }, /* OMAP3ISP_PREV_BLKADJ */ {
+ preview_config_blkadj,
+ NULL,
+ offsetof(struct prev_params, blkadj),
+ FIELD_SIZEOF(struct prev_params, blkadj),
+ offsetof(struct omap3isp_prev_update_config, blkadj),
+ }, /* OMAP3ISP_PREV_RGB2RGB */ {
+ preview_config_rgb_blending,
+ NULL,
+ offsetof(struct prev_params, rgb2rgb),
+ FIELD_SIZEOF(struct prev_params, rgb2rgb),
+ offsetof(struct omap3isp_prev_update_config, rgb2rgb),
+ }, /* OMAP3ISP_PREV_COLOR_CONV */ {
+ preview_config_csc,
+ NULL,
+ offsetof(struct prev_params, csc),
+ FIELD_SIZEOF(struct prev_params, csc),
+ offsetof(struct omap3isp_prev_update_config, csc),
+ }, /* OMAP3ISP_PREV_YC_LIMIT */ {
+ preview_config_yc_range,
+ NULL,
+ offsetof(struct prev_params, yclimit),
+ FIELD_SIZEOF(struct prev_params, yclimit),
+ offsetof(struct omap3isp_prev_update_config, yclimit),
+ }, /* OMAP3ISP_PREV_DEFECT_COR */ {
+ preview_config_dcor,
+ preview_enable_dcor,
+ offsetof(struct prev_params, dcor),
+ FIELD_SIZEOF(struct prev_params, dcor),
+ offsetof(struct omap3isp_prev_update_config, dcor),
+ }, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
+ NULL,
+ NULL,
+ }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
+ NULL,
+ preview_enable_drkframe_capture,
+ }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
+ NULL,
+ preview_enable_drkframe,
+ }, /* OMAP3ISP_PREV_LENS_SHADING */ {
+ NULL,
+ preview_enable_drkframe,
+ }, /* OMAP3ISP_PREV_NF */ {
+ preview_config_noisefilter,
+ preview_enable_noisefilter,
+ offsetof(struct prev_params, nf),
+ FIELD_SIZEOF(struct prev_params, nf),
+ offsetof(struct omap3isp_prev_update_config, nf),
+ }, /* OMAP3ISP_PREV_GAMMA */ {
+ preview_config_gammacorrn,
+ preview_enable_gammacorrn,
+ offsetof(struct prev_params, gamma),
+ FIELD_SIZEOF(struct prev_params, gamma),
+ offsetof(struct omap3isp_prev_update_config, gamma),
+ }, /* OMAP3ISP_PREV_CONTRAST */ {
+ preview_config_contrast,
+ NULL,
+ 0, 0, 0, true,
+ }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
+ preview_config_brightness,
+ NULL,
+ 0, 0, 0, true,
+ },
+};
+
+/*
+ * preview_config - Copy and update local structure with userspace preview
+ * configuration.
+ * @prev: ISP preview engine
+ * @cfg: Configuration
+ *
+ * Return zero if success or -EFAULT if the configuration can't be copied from
+ * userspace.
+ */
+static int preview_config(struct isp_prev_device *prev,
+ struct omap3isp_prev_update_config *cfg)
+{
+ unsigned long flags;
+ unsigned int i;
+ int rval = 0;
+ u32 update;
+ u32 active;
+
+ if (cfg->update == 0)
+ return 0;
+
+ /* Mark the shadow parameters we're going to update as busy. */
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_lock(prev, cfg->update, true);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
+ update = 0;
+
+ for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+ const struct preview_update *attr = &update_attrs[i];
+ struct prev_params *params;
+ unsigned int bit = 1 << i;
+
+ if (attr->skip || !(cfg->update & bit))
+ continue;
+
+ params = &prev->params.params[!!(active & bit)];
+
+ if (cfg->flag & bit) {
+ void __user *from = *(void * __user *)
+ ((void *)cfg + attr->config_offset);
+ void *to = (void *)params + attr->param_offset;
+ size_t size = attr->param_size;
+
+ if (to && from && size) {
+ if (copy_from_user(to, from, size)) {
+ rval = -EFAULT;
+ break;
+ }
+ }
+ params->features |= bit;
+ } else {
+ params->features &= ~bit;
+ }
+
+ update |= bit;
+ }
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, true);
+ preview_params_switch(prev);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
+ return rval;
+}
+
+/*
+ * preview_setup_hw - Setup preview registers and/or internal memory
+ * @prev: pointer to preview private structure
+ * @update: Bitmask of parameters to setup
+ * @active: Bitmask of parameters active in set 0
+ * Note: can be called from interrupt context
+ * Return none
+ */
+static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
+ u32 active)
+{
+ unsigned int i;
+ u32 features;
+
+ if (update == 0)
+ return;
+
+ features = (prev->params.params[0].features & active)
+ | (prev->params.params[1].features & ~active);
+
+ for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+ const struct preview_update *attr = &update_attrs[i];
+ struct prev_params *params;
+ unsigned int bit = 1 << i;
+
+ if (!(update & bit))
+ continue;
+
+ params = &prev->params.params[!(active & bit)];
+
+ if (params->features & bit) {
+ if (attr->config)
+ attr->config(prev, params);
+ if (attr->enable)
+ attr->enable(prev, true);
+ } else {
+ if (attr->enable)
+ attr->enable(prev, false);
+ }
+ }
+}
+
+/*
+ * preview_config_ycpos - Configure byte layout of YUV image.
+ * @mode: Indicates the required byte layout.
+ */
+static void
+preview_config_ycpos(struct isp_prev_device *prev,
+ enum v4l2_mbus_pixelcode pixelcode)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ enum preview_ycpos_mode mode;
+
+ switch (pixelcode) {
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ mode = YCPOS_CrYCbY;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ mode = YCPOS_YCrYCb;
+ break;
+ default:
+ return;
+ }
+
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_YCPOS_CrYCbY,
+ mode << ISPPRV_PCR_YCPOS_SHIFT);
+}
+
+/*
+ * preview_config_averager - Enable / disable / configure averager
+ * @average: Average value to be configured.
+ */
+static void preview_config_averager(struct isp_prev_device *prev, u8 average)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
+ ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
+ average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+}
+
+
+/*
+ * preview_config_input_format - Configure the input format
+ * @prev: The preview engine
+ * @format: Format on the preview engine sink pad
+ *
+ * Enable and configure CFA interpolation for Bayer formats and disable it for
+ * greyscale formats.
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
+ */
+static void preview_config_input_format(struct isp_prev_device *prev,
+ const struct v4l2_mbus_framefmt *format)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ struct prev_params *params;
+
+ switch (format->code) {
+ case V4L2_MBUS_FMT_SGRBG10_1X10:
+ prev->params.cfa_order = 0;
+ break;
+ case V4L2_MBUS_FMT_SRGGB10_1X10:
+ prev->params.cfa_order = 1;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ prev->params.cfa_order = 2;
+ break;
+ case V4L2_MBUS_FMT_SGBRG10_1X10:
+ prev->params.cfa_order = 3;
+ break;
+ default:
+ /* Disable CFA for non-Bayer formats. */
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_CFAEN);
+ return;
+ }
+
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
+
+ params = (prev->params.active & OMAP3ISP_PREV_CFA)
+ ? &prev->params.params[0] : &prev->params.params[1];
+
+ preview_config_cfa(prev, params);
+}
+
+/*
+ * preview_config_input_size - Configure the input frame size
+ *
+ * The preview engine crops several rows and columns internally depending on
+ * which processing blocks are enabled. The driver assumes all those blocks are
+ * enabled when reporting source pad formats to userspace. If this assumption is
+ * not true, rows and columns must be manually cropped at the preview engine
+ * input to avoid overflows at the end of lines and frames.
+ *
+ * See the explanation at the PREV_MARGIN_* definitions for more details.
+ */
+static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
+{
+ const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
+ struct isp_device *isp = to_isp_device(prev);
+ unsigned int sph = prev->crop.left;
+ unsigned int eph = prev->crop.left + prev->crop.width - 1;
+ unsigned int slv = prev->crop.top;
+ unsigned int elv = prev->crop.top + prev->crop.height - 1;
+ u32 features;
+
+ if (format->code != V4L2_MBUS_FMT_Y10_1X10) {
+ sph -= 2;
+ eph += 2;
+ slv -= 2;
+ elv += 2;
+ }
+
+ features = (prev->params.params[0].features & active)
+ | (prev->params.params[1].features & ~active);
+
+ if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
+ sph -= 2;
+ eph += 2;
+ slv -= 2;
+ elv += 2;
+ }
+ if (features & OMAP3ISP_PREV_HRZ_MED) {
+ sph -= 2;
+ eph += 2;
+ }
+ if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
+ sph -= 2;
+
+ isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
+ isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
+}
+
+/*
+ * preview_config_inlineoffset - Configures the Read address line offset.
+ * @prev: Preview module
+ * @offset: Line offset
+ *
+ * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
+ * However, a hardware bug requires the memory start address to be aligned on a
+ * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
+ * well.
+ */
+static void
+preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RADR_OFFSET);
+}
+
+/*
+ * preview_set_inaddr - Sets memory address of input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address from which the input frame is to be read.
+ */
+static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
+}
+
+/*
+ * preview_config_outlineoffset - Configures the Write address line offset.
+ * @offset: Line Offset for the preview output.
+ *
+ * The offset must be a multiple of 32 bytes.
+ */
+static void preview_config_outlineoffset(struct isp_prev_device *prev,
+ u32 offset)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WADD_OFFSET);
+}
+
+/*
+ * preview_set_outaddr - Sets the memory address to store output frame
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address to which the output frame is written.
+ */
+static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+}
+
+static void preview_adjust_bandwidth(struct isp_prev_device *prev)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+ struct isp_device *isp = to_isp_device(prev);
+ const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
+ unsigned long l3_ick = pipe->l3_ick;
+ struct v4l2_fract *timeperframe;
+ unsigned int cycles_per_frame;
+ unsigned int requests_per_frame;
+ unsigned int cycles_per_request;
+ unsigned int minimum;
+ unsigned int maximum;
+ unsigned int value;
+
+ if (prev->input != PREVIEW_INPUT_MEMORY) {
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+ ISPSBL_SDR_REQ_PRV_EXP_MASK);
+ return;
+ }
+
+ /* Compute the minimum number of cycles per request, based on the
+ * pipeline maximum data rate. This is an absolute lower bound if we
+ * don't want SBL overflows, so round the value up.
+ */
+ cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+ pipe->max_rate);
+ minimum = DIV_ROUND_UP(cycles_per_request, 32);
+
+ /* Compute the maximum number of cycles per request, based on the
+ * requested frame rate. This is a soft upper bound to achieve a frame
+ * rate equal or higher than the requested value, so round the value
+ * down.
+ */
+ timeperframe = &pipe->max_timeperframe;
+
+ requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
+ cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+ timeperframe->denominator);
+ cycles_per_request = cycles_per_frame / requests_per_frame;
+
+ maximum = cycles_per_request / 32;
+
+ value = max(minimum, maximum);
+
+ dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+ ISPSBL_SDR_REQ_PRV_EXP_MASK,
+ value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_preview_busy - Gets busy state of preview module.
+ */
+int omap3isp_preview_busy(struct isp_prev_device *prev)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
+ & ISPPRV_PCR_BUSY;
+}
+
+/*
+ * omap3isp_preview_restore_context - Restores the values of preview registers
+ */
+void omap3isp_preview_restore_context(struct isp_device *isp)
+{
+ struct isp_prev_device *prev = &isp->isp_prev;
+ const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
+
+ prev->params.params[0].update = prev->params.active & update;
+ prev->params.params[1].update = ~prev->params.active & update;
+
+ preview_setup_hw(prev, update, prev->params.active);
+
+ prev->params.params[0].update = 0;
+ prev->params.params[1].update = 0;
+}
+
+/*
+ * preview_print_status - Dump preview module registers to the kernel log
+ */
+#define PREV_PRINT_REGISTER(isp, name)\
+ dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
+
+static void preview_print_status(struct isp_prev_device *prev)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
+
+ PREV_PRINT_REGISTER(isp, PCR);
+ PREV_PRINT_REGISTER(isp, HORZ_INFO);
+ PREV_PRINT_REGISTER(isp, VERT_INFO);
+ PREV_PRINT_REGISTER(isp, RSDR_ADDR);
+ PREV_PRINT_REGISTER(isp, RADR_OFFSET);
+ PREV_PRINT_REGISTER(isp, DSDR_ADDR);
+ PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
+ PREV_PRINT_REGISTER(isp, WSDR_ADDR);
+ PREV_PRINT_REGISTER(isp, WADD_OFFSET);
+ PREV_PRINT_REGISTER(isp, AVE);
+ PREV_PRINT_REGISTER(isp, HMED);
+ PREV_PRINT_REGISTER(isp, NF);
+ PREV_PRINT_REGISTER(isp, WB_DGAIN);
+ PREV_PRINT_REGISTER(isp, WBGAIN);
+ PREV_PRINT_REGISTER(isp, WBSEL);
+ PREV_PRINT_REGISTER(isp, CFA);
+ PREV_PRINT_REGISTER(isp, BLKADJOFF);
+ PREV_PRINT_REGISTER(isp, RGB_MAT1);
+ PREV_PRINT_REGISTER(isp, RGB_MAT2);
+ PREV_PRINT_REGISTER(isp, RGB_MAT3);
+ PREV_PRINT_REGISTER(isp, RGB_MAT4);
+ PREV_PRINT_REGISTER(isp, RGB_MAT5);
+ PREV_PRINT_REGISTER(isp, RGB_OFF1);
+ PREV_PRINT_REGISTER(isp, RGB_OFF2);
+ PREV_PRINT_REGISTER(isp, CSC0);
+ PREV_PRINT_REGISTER(isp, CSC1);
+ PREV_PRINT_REGISTER(isp, CSC2);
+ PREV_PRINT_REGISTER(isp, CSC_OFFSET);
+ PREV_PRINT_REGISTER(isp, CNT_BRT);
+ PREV_PRINT_REGISTER(isp, CSUP);
+ PREV_PRINT_REGISTER(isp, SETUP_YC);
+ PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
+ PREV_PRINT_REGISTER(isp, CDC_THR0);
+ PREV_PRINT_REGISTER(isp, CDC_THR1);
+ PREV_PRINT_REGISTER(isp, CDC_THR2);
+ PREV_PRINT_REGISTER(isp, CDC_THR3);
+
+ dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * preview_init_params - init image processing parameters.
+ * @prev: pointer to previewer private structure
+ */
+static void preview_init_params(struct isp_prev_device *prev)
+{
+ struct prev_params *params;
+ unsigned int i;
+
+ spin_lock_init(&prev->params.lock);
+
+ prev->params.active = ~0;
+ prev->params.params[0].busy = 0;
+ prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
+ prev->params.params[1].busy = 0;
+ prev->params.params[1].update = 0;
+
+ params = &prev->params.params[0];
+
+ /* Init values */
+ params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
+ params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
+ params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
+ memcpy(params->cfa.table, cfa_coef_table,
+ sizeof(params->cfa.table));
+ params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
+ params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
+ params->csup.gain = FLR_CSUP_GAIN;
+ params->csup.thres = FLR_CSUP_THRES;
+ params->csup.hypf_en = 0;
+ memcpy(params->luma.table, luma_enhance_table,
+ sizeof(params->luma.table));
+ params->nf.spread = FLR_NF_STRGTH;
+ memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
+ params->dcor.couplet_mode_en = 1;
+ for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
+ params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
+ memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
+ memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
+ memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
+ params->wbal.dgain = FLR_WBAL_DGAIN;
+ params->wbal.coef0 = FLR_WBAL_COEF;
+ params->wbal.coef1 = FLR_WBAL_COEF;
+ params->wbal.coef2 = FLR_WBAL_COEF;
+ params->wbal.coef3 = FLR_WBAL_COEF;
+ params->blkadj.red = FLR_BLKADJ_RED;
+ params->blkadj.green = FLR_BLKADJ_GREEN;
+ params->blkadj.blue = FLR_BLKADJ_BLUE;
+ params->rgb2rgb = flr_rgb2rgb;
+ params->csc = flr_prev_csc;
+ params->yclimit.minC = ISPPRV_YC_MIN;
+ params->yclimit.maxC = ISPPRV_YC_MAX;
+ params->yclimit.minY = ISPPRV_YC_MIN;
+ params->yclimit.maxY = ISPPRV_YC_MAX;
+
+ params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
+ | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
+ | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
+ | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
+ | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
+ | OMAP3ISP_PREV_CONTRAST;
+}
+
+/*
+ * preview_max_out_width - Handle previewer hardware ouput limitations
+ * @isp_revision : ISP revision
+ * returns maximum width output for current isp revision
+ */
+static unsigned int preview_max_out_width(struct isp_prev_device *prev)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ switch (isp->revision) {
+ case ISP_REVISION_1_0:
+ return PREV_MAX_OUT_WIDTH_REV_1;
+
+ case ISP_REVISION_2_0:
+ default:
+ return PREV_MAX_OUT_WIDTH_REV_2;
+
+ case ISP_REVISION_15_0:
+ return PREV_MAX_OUT_WIDTH_REV_15;
+ }
+}
+
+static void preview_configure(struct isp_prev_device *prev)
+{
+ struct isp_device *isp = to_isp_device(prev);
+ struct v4l2_mbus_framefmt *format;
+ unsigned long flags;
+ u32 update;
+ u32 active;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ /* Mark all active parameters we are going to touch as busy. */
+ update = preview_params_lock(prev, 0, false);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
+ /* PREV_PAD_SINK */
+ format = &prev->formats[PREV_PAD_SINK];
+
+ preview_adjust_bandwidth(prev);
+
+ preview_config_input_format(prev, format);
+ preview_config_input_size(prev, active);
+
+ if (prev->input == PREVIEW_INPUT_CCDC)
+ preview_config_inlineoffset(prev, 0);
+ else
+ preview_config_inlineoffset(prev,
+ ALIGN(format->width, 0x20) * 2);
+
+ preview_setup_hw(prev, update, active);
+
+ /* PREV_PAD_SOURCE */
+ format = &prev->formats[PREV_PAD_SOURCE];
+
+ if (prev->output & PREVIEW_OUTPUT_MEMORY)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SDRPORT);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SDRPORT);
+
+ if (prev->output & PREVIEW_OUTPUT_RESIZER)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_RSZPORT);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_RSZPORT);
+
+ if (prev->output & PREVIEW_OUTPUT_MEMORY)
+ preview_config_outlineoffset(prev,
+ ALIGN(format->width, 0x10) * 2);
+
+ preview_config_averager(prev, 0);
+ preview_config_ycpos(prev, format->code);
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, false);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void preview_enable_oneshot(struct isp_prev_device *prev)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
+ * bit is set. As the preview engine is used in single-shot mode, we
+ * need to set PCR.SOURCE before enabling the preview engine.
+ */
+ if (prev->input == PREVIEW_INPUT_MEMORY)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SOURCE);
+
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
+}
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
+{
+ /*
+ * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+ * condition, the module was paused and now we have a buffer queued
+ * on the output again. Restart the pipeline if running in continuous
+ * mode.
+ */
+ if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+ prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+ preview_enable_oneshot(prev);
+ isp_video_dmaqueue_flags_clr(&prev->video_out);
+ }
+}
+
+static void preview_isr_buffer(struct isp_prev_device *prev)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+ struct isp_buffer *buffer;
+ int restart = 0;
+
+ if (prev->input == PREVIEW_INPUT_MEMORY) {
+ 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);
+ if (buffer != NULL) {
+ preview_set_outaddr(prev, buffer->isp_addr);
+ restart = 1;
+ }
+ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+ }
+
+ switch (prev->state) {
+ case ISP_PIPELINE_STREAM_SINGLESHOT:
+ if (isp_pipeline_ready(pipe))
+ omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_SINGLESHOT);
+ break;
+
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ /* If an underrun occurs, the video queue operation handler will
+ * restart the preview engine. Otherwise restart it immediately.
+ */
+ if (restart)
+ preview_enable_oneshot(prev);
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ default:
+ return;
+ }
+}
+
+/*
+ * omap3isp_preview_isr - ISP preview engine interrupt handler
+ *
+ * Manage the preview engine video buffers and configure shadowed registers.
+ */
+void omap3isp_preview_isr(struct isp_prev_device *prev)
+{
+ unsigned long flags;
+ u32 update;
+ u32 active;
+
+ if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
+ return;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_switch(prev);
+ update = preview_params_lock(prev, 0, false);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
+ preview_setup_hw(prev, update, active);
+ preview_config_input_size(prev, active);
+
+ if (prev->input == PREVIEW_INPUT_MEMORY ||
+ prev->output & PREVIEW_OUTPUT_MEMORY)
+ preview_isr_buffer(prev);
+ else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+ preview_enable_oneshot(prev);
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, false);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int preview_video_queue(struct isp_video *video,
+ struct isp_buffer *buffer)
+{
+ struct isp_prev_device *prev = &video->isp->isp_prev;
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ preview_set_inaddr(prev, buffer->isp_addr);
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ preview_set_outaddr(prev, buffer->isp_addr);
+
+ return 0;
+}
+
+static const struct isp_video_operations preview_video_ops = {
+ .queue = preview_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * preview_s_ctrl - Handle set control subdev method
+ * @ctrl: pointer to v4l2 control structure
+ */
+static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isp_prev_device *prev =
+ container_of(ctrl->handler, struct isp_prev_device, ctrls);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ preview_update_brightness(prev, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ preview_update_contrast(prev, ctrl->val);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops preview_ctrl_ops = {
+ .s_ctrl = preview_s_ctrl,
+};
+
+/*
+ * preview_ioctl - Handle preview module private ioctl's
+ * @prev: pointer to preview context structure
+ * @cmd: configuration command
+ * @arg: configuration argument
+ * return -EINVAL or zero on success
+ */
+static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+ switch (cmd) {
+ case VIDIOC_OMAP3ISP_PRV_CFG:
+ return preview_config(prev, arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/*
+ * preview_set_stream - Enable/Disable streaming on preview subdev
+ * @sd : pointer to v4l2 subdev structure
+ * @enable: 1 == Enable, 0 == Disable
+ * return -EINVAL or zero on success
+ */
+static int preview_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct isp_video *video_out = &prev->video_out;
+ struct isp_device *isp = to_isp_device(prev);
+ struct device *dev = to_device(prev);
+
+ if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
+ if (enable == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+
+ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+ preview_configure(prev);
+ atomic_set(&prev->stopping, 0);
+ preview_print_status(prev);
+ }
+
+ switch (enable) {
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ if (prev->output & PREVIEW_OUTPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+ if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
+ !(prev->output & PREVIEW_OUTPUT_MEMORY))
+ preview_enable_oneshot(prev);
+
+ isp_video_dmaqueue_flags_clr(video_out);
+ break;
+
+ case ISP_PIPELINE_STREAM_SINGLESHOT:
+ if (prev->input == PREVIEW_INPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+ if (prev->output & PREVIEW_OUTPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+ preview_enable_oneshot(prev);
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
+ &prev->stopping))
+ dev_dbg(dev, "%s: stop timeout.\n", sd->name);
+ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+ isp_video_dmaqueue_flags_clr(video_out);
+ break;
+ }
+
+ prev->state = enable;
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &prev->formats[pad];
+}
+
+static struct v4l2_rect *
+__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK);
+ else
+ return &prev->crop;
+}
+
+/* previewer format descriptions */
+static const unsigned int preview_input_fmts[] = {
+ V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_SGRBG10_1X10,
+ V4L2_MBUS_FMT_SRGGB10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_SGBRG10_1X10,
+};
+
+static const unsigned int preview_output_fmts[] = {
+ V4L2_MBUS_FMT_UYVY8_1X16,
+ V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/*
+ * preview_try_format - Validate a format
+ * @prev: ISP preview engine
+ * @fh: V4L2 subdev file handle
+ * @pad: pad number
+ * @fmt: format to be validated
+ * @which: try/active format selector
+ *
+ * Validate and adjust the given format for the given pad based on the preview
+ * engine limits and the format and crop rectangles on other pads.
+ */
+static void preview_try_format(struct isp_prev_device *prev,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ enum v4l2_mbus_pixelcode pixelcode;
+ struct v4l2_rect *crop;
+ unsigned int i;
+
+ switch (pad) {
+ case PREV_PAD_SINK:
+ /* When reading data from the CCDC, the input size has already
+ * been mangled by the CCDC output pad so it can be accepted
+ * as-is.
+ *
+ * When reading data from memory, clamp the requested width and
+ * height. The TRM doesn't specify a minimum input height, make
+ * sure we got enough lines to enable the noise filter and color
+ * filter array interpolation.
+ */
+ if (prev->input == PREVIEW_INPUT_MEMORY) {
+ fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
+ preview_max_out_width(prev));
+ fmt->height = clamp_t(u32, fmt->height,
+ PREV_MIN_IN_HEIGHT,
+ PREV_MAX_IN_HEIGHT);
+ }
+
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+ for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
+ if (fmt->code == preview_input_fmts[i])
+ break;
+ }
+
+ /* If not found, use SGRBG10 as default */
+ if (i >= ARRAY_SIZE(preview_input_fmts))
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ break;
+
+ case PREV_PAD_SOURCE:
+ pixelcode = fmt->code;
+ *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);
+
+ switch (pixelcode) {
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ fmt->code = pixelcode;
+ break;
+
+ default:
+ fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ break;
+ }
+
+ /* The preview module output size is configurable through the
+ * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
+ * is not supported yet, hardcode the output size to the crop
+ * rectangle size.
+ */
+ crop = __preview_get_crop(prev, fh, which);
+ fmt->width = crop->width;
+ fmt->height = crop->height;
+
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ }
+
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * preview_try_crop - Validate a crop rectangle
+ * @prev: ISP preview engine
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ *
+ * The preview engine crops lines and columns for its internal operation,
+ * depending on which filters are enabled. Enforce minimum crop margins to
+ * handle that transparently for userspace.
+ *
+ * See the explanation at the PREV_MARGIN_* definitions for more details.
+ */
+static void preview_try_crop(struct isp_prev_device *prev,
+ const struct v4l2_mbus_framefmt *sink,
+ struct v4l2_rect *crop)
+{
+ unsigned int left = PREV_MARGIN_LEFT;
+ unsigned int right = sink->width - PREV_MARGIN_RIGHT;
+ unsigned int top = PREV_MARGIN_TOP;
+ unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
+
+ /* When processing data on-the-fly from the CCDC, at least 2 pixels must
+ * be cropped from the left and right sides of the image. As we don't
+ * know which filters will be enabled, increase the left and right
+ * margins by two.
+ */
+ if (prev->input == PREVIEW_INPUT_CCDC) {
+ left += 2;
+ right -= 2;
+ }
+
+ /* Restrict left/top to even values to keep the Bayer pattern. */
+ crop->left &= ~1;
+ crop->top &= ~1;
+
+ crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
+ crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
+ crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
+ right - crop->left);
+ crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
+ bottom - crop->top);
+}
+
+/*
+ * preview_enum_mbus_code - Handle pixel format enumeration
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int preview_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ switch (code->pad) {
+ case PREV_PAD_SINK:
+ if (code->index >= ARRAY_SIZE(preview_input_fmts))
+ return -EINVAL;
+
+ code->code = preview_input_fmts[code->index];
+ break;
+ case PREV_PAD_SOURCE:
+ if (code->index >= ARRAY_SIZE(preview_output_fmts))
+ return -EINVAL;
+
+ code->code = preview_output_fmts[code->index];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int preview_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt format;
+
+ if (fse->index != 0)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = 1;
+ format.height = 1;
+ preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->min_width = format.width;
+ fse->min_height = format.height;
+
+ if (format.code != fse->code)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = -1;
+ format.height = -1;
+ preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->max_width = format.width;
+ fse->max_height = format.height;
+
+ return 0;
+}
+
+/*
+ * preview_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int preview_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->pad != PREV_PAD_SINK)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ format = __preview_get_format(prev, fh, PREV_PAD_SINK,
+ sel->which);
+ preview_try_crop(prev, format, &sel->r);
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *__preview_get_crop(prev, fh, sel->which);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * preview_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int preview_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->target != V4L2_SEL_TGT_CROP ||
+ sel->pad != PREV_PAD_SINK)
+ return -EINVAL;
+
+ /* The crop rectangle can't be changed while streaming. */
+ if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
+ return -EBUSY;
+
+ /* Modifying the crop rectangle always changes the format on the source
+ * pad. If the KEEP_CONFIG flag is set, just return the current crop
+ * rectangle.
+ */
+ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
+ sel->r = *__preview_get_crop(prev, fh, sel->which);
+ return 0;
+ }
+
+ format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
+ preview_try_crop(prev, format, &sel->r);
+ *__preview_get_crop(prev, fh, sel->which) = sel->r;
+
+ /* Update the source format. */
+ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
+ preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
+
+ return 0;
+}
+
+/*
+ * preview_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+/*
+ * preview_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+
+ /* Propagate the format from sink to source */
+ if (fmt->pad == PREV_PAD_SINK) {
+ /* Reset the crop rectangle. */
+ crop = __preview_get_crop(prev, fh, fmt->which);
+ crop->left = 0;
+ crop->top = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+
+ preview_try_crop(prev, &fmt->format, crop);
+
+ /* Update the source format. */
+ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
+ fmt->which);
+ preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
+ fmt->which);
+ }
+
+ return 0;
+}
+
+/*
+ * preview_init_formats - Initialize formats on all pads
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int preview_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+ format.pad = PREV_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.width = 4096;
+ format.format.height = 4096;
+ preview_set_format(sd, fh, &format);
+
+ return 0;
+}
+
+/* subdev core operations */
+static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
+ .ioctl = preview_ioctl,
+};
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
+ .s_stream = preview_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
+ .enum_mbus_code = preview_enum_mbus_code,
+ .enum_frame_size = preview_enum_frame_size,
+ .get_fmt = preview_get_format,
+ .set_fmt = preview_set_format,
+ .get_selection = preview_get_selection,
+ .set_selection = preview_set_selection,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops preview_v4l2_ops = {
+ .core = &preview_v4l2_core_ops,
+ .video = &preview_v4l2_video_ops,
+ .pad = &preview_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
+ .open = preview_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * preview_link_setup - Setup previewer connections.
+ * @entity : Pointer to media entity structure
+ * @local : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags : Link flags
+ * return -EINVAL or zero on success
+ */
+static int preview_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* read from memory */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (prev->input == PREVIEW_INPUT_CCDC)
+ return -EBUSY;
+ prev->input = PREVIEW_INPUT_MEMORY;
+ } else {
+ if (prev->input == PREVIEW_INPUT_MEMORY)
+ prev->input = PREVIEW_INPUT_NONE;
+ }
+ break;
+
+ case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* read from ccdc */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (prev->input == PREVIEW_INPUT_MEMORY)
+ return -EBUSY;
+ prev->input = PREVIEW_INPUT_CCDC;
+ } else {
+ if (prev->input == PREVIEW_INPUT_CCDC)
+ prev->input = PREVIEW_INPUT_NONE;
+ }
+ break;
+
+ /*
+ * The ISP core doesn't support pipelines with multiple video outputs.
+ * Revisit this when it will be implemented, and return -EBUSY for now.
+ */
+
+ case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ /* write to memory */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
+ return -EBUSY;
+ prev->output |= PREVIEW_OUTPUT_MEMORY;
+ } else {
+ prev->output &= ~PREVIEW_OUTPUT_MEMORY;
+ }
+ break;
+
+ case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* write to resizer */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
+ return -EBUSY;
+ prev->output |= PREVIEW_OUTPUT_RESIZER;
+ } else {
+ prev->output &= ~PREVIEW_OUTPUT_RESIZER;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations preview_media_ops = {
+ .link_setup = preview_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
+{
+ v4l2_device_unregister_subdev(&prev->subdev);
+ omap3isp_video_unregister(&prev->video_in);
+ omap3isp_video_unregister(&prev->video_out);
+}
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prev,
+ struct v4l2_device *vdev)
+{
+ int ret;
+
+ /* Register the subdev and video nodes. */
+ ret = v4l2_device_register_subdev(vdev, &prev->subdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&prev->video_in, vdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&prev->video_out, vdev);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ omap3isp_preview_unregister_entities(prev);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP previewer initialisation and cleanup
+ */
+
+/*
+ * preview_init_entities - Initialize subdev and media entity.
+ * @prev : Pointer to preview structure
+ * return -ENOMEM or zero on success
+ */
+static int preview_init_entities(struct isp_prev_device *prev)
+{
+ struct v4l2_subdev *sd = &prev->subdev;
+ struct media_pad *pads = prev->pads;
+ struct media_entity *me = &sd->entity;
+ int ret;
+
+ prev->input = PREVIEW_INPUT_NONE;
+
+ v4l2_subdev_init(sd, &preview_v4l2_ops);
+ sd->internal_ops = &preview_v4l2_internal_ops;
+ strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
+ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
+ v4l2_set_subdevdata(sd, prev);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ v4l2_ctrl_handler_init(&prev->ctrls, 2);
+ v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
+ ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
+ v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
+ ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
+ ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
+ v4l2_ctrl_handler_setup(&prev->ctrls);
+ sd->ctrl_handler = &prev->ctrls;
+
+ pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ me->ops = &preview_media_ops;
+ ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
+ if (ret < 0)
+ return ret;
+
+ preview_init_formats(sd, NULL);
+
+ /* According to the OMAP34xx TRM, video buffers need to be aligned on a
+ * 32 bytes boundary. However, an undocumented hardware bug requires a
+ * 64 bytes boundary at the preview engine input.
+ */
+ prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ prev->video_in.ops = &preview_video_ops;
+ prev->video_in.isp = to_isp_device(prev);
+ prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+ prev->video_in.bpl_alignment = 64;
+ prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ prev->video_out.ops = &preview_video_ops;
+ prev->video_out.isp = to_isp_device(prev);
+ prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+ prev->video_out.bpl_alignment = 32;
+
+ ret = omap3isp_video_init(&prev->video_in, "preview");
+ if (ret < 0)
+ goto error_video_in;
+
+ ret = omap3isp_video_init(&prev->video_out, "preview");
+ if (ret < 0)
+ goto error_video_out;
+
+ /* Connect the video nodes to the previewer subdev. */
+ ret = media_entity_create_link(&prev->video_in.video.entity, 0,
+ &prev->subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
+ &prev->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ goto error_link;
+
+ return 0;
+
+error_link:
+ omap3isp_video_cleanup(&prev->video_out);
+error_video_out:
+ omap3isp_video_cleanup(&prev->video_in);
+error_video_in:
+ media_entity_cleanup(&prev->subdev.entity);
+ return ret;
+}
+
+/*
+ * omap3isp_preview_init - Previewer initialization.
+ * @dev : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_preview_init(struct isp_device *isp)
+{
+ struct isp_prev_device *prev = &isp->isp_prev;
+
+ init_waitqueue_head(&prev->wait);
+
+ preview_init_params(prev);
+
+ return preview_init_entities(prev);
+}
+
+void omap3isp_preview_cleanup(struct isp_device *isp)
+{
+ struct isp_prev_device *prev = &isp->isp_prev;
+
+ v4l2_ctrl_handler_free(&prev->ctrls);
+ omap3isp_video_cleanup(&prev->video_in);
+ omap3isp_video_cleanup(&prev->video_out);
+ media_entity_cleanup(&prev->subdev.entity);
+}
diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h
new file mode 100644
index 000000000000..f66923407f8c
--- /dev/null
+++ b/drivers/media/platform/omap3isp/isppreview.h
@@ -0,0 +1,174 @@
+/*
+ * isppreview.h
+ *
+ * TI OMAP3 ISP - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 OMAP3_ISP_PREVIEW_H
+#define OMAP3_ISP_PREVIEW_H
+
+#include <linux/omap3isp.h>
+#include <linux/types.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ispvideo.h"
+
+#define ISPPRV_BRIGHT_STEP 0x1
+#define ISPPRV_BRIGHT_DEF 0x0
+#define ISPPRV_BRIGHT_LOW 0x0
+#define ISPPRV_BRIGHT_HIGH 0xFF
+#define ISPPRV_BRIGHT_UNITS 0x1
+
+#define ISPPRV_CONTRAST_STEP 0x1
+#define ISPPRV_CONTRAST_DEF 0x10
+#define ISPPRV_CONTRAST_LOW 0x0
+#define ISPPRV_CONTRAST_HIGH 0xFF
+#define ISPPRV_CONTRAST_UNITS 0x1
+
+/* Additional features not listed in linux/omap3isp.h */
+#define OMAP3ISP_PREV_CONTRAST (1 << 17)
+#define OMAP3ISP_PREV_BRIGHTNESS (1 << 18)
+#define OMAP3ISP_PREV_FEATURES_END (1 << 19)
+
+enum preview_input_entity {
+ PREVIEW_INPUT_NONE,
+ PREVIEW_INPUT_CCDC,
+ PREVIEW_INPUT_MEMORY,
+};
+
+#define PREVIEW_OUTPUT_RESIZER (1 << 1)
+#define PREVIEW_OUTPUT_MEMORY (1 << 2)
+
+/* Configure byte layout of YUV image */
+enum preview_ycpos_mode {
+ YCPOS_YCrYCb = 0,
+ YCPOS_YCbYCr = 1,
+ YCPOS_CbYCrY = 2,
+ YCPOS_CrYCbY = 3
+};
+
+/*
+ * struct prev_params - Structure for all configuration
+ * @busy: Bitmask of busy parameters (being updated or used)
+ * @update: Bitmask of the parameters to be updated
+ * @features: Set of features enabled.
+ * @cfa: CFA coefficients.
+ * @csup: Chroma suppression coefficients.
+ * @luma: Luma enhancement coefficients.
+ * @nf: Noise filter coefficients.
+ * @dcor: Noise filter coefficients.
+ * @gamma: Gamma coefficients.
+ * @wbal: White Balance parameters.
+ * @blkadj: Black adjustment parameters.
+ * @rgb2rgb: RGB blending parameters.
+ * @csc: Color space conversion (RGB to YCbCr) parameters.
+ * @hmed: Horizontal median filter.
+ * @yclimit: YC limits parameters.
+ * @contrast: Contrast.
+ * @brightness: Brightness.
+ */
+struct prev_params {
+ u32 busy;
+ u32 update;
+ u32 features;
+ struct omap3isp_prev_cfa cfa;
+ struct omap3isp_prev_csup csup;
+ struct omap3isp_prev_luma luma;
+ struct omap3isp_prev_nf nf;
+ struct omap3isp_prev_dcor dcor;
+ struct omap3isp_prev_gtables gamma;
+ struct omap3isp_prev_wbal wbal;
+ struct omap3isp_prev_blkadj blkadj;
+ struct omap3isp_prev_rgbtorgb rgb2rgb;
+ struct omap3isp_prev_csc csc;
+ struct omap3isp_prev_hmed hmed;
+ struct omap3isp_prev_yclimit yclimit;
+ u8 contrast;
+ u8 brightness;
+};
+
+/* Sink and source previewer pads */
+#define PREV_PAD_SINK 0
+#define PREV_PAD_SOURCE 1
+#define PREV_PADS_NUM 2
+
+/*
+ * struct isp_prev_device - Structure for storing ISP Preview module information
+ * @subdev: V4L2 subdevice
+ * @pads: Media entity pads
+ * @formats: Active formats at the subdev pad
+ * @crop: Active crop rectangle
+ * @input: Module currently connected to the input pad
+ * @output: Bitmask of the active output
+ * @video_in: Input video entity
+ * @video_out: Output video entity
+ * @params.params : Active and shadow parameters sets
+ * @params.active: Bitmask of parameters active in set 0
+ * @params.lock: Parameters lock, protects params.active and params.shadow
+ * @underrun: Whether the preview entity has queued buffers on the output
+ * @state: Current preview pipeline state
+ *
+ * This structure is used to store the OMAP ISP Preview module Information.
+ */
+struct isp_prev_device {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[PREV_PADS_NUM];
+ struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
+ struct v4l2_rect crop;
+
+ struct v4l2_ctrl_handler ctrls;
+
+ enum preview_input_entity input;
+ unsigned int output;
+ struct isp_video video_in;
+ struct isp_video video_out;
+
+ struct {
+ unsigned int cfa_order;
+ struct prev_params params[2];
+ u32 active;
+ spinlock_t lock;
+ } params;
+
+ enum isp_pipeline_stream_state state;
+ wait_queue_head_t wait;
+ atomic_t stopping;
+};
+
+struct isp_device;
+
+int omap3isp_preview_init(struct isp_device *isp);
+void omap3isp_preview_cleanup(struct isp_device *isp);
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prv,
+ struct v4l2_device *vdev);
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
+void omap3isp_preview_isr(struct isp_prev_device *prev);
+
+int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
+
+void omap3isp_preview_restore_context(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_PREVIEW_H */
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
new file mode 100644
index 000000000000..15bf3eab2224
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -0,0 +1,1158 @@
+/*
+ * ispqueue.c
+ *
+ * TI OMAP3 ISP - Video buffers queue handling
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "ispqueue.h"
+
+/* -----------------------------------------------------------------------------
+ * Video buffers management
+ */
+
+/*
+ * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP
+ *
+ * The typical operation required here is Cache Invalidation across
+ * the (user space) buffer address range. And this _must_ be done
+ * at QBUF stage (and *only* at QBUF).
+ *
+ * We try to use optimal cache invalidation function:
+ * - dmac_map_area:
+ * - used when the number of pages are _low_.
+ * - it becomes quite slow as the number of pages increase.
+ * - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
+ * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
+ *
+ * - flush_cache_all:
+ * - used when the number of pages are _high_.
+ * - time taken in the range of 500-900 us.
+ * - has a higher penalty but, as whole dcache + icache is invalidated
+ */
+/*
+ * FIXME: dmac_inv_range crashes randomly on the user space buffer
+ * address. Fall back to flush_cache_all for now.
+ */
+#define ISP_CACHE_FLUSH_PAGES_MAX 0
+
+static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf)
+{
+ if (buf->skip_cache)
+ return;
+
+ if (buf->vbuf.m.userptr == 0 || buf->npages == 0 ||
+ buf->npages > ISP_CACHE_FLUSH_PAGES_MAX)
+ flush_cache_all();
+ else {
+ dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length,
+ DMA_FROM_DEVICE);
+ outer_inv_range(buf->vbuf.m.userptr,
+ buf->vbuf.m.userptr + buf->vbuf.length);
+ }
+}
+
+/*
+ * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped
+ *
+ * Lock the VMAs underlying the given buffer into memory. This avoids the
+ * userspace buffer mapping from being swapped out, making VIPT cache handling
+ * easier.
+ *
+ * Note that the pages will not be freed as the buffers have been locked to
+ * memory using by a call to get_user_pages(), but the userspace mapping could
+ * still disappear if the VMAs are not locked. This is caused by the memory
+ * management code trying to be as lock-less as possible, which results in the
+ * userspace mapping manager not finding out that the pages are locked under
+ * some conditions.
+ */
+static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock)
+{
+ struct vm_area_struct *vma;
+ unsigned long start;
+ unsigned long end;
+ int ret = 0;
+
+ if (buf->vbuf.memory == V4L2_MEMORY_MMAP)
+ return 0;
+
+ /* We can be called from workqueue context if the current task dies to
+ * unlock the VMAs. In that case there's no current memory management
+ * context so unlocking can't be performed, but the VMAs have been or
+ * are getting destroyed anyway so it doesn't really matter.
+ */
+ if (!current || !current->mm)
+ return lock ? -EINVAL : 0;
+
+ start = buf->vbuf.m.userptr;
+ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+ down_write(&current->mm->mmap_sem);
+ spin_lock(&current->mm->page_table_lock);
+
+ do {
+ vma = find_vma(current->mm, start);
+ if (vma == NULL) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (lock)
+ vma->vm_flags |= VM_LOCKED;
+ else
+ vma->vm_flags &= ~VM_LOCKED;
+
+ start = vma->vm_end + 1;
+ } while (vma->vm_end < end);
+
+ if (lock)
+ buf->vm_flags |= VM_LOCKED;
+ else
+ buf->vm_flags &= ~VM_LOCKED;
+
+out:
+ spin_unlock(&current->mm->page_table_lock);
+ up_write(&current->mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer
+ *
+ * Iterate over the vmalloc'ed area and create a scatter list entry for every
+ * page.
+ */
+static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
+{
+ struct scatterlist *sglist;
+ unsigned int npages;
+ unsigned int i;
+ void *addr;
+
+ addr = buf->vaddr;
+ npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT;
+
+ sglist = vmalloc(npages * sizeof(*sglist));
+ if (sglist == NULL)
+ return -ENOMEM;
+
+ sg_init_table(sglist, npages);
+
+ for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
+ struct page *page = vmalloc_to_page(addr);
+
+ if (page == NULL || PageHighMem(page)) {
+ vfree(sglist);
+ return -EINVAL;
+ }
+
+ sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
+ }
+
+ buf->sglen = npages;
+ buf->sglist = sglist;
+
+ return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
+ *
+ * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
+ */
+static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
+{
+ struct scatterlist *sglist;
+ unsigned int offset = buf->offset;
+ unsigned int i;
+
+ sglist = vmalloc(buf->npages * sizeof(*sglist));
+ if (sglist == NULL)
+ return -ENOMEM;
+
+ sg_init_table(sglist, buf->npages);
+
+ for (i = 0; i < buf->npages; ++i) {
+ if (PageHighMem(buf->pages[i])) {
+ vfree(sglist);
+ return -EINVAL;
+ }
+
+ sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset,
+ offset);
+ offset = 0;
+ }
+
+ buf->sglen = buf->npages;
+ buf->sglist = sglist;
+
+ return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
+ *
+ * Create a scatter list of physically contiguous pages starting at the buffer
+ * memory physical address.
+ */
+static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
+{
+ struct scatterlist *sglist;
+ unsigned int offset = buf->offset;
+ unsigned long pfn = buf->paddr >> PAGE_SHIFT;
+ unsigned int i;
+
+ sglist = vmalloc(buf->npages * sizeof(*sglist));
+ if (sglist == NULL)
+ return -ENOMEM;
+
+ sg_init_table(sglist, buf->npages);
+
+ for (i = 0; i < buf->npages; ++i, ++pfn) {
+ sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset,
+ offset);
+ /* PFNMAP buffers will not get DMA-mapped, set the DMA address
+ * manually.
+ */
+ sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset;
+ offset = 0;
+ }
+
+ buf->sglen = buf->npages;
+ buf->sglist = sglist;
+
+ return 0;
+}
+
+/*
+ * isp_video_buffer_cleanup - Release pages for a userspace VMA.
+ *
+ * Release pages locked by a call isp_video_buffer_prepare_user and free the
+ * pages table.
+ */
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+ enum dma_data_direction direction;
+ unsigned int i;
+
+ if (buf->queue->ops->buffer_cleanup)
+ buf->queue->ops->buffer_cleanup(buf);
+
+ if (!(buf->vm_flags & VM_PFNMAP)) {
+ direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen,
+ direction);
+ }
+
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+ buf->sglen = 0;
+
+ if (buf->pages != NULL) {
+ isp_video_buffer_lock_vma(buf, 0);
+
+ for (i = 0; i < buf->npages; ++i)
+ page_cache_release(buf->pages[i]);
+
+ vfree(buf->pages);
+ buf->pages = NULL;
+ }
+
+ buf->npages = 0;
+ buf->skip_cache = false;
+}
+
+/*
+ * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory.
+ *
+ * This function creates a list of pages for a userspace VMA. The number of
+ * pages is first computed based on the buffer size, and pages are then
+ * retrieved by a call to get_user_pages.
+ *
+ * Pages are pinned to memory by get_user_pages, making them available for DMA
+ * transfers. However, due to memory management optimization, it seems the
+ * get_user_pages doesn't guarantee that the pinned pages will not be written
+ * to swap and removed from the userspace mapping(s). When this happens, a page
+ * fault can be generated when accessing those unmapped pages.
+ *
+ * If the fault is triggered by a page table walk caused by VIPT cache
+ * management operations, the page fault handler might oops if the MM semaphore
+ * is held, as it can't handle kernel page faults in that case. To fix that, a
+ * fixup entry needs to be added to the cache management code, or the userspace
+ * VMA must be locked to avoid removing pages from the userspace mapping in the
+ * first place.
+ *
+ * If the number of pages retrieved is smaller than the number required by the
+ * buffer size, the function returns -EFAULT.
+ */
+static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
+{
+ unsigned long data;
+ unsigned int first;
+ unsigned int last;
+ int ret;
+
+ data = buf->vbuf.m.userptr;
+ first = (data & PAGE_MASK) >> PAGE_SHIFT;
+ last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
+
+ buf->offset = data & ~PAGE_MASK;
+ buf->npages = last - first + 1;
+ buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
+ if (buf->pages == NULL)
+ return -ENOMEM;
+
+ down_read(&current->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm, data & PAGE_MASK,
+ buf->npages,
+ buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ buf->pages, NULL);
+ up_read(&current->mm->mmap_sem);
+
+ if (ret != buf->npages) {
+ buf->npages = ret < 0 ? 0 : ret;
+ isp_video_buffer_cleanup(buf);
+ return -EFAULT;
+ }
+
+ ret = isp_video_buffer_lock_vma(buf, 1);
+ if (ret < 0)
+ isp_video_buffer_cleanup(buf);
+
+ return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer
+ *
+ * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
+ * memory and if they span a single VMA.
+ *
+ * Return 0 if the buffer is valid, or -EFAULT otherwise.
+ */
+static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
+{
+ struct vm_area_struct *vma;
+ unsigned long prev_pfn;
+ unsigned long this_pfn;
+ unsigned long start;
+ unsigned long end;
+ dma_addr_t pa;
+ int ret = -EFAULT;
+
+ start = buf->vbuf.m.userptr;
+ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+ buf->offset = start & ~PAGE_MASK;
+ buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
+ buf->pages = NULL;
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(current->mm, start);
+ if (vma == NULL || vma->vm_end < end)
+ goto done;
+
+ for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
+ ret = follow_pfn(vma, start, &this_pfn);
+ if (ret)
+ goto done;
+
+ if (prev_pfn == 0)
+ pa = this_pfn << PAGE_SHIFT;
+ else if (this_pfn != prev_pfn + 1) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ prev_pfn = this_pfn;
+ }
+
+ buf->paddr = pa + buf->offset;
+ ret = 0;
+
+done:
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
+ *
+ * This function locates the VMAs for the buffer's userspace address and checks
+ * that their flags match. The only flag that we need to care for at the moment
+ * is VM_PFNMAP.
+ *
+ * The buffer vm_flags field is set to the first VMA flags.
+ *
+ * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs
+ * have incompatible flags.
+ */
+static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
+{
+ struct vm_area_struct *vma;
+ pgprot_t vm_page_prot;
+ unsigned long start;
+ unsigned long end;
+ int ret = -EFAULT;
+
+ start = buf->vbuf.m.userptr;
+ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+ down_read(&current->mm->mmap_sem);
+
+ do {
+ vma = find_vma(current->mm, start);
+ if (vma == NULL)
+ goto done;
+
+ if (start == buf->vbuf.m.userptr) {
+ buf->vm_flags = vma->vm_flags;
+ vm_page_prot = vma->vm_page_prot;
+ }
+
+ if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP)
+ goto done;
+
+ if (vm_page_prot != vma->vm_page_prot)
+ goto done;
+
+ start = vma->vm_end + 1;
+ } while (vma->vm_end < end);
+
+ /* Skip cache management to enhance performances for non-cached or
+ * write-combining buffers.
+ */
+ if (vm_page_prot == pgprot_noncached(vm_page_prot) ||
+ vm_page_prot == pgprot_writecombine(vm_page_prot))
+ buf->skip_cache = true;
+
+ ret = 0;
+
+done:
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * isp_video_buffer_prepare - Make a buffer ready for operation
+ *
+ * Preparing a buffer involves:
+ *
+ * - validating VMAs (userspace buffers only)
+ * - locking pages and VMAs into memory (userspace buffers only)
+ * - building page and scatter-gather lists
+ * - mapping buffers for DMA operation
+ * - performing driver-specific preparation
+ *
+ * The function must be called in userspace context with a valid mm context
+ * (this excludes cleanup paths such as sys_close when the userspace process
+ * segfaults).
+ */
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+ enum dma_data_direction direction;
+ int ret;
+
+ switch (buf->vbuf.memory) {
+ case V4L2_MEMORY_MMAP:
+ ret = isp_video_buffer_sglist_kernel(buf);
+ break;
+
+ case V4L2_MEMORY_USERPTR:
+ ret = isp_video_buffer_prepare_vm_flags(buf);
+ if (ret < 0)
+ return ret;
+
+ if (buf->vm_flags & VM_PFNMAP) {
+ ret = isp_video_buffer_prepare_pfnmap(buf);
+ if (ret < 0)
+ return ret;
+
+ ret = isp_video_buffer_sglist_pfnmap(buf);
+ } else {
+ ret = isp_video_buffer_prepare_user(buf);
+ if (ret < 0)
+ return ret;
+
+ ret = isp_video_buffer_sglist_user(buf);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ goto done;
+
+ if (!(buf->vm_flags & VM_PFNMAP)) {
+ direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen,
+ direction);
+ if (ret != buf->sglen) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (buf->queue->ops->buffer_prepare)
+ ret = buf->queue->ops->buffer_prepare(buf);
+
+done:
+ if (ret < 0) {
+ isp_video_buffer_cleanup(buf);
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * isp_video_queue_query - Query the status of a given buffer
+ *
+ * Locking: must be called with the queue lock held.
+ */
+static void isp_video_buffer_query(struct isp_video_buffer *buf,
+ struct v4l2_buffer *vbuf)
+{
+ memcpy(vbuf, &buf->vbuf, sizeof(*vbuf));
+
+ if (buf->vma_use_count)
+ vbuf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ switch (buf->state) {
+ case ISP_BUF_STATE_ERROR:
+ vbuf->flags |= V4L2_BUF_FLAG_ERROR;
+ case ISP_BUF_STATE_DONE:
+ vbuf->flags |= V4L2_BUF_FLAG_DONE;
+ case ISP_BUF_STATE_QUEUED:
+ case ISP_BUF_STATE_ACTIVE:
+ vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
+ break;
+ case ISP_BUF_STATE_IDLE:
+ default:
+ break;
+ }
+}
+
+/*
+ * isp_video_buffer_wait - Wait for a buffer to be ready
+ *
+ * In non-blocking mode, return immediately with 0 if the buffer is ready or
+ * -EAGAIN if the buffer is in the QUEUED or ACTIVE state.
+ *
+ * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait
+ * queue using the same condition.
+ */
+static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
+{
+ if (nonblocking) {
+ return (buf->state != ISP_BUF_STATE_QUEUED &&
+ buf->state != ISP_BUF_STATE_ACTIVE)
+ ? 0 : -EAGAIN;
+ }
+
+ return wait_event_interruptible(buf->wait,
+ buf->state != ISP_BUF_STATE_QUEUED &&
+ buf->state != ISP_BUF_STATE_ACTIVE);
+}
+
+/* -----------------------------------------------------------------------------
+ * Queue management
+ */
+
+/*
+ * isp_video_queue_free - Free video buffers memory
+ *
+ * Buffers can only be freed if the queue isn't streaming and if no buffer is
+ * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_free(struct isp_video_queue *queue)
+{
+ unsigned int i;
+
+ if (queue->streaming)
+ return -EBUSY;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffers[i]->vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ for (i = 0; i < queue->count; ++i) {
+ struct isp_video_buffer *buf = queue->buffers[i];
+
+ isp_video_buffer_cleanup(buf);
+
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+
+ kfree(buf);
+ queue->buffers[i] = NULL;
+ }
+
+ INIT_LIST_HEAD(&queue->queue);
+ queue->count = 0;
+ return 0;
+}
+
+/*
+ * isp_video_queue_alloc - Allocate video buffers memory
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_alloc(struct isp_video_queue *queue,
+ unsigned int nbuffers,
+ unsigned int size, enum v4l2_memory memory)
+{
+ struct isp_video_buffer *buf;
+ unsigned int i;
+ void *mem;
+ int ret;
+
+ /* Start by freeing the buffers. */
+ ret = isp_video_queue_free(queue);
+ if (ret < 0)
+ return ret;
+
+ /* Bail out if no buffers should be allocated. */
+ if (nbuffers == 0)
+ return 0;
+
+ /* Initialize the allocated buffers. */
+ for (i = 0; i < nbuffers; ++i) {
+ buf = kzalloc(queue->bufsize, GFP_KERNEL);
+ if (buf == NULL)
+ break;
+
+ if (memory == V4L2_MEMORY_MMAP) {
+ /* Allocate video buffers memory for mmap mode. Align
+ * the size to the page size.
+ */
+ mem = vmalloc_32_user(PAGE_ALIGN(size));
+ if (mem == NULL) {
+ kfree(buf);
+ break;
+ }
+
+ buf->vbuf.m.offset = i * PAGE_ALIGN(size);
+ buf->vaddr = mem;
+ }
+
+ buf->vbuf.index = i;
+ buf->vbuf.length = size;
+ buf->vbuf.type = queue->type;
+ buf->vbuf.field = V4L2_FIELD_NONE;
+ buf->vbuf.memory = memory;
+
+ buf->queue = queue;
+ init_waitqueue_head(&buf->wait);
+
+ queue->buffers[i] = buf;
+ }
+
+ if (i == 0)
+ return -ENOMEM;
+
+ queue->count = i;
+ return nbuffers;
+}
+
+/**
+ * omap3isp_video_queue_cleanup - Clean up the video buffers queue
+ * @queue: Video buffers queue
+ *
+ * Free all allocated resources and clean up the video buffers queue. The queue
+ * must not be busy (no ongoing video stream) and buffers must have been
+ * unmapped.
+ *
+ * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been
+ * unmapped.
+ */
+int omap3isp_video_queue_cleanup(struct isp_video_queue *queue)
+{
+ return isp_video_queue_free(queue);
+}
+
+/**
+ * omap3isp_video_queue_init - Initialize the video buffers queue
+ * @queue: Video buffers queue
+ * @type: V4L2 buffer type (capture or output)
+ * @ops: Driver-specific queue operations
+ * @dev: Device used for DMA operations
+ * @bufsize: Size of the driver-specific buffer structure
+ *
+ * Initialize the video buffers queue with the supplied parameters.
+ *
+ * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or
+ * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet.
+ *
+ * Buffer objects will be allocated using the given buffer size to allow room
+ * for driver-specific fields. Driver-specific buffer structures must start
+ * with a struct isp_video_buffer field. Drivers with no driver-specific buffer
+ * structure must pass the size of the isp_video_buffer structure in the bufsize
+ * parameter.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_init(struct isp_video_queue *queue,
+ enum v4l2_buf_type type,
+ const struct isp_video_queue_operations *ops,
+ struct device *dev, unsigned int bufsize)
+{
+ INIT_LIST_HEAD(&queue->queue);
+ mutex_init(&queue->lock);
+ spin_lock_init(&queue->irqlock);
+
+ queue->type = type;
+ queue->ops = ops;
+ queue->dev = dev;
+ queue->bufsize = bufsize;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 operations
+ */
+
+/**
+ * omap3isp_video_queue_reqbufs - Allocate video buffers memory
+ *
+ * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It
+ * allocated video buffer objects and, for MMAP buffers, buffer memory.
+ *
+ * If the number of buffers is 0, all buffers are freed and the function returns
+ * without performing any allocation.
+ *
+ * If the number of buffers is not 0, currently allocated buffers (if any) are
+ * freed and the requested number of buffers are allocated. Depending on
+ * driver-specific requirements and on memory availability, a number of buffer
+ * smaller or bigger than requested can be allocated. This isn't considered as
+ * an error.
+ *
+ * Return 0 on success or one of the following error codes:
+ *
+ * -EINVAL if the buffer type or index are invalid
+ * -EBUSY if the queue is busy (streaming or buffers mapped)
+ * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition
+ */
+int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
+ struct v4l2_requestbuffers *rb)
+{
+ unsigned int nbuffers = rb->count;
+ unsigned int size;
+ int ret;
+
+ if (rb->type != queue->type)
+ return -EINVAL;
+
+ queue->ops->queue_prepare(queue, &nbuffers, &size);
+ if (size == 0)
+ return -EINVAL;
+
+ nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS);
+
+ mutex_lock(&queue->lock);
+
+ ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory);
+ if (ret < 0)
+ goto done;
+
+ rb->count = ret;
+ ret = 0;
+
+done:
+ mutex_unlock(&queue->lock);
+ return ret;
+}
+
+/**
+ * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue
+ *
+ * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It
+ * returns the status of a given video buffer.
+ *
+ * Return 0 on success or -EINVAL if the buffer type or index are invalid.
+ */
+int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
+ struct v4l2_buffer *vbuf)
+{
+ struct isp_video_buffer *buf;
+ int ret = 0;
+
+ if (vbuf->type != queue->type)
+ return -EINVAL;
+
+ mutex_lock(&queue->lock);
+
+ if (vbuf->index >= queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = queue->buffers[vbuf->index];
+ isp_video_buffer_query(buf, vbuf);
+
+done:
+ mutex_unlock(&queue->lock);
+ return ret;
+}
+
+/**
+ * omap3isp_video_queue_qbuf - Queue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_QBUF ioctl handler.
+ *
+ * The v4l2_buffer structure passed from userspace is first sanity tested. If
+ * sane, the buffer is then processed and added to the main queue and, if the
+ * queue is streaming, to the IRQ queue.
+ *
+ * Before being enqueued, USERPTR buffers are checked for address changes. If
+ * the buffer has a different userspace address, the old memory area is unlocked
+ * and the new memory area is locked.
+ */
+int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
+ struct v4l2_buffer *vbuf)
+{
+ struct isp_video_buffer *buf;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ if (vbuf->type != queue->type)
+ goto done;
+
+ mutex_lock(&queue->lock);
+
+ if (vbuf->index >= queue->count)
+ goto done;
+
+ buf = queue->buffers[vbuf->index];
+
+ if (vbuf->memory != buf->vbuf.memory)
+ goto done;
+
+ if (buf->state != ISP_BUF_STATE_IDLE)
+ goto done;
+
+ if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+ vbuf->length < buf->vbuf.length)
+ goto done;
+
+ if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+ vbuf->m.userptr != buf->vbuf.m.userptr) {
+ isp_video_buffer_cleanup(buf);
+ buf->vbuf.m.userptr = vbuf->m.userptr;
+ buf->prepared = 0;
+ }
+
+ if (!buf->prepared) {
+ ret = isp_video_buffer_prepare(buf);
+ if (ret < 0)
+ goto done;
+ buf->prepared = 1;
+ }
+
+ isp_video_buffer_cache_sync(buf);
+
+ buf->state = ISP_BUF_STATE_QUEUED;
+ list_add_tail(&buf->stream, &queue->queue);
+
+ if (queue->streaming) {
+ spin_lock_irqsave(&queue->irqlock, flags);
+ queue->ops->buffer_queue(buf);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+ }
+
+ ret = 0;
+
+done:
+ mutex_unlock(&queue->lock);
+ return ret;
+}
+
+/**
+ * omap3isp_video_queue_dqbuf - Dequeue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
+ *
+ * Wait until a buffer is ready to be dequeued, remove it from the queue and
+ * copy its information to the v4l2_buffer structure.
+ *
+ * If the nonblocking argument is not zero and no buffer is ready, return
+ * -EAGAIN immediately instead of waiting.
+ *
+ * If no buffer has been enqueued, or if the requested buffer type doesn't match
+ * the queue type, return -EINVAL.
+ */
+int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
+ struct v4l2_buffer *vbuf, int nonblocking)
+{
+ struct isp_video_buffer *buf;
+ int ret;
+
+ if (vbuf->type != queue->type)
+ return -EINVAL;
+
+ mutex_lock(&queue->lock);
+
+ if (list_empty(&queue->queue)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+ ret = isp_video_buffer_wait(buf, nonblocking);
+ if (ret < 0)
+ goto done;
+
+ list_del(&buf->stream);
+
+ isp_video_buffer_query(buf, vbuf);
+ buf->state = ISP_BUF_STATE_IDLE;
+ vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+done:
+ mutex_unlock(&queue->lock);
+ return ret;
+}
+
+/**
+ * omap3isp_video_queue_streamon - Start streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It
+ * starts streaming on the queue and calls the buffer_queue operation for all
+ * queued buffers.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_streamon(struct isp_video_queue *queue)
+{
+ struct isp_video_buffer *buf;
+ unsigned long flags;
+
+ mutex_lock(&queue->lock);
+
+ if (queue->streaming)
+ goto done;
+
+ queue->streaming = 1;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ list_for_each_entry(buf, &queue->queue, stream)
+ queue->ops->buffer_queue(buf);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+ mutex_unlock(&queue->lock);
+ return 0;
+}
+
+/**
+ * omap3isp_video_queue_streamoff - Stop streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It
+ * stops streaming on the queue and wakes up all the buffers.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_streamoff(struct isp_video_queue *queue)
+{
+ struct isp_video_buffer *buf;
+ unsigned long flags;
+ unsigned int i;
+
+ mutex_lock(&queue->lock);
+
+ if (!queue->streaming)
+ goto done;
+
+ queue->streaming = 0;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ for (i = 0; i < queue->count; ++i) {
+ buf = queue->buffers[i];
+
+ if (buf->state == ISP_BUF_STATE_ACTIVE)
+ wake_up(&buf->wait);
+
+ buf->state = ISP_BUF_STATE_IDLE;
+ }
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ INIT_LIST_HEAD(&queue->queue);
+
+done:
+ mutex_unlock(&queue->lock);
+}
+
+/**
+ * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE
+ *
+ * This function is intended to be used with suspend/resume operations. It
+ * discards all 'done' buffers as they would be too old to be requested after
+ * resume.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_discard_done(struct isp_video_queue *queue)
+{
+ struct isp_video_buffer *buf;
+ unsigned int i;
+
+ mutex_lock(&queue->lock);
+
+ if (!queue->streaming)
+ goto done;
+
+ for (i = 0; i < queue->count; ++i) {
+ buf = queue->buffers[i];
+
+ if (buf->state == ISP_BUF_STATE_DONE)
+ buf->state = ISP_BUF_STATE_ERROR;
+ }
+
+done:
+ mutex_unlock(&queue->lock);
+}
+
+static void isp_video_queue_vm_open(struct vm_area_struct *vma)
+{
+ struct isp_video_buffer *buf = vma->vm_private_data;
+
+ buf->vma_use_count++;
+}
+
+static void isp_video_queue_vm_close(struct vm_area_struct *vma)
+{
+ struct isp_video_buffer *buf = vma->vm_private_data;
+
+ buf->vma_use_count--;
+}
+
+static const struct vm_operations_struct isp_video_queue_vm_ops = {
+ .open = isp_video_queue_vm_open,
+ .close = isp_video_queue_vm_close,
+};
+
+/**
+ * omap3isp_video_queue_mmap - Map buffers to userspace
+ *
+ * This function is intended to be used as an mmap() file operation handler. It
+ * maps a buffer to userspace based on the VMA offset.
+ *
+ * Only buffers of memory type MMAP are supported.
+ */
+int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
+ struct vm_area_struct *vma)
+{
+ struct isp_video_buffer *uninitialized_var(buf);
+ unsigned long size;
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&queue->lock);
+
+ for (i = 0; i < queue->count; ++i) {
+ buf = queue->buffers[i];
+ if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ size = vma->vm_end - vma->vm_start;
+
+ if (buf->vbuf.memory != V4L2_MEMORY_MMAP ||
+ size != PAGE_ALIGN(buf->vbuf.length)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+ if (ret < 0)
+ goto done;
+
+ vma->vm_ops = &isp_video_queue_vm_ops;
+ vma->vm_private_data = buf;
+ isp_video_queue_vm_open(vma);
+
+done:
+ mutex_unlock(&queue->lock);
+ return ret;
+}
+
+/**
+ * omap3isp_video_queue_poll - Poll video queue state
+ *
+ * This function is intended to be used as a poll() file operation handler. It
+ * polls the state of the video buffer at the front of the queue and returns an
+ * events mask.
+ *
+ * If no buffer is present at the front of the queue, POLLERR is returned.
+ */
+unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
+ struct file *file, poll_table *wait)
+{
+ struct isp_video_buffer *buf;
+ unsigned int mask = 0;
+
+ mutex_lock(&queue->lock);
+ if (list_empty(&queue->queue)) {
+ mask |= POLLERR;
+ goto done;
+ }
+ buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+
+ poll_wait(file, &buf->wait, wait);
+ if (buf->state == ISP_BUF_STATE_DONE ||
+ buf->state == ISP_BUF_STATE_ERROR) {
+ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ mask |= POLLIN | POLLRDNORM;
+ else
+ mask |= POLLOUT | POLLWRNORM;
+ }
+
+done:
+ mutex_unlock(&queue->lock);
+ return mask;
+}
diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
index 908dfd712e8e..908dfd712e8e 100644
--- a/drivers/media/video/omap3isp/ispqueue.h
+++ b/drivers/media/platform/omap3isp/ispqueue.h
diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
index 084ea77d65a7..084ea77d65a7 100644
--- a/drivers/media/video/omap3isp/ispreg.h
+++ b/drivers/media/platform/omap3isp/ispreg.h
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
new file mode 100644
index 000000000000..d11fb261d530
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -0,0 +1,1778 @@
+/*
+ * ispresizer.c
+ *
+ * TI OMAP3 ISP - Resizer module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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/mm.h>
+#include <linux/module.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+
+/*
+ * Resizer Constants
+ */
+#define MIN_RESIZE_VALUE 64
+#define MID_RESIZE_VALUE 512
+#define MAX_RESIZE_VALUE 1024
+
+#define MIN_IN_WIDTH 32
+#define MIN_IN_HEIGHT 32
+#define MAX_IN_WIDTH_MEMORY_MODE 4095
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
+#define MAX_IN_HEIGHT 4095
+
+#define MIN_OUT_WIDTH 16
+#define MIN_OUT_HEIGHT 2
+#define MAX_OUT_HEIGHT 4095
+
+/*
+ * Resizer Use Constraints
+ * "TRM ES3.1, table 12-46"
+ */
+#define MAX_4TAP_OUT_WIDTH_ES1 1280
+#define MAX_7TAP_OUT_WIDTH_ES1 640
+#define MAX_4TAP_OUT_WIDTH_ES2 3312
+#define MAX_7TAP_OUT_WIDTH_ES2 1650
+#define MAX_4TAP_OUT_WIDTH_3630 4096
+#define MAX_7TAP_OUT_WIDTH_3630 2048
+
+/*
+ * Constants for ratio calculation
+ */
+#define RESIZE_DIVISOR 256
+#define DEFAULT_PHASE 1
+
+/*
+ * Default (and only) configuration of filter coefficients.
+ * 7-tap mode is for scale factors 0.25x to 0.5x.
+ * 4-tap mode is for scale factors 0.5x to 4.0x.
+ * There shouldn't be any reason to recalculate these, EVER.
+ */
+static const struct isprsz_coef filter_coefs = {
+ /* For 8-phase 4-tap horizontal filter: */
+ {
+ 0x0000, 0x0100, 0x0000, 0x0000,
+ 0x03FA, 0x00F6, 0x0010, 0x0000,
+ 0x03F9, 0x00DB, 0x002C, 0x0000,
+ 0x03FB, 0x00B3, 0x0053, 0x03FF,
+ 0x03FD, 0x0082, 0x0084, 0x03FD,
+ 0x03FF, 0x0053, 0x00B3, 0x03FB,
+ 0x0000, 0x002C, 0x00DB, 0x03F9,
+ 0x0000, 0x0010, 0x00F6, 0x03FA
+ },
+ /* For 8-phase 4-tap vertical filter: */
+ {
+ 0x0000, 0x0100, 0x0000, 0x0000,
+ 0x03FA, 0x00F6, 0x0010, 0x0000,
+ 0x03F9, 0x00DB, 0x002C, 0x0000,
+ 0x03FB, 0x00B3, 0x0053, 0x03FF,
+ 0x03FD, 0x0082, 0x0084, 0x03FD,
+ 0x03FF, 0x0053, 0x00B3, 0x03FB,
+ 0x0000, 0x002C, 0x00DB, 0x03F9,
+ 0x0000, 0x0010, 0x00F6, 0x03FA
+ },
+ /* For 4-phase 7-tap horizontal filter: */
+ #define DUMMY 0
+ {
+ 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+ 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+ 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+ 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+ },
+ /* For 4-phase 7-tap vertical filter: */
+ {
+ 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+ 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+ 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+ 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+ }
+ /*
+ * The dummy padding is required in 7-tap mode because of how the
+ * registers are arranged physically.
+ */
+ #undef DUMMY
+};
+
+/*
+ * __resizer_get_format - helper function for getting resizer format
+ * @res : pointer to resizer private structure
+ * @pad : pad number
+ * @fh : V4L2 subdev file handle
+ * @which : wanted subdev format
+ * return zero
+ */
+static struct v4l2_mbus_framefmt *
+__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &res->formats[pad];
+}
+
+/*
+ * __resizer_get_crop - helper function for getting resizer crop rectangle
+ * @res : pointer to resizer private structure
+ * @fh : V4L2 subdev file handle
+ * @which : wanted subdev crop rectangle
+ */
+static struct v4l2_rect *
+__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
+ else
+ return &res->crop.request;
+}
+
+/*
+ * resizer_set_filters - Set resizer filters
+ * @res: Device context.
+ * @h_coeff: horizontal coefficient
+ * @v_coeff: vertical coefficient
+ * Return none
+ */
+static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
+ const u16 *v_coeff)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
+ int i;
+
+ startaddr_h = ISPRSZ_HFILT10;
+ startaddr_v = ISPRSZ_VFILT10;
+
+ for (i = 0; i < COEFF_CNT; i += 2) {
+ tmp_h = h_coeff[i] |
+ (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
+ tmp_v = v_coeff[i] |
+ (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
+ isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
+ isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
+ startaddr_h += 4;
+ startaddr_v += 4;
+ }
+}
+
+/*
+ * resizer_set_bilinear - Chrominance horizontal algorithm select
+ * @res: Device context.
+ * @type: Filtering interpolation type.
+ *
+ * Filtering that is same as luminance processing is
+ * intended only for downsampling, and bilinear interpolation
+ * is intended only for upsampling.
+ */
+static void resizer_set_bilinear(struct isp_res_device *res,
+ enum resizer_chroma_algo type)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ if (type == RSZ_BILINEAR)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_CBILIN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_CBILIN);
+}
+
+/*
+ * resizer_set_ycpos - Luminance and chrominance order
+ * @res: Device context.
+ * @order: order type.
+ */
+static void resizer_set_ycpos(struct isp_res_device *res,
+ enum v4l2_mbus_pixelcode pixelcode)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ switch (pixelcode) {
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_YCPOS);
+ break;
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_YCPOS);
+ break;
+ default:
+ return;
+ }
+}
+
+/*
+ * resizer_set_phase - Setup horizontal and vertical starting phase
+ * @res: Device context.
+ * @h_phase: horizontal phase parameters.
+ * @v_phase: vertical phase parameters.
+ *
+ * Horizontal and vertical phase range is 0 to 7
+ */
+static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
+ u32 v_phase)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 rgval = 0;
+
+ rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+ ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
+ rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
+ rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
+
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+}
+
+/*
+ * resizer_set_luma - Setup luminance enhancer parameters
+ * @res: Device context.
+ * @luma: Structure for luminance enhancer parameters.
+ *
+ * Algorithm select:
+ * 0x0: Disable
+ * 0x1: [-1 2 -1]/2 high-pass filter
+ * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
+ *
+ * Maximum gain:
+ * The data is coded in U4Q4 representation.
+ *
+ * Slope:
+ * The data is coded in U4Q4 representation.
+ *
+ * Coring offset:
+ * The data is coded in U8Q0 representation.
+ *
+ * The new luminance value is computed as:
+ * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
+ */
+static void resizer_set_luma(struct isp_res_device *res,
+ struct resizer_luma_yenh *luma)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 rgval = 0;
+
+ rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
+ & ISPRSZ_YENH_ALGO_MASK;
+ rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
+ & ISPRSZ_YENH_GAIN_MASK;
+ rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
+ & ISPRSZ_YENH_SLOP_MASK;
+ rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
+ & ISPRSZ_YENH_CORE_MASK;
+
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
+}
+
+/*
+ * resizer_set_source - Input source select
+ * @res: Device context.
+ * @source: Input source type
+ *
+ * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
+ * Preview/CCDC engine, otherwise from memory.
+ */
+static void resizer_set_source(struct isp_res_device *res,
+ enum resizer_input_entity source)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ if (source == RESIZER_INPUT_MEMORY)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_INPSRC);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_INPSRC);
+}
+
+/*
+ * resizer_set_ratio - Setup horizontal and vertical resizing value
+ * @res: Device context.
+ * @ratio: Structure for ratio parameters.
+ *
+ * Resizing range from 64 to 1024
+ */
+static void resizer_set_ratio(struct isp_res_device *res,
+ const struct resizer_ratio *ratio)
+{
+ struct isp_device *isp = to_isp_device(res);
+ const u16 *h_filter, *v_filter;
+ u32 rgval = 0;
+
+ rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+ ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
+ rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
+ & ISPRSZ_CNT_HRSZ_MASK;
+ rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
+ & ISPRSZ_CNT_VRSZ_MASK;
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+
+ /* prepare horizontal filter coefficients */
+ if (ratio->horz > MID_RESIZE_VALUE)
+ h_filter = &filter_coefs.h_filter_coef_7tap[0];
+ else
+ h_filter = &filter_coefs.h_filter_coef_4tap[0];
+
+ /* prepare vertical filter coefficients */
+ if (ratio->vert > MID_RESIZE_VALUE)
+ v_filter = &filter_coefs.v_filter_coef_7tap[0];
+ else
+ v_filter = &filter_coefs.v_filter_coef_4tap[0];
+
+ resizer_set_filters(res, h_filter, v_filter);
+}
+
+/*
+ * resizer_set_dst_size - Setup the output height and width
+ * @res: Device context.
+ * @width: Output width.
+ * @height: Output height.
+ *
+ * Width :
+ * The value must be EVEN.
+ *
+ * Height:
+ * The number of bytes written to SDRAM must be
+ * a multiple of 16-bytes if the vertical resizing factor
+ * is greater than 1x (upsizing)
+ */
+static void resizer_set_output_size(struct isp_res_device *res,
+ u32 width, u32 height)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 rgval = 0;
+
+ dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
+ rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
+ & ISPRSZ_OUT_SIZE_HORZ_MASK;
+ rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
+ & ISPRSZ_OUT_SIZE_VERT_MASK;
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
+}
+
+/*
+ * resizer_set_output_offset - Setup memory offset for the output lines.
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
+ * the SDRAM line offset must be set on a 256-byte boundary
+ */
+static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+}
+
+/*
+ * resizer_set_start - Setup vertical and horizontal start position
+ * @res: Device context.
+ * @left: Horizontal start position.
+ * @top: Vertical start position.
+ *
+ * Vertical start line:
+ * This field makes sense only when the resizer obtains its input
+ * from the preview engine/CCDC
+ *
+ * Horizontal start pixel:
+ * Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
+ * When the resizer gets its input from SDRAM, this field must be set
+ * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
+ */
+static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 rgval = 0;
+
+ rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
+ & ISPRSZ_IN_START_HORZ_ST_MASK;
+ rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
+ & ISPRSZ_IN_START_VERT_ST_MASK;
+
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+}
+
+/*
+ * resizer_set_input_size - Setup the input size
+ * @res: Device context.
+ * @width: The range is 0 to 4095 pixels
+ * @height: The range is 0 to 4095 lines
+ */
+static void resizer_set_input_size(struct isp_res_device *res,
+ u32 width, u32 height)
+{
+ struct isp_device *isp = to_isp_device(res);
+ u32 rgval = 0;
+
+ dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+
+ rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
+ & ISPRSZ_IN_SIZE_HORZ_MASK;
+ rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
+ & ISPRSZ_IN_SIZE_VERT_MASK;
+
+ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
+}
+
+/*
+ * resizer_set_src_offs - Setup the memory offset for the input lines
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. This field must be programmed to be
+ * 0x0 if the resizer input is from preview engine/CCDC.
+ */
+static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
+}
+
+/*
+ * resizer_set_intype - Input type select
+ * @res: Device context.
+ * @type: Pixel format type.
+ */
+static void resizer_set_intype(struct isp_res_device *res,
+ enum resizer_colors_type type)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ if (type == RSZ_COLOR8)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_INPTYP);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ISPRSZ_CNT_INPTYP);
+}
+
+/*
+ * __resizer_set_inaddr - Helper function for set input address
+ * @res : pointer to resizer private data structure
+ * @addr: input address
+ * return none
+ */
+static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+}
+
+/*
+ * The data rate at the horizontal resizer output must not exceed half the
+ * functional clock or 100 MP/s, whichever is lower. According to the TRM
+ * there's no similar requirement for the vertical resizer output. However
+ * experience showed that vertical upscaling by 4 leads to SBL overflows (with
+ * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
+ * output data rate to the functional clock or 200 MP/s, whichever is lower,
+ * seems to get rid of SBL overflows.
+ *
+ * The maximum data rate at the output of the horizontal resizer can thus be
+ * computed with
+ *
+ * max intermediate rate <= L3 clock * input height / output height
+ * max intermediate rate <= L3 clock / 2
+ *
+ * The maximum data rate at the resizer input is then
+ *
+ * max input rate <= max intermediate rate * input width / output width
+ *
+ * where the input width and height are the resizer input crop rectangle size.
+ * The TRM doesn't clearly explain if that's a maximum instant data rate or a
+ * maximum average data rate.
+ */
+void omap3isp_resizer_max_rate(struct isp_res_device *res,
+ unsigned int *max_rate)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+ const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
+ unsigned long limit = min(pipe->l3_ick, 200000000UL);
+ unsigned long clock;
+
+ clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
+ clock = min(clock, limit / 2);
+ *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
+}
+
+/*
+ * When the resizer processes images from memory, the driver must slow down read
+ * requests on the input to at least comply with the internal data rate
+ * requirements. If the application real-time requirements can cope with slower
+ * processing, the resizer can be slowed down even more to put less pressure on
+ * the overall system.
+ *
+ * When the resizer processes images on the fly (either from the CCDC or the
+ * preview module), the same data rate requirements apply but they can't be
+ * enforced at the resizer level. The image input module (sensor, CCP2 or
+ * preview module) must not provide image data faster than the resizer can
+ * process.
+ *
+ * For live image pipelines, the data rate is set by the frame format, size and
+ * rate. The sensor output frame rate must not exceed the maximum resizer data
+ * rate.
+ *
+ * The resizer slows down read requests by inserting wait cycles in the SBL
+ * requests. The maximum number of 256-byte requests per second can be computed
+ * as (the data rate is multiplied by 2 to convert from pixels per second to
+ * bytes per second)
+ *
+ * request per second = data rate * 2 / 256
+ * cycles per request = cycles per second / requests per second
+ *
+ * The number of cycles per second is controlled by the L3 clock, leading to
+ *
+ * cycles per request = L3 frequency / 2 * 256 / data rate
+ */
+static void resizer_adjust_bandwidth(struct isp_res_device *res)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+ struct isp_device *isp = to_isp_device(res);
+ unsigned long l3_ick = pipe->l3_ick;
+ struct v4l2_fract *timeperframe;
+ unsigned int cycles_per_frame;
+ unsigned int requests_per_frame;
+ unsigned int cycles_per_request;
+ unsigned int granularity;
+ unsigned int minimum;
+ unsigned int maximum;
+ unsigned int value;
+
+ if (res->input != RESIZER_INPUT_MEMORY) {
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+ ISPSBL_SDR_REQ_RSZ_EXP_MASK);
+ return;
+ }
+
+ switch (isp->revision) {
+ case ISP_REVISION_1_0:
+ case ISP_REVISION_2_0:
+ default:
+ granularity = 1024;
+ break;
+
+ case ISP_REVISION_15_0:
+ granularity = 32;
+ break;
+ }
+
+ /* Compute the minimum number of cycles per request, based on the
+ * pipeline maximum data rate. This is an absolute lower bound if we
+ * don't want SBL overflows, so round the value up.
+ */
+ cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+ pipe->max_rate);
+ minimum = DIV_ROUND_UP(cycles_per_request, granularity);
+
+ /* Compute the maximum number of cycles per request, based on the
+ * requested frame rate. This is a soft upper bound to achieve a frame
+ * rate equal or higher than the requested value, so round the value
+ * down.
+ */
+ timeperframe = &pipe->max_timeperframe;
+
+ requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
+ * res->crop.active.height;
+ cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+ timeperframe->denominator);
+ cycles_per_request = cycles_per_frame / requests_per_frame;
+
+ maximum = cycles_per_request / granularity;
+
+ value = max(minimum, maximum);
+
+ dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+ ISPSBL_SDR_REQ_RSZ_EXP_MASK,
+ value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_resizer_busy - Checks if ISP resizer is busy.
+ *
+ * Returns busy field from ISPRSZ_PCR register.
+ */
+int omap3isp_resizer_busy(struct isp_res_device *res)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+ ISPRSZ_PCR_BUSY;
+}
+
+/*
+ * resizer_set_inaddr - Sets the memory address of the input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ */
+static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+ res->addr_base = addr;
+
+ /* This will handle crop settings in stream off state */
+ if (res->crop_offset)
+ addr += res->crop_offset & ~0x1f;
+
+ __resizer_set_inaddr(res, addr);
+}
+
+/*
+ * Configures the memory address to which the output frame is written.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ * Note: For SBL efficiency reasons the address should be on a 256-byte
+ * boundary.
+ */
+static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ /*
+ * Set output address. This needs to be in its own function
+ * because it changes often.
+ */
+ isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+}
+
+/*
+ * resizer_print_status - Prints the values of the resizer module registers.
+ */
+#define RSZ_PRINT_REGISTER(isp, name)\
+ dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
+ isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
+
+static void resizer_print_status(struct isp_res_device *res)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
+
+ RSZ_PRINT_REGISTER(isp, PCR);
+ RSZ_PRINT_REGISTER(isp, CNT);
+ RSZ_PRINT_REGISTER(isp, OUT_SIZE);
+ RSZ_PRINT_REGISTER(isp, IN_START);
+ RSZ_PRINT_REGISTER(isp, IN_SIZE);
+ RSZ_PRINT_REGISTER(isp, SDR_INADD);
+ RSZ_PRINT_REGISTER(isp, SDR_INOFF);
+ RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
+ RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
+ RSZ_PRINT_REGISTER(isp, YENH);
+
+ dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * resizer_calc_ratios - Helper function for calculating resizer ratios
+ * @res: pointer to resizer private data structure
+ * @input: input frame size
+ * @output: output frame size
+ * @ratio : return calculated ratios
+ * return none
+ *
+ * The resizer uses a polyphase sample rate converter. The upsampling filter
+ * has a fixed number of phases that depend on the resizing ratio. As the ratio
+ * computation depends on the number of phases, we need to compute a first
+ * approximation and then refine it.
+ *
+ * The input/output/ratio relationship is given by the OMAP34xx TRM:
+ *
+ * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
+ * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
+ * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
+ * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
+ * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
+ * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
+ *
+ * iw and ih are the input width and height after cropping. Those equations need
+ * to be satisfied exactly for the resizer to work correctly.
+ *
+ * The equations can't be easily reverted, as the >> 8 operation is not linear.
+ * In addition, not all input sizes can be achieved for a given output size. To
+ * get the highest input size lower than or equal to the requested input size,
+ * we need to compute the highest resizing ratio that satisfies the following
+ * inequality (taking the 4-tap mode width equation as an example)
+ *
+ * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
+ *
+ * (where iw is the requested input width) which can be rewritten as
+ *
+ * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
+ * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b
+ * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16
+ *
+ * where b is the value of the 8 least significant bits of the right hand side
+ * expression of the last inequality. The highest resizing ratio value will be
+ * achieved when b is equal to its maximum value of 255. That resizing ratio
+ * value will still satisfy the original inequality, as b will disappear when
+ * the expression will be shifted right by 8.
+ *
+ * The reverted equations thus become
+ *
+ * - 8-phase, 4-tap mode
+ * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
+ * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
+ * - 4-phase, 7-tap mode
+ * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
+ * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
+ *
+ * The ratios are integer values, and are rounded down to ensure that the
+ * cropped input size is not bigger than the uncropped input size.
+ *
+ * As the number of phases/taps, used to select the correct equations to compute
+ * the ratio, depends on the ratio, we start with the 4-tap mode equations to
+ * compute an approximation of the ratio, and switch to the 7-tap mode equations
+ * if the approximation is higher than the ratio threshold.
+ *
+ * As the 7-tap mode equations will return a ratio smaller than or equal to the
+ * 4-tap mode equations, the resulting ratio could become lower than or equal to
+ * the ratio threshold. This 'equations loop' isn't an issue as long as the
+ * correct equations are used to compute the final input size. Starting with the
+ * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
+ * loop', the smallest of the ratio values will be used, never exceeding the
+ * requested input size.
+ *
+ * We first clamp the output size according to the hardware capability to avoid
+ * auto-cropping the input more than required to satisfy the TRM equations. The
+ * minimum output size is achieved with a scaling factor of 1024. It is thus
+ * computed using the 7-tap equations.
+ *
+ * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
+ * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
+ *
+ * Similarly, the maximum output size is achieved with a scaling factor of 64
+ * and computed using the 4-tap equations.
+ *
+ * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
+ * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
+ *
+ * The additional +255 term compensates for the round down operation performed
+ * by the TRM equations when shifting the value right by 8 bits.
+ *
+ * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
+ * the maximum value guarantees that the ratio value will never be smaller than
+ * the minimum, but it could still slightly exceed the maximum. Clamping the
+ * ratio will thus result in a resizing factor slightly larger than the
+ * requested value.
+ *
+ * To accommodate that, and make sure the TRM equations are satisfied exactly, we
+ * compute the input crop rectangle as the last step.
+ *
+ * As if the situation wasn't complex enough, the maximum output width depends
+ * on the vertical resizing ratio. Fortunately, the output height doesn't
+ * depend on the horizontal resizing ratio. We can then start by computing the
+ * output height and the vertical ratio, and then move to computing the output
+ * width and the horizontal ratio.
+ */
+static void resizer_calc_ratios(struct isp_res_device *res,
+ struct v4l2_rect *input,
+ struct v4l2_mbus_framefmt *output,
+ struct resizer_ratio *ratio)
+{
+ struct isp_device *isp = to_isp_device(res);
+ const unsigned int spv = DEFAULT_PHASE;
+ const unsigned int sph = DEFAULT_PHASE;
+ unsigned int upscaled_width;
+ unsigned int upscaled_height;
+ unsigned int min_width;
+ unsigned int min_height;
+ unsigned int max_width;
+ unsigned int max_height;
+ unsigned int width_alignment;
+ unsigned int width;
+ unsigned int height;
+
+ /*
+ * Clamp the output height based on the hardware capabilities and
+ * compute the vertical resizing ratio.
+ */
+ min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
+ min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
+ max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
+ max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
+ output->height = clamp(output->height, min_height, max_height);
+
+ ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
+ / (output->height - 1);
+ if (ratio->vert > MID_RESIZE_VALUE)
+ ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
+ / (output->height - 1);
+ ratio->vert = clamp_t(unsigned int, ratio->vert,
+ MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+ if (ratio->vert <= MID_RESIZE_VALUE) {
+ upscaled_height = (output->height - 1) * ratio->vert
+ + 32 * spv + 16;
+ height = (upscaled_height >> 8) + 4;
+ } else {
+ upscaled_height = (output->height - 1) * ratio->vert
+ + 64 * spv + 32;
+ height = (upscaled_height >> 8) + 7;
+ }
+
+ /*
+ * Compute the minimum and maximum output widths based on the hardware
+ * capabilities. The maximum depends on the vertical resizing ratio.
+ */
+ min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
+ min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
+
+ if (ratio->vert <= MID_RESIZE_VALUE) {
+ switch (isp->revision) {
+ case ISP_REVISION_1_0:
+ max_width = MAX_4TAP_OUT_WIDTH_ES1;
+ break;
+
+ case ISP_REVISION_2_0:
+ default:
+ max_width = MAX_4TAP_OUT_WIDTH_ES2;
+ break;
+
+ case ISP_REVISION_15_0:
+ max_width = MAX_4TAP_OUT_WIDTH_3630;
+ break;
+ }
+ } else {
+ switch (isp->revision) {
+ case ISP_REVISION_1_0:
+ max_width = MAX_7TAP_OUT_WIDTH_ES1;
+ break;
+
+ case ISP_REVISION_2_0:
+ default:
+ max_width = MAX_7TAP_OUT_WIDTH_ES2;
+ break;
+
+ case ISP_REVISION_15_0:
+ max_width = MAX_7TAP_OUT_WIDTH_3630;
+ break;
+ }
+ }
+ max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
+ + 1, max_width);
+
+ /*
+ * The output width must be even, and must be a multiple of 16 bytes
+ * when upscaling vertically. Clamp the output width to the valid range.
+ * Take the alignment into account (the maximum width in 7-tap mode on
+ * ES2 isn't a multiple of 8) and align the result up to make sure it
+ * won't be smaller than the minimum.
+ */
+ width_alignment = ratio->vert < 256 ? 8 : 2;
+ output->width = clamp(output->width, min_width,
+ max_width & ~(width_alignment - 1));
+ output->width = ALIGN(output->width, width_alignment);
+
+ ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
+ / (output->width - 1);
+ if (ratio->horz > MID_RESIZE_VALUE)
+ ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
+ / (output->width - 1);
+ ratio->horz = clamp_t(unsigned int, ratio->horz,
+ MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+ if (ratio->horz <= MID_RESIZE_VALUE) {
+ upscaled_width = (output->width - 1) * ratio->horz
+ + 32 * sph + 16;
+ width = (upscaled_width >> 8) + 7;
+ } else {
+ upscaled_width = (output->width - 1) * ratio->horz
+ + 64 * sph + 32;
+ width = (upscaled_width >> 8) + 7;
+ }
+
+ /* Center the new crop rectangle. */
+ input->left += (input->width - width) / 2;
+ input->top += (input->height - height) / 2;
+ input->width = width;
+ input->height = height;
+}
+
+/*
+ * resizer_set_crop_params - Setup hardware with cropping parameters
+ * @res : resizer private structure
+ * @crop_rect : current crop rectangle
+ * @ratio : resizer ratios
+ * return none
+ */
+static void resizer_set_crop_params(struct isp_res_device *res,
+ const struct v4l2_mbus_framefmt *input,
+ const struct v4l2_mbus_framefmt *output)
+{
+ resizer_set_ratio(res, &res->ratio);
+
+ /* Set chrominance horizontal algorithm */
+ if (res->ratio.horz >= RESIZE_DIVISOR)
+ resizer_set_bilinear(res, RSZ_THE_SAME);
+ else
+ resizer_set_bilinear(res, RSZ_BILINEAR);
+
+ resizer_adjust_bandwidth(res);
+
+ if (res->input == RESIZER_INPUT_MEMORY) {
+ /* Calculate additional offset for crop */
+ res->crop_offset = (res->crop.active.top * input->width +
+ res->crop.active.left) * 2;
+ /*
+ * Write lowest 4 bits of horizontal pixel offset (in pixels),
+ * vertical start must be 0.
+ */
+ resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
+
+ /*
+ * Set start (read) address for cropping, in bytes.
+ * Lowest 5 bits must be zero.
+ */
+ __resizer_set_inaddr(res,
+ res->addr_base + (res->crop_offset & ~0x1f));
+ } else {
+ /*
+ * Set vertical start line and horizontal starting pixel.
+ * If the input is from CCDC/PREV, horizontal start field is
+ * in bytes (twice number of pixels).
+ */
+ resizer_set_start(res, res->crop.active.left * 2,
+ res->crop.active.top);
+ /* Input address and offset must be 0 for preview/ccdc input */
+ __resizer_set_inaddr(res, 0);
+ resizer_set_input_offset(res, 0);
+ }
+
+ /* Set the input size */
+ resizer_set_input_size(res, res->crop.active.width,
+ res->crop.active.height);
+}
+
+static void resizer_configure(struct isp_res_device *res)
+{
+ struct v4l2_mbus_framefmt *informat, *outformat;
+ struct resizer_luma_yenh luma = {0, 0, 0, 0};
+
+ resizer_set_source(res, res->input);
+
+ informat = &res->formats[RESZ_PAD_SINK];
+ outformat = &res->formats[RESZ_PAD_SOURCE];
+
+ /* RESZ_PAD_SINK */
+ if (res->input == RESIZER_INPUT_VP)
+ resizer_set_input_offset(res, 0);
+ else
+ resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
+
+ /* YUV422 interleaved, default phase, no luma enhancement */
+ resizer_set_intype(res, RSZ_YUV422);
+ resizer_set_ycpos(res, informat->code);
+ resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
+ resizer_set_luma(res, &luma);
+
+ /* RESZ_PAD_SOURCE */
+ resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
+ resizer_set_output_size(res, outformat->width, outformat->height);
+
+ resizer_set_crop_params(res, informat, outformat);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void resizer_enable_oneshot(struct isp_res_device *res)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
+ ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
+}
+
+void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
+{
+ /*
+ * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+ * condition, the module was paused and now we have a buffer queued
+ * on the output again. Restart the pipeline if running in continuous
+ * mode.
+ */
+ if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+ res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+ resizer_enable_oneshot(res);
+ isp_video_dmaqueue_flags_clr(&res->video_out);
+ }
+}
+
+static void resizer_isr_buffer(struct isp_res_device *res)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+ struct isp_buffer *buffer;
+ int restart = 0;
+
+ if (res->state == ISP_PIPELINE_STREAM_STOPPED)
+ return;
+
+ /* Complete the output buffer and, if reading from memory, the input
+ * buffer.
+ */
+ buffer = omap3isp_video_buffer_next(&res->video_out);
+ if (buffer != NULL) {
+ resizer_set_outaddr(res, buffer->isp_addr);
+ restart = 1;
+ }
+
+ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+ if (res->input == RESIZER_INPUT_MEMORY) {
+ buffer = omap3isp_video_buffer_next(&res->video_in);
+ if (buffer != NULL)
+ resizer_set_inaddr(res, buffer->isp_addr);
+ pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+ }
+
+ if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
+ if (isp_pipeline_ready(pipe))
+ omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_SINGLESHOT);
+ } else {
+ /* If an underrun occurs, the video queue operation handler will
+ * restart the resizer. Otherwise restart it immediately.
+ */
+ if (restart)
+ resizer_enable_oneshot(res);
+ }
+}
+
+/*
+ * omap3isp_resizer_isr - ISP resizer interrupt handler
+ *
+ * Manage the resizer video buffers and configure shadowed and busy-locked
+ * registers.
+ */
+void omap3isp_resizer_isr(struct isp_res_device *res)
+{
+ struct v4l2_mbus_framefmt *informat, *outformat;
+
+ if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
+ return;
+
+ if (res->applycrop) {
+ outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
+ V4L2_SUBDEV_FORMAT_ACTIVE);
+ informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
+ V4L2_SUBDEV_FORMAT_ACTIVE);
+ resizer_set_crop_params(res, informat, outformat);
+ res->applycrop = 0;
+ }
+
+ resizer_isr_buffer(res);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int resizer_video_queue(struct isp_video *video,
+ struct isp_buffer *buffer)
+{
+ struct isp_res_device *res = &video->isp->isp_res;
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ resizer_set_inaddr(res, buffer->isp_addr);
+
+ /*
+ * We now have a buffer queued on the output. Despite what the
+ * TRM says, the resizer can't be restarted immediately.
+ * Enabling it in one shot mode in the middle of a frame (or at
+ * least asynchronously to the frame) results in the output
+ * being shifted randomly left/right and up/down, as if the
+ * hardware didn't synchronize itself to the beginning of the
+ * frame correctly.
+ *
+ * Restart the resizer on the next sync interrupt if running in
+ * continuous mode or when starting the stream.
+ */
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ resizer_set_outaddr(res, buffer->isp_addr);
+
+ return 0;
+}
+
+static const struct isp_video_operations resizer_video_ops = {
+ .queue = resizer_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * resizer_set_stream - Enable/Disable streaming on resizer subdev
+ * @sd: ISP resizer V4L2 subdev
+ * @enable: 1 == Enable, 0 == Disable
+ *
+ * The resizer hardware can't be enabled without a memory buffer to write to.
+ * As the s_stream operation is called in response to a STREAMON call without
+ * any buffer queued yet, just update the state field and return immediately.
+ * The resizer will be enabled in resizer_video_queue().
+ */
+static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct isp_video *video_out = &res->video_out;
+ struct isp_device *isp = to_isp_device(res);
+ struct device *dev = to_device(res);
+
+ if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
+ if (enable == ISP_PIPELINE_STREAM_STOPPED)
+ return 0;
+
+ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+ resizer_configure(res);
+ resizer_print_status(res);
+ }
+
+ switch (enable) {
+ case ISP_PIPELINE_STREAM_CONTINUOUS:
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+ if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+ resizer_enable_oneshot(res);
+ isp_video_dmaqueue_flags_clr(video_out);
+ }
+ break;
+
+ case ISP_PIPELINE_STREAM_SINGLESHOT:
+ if (res->input == RESIZER_INPUT_MEMORY)
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
+ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+
+ resizer_enable_oneshot(res);
+ break;
+
+ case ISP_PIPELINE_STREAM_STOPPED:
+ if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
+ &res->stopping))
+ dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
+ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
+ OMAP3_ISP_SBL_RESIZER_WRITE);
+ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+ isp_video_dmaqueue_flags_clr(video_out);
+ break;
+ }
+
+ res->state = enable;
+ return 0;
+}
+
+/*
+ * resizer_try_crop - mangles crop parameters.
+ */
+static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
+ const struct v4l2_mbus_framefmt *source,
+ struct v4l2_rect *crop)
+{
+ const unsigned int spv = DEFAULT_PHASE;
+ const unsigned int sph = DEFAULT_PHASE;
+
+ /* Crop rectangle is constrained by the output size so that zoom ratio
+ * cannot exceed +/-4.0.
+ */
+ unsigned int min_width =
+ ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
+ unsigned int min_height =
+ ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
+ unsigned int max_width =
+ ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
+ unsigned int max_height =
+ ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
+
+ crop->width = clamp_t(u32, crop->width, min_width, max_width);
+ crop->height = clamp_t(u32, crop->height, min_height, max_height);
+
+ /* Crop can not go beyond of the input rectangle */
+ crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
+ crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
+ sink->width - crop->left);
+ crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
+ crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
+ sink->height - crop->top);
+}
+
+/*
+ * resizer_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format_source;
+ struct v4l2_mbus_framefmt *format_sink;
+ struct resizer_ratio ratio;
+
+ if (sel->pad != RESZ_PAD_SINK)
+ return -EINVAL;
+
+ format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ sel->which);
+ format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ sel->which);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ resizer_try_crop(format_sink, format_source, &sel->r);
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *__resizer_get_crop(res, fh, sel->which);
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * resizer_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
+ * was always set.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct isp_device *isp = to_isp_device(res);
+ struct v4l2_mbus_framefmt *format_sink, *format_source;
+ struct resizer_ratio ratio;
+
+ if (sel->target != V4L2_SEL_TGT_CROP ||
+ sel->pad != RESZ_PAD_SINK)
+ return -EINVAL;
+
+ format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ sel->which);
+ format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ sel->which);
+
+ dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
+ sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+ sel->which);
+
+ dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+ format_sink->width, format_sink->height,
+ format_source->width, format_source->height);
+
+ /* Clamp the crop rectangle to the bounds, and then mangle it further to
+ * fulfill the TRM equations. Store the clamped but otherwise unmangled
+ * rectangle to avoid cropping the input multiple times: when an
+ * application sets the output format, the current crop rectangle is
+ * mangled during crop rectangle computation, which would lead to a new,
+ * smaller input crop rectangle every time the output size is set if we
+ * stored the mangled rectangle.
+ */
+ resizer_try_crop(format_sink, format_source, &sel->r);
+ *__resizer_get_crop(res, fh, sel->which) = sel->r;
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ res->ratio = ratio;
+ res->crop.active = sel->r;
+
+ /*
+ * set_selection can be called while streaming is on. In this case the
+ * crop values will be set in the next IRQ.
+ */
+ if (res->state != ISP_PIPELINE_STREAM_STOPPED)
+ res->applycrop = 1;
+
+ return 0;
+}
+
+/* resizer pixel formats */
+static const unsigned int resizer_formats[] = {
+ V4L2_MBUS_FMT_UYVY8_1X16,
+ V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+static unsigned int resizer_max_in_width(struct isp_res_device *res)
+{
+ struct isp_device *isp = to_isp_device(res);
+
+ if (res->input == RESIZER_INPUT_MEMORY) {
+ return MAX_IN_WIDTH_MEMORY_MODE;
+ } else {
+ if (isp->revision == ISP_REVISION_1_0)
+ return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
+ else
+ return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
+ }
+}
+
+/*
+ * resizer_try_format - Handle try format by pad subdev method
+ * @res : ISP resizer device
+ * @fh : V4L2 subdev file handle
+ * @pad : pad num
+ * @fmt : pointer to v4l2 format structure
+ * @which : wanted subdev format
+ */
+static void resizer_try_format(struct isp_res_device *res,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct resizer_ratio ratio;
+ struct v4l2_rect crop;
+
+ switch (pad) {
+ case RESZ_PAD_SINK:
+ if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
+ fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
+ fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+
+ fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
+ resizer_max_in_width(res));
+ fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
+ MAX_IN_HEIGHT);
+ break;
+
+ case RESZ_PAD_SOURCE:
+ format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
+ fmt->code = format->code;
+
+ crop = *__resizer_get_crop(res, fh, which);
+ resizer_calc_ratios(res, &crop, fmt, &ratio);
+ break;
+ }
+
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * resizer_enum_mbus_code - Handle pixel format enumeration
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (code->pad == RESZ_PAD_SINK) {
+ if (code->index >= ARRAY_SIZE(resizer_formats))
+ return -EINVAL;
+
+ code->code = resizer_formats[code->index];
+ } else {
+ if (code->index != 0)
+ return -EINVAL;
+
+ format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ V4L2_SUBDEV_FORMAT_TRY);
+ code->code = format->code;
+ }
+
+ return 0;
+}
+
+static int resizer_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt format;
+
+ if (fse->index != 0)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = 1;
+ format.height = 1;
+ resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->min_width = format.width;
+ fse->min_height = format.height;
+
+ if (format.code != fse->code)
+ return -EINVAL;
+
+ format.code = fse->code;
+ format.width = -1;
+ format.height = -1;
+ resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+ fse->max_width = format.width;
+ fse->max_height = format.height;
+
+ return 0;
+}
+
+/*
+ * resizer_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+/*
+ * resizer_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+ if (format == NULL)
+ return -EINVAL;
+
+ resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+
+ if (fmt->pad == RESZ_PAD_SINK) {
+ /* reset crop rectangle */
+ crop = __resizer_get_crop(res, fh, fmt->which);
+ crop->left = 0;
+ crop->top = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+
+ /* Propagate the format from sink to source */
+ format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ fmt->which);
+ *format = fmt->format;
+ resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
+ fmt->which);
+ }
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ /* Compute and store the active crop rectangle and resizer
+ * ratios. format already points to the source pad active
+ * format.
+ */
+ res->crop.active = res->crop.request;
+ resizer_calc_ratios(res, &res->crop.active, format,
+ &res->ratio);
+ }
+
+ return 0;
+}
+
+/*
+ * resizer_init_formats - Initialize formats on all pads
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int resizer_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+ format.pad = RESZ_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ format.format.width = 4096;
+ format.format.height = 4096;
+ resizer_set_format(sd, fh, &format);
+
+ return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
+ .s_stream = resizer_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
+ .enum_mbus_code = resizer_enum_mbus_code,
+ .enum_frame_size = resizer_enum_frame_size,
+ .get_fmt = resizer_get_format,
+ .set_fmt = resizer_set_format,
+ .get_selection = resizer_get_selection,
+ .set_selection = resizer_set_selection,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops resizer_v4l2_ops = {
+ .video = &resizer_v4l2_video_ops,
+ .pad = &resizer_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
+ .open = resizer_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * resizer_link_setup - Setup resizer connections.
+ * @entity : Pointer to media entity structure
+ * @local : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags : Link flags
+ * return -EINVAL or zero on success
+ */
+static int resizer_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* read from memory */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (res->input == RESIZER_INPUT_VP)
+ return -EBUSY;
+ res->input = RESIZER_INPUT_MEMORY;
+ } else {
+ if (res->input == RESIZER_INPUT_MEMORY)
+ res->input = RESIZER_INPUT_NONE;
+ }
+ break;
+
+ case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* read from ccdc or previewer */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (res->input == RESIZER_INPUT_MEMORY)
+ return -EBUSY;
+ res->input = RESIZER_INPUT_VP;
+ } else {
+ if (res->input == RESIZER_INPUT_VP)
+ res->input = RESIZER_INPUT_NONE;
+ }
+ break;
+
+ case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ /* resizer always write to memory */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations resizer_media_ops = {
+ .link_setup = resizer_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
+{
+ v4l2_device_unregister_subdev(&res->subdev);
+ omap3isp_video_unregister(&res->video_in);
+ omap3isp_video_unregister(&res->video_out);
+}
+
+int omap3isp_resizer_register_entities(struct isp_res_device *res,
+ struct v4l2_device *vdev)
+{
+ int ret;
+
+ /* Register the subdev and video nodes. */
+ ret = v4l2_device_register_subdev(vdev, &res->subdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&res->video_in, vdev);
+ if (ret < 0)
+ goto error;
+
+ ret = omap3isp_video_register(&res->video_out, vdev);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ omap3isp_resizer_unregister_entities(res);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP resizer initialization and cleanup
+ */
+
+/*
+ * resizer_init_entities - Initialize resizer subdev and media entity.
+ * @res : Pointer to resizer device structure
+ * return -ENOMEM or zero on success
+ */
+static int resizer_init_entities(struct isp_res_device *res)
+{
+ struct v4l2_subdev *sd = &res->subdev;
+ struct media_pad *pads = res->pads;
+ struct media_entity *me = &sd->entity;
+ int ret;
+
+ res->input = RESIZER_INPUT_NONE;
+
+ v4l2_subdev_init(sd, &resizer_v4l2_ops);
+ sd->internal_ops = &resizer_v4l2_internal_ops;
+ strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
+ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
+ v4l2_set_subdevdata(sd, res);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ me->ops = &resizer_media_ops;
+ ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
+ if (ret < 0)
+ return ret;
+
+ resizer_init_formats(sd, NULL);
+
+ res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ res->video_in.ops = &resizer_video_ops;
+ res->video_in.isp = to_isp_device(res);
+ res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+ res->video_in.bpl_alignment = 32;
+ res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ res->video_out.ops = &resizer_video_ops;
+ res->video_out.isp = to_isp_device(res);
+ res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+ res->video_out.bpl_alignment = 32;
+
+ ret = omap3isp_video_init(&res->video_in, "resizer");
+ if (ret < 0)
+ goto error_video_in;
+
+ ret = omap3isp_video_init(&res->video_out, "resizer");
+ if (ret < 0)
+ goto error_video_out;
+
+ res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
+
+ /* Connect the video nodes to the resizer subdev. */
+ ret = media_entity_create_link(&res->video_in.video.entity, 0,
+ &res->subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ goto error_link;
+
+ ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
+ &res->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ goto error_link;
+
+ return 0;
+
+error_link:
+ omap3isp_video_cleanup(&res->video_out);
+error_video_out:
+ omap3isp_video_cleanup(&res->video_in);
+error_video_in:
+ media_entity_cleanup(&res->subdev.entity);
+ return ret;
+}
+
+/*
+ * isp_resizer_init - Resizer initialization.
+ * @isp : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_resizer_init(struct isp_device *isp)
+{
+ struct isp_res_device *res = &isp->isp_res;
+
+ init_waitqueue_head(&res->wait);
+ atomic_set(&res->stopping, 0);
+ return resizer_init_entities(res);
+}
+
+void omap3isp_resizer_cleanup(struct isp_device *isp)
+{
+ struct isp_res_device *res = &isp->isp_res;
+
+ omap3isp_video_cleanup(&res->video_in);
+ omap3isp_video_cleanup(&res->video_out);
+ media_entity_cleanup(&res->subdev.entity);
+}
diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h
index 70c1c0e1bbdf..70c1c0e1bbdf 100644
--- a/drivers/media/video/omap3isp/ispresizer.h
+++ b/drivers/media/platform/omap3isp/ispresizer.h
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index b8640be692f1..b8640be692f1 100644
--- a/drivers/media/video/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index 9b7c8654dc8a..9b7c8654dc8a 100644
--- a/drivers/media/video/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
new file mode 100644
index 000000000000..3a5085e90024
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -0,0 +1,1403 @@
+/*
+ * ispvideo.c
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 <asm/cacheflush.h>
+#include <linux/clk.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+#include <plat/omap-pm.h>
+
+#include "ispvideo.h"
+#include "isp.h"
+
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+/*
+ * NOTE: When adding new media bus codes, always remember to add
+ * corresponding in-memory formats to the table below!!!
+ */
+static struct isp_format_info formats[] = {
+ { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_GREY, 8, 1, },
+ { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_Y10, 10, 2, },
+ { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_PIX_FMT_Y12, 12, 2, },
+ { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR8, 8, 1, },
+ { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG8, 8, 1, },
+ { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG8, 8, 1, },
+ { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB8, 8, 1, },
+ { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SBGGR10_1X10, 0,
+ V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, },
+ { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SGBRG10_1X10, 0,
+ V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, },
+ { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+ V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, },
+ { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SRGGB10_1X10, 0,
+ V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, },
+ { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR10, 10, 2, },
+ { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
+ V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG10, 10, 2, },
+ { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
+ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG10, 10, 2, },
+ { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
+ V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB10, 10, 2, },
+ { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_PIX_FMT_SBGGR12, 12, 2, },
+ { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
+ V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+ V4L2_PIX_FMT_SGBRG12, 12, 2, },
+ { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
+ V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_PIX_FMT_SGRBG12, 12, 2, },
+ { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
+ V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+ V4L2_PIX_FMT_SRGGB12, 12, 2, },
+ { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
+ V4L2_MBUS_FMT_UYVY8_1X16, 0,
+ V4L2_PIX_FMT_UYVY, 16, 2, },
+ { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
+ V4L2_MBUS_FMT_YUYV8_1X16, 0,
+ V4L2_PIX_FMT_YUYV, 16, 2, },
+ { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8, 0,
+ V4L2_PIX_FMT_UYVY, 8, 2, },
+ { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_YUYV8_2X8, 0,
+ V4L2_PIX_FMT_YUYV, 8, 2, },
+ /* Empty entry to catch the unsupported pixel code (0) used by the CCDC
+ * module and avoid NULL pointer dereferences.
+ */
+ { 0, }
+};
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (formats[i].code == code)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+/*
+ * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
+ * @video: ISP video instance
+ * @mbus: v4l2_mbus_framefmt format (input)
+ * @pix: v4l2_pix_format format (output)
+ *
+ * Fill the output pix structure with information from the input mbus format.
+ * The bytesperline and sizeimage fields are computed from the requested bytes
+ * per line value in the pix format and information from the video instance.
+ *
+ * Return the number of padding bytes at end of line.
+ */
+static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
+ const struct v4l2_mbus_framefmt *mbus,
+ struct v4l2_pix_format *pix)
+{
+ unsigned int bpl = pix->bytesperline;
+ unsigned int min_bpl;
+ unsigned int i;
+
+ memset(pix, 0, sizeof(*pix));
+ pix->width = mbus->width;
+ pix->height = mbus->height;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (formats[i].code == mbus->code)
+ break;
+ }
+
+ if (WARN_ON(i == ARRAY_SIZE(formats)))
+ return 0;
+
+ min_bpl = pix->width * formats[i].bpp;
+
+ /* Clamp the requested bytes per line value. If the maximum bytes per
+ * line value is zero, the module doesn't support user configurable line
+ * sizes. Override the requested value with the minimum in that case.
+ */
+ if (video->bpl_max)
+ bpl = clamp(bpl, min_bpl, video->bpl_max);
+ else
+ bpl = min_bpl;
+
+ if (!video->bpl_zero_padding || bpl != min_bpl)
+ bpl = ALIGN(bpl, video->bpl_alignment);
+
+ pix->pixelformat = formats[i].pixelformat;
+ pix->bytesperline = bpl;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->colorspace = mbus->colorspace;
+ pix->field = mbus->field;
+
+ return bpl - min_bpl;
+}
+
+static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
+ struct v4l2_mbus_framefmt *mbus)
+{
+ unsigned int i;
+
+ memset(mbus, 0, sizeof(*mbus));
+ mbus->width = pix->width;
+ mbus->height = pix->height;
+
+ /* 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;
+ }
+
+ mbus->code = formats[i].code;
+ mbus->colorspace = pix->colorspace;
+ mbus->field = pix->field;
+}
+
+static struct v4l2_subdev *
+isp_video_remote_subdev(struct isp_video *video, u32 *pad)
+{
+ struct media_pad *remote;
+
+ remote = media_entity_remote_source(&video->pad);
+
+ if (remote == NULL ||
+ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return NULL;
+
+ if (pad)
+ *pad = remote->index;
+
+ return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* Return a pointer to the ISP video instance at the far end of the pipeline. */
+static int isp_video_get_graph_data(struct isp_video *video,
+ struct isp_pipeline *pipe)
+{
+ struct media_entity_graph graph;
+ struct media_entity *entity = &video->video.entity;
+ struct media_device *mdev = entity->parent;
+ struct isp_video *far_end = NULL;
+
+ mutex_lock(&mdev->graph_mutex);
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ struct isp_video *__video;
+
+ pipe->entities |= 1 << entity->id;
+
+ if (far_end != NULL)
+ continue;
+
+ if (entity == &video->video.entity)
+ continue;
+
+ if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ continue;
+
+ __video = to_isp_video(media_entity_to_video_device(entity));
+ if (__video->type != video->type)
+ far_end = __video;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pipe->input = far_end;
+ pipe->output = video;
+ } else {
+ if (far_end == NULL)
+ return -EPIPE;
+
+ pipe->input = video;
+ pipe->output = far_end;
+ }
+
+ return 0;
+}
+
+/*
+ * Validate a pipeline by checking both ends of all links for format
+ * discrepancies.
+ *
+ * Compute the minimum time per frame value as the maximum of time per frame
+ * limits reported by every block in the pipeline.
+ *
+ * Return 0 if all formats match, or -EPIPE if at least one link is found with
+ * different formats on its two ends or if the pipeline doesn't start with a
+ * video source (either a subdev with no input pad, or a non-subdev entity).
+ */
+static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
+{
+ struct isp_device *isp = pipe->output->isp;
+ struct media_pad *pad;
+ struct v4l2_subdev *subdev;
+
+ subdev = isp_video_remote_subdev(pipe->output, NULL);
+ if (subdev == NULL)
+ return -EPIPE;
+
+ while (1) {
+ /* Retrieve the sink format */
+ pad = &subdev->entity.pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ /* Update the maximum frame rate */
+ if (subdev == &isp->isp_res.subdev)
+ omap3isp_resizer_max_rate(&isp->isp_res,
+ &pipe->max_rate);
+
+ /* Retrieve the source format. Return an error if no source
+ * entity can be found, and stop checking the pipeline if the
+ * source entity isn't a subdev.
+ */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL)
+ return -EPIPE;
+
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ subdev = media_entity_to_v4l2_subdev(pad->entity);
+ }
+
+ return 0;
+}
+
+static int
+__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
+{
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ u32 pad;
+ int ret;
+
+ subdev = isp_video_remote_subdev(video, &pad);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ mutex_lock(&video->mutex);
+
+ fmt.pad = pad;
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret == -ENOIOCTLCMD)
+ ret = -EINVAL;
+
+ mutex_unlock(&video->mutex);
+
+ if (ret)
+ return ret;
+
+ format->type = video->type;
+ return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+}
+
+static int
+isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
+{
+ struct v4l2_format format;
+ int ret;
+
+ memcpy(&format, &vfh->format, sizeof(format));
+ ret = __isp_video_get_format(video, &format);
+ if (ret < 0)
+ return ret;
+
+ if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
+ vfh->format.fmt.pix.height != format.fmt.pix.height ||
+ vfh->format.fmt.pix.width != format.fmt.pix.width ||
+ vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
+ vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+ return -EINVAL;
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * IOMMU management
+ */
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+/*
+ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @sglist: Pointer to source Scatter gather list to allocate.
+ * @sglen: Number of elements of the scatter-gatter list.
+ *
+ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
+ * we ran out of memory.
+ */
+static dma_addr_t
+ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
+{
+ struct sg_table *sgt;
+ u32 da;
+
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+ if (sgt == NULL)
+ return -ENOMEM;
+
+ sgt->sgl = (struct scatterlist *)sglist;
+ sgt->nents = sglen;
+ sgt->orig_nents = sglen;
+
+ da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG);
+ if (IS_ERR_VALUE(da))
+ kfree(sgt);
+
+ return da;
+}
+
+/*
+ * ispmmu_vunmap - Unmap a device address from the ISP MMU
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @da: Device address generated from a ispmmu_vmap call.
+ */
+static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
+{
+ struct sg_table *sgt;
+
+ sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da);
+ kfree(sgt);
+}
+
+/* -----------------------------------------------------------------------------
+ * Video queue operations
+ */
+
+static void isp_video_queue_prepare(struct isp_video_queue *queue,
+ unsigned int *nbuffers, unsigned int *size)
+{
+ struct isp_video_fh *vfh =
+ container_of(queue, struct isp_video_fh, queue);
+ struct isp_video *video = vfh->video;
+
+ *size = vfh->format.fmt.pix.sizeimage;
+ if (*size == 0)
+ return;
+
+ *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
+}
+
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+ struct isp_buffer *buffer = to_isp_buffer(buf);
+ struct isp_video *video = vfh->video;
+
+ if (buffer->isp_addr) {
+ ispmmu_vunmap(video->isp, buffer->isp_addr);
+ buffer->isp_addr = 0;
+ }
+}
+
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+ struct isp_buffer *buffer = to_isp_buffer(buf);
+ struct isp_video *video = vfh->video;
+ unsigned long addr;
+
+ addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
+ if (IS_ERR_VALUE(addr))
+ return -EIO;
+
+ if (!IS_ALIGNED(addr, 32)) {
+ dev_dbg(video->isp->dev, "Buffer address must be "
+ "aligned to 32 bytes boundary.\n");
+ ispmmu_vunmap(video->isp, buffer->isp_addr);
+ return -EINVAL;
+ }
+
+ buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
+ buffer->isp_addr = addr;
+ return 0;
+}
+
+/*
+ * isp_video_buffer_queue - Add buffer to streaming queue
+ * @buf: Video buffer
+ *
+ * In memory-to-memory mode, start streaming on the pipeline if buffers are
+ * queued on both the input and the output, if the pipeline isn't already busy.
+ * If the pipeline is busy, it will be restarted in the output module interrupt
+ * handler.
+ */
+static void isp_video_buffer_queue(struct isp_video_buffer *buf)
+{
+ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+ struct isp_buffer *buffer = to_isp_buffer(buf);
+ struct isp_video *video = vfh->video;
+ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+ enum isp_pipeline_state state;
+ unsigned long flags;
+ unsigned int empty;
+ unsigned int start;
+
+ empty = list_empty(&video->dmaqueue);
+ list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
+
+ if (empty) {
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ state = ISP_PIPELINE_QUEUE_OUTPUT;
+ else
+ state = ISP_PIPELINE_QUEUE_INPUT;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state |= state;
+ video->ops->queue(video, buffer);
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+
+ start = isp_pipeline_ready(pipe);
+ if (start)
+ pipe->state |= ISP_PIPELINE_STREAM;
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ if (start)
+ omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_SINGLESHOT);
+ }
+}
+
+static const struct isp_video_queue_operations isp_video_queue_ops = {
+ .queue_prepare = &isp_video_queue_prepare,
+ .buffer_prepare = &isp_video_buffer_prepare,
+ .buffer_queue = &isp_video_buffer_queue,
+ .buffer_cleanup = &isp_video_buffer_cleanup,
+};
+
+/*
+ * omap3isp_video_buffer_next - Complete the current buffer and return the next
+ * @video: ISP video object
+ *
+ * Remove the current video buffer from the DMA queue and fill its timestamp,
+ * field count and state fields before waking up its completion handler.
+ *
+ * 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)
+{
+ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+ struct isp_video_queue *queue = video->queue;
+ enum isp_pipeline_state state;
+ struct isp_video_buffer *buf;
+ unsigned long flags;
+ struct timespec ts;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (WARN_ON(list_empty(&video->dmaqueue))) {
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+ return NULL;
+ }
+
+ buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+ irqlist);
+ list_del(&buf->irqlist);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ ktime_get_ts(&ts);
+ buf->vbuf.timestamp.tv_sec = ts.tv_sec;
+ buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+ /* Do frame number propagation only if this is the output video node.
+ * Frame number either comes from the CSI receivers or it gets
+ * incremented here if H3A is not active.
+ * Note: There is no guarantee that the output buffer will finish
+ * first, so the input number might lag behind by 1 in some cases.
+ */
+ if (video == pipe->output && !pipe->do_propagation)
+ buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
+ else
+ buf->vbuf.sequence = atomic_read(&pipe->frame_number);
+
+ /* 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);
+
+ if (list_empty(&video->dmaqueue)) {
+ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ state = ISP_PIPELINE_QUEUE_OUTPUT
+ | ISP_PIPELINE_STREAM;
+ else
+ state = ISP_PIPELINE_QUEUE_INPUT
+ | ISP_PIPELINE_STREAM;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~state;
+ if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+ spin_unlock_irqrestore(&pipe->lock, flags);
+ return NULL;
+ }
+
+ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~ISP_PIPELINE_STREAM;
+ spin_unlock_irqrestore(&pipe->lock, flags);
+ }
+
+ buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+ irqlist);
+ buf->state = ISP_BUF_STATE_ACTIVE;
+ return to_isp_buffer(buf);
+}
+
+/*
+ * omap3isp_video_resume - Perform resume operation on the buffers
+ * @video: ISP video object
+ * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise
+ *
+ * This function is intended to be used on suspend/resume scenario. It
+ * requests video queue layer to discard buffers marked as DONE if it's in
+ * continuous mode and requests ISP modules to queue again the ACTIVE buffer
+ * if there's any.
+ */
+void omap3isp_video_resume(struct isp_video *video, int continuous)
+{
+ struct isp_buffer *buf = NULL;
+
+ if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ omap3isp_video_queue_discard_done(video->queue);
+
+ if (!list_empty(&video->dmaqueue)) {
+ buf = list_first_entry(&video->dmaqueue,
+ struct isp_buffer, buffer.irqlist);
+ video->ops->queue(video, buf);
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+ } else {
+ if (continuous)
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ struct isp_video *video = video_drvdata(file);
+
+ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, video->video.name, sizeof(cap->card));
+ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ else
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int
+isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+
+ if (format->type != video->type)
+ return -EINVAL;
+
+ mutex_lock(&video->mutex);
+ *format = vfh->format;
+ mutex_unlock(&video->mutex);
+
+ return 0;
+}
+
+static int
+isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_mbus_framefmt fmt;
+
+ if (format->type != video->type)
+ return -EINVAL;
+
+ mutex_lock(&video->mutex);
+
+ /* Fill the bytesperline and sizeimage fields by converting to media bus
+ * format and back to pixel format.
+ */
+ isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
+ isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
+
+ vfh->format = *format;
+
+ mutex_unlock(&video->mutex);
+ return 0;
+}
+
+static int
+isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ u32 pad;
+ int ret;
+
+ if (format->type != video->type)
+ return -EINVAL;
+
+ subdev = isp_video_remote_subdev(video, &pad);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
+
+ fmt.pad = pad;
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+ return 0;
+}
+
+static int
+isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = isp_video_remote_subdev(video, NULL);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ mutex_lock(&video->mutex);
+ ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
+ mutex_unlock(&video->mutex);
+
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_subdev_format format;
+ struct v4l2_subdev *subdev;
+ u32 pad;
+ int ret;
+
+ subdev = isp_video_remote_subdev(video, &pad);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ /* Try the get crop operation first and fallback to get format if not
+ * implemented.
+ */
+ ret = v4l2_subdev_call(subdev, video, g_crop, crop);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+
+ format.pad = pad;
+ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ crop->c.left = 0;
+ crop->c.top = 0;
+ crop->c.width = format.format.width;
+ crop->c.height = format.format.height;
+
+ return 0;
+}
+
+static int
+isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = isp_video_remote_subdev(video, NULL);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ mutex_lock(&video->mutex);
+ ret = v4l2_subdev_call(subdev, video, s_crop, crop);
+ mutex_unlock(&video->mutex);
+
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+
+ if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ video->type != a->type)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ a->parm.output.timeperframe = vfh->timeperframe;
+
+ return 0;
+}
+
+static int
+isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+
+ if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ video->type != a->type)
+ return -EINVAL;
+
+ if (a->parm.output.timeperframe.denominator == 0)
+ a->parm.output.timeperframe.denominator = 1;
+
+ vfh->timeperframe = a->parm.output.timeperframe;
+
+ return 0;
+}
+
+static int
+isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+ return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
+}
+
+static int
+isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+ return omap3isp_video_queue_querybuf(&vfh->queue, b);
+}
+
+static int
+isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+ return omap3isp_video_queue_qbuf(&vfh->queue, b);
+}
+
+static int
+isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+ return omap3isp_video_queue_dqbuf(&vfh->queue, b,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int isp_video_check_external_subdevs(struct isp_video *video,
+ struct isp_pipeline *pipe)
+{
+ struct isp_device *isp = video->isp;
+ struct media_entity *ents[] = {
+ &isp->isp_csi2a.subdev.entity,
+ &isp->isp_csi2c.subdev.entity,
+ &isp->isp_ccp2.subdev.entity,
+ &isp->isp_ccdc.subdev.entity
+ };
+ struct media_pad *source_pad;
+ struct media_entity *source = NULL;
+ struct media_entity *sink;
+ struct v4l2_subdev_format fmt;
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control ctrl;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ents); i++) {
+ /* Is the entity part of the pipeline? */
+ if (!(pipe->entities & (1 << ents[i]->id)))
+ continue;
+
+ /* ISP entities have always sink pad == 0. Find source. */
+ source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+ if (source_pad == NULL)
+ continue;
+
+ source = source_pad->entity;
+ sink = ents[i];
+ break;
+ }
+
+ if (!source) {
+ dev_warn(isp->dev, "can't find source, failing now\n");
+ return ret;
+ }
+
+ if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return 0;
+
+ pipe->external = media_entity_to_v4l2_subdev(source);
+
+ fmt.pad = source_pad->index;
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
+ pad, get_fmt, NULL, &fmt);
+ if (unlikely(ret < 0)) {
+ dev_warn(isp->dev, "get_fmt returned null!\n");
+ return ret;
+ }
+
+ pipe->external_width =
+ omap3isp_video_format_info(fmt.format.code)->width;
+
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(&ctrl, 0, sizeof(ctrl));
+
+ ctrl.id = V4L2_CID_PIXEL_RATE;
+
+ ctrls.count = 1;
+ ctrls.controls = &ctrl;
+
+ ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+ if (ret < 0) {
+ dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
+ pipe->external->name);
+ return ret;
+ }
+
+ pipe->external_rate = ctrl.value64;
+
+ if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+ unsigned int rate = UINT_MAX;
+ /*
+ * Check that maximum allowed CCDC pixel rate isn't
+ * exceeded by the pixel rate.
+ */
+ omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+ if (pipe->external_rate > rate)
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/*
+ * Stream management
+ *
+ * Every ISP pipeline has a single input and a single output. The input can be
+ * either a sensor or a video node. The output is always a video node.
+ *
+ * As every pipeline has an output video node, the ISP video objects at the
+ * pipeline output stores the pipeline state. It tracks the streaming state of
+ * both the input and output, as well as the availability of buffers.
+ *
+ * In sensor-to-memory mode, frames are always available at the pipeline input.
+ * Starting the sensor usually requires I2C transfers and must be done in
+ * interruptible context. The pipeline is started and stopped synchronously
+ * to the stream on/off commands. All modules in the pipeline will get their
+ * subdev set stream handler called. The module at the end of the pipeline must
+ * delay starting the hardware until buffers are available at its output.
+ *
+ * In memory-to-memory mode, starting/stopping the stream requires
+ * synchronization between the input and output. ISP modules can't be stopped
+ * in the middle of a frame, and at least some of the modules seem to become
+ * busy as soon as they're started, even if they don't receive a frame start
+ * event. For that reason frames need to be processed in single-shot mode. The
+ * driver needs to wait until a frame is completely processed and written to
+ * memory before restarting the pipeline for the next frame. Pipelined
+ * processing might be possible but requires more testing.
+ *
+ * Stream start must be delayed until buffers are available at both the input
+ * and output. The pipeline must be started in the videobuf queue callback with
+ * the buffers queue spinlock held. The modules subdev set stream operation must
+ * not sleep.
+ */
+static int
+isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+ enum isp_pipeline_state state;
+ struct isp_pipeline *pipe;
+ unsigned long flags;
+ int ret;
+
+ if (type != video->type)
+ return -EINVAL;
+
+ mutex_lock(&video->stream_lock);
+
+ if (video->streaming) {
+ mutex_unlock(&video->stream_lock);
+ return -EBUSY;
+ }
+
+ /* Start streaming on the pipeline. No link touching an entity in the
+ * pipeline can be activated or deactivated once streaming is started.
+ */
+ pipe = video->video.entity.pipe
+ ? to_isp_pipeline(&video->video.entity) : &video->pipe;
+
+ pipe->entities = 0;
+
+ if (video->isp->pdata->set_constraints)
+ video->isp->pdata->set_constraints(video->isp, true);
+ pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+ pipe->max_rate = pipe->l3_ick;
+
+ ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+ if (ret < 0)
+ goto err_pipeline_start;
+
+ /* Verify that the currently configured format matches the output of
+ * the connected subdev.
+ */
+ ret = isp_video_check_format(video, vfh);
+ if (ret < 0)
+ goto err_check_format;
+
+ video->bpl_padding = ret;
+ video->bpl_value = vfh->format.fmt.pix.bytesperline;
+
+ ret = isp_video_get_graph_data(video, pipe);
+ if (ret < 0)
+ goto err_check_format;
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
+ else
+ state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
+
+ ret = isp_video_check_external_subdevs(video, pipe);
+ if (ret < 0)
+ goto err_check_format;
+
+ /* Validate the pipeline and update its state. */
+ ret = isp_video_validate_pipeline(pipe);
+ if (ret < 0)
+ goto err_check_format;
+
+ pipe->error = false;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~ISP_PIPELINE_STREAM;
+ pipe->state |= state;
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ /* Set the maximum time per frame as the value requested by userspace.
+ * This is a soft limit that can be overridden if the hardware doesn't
+ * support the request limit.
+ */
+ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ pipe->max_timeperframe = vfh->timeperframe;
+
+ video->queue = &vfh->queue;
+ INIT_LIST_HEAD(&video->dmaqueue);
+ atomic_set(&pipe->frame_number, -1);
+
+ ret = omap3isp_video_queue_streamon(&vfh->queue);
+ if (ret < 0)
+ goto err_check_format;
+
+ /* In sensor-to-memory mode, the stream can be started synchronously
+ * to the stream on command. In memory-to-memory mode, it will be
+ * started when buffers are queued on both the input and output.
+ */
+ if (pipe->input == NULL) {
+ ret = omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_CONTINUOUS);
+ if (ret < 0)
+ goto err_set_stream;
+ spin_lock_irqsave(&video->queue->irqlock, flags);
+ if (list_empty(&video->dmaqueue))
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+ spin_unlock_irqrestore(&video->queue->irqlock, flags);
+ }
+
+ video->streaming = 1;
+
+ mutex_unlock(&video->stream_lock);
+ return 0;
+
+err_set_stream:
+ omap3isp_video_queue_streamoff(&vfh->queue);
+err_check_format:
+ media_entity_pipeline_stop(&video->video.entity);
+err_pipeline_start:
+ if (video->isp->pdata->set_constraints)
+ video->isp->pdata->set_constraints(video->isp, false);
+ /* The DMA queue must be emptied here, otherwise CCDC interrupts that
+ * will get triggered the next time the CCDC is powered up will try to
+ * access buffers that might have been freed but still present in the
+ * DMA queue. This can easily get triggered if the above
+ * omap3isp_pipeline_set_stream() call fails on a system with a
+ * free-running sensor.
+ */
+ INIT_LIST_HEAD(&video->dmaqueue);
+ video->queue = NULL;
+
+ mutex_unlock(&video->stream_lock);
+ return ret;
+}
+
+static int
+isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(fh);
+ struct isp_video *video = video_drvdata(file);
+ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+ enum isp_pipeline_state state;
+ unsigned int streaming;
+ unsigned long flags;
+
+ if (type != video->type)
+ return -EINVAL;
+
+ mutex_lock(&video->stream_lock);
+
+ /* Make sure we're not streaming yet. */
+ mutex_lock(&vfh->queue.lock);
+ streaming = vfh->queue.streaming;
+ mutex_unlock(&vfh->queue.lock);
+
+ if (!streaming)
+ goto done;
+
+ /* Update the pipeline state. */
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ state = ISP_PIPELINE_STREAM_OUTPUT
+ | ISP_PIPELINE_QUEUE_OUTPUT;
+ else
+ state = ISP_PIPELINE_STREAM_INPUT
+ | ISP_PIPELINE_QUEUE_INPUT;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~state;
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ /* Stop the stream. */
+ omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
+ omap3isp_video_queue_streamoff(&vfh->queue);
+ video->queue = NULL;
+ video->streaming = 0;
+
+ if (video->isp->pdata->set_constraints)
+ video->isp->pdata->set_constraints(video->isp, false);
+ media_entity_pipeline_stop(&video->video.entity);
+
+done:
+ mutex_unlock(&video->stream_lock);
+ return 0;
+}
+
+static int
+isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
+{
+ if (input->index > 0)
+ return -EINVAL;
+
+ strlcpy(input->name, "camera", sizeof(input->name));
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int
+isp_video_g_input(struct file *file, void *fh, unsigned int *input)
+{
+ *input = 0;
+
+ return 0;
+}
+
+static int
+isp_video_s_input(struct file *file, void *fh, unsigned int input)
+{
+ return input == 0 ? 0 : -EINVAL;
+}
+
+static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
+ .vidioc_querycap = isp_video_querycap,
+ .vidioc_g_fmt_vid_cap = isp_video_get_format,
+ .vidioc_s_fmt_vid_cap = isp_video_set_format,
+ .vidioc_try_fmt_vid_cap = isp_video_try_format,
+ .vidioc_g_fmt_vid_out = isp_video_get_format,
+ .vidioc_s_fmt_vid_out = isp_video_set_format,
+ .vidioc_try_fmt_vid_out = isp_video_try_format,
+ .vidioc_cropcap = isp_video_cropcap,
+ .vidioc_g_crop = isp_video_get_crop,
+ .vidioc_s_crop = isp_video_set_crop,
+ .vidioc_g_parm = isp_video_get_param,
+ .vidioc_s_parm = isp_video_set_param,
+ .vidioc_reqbufs = isp_video_reqbufs,
+ .vidioc_querybuf = isp_video_querybuf,
+ .vidioc_qbuf = isp_video_qbuf,
+ .vidioc_dqbuf = isp_video_dqbuf,
+ .vidioc_streamon = isp_video_streamon,
+ .vidioc_streamoff = isp_video_streamoff,
+ .vidioc_enum_input = isp_video_enum_input,
+ .vidioc_g_input = isp_video_g_input,
+ .vidioc_s_input = isp_video_s_input,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int isp_video_open(struct file *file)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct isp_video_fh *handle;
+ int ret = 0;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (handle == NULL)
+ return -ENOMEM;
+
+ v4l2_fh_init(&handle->vfh, &video->video);
+ v4l2_fh_add(&handle->vfh);
+
+ /* If this is the first user, initialise the pipeline. */
+ if (omap3isp_get(video->isp) == NULL) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
+ if (ret < 0) {
+ omap3isp_put(video->isp);
+ goto done;
+ }
+
+ omap3isp_video_queue_init(&handle->queue, video->type,
+ &isp_video_queue_ops, video->isp->dev,
+ sizeof(struct isp_buffer));
+
+ memset(&handle->format, 0, sizeof(handle->format));
+ handle->format.type = video->type;
+ handle->timeperframe.denominator = 1;
+
+ handle->video = video;
+ file->private_data = &handle->vfh;
+
+done:
+ if (ret < 0) {
+ v4l2_fh_del(&handle->vfh);
+ kfree(handle);
+ }
+
+ return ret;
+}
+
+static int isp_video_release(struct file *file)
+{
+ struct isp_video *video = video_drvdata(file);
+ struct v4l2_fh *vfh = file->private_data;
+ struct isp_video_fh *handle = to_isp_video_fh(vfh);
+
+ /* Disable streaming and free the buffers queue resources. */
+ isp_video_streamoff(file, vfh, video->type);
+
+ mutex_lock(&handle->queue.lock);
+ omap3isp_video_queue_cleanup(&handle->queue);
+ mutex_unlock(&handle->queue.lock);
+
+ omap3isp_pipeline_pm_use(&video->video.entity, 0);
+
+ /* Release the file handle. */
+ v4l2_fh_del(vfh);
+ kfree(handle);
+ file->private_data = NULL;
+
+ omap3isp_put(video->isp);
+
+ return 0;
+}
+
+static unsigned int isp_video_poll(struct file *file, poll_table *wait)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+ struct isp_video_queue *queue = &vfh->queue;
+
+ return omap3isp_video_queue_poll(queue, file, wait);
+}
+
+static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+
+ return omap3isp_video_queue_mmap(&vfh->queue, vma);
+}
+
+static struct v4l2_file_operations isp_video_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = isp_video_open,
+ .release = isp_video_release,
+ .poll = isp_video_poll,
+ .mmap = isp_video_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * ISP video core
+ */
+
+static const struct isp_video_operations isp_video_dummy_ops = {
+};
+
+int omap3isp_video_init(struct isp_video *video, const char *name)
+{
+ const char *direction;
+ int ret;
+
+ switch (video->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ direction = "output";
+ video->pad.flags = MEDIA_PAD_FL_SINK;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ direction = "input";
+ video->pad.flags = MEDIA_PAD_FL_SOURCE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+ if (ret < 0)
+ return ret;
+
+ mutex_init(&video->mutex);
+ atomic_set(&video->active, 0);
+
+ spin_lock_init(&video->pipe.lock);
+ mutex_init(&video->stream_lock);
+
+ /* Initialize the video device. */
+ if (video->ops == NULL)
+ video->ops = &isp_video_dummy_ops;
+
+ video->video.fops = &isp_video_fops;
+ snprintf(video->video.name, sizeof(video->video.name),
+ "OMAP3 ISP %s %s", name, direction);
+ video->video.vfl_type = VFL_TYPE_GRABBER;
+ video->video.release = video_device_release_empty;
+ video->video.ioctl_ops = &isp_video_ioctl_ops;
+ video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
+
+ video_set_drvdata(&video->video, video);
+
+ return 0;
+}
+
+void omap3isp_video_cleanup(struct isp_video *video)
+{
+ media_entity_cleanup(&video->video.entity);
+ mutex_destroy(&video->stream_lock);
+ mutex_destroy(&video->mutex);
+}
+
+int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
+{
+ int ret;
+
+ video->video.v4l2_dev = vdev;
+
+ ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+ if (ret < 0)
+ printk(KERN_ERR "%s: could not register video device (%d)\n",
+ __func__, ret);
+
+ return ret;
+}
+
+void omap3isp_video_unregister(struct isp_video *video)
+{
+ if (video_is_registered(&video->video))
+ video_unregister_device(&video->video);
+}
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
new file mode 100644
index 000000000000..1ad470ec2b9d
--- /dev/null
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -0,0 +1,216 @@
+/*
+ * ispvideo.h
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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 OMAP3_ISP_VIDEO_H
+#define OMAP3_ISP_VIDEO_H
+
+#include <linux/v4l2-mediabus.h>
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include "ispqueue.h"
+
+#define ISP_VIDEO_DRIVER_NAME "ispvideo"
+#define ISP_VIDEO_DRIVER_VERSION "0.0.2"
+
+struct isp_device;
+struct isp_video;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+
+/*
+ * struct isp_format_info - ISP media bus format information
+ * @code: V4L2 media bus format code
+ * @truncated: V4L2 media bus format code for the same format truncated to 10
+ * bits. Identical to @code if the format is 10 bits wide or less.
+ * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
+ * format. Identical to @code if the format is not DPCM compressed.
+ * @flavor: V4L2 media bus format code for the same pixel layout but
+ * shifted to be 8 bits per pixel. =0 if format is not shiftable.
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @width: Bits per pixel (when transferred over a bus)
+ * @bpp: Bytes per pixel (when stored in memory)
+ */
+struct isp_format_info {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_mbus_pixelcode truncated;
+ enum v4l2_mbus_pixelcode uncompressed;
+ enum v4l2_mbus_pixelcode flavor;
+ u32 pixelformat;
+ unsigned int width;
+ unsigned int bpp;
+};
+
+enum isp_pipeline_stream_state {
+ ISP_PIPELINE_STREAM_STOPPED = 0,
+ ISP_PIPELINE_STREAM_CONTINUOUS = 1,
+ ISP_PIPELINE_STREAM_SINGLESHOT = 2,
+};
+
+enum isp_pipeline_state {
+ /* The stream has been started on the input video node. */
+ ISP_PIPELINE_STREAM_INPUT = 1,
+ /* The stream has been started on the output video node. */
+ ISP_PIPELINE_STREAM_OUTPUT = 2,
+ /* At least one buffer is queued on the input video node. */
+ ISP_PIPELINE_QUEUE_INPUT = 4,
+ /* At least one buffer is queued on the output video node. */
+ ISP_PIPELINE_QUEUE_OUTPUT = 8,
+ /* The input entity is idle, ready to be started. */
+ ISP_PIPELINE_IDLE_INPUT = 16,
+ /* The output entity is idle, ready to be started. */
+ ISP_PIPELINE_IDLE_OUTPUT = 32,
+ /* The pipeline is currently streaming. */
+ ISP_PIPELINE_STREAM = 64,
+};
+
+/*
+ * struct isp_pipeline - An ISP hardware pipeline
+ * @error: A hardware error occurred during capture
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
+ */
+struct isp_pipeline {
+ struct media_pipeline pipe;
+ spinlock_t lock; /* Pipeline state and queue flags */
+ unsigned int state;
+ enum isp_pipeline_stream_state stream_state;
+ struct isp_video *input;
+ struct isp_video *output;
+ u32 entities;
+ unsigned long l3_ick;
+ unsigned int max_rate;
+ atomic_t frame_number;
+ bool do_propagation; /* of frame number */
+ bool error;
+ struct v4l2_fract max_timeperframe;
+ struct v4l2_subdev *external;
+ unsigned int external_rate;
+ unsigned int external_width;
+};
+
+#define to_isp_pipeline(__e) \
+ container_of((__e)->pipe, struct isp_pipeline, pipe)
+
+static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
+{
+ return pipe->state == (ISP_PIPELINE_STREAM_INPUT |
+ ISP_PIPELINE_STREAM_OUTPUT |
+ ISP_PIPELINE_QUEUE_INPUT |
+ ISP_PIPELINE_QUEUE_OUTPUT |
+ ISP_PIPELINE_IDLE_INPUT |
+ ISP_PIPELINE_IDLE_OUTPUT);
+}
+
+/*
+ * struct isp_buffer - ISP buffer
+ * @buffer: ISP video buffer
+ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
+ */
+struct isp_buffer {
+ struct isp_video_buffer buffer;
+ dma_addr_t isp_addr;
+};
+
+#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer)
+
+enum isp_video_dmaqueue_flags {
+ /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */
+ ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
+ /* Set when queuing buffer to an empty DMA queue */
+ ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
+};
+
+#define isp_video_dmaqueue_flags_clr(video) \
+ ({ (video)->dmaqueue_flags = 0; })
+
+/*
+ * struct isp_video_operations - ISP video operations
+ * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
+ * if there was no buffer previously queued.
+ */
+struct isp_video_operations {
+ int(*queue)(struct isp_video *video, struct isp_buffer *buffer);
+};
+
+struct isp_video {
+ struct video_device video;
+ enum v4l2_buf_type type;
+ struct media_pad pad;
+
+ struct mutex mutex; /* format and crop settings */
+ atomic_t active;
+
+ struct isp_device *isp;
+
+ unsigned int capture_mem;
+ unsigned int bpl_alignment; /* alignment value */
+ unsigned int bpl_zero_padding; /* whether the alignment is optional */
+ unsigned int bpl_max; /* maximum bytes per line value */
+ unsigned int bpl_value; /* bytes per line value */
+ unsigned int bpl_padding; /* padding at end of line */
+
+ /* Entity video node streaming */
+ unsigned int streaming:1;
+
+ /* Pipeline state */
+ struct isp_pipeline pipe;
+ struct mutex stream_lock; /* pipeline and stream states */
+
+ /* Video buffers queue */
+ struct isp_video_queue *queue;
+ struct list_head dmaqueue;
+ enum isp_video_dmaqueue_flags dmaqueue_flags;
+
+ const struct isp_video_operations *ops;
+};
+
+#define to_isp_video(vdev) container_of(vdev, struct isp_video, video)
+
+struct isp_video_fh {
+ struct v4l2_fh vfh;
+ struct isp_video *video;
+ struct isp_video_queue queue;
+ struct v4l2_format format;
+ struct v4l2_fract timeperframe;
+};
+
+#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh)
+#define isp_video_queue_to_isp_video_fh(q) \
+ container_of(q, struct isp_video_fh, queue)
+
+int omap3isp_video_init(struct isp_video *video, const char *name);
+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);
+void omap3isp_video_resume(struct isp_video *video, int continuous);
+struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
+
+#endif /* OMAP3_ISP_VIDEO_H */
diff --git a/drivers/media/video/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h
index 098b45e2280f..098b45e2280f 100644
--- a/drivers/media/video/omap3isp/luma_enhance_table.h
+++ b/drivers/media/platform/omap3isp/luma_enhance_table.h
diff --git a/drivers/media/video/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h
index d50451a4a242..d50451a4a242 100644
--- a/drivers/media/video/omap3isp/noise_filter_table.h
+++ b/drivers/media/platform/omap3isp/noise_filter_table.h
diff --git a/drivers/media/video/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
index a564f7eeb064..a564f7eeb064 100644
--- a/drivers/media/video/s5p-fimc/Kconfig
+++ b/drivers/media/platform/s5p-fimc/Kconfig
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/platform/s5p-fimc/Makefile
index 46485143e1ca..46485143e1ca 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/platform/s5p-fimc/Makefile
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c
index 8e413dd3c0b0..8e413dd3c0b0 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/platform/s5p-fimc/fimc-capture.c
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c
index 1a445404e73d..1a445404e73d 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/platform/s5p-fimc/fimc-core.c
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h
index 808ccc621846..808ccc621846 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/platform/s5p-fimc/fimc-core.h
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
index f996e94873f6..f996e94873f6 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite-reg.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.h b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
index adb9e9e6f3c2..adb9e9e6f3c2 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite-reg.h
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c
index c5b57e805b68..c5b57e805b68 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.c
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h
index 44424eee81d8..44424eee81d8 100644
--- a/drivers/media/video/s5p-fimc/fimc-lite.h
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.h
diff --git a/drivers/media/video/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c
index c587011d80ef..c587011d80ef 100644
--- a/drivers/media/video/s5p-fimc/fimc-m2m.c
+++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index e65bb283fd8a..e65bb283fd8a 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
index 1f5dbaff5442..1f5dbaff5442 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c
index 0e3eb9ce4f98..0e3eb9ce4f98 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.c
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h
index 579ac8ac03de..579ac8ac03de 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.h
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.h
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index 2f73d9e3d0b7..2f73d9e3d0b7 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h
index 2709286396e1..2709286396e1 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.h
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.h
diff --git a/drivers/media/video/s5p-g2d/Makefile b/drivers/media/platform/s5p-g2d/Makefile
index 2c48c416a804..2c48c416a804 100644
--- a/drivers/media/video/s5p-g2d/Makefile
+++ b/drivers/media/platform/s5p-g2d/Makefile
diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/platform/s5p-g2d/g2d-hw.c
index 5b86cbe408e2..5b86cbe408e2 100644
--- a/drivers/media/video/s5p-g2d/g2d-hw.c
+++ b/drivers/media/platform/s5p-g2d/g2d-hw.c
diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h b/drivers/media/platform/s5p-g2d/g2d-regs.h
index 02e1cf50da4e..02e1cf50da4e 100644
--- a/drivers/media/video/s5p-g2d/g2d-regs.h
+++ b/drivers/media/platform/s5p-g2d/g2d-regs.h
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
new file mode 100644
index 000000000000..0edc2df98732
--- /dev/null
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -0,0 +1,847 @@
+/*
+ * 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)
+
+static 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,
+};
+
+static 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,
+};
+
+static 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;
+
+ if (mutex_lock_interruptible(&dev->mutex)) {
+ kfree(ctx);
+ return -ERESTARTSYS;
+ }
+ 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);
+ mutex_unlock(&dev->mutex);
+ 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;
+ mutex_unlock(&dev->mutex);
+
+ 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);
+ /*
+ * This is only a mem-to-mem video device. The capture and output
+ * device capability flags are left only for backward compatibility
+ * and are scheduled for removal.
+ */
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_M2M | 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);
+ struct g2d_dev *dev = ctx->dev;
+ unsigned int res;
+
+ mutex_lock(&dev->mutex);
+ res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+ mutex_unlock(&dev->mutex);
+ return res;
+}
+
+static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct g2d_ctx *ctx = fh2ctx(file->private_data);
+ struct g2d_dev *dev = ctx->dev;
+ int ret;
+
+ if (mutex_lock_interruptible(&dev->mutex))
+ return -ERESTARTSYS;
+ ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+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 == NULL) /* No job currently running */
+ return;
+
+ ret = wait_event_timeout(dev->irq_queue,
+ dev->curr == NULL,
+ 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 == NULL);
+
+ src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ BUG_ON(src == NULL);
+ BUG_ON(dst == NULL);
+
+ 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 = NULL;
+ 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 = devm_kzalloc(&pdev->dev, 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);
+
+ dev->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (dev->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
+ }
+
+ 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");
+ return -ENXIO;
+ }
+
+ 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 = devm_request_irq(&pdev->dev, 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 unprep_clk_gate;
+ }
+
+ 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);
+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);
+
+ 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);
+ clk_unprepare(dev->gate);
+ clk_put(dev->gate);
+ clk_unprepare(dev->clk);
+ clk_put(dev->clk);
+ 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/platform/s5p-g2d/g2d.h
index 6b765b0216c5..6b765b0216c5 100644
--- a/drivers/media/video/s5p-g2d/g2d.h
+++ b/drivers/media/platform/s5p-g2d/g2d.h
diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
index ddc2900d88a2..ddc2900d88a2 100644
--- a/drivers/media/video/s5p-jpeg/Makefile
+++ b/drivers/media/platform/s5p-jpeg/Makefile
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
new file mode 100644
index 000000000000..72c3e525f921
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -0,0 +1,1529 @@
+/* linux/drivers/media/platform/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;
+
+ if (mutex_lock_interruptible(&jpeg->lock)) {
+ ret = -ERESTARTSYS;
+ goto free;
+ }
+
+ 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);
+ mutex_unlock(&jpeg->lock);
+ return 0;
+
+error:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ mutex_unlock(&jpeg->lock);
+free:
+ kfree(ctx);
+ return ret;
+}
+
+static int s5p_jpeg_release(struct file *file)
+{
+ struct s5p_jpeg *jpeg = video_drvdata(file);
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+
+ mutex_lock(&jpeg->lock);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ mutex_unlock(&jpeg->lock);
+ 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 *jpeg = video_drvdata(file);
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+ unsigned int res;
+
+ mutex_lock(&jpeg->lock);
+ res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+ mutex_unlock(&jpeg->lock);
+ return res;
+}
+
+static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct s5p_jpeg *jpeg = video_drvdata(file);
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+ int ret;
+
+ if (mutex_lock_interruptible(&jpeg->lock))
+ return -ERESTARTSYS;
+ ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+ mutex_unlock(&jpeg->lock);
+ return ret;
+}
+
+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;
+ /*
+ * This is only a mem-to-mem video device. The capture and output
+ * device capability flags are left only for backward compatibility
+ * and are scheduled for removal.
+ */
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
+ 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);
+}
+
+static 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:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE:
+ 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 = devm_kzalloc(&pdev->dev, 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);
+
+ jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (jpeg->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
+ }
+
+ /* interrupt service routine registration */
+ jpeg->irq = ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
+ dev_name(&pdev->dev), jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
+ return ret;
+ }
+
+ /* 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);
+ return ret;
+ }
+ 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);
+
+ 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);
+
+ 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,
+ },
+};
+
+module_platform_driver(s5p_jpeg_driver);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung JPEG codec driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
new file mode 100644
index 000000000000..022b9b9baff9
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -0,0 +1,150 @@
+/* linux/drivers/media/platform/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
+ * @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;
+
+ 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/platform/s5p-jpeg/jpeg-hw.h b/drivers/media/platform/s5p-jpeg/jpeg-hw.h
new file mode 100644
index 000000000000..b47e887b6138
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw.h
@@ -0,0 +1,357 @@
+/* linux/drivers/media/platform/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/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
new file mode 100644
index 000000000000..38e50815668c
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -0,0 +1,170 @@
+/* linux/drivers/media/platform/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/Makefile b/drivers/media/platform/s5p-mfc/Makefile
index d0663409af00..d0663409af00 100644
--- a/drivers/media/video/s5p-mfc/Makefile
+++ b/drivers/media/platform/s5p-mfc/Makefile
diff --git a/drivers/media/video/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h
index a19bece41ba9..a19bece41ba9 100644
--- a/drivers/media/video/s5p-mfc/regs-mfc.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc.h
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
new file mode 100644
index 000000000000..e3e616d8a09d
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -0,0 +1,1230 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.1
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+#define S5P_MFC_NAME "s5p-mfc"
+#define S5P_MFC_DEC_NAME "s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
+
+int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
+
+/* Helper functions for interrupt processing */
+/* Remove from hw execution round robin */
+static void clear_work_bit(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+}
+
+/* Wake up context wait_queue */
+static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+ unsigned int err)
+{
+ ctx->int_cond = 1;
+ ctx->int_type = reason;
+ ctx->int_err = err;
+ wake_up(&ctx->queue);
+}
+
+/* Wake up device wait_queue */
+static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+ unsigned int err)
+{
+ dev->int_cond = 1;
+ dev->int_type = reason;
+ dev->int_err = err;
+ wake_up(&dev->queue);
+}
+
+static void s5p_mfc_watchdog(unsigned long arg)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+ if (test_bit(0, &dev->hw_lock))
+ atomic_inc(&dev->watchdog_cnt);
+ if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
+ /* This means that hw is busy and no interrupts were
+ * generated by hw for the Nth time of running this
+ * watchdog timer. This usually means a serious hw
+ * error. Now it is time to kill all instances and
+ * reset the MFC. */
+ mfc_err("Time out during waiting for HW\n");
+ queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+ }
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+}
+
+static void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx;
+ unsigned long flags;
+ int mutex_locked;
+ int i, ret;
+
+ dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+ mfc_err("Driver timeout error handling\n");
+ /* Lock the mutex that protects open and release.
+ * This is necessary as they may load and unload firmware. */
+ mutex_locked = mutex_trylock(&dev->mfc_mutex);
+ if (!mutex_locked)
+ mfc_err("Error: some instance may be closing/opening\n");
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ s5p_mfc_clock_off();
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ ctx = dev->ctx[i];
+ if (!ctx)
+ continue;
+ ctx->state = MFCINST_ERROR;
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ clear_work_bit(ctx);
+ wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
+ }
+ clear_bit(0, &dev->hw_lock);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ /* Double check if there is at least one instance running.
+ * If no instance is in memory than no firmware should be present */
+ if (dev->num_inst > 0) {
+ ret = s5p_mfc_reload_firmware(dev);
+ if (ret) {
+ mfc_err("Failed to reload FW\n");
+ goto unlock;
+ }
+ s5p_mfc_clock_on();
+ ret = s5p_mfc_init_hw(dev);
+ if (ret)
+ mfc_err("Failed to reinit FW\n");
+ }
+unlock:
+ if (mutex_locked)
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (!vdev) {
+ mfc_err("failed to get video_device");
+ return MFCNODE_INVALID;
+ }
+ if (vdev->index == 0)
+ return MFCNODE_DECODER;
+ else if (vdev->index == 1)
+ return MFCNODE_ENCODER;
+ return MFCNODE_INVALID;
+}
+
+static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
+{
+ mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
+ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+ mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
+}
+
+static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *dst_buf;
+
+ ctx->state = MFCINST_FINISHED;
+ ctx->sequence++;
+ while (!list_empty(&ctx->dst_queue)) {
+ dst_buf = list_entry(ctx->dst_queue.next,
+ struct s5p_mfc_buf, list);
+ mfc_debug(2, "Cleaning up buffer: %d\n",
+ dst_buf->b->v4l2_buf.index);
+ vb2_set_plane_payload(dst_buf->b, 0, 0);
+ vb2_set_plane_payload(dst_buf->b, 1, 0);
+ list_del(&dst_buf->list);
+ ctx->dst_queue_cnt--;
+ dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
+
+ if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+ s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+ dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+ else
+ dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+ ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index);
+ vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE);
+ }
+}
+
+static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_buf, *src_buf;
+ size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
+ unsigned int frame_type = s5p_mfc_get_frame_type();
+
+ /* Copy timestamp / timecode from decoded src to dst and set
+ appropraite flags */
+ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+ if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
+ memcpy(&dst_buf->b->v4l2_buf.timecode,
+ &src_buf->b->v4l2_buf.timecode,
+ sizeof(struct v4l2_timecode));
+ memcpy(&dst_buf->b->v4l2_buf.timestamp,
+ &src_buf->b->v4l2_buf.timestamp,
+ sizeof(struct timeval));
+ switch (frame_type) {
+ case S5P_FIMV_DECODE_FRAME_I_FRAME:
+ dst_buf->b->v4l2_buf.flags |=
+ V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_DECODE_FRAME_P_FRAME:
+ dst_buf->b->v4l2_buf.flags |=
+ V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_DECODE_FRAME_B_FRAME:
+ dst_buf->b->v4l2_buf.flags |=
+ V4L2_BUF_FLAG_BFRAME;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_buf;
+ size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
+ unsigned int frame_type = s5p_mfc_get_frame_type();
+ unsigned int index;
+
+ /* If frame is same as previous then skip and do not dequeue */
+ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
+ if (!ctx->after_packed_pb)
+ ctx->sequence++;
+ ctx->after_packed_pb = 0;
+ return;
+ }
+ ctx->sequence++;
+ /* The MFC returns address of the buffer, now we have to
+ * check which videobuf does it correspond to */
+ list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+ /* Check if this is the buffer we're looking for */
+ if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) {
+ list_del(&dst_buf->list);
+ ctx->dst_queue_cnt--;
+ dst_buf->b->v4l2_buf.sequence = ctx->sequence;
+ if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+ s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+ dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+ else
+ dst_buf->b->v4l2_buf.field =
+ V4L2_FIELD_INTERLACED;
+ vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size);
+ vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size);
+ clear_bit(dst_buf->b->v4l2_buf.index,
+ &ctx->dec_dst_flag);
+
+ vb2_buffer_done(dst_buf->b,
+ err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+ index = dst_buf->b->v4l2_buf.index;
+ break;
+ }
+ }
+}
+
+/* Handle frame decoding interrupt */
+static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int dst_frame_status;
+ struct s5p_mfc_buf *src_buf;
+ unsigned long flags;
+ unsigned int res_change;
+
+ unsigned int index;
+
+ dst_frame_status = s5p_mfc_get_dspl_status()
+ & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+ res_change = s5p_mfc_get_dspl_status()
+ & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
+ mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
+ if (ctx->state == MFCINST_RES_CHANGE_INIT)
+ ctx->state = MFCINST_RES_CHANGE_FLUSH;
+ if (res_change) {
+ ctx->state = MFCINST_RES_CHANGE_INIT;
+ s5p_mfc_clear_int_flags(dev);
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ s5p_mfc_try_run(dev);
+ return;
+ }
+ if (ctx->dpb_flush_flag)
+ ctx->dpb_flush_flag = 0;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ /* All frames remaining in the buffer have been extracted */
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+ if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+ s5p_mfc_handle_frame_all_extracted(ctx);
+ ctx->state = MFCINST_RES_CHANGE_END;
+ goto leave_handle_frame;
+ } else {
+ s5p_mfc_handle_frame_all_extracted(ctx);
+ }
+ }
+
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+ s5p_mfc_handle_frame_copy_time(ctx);
+
+ /* A frame has been decoded and is in the buffer */
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
+ s5p_mfc_handle_frame_new(ctx, err);
+ } else {
+ mfc_debug(2, "No frame decode\n");
+ }
+ /* Mark source buffer as complete */
+ if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
+ && !list_empty(&ctx->src_queue)) {
+ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+ list);
+ ctx->consumed_stream += s5p_mfc_get_consumed_stream();
+ if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
+ s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
+ && ctx->consumed_stream + STUFF_BYTE <
+ src_buf->b->v4l2_planes[0].bytesused) {
+ /* Run MFC again on the same buffer */
+ mfc_debug(2, "Running again the same buffer\n");
+ ctx->after_packed_pb = 1;
+ } else {
+ index = src_buf->b->v4l2_buf.index;
+ mfc_debug(2, "MFC needs next buffer\n");
+ ctx->consumed_stream = 0;
+ list_del(&src_buf->list);
+ ctx->src_queue_cnt--;
+ if (s5p_mfc_err_dec(err) > 0)
+ vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
+ else
+ vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
+ }
+ }
+leave_handle_frame:
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
+ || ctx->dst_queue_cnt < ctx->dpb_count)
+ clear_work_bit(ctx);
+ s5p_mfc_clear_int_flags(dev);
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ s5p_mfc_try_run(dev);
+}
+
+/* Error handling for interrupt */
+static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev;
+ unsigned long flags;
+
+ /* If no context is available then all necessary
+ * processing has been done. */
+ if (ctx == NULL)
+ return;
+
+ dev = ctx->dev;
+ mfc_err("Interrupt Error: %08x\n", err);
+ s5p_mfc_clear_int_flags(dev);
+ wake_up_dev(dev, reason, err);
+
+ /* Error recovery is dependent on the state of context */
+ switch (ctx->state) {
+ case MFCINST_INIT:
+ /* This error had to happen while acquireing instance */
+ case MFCINST_GOT_INST:
+ /* This error had to happen while parsing the header */
+ case MFCINST_HEAD_PARSED:
+ /* This error had to happen while setting dst buffers */
+ case MFCINST_RETURN_INST:
+ /* This error had to happen while releasing instance */
+ clear_work_bit(ctx);
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ ctx->state = MFCINST_ERROR;
+ break;
+ case MFCINST_FINISHING:
+ case MFCINST_FINISHED:
+ case MFCINST_RUNNING:
+ /* It is higly probable that an error occured
+ * while decoding a frame */
+ clear_work_bit(ctx);
+ ctx->state = MFCINST_ERROR;
+ /* Mark all dst buffers as having an error */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ /* Mark all src buffers as having an error */
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ break;
+ default:
+ mfc_err("Encountered an error interrupt which had not been handled\n");
+ break;
+ }
+ return;
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev;
+ unsigned int guard_width, guard_height;
+
+ if (ctx == NULL)
+ return;
+ dev = ctx->dev;
+ if (ctx->c_ops->post_seq_start) {
+ if (ctx->c_ops->post_seq_start(ctx))
+ mfc_err("post_seq_start() failed\n");
+ } else {
+ ctx->img_width = s5p_mfc_get_img_width();
+ ctx->img_height = s5p_mfc_get_img_height();
+
+ ctx->buf_width = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12MT_HALIGN);
+ ctx->buf_height = ALIGN(ctx->img_height,
+ S5P_FIMV_NV12MT_VALIGN);
+ mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+ "buffer dimensions: %dx%d\n", ctx->img_width,
+ ctx->img_height, ctx->buf_width,
+ ctx->buf_height);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+ ctx->luma_size = ALIGN(ctx->buf_width *
+ ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->chroma_size = ALIGN(ctx->buf_width *
+ ALIGN((ctx->img_height >> 1),
+ S5P_FIMV_NV12MT_VALIGN),
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->mv_size = ALIGN(ctx->buf_width *
+ ALIGN((ctx->buf_height >> 2),
+ S5P_FIMV_NV12MT_VALIGN),
+ S5P_FIMV_DEC_BUF_ALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 24,
+ S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN(ctx->img_height + 16,
+ S5P_FIMV_NV12MT_VALIGN);
+ ctx->luma_size = ALIGN(guard_width *
+ guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+ guard_width = ALIGN(ctx->img_width + 16,
+ S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4,
+ S5P_FIMV_NV12MT_VALIGN);
+ ctx->chroma_size = ALIGN(guard_width *
+ guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->mv_size = 0;
+ }
+ ctx->dpb_count = s5p_mfc_get_dpb_count();
+ if (ctx->img_width == 0 || ctx->img_height == 0)
+ ctx->state = MFCINST_ERROR;
+ else
+ ctx->state = MFCINST_HEAD_PARSED;
+ }
+ s5p_mfc_clear_int_flags(dev);
+ clear_work_bit(ctx);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ s5p_mfc_try_run(dev);
+ wake_up_ctx(ctx, reason, err);
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_buf *src_buf;
+ struct s5p_mfc_dev *dev;
+ unsigned long flags;
+
+ if (ctx == NULL)
+ return;
+ dev = ctx->dev;
+ s5p_mfc_clear_int_flags(dev);
+ ctx->int_type = reason;
+ ctx->int_err = err;
+ ctx->int_cond = 1;
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+ if (err == 0) {
+ ctx->state = MFCINST_RUNNING;
+ if (!ctx->dpb_flush_flag) {
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (!list_empty(&ctx->src_queue)) {
+ src_buf = list_entry(ctx->src_queue.next,
+ struct s5p_mfc_buf, list);
+ list_del(&src_buf->list);
+ ctx->src_queue_cnt--;
+ vb2_buffer_done(src_buf->b,
+ VB2_BUF_STATE_DONE);
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else {
+ ctx->dpb_flush_flag = 0;
+ }
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ wake_up(&ctx->queue);
+ s5p_mfc_try_run(dev);
+ } else {
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ wake_up(&ctx->queue);
+ }
+}
+
+/* Interrupt processing */
+static irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+ struct s5p_mfc_dev *dev = priv;
+ struct s5p_mfc_ctx *ctx;
+ unsigned int reason;
+ unsigned int err;
+
+ mfc_debug_enter();
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_cnt, 0);
+ ctx = dev->ctx[dev->curr_ctx];
+ /* Get the reason of interrupt and the error code */
+ reason = s5p_mfc_get_int_reason();
+ err = s5p_mfc_get_int_err();
+ mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_ERR_RET:
+ /* An error has occured */
+ if (ctx->state == MFCINST_RUNNING &&
+ s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
+ s5p_mfc_handle_frame(ctx, reason, err);
+ else
+ s5p_mfc_handle_error(ctx, reason, err);
+ clear_bit(0, &dev->enter_suspend);
+ break;
+
+ case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+ case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+ if (ctx->c_ops->post_frame_start) {
+ if (ctx->c_ops->post_frame_start(ctx))
+ mfc_err("post_frame_start() failed\n");
+ s5p_mfc_clear_int_flags(dev);
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ BUG();
+ s5p_mfc_clock_off();
+ s5p_mfc_try_run(dev);
+ } else {
+ s5p_mfc_handle_frame(ctx, reason, err);
+ }
+ break;
+
+ case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+ s5p_mfc_handle_seq_done(ctx, reason, err);
+ break;
+
+ case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+ ctx->inst_no = s5p_mfc_get_inst_no();
+ ctx->state = MFCINST_GOT_INST;
+ clear_work_bit(ctx);
+ wake_up(&ctx->queue);
+ goto irq_cleanup_hw;
+
+ case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+ clear_work_bit(ctx);
+ ctx->state = MFCINST_FREE;
+ wake_up(&ctx->queue);
+ goto irq_cleanup_hw;
+
+ case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+ case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+ case S5P_FIMV_R2H_CMD_SLEEP_RET:
+ case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+ if (ctx)
+ clear_work_bit(ctx);
+ s5p_mfc_clear_int_flags(dev);
+ wake_up_dev(dev, reason, err);
+ clear_bit(0, &dev->hw_lock);
+ clear_bit(0, &dev->enter_suspend);
+ break;
+
+ case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+ s5p_mfc_handle_init_buffers(ctx, reason, err);
+ break;
+ default:
+ mfc_debug(2, "Unknown int reason\n");
+ s5p_mfc_clear_int_flags(dev);
+ }
+ mfc_debug_leave();
+ return IRQ_HANDLED;
+irq_cleanup_hw:
+ s5p_mfc_clear_int_flags(dev);
+ ctx->int_type = reason;
+ ctx->int_err = err;
+ ctx->int_cond = 1;
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ mfc_err("Failed to unlock hw\n");
+
+ s5p_mfc_clock_off();
+
+ s5p_mfc_try_run(dev);
+ mfc_debug(2, "Exit via irq_cleanup_hw\n");
+ return IRQ_HANDLED;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = NULL;
+ struct vb2_queue *q;
+ unsigned long flags;
+ int ret = 0;
+
+ mfc_debug_enter();
+ if (mutex_lock_interruptible(&dev->mfc_mutex))
+ return -ERESTARTSYS;
+ dev->num_inst++; /* It is guarded by mfc_mutex in vfd */
+ /* Allocate memory for context */
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ mfc_err("Not enough memory\n");
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+ ctx->dev = dev;
+ INIT_LIST_HEAD(&ctx->src_queue);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->src_queue_cnt = 0;
+ ctx->dst_queue_cnt = 0;
+ /* Get context number */
+ ctx->num = 0;
+ while (dev->ctx[ctx->num]) {
+ ctx->num++;
+ if (ctx->num >= MFC_NUM_CONTEXTS) {
+ mfc_err("Too many open contexts\n");
+ ret = -EBUSY;
+ goto err_no_ctx;
+ }
+ }
+ /* Mark context as idle */
+ spin_lock_irqsave(&dev->condlock, flags);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ dev->ctx[ctx->num] = ctx;
+ if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+ ctx->type = MFCINST_DECODER;
+ ctx->c_ops = get_dec_codec_ops();
+ /* Setup ctrl handler */
+ ret = s5p_mfc_dec_ctrls_setup(ctx);
+ if (ret) {
+ mfc_err("Failed to setup mfc controls\n");
+ goto err_ctrls_setup;
+ }
+ } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+ ctx->type = MFCINST_ENCODER;
+ ctx->c_ops = get_enc_codec_ops();
+ /* only for encoder */
+ INIT_LIST_HEAD(&ctx->ref_queue);
+ ctx->ref_queue_cnt = 0;
+ /* Setup ctrl handler */
+ ret = s5p_mfc_enc_ctrls_setup(ctx);
+ if (ret) {
+ mfc_err("Failed to setup mfc controls\n");
+ goto err_ctrls_setup;
+ }
+ } else {
+ ret = -ENOENT;
+ goto err_bad_node;
+ }
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+ ctx->inst_no = -1;
+ /* Load firmware if this is the first instance */
+ if (dev->num_inst == 1) {
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+ ret = s5p_mfc_power_on();
+ if (ret < 0) {
+ mfc_err("power on failed\n");
+ goto err_pwr_enable;
+ }
+ s5p_mfc_clock_on();
+ ret = s5p_mfc_alloc_and_load_firmware(dev);
+ if (ret)
+ goto err_alloc_fw;
+ /* Init the FW */
+ ret = s5p_mfc_init_hw(dev);
+ if (ret)
+ goto err_init_hw;
+ s5p_mfc_clock_off();
+ }
+ /* Init videobuf2 queue for CAPTURE */
+ q = &ctx->vq_dst;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->drv_priv = &ctx->fh;
+ if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+ q->io_modes = VB2_MMAP;
+ q->ops = get_dec_queue_ops();
+ } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->ops = get_enc_queue_ops();
+ } else {
+ ret = -ENOENT;
+ goto err_queue_init;
+ }
+ q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ ret = vb2_queue_init(q);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+ goto err_queue_init;
+ }
+ /* Init videobuf2 queue for OUTPUT */
+ q = &ctx->vq_src;
+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ q->io_modes = VB2_MMAP;
+ q->drv_priv = &ctx->fh;
+ if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+ q->io_modes = VB2_MMAP;
+ q->ops = get_dec_queue_ops();
+ } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->ops = get_enc_queue_ops();
+ } else {
+ ret = -ENOENT;
+ goto err_queue_init;
+ }
+ q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ ret = vb2_queue_init(q);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(output)\n");
+ goto err_queue_init;
+ }
+ init_waitqueue_head(&ctx->queue);
+ mutex_unlock(&dev->mfc_mutex);
+ mfc_debug_leave();
+ return ret;
+ /* Deinit when failure occured */
+err_queue_init:
+err_init_hw:
+ s5p_mfc_release_firmware(dev);
+err_alloc_fw:
+ dev->ctx[ctx->num] = NULL;
+ del_timer_sync(&dev->watchdog_timer);
+ s5p_mfc_clock_off();
+err_pwr_enable:
+ if (dev->num_inst == 1) {
+ if (s5p_mfc_power_off() < 0)
+ mfc_err("power off failed\n");
+ s5p_mfc_release_firmware(dev);
+ }
+err_ctrls_setup:
+ s5p_mfc_dec_ctrls_delete(ctx);
+err_bad_node:
+err_no_ctx:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+err_alloc:
+ dev->num_inst--;
+ mutex_unlock(&dev->mfc_mutex);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ mfc_debug_enter();
+ mutex_lock(&dev->mfc_mutex);
+ s5p_mfc_clock_on();
+ vb2_queue_release(&ctx->vq_src);
+ vb2_queue_release(&ctx->vq_dst);
+ /* Mark context as idle */
+ spin_lock_irqsave(&dev->condlock, flags);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ /* If instance was initialised then
+ * return instance and free reosurces */
+ if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+ mfc_debug(2, "Has to free instance\n");
+ ctx->state = MFCINST_RETURN_INST;
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_try_run(dev);
+ /* Wait until instance is returned or timeout occured */
+ if (s5p_mfc_wait_for_done_ctx
+ (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
+ s5p_mfc_clock_off();
+ mfc_err("Err returning instance\n");
+ }
+ mfc_debug(2, "After free instance\n");
+ /* Free resources */
+ s5p_mfc_release_codec_buffers(ctx);
+ s5p_mfc_release_instance_buffer(ctx);
+ if (ctx->type == MFCINST_DECODER)
+ s5p_mfc_release_dec_desc_buffer(ctx);
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+ }
+ /* hardware locking scheme */
+ if (dev->curr_ctx == ctx->num)
+ clear_bit(0, &dev->hw_lock);
+ dev->num_inst--;
+ if (dev->num_inst == 0) {
+ mfc_debug(2, "Last instance - release firmware\n");
+ /* reset <-> F/W release */
+ s5p_mfc_reset(dev);
+ s5p_mfc_release_firmware(dev);
+ del_timer_sync(&dev->watchdog_timer);
+ if (s5p_mfc_power_off() < 0)
+ mfc_err("Power off failed\n");
+ }
+ mfc_debug(2, "Shutting down clock\n");
+ s5p_mfc_clock_off();
+ dev->ctx[ctx->num] = NULL;
+ s5p_mfc_dec_ctrls_delete(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ mfc_debug_leave();
+ mutex_unlock(&dev->mfc_mutex);
+ return 0;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct vb2_queue *src_q, *dst_q;
+ struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
+ unsigned int rc = 0;
+ unsigned long flags;
+
+ mutex_lock(&dev->mfc_mutex);
+ src_q = &ctx->vq_src;
+ dst_q = &ctx->vq_dst;
+ /*
+ * There has to be at least one buffer queued on each queued_list, which
+ * means either in driver already or waiting for driver to claim it
+ * and start processing.
+ */
+ if ((!src_q->streaming || list_empty(&src_q->queued_list))
+ && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+ rc = POLLERR;
+ goto end;
+ }
+ mutex_unlock(&dev->mfc_mutex);
+ poll_wait(file, &src_q->done_wq, wait);
+ poll_wait(file, &dst_q->done_wq, wait);
+ mutex_lock(&dev->mfc_mutex);
+ spin_lock_irqsave(&src_q->done_lock, flags);
+ if (!list_empty(&src_q->done_list))
+ src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
+ done_entry);
+ if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
+ || src_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&src_q->done_lock, flags);
+ spin_lock_irqsave(&dst_q->done_lock, flags);
+ if (!list_empty(&dst_q->done_list))
+ dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
+ done_entry);
+ if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
+ || dst_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&dst_q->done_lock, flags);
+end:
+ mutex_unlock(&dev->mfc_mutex);
+ return rc;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int ret;
+
+ if (mutex_lock_interruptible(&dev->mfc_mutex))
+ return -ERESTARTSYS;
+ if (offset < DST_QUEUE_OFF_BASE) {
+ mfc_debug(2, "mmaping source\n");
+ ret = vb2_mmap(&ctx->vq_src, vma);
+ } else { /* capture */
+ mfc_debug(2, "mmaping destination\n");
+ vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+ ret = vb2_mmap(&ctx->vq_dst, vma);
+ }
+ mutex_unlock(&dev->mfc_mutex);
+ return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_mfc_open,
+ .release = s5p_mfc_release,
+ .poll = s5p_mfc_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = s5p_mfc_mmap,
+};
+
+static int match_child(struct device *dev, void *data)
+{
+ if (!dev_name(dev))
+ return 0;
+ return !strcmp(dev_name(dev), (char *)data);
+}
+
+/* MFC probe function */
+static int s5p_mfc_probe(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev;
+ struct video_device *vfd;
+ struct resource *res;
+ int ret;
+
+ pr_debug("%s++\n", __func__);
+ dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Not enough memory for MFC device\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&dev->irqlock);
+ spin_lock_init(&dev->condlock);
+ dev->plat_dev = pdev;
+ if (!dev->plat_dev) {
+ dev_err(&pdev->dev, "No platform data specified\n");
+ return -ENODEV;
+ }
+
+ ret = s5p_mfc_init_pm(dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get mfc clock source\n");
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (dev->regs_base == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
+ dev->irq = res->start;
+ ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
+ IRQF_DISABLED, pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+ goto err_res;
+ }
+
+ dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
+ match_child);
+ if (!dev->mem_dev_l) {
+ mfc_err("Mem child (L) device get failed\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
+ dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
+ match_child);
+ if (!dev->mem_dev_r) {
+ mfc_err("Mem child (R) device get failed\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
+
+ dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
+ if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
+ ret = PTR_ERR(dev->alloc_ctx[0]);
+ goto err_res;
+ }
+ dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
+ if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
+ ret = PTR_ERR(dev->alloc_ctx[1]);
+ goto err_mem_init_ctx_1;
+ }
+
+ mutex_init(&dev->mfc_mutex);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto err_v4l2_dev_reg;
+ init_waitqueue_head(&dev->queue);
+
+ /* decoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto err_dec_alloc;
+ }
+ vfd->fops = &s5p_mfc_fops,
+ vfd->ioctl_ops = get_dec_v4l2_ioctl_ops();
+ vfd->release = video_device_release,
+ vfd->lock = &dev->mfc_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
+ dev->vfd_dec = vfd;
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(vfd);
+ goto err_dec_reg;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "decoder registered as /dev/video%d\n", vfd->num);
+ video_set_drvdata(vfd, dev);
+
+ /* encoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto err_enc_alloc;
+ }
+ vfd->fops = &s5p_mfc_fops,
+ vfd->ioctl_ops = get_enc_v4l2_ioctl_ops();
+ vfd->release = video_device_release,
+ vfd->lock = &dev->mfc_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
+ dev->vfd_enc = vfd;
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(vfd);
+ goto err_enc_reg;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "encoder registered as /dev/video%d\n", vfd->num);
+ video_set_drvdata(vfd, dev);
+ platform_set_drvdata(pdev, dev);
+
+ dev->hw_lock = 0;
+ dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
+ INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+ atomic_set(&dev->watchdog_cnt, 0);
+ init_timer(&dev->watchdog_timer);
+ dev->watchdog_timer.data = (unsigned long)dev;
+ dev->watchdog_timer.function = s5p_mfc_watchdog;
+
+ pr_debug("%s--\n", __func__);
+ return 0;
+
+/* Deinit MFC if probe had failed */
+err_enc_reg:
+ video_device_release(dev->vfd_enc);
+err_enc_alloc:
+ video_unregister_device(dev->vfd_dec);
+err_dec_reg:
+ video_device_release(dev->vfd_dec);
+err_dec_alloc:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_dev_reg:
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+err_mem_init_ctx_1:
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+err_res:
+ s5p_mfc_final_pm(dev);
+
+ pr_debug("%s-- with error\n", __func__);
+ return ret;
+
+}
+
+/* Remove the driver */
+static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+ v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+
+ del_timer_sync(&dev->watchdog_timer);
+ flush_workqueue(dev->watchdog_workqueue);
+ destroy_workqueue(dev->watchdog_workqueue);
+
+ video_unregister_device(dev->vfd_enc);
+ video_unregister_device(dev->vfd_dec);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+
+ s5p_mfc_final_pm(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int s5p_mfc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+ int ret;
+
+ if (m_dev->num_inst == 0)
+ return 0;
+ return s5p_mfc_sleep(m_dev);
+ if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) {
+ mfc_err("Error: going to suspend for a second time\n");
+ return -EIO;
+ }
+
+ /* Check if we're processing then wait if it necessary. */
+ while (test_and_set_bit(0, &m_dev->hw_lock) != 0) {
+ /* Try and lock the HW */
+ /* Wait on the interrupt waitqueue */
+ ret = wait_event_interruptible_timeout(m_dev->queue,
+ m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+
+ if (ret == 0) {
+ mfc_err("Waiting for hardware to finish timed out\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+ if (m_dev->num_inst == 0)
+ return 0;
+ return s5p_mfc_wakeup(m_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+ atomic_set(&m_dev->pm.power, 0);
+ return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+ int pre_power;
+
+ if (!m_dev->alloc_ctx)
+ return 0;
+ pre_power = atomic_read(&m_dev->pm.power);
+ atomic_set(&m_dev->pm.power, 1);
+ return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+ SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver s5p_mfc_driver = {
+ .probe = s5p_mfc_probe,
+ .remove = __devexit_p(s5p_mfc_remove),
+ .driver = {
+ .name = S5P_MFC_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5p_mfc_pm_ops
+ },
+};
+
+module_platform_driver(s5p_mfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver");
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
new file mode 100644
index 000000000000..91a415573bd2
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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 "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+/* This function is used to send a command to the MFC */
+static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
+ struct s5p_mfc_cmd_args *args)
+{
+ int cur_cmd;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while waiting for hardware\n");
+ return -EIO;
+ }
+ cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
+ } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
+ mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
+ mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
+ mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
+ mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
+ /* Issue the command */
+ mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
+ return 0;
+}
+
+/* Initialize the MFC */
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = dev->fw_size;
+ return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+}
+
+/* Suspend the MFC hardware */
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+}
+
+/* Wake up the MFC hardware */
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+}
+
+
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ /* Preparing decoding - getting instance number */
+ mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
+ dev->curr_ctx = ctx->num;
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = ctx->codec_mode;
+ h2r_args.arg[1] = 0; /* no crc & no pixelcache */
+ h2r_args.arg[2] = ctx->ctx_ofs;
+ h2r_args.arg[3] = ctx->ctx_size;
+ ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
+ &h2r_args);
+ if (ret) {
+ mfc_err("Failed to create a new instance\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ if (ctx->state == MFCINST_FREE) {
+ mfc_err("Instance already returned\n");
+ ctx->state = MFCINST_ERROR;
+ return -EINVAL;
+ }
+ /* Closing decoding instance */
+ mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
+ dev->curr_ctx = ctx->num;
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = ctx->inst_no;
+ ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+ &h2r_args);
+ if (ret) {
+ mfc_err("Failed to return an instance\n");
+ ctx->state = MFCINST_ERROR;
+ return -EINVAL;
+ }
+ return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
new file mode 100644
index 000000000000..8b090d3723e7
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
@@ -0,0 +1,30 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_CMD_H_
+#define S5P_MFC_CMD_H_
+
+#include "s5p_mfc_common.h"
+
+#define MAX_H2R_ARG 4
+
+struct s5p_mfc_cmd_args {
+ unsigned int arg[MAX_H2R_ARG];
+};
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_CMD_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index bd5706a6bad1..bd5706a6bad1 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
new file mode 100644
index 000000000000..4d662f1c4acc
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.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/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_pm.h"
+
+static void *s5p_mfc_bitproc_buf;
+static size_t s5p_mfc_bitproc_phys;
+static unsigned char *s5p_mfc_bitproc_virt;
+
+/* Allocate and load firmware */
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
+{
+ struct firmware *fw_blob;
+ size_t bank2_base_phys;
+ void *b_base;
+ int err;
+
+ /* Firmare has to be present as a separate file or compiled
+ * into kernel. */
+ mfc_debug_enter();
+ err = request_firmware((const struct firmware **)&fw_blob,
+ "s5p-mfc.fw", dev->v4l2_dev.dev);
+ if (err != 0) {
+ mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+ return -EINVAL;
+ }
+ dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN);
+ if (s5p_mfc_bitproc_buf) {
+ mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+ s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
+ if (IS_ERR(s5p_mfc_bitproc_buf)) {
+ s5p_mfc_bitproc_buf = NULL;
+ mfc_err("Allocating bitprocessor buffer failed\n");
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+ s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
+ if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+ mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
+ vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = NULL;
+ release_firmware(fw_blob);
+ return -EIO;
+ }
+ s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
+ if (!s5p_mfc_bitproc_virt) {
+ mfc_err("Bitprocessor memory remap failed\n");
+ vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = NULL;
+ release_firmware(fw_blob);
+ return -EIO;
+ }
+ dev->bank1 = s5p_mfc_bitproc_phys;
+ b_base = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER);
+ if (IS_ERR(b_base)) {
+ vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = NULL;
+ mfc_err("Allocating bank2 base failed\n");
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+ bank2_base_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
+ vb2_dma_contig_memops.put(b_base);
+ if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+ mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
+ vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = NULL;
+ release_firmware(fw_blob);
+ return -EIO;
+ }
+ dev->bank2 = bank2_base_phys;
+ memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+ wmb();
+ release_firmware(fw_blob);
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Reload firmware to MFC */
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
+{
+ struct firmware *fw_blob;
+ int err;
+
+ /* Firmare has to be present as a separate file or compiled
+ * into kernel. */
+ mfc_debug_enter();
+ err = request_firmware((const struct firmware **)&fw_blob,
+ "s5p-mfc.fw", dev->v4l2_dev.dev);
+ if (err != 0) {
+ mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+ return -EINVAL;
+ }
+ if (fw_blob->size > dev->fw_size) {
+ mfc_err("MFC firmware is too big to be loaded\n");
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+ if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
+ mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
+ release_firmware(fw_blob);
+ return -EINVAL;
+ }
+ memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+ wmb();
+ release_firmware(fw_blob);
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+ /* Before calling this function one has to make sure
+ * that MFC is no longer processing */
+ if (!s5p_mfc_bitproc_buf)
+ return -EINVAL;
+ vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_virt = NULL;
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = NULL;
+ return 0;
+}
+
+/* Reset the device */
+int s5p_mfc_reset(struct s5p_mfc_dev *dev)
+{
+ unsigned int mc_status;
+ unsigned long timeout;
+
+ mfc_debug_enter();
+ /* Stop procedure */
+ /* reset RISC */
+ mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
+ /* All reset except for MC */
+ mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
+ mdelay(10);
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check MC status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while resetting MFC\n");
+ return -EIO;
+ }
+
+ mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
+
+ } while (mc_status & 0x3);
+
+ mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
+ mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
+ mfc_debug_leave();
+ return 0;
+}
+
+static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
+{
+ mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
+ mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
+ mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
+}
+
+static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
+{
+ mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
+ mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
+ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+ mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
+}
+
+/* Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+ unsigned int ver;
+ int ret;
+
+ mfc_debug_enter();
+ if (!s5p_mfc_bitproc_buf)
+ return -EINVAL;
+
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset..\n");
+ s5p_mfc_clock_on();
+ ret = s5p_mfc_reset(dev);
+ if (ret) {
+ mfc_err("Failed to reset MFC - timeout\n");
+ return ret;
+ }
+ mfc_debug(2, "Done MFC reset..\n");
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_init_memctrl(dev);
+ /* 2. Initialize registers of channel I/F */
+ s5p_mfc_clear_cmds(dev);
+ /* 3. Release reset signal to the RISC */
+ s5p_mfc_clean_dev_int_flags(dev);
+ mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+ mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+ mfc_err("Failed to load firmware\n");
+ s5p_mfc_reset(dev);
+ s5p_mfc_clock_off();
+ return -EIO;
+ }
+ s5p_mfc_clean_dev_int_flags(dev);
+ /* 4. Initialize firmware */
+ ret = s5p_mfc_sys_init_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout\n");
+ s5p_mfc_reset(dev);
+ s5p_mfc_clock_off();
+ return ret;
+ }
+ mfc_debug(2, "Ok, now will write a command to init the system\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+ mfc_err("Failed to load firmware\n");
+ s5p_mfc_reset(dev);
+ s5p_mfc_clock_off();
+ return -EIO;
+ }
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+ /* Failure. */
+ mfc_err("Failed to init firmware - error: %d int: %d\n",
+ dev->int_err, dev->int_type);
+ s5p_mfc_reset(dev);
+ s5p_mfc_clock_off();
+ return -EIO;
+ }
+ ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
+ mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
+ (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
+ s5p_mfc_clock_off();
+ mfc_debug_leave();
+ return 0;
+}
+
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ mfc_debug_enter();
+ s5p_mfc_clock_on();
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = s5p_mfc_sleep_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout\n");
+ return ret;
+ }
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+ mfc_err("Failed to sleep\n");
+ return -EIO;
+ }
+ s5p_mfc_clock_off();
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_SLEEP_RET) {
+ /* Failure. */
+ mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
+ dev->int_type);
+ return -EIO;
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ mfc_debug_enter();
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset..\n");
+ s5p_mfc_clock_on();
+ ret = s5p_mfc_reset(dev);
+ if (ret) {
+ mfc_err("Failed to reset MFC - timeout\n");
+ return ret;
+ }
+ mfc_debug(2, "Done MFC reset..\n");
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_init_memctrl(dev);
+ /* 2. Initialize registers of channel I/F */
+ s5p_mfc_clear_cmds(dev);
+ s5p_mfc_clean_dev_int_flags(dev);
+ /* 3. Initialize firmware */
+ ret = s5p_mfc_wakeup_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout\n");
+ return ret;
+ }
+ /* 4. Release reset signal to the RISC */
+ mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+ mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+ mfc_err("Failed to load firmware\n");
+ return -EIO;
+ }
+ s5p_mfc_clock_off();
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+ /* Failure. */
+ mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
+ dev->int_type);
+ return -EIO;
+ }
+ mfc_debug_leave();
+ return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
new file mode 100644
index 000000000000..e1e0c544b6a2
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_CTRL_H
+#define S5P_MFC_CTRL_H
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_reset(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
new file mode 100644
index 000000000000..bd5cd4ae993c
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
@@ -0,0 +1,48 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains debug macros
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.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 S5P_MFC_DEBUG_H_
+#define S5P_MFC_DEBUG_H_
+
+#define DEBUG
+
+#ifdef DEBUG
+extern int debug;
+
+#define mfc_debug(level, fmt, args...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define mfc_debug(level, fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter")
+#define mfc_debug_leave() mfc_debug(5, "leave")
+
+#define mfc_err(fmt, args...) \
+ do { \
+ printk(KERN_ERR "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define mfc_info(fmt, args...) \
+ do { \
+ printk(KERN_INFO "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
new file mode 100644
index 000000000000..456f5df6b179
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -0,0 +1,1044 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ * 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/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#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/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+static struct s5p_mfc_fmt formats[] = {
+ {
+ .name = "4:2:0 2 Planes 64x32 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT,
+ .codec_mode = S5P_FIMV_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = S5P_FIMV_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG1,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "XviD Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_XVID,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "VC1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "VC1 RCV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+ formats[i].type == t)
+ return &formats[i];
+ }
+ return NULL;
+}
+
+static struct mfc_control controls[] = {
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Display Delay",
+ .minimum = 0,
+ .maximum = 16383,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 Display Delay Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mpeg4 Loop Filter Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Slice Interface Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Minimum number of cap bufs",
+ .minimum = 1,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 1,
+ .is_volatile = 1,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+/* Check whether a context should be run on hardware */
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ /* Context is to parse header */
+ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
+ return 1;
+ /* Context is to decode a frame */
+ if (ctx->src_queue_cnt >= 1 &&
+ ctx->state == MFCINST_RUNNING &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ /* Context is to return last frame */
+ if (ctx->state == MFCINST_FINISHING &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ /* Context is to set buffers */
+ if (ctx->src_queue_cnt >= 1 &&
+ ctx->state == MFCINST_HEAD_PARSED &&
+ ctx->capture_state == QUEUE_BUFS_MMAPED)
+ return 1;
+ /* Resolution change */
+ if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
+ ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ if (ctx->state == MFCINST_RES_CHANGE_END &&
+ ctx->src_queue_cnt >= 1)
+ return 1;
+ mfc_debug(2, "ctx is not ready\n");
+ return 0;
+}
+
+static struct s5p_mfc_codec_ops decoder_codec_ops = {
+ .pre_seq_start = NULL,
+ .post_seq_start = NULL,
+ .pre_frame_start = NULL,
+ .post_frame_start = NULL,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ /*
+ * This is only a mem-to-mem video device. The capture and output
+ * device capability flags are left only for backward compatibility
+ * and are scheduled for removal.
+ */
+ cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+/* Enumerate format */
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+ struct s5p_mfc_fmt *fmt;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (mplane && formats[i].num_planes == 1)
+ continue;
+ else if (!mplane && formats[i].num_planes > 1)
+ continue;
+ if (out && formats[i].type != MFC_FMT_DEC)
+ continue;
+ else if (!out && formats[i].type != MFC_FMT_RAW)
+ continue;
+
+ if (j == f->index)
+ break;
+ ++j;
+ }
+ if (i == ARRAY_SIZE(formats))
+ return -EINVAL;
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, true);
+}
+
+/* Get format */
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ mfc_debug_enter();
+ pix_mp = &f->fmt.pix_mp;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ (ctx->state == MFCINST_GOT_INST || ctx->state ==
+ MFCINST_RES_CHANGE_END)) {
+ /* If the MFC is parsing the header,
+ * so wait until it is finished */
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
+ 0);
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ /* This is run on CAPTURE (decode output) */
+ /* Width and height are set to the dimensions
+ of the movie, the buffer is bigger and
+ further processing stages should crop to this
+ rectangle. */
+ pix_mp->width = ctx->buf_width;
+ pix_mp->height = ctx->buf_height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = 2;
+ /* Set pixelformat to the format in which MFC
+ outputs the decoded frame */
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+ pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* This is run on OUTPUT
+ The buffer contains compressed image
+ so width and height have no meaning */
+ pix_mp->width = 0;
+ pix_mp->height = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
+ pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
+ pix_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_mp->num_planes = ctx->src_fmt->num_planes;
+ } else {
+ mfc_err("Format could not be read\n");
+ mfc_debug(2, "%s-- with error\n", __func__);
+ return -EINVAL;
+ }
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_fmt *fmt;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_err("This node supports decoding only\n");
+ return -EINVAL;
+ }
+ fmt = find_format(f, MFC_FMT_DEC);
+ if (!fmt) {
+ mfc_err("Unsupported format\n");
+ return -EINVAL;
+ }
+ if (fmt->type != MFC_FMT_DEC) {
+ mfc_err("\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret = 0;
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ mfc_debug_enter();
+ ret = vidioc_try_fmt(file, priv, f);
+ pix_mp = &f->fmt.pix_mp;
+ if (ret)
+ return ret;
+ if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+ v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+ fmt = find_format(f, MFC_FMT_DEC);
+ if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+ mfc_err("Unknown codec\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (fmt->type != MFC_FMT_DEC) {
+ mfc_err("Wrong format selected, you should choose "
+ "format for decoding\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ctx->src_fmt = fmt;
+ ctx->codec_mode = fmt->codec_mode;
+ mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+ pix_mp->height = 0;
+ pix_mp->width = 0;
+ if (pix_mp->plane_fmt[0].sizeimage)
+ ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+ else
+ pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+ DEF_CPB_SIZE;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ ctx->state = MFCINST_INIT;
+out:
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret = 0;
+ unsigned long flags;
+
+ if (reqbufs->memory != V4L2_MEMORY_MMAP) {
+ mfc_err("Only V4L2_MEMORY_MAP is supported\n");
+ return -EINVAL;
+ }
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* Can only request buffers after an instance has been opened.*/
+ if (ctx->state == MFCINST_INIT) {
+ ctx->src_bufs_cnt = 0;
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers\n");
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ s5p_mfc_clock_off();
+ return ret;
+ }
+ /* Decoding */
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err("Bufs have already been requested\n");
+ return -EINVAL;
+ }
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ s5p_mfc_clock_off();
+ if (ret) {
+ mfc_err("vb2_reqbufs on output failed\n");
+ return ret;
+ }
+ mfc_debug(2, "vb2_reqbufs: %d\n", ret);
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ }
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ctx->dst_bufs_cnt = 0;
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers\n");
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_clock_off();
+ return ret;
+ }
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err("Bufs have already been requested\n");
+ return -EINVAL;
+ }
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_clock_off();
+ if (ret) {
+ mfc_err("vb2_reqbufs on capture failed\n");
+ return ret;
+ }
+ if (reqbufs->count < ctx->dpb_count) {
+ mfc_err("Not enough buffers allocated\n");
+ reqbufs->count = 0;
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_clock_off();
+ return -ENOMEM;
+ }
+ ctx->total_dpb_count = reqbufs->count;
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err("Failed to allocate decoding buffers\n");
+ reqbufs->count = 0;
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_clock_off();
+ return -ENOMEM;
+ }
+ if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
+ ctx->capture_state = QUEUE_BUFS_MMAPED;
+ } else {
+ mfc_err("Not all buffers passed to buf_init\n");
+ reqbufs->count = 0;
+ s5p_mfc_clock_on();
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_release_codec_buffers(ctx);
+ s5p_mfc_clock_off();
+ return -ENOMEM;
+ }
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
+ }
+ return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret;
+ int i;
+
+ if (buf->memory != V4L2_MEMORY_MMAP) {
+ mfc_err("Only mmaped buffers can be used\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
+ if (ctx->state == MFCINST_INIT &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ } else if (ctx->state == MFCINST_RUNNING &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ for (i = 0; i < buf->length; i++)
+ buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+ } else {
+ mfc_err("vidioc_querybuf called in an inappropriate state\n");
+ ret = -EINVAL;
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on QBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_qbuf(&ctx->vq_src, buf);
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_qbuf(&ctx->vq_dst, buf);
+ return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on DQBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+
+ if (ctx->state == MFCINST_INIT) {
+ ctx->dst_bufs_cnt = 0;
+ ctx->src_bufs_cnt = 0;
+ ctx->capture_state = QUEUE_FREE;
+ ctx->output_state = QUEUE_FREE;
+ s5p_mfc_alloc_instance_buffer(ctx);
+ s5p_mfc_alloc_dec_temp_buffers(ctx);
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_try_run(dev);
+
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
+ /* Error or timeout */
+ mfc_err("Error getting instance from hardware\n");
+ s5p_mfc_release_instance_buffer(ctx);
+ s5p_mfc_release_dec_desc_buffer(ctx);
+ return -EIO;
+ }
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+ }
+ ret = vb2_streamon(&ctx->vq_src, type);
+ }
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ret = vb2_streamon(&ctx->vq_dst, type);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_streamoff(&ctx->vq_src, type);
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_streamoff(&ctx->vq_dst, type);
+ return -EINVAL;
+}
+
+/* Set controls - v4l2 control framework */
+static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+ ctx->display_delay = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
+ ctx->display_delay_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ ctx->loop_filter_mpeg4 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ ctx->slice_interface = ctrl->val;
+ break;
+ default:
+ mfc_err("Invalid control 0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->val = ctx->dpb_count;
+ break;
+ } else if (ctx->state != MFCINST_INIT) {
+ v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+ return -EINVAL;
+ }
+ /* Should wait for the header to be parsed */
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0);
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->val = ctx->dpb_count;
+ } else {
+ v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+ return -EINVAL;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
+ .s_ctrl = s5p_mfc_dec_s_ctrl,
+ .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
+};
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *cr)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ u32 left, right, top, bottom;
+
+ if (ctx->state != MFCINST_HEAD_PARSED &&
+ ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
+ && ctx->state != MFCINST_FINISHED) {
+ mfc_err("Cannont set crop\n");
+ return -EINVAL;
+ }
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
+ left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
+ right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
+ left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
+ top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
+ bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
+ top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
+ cr->c.left = left;
+ cr->c.top = top;
+ cr->c.width = ctx->img_width - left - right;
+ cr->c.height = ctx->img_height - top - bottom;
+ mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
+ "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
+ cr->c.width, cr->c.height, right, bottom,
+ ctx->buf_width, ctx->buf_height);
+ } else {
+ cr->c.left = 0;
+ cr->c.top = 0;
+ cr->c.width = ctx->img_width;
+ cr->c.height = ctx->img_height;
+ mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
+ "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width,
+ ctx->buf_height);
+ }
+ return 0;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = 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,
+};
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *buf_count,
+ unsigned int *plane_count, unsigned int psize[],
+ void *allocators[])
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+ /* Video output for decoding (source)
+ * this can be set after getting an instance */
+ if (ctx->state == MFCINST_INIT &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* A single plane is required for input */
+ *plane_count = 1;
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ /* Video capture for decoding (destination)
+ * this can be set after the header was parsed */
+ } else if (ctx->state == MFCINST_HEAD_PARSED &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ /* Output plane count is 2 - one for Y and one for CbCr */
+ *plane_count = 2;
+ /* Setup buffer count */
+ if (*buf_count < ctx->dpb_count)
+ *buf_count = ctx->dpb_count;
+ if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
+ *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ } else {
+ mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+ ctx->state, vq->type);
+ return -EINVAL;
+ }
+ mfc_debug(2, "Buffer count=%d, plane count=%d\n",
+ *buf_count, *plane_count);
+ if (ctx->state == MFCINST_HEAD_PARSED &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ psize[0] = ctx->luma_size;
+ psize[1] = ctx->chroma_size;
+ allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+ allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ ctx->state == MFCINST_INIT) {
+ psize[0] = ctx->dec_src_buf_size;
+ allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+ } else {
+ mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+ unsigned int i;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->capture_state == QUEUE_BUFS_MMAPED)
+ return 0;
+ for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+ if (IS_ERR_OR_NULL(ERR_PTR(
+ vb2_dma_contig_plane_dma_addr(vb, i)))) {
+ mfc_err("Plane mem not allocated\n");
+ return -EINVAL;
+ }
+ }
+ if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+ vb2_plane_size(vb, 1) < ctx->chroma_size) {
+ mfc_err("Plane buffer (CAPTURE) is too small\n");
+ return -EINVAL;
+ }
+ i = vb->v4l2_buf.index;
+ ctx->dst_bufs[i].b = vb;
+ ctx->dst_bufs[i].cookie.raw.luma =
+ vb2_dma_contig_plane_dma_addr(vb, 0);
+ ctx->dst_bufs[i].cookie.raw.chroma =
+ vb2_dma_contig_plane_dma_addr(vb, 1);
+ ctx->dst_bufs_cnt++;
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (IS_ERR_OR_NULL(ERR_PTR(
+ vb2_dma_contig_plane_dma_addr(vb, 0)))) {
+ mfc_err("Plane memory not allocated\n");
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
+ mfc_err("Plane buffer (OUTPUT) is too small\n");
+ return -EINVAL;
+ }
+
+ i = vb->v4l2_buf.index;
+ ctx->src_bufs[i].b = vb;
+ ctx->src_bufs[i].cookie.stream =
+ vb2_dma_contig_plane_dma_addr(vb, 0);
+ ctx->src_bufs_cnt++;
+ } else {
+ mfc_err("s5p_mfc_buf_init: unknown queue type\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+ if (ctx->state == MFCINST_FINISHING ||
+ ctx->state == MFCINST_FINISHED)
+ ctx->state = MFCINST_RUNNING;
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+ return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+ unsigned long flags;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int aborted = 0;
+
+ if ((ctx->state == MFCINST_FINISHING ||
+ ctx->state == MFCINST_RUNNING) &&
+ dev->curr_ctx == ctx->num && dev->hw_lock) {
+ ctx->state = MFCINST_ABORT;
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
+ aborted = 1;
+ }
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->dst_queue_cnt = 0;
+ ctx->dpb_flush_flag = 1;
+ ctx->dec_dst_flag = 0;
+ }
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ INIT_LIST_HEAD(&ctx->src_queue);
+ ctx->src_queue_cnt = 0;
+ }
+ if (aborted)
+ ctx->state = MFCINST_RUNNING;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return 0;
+}
+
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+ mfc_buf->used = 0;
+ spin_lock_irqsave(&dev->irqlock, flags);
+ list_add_tail(&mfc_buf->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+ mfc_buf->used = 0;
+ /* Mark destination as available for use by MFC */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag);
+ list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+ ctx->dst_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else {
+ mfc_err("Unsupported buffer type (%d)\n", vq->type);
+ }
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_dec_qops = {
+ .queue_setup = s5p_mfc_queue_setup,
+ .wait_prepare = s5p_mfc_unlock,
+ .wait_finish = s5p_mfc_lock,
+ .buf_init = s5p_mfc_buf_init,
+ .start_streaming = s5p_mfc_start_streaming,
+ .stop_streaming = s5p_mfc_stop_streaming,
+ .buf_queue = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+{
+ return &decoder_codec_ops;
+}
+
+struct vb2_ops *get_dec_queue_ops(void)
+{
+ return &s5p_mfc_dec_qops;
+}
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_dec_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+ && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+ struct v4l2_ctrl_config cfg;
+ int i;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+ if (ctx->ctrl_handler.error) {
+ mfc_err("v4l2_ctrl_handler_init failed\n");
+ return ctx->ctrl_handler.error;
+ }
+
+ for (i = 0; i < NUM_CTRLS; i++) {
+ if (IS_MFC51_PRIV(controls[i].id)) {
+ memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
+ cfg.ops = &s5p_mfc_dec_ctrl_ops;
+ cfg.id = controls[i].id;
+ cfg.min = controls[i].minimum;
+ cfg.max = controls[i].maximum;
+ cfg.def = controls[i].default_value;
+ cfg.name = controls[i].name;
+ cfg.type = controls[i].type;
+
+ cfg.step = controls[i].step;
+ cfg.menu_skip_mask = 0;
+
+ ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &cfg, NULL);
+ } else {
+ ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &s5p_mfc_dec_ctrl_ops,
+ controls[i].id, controls[i].minimum,
+ controls[i].maximum, controls[i].step,
+ controls[i].default_value);
+ }
+ if (ctx->ctrl_handler.error) {
+ mfc_err("Adding control (%d) failed\n", i);
+ return ctx->ctrl_handler.error;
+ }
+ if (controls[i].is_volatile && ctx->ctrls[i])
+ ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ }
+ return 0;
+}
+
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+ int i;
+
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ for (i = 0; i < NUM_CTRLS; i++)
+ ctx->ctrls[i] = NULL;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
new file mode 100644
index 000000000000..fdf1d99a9d15
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_DEC_H_
+#define S5P_MFC_DEC_H_
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+struct vb2_ops *get_dec_queue_ops(void);
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_DEC_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
new file mode 100644
index 000000000000..fdeebb031b45
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -0,0 +1,1834 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Jeongtae Park <jtp.park@samsung.com>
+ * 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/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+
+static struct s5p_mfc_fmt formats[] = {
+ {
+ .name = "4:2:0 2 Planes 64x32 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT,
+ .codec_mode = S5P_FIMV_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = S5P_FIMV_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+ formats[i].type == t)
+ return &formats[i];
+ }
+ return NULL;
+}
+
+static struct mfc_control controls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1900,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 1900,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Padding Control Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Padding Color YUV Value",
+ .minimum = 0,
+ .maximum = (1 << 25) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rate Control Reaction Coeff.",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Force frame type",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+ .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Frame Skip Enable",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .menu_skip_mask = 0,
+ .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Fixed Target Bit Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+ .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The Number of Ref. Pic for P",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 I-Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Minimum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Maximum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 B frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 I-Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Minimum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Maximum QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 B frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 Dark Reg Adaptive RC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 Smooth Reg Adaptive RC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 Static Reg Adaptive RC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 Activity Reg Adaptive RC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+ .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+ .default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+static const char * const *mfc51_get_menu(u32 id)
+{
+ static const char * const mfc51_video_frame_skip[] = {
+ "Disabled",
+ "Level Limit",
+ "VBV/CPB Limit",
+ NULL,
+ };
+ static const char * const mfc51_video_force_frame[] = {
+ "Disabled",
+ "I Frame",
+ "Not Coded",
+ NULL,
+ };
+ switch (id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+ return mfc51_video_frame_skip;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ return mfc51_video_force_frame;
+ }
+ return NULL;
+}
+
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug(2, "src=%d, dst=%d, state=%d\n",
+ ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
+ /* context is ready to make header */
+ if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
+ return 1;
+ /* context is ready to encode a frame */
+ if (ctx->state == MFCINST_RUNNING &&
+ ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ return 1;
+ /* context is ready to encode remain frames */
+ if (ctx->state == MFCINST_FINISHING &&
+ ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ return 1;
+ mfc_debug(2, "ctx is not ready\n");
+ return 0;
+}
+
+static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *mb_entry;
+ unsigned long mb_y_addr, mb_c_addr;
+
+ /* move buffers in ref queue to src queue */
+ while (!list_empty(&ctx->ref_queue)) {
+ mb_entry = list_entry((&ctx->ref_queue)->next,
+ struct s5p_mfc_buf, list);
+ mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+ mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+ list_del(&mb_entry->list);
+ ctx->ref_queue_cnt--;
+ list_add_tail(&mb_entry->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ }
+ mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+ ctx->src_queue_cnt, ctx->ref_queue_cnt);
+ INIT_LIST_HEAD(&ctx->ref_queue);
+ ctx->ref_queue_cnt = 0;
+}
+
+static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned long dst_addr;
+ unsigned int dst_size;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+ dst_size = vb2_plane_size(dst_mb->b, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return 0;
+}
+
+static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned long flags;
+
+ if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
+ spin_lock_irqsave(&dev->irqlock, flags);
+ dst_mb = list_entry(ctx->dst_queue.next,
+ struct s5p_mfc_buf, list);
+ list_del(&dst_mb->list);
+ ctx->dst_queue_cnt--;
+ vb2_set_plane_payload(dst_mb->b, 0,
+ s5p_mfc_get_enc_strm_size());
+ vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ }
+ ctx->state = MFCINST_RUNNING;
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+ return 0;
+}
+
+static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ unsigned long flags;
+ unsigned long src_y_addr, src_c_addr, dst_addr;
+ unsigned int dst_size;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+ src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
+ s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+ dst_size = vb2_plane_size(dst_mb->b, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ return 0;
+}
+
+static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *mb_entry;
+ unsigned long enc_y_addr, enc_c_addr;
+ unsigned long mb_y_addr, mb_c_addr;
+ int slice_type;
+ unsigned int strm_size;
+ unsigned long flags;
+
+ slice_type = s5p_mfc_get_enc_slice_type();
+ strm_size = s5p_mfc_get_enc_strm_size();
+ mfc_debug(2, "Encoded slice type: %d", slice_type);
+ mfc_debug(2, "Encoded stream size: %d", strm_size);
+ mfc_debug(2, "Display order: %d",
+ mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (slice_type >= 0) {
+ s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
+ list_for_each_entry(mb_entry, &ctx->src_queue, list) {
+ mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+ mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+ if ((enc_y_addr == mb_y_addr) &&
+ (enc_c_addr == mb_c_addr)) {
+ list_del(&mb_entry->list);
+ ctx->src_queue_cnt--;
+ vb2_buffer_done(mb_entry->b,
+ VB2_BUF_STATE_DONE);
+ break;
+ }
+ }
+ list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
+ mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
+ mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
+ if ((enc_y_addr == mb_y_addr) &&
+ (enc_c_addr == mb_c_addr)) {
+ list_del(&mb_entry->list);
+ ctx->ref_queue_cnt--;
+ vb2_buffer_done(mb_entry->b,
+ VB2_BUF_STATE_DONE);
+ break;
+ }
+ }
+ }
+ if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+ mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+ list);
+ if (mb_entry->used) {
+ list_del(&mb_entry->list);
+ ctx->src_queue_cnt--;
+ list_add_tail(&mb_entry->list, &ctx->ref_queue);
+ ctx->ref_queue_cnt++;
+ }
+ mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+ ctx->src_queue_cnt, ctx->ref_queue_cnt);
+ }
+ if (strm_size > 0) {
+ /* at least one more dest. buffers exist always */
+ mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
+ list);
+ list_del(&mb_entry->list);
+ ctx->dst_queue_cnt--;
+ switch (slice_type) {
+ case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
+ mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
+ mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
+ mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ }
+ vb2_set_plane_payload(mb_entry->b, 0, strm_size);
+ vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE);
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+ }
+ return 0;
+}
+
+static struct s5p_mfc_codec_ops encoder_codec_ops = {
+ .pre_seq_start = enc_pre_seq_start,
+ .post_seq_start = enc_post_seq_start,
+ .pre_frame_start = enc_pre_frame_start,
+ .post_frame_start = enc_post_frame_start,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ /*
+ * This is only a mem-to-mem video device. The capture and output
+ * device capability flags are left only for backward compatibility
+ * and are scheduled for removal.
+ */
+ cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+ struct s5p_mfc_fmt *fmt;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (mplane && formats[i].num_planes == 1)
+ continue;
+ else if (!mplane && formats[i].num_planes > 1)
+ continue;
+ if (out && formats[i].type != MFC_FMT_RAW)
+ continue;
+ else if (!out && formats[i].type != MFC_FMT_ENC)
+ continue;
+ if (j == f->index) {
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+ }
+ ++j;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, true);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ /* This is run on output (encoder dest) */
+ pix_fmt_mp->width = 0;
+ pix_fmt_mp->height = 0;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* This is run on capture (encoder src) */
+ pix_fmt_mp->width = ctx->img_width;
+ pix_fmt_mp->height = ctx->img_height;
+
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = find_format(f, MFC_FMT_ENC);
+ if (!fmt) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+
+ if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+ mfc_err("must be set encoding output size\n");
+ return -EINVAL;
+ }
+
+ pix_fmt_mp->plane_fmt[0].bytesperline =
+ pix_fmt_mp->plane_fmt[0].sizeimage;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = find_format(f, MFC_FMT_RAW);
+ if (!fmt) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+
+ if (fmt->num_planes != pix_fmt_mp->num_planes) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+ v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
+ &pix_fmt_mp->height, 4, 1080, 1, 0);
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ unsigned long flags;
+ int ret = 0;
+
+ ret = vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+ if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+ v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = find_format(f, MFC_FMT_ENC);
+ if (!fmt) {
+ mfc_err("failed to set capture format\n");
+ return -EINVAL;
+ }
+ ctx->state = MFCINST_INIT;
+ ctx->dst_fmt = fmt;
+ ctx->codec_mode = ctx->dst_fmt->codec_mode;
+ ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+ pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+ ctx->dst_bufs_cnt = 0;
+ ctx->capture_state = QUEUE_FREE;
+ s5p_mfc_alloc_instance_buffer(ctx);
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_try_run(dev);
+ if (s5p_mfc_wait_for_done_ctx(ctx, \
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
+ /* Error or timeout */
+ mfc_err("Error getting instance from hardware\n");
+ s5p_mfc_release_instance_buffer(ctx);
+ ret = -EIO;
+ goto out;
+ }
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = find_format(f, MFC_FMT_RAW);
+ if (!fmt) {
+ mfc_err("failed to set output format\n");
+ return -EINVAL;
+ }
+ if (fmt->num_planes != pix_fmt_mp->num_planes) {
+ mfc_err("failed to set output format\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ctx->src_fmt = fmt;
+ ctx->img_width = pix_fmt_mp->width;
+ ctx->img_height = pix_fmt_mp->height;
+ mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
+ mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
+ pix_fmt_mp->width, pix_fmt_mp->height,
+ ctx->img_width, ctx->img_height);
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+ ctx->buf_width = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12M_HALIGN);
+ ctx->luma_size = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height,
+ S5P_FIMV_NV12M_LVALIGN);
+ ctx->chroma_size = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height
+ >> 1), S5P_FIMV_NV12M_CVALIGN);
+
+ ctx->luma_size = ALIGN(ctx->luma_size,
+ S5P_FIMV_NV12M_SALIGN);
+ ctx->chroma_size = ALIGN(ctx->chroma_size,
+ S5P_FIMV_NV12M_SALIGN);
+
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+ ctx->buf_width = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12MT_HALIGN);
+ ctx->luma_size = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height,
+ S5P_FIMV_NV12MT_VALIGN);
+ ctx->chroma_size = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height
+ >> 1), S5P_FIMV_NV12MT_VALIGN);
+ ctx->luma_size = ALIGN(ctx->luma_size,
+ S5P_FIMV_NV12MT_SALIGN);
+ ctx->chroma_size = ALIGN(ctx->chroma_size,
+ S5P_FIMV_NV12MT_SALIGN);
+
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ }
+ ctx->src_bufs_cnt = 0;
+ ctx->output_state = QUEUE_FREE;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+out:
+ mfc_debug_leave();
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret = 0;
+
+ /* if memory is not mmp or userptr return error */
+ if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
+ (reqbufs->memory != V4L2_MEMORY_USERPTR))
+ return -EINVAL;
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err("invalid capture state: %d\n",
+ ctx->capture_state);
+ return -EINVAL;
+ }
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret != 0) {
+ mfc_err("error in vb2_reqbufs() for E(D)\n");
+ return ret;
+ }
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err("Failed to allocate encoding buffers\n");
+ reqbufs->count = 0;
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err("invalid output state: %d\n",
+ ctx->output_state);
+ return -EINVAL;
+ }
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret != 0) {
+ mfc_err("error in vb2_reqbufs() for E(S)\n");
+ return ret;
+ }
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret = 0;
+
+ /* if memory is not mmp or userptr return error */
+ if ((buf->memory != V4L2_MEMORY_MMAP) &&
+ (buf->memory != V4L2_MEMORY_USERPTR))
+ return -EINVAL;
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->state != MFCINST_GOT_INST) {
+ mfc_err("invalid context state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ if (ret != 0) {
+ mfc_err("error in vb2_querybuf() for E(D)\n");
+ return ret;
+ }
+ buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
+ } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ if (ret != 0) {
+ mfc_err("error in vb2_querybuf() for E(S)\n");
+ return ret;
+ }
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on QBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_qbuf(&ctx->vq_src, buf);
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_qbuf(&ctx->vq_dst, buf);
+ return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on DQBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_streamon(&ctx->vq_src, type);
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_streamon(&ctx->vq_dst, type);
+ return -EINVAL;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_streamoff(&ctx->vq_src, type);
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return vb2_streamoff(&ctx->vq_dst, type);
+ return -EINVAL;
+}
+
+static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
+ };
+ return t[lvl];
+}
+
+static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
+ };
+ return t[lvl];
+}
+
+static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
+ };
+ return t[sar];
+}
+
+static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ p->gop_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ p->slice_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ p->slice_mb = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ p->slice_bit = ctrl->val * 8;
+ break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ p->intra_refresh_mb = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+ p->pad = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+ p->pad_luma = (ctrl->val >> 16) & 0xff;
+ p->pad_cb = (ctrl->val >> 8) & 0xff;
+ p->pad_cr = (ctrl->val >> 0) & 0xff;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ p->rc_frame = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ p->rc_bitrate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+ p->rc_reaction_coeff = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ ctx->force_frame_type = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+ p->vbv_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+ p->codec.h264.cpb_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ p->seq_hdr_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+ p->frame_skip_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
+ p->fixed_target_bit = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ p->num_b_frame = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_HIGH;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_BASELINE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ p->codec.h264.level_v4l2 = ctrl->val;
+ p->codec.h264.level = h264_level(ctrl->val);
+ if (p->codec.h264.level < 0) {
+ mfc_err("Level number is wrong\n");
+ ret = p->codec.h264.level;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ p->codec.mpeg4.level_v4l2 = ctrl->val;
+ p->codec.mpeg4.level = mpeg4_level(ctrl->val);
+ if (p->codec.mpeg4.level < 0) {
+ mfc_err("Level number is wrong\n");
+ ret = p->codec.mpeg4.level;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ p->codec.h264.loop_filter_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ p->codec.h264.loop_filter_alpha = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ p->codec.h264.loop_filter_beta = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ p->codec.h264.entropy_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+ p->codec.h264.num_ref_pic_4p = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ p->codec.h264._8x8_transform = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ p->codec.h264.rc_mb = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ p->codec.h264.rc_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ p->codec.h264.rc_min_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ p->codec.h264.rc_max_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ p->codec.h264.rc_p_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ p->codec.h264.rc_b_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+ p->codec.mpeg4.rc_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+ p->codec.mpeg4.rc_min_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+ p->codec.mpeg4.rc_max_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+ p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+ p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+ p->codec.h264.rc_mb_dark = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+ p->codec.h264.rc_mb_smooth = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+ p->codec.h264.rc_mb_static = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+ p->codec.h264.rc_mb_activity = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+ p->codec.h264.vui_sar = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+ p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+ p->codec.h264.vui_ext_sar_width = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+ p->codec.h264.vui_ext_sar_height = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ p->codec.h264.open_gop = !ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ p->codec.h264.open_gop_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ p->codec.mpeg4.quarter_pixel = ctrl->val;
+ break;
+ default:
+ v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
+ ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
+ .s_ctrl = s5p_mfc_enc_s_ctrl,
+};
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ctx->enc_params.rc_framerate_num =
+ a->parm.output.timeperframe.denominator;
+ ctx->enc_params.rc_framerate_denom =
+ a->parm.output.timeperframe.numerator;
+ } else {
+ mfc_err("Setting FPS is only possible for the output queue\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ a->parm.output.timeperframe.denominator =
+ ctx->enc_params.rc_framerate_num;
+ a->parm.output.timeperframe.numerator =
+ ctx->enc_params.rc_framerate_denom;
+ } else {
+ mfc_err("Setting FPS is only possible for the output queue\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = 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_s_parm = vidioc_s_parm,
+ .vidioc_g_parm = vidioc_g_parm,
+};
+
+static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+ int i;
+
+ if (!fmt)
+ return -EINVAL;
+ if (fmt->num_planes != vb->num_planes) {
+ mfc_err("invalid plane number for the format\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < fmt->num_planes; i++) {
+ if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
+ mfc_err("failed to get plane cookie\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
+ vb->v4l2_buf.index, i,
+ vb2_dma_contig_plane_dma_addr(vb, i));
+ }
+ return 0;
+}
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *buf_count, unsigned int *plane_count,
+ unsigned int psize[], void *allocators[])
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+ if (ctx->state != MFCINST_GOT_INST) {
+ mfc_err("inavlid state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->dst_fmt)
+ *plane_count = ctx->dst_fmt->num_planes;
+ else
+ *plane_count = MFC_ENC_CAP_PLANE_COUNT;
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ psize[0] = ctx->enc_dst_buf_size;
+ allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->src_fmt)
+ *plane_count = ctx->src_fmt->num_planes;
+ else
+ *plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ psize[0] = ctx->luma_size;
+ psize[1] = ctx->chroma_size;
+ allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+ allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+ } else {
+ mfc_err("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+ unsigned int i;
+ int ret;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+ i = vb->v4l2_buf.index;
+ ctx->dst_bufs[i].b = vb;
+ ctx->dst_bufs[i].cookie.stream =
+ vb2_dma_contig_plane_dma_addr(vb, 0);
+ ctx->dst_bufs_cnt++;
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+ i = vb->v4l2_buf.index;
+ ctx->src_bufs[i].b = vb;
+ ctx->src_bufs[i].cookie.raw.luma =
+ vb2_dma_contig_plane_dma_addr(vb, 0);
+ ctx->src_bufs[i].cookie.raw.chroma =
+ vb2_dma_contig_plane_dma_addr(vb, 1);
+ ctx->src_bufs_cnt++;
+ } else {
+ mfc_err("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+ int ret;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+ mfc_debug(2, "plane size: %ld, dst size: %d\n",
+ vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
+ if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
+ mfc_err("plane size is too small for capture\n");
+ return -EINVAL;
+ }
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+ mfc_debug(2, "plane size: %ld, luma size: %d\n",
+ vb2_plane_size(vb, 0), ctx->luma_size);
+ mfc_debug(2, "plane size: %ld, chroma size: %d\n",
+ vb2_plane_size(vb, 1), ctx->chroma_size);
+ if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+ vb2_plane_size(vb, 1) < ctx->chroma_size) {
+ mfc_err("plane size is too small for output\n");
+ return -EINVAL;
+ }
+ } else {
+ mfc_err("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+ return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+ unsigned long flags;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ if ((ctx->state == MFCINST_FINISHING ||
+ ctx->state == MFCINST_RUNNING) &&
+ dev->curr_ctx == ctx->num && dev->hw_lock) {
+ ctx->state = MFCINST_ABORT;
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET,
+ 0);
+ }
+ ctx->state = MFCINST_FINISHED;
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->dst_queue_cnt = 0;
+ }
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ cleanup_ref_queue(ctx);
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ INIT_LIST_HEAD(&ctx->src_queue);
+ ctx->src_queue_cnt = 0;
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return 0;
+}
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf;
+
+ if (ctx->state == MFCINST_ERROR) {
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ cleanup_ref_queue(ctx);
+ return;
+ }
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+ mfc_buf->used = 0;
+ /* Mark destination as available for use by MFC */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+ ctx->dst_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+ mfc_buf->used = 0;
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (vb->v4l2_planes[0].bytesused == 0) {
+ mfc_debug(1, "change state to FINISHING\n");
+ ctx->state = MFCINST_FINISHING;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ cleanup_ref_queue(ctx);
+ } else {
+ list_add_tail(&mfc_buf->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else {
+ mfc_err("unsupported buffer type (%d)\n", vq->type);
+ }
+ if (s5p_mfc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_enc_qops = {
+ .queue_setup = s5p_mfc_queue_setup,
+ .wait_prepare = s5p_mfc_unlock,
+ .wait_finish = s5p_mfc_lock,
+ .buf_init = s5p_mfc_buf_init,
+ .buf_prepare = s5p_mfc_buf_prepare,
+ .start_streaming = s5p_mfc_start_streaming,
+ .stop_streaming = s5p_mfc_stop_streaming,
+ .buf_queue = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+{
+ return &encoder_codec_ops;
+}
+
+struct vb2_ops *get_enc_queue_ops(void)
+{
+ return &s5p_mfc_enc_qops;
+}
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_enc_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+ && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+ struct v4l2_ctrl_config cfg;
+ int i;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+ if (ctx->ctrl_handler.error) {
+ mfc_err("v4l2_ctrl_handler_init failed\n");
+ return ctx->ctrl_handler.error;
+ }
+ for (i = 0; i < NUM_CTRLS; i++) {
+ if (IS_MFC51_PRIV(controls[i].id)) {
+ memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
+ cfg.ops = &s5p_mfc_enc_ctrl_ops;
+ cfg.id = controls[i].id;
+ cfg.min = controls[i].minimum;
+ cfg.max = controls[i].maximum;
+ cfg.def = controls[i].default_value;
+ cfg.name = controls[i].name;
+ cfg.type = controls[i].type;
+ cfg.flags = 0;
+
+ if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+ cfg.step = 0;
+ cfg.menu_skip_mask = cfg.menu_skip_mask;
+ cfg.qmenu = mfc51_get_menu(cfg.id);
+ } else {
+ cfg.step = controls[i].step;
+ cfg.menu_skip_mask = 0;
+ }
+ ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &cfg, NULL);
+ } else {
+ if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
+ ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
+ &ctx->ctrl_handler,
+ &s5p_mfc_enc_ctrl_ops, controls[i].id,
+ controls[i].maximum, 0,
+ controls[i].default_value);
+ } else {
+ ctx->ctrls[i] = v4l2_ctrl_new_std(
+ &ctx->ctrl_handler,
+ &s5p_mfc_enc_ctrl_ops, controls[i].id,
+ controls[i].minimum,
+ controls[i].maximum, controls[i].step,
+ controls[i].default_value);
+ }
+ }
+ if (ctx->ctrl_handler.error) {
+ mfc_err("Adding control (%d) failed\n", i);
+ return ctx->ctrl_handler.error;
+ }
+ if (controls[i].is_volatile && ctx->ctrls[i])
+ ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ }
+ return 0;
+}
+
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+ int i;
+
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ for (i = 0; i < NUM_CTRLS; i++)
+ ctx->ctrls[i] = NULL;
+}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
new file mode 100644
index 000000000000..ca9fd66bd310
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_ENC_H_
+#define S5P_MFC_ENC_H_
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+struct vb2_ops *get_enc_queue_ops(void);
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_ENC_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
new file mode 100644
index 000000000000..37860e299021
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
@@ -0,0 +1,92 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains functions used to wait for command completion.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+ int ret;
+
+ ret = wait_event_interruptible_timeout(dev->queue,
+ (dev->int_cond && (dev->int_type == command
+ || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ if (ret == 0) {
+ mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n",
+ dev->int_type, command);
+ return 1;
+ } else if (ret == -ERESTARTSYS) {
+ mfc_err("Interrupted by a signal\n");
+ return 1;
+ }
+ mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n",
+ dev->int_type, command);
+ if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+ return 1;
+ return 0;
+}
+
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+ dev->int_cond = 0;
+ dev->int_type = 0;
+ dev->int_err = 0;
+}
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+ int command, int interrupt)
+{
+ int ret;
+
+ if (interrupt) {
+ ret = wait_event_interruptible_timeout(ctx->queue,
+ (ctx->int_cond && (ctx->int_type == command
+ || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ } else {
+ ret = wait_event_timeout(ctx->queue,
+ (ctx->int_cond && (ctx->int_type == command
+ || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ }
+ if (ret == 0) {
+ mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
+ ctx->int_type, command);
+ return 1;
+ } else if (ret == -ERESTARTSYS) {
+ mfc_err("Interrupted by a signal\n");
+ return 1;
+ }
+ mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
+ ctx->int_type, command);
+ if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+ return 1;
+ return 0;
+}
+
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+ ctx->int_cond = 0;
+ ctx->int_type = 0;
+ ctx->int_err = 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
new file mode 100644
index 000000000000..18341a88514e
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * It contains waiting functions declarations.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.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 S5P_MFC_INTR_H_
+#define S5P_MFC_INTR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+ int command, int interrupt);
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_INTR_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
new file mode 100644
index 000000000000..b5fd3d4d5a7b
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -0,0 +1,1397 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.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 "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT)
+#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+ void *desc_virt;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ ctx->desc_buf = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
+ if (IS_ERR_VALUE((int)ctx->desc_buf)) {
+ ctx->desc_buf = NULL;
+ mfc_err("Allocating DESC buffer failed\n");
+ return -ENOMEM;
+ }
+ ctx->desc_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf);
+ BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf);
+ if (desc_virt == NULL) {
+ vb2_dma_contig_memops.put(ctx->desc_buf);
+ ctx->desc_phys = 0;
+ ctx->desc_buf = NULL;
+ mfc_err("Remapping DESC buffer failed\n");
+ return -ENOMEM;
+ }
+ memset(desc_virt, 0, DESC_BUF_SIZE);
+ wmb();
+ return 0;
+}
+
+/* Release temporary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->desc_phys) {
+ vb2_dma_contig_memops.put(ctx->desc_buf);
+ ctx->desc_phys = 0;
+ ctx->desc_buf = NULL;
+ }
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int enc_ref_y_size = 0;
+ unsigned int enc_ref_c_size = 0;
+ unsigned int guard_width, guard_height;
+
+ if (ctx->type == MFCINST_DECODER) {
+ mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+ ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+ mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+ enc_ref_c_size = ALIGN(ctx->img_width,
+ S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height >> 1,
+ S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(enc_ref_c_size,
+ S5P_FIMV_NV12MT_SALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 16,
+ S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4,
+ S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_NV12MT_SALIGN);
+ }
+ mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+ enc_ref_y_size, enc_ref_c_size);
+ } else {
+ return -EINVAL;
+ }
+ /* Codecs have different memory requirements */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ ctx->bank1_size =
+ ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
+ S5P_FIMV_DEC_VERT_NB_MV_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ ctx->bank1_size =
+ ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_STX_PARSER_SIZE +
+ S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->bank2_size = 0;
+ break;
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ ctx->bank1_size =
+ ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_NB_DCAC_SIZE +
+ 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->bank2_size = 0;
+ break;
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ ctx->bank1_size = 0;
+ ctx->bank2_size = 0;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ ctx->bank1_size =
+ ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_NB_DCAC_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->bank2_size = 0;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ ctx->bank1_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_COLFLG_SIZE +
+ S5P_FIMV_ENC_INTRAMD_SIZE +
+ S5P_FIMV_ENC_NBORINFO_SIZE;
+ ctx->bank2_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4) +
+ S5P_FIMV_ENC_INTRAPRED_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ ctx->bank1_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_COLFLG_SIZE +
+ S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ ctx->bank2_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4);
+ break;
+ case S5P_FIMV_CODEC_H263_ENC:
+ ctx->bank1_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ ctx->bank2_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4);
+ break;
+ default:
+ break;
+ }
+ /* Allocate only if memory from bank 1 is necessary */
+ if (ctx->bank1_size > 0) {
+ ctx->bank1_buf = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
+ if (IS_ERR(ctx->bank1_buf)) {
+ ctx->bank1_buf = NULL;
+ printk(KERN_ERR
+ "Buf alloc for decoding failed (port A)\n");
+ return -ENOMEM;
+ }
+ ctx->bank1_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
+ BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ }
+ /* Allocate only if memory from bank 2 is necessary */
+ if (ctx->bank2_size > 0) {
+ ctx->bank2_buf = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
+ if (IS_ERR(ctx->bank2_buf)) {
+ ctx->bank2_buf = NULL;
+ mfc_err("Buf alloc for decoding failed (port B)\n");
+ return -ENOMEM;
+ }
+ ctx->bank2_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
+ BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
+ }
+ return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->bank1_buf) {
+ vb2_dma_contig_memops.put(ctx->bank1_buf);
+ ctx->bank1_buf = NULL;
+ ctx->bank1_phys = 0;
+ ctx->bank1_size = 0;
+ }
+ if (ctx->bank2_buf) {
+ vb2_dma_contig_memops.put(ctx->bank2_buf);
+ ctx->bank2_buf = NULL;
+ ctx->bank2_phys = 0;
+ ctx->bank2_size = 0;
+ }
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ void *context_virt;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+ ctx->ctx_size = MFC_H264_CTX_BUF_SIZE;
+ else
+ ctx->ctx_size = MFC_CTX_BUF_SIZE;
+ ctx->ctx_buf = vb2_dma_contig_memops.alloc(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size);
+ if (IS_ERR(ctx->ctx_buf)) {
+ mfc_err("Allocating context buffer failed\n");
+ ctx->ctx_phys = 0;
+ ctx->ctx_buf = NULL;
+ return -ENOMEM;
+ }
+ ctx->ctx_phys = s5p_mfc_mem_cookie(
+ dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf);
+ BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ ctx->ctx_ofs = OFFSETA(ctx->ctx_phys);
+ context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf);
+ if (context_virt == NULL) {
+ mfc_err("Remapping instance buffer failed\n");
+ vb2_dma_contig_memops.put(ctx->ctx_buf);
+ ctx->ctx_phys = 0;
+ ctx->ctx_buf = NULL;
+ return -ENOMEM;
+ }
+ /* Zero content of the allocated memory */
+ memset(context_virt, 0, ctx->ctx_size);
+ wmb();
+ if (s5p_mfc_init_shm(ctx) < 0) {
+ vb2_dma_contig_memops.put(ctx->ctx_buf);
+ ctx->ctx_phys = 0;
+ ctx->ctx_buf = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->ctx_buf) {
+ vb2_dma_contig_memops.put(ctx->ctx_buf);
+ ctx->ctx_phys = 0;
+ ctx->ctx_buf = NULL;
+ }
+ if (ctx->shm_alloc) {
+ vb2_dma_contig_memops.put(ctx->shm_alloc);
+ ctx->shm_alloc = NULL;
+ ctx->shm = NULL;
+ }
+}
+
+/* Set registers for decoding temporary buffers */
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR);
+ mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE);
+}
+
+/* Set registers for shared buffer */
+static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+ unsigned int start_num_byte, unsigned int buf_size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
+ mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE);
+ mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
+ s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM);
+ return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+ unsigned int frame_size, i;
+ unsigned int frame_size_ch, frame_size_mv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int dpb;
+ size_t buf_addr1, buf_addr2;
+ int buf_size1, buf_size2;
+
+ buf_addr1 = ctx->bank1_phys;
+ buf_size1 = ctx->bank1_size;
+ buf_addr2 = ctx->bank2_phys;
+ buf_size2 = ctx->bank2_size;
+ dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+ ~S5P_FIMV_DPB_COUNT_MASK;
+ mfc_write(dev, ctx->total_dpb_count | dpb,
+ S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+ s5p_mfc_set_shared_buffer(ctx);
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_H264_VERT_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
+ buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ break;
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ break;
+ default:
+ mfc_err("Unknown codec for decoding (%x)\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ break;
+ }
+ frame_size = ctx->luma_size;
+ frame_size_ch = ctx->chroma_size;
+ frame_size_mv = ctx->mv_size;
+ mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+ frame_size_mv);
+ for (i = 0; i < ctx->total_dpb_count; i++) {
+ /* Bank2 */
+ mfc_debug(2, "Luma %d: %x\n", i,
+ ctx->dst_bufs[i].cookie.raw.luma);
+ mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
+ S5P_FIMV_DEC_LUMA_ADR + i * 4);
+ mfc_debug(2, "\tChroma %d: %x\n", i,
+ ctx->dst_bufs[i].cookie.raw.chroma);
+ mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
+ S5P_FIMV_DEC_CHROMA_ADR + i * 4);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+ mfc_debug(2, "\tBuf2: %x, size: %d\n",
+ buf_addr2, buf_size2);
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_H264_MV_ADR + i * 4);
+ buf_addr2 += frame_size_mv;
+ buf_size2 -= frame_size_mv;
+ }
+ }
+ mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+ mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
+ buf_size1, buf_size2, ctx->total_dpb_count);
+ if (buf_size1 < 0 || buf_size2 < 0) {
+ mfc_debug(2, "Not enough memory has been allocated\n");
+ return -ENOMEM;
+ }
+ s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+ s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+ s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE);
+ mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK)
+ << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+ S5P_FIMV_SI_CH0_INST_ID);
+ return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long addr, unsigned int size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
+ mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
+ return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long y_addr, unsigned long c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
+ mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long *y_addr, unsigned long *c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR)
+ << MFC_OFFSET_SHIFT);
+ *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR)
+ << MFC_OFFSET_SHIFT);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ size_t buf_addr1, buf_addr2;
+ size_t buf_size1, buf_size2;
+ unsigned int enc_ref_y_size, enc_ref_c_size;
+ unsigned int guard_width, guard_height;
+ int i;
+
+ buf_addr1 = ctx->bank1_phys;
+ buf_size1 = ctx->bank1_size;
+ buf_addr2 = ctx->bank2_phys;
+ buf_size2 = ctx->bank2_size;
+ enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+ enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 16,
+ S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4,
+ S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_NV12MT_SALIGN);
+ }
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_ENC:
+ for (i = 0; i < 2; i++) {
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+ for (i = 0; i < 4; i++) {
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_H264_COZERO_FLAG_ADR);
+ buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_H264_UP_INTRA_MD_ADR);
+ buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_H264_UP_INTRA_PRED_ADR);
+ buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
+ buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_H264_NBOR_INFO_ADR);
+ buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ for (i = 0; i < 2; i++) {
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+ for (i = 0; i < 4; i++) {
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
+ buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_MPEG4_ACDC_COEF_ADR);
+ buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+ case S5P_FIMV_CODEC_H263_ENC:
+ for (i = 0; i < 2; i++) {
+ mfc_write(dev, OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+ for (i = 0; i < 4; i++) {
+ mfc_write(dev, OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+ mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
+ buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+ default:
+ mfc_err("Unknown codec set for encoding: %d\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ unsigned int reg;
+ unsigned int shm;
+
+ /* width */
+ mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
+ /* height */
+ mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
+ /* pictype : enable, IDR period */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ reg |= (1 << 18);
+ reg &= ~(0xFFFF);
+ reg |= p->gop_size;
+ mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
+ /* multi-slice control */
+ /* multi-slice MB number or bit size */
+ mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
+ } else {
+ mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
+ mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT);
+ }
+ /* cyclic intra refresh */
+ mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
+ /* memory structure cur. frame */
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+ else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+ mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+ /* padding control & value */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
+ if (p->pad) {
+ /** enable */
+ reg |= (1 << 31);
+ /** cr value */
+ reg &= ~(0xFF << 16);
+ reg |= (p->pad_cr << 16);
+ /** cb value */
+ reg &= ~(0xFF << 8);
+ reg |= (p->pad_cb << 8);
+ /** y value */
+ reg &= ~(0xFF);
+ reg |= (p->pad_luma);
+ } else {
+ /** disable & all value clear */
+ reg = 0;
+ }
+ mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL);
+ /* rate control config. */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+ /** frame-level rate control */
+ reg &= ~(0x1 << 9);
+ reg |= (p->rc_frame << 9);
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+ /* bit rate */
+ if (p->rc_frame)
+ mfc_write(dev, p->rc_bitrate,
+ S5P_FIMV_ENC_RC_BIT_RATE);
+ else
+ mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
+ /* reaction coefficient */
+ if (p->rc_frame)
+ mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
+ shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+ /* seq header ctrl */
+ shm &= ~(0x1 << 3);
+ shm |= (p->seq_hdr_mode << 3);
+ /* frame skip mode */
+ shm &= ~(0x3 << 1);
+ shm |= (p->frame_skip_mode << 1);
+ s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+ /* fixed target bit */
+ s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ unsigned int reg;
+ unsigned int shm;
+
+ s5p_mfc_set_enc_params(ctx);
+ /* pictype : number of B */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /* num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /* profile & level */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+ /* level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_264->level << 8);
+ /* profile - 0 ~ 2 */
+ reg &= ~(0x3F);
+ reg |= p_264->profile;
+ mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+ /* interlace */
+ mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT);
+ /* height */
+ if (p->interlace)
+ mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
+ /* loopfilter ctrl */
+ mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
+ /* loopfilter alpha offset */
+ if (p_264->loop_filter_alpha < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_alpha & 0xF);
+ }
+ mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF);
+ /* loopfilter beta offset */
+ if (p_264->loop_filter_beta < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_beta) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_beta & 0xF);
+ }
+ mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF);
+ /* entropy coding mode */
+ if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+ mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+ else
+ mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+ /* number of ref. picture */
+ reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF);
+ /* num of ref. pictures of P */
+ reg &= ~(0x3 << 5);
+ reg |= (p_264->num_ref_pic_4p << 5);
+ /* max number of ref. pictures */
+ reg &= ~(0x1F);
+ reg |= p_264->max_ref_pic;
+ mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
+ /* 8x8 transform enable */
+ mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
+ /* rate control config. */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+ /* macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p_264->rc_mb << 8);
+ /* frame QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_frame_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+ /* frame rate */
+ if (p->rc_frame && p->rc_framerate_denom)
+ mfc_write(dev, p->rc_framerate_num * 1000
+ / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+ else
+ mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+ /* max & min value of QP */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+ /* max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_264->rc_max_qp << 8);
+ /* min QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_min_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+ /* macroblock adaptive scaling features */
+ if (p_264->rc_mb) {
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL);
+ /* dark region */
+ reg &= ~(0x1 << 3);
+ reg |= (p_264->rc_mb_dark << 3);
+ /* smooth region */
+ reg &= ~(0x1 << 2);
+ reg |= (p_264->rc_mb_smooth << 2);
+ /* static region */
+ reg &= ~(0x1 << 1);
+ reg |= (p_264->rc_mb_static << 1);
+ /* high activity region */
+ reg &= ~(0x1);
+ reg |= p_264->rc_mb_activity;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL);
+ }
+ if (!p->rc_frame &&
+ !p_264->rc_mb) {
+ shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
+ shm |= (p_264->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+ }
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+ /* AR VUI control */
+ shm &= ~(0x1 << 15);
+ shm |= (p_264->vui_sar << 1);
+ s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+ if (p_264->vui_sar) {
+ /* aspect ration IDC */
+ shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC);
+ shm &= ~(0xFF);
+ shm |= p_264->vui_sar_idc;
+ s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC);
+ if (p_264->vui_sar_idc == 0xFF) {
+ /* sample AR info */
+ shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR);
+ shm &= ~(0xFFFFFFFF);
+ shm |= p_264->vui_ext_sar_width << 16;
+ shm |= p_264->vui_ext_sar_height;
+ s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR);
+ }
+ }
+ /* intra picture period for H.264 */
+ shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD);
+ /* control */
+ shm &= ~(0x1 << 16);
+ shm |= (p_264->open_gop << 16);
+ /* value */
+ if (p_264->open_gop) {
+ shm &= ~(0xFFFF);
+ shm |= p_264->open_gop_size;
+ }
+ s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD);
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+ /* vbv buffer size */
+ if (p->frame_skip_mode ==
+ V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+ shm &= ~(0xFFFF << 16);
+ shm |= (p_264->cpb_size << 16);
+ }
+ s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg;
+ unsigned int shm;
+ unsigned int framerate;
+
+ s5p_mfc_set_enc_params(ctx);
+ /* pictype : number of B */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /* num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /* profile & level */
+ reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+ /* level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_mpeg4->level << 8);
+ /* profile - 0 ~ 2 */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->profile;
+ mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+ /* quarter_pixel */
+ mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
+ /* qp */
+ if (!p->rc_frame) {
+ shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
+ shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+ }
+ /* frame rate */
+ if (p->rc_frame) {
+ if (p->rc_framerate_denom > 0) {
+ framerate = p->rc_framerate_num * 1000 /
+ p->rc_framerate_denom;
+ mfc_write(dev, framerate,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
+ shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING);
+ shm &= ~(0xFFFFFFFF);
+ shm |= (1 << 31);
+ shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
+ shm |= (p->rc_framerate_denom & 0xFFFF);
+ s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING);
+ }
+ } else {
+ mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+ }
+ /* rate control config. */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+ /* frame QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_frame_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+ /* max & min value of QP */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+ /* max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_mpeg4->rc_max_qp << 8);
+ /* min QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_min_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+ /* vbv buffer size */
+ if (p->frame_skip_mode ==
+ V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+ shm &= ~(0xFFFF << 16);
+ shm |= (p->vbv_size << 16);
+ }
+ s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
+ unsigned int reg;
+ unsigned int shm;
+
+ s5p_mfc_set_enc_params(ctx);
+ /* qp */
+ if (!p->rc_frame) {
+ shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= (p_h263->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+ }
+ /* frame rate */
+ if (p->rc_frame && p->rc_framerate_denom)
+ mfc_write(dev, p->rc_framerate_num * 1000
+ / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+ else
+ mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+ /* rate control config. */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+ /* frame QP */
+ reg &= ~(0x3F);
+ reg |= p_h263->rc_frame_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+ /* max & min value of QP */
+ reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+ /* max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_h263->rc_max_qp << 8);
+ /* min QP */
+ reg &= ~(0x3F);
+ reg |= p_h263->rc_min_qp;
+ mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+ /* vbv buffer size */
+ if (p->frame_skip_mode ==
+ V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+ shm &= ~(0xFFFF << 16);
+ shm |= (p->vbv_size << 16);
+ }
+ s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+ return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ s5p_mfc_set_shared_buffer(ctx);
+ /* Setup loop filter, for decoding this is only valid for MPEG4 */
+ if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
+ mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
+ else
+ mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL);
+ mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) <<
+ S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable <<
+ S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay &
+ S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
+ S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+ mfc_write(dev,
+ ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
+ | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ return 0;
+}
+
+static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int dpb;
+
+ if (flush)
+ dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (
+ S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+ else
+ dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+ ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+ mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_decode_arg last_frame)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF);
+ s5p_mfc_set_shared_buffer(ctx);
+ s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
+ /* Issue different commands to instance basing on whether it
+ * is the last frame or not. */
+ switch (last_frame) {
+ case MFC_DEC_FRAME:
+ mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
+ S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ case MFC_DEC_LAST_FRAME:
+ mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
+ S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ case MFC_DEC_RES_CHANGE:
+ mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC &
+ S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+ S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ }
+ mfc_debug(2, "Decoding a usual frame\n");
+ return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+ s5p_mfc_set_enc_params_h264(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+ s5p_mfc_set_enc_params_mpeg4(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+ s5p_mfc_set_enc_params_h263(ctx);
+ else {
+ mfc_err("Unknown codec for encoding (%x)\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+ s5p_mfc_set_shared_buffer(ctx);
+ mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) |
+ (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ /* memory structure cur. frame */
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+ else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+ mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+ s5p_mfc_set_shared_buffer(ctx);
+ mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) |
+ (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ return 0;
+}
+
+static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+ unsigned long flags;
+ int new_ctx;
+ int cnt;
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+ cnt = 0;
+ while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+ new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+ if (++cnt > MFC_NUM_CONTEXTS) {
+ /* No contexts to run */
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ return -EAGAIN;
+ }
+ }
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ return new_ctx;
+}
+
+static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE);
+}
+
+static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *temp_vb;
+ unsigned long flags;
+ unsigned int index;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ /* Frames are being decoded */
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "No src buffers\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ /* Get the next source buffer */
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ temp_vb->used = 1;
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream,
+ temp_vb->b->v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ index = temp_vb->b->v4l2_buf.index;
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
+ last_frame = MFC_DEC_LAST_FRAME;
+ mfc_debug(2, "Setting ctx->state to FINISHING\n");
+ ctx->state = MFCINST_FINISHING;
+ }
+ s5p_mfc_decode_one_frame(ctx, last_frame);
+ return 0;
+}
+
+static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ unsigned long src_y_addr, src_c_addr, dst_addr;
+ unsigned int dst_size;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "no src buffers\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ if (list_empty(&ctx->dst_queue)) {
+ mfc_debug(2, "no dst buffers\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ src_mb->used = 1;
+ src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
+ src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
+ s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_mb->used = 1;
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+ dst_size = vb2_plane_size(dst_mb->b, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx);
+ return 0;
+}
+
+static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *temp_vb;
+
+ /* Initializing decoding - parsing header */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ mfc_debug(2, "Preparing to init decoding\n");
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
+ 0, temp_vb->b->v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_decode(ctx);
+}
+
+static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned long dst_addr;
+ unsigned int dst_size;
+
+ s5p_mfc_set_enc_ref_buffer(ctx);
+ spin_lock_irqsave(&dev->irqlock, flags);
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
+ dst_size = vb2_plane_size(dst_mb->b, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_encode(ctx);
+}
+
+static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *temp_vb;
+ int ret;
+
+ /*
+ * Header was parsed now starting processing
+ * First set the output frame buffers
+ */
+ if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+ mfc_err("It seems that not all destionation buffers were "
+ "mmaped\nMFC requires that all destination are mmaped "
+ "before starting processing\n");
+ return -EAGAIN;
+ }
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (list_empty(&ctx->src_queue)) {
+ mfc_err("Header has been deallocated in the middle of"
+ " initialization\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EIO;
+ }
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
+ 0, temp_vb->b->v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_dec_frame_buffer(ctx);
+ if (ret) {
+ mfc_err("Failed to alloc frame mem\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+ int new_ctx;
+ unsigned int ret = 0;
+
+ if (test_bit(0, &dev->enter_suspend)) {
+ mfc_debug(1, "Entering suspend so do not schedule any jobs\n");
+ return;
+ }
+ /* Check whether hardware is not running */
+ if (test_and_set_bit(0, &dev->hw_lock) != 0) {
+ /* This is perfectly ok, the scheduled ctx should wait */
+ mfc_debug(1, "Couldn't lock HW\n");
+ return;
+ }
+ /* Choose the context to run */
+ new_ctx = s5p_mfc_get_new_ctx(dev);
+ if (new_ctx < 0) {
+ /* No contexts to run */
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
+ mfc_err("Failed to unlock hardware\n");
+ return;
+ }
+ mfc_debug(1, "No ctx is scheduled to be run\n");
+ return;
+ }
+ ctx = dev->ctx[new_ctx];
+ /* Got context to run in ctx */
+ /*
+ * Last frame has already been sent to MFC.
+ * Now obtaining frames from MFC buffer
+ */
+ s5p_mfc_clock_on();
+ if (ctx->type == MFCINST_DECODER) {
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME);
+ break;
+ case MFCINST_RUNNING:
+ ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+ break;
+ case MFCINST_INIT:
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_open_inst_cmd(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_close_inst_cmd(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ case MFCINST_HEAD_PARSED:
+ ret = s5p_mfc_run_init_dec_buffers(ctx);
+ mfc_debug(1, "head parsed\n");
+ break;
+ case MFCINST_RES_CHANGE_INIT:
+ s5p_mfc_run_res_change(ctx);
+ break;
+ case MFCINST_RES_CHANGE_FLUSH:
+ s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+ break;
+ case MFCINST_RES_CHANGE_END:
+ mfc_debug(2, "Finished remaining frames after resolution change\n");
+ ctx->capture_state = QUEUE_FREE;
+ mfc_debug(2, "Will re-init the codec\n");
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else if (ctx->type == MFCINST_ENCODER) {
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ case MFCINST_RUNNING:
+ ret = s5p_mfc_run_enc_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_open_inst_cmd(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_close_inst_cmd(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ s5p_mfc_run_init_enc(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else {
+ mfc_err("Invalid context type: %d\n", ctx->type);
+ ret = -EAGAIN;
+ }
+
+ if (ret) {
+ /* Free hardware lock */
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ mfc_err("Failed to unlock hardware\n");
+
+ /* This is in deed imporant, as no operation has been
+ * scheduled, reduce the clock count as no one will
+ * ever do this, because no interrupt related to this try_run
+ * will ever come from hardware. */
+ s5p_mfc_clock_off();
+ }
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+ struct s5p_mfc_buf *b;
+ int i;
+
+ while (!list_empty(lh)) {
+ b = list_entry(lh->next, struct s5p_mfc_buf, list);
+ for (i = 0; i < b->b->num_planes; i++)
+ vb2_set_plane_payload(b->b, i, 0);
+ vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR);
+ list_del(&b->list);
+ }
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
new file mode 100644
index 000000000000..2ad3def052f8
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -0,0 +1,93 @@
+/*
+ * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.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 S5P_MFC_OPR_H_
+#define S5P_MFC_OPR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Decoding functions */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+ unsigned int start_num_byte,
+ unsigned int buf_size);
+
+/* Encoding functions */
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long y_addr, unsigned long c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ unsigned long *y_addr, unsigned long *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_decode_arg last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \
+ S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+ MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \
+ S5P_FIMV_SI_DECODE_Y_ADR) << \
+ MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \
+ S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_dec_status() readl(dev->regs_base + \
+ S5P_FIMV_SI_DECODE_STATUS)
+#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \
+ S5P_FIMV_DECODE_FRAME_TYPE) \
+ & S5P_FIMV_DECODE_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \
+ S5P_FIMV_SI_CONSUMED_BYTES)
+#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_CMD) & \
+ S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err() readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_ARG2)
+#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+ S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+ S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width() readl(dev->regs_base + \
+ S5P_FIMV_SI_HRESOL)
+#define s5p_mfc_get_img_height() readl(dev->regs_base + \
+ S5P_FIMV_SI_VRESOL)
+#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \
+ S5P_FIMV_SI_BUF_NUMBER)
+#define s5p_mfc_get_inst_no() readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_ARG1)
+#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \
+ S5P_FIMV_ENC_SI_STRM_SIZE)
+#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \
+ S5P_FIMV_ENC_SI_SLICE_TYPE)
+
+#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
new file mode 100644
index 000000000000..0503d14ac94e
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -0,0 +1,137 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.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/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_pm.h"
+
+#define MFC_CLKNAME "sclk_mfc"
+#define MFC_GATE_CLK_NAME "mfc"
+
+#define CLK_DEBUG
+
+static struct s5p_mfc_pm *pm;
+static struct s5p_mfc_dev *p_dev;
+
+#ifdef CLK_DEBUG
+atomic_t clk_ref;
+#endif
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+ int ret = 0;
+
+ pm = &dev->pm;
+ p_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 = 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 = 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;
+ pm_runtime_enable(pm->device);
+#endif
+#ifdef CLK_DEBUG
+ 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;
+}
+
+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);
+#endif
+}
+
+int s5p_mfc_clock_on(void)
+{
+ int ret;
+#ifdef CLK_DEBUG
+ atomic_inc(&clk_ref);
+ mfc_debug(3, "+ %d", atomic_read(&clk_ref));
+#endif
+ ret = clk_enable(pm->clock_gate);
+ return ret;
+}
+
+void s5p_mfc_clock_off(void)
+{
+#ifdef CLK_DEBUG
+ atomic_dec(&clk_ref);
+ mfc_debug(3, "- %d", atomic_read(&clk_ref));
+#endif
+ clk_disable(pm->clock_gate);
+}
+
+int s5p_mfc_power_on(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+ return pm_runtime_get_sync(pm->device);
+#else
+ atomic_set(&pm->power, 1);
+ return 0;
+#endif
+}
+
+int s5p_mfc_power_off(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+ return pm_runtime_put_sync(pm->device);
+#else
+ atomic_set(&pm->power, 0);
+ return 0;
+#endif
+}
+
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
new file mode 100644
index 000000000000..875c5346bc85
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
@@ -0,0 +1,24 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_PM_H_
+#define S5P_MFC_PM_H_
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_clock_on(void);
+void s5p_mfc_clock_off(void);
+int s5p_mfc_power_on(void);
+int s5p_mfc_power_off(void);
+
+#endif /* S5P_MFC_PM_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
new file mode 100644
index 000000000000..b5933d233a4b
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
@@ -0,0 +1,47 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifdef CONFIG_ARCH_EXYNOS4
+#include <linux/dma-mapping.h>
+#endif
+#include <linux/io.h>
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+
+ ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx,
+ SHARED_BUF_SIZE);
+ if (IS_ERR(ctx->shm_alloc)) {
+ mfc_err("failed to allocate shared memory\n");
+ return PTR_ERR(ctx->shm_alloc);
+ }
+ /* shm_ofs only keeps the offset from base (port a) */
+ ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc)
+ - dev->bank1;
+ BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc);
+ if (!ctx->shm) {
+ vb2_dma_contig_memops.put(ctx->shm_alloc);
+ ctx->shm_ofs = 0;
+ ctx->shm_alloc = NULL;
+ mfc_err("failed to virt addr of shared memory\n");
+ return -ENOMEM;
+ }
+ memset((void *)ctx->shm, 0, SHARED_BUF_SIZE);
+ wmb();
+ return 0;
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
new file mode 100644
index 000000000000..416ebd7ba35a
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
@@ -0,0 +1,90 @@
+/*
+ * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.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.
+ */
+
+#ifndef S5P_MFC_SHM_H_
+#define S5P_MFC_SHM_H_
+
+enum MFC_SHM_OFS {
+ EXTENEDED_DECODE_STATUS = 0x00, /* D */
+ SET_FRAME_TAG = 0x04, /* D */
+ GET_FRAME_TAG_TOP = 0x08, /* D */
+ GET_FRAME_TAG_BOT = 0x0C, /* D */
+ PIC_TIME_TOP = 0x10, /* D */
+ PIC_TIME_BOT = 0x14, /* D */
+ START_BYTE_NUM = 0x18, /* D */
+
+ CROP_INFO_H = 0x20, /* D */
+ CROP_INFO_V = 0x24, /* D */
+ EXT_ENC_CONTROL = 0x28, /* E */
+ ENC_PARAM_CHANGE = 0x2C, /* E */
+ RC_VOP_TIMING = 0x30, /* E, MPEG4 */
+ HEC_PERIOD = 0x34, /* E, MPEG4 */
+ METADATA_ENABLE = 0x38, /* C */
+ METADATA_STATUS = 0x3C, /* C */
+ METADATA_DISPLAY_INDEX = 0x40, /* C */
+ EXT_METADATA_START_ADDR = 0x44, /* C */
+ PUT_EXTRADATA = 0x48, /* C */
+ EXTRADATA_ADDR = 0x4C, /* C */
+
+ ALLOC_LUMA_DPB_SIZE = 0x64, /* D */
+ ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */
+ ALLOC_MV_SIZE = 0x6C, /* D */
+ P_B_FRAME_QP = 0x70, /* E */
+ SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on
+ ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+ EXTENDED_SAR = 0x78, /* E, H.264, depned on
+ ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+ DISP_PIC_PROFILE = 0x7C, /* D */
+ FLUSH_CMD_TYPE = 0x80, /* C */
+ FLUSH_CMD_INBUF1 = 0x84, /* C */
+ FLUSH_CMD_INBUF2 = 0x88, /* C */
+ FLUSH_CMD_OUTBUF = 0x8C, /* E */
+ NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8)
+ depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
+ NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0)
+ depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
+ NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504)
+ depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
+ H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */
+ RC_CONTROL_CONFIG = 0xA0, /* E */
+ BATCH_INPUT_ADDR = 0xA4, /* E */
+ BATCH_OUTPUT_ADDR = 0xA8, /* E */
+ BATCH_OUTPUT_SIZE = 0xAC, /* E */
+ MIN_LUMA_DPB_SIZE = 0xB0, /* D */
+ DEVICE_FORMAT_ID = 0xB4, /* C */
+ H264_POC_TYPE = 0xB8, /* D */
+ MIN_CHROMA_DPB_SIZE = 0xBC, /* D */
+ DISP_PIC_FRAME_TYPE = 0xC0, /* D */
+ FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */
+ ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */
+ EXTENDED_PAR = 0xCC, /* D, MPEG4 */
+ DBG_HISTORY_INPUT0 = 0xD0, /* C */
+ DBG_HISTORY_INPUT1 = 0xD4, /* C */
+ DBG_HISTORY_OUTPUT = 0xD8, /* C */
+ HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */
+};
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_write_shm(ctx, x, ofs) \
+ do { \
+ writel(x, (ctx->shm + ofs)); \
+ wmb(); \
+ } while (0)
+
+static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+ rmb();
+ return readl(ctx->shm + ofs);
+}
+
+#endif /* S5P_MFC_SHM_H_ */
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig
new file mode 100644
index 000000000000..ea11a513033f
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/Kconfig
@@ -0,0 +1,86 @@
+# drivers/media/platform/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+config VIDEO_SAMSUNG_S5P_TV
+ bool "Samsung TV driver for S5P platform (experimental)"
+ depends on PLAT_S5P && PM_RUNTIME
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ Say Y here to enable selecting the TV output devices for
+ Samsung S5P platform.
+
+if VIDEO_SAMSUNG_S5P_TV
+
+config VIDEO_SAMSUNG_S5P_HDMI
+ tristate "Samsung HDMI Driver"
+ depends on VIDEO_V4L2
+ depends on VIDEO_SAMSUNG_S5P_TV
+ select VIDEO_SAMSUNG_S5P_HDMIPHY
+ help
+ Say Y here if you want support for the HDMI output
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module. It is an auxiliary driver, that exposes a V4L2
+ subdev for use by other drivers. This driver requires
+ hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+ bool "Enable debug for HDMI Driver"
+ depends on VIDEO_SAMSUNG_S5P_HDMI
+ default n
+ help
+ Enables debugging for HDMI driver.
+
+config VIDEO_SAMSUNG_S5P_HDMIPHY
+ tristate "Samsung HDMIPHY Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+ depends on VIDEO_SAMSUNG_S5P_TV
+ help
+ Say Y here if you want support for the physical HDMI
+ 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_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
+ depends on VIDEO_SAMSUNG_S5P_TV
+ help
+ Say Y here if you want support for the analog TV output
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module. It is an auxiliary driver, that exposes a V4L2
+ subdev for use by other drivers. This driver requires
+ hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_MIXER
+ tristate "Samsung Mixer and Video Processor Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on VIDEO_SAMSUNG_S5P_TV
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+ This device produce image data to one of output interfaces.
+
+config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+ bool "Enable debug for Mixer Driver"
+ depends on VIDEO_SAMSUNG_S5P_MIXER
+ default n
+ help
+ Enables debugging for Mixer driver.
+
+endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/platform/s5p-tv/Makefile b/drivers/media/platform/s5p-tv/Makefile
new file mode 100644
index 000000000000..7cd47902e269
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/Makefile
@@ -0,0 +1,19 @@
+# drivers/media/platform/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+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
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
+
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
new file mode 100644
index 000000000000..8a9cf43018f6
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -0,0 +1,1009 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#define pr_fmt(fmt) "s5p-tv (hdmi_drv): " fmt
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#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>
+
+#include "regs-hdmi.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
+
+struct hdmi_pulse {
+ u32 beg;
+ u32 end;
+};
+
+struct hdmi_timings {
+ struct hdmi_pulse hact;
+ u32 hsyn_pol; /* 0 - high, 1 - low */
+ struct hdmi_pulse hsyn;
+ u32 interlaced;
+ struct hdmi_pulse vact[2];
+ u32 vsyn_pol; /* 0 - high, 1 - low */
+ u32 vsyn_off;
+ struct hdmi_pulse vsyn[2];
+};
+
+struct hdmi_resources {
+ struct clk *hdmi;
+ struct clk *sclk_hdmi;
+ struct clk *sclk_pixel;
+ struct clk *sclk_hdmiphy;
+ struct clk *hdmiphy;
+ struct regulator_bulk_data *regul_bulk;
+ int regul_count;
+};
+
+struct hdmi_device {
+ /** base address of HDMI registers */
+ void __iomem *regs;
+ /** HDMI interrupt */
+ unsigned int irq;
+ /** pointer to device parent */
+ struct device *dev;
+ /** subdev generated by HDMI device */
+ struct v4l2_subdev sd;
+ /** V4L2 device structure */
+ 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_timings *cur_conf;
+ /** flag indicating that timings are dirty */
+ int cur_conf_dirty;
+ /** current preset */
+ u32 cur_preset;
+ /** other resources */
+ struct hdmi_resources res;
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+ {
+ .name = "s5pv210-hdmi",
+ }, {
+ .name = "exynos4-hdmi",
+ }, {
+ /* end node */
+ }
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct hdmi_device, sd);
+}
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+ writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+ u32 old = readl(hdev->regs + reg_id);
+ value = (value & mask) | (old & ~mask);
+ writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+ writeb(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value)
+{
+ switch (n) {
+ default:
+ writeb(value >> 24, hdev->regs + reg_id + 12);
+ case 3:
+ writeb(value >> 16, hdev->regs + reg_id + 8);
+ case 2:
+ writeb(value >> 8, hdev->regs + reg_id + 4);
+ case 1:
+ writeb(value >> 0, hdev->regs + reg_id + 0);
+ }
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+ return readl(hdev->regs + reg_id);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+ struct hdmi_device *hdev = dev_data;
+ u32 intc_flag;
+
+ (void)irq;
+ intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+ /* clearing flags for HPD plug/unplug */
+ if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+ pr_info("unplugged\n");
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+ HDMI_INTC_FLAG_HPD_UNPLUG);
+ }
+ if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+ pr_info("plugged\n");
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+ HDMI_INTC_FLAG_HPD_PLUG);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+ /* enable HPD interrupts */
+ hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+ HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+ /* choose DVI mode */
+ hdmi_write_mask(hdev, HDMI_MODE_SEL,
+ HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
+ hdmi_write_mask(hdev, HDMI_CON_2, ~0,
+ HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN);
+ /* disable bluescreen */
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+ /* choose bluescreen (fecal) color */
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+ const struct hdmi_timings *t)
+{
+ /* setting core registers */
+ hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
+ hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
+ (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
+ hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
+ hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
+ (t->vact[0].beg << 11) | t->vact[0].end);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
+ (t->vsyn[0].beg << 12) | t->vsyn[0].end);
+ if (t->interlaced) {
+ u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
+
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1);
+ hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+ (t->hact.end << 12) | t->vact[1].end);
+ hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
+ (t->vact[1].end << 11) | t->vact[1].beg);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
+ (t->vsyn[1].beg << 12) | t->vsyn[1].end);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
+ (vsyn_trans << 12) | vsyn_trans);
+ } else {
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
+ hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+ (t->hact.end << 12) | t->vact[0].end);
+ }
+
+ /* Timing generator registers */
+ hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
+ hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
+ hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
+ t->vact[0].end - t->vact[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
+ if (t->interlaced) {
+ hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
+ hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
+ hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
+ } else {
+ hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
+ hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
+ }
+}
+
+static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+ struct device *dev = hdmi_dev->dev;
+ const struct hdmi_timings *conf = hdmi_dev->cur_conf;
+ struct v4l2_dv_preset preset;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* skip if conf is already synchronized with HW */
+ if (!hdmi_dev->cur_conf_dirty)
+ return 0;
+
+ /* reset hdmiphy */
+ hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
+ mdelay(10);
+
+ /* configure presets */
+ preset.preset = hdmi_dev->cur_preset;
+ ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+ if (ret) {
+ dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+ return ret;
+ }
+
+ /* resetting HDMI core */
+ hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+ mdelay(10);
+
+ hdmi_reg_init(hdmi_dev);
+
+ /* setting core registers */
+ hdmi_timing_apply(hdmi_dev, conf);
+
+ hdmi_dev->cur_conf_dirty = 0;
+
+ return 0;
+}
+
+static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+ dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+ readl(hdev->regs + reg_id))
+
+ dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_INTC_FLAG);
+ DUMPREG(HDMI_INTC_CON);
+ DUMPREG(HDMI_HPD_STATUS);
+ DUMPREG(HDMI_PHY_RSTOUT);
+ DUMPREG(HDMI_PHY_VPLL);
+ DUMPREG(HDMI_PHY_CMU);
+ DUMPREG(HDMI_CORE_RSTOUT);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_CON_0);
+ DUMPREG(HDMI_CON_1);
+ DUMPREG(HDMI_CON_2);
+ DUMPREG(HDMI_SYS_STATUS);
+ DUMPREG(HDMI_PHY_STATUS);
+ DUMPREG(HDMI_STATUS_EN);
+ DUMPREG(HDMI_HPD);
+ DUMPREG(HDMI_MODE_SEL);
+ DUMPREG(HDMI_HPD_GEN);
+ DUMPREG(HDMI_DC_CONTROL);
+ DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_H_BLANK_0);
+ DUMPREG(HDMI_H_BLANK_1);
+ DUMPREG(HDMI_V_BLANK_0);
+ DUMPREG(HDMI_V_BLANK_1);
+ DUMPREG(HDMI_V_BLANK_2);
+ DUMPREG(HDMI_H_V_LINE_0);
+ DUMPREG(HDMI_H_V_LINE_1);
+ DUMPREG(HDMI_H_V_LINE_2);
+ DUMPREG(HDMI_VSYNC_POL);
+ DUMPREG(HDMI_INT_PRO_MODE);
+ DUMPREG(HDMI_V_BLANK_F_0);
+ DUMPREG(HDMI_V_BLANK_F_1);
+ DUMPREG(HDMI_V_BLANK_F_2);
+ DUMPREG(HDMI_H_SYNC_GEN_0);
+ DUMPREG(HDMI_H_SYNC_GEN_1);
+ DUMPREG(HDMI_H_SYNC_GEN_2);
+ DUMPREG(HDMI_V_SYNC_GEN_1_0);
+ DUMPREG(HDMI_V_SYNC_GEN_1_1);
+ DUMPREG(HDMI_V_SYNC_GEN_1_2);
+ DUMPREG(HDMI_V_SYNC_GEN_2_0);
+ DUMPREG(HDMI_V_SYNC_GEN_2_1);
+ DUMPREG(HDMI_V_SYNC_GEN_2_2);
+ DUMPREG(HDMI_V_SYNC_GEN_3_0);
+ DUMPREG(HDMI_V_SYNC_GEN_3_1);
+ DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+ dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_TG_CMD);
+ DUMPREG(HDMI_TG_H_FSZ_L);
+ DUMPREG(HDMI_TG_H_FSZ_H);
+ DUMPREG(HDMI_TG_HACT_ST_L);
+ DUMPREG(HDMI_TG_HACT_ST_H);
+ DUMPREG(HDMI_TG_HACT_SZ_L);
+ DUMPREG(HDMI_TG_HACT_SZ_H);
+ DUMPREG(HDMI_TG_V_FSZ_L);
+ DUMPREG(HDMI_TG_V_FSZ_H);
+ DUMPREG(HDMI_TG_VSYNC_L);
+ DUMPREG(HDMI_TG_VSYNC_H);
+ DUMPREG(HDMI_TG_VSYNC2_L);
+ DUMPREG(HDMI_TG_VSYNC2_H);
+ DUMPREG(HDMI_TG_VACT_ST_L);
+ DUMPREG(HDMI_TG_VACT_ST_H);
+ DUMPREG(HDMI_TG_VACT_SZ_L);
+ DUMPREG(HDMI_TG_VACT_SZ_H);
+ DUMPREG(HDMI_TG_FIELD_CHG_L);
+ DUMPREG(HDMI_TG_FIELD_CHG_H);
+ DUMPREG(HDMI_TG_VACT_ST2_L);
+ DUMPREG(HDMI_TG_VACT_ST2_H);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static const struct hdmi_timings hdmi_timings_480p = {
+ .hact = { .beg = 138, .end = 858 },
+ .hsyn_pol = 1,
+ .hsyn = { .beg = 16, .end = 16 + 62 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
+ .vsyn_pol = 1,
+ .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
+};
+
+static const struct hdmi_timings hdmi_timings_576p50 = {
+ .hact = { .beg = 144, .end = 864 },
+ .hsyn_pol = 1,
+ .hsyn = { .beg = 12, .end = 12 + 64 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
+ .vsyn_pol = 1,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_720p60 = {
+ .hact = { .beg = 370, .end = 1650 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 110, .end = 110 + 40 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_720p50 = {
+ .hact = { .beg = 700, .end = 1980 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 440, .end = 440 + 40 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p24 = {
+ .hact = { .beg = 830, .end = 2750 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 638, .end = 638 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p60 = {
+ .hact = { .beg = 280, .end = 2200 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 88, .end = 88 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i60 = {
+ .hact = { .beg = 280, .end = 2200 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 88, .end = 88 + 44 },
+ .interlaced = 1,
+ .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+ .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+ .vsyn_pol = 0,
+ .vsyn_off = 1100,
+ .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i50 = {
+ .hact = { .beg = 720, .end = 2640 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 528, .end = 528 + 44 },
+ .interlaced = 1,
+ .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+ .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+ .vsyn_pol = 0,
+ .vsyn_off = 1320,
+ .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p50 = {
+ .hact = { .beg = 720, .end = 2640 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 528, .end = 528 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct {
+ u32 preset;
+ const struct hdmi_timings *timings;
+} hdmi_timings[] = {
+ { V4L2_DV_480P59_94, &hdmi_timings_480p },
+ { V4L2_DV_576P50, &hdmi_timings_576p50 },
+ { V4L2_DV_720P50, &hdmi_timings_720p50 },
+ { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
+ { V4L2_DV_720P60, &hdmi_timings_720p60 },
+ { V4L2_DV_1080P24, &hdmi_timings_1080p24 },
+ { V4L2_DV_1080P30, &hdmi_timings_1080p60 },
+ { V4L2_DV_1080P50, &hdmi_timings_1080p50 },
+ { V4L2_DV_1080I50, &hdmi_timings_1080i50 },
+ { V4L2_DV_1080I60, &hdmi_timings_1080i60 },
+ { V4L2_DV_1080P60, &hdmi_timings_1080p60 },
+};
+
+static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
+ if (hdmi_timings[i].preset == preset)
+ return hdmi_timings[i].timings;
+ return NULL;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+ int ret, tries;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = hdmi_conf_apply(hdev);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+ if (ret)
+ return ret;
+
+ /* waiting for HDMIPHY's PLL to get to steady state */
+ for (tries = 100; tries; --tries) {
+ u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+ if (val & HDMI_PHY_STATUS_READY)
+ break;
+ mdelay(1);
+ }
+ /* steady state not achieved */
+ 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, "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;
+ }
+
+ /* hdmiphy clock is used for HDMI in streaming mode */
+ clk_disable(res->sclk_hdmi);
+ clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+ clk_enable(res->sclk_hdmi);
+
+ /* enable HDMI and timing generator */
+ hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+ hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+ hdmi_dumpregs(hdev, "streamon");
+ return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+ hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
+
+ /* pixel(vpll) clock is used for HDMI in config mode */
+ clk_disable(res->sclk_hdmi);
+ 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");
+ return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s(%d)\n", __func__, enable);
+ if (enable)
+ return hdmi_streamon(hdev);
+ return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+ /* turn HDMI power on */
+ regulator_bulk_enable(res->regul_count, res->regul_bulk);
+ /* power-on hdmi physical interface */
+ clk_enable(res->hdmiphy);
+ /* use VPP as parent clock; HDMIPHY is not working yet */
+ clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+ /* turn clocks on */
+ clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_resource_poweroff(struct hdmi_resources *res)
+{
+ /* turn clocks off */
+ clk_disable(res->sclk_hdmi);
+ /* power-off hdmiphy */
+ clk_disable(res->hdmiphy);
+ /* turn HDMI power off */
+ regulator_bulk_disable(res->regul_count, res->regul_bulk);
+}
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ int ret;
+
+ if (on)
+ ret = pm_runtime_get_sync(hdev->dev);
+ else
+ ret = pm_runtime_put_sync(hdev->dev);
+ /* only values < 0 indicate errors */
+ return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *preset)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+ const struct hdmi_timings *conf;
+
+ conf = hdmi_preset2timings(preset->preset);
+ if (conf == NULL) {
+ dev_err(dev, "preset (%u) not supported\n", preset->preset);
+ return -EINVAL;
+ }
+ hdev->cur_conf = conf;
+ hdev->cur_conf_dirty = 1;
+ hdev->cur_preset = preset->preset;
+ return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *preset)
+{
+ memset(preset, 0, sizeof(*preset));
+ preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+ return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ const struct hdmi_timings *t = hdev->cur_conf;
+
+ dev_dbg(hdev->dev, "%s\n", __func__);
+ if (!hdev->cur_conf)
+ return -EINVAL;
+ memset(fmt, 0, sizeof *fmt);
+ fmt->width = t->hact.end - t->hact.beg;
+ fmt->height = t->vact[0].end - t->vact[0].beg;
+ fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ if (t->interlaced) {
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->height *= 2;
+ } else {
+ fmt->field = V4L2_FIELD_NONE;
+ }
+ return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+ struct v4l2_dv_enum_preset *preset)
+{
+ if (preset->index >= ARRAY_SIZE(hdmi_timings))
+ return -EINVAL;
+ return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
+ preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+ .s_power = hdmi_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+ .s_dv_preset = hdmi_s_dv_preset,
+ .g_dv_preset = hdmi_g_dv_preset,
+ .enum_dv_presets = hdmi_enum_dv_presets,
+ .g_mbus_fmt = hdmi_g_mbus_fmt,
+ .s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+ .core = &hdmi_sd_core_ops,
+ .video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(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);
+ /* flag that device context is lost */
+ hdev->cur_conf_dirty = 1;
+ return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdmi_resource_poweron(&hdev->res);
+
+ /* 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;
+
+fail:
+ hdmi_resource_poweroff(&hdev->res);
+ dev_err(dev, "poweron failed\n");
+
+ return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+ .runtime_suspend = hdmi_runtime_suspend,
+ .runtime_resume = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+ /* put clocks, power */
+ if (res->regul_count)
+ regulator_bulk_free(res->regul_count, res->regul_bulk);
+ /* kfree is NULL-safe */
+ kfree(res->regul_bulk);
+ if (!IS_ERR_OR_NULL(res->hdmiphy))
+ clk_put(res->hdmiphy);
+ if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+ clk_put(res->sclk_hdmiphy);
+ if (!IS_ERR_OR_NULL(res->sclk_pixel))
+ clk_put(res->sclk_pixel);
+ if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ clk_put(res->sclk_hdmi);
+ if (!IS_ERR_OR_NULL(res->hdmi))
+ clk_put(res->hdmi);
+ memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+ static char *supply[] = {
+ "hdmi-en",
+ "vdd",
+ "vdd_osc",
+ "vdd_pll",
+ };
+ int i, ret;
+
+ dev_dbg(dev, "HDMI resource init\n");
+
+ memset(res, 0, sizeof *res);
+ /* get clocks, power */
+
+ res->hdmi = clk_get(dev, "hdmi");
+ if (IS_ERR_OR_NULL(res->hdmi)) {
+ dev_err(dev, "failed to get clock 'hdmi'\n");
+ goto fail;
+ }
+ res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+ if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+ goto fail;
+ }
+ res->sclk_pixel = clk_get(dev, "sclk_pixel");
+ if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+ dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+ goto fail;
+ }
+ res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+ if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+ dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+ goto fail;
+ }
+ res->hdmiphy = clk_get(dev, "hdmiphy");
+ if (IS_ERR_OR_NULL(res->hdmiphy)) {
+ dev_err(dev, "failed to get clock 'hdmiphy'\n");
+ goto fail;
+ }
+ 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;
+ }
+ for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+ res->regul_bulk[i].supply = supply[i];
+ res->regul_bulk[i].consumer = NULL;
+ }
+
+ ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+ if (ret) {
+ dev_err(dev, "failed to get regulators\n");
+ goto fail;
+ }
+ res->regul_count = ARRAY_SIZE(supply);
+
+ return 0;
+fail:
+ dev_err(dev, "HDMI resource init - failed\n");
+ hdmi_resources_cleanup(hdev);
+ return -ENODEV;
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct i2c_adapter *adapter;
+ struct v4l2_subdev *sd;
+ struct hdmi_device *hdmi_dev = NULL;
+ struct s5p_hdmi_platform_data *pdata = dev->platform_data;
+ int ret;
+
+ dev_dbg(dev, "probe start\n");
+
+ 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;
+ goto fail;
+ }
+
+ hdmi_dev->dev = dev;
+
+ ret = hdmi_resources_init(hdmi_dev);
+ if (ret)
+ goto fail;
+
+ /* mapping HDMI registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_init;
+ }
+
+ 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_init;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_init;
+ }
+
+ 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_init;
+ }
+ hdmi_dev->irq = res->start;
+
+ /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+ strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+ sizeof(hdmi_dev->v4l2_dev.name));
+ /* passing NULL owner prevents driver from erasing drvdata */
+ ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "could not register v4l2 device.\n");
+ goto fail_init;
+ }
+
+ /* 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,
+ adapter, pdata->hdmiphy_info, NULL);
+ /* on failure or not adapter is no longer useful */
+ 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);
+
+ sd = &hdmi_dev->sd;
+ v4l2_subdev_init(sd, &hdmi_sd_ops);
+ sd->owner = THIS_MODULE;
+
+ strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+ hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+ /* FIXME: missing fail preset is not supported */
+ hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+ hdmi_dev->cur_conf_dirty = 1;
+
+ /* storing subdev for call that have only access to struct device */
+ dev_set_drvdata(dev, sd);
+
+ dev_info(dev, "probe successful\n");
+
+ return 0;
+
+fail_vdev:
+ v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_init:
+ hdmi_resources_cleanup(hdmi_dev);
+
+fail:
+ dev_err(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+ pm_runtime_disable(dev);
+ clk_disable(hdmi_dev->res.hdmi);
+ v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+ disable_irq(hdmi_dev->irq);
+ hdmi_resources_cleanup(hdmi_dev);
+ dev_info(dev, "remove successful\n");
+
+ return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+ .probe = hdmi_probe,
+ .remove = __devexit_p(hdmi_remove),
+ .id_table = hdmi_driver_types,
+ .driver = {
+ .name = "s5p-hdmi",
+ .owner = THIS_MODULE,
+ .pm = &hdmi_pm_ops,
+ }
+};
+
+module_platform_driver(hdmi_driver);
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
index f67b38631801..f67b38631801 100644
--- a/drivers/media/video/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h
index ddb422e23550..ddb422e23550 100644
--- a/drivers/media/video/s5p-tv/mixer.h
+++ b/drivers/media/platform/s5p-tv/mixer.h
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c
new file mode 100644
index 000000000000..a15ca0595b87
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_drv.c
@@ -0,0 +1,487 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+ {
+ .output_name = "S5P HDMI connector",
+ .module_name = "s5p-hdmi",
+ .cookie = 1,
+ },
+ {
+ .output_name = "S5P SDO connector",
+ .module_name = "s5p-sdo",
+ .cookie = 0,
+ },
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+ struct v4l2_mbus_framefmt *mbus_fmt)
+{
+ struct v4l2_subdev *sd;
+ int ret;
+
+ mutex_lock(&mdev->mutex);
+ sd = to_outsd(mdev);
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+ WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+ mutex_unlock(&mdev->mutex);
+}
+
+void mxr_streamer_get(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ ++mdev->n_streamer;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+ if (mdev->n_streamer == 1) {
+ struct v4l2_subdev *sd = to_outsd(mdev);
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct mxr_resources *res = &mdev->res;
+ int ret;
+
+ if (to_output(mdev)->cookie == 0)
+ clk_set_parent(res->sclk_mixer, res->sclk_dac);
+ else
+ clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+ mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+ WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ WARN(ret, "starting stream failed for output %s\n", sd->name);
+
+ mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+ mxr_reg_streamon(mdev);
+ ret = mxr_reg_wait4vsync(mdev);
+ WARN(ret, "failed to get vsync (%d) from output\n", ret);
+ }
+ mutex_unlock(&mdev->mutex);
+ mxr_reg_dump(mdev);
+ /* FIXME: what to do when streaming fails? */
+}
+
+void mxr_streamer_put(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ --mdev->n_streamer;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+ if (mdev->n_streamer == 0) {
+ int ret;
+ struct v4l2_subdev *sd = to_outsd(mdev);
+
+ mxr_reg_streamoff(mdev);
+ /* vsync applies Mixer setup */
+ ret = mxr_reg_wait4vsync(mdev);
+ WARN(ret, "failed to get vsync (%d) from output\n", ret);
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ WARN(ret, "stopping stream failed for output %s\n", sd->name);
+ }
+ WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+ mdev->n_streamer);
+ mutex_unlock(&mdev->mutex);
+ mxr_reg_dump(mdev);
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ ++mdev->n_output;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+ /* turn on auxiliary driver */
+ if (mdev->n_output == 1)
+ v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+ mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ --mdev->n_output;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+ /* turn on auxiliary driver */
+ if (mdev->n_output == 0)
+ v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+ WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+ mdev->n_output);
+ mutex_unlock(&mdev->mutex);
+}
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+ int ret = pm_runtime_get_sync(mdev->dev);
+
+ /* returning 1 means that power is already enabled,
+ * so zero success be returned */
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ return 0;
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+ pm_runtime_put_sync(mdev->dev);
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+ if (res == NULL) {
+ mxr_err(mdev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+ if (mdev->res.mxr_regs == NULL) {
+ mxr_err(mdev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+ if (res == NULL) {
+ mxr_err(mdev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_mxr_regs;
+ }
+
+ mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+ if (mdev->res.vp_regs == NULL) {
+ mxr_err(mdev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail_mxr_regs;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+ if (res == NULL) {
+ mxr_err(mdev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_vp_regs;
+ }
+
+ ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+ if (ret) {
+ mxr_err(mdev, "request interrupt failed.\n");
+ goto fail_vp_regs;
+ }
+ mdev->res.irq = res->start;
+
+ return 0;
+
+fail_vp_regs:
+ iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+ iounmap(mdev->res.mxr_regs);
+
+fail:
+ return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+ free_irq(mdev->res.irq, mdev);
+ iounmap(mdev->res.vp_regs);
+ iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+ struct mxr_resources *res = &mdev->res;
+
+ if (!IS_ERR_OR_NULL(res->sclk_dac))
+ clk_put(res->sclk_dac);
+ if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ clk_put(res->sclk_hdmi);
+ if (!IS_ERR_OR_NULL(res->sclk_mixer))
+ clk_put(res->sclk_mixer);
+ if (!IS_ERR_OR_NULL(res->vp))
+ clk_put(res->vp);
+ if (!IS_ERR_OR_NULL(res->mixer))
+ clk_put(res->mixer);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+ struct mxr_resources *res = &mdev->res;
+ struct device *dev = mdev->dev;
+
+ res->mixer = clk_get(dev, "mixer");
+ if (IS_ERR_OR_NULL(res->mixer)) {
+ mxr_err(mdev, "failed to get clock 'mixer'\n");
+ goto fail;
+ }
+ res->vp = clk_get(dev, "vp");
+ if (IS_ERR_OR_NULL(res->vp)) {
+ mxr_err(mdev, "failed to get clock 'vp'\n");
+ goto fail;
+ }
+ res->sclk_mixer = clk_get(dev, "sclk_mixer");
+ if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+ mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+ goto fail;
+ }
+ res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+ if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+ goto fail;
+ }
+ res->sclk_dac = clk_get(dev, "sclk_dac");
+ if (IS_ERR_OR_NULL(res->sclk_dac)) {
+ mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ mxr_release_clocks(mdev);
+ return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+ struct platform_device *pdev)
+{
+ int ret;
+ ret = mxr_acquire_plat_resources(mdev, pdev);
+
+ if (ret)
+ goto fail;
+
+ ret = mxr_acquire_clocks(mdev);
+ if (ret)
+ goto fail_plat;
+
+ mxr_info(mdev, "resources acquired\n");
+ return 0;
+
+fail_plat:
+ mxr_release_plat_resources(mdev);
+fail:
+ mxr_err(mdev, "resources acquire failed\n");
+ return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+ mxr_release_clocks(mdev);
+ mxr_release_plat_resources(mdev);
+ memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
+ if (mdev->layer[i])
+ mxr_layer_release(mdev->layer[i]);
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+ struct mxr_platform_data *pdata)
+{
+ mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
+ mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
+ mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
+
+ if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
+ mxr_err(mdev, "failed to acquire layers\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ mxr_release_layers(mdev);
+ return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+ struct mxr_device *mdev = to_mdev(dev);
+ struct mxr_resources *res = &mdev->res;
+
+ mxr_dbg(mdev, "resume - start\n");
+ mutex_lock(&mdev->mutex);
+ /* turn clocks on */
+ clk_enable(res->mixer);
+ clk_enable(res->vp);
+ clk_enable(res->sclk_mixer);
+ /* apply default configuration */
+ mxr_reg_reset(mdev);
+ mxr_dbg(mdev, "resume - finished\n");
+
+ mutex_unlock(&mdev->mutex);
+ return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+ struct mxr_device *mdev = to_mdev(dev);
+ struct mxr_resources *res = &mdev->res;
+ mxr_dbg(mdev, "suspend - start\n");
+ mutex_lock(&mdev->mutex);
+ /* turn clocks off */
+ clk_disable(res->sclk_mixer);
+ clk_disable(res->vp);
+ clk_disable(res->mixer);
+ mutex_unlock(&mdev->mutex);
+ mxr_dbg(mdev, "suspend - finished\n");
+ return 0;
+}
+
+static const struct dev_pm_ops mxr_pm_ops = {
+ .runtime_suspend = mxr_runtime_suspend,
+ .runtime_resume = mxr_runtime_resume,
+};
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxr_platform_data *pdata = dev->platform_data;
+ struct mxr_device *mdev;
+ int ret;
+
+ /* mdev does not exist yet so no mxr_dbg is used */
+ dev_info(dev, "probe start\n");
+
+ mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+ if (!mdev) {
+ mxr_err(mdev, "not enough memory.\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* setup pointer to master device */
+ mdev->dev = dev;
+
+ mutex_init(&mdev->mutex);
+ spin_lock_init(&mdev->reg_slock);
+ init_waitqueue_head(&mdev->event_queue);
+
+ /* acquire resources: regs, irqs, clocks, regulators */
+ ret = mxr_acquire_resources(mdev, pdev);
+ if (ret)
+ goto fail_mem;
+
+ /* configure resources for video output */
+ ret = mxr_acquire_video(mdev, mxr_output_conf,
+ ARRAY_SIZE(mxr_output_conf));
+ if (ret)
+ goto fail_resources;
+
+ /* configure layers */
+ ret = mxr_acquire_layers(mdev, pdata);
+ if (ret)
+ goto fail_video;
+
+ pm_runtime_enable(dev);
+
+ mxr_info(mdev, "probe successful\n");
+ return 0;
+
+fail_video:
+ mxr_release_video(mdev);
+
+fail_resources:
+ mxr_release_resources(mdev);
+
+fail_mem:
+ kfree(mdev);
+
+fail:
+ dev_info(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxr_device *mdev = to_mdev(dev);
+
+ pm_runtime_disable(dev);
+
+ mxr_release_layers(mdev);
+ mxr_release_video(mdev);
+ mxr_release_resources(mdev);
+
+ kfree(mdev);
+
+ dev_info(dev, "remove successful\n");
+ return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+ .probe = mxr_probe,
+ .remove = __devexit_p(mxr_remove),
+ .driver = {
+ .name = MXR_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &mxr_pm_ops,
+ }
+};
+
+static int __init mxr_init(void)
+{
+ int i, ret;
+ static const char banner[] __initconst =
+ "Samsung TV Mixer driver, "
+ "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+ pr_info("%s\n", banner);
+
+ /* Loading auxiliary modules */
+ for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+ request_module(mxr_output_conf[i].module_name);
+
+ ret = platform_driver_register(&mxr_driver);
+ if (ret != 0) {
+ pr_err("s5p-tv: registration of MIXER driver failed\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+ platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c
index b93a21f5aa13..b93a21f5aa13 100644
--- a/drivers/media/video/s5p-tv/mixer_grp_layer.c
+++ b/drivers/media/platform/s5p-tv/mixer_grp_layer.c
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c
index 3b1670a045f4..3b1670a045f4 100644
--- a/drivers/media/video/s5p-tv/mixer_reg.c
+++ b/drivers/media/platform/s5p-tv/mixer_reg.c
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
new file mode 100644
index 000000000000..a9c6be39246d
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -0,0 +1,1127 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * 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
+ */
+
+#define pr_fmt(fmt) "s5p-tv (mixer): " fmt
+
+#include "mixer.h"
+
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <media/videobuf2-dma-contig.h>
+
+static int find_reg_callback(struct device *dev, void *p)
+{
+ struct v4l2_subdev **sd = p;
+
+ *sd = dev_get_drvdata(dev);
+ /* non-zero value stops iteration */
+ return 1;
+}
+
+static struct v4l2_subdev *find_and_register_subdev(
+ struct mxr_device *mdev, char *module_name)
+{
+ struct device_driver *drv;
+ struct v4l2_subdev *sd = NULL;
+ int ret;
+
+ /* TODO: add waiting until probe is finished */
+ drv = driver_find(module_name, &platform_bus_type);
+ if (!drv) {
+ mxr_warn(mdev, "module %s is missing\n", module_name);
+ return NULL;
+ }
+ /* driver refcnt is increased, it is safe to iterate over devices */
+ ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
+ /* ret == 0 means that find_reg_callback was never executed */
+ if (sd == NULL) {
+ mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
+ goto done;
+ }
+ /* v4l2_device_register_subdev detects if sd is NULL */
+ ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
+ if (ret) {
+ mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
+ sd = NULL;
+ }
+
+done:
+ return sd;
+}
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+ struct mxr_output_conf *output_conf, int output_count)
+{
+ struct device *dev = mdev->dev;
+ struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
+ int i;
+ int ret = 0;
+ struct v4l2_subdev *sd;
+
+ strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
+ /* prepare context for V4L2 device */
+ ret = v4l2_device_register(dev, v4l2_dev);
+ if (ret) {
+ mxr_err(mdev, "could not register v4l2 device.\n");
+ goto fail;
+ }
+
+ mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
+ if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+ mxr_err(mdev, "could not acquire vb2 allocator\n");
+ goto fail_v4l2_dev;
+ }
+
+ /* registering outputs */
+ mdev->output_cnt = 0;
+ for (i = 0; i < output_count; ++i) {
+ struct mxr_output_conf *conf = &output_conf[i];
+ struct mxr_output *out;
+
+ sd = find_and_register_subdev(mdev, conf->module_name);
+ /* trying to register next output */
+ if (sd == NULL)
+ continue;
+ out = kzalloc(sizeof *out, GFP_KERNEL);
+ if (out == NULL) {
+ mxr_err(mdev, "no memory for '%s'\n",
+ conf->output_name);
+ ret = -ENOMEM;
+ /* registered subdevs are removed in fail_v4l2_dev */
+ goto fail_output;
+ }
+ strlcpy(out->name, conf->output_name, sizeof(out->name));
+ out->sd = sd;
+ out->cookie = conf->cookie;
+ mdev->output[mdev->output_cnt++] = out;
+ mxr_info(mdev, "added output '%s' from module '%s'\n",
+ conf->output_name, conf->module_name);
+ /* checking if maximal number of outputs is reached */
+ if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+ break;
+ }
+
+ if (mdev->output_cnt == 0) {
+ mxr_err(mdev, "failed to register any output\n");
+ ret = -ENODEV;
+ /* skipping fail_output because there is nothing to free */
+ goto fail_vb2_allocator;
+ }
+
+ return 0;
+
+fail_output:
+ /* kfree is NULL-safe */
+ for (i = 0; i < mdev->output_cnt; ++i)
+ kfree(mdev->output[i]);
+ memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+ /* freeing allocator context */
+ vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+
+fail_v4l2_dev:
+ /* NOTE: automatically unregister all subdevs */
+ v4l2_device_unregister(v4l2_dev);
+
+fail:
+ return ret;
+}
+
+void mxr_release_video(struct mxr_device *mdev)
+{
+ int i;
+
+ /* kfree is NULL-safe */
+ for (i = 0; i < mdev->output_cnt; ++i)
+ kfree(mdev->output[i]);
+
+ vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+ v4l2_device_unregister(&mdev->v4l2_dev);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+ strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+ sprintf(cap->bus_info, "%d", layer->idx);
+ cap->version = KERNEL_VERSION(0, 1, 0);
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+ 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)
+{
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ memset(&layer->geo, 0, sizeof layer->geo);
+
+ 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.width = layer->geo.dst.full_width;
+ layer->geo.dst.height = layer->geo.dst.full_height;
+ layer->geo.dst.field = mbus_fmt.field;
+
+ layer->geo.src.full_width = mbus_fmt.width;
+ layer->geo.src.full_height = mbus_fmt.height;
+ layer->geo.src.width = layer->geo.src.full_width;
+ layer->geo.src.height = layer->geo.src.full_height;
+
+ mxr_geometry_dump(mdev, &layer->geo);
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+ mxr_geometry_dump(mdev, &layer->geo);
+}
+
+static void mxr_layer_update_output(struct mxr_layer *layer)
+{
+ 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);
+static const struct mxr_format *find_format_by_index(
+ struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ const struct mxr_format *fmt;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+ fmt = find_format_by_index(layer, f->index);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+ return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+ unsigned int width, unsigned int height)
+{
+ unsigned int bl_width = divup(width, blk->width);
+ unsigned int bl_height = divup(height, blk->height);
+
+ return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+ const struct mxr_format *fmt, u32 width, u32 height)
+{
+ 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
+ + fmt->plane2subframe[i];
+ const struct mxr_block *blk = &fmt->plane[i];
+ u32 bl_width = divup(width, blk->width);
+ u32 bl_height = divup(height, blk->height);
+ u32 sizeimage = bl_width * bl_height * blk->size;
+ u16 bytesperline = bl_width * blk->size / blk->height;
+
+ plane->sizeimage += sizeimage;
+ plane->bytesperline = max(plane->bytesperline, bytesperline);
+ }
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ pix->width = layer->geo.src.full_width;
+ pix->height = layer->geo.src.full_height;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = layer->fmt->fourcc;
+ pix->colorspace = layer->fmt->colorspace;
+ mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+ 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;
+ /* 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_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_geometry *geo = &layer->geo;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ 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:
+ 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:
+ 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;
+ }
+
+ return 0;
+}
+
+/* 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_geometry *geo = &layer->geo;
+ struct mxr_crop *target = NULL;
+ enum mxr_geometry_stage stage;
+ struct mxr_geometry tmp;
+ struct v4l2_rect res;
+
+ 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;
+
+ 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:
+ target = &geo->src;
+ stage = MXR_GEOMETRY_CROP;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ 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,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+ struct v4l2_dv_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+
+ /* preset change cannot be done while there is an entity
+ * dependant on output configuration
+ */
+ if (mdev->n_output > 0) {
+ mutex_unlock(&mdev->mutex);
+ return -EBUSY;
+ }
+
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+ mutex_unlock(&mdev->mutex);
+
+ mxr_layer_update_output(layer);
+
+ /* any failure should return EINVAL according to V4L2 doc */
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+ struct v4l2_dv_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+
+ /* standard change cannot be done while there is an entity
+ * dependant on output configuration
+ */
+ if (mdev->n_output > 0) {
+ mutex_unlock(&mdev->mutex);
+ return -EBUSY;
+ }
+
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+ mutex_unlock(&mdev->mutex);
+
+ mxr_layer_update_output(layer);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ struct mxr_output *out;
+ struct v4l2_subdev *sd;
+
+ if (a->index >= mdev->output_cnt)
+ return -EINVAL;
+ out = mdev->output[a->index];
+ BUG_ON(out == NULL);
+ sd = out->sd;
+ strlcpy(a->name, out->name, sizeof(a->name));
+
+ /* try to obtain supported tv norms */
+ v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+ a->capabilities = 0;
+ if (sd->ops->video && sd->ops->video->s_dv_preset)
+ a->capabilities |= V4L2_OUT_CAP_PRESETS;
+ if (sd->ops->video && sd->ops->video->s_std_output)
+ a->capabilities |= V4L2_OUT_CAP_STD;
+ a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+ return 0;
+}
+
+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;
+
+ if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+ return -EINVAL;
+
+ mutex_lock(&mdev->mutex);
+ if (mdev->n_output > 0) {
+ 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);
+
+ return 0;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+
+ mutex_lock(&mdev->mutex);
+ *p = mdev->current_output;
+ mutex_unlock(&mdev->mutex);
+
+ return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+ return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+ .vidioc_querycap = mxr_querycap,
+ /* format handling */
+ .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+ .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+ .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+ /* buffer control */
+ .vidioc_reqbufs = mxr_reqbufs,
+ .vidioc_querybuf = mxr_querybuf,
+ .vidioc_qbuf = mxr_qbuf,
+ .vidioc_dqbuf = mxr_dqbuf,
+ /* Streaming control */
+ .vidioc_streamon = mxr_streamon,
+ .vidioc_streamoff = mxr_streamoff,
+ /* Preset functions */
+ .vidioc_enum_dv_presets = mxr_enum_dv_presets,
+ .vidioc_s_dv_preset = mxr_s_dv_preset,
+ .vidioc_g_dv_preset = mxr_g_dv_preset,
+ /* analog TV standard functions */
+ .vidioc_s_std = mxr_s_std,
+ .vidioc_g_std = mxr_g_std,
+ /* Output handling */
+ .vidioc_enum_output = mxr_enum_output,
+ .vidioc_s_output = mxr_s_output,
+ .vidioc_g_output = mxr_g_output,
+ /* selection ioctls */
+ .vidioc_g_selection = mxr_g_selection,
+ .vidioc_s_selection = mxr_s_selection,
+};
+
+static int mxr_video_open(struct file *file)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret = 0;
+
+ mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+ if (mutex_lock_interruptible(&layer->mutex))
+ return -ERESTARTSYS;
+ /* assure device probe is finished */
+ wait_for_device_probe();
+ /* creating context for file descriptor */
+ ret = v4l2_fh_open(file);
+ if (ret) {
+ mxr_err(mdev, "v4l2_fh_open failed\n");
+ goto unlock;
+ }
+
+ /* leaving if layer is already initialized */
+ if (!v4l2_fh_is_singular_file(file))
+ goto unlock;
+
+ /* FIXME: should power be enabled on open? */
+ ret = mxr_power_get(mdev);
+ if (ret) {
+ mxr_err(mdev, "power on failed\n");
+ goto fail_fh_open;
+ }
+
+ ret = vb2_queue_init(&layer->vb_queue);
+ if (ret != 0) {
+ mxr_err(mdev, "failed to initialize vb2 queue\n");
+ goto fail_power;
+ }
+ /* set default format, first on the list */
+ layer->fmt = layer->fmt_array[0];
+ /* setup default geometry */
+ mxr_layer_default_geo(layer);
+ mutex_unlock(&layer->mutex);
+
+ return 0;
+
+fail_power:
+ mxr_power_put(mdev);
+
+fail_fh_open:
+ v4l2_fh_release(file);
+
+unlock:
+ mutex_unlock(&layer->mutex);
+
+ return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ unsigned int res;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ mutex_lock(&layer->mutex);
+ res = vb2_poll(&layer->vb_queue, file, wait);
+ mutex_unlock(&layer->mutex);
+ return res;
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ int ret;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ if (mutex_lock_interruptible(&layer->mutex))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&layer->vb_queue, vma);
+ mutex_unlock(&layer->mutex);
+ return ret;
+}
+
+static int mxr_video_release(struct file *file)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ mutex_lock(&layer->mutex);
+ if (v4l2_fh_is_singular_file(file)) {
+ vb2_queue_release(&layer->vb_queue);
+ mxr_power_put(layer->mdev);
+ }
+ v4l2_fh_release(file);
+ mutex_unlock(&layer->mutex);
+ return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+ .owner = THIS_MODULE,
+ .open = mxr_video_open,
+ .poll = mxr_video_poll,
+ .mmap = mxr_video_mmap,
+ .release = mxr_video_release,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+ unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[],
+ void *alloc_ctxs[])
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ const struct mxr_format *fmt = layer->fmt;
+ int i;
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_plane_pix_format planes[3];
+
+ mxr_dbg(mdev, "%s\n", __func__);
+ /* checking if format was configured */
+ if (fmt == NULL)
+ return -EINVAL;
+ mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+ mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+ layer->geo.src.full_height);
+
+ *nplanes = fmt->num_subframes;
+ for (i = 0; i < fmt->num_subframes; ++i) {
+ alloc_ctxs[i] = layer->mdev->alloc_ctx;
+ sizes[i] = planes[i].sizeimage;
+ mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
+ }
+
+ if (*nbuffers == 0)
+ *nbuffers = 1;
+
+ return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+ struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+ struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ list_add_tail(&buffer->list, &layer->enq_list);
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+ mxr_dbg(layer->mdev, "%s\n", __func__);
+ mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+ mxr_dbg(layer->mdev, "%s\n", __func__);
+ mutex_unlock(&layer->mutex);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+
+ if (count == 0) {
+ mxr_dbg(mdev, "no output buffers queued\n");
+ return -EINVAL;
+ }
+
+ /* block any changes in output configuration */
+ mxr_output_get(mdev);
+
+ mxr_layer_update_output(layer);
+ layer->ops.format_set(layer);
+ /* enabling layer in hardware */
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ layer->state = MXR_LAYER_STREAMING;
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ layer->ops.stream_set(layer, MXR_ENABLE);
+ mxr_streamer_get(mdev);
+
+ return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+ struct mxr_layer *layer = (struct mxr_layer *) arg;
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+
+ mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ if (layer->update_buf == layer->shadow_buf)
+ layer->update_buf = NULL;
+ if (layer->update_buf) {
+ vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+ layer->update_buf = NULL;
+ }
+ if (layer->shadow_buf) {
+ vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+ layer->shadow_buf = NULL;
+ }
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+ struct timer_list watchdog;
+ struct mxr_buffer *buf, *buf_tmp;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ /* reset list */
+ layer->state = MXR_LAYER_STREAMING_FINISH;
+
+ /* set all buffer to be done */
+ list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ /* give 1 seconds to complete to complete last buffers */
+ setup_timer_on_stack(&watchdog, mxr_watchdog,
+ (unsigned long)layer);
+ mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+ /* wait until all buffers are goes to done state */
+ vb2_wait_for_all_buffers(vq);
+
+ /* stop timer if all synchronization is done */
+ del_timer_sync(&watchdog);
+ destroy_timer_on_stack(&watchdog);
+
+ /* stopping hardware */
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ layer->state = MXR_LAYER_IDLE;
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ /* disabling layer in hardware */
+ layer->ops.stream_set(layer, MXR_DISABLE);
+ /* remove one streamer */
+ mxr_streamer_put(mdev);
+ /* allow changes in output configuration */
+ mxr_output_put(mdev);
+ return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buf_queue,
+ .wait_prepare = wait_unlock,
+ .wait_finish = wait_lock,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ mxr_err(mdev, "failed to register video device\n");
+ else
+ mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+ layer->vfd.name, layer->vfd.num);
+ return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+ video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+ if (layer->ops.release)
+ layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+ kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+ pr_info("video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+ int idx, char *name, struct mxr_layer_ops *ops)
+{
+ struct mxr_layer *layer;
+
+ layer = kzalloc(sizeof *layer, GFP_KERNEL);
+ if (layer == NULL) {
+ mxr_err(mdev, "not enough memory for layer.\n");
+ goto fail;
+ }
+
+ layer->mdev = mdev;
+ layer->idx = idx;
+ layer->ops = *ops;
+
+ spin_lock_init(&layer->enq_slock);
+ INIT_LIST_HEAD(&layer->enq_list);
+ mutex_init(&layer->mutex);
+
+ layer->vfd = (struct video_device) {
+ .minor = -1,
+ .release = mxr_vfd_release,
+ .fops = &mxr_fops,
+ .ioctl_ops = &mxr_ioctl_ops,
+ };
+ strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+ /* let framework control PRIORITY */
+ set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+ video_set_drvdata(&layer->vfd, layer);
+ layer->vfd.lock = &layer->mutex;
+ layer->vfd.v4l2_dev = &mdev->v4l2_dev;
+
+ layer->vb_queue = (struct vb2_queue) {
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .io_modes = VB2_MMAP | VB2_USERPTR,
+ .drv_priv = layer,
+ .buf_struct_size = sizeof(struct mxr_buffer),
+ .ops = &mxr_video_qops,
+ .mem_ops = &vb2_dma_contig_memops,
+ };
+
+ return layer;
+
+fail:
+ return NULL;
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+ struct mxr_layer *layer, unsigned long fourcc)
+{
+ int i;
+
+ for (i = 0; i < layer->fmt_array_size; ++i)
+ if (layer->fmt_array[i]->fourcc == fourcc)
+ return layer->fmt_array[i];
+ return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+ struct mxr_layer *layer, unsigned long index)
+{
+ if (index >= layer->fmt_array_size)
+ return NULL;
+ return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c
index 3d13a636877b..3d13a636877b 100644
--- a/drivers/media/video/s5p-tv/mixer_vp_layer.c
+++ b/drivers/media/platform/s5p-tv/mixer_vp_layer.c
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/platform/s5p-tv/regs-hdmi.h
index a889d1f57f28..a889d1f57f28 100644
--- a/drivers/media/video/s5p-tv/regs-hdmi.h
+++ b/drivers/media/platform/s5p-tv/regs-hdmi.h
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/platform/s5p-tv/regs-mixer.h
index 158abb43d0a4..158abb43d0a4 100644
--- a/drivers/media/video/s5p-tv/regs-mixer.h
+++ b/drivers/media/platform/s5p-tv/regs-mixer.h
diff --git a/drivers/media/platform/s5p-tv/regs-sdo.h b/drivers/media/platform/s5p-tv/regs-sdo.h
new file mode 100644
index 000000000000..6f22fbfe2f6c
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-sdo.h
@@ -0,0 +1,63 @@
+/* drivers/media/platform/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * 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 SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON 0x0000
+#define SDO_CONFIG 0x0008
+#define SDO_VBI 0x0014
+#define SDO_DAC 0x003C
+#define SDO_CCCON 0x0180
+#define SDO_IRQ 0x0280
+#define SDO_IRQMASK 0x0284
+#define SDO_VERSION 0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET (1 << 4)
+#define SDO_TVOUT_CLOCK_READY (1 << 1)
+#define SDO_TVOUT_CLOCK_ON (1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE (1 << 4)
+#define SDO_NTSC_M 0
+#define SDO_PAL_M 1
+#define SDO_PAL_BGHID 2
+#define SDO_PAL_N 3
+#define SDO_PAL_NC 4
+#define SDO_NTSC_443 8
+#define SDO_PAL_60 9
+#define SDO_STANDARD_MASK 0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS (1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK (3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC (1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF (1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND (1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/platform/s5p-tv/regs-vp.h
index 6c63984e11e8..6c63984e11e8 100644
--- a/drivers/media/video/s5p-tv/regs-vp.h
+++ b/drivers/media/platform/s5p-tv/regs-vp.h
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
new file mode 100644
index 000000000000..ad68bbed014e
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -0,0 +1,448 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+#define SDO_DEFAULT_STD V4L2_STD_PAL
+
+struct sdo_format {
+ v4l2_std_id id;
+ /* all modes are 720 pixels wide */
+ unsigned int height;
+ unsigned int cookie;
+};
+
+struct sdo_device {
+ /** pointer to device parent */
+ struct device *dev;
+ /** base address of SDO registers */
+ void __iomem *regs;
+ /** SDO interrupt */
+ unsigned int irq;
+ /** DAC source clock */
+ struct clk *sclk_dac;
+ /** DAC clock */
+ struct clk *dac;
+ /** DAC physical interface */
+ struct clk *dacphy;
+ /** clock for control of VPLL */
+ struct clk *fout_vpll;
+ /** regulator for SDO IP power */
+ struct regulator *vdac;
+ /** regulator for SDO plug detection */
+ struct regulator *vdet;
+ /** subdev used as device interface */
+ struct v4l2_subdev sd;
+ /** current format */
+ const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+ u32 old = readl(sdev->regs + reg_id);
+ value = (value & mask) | (old & ~mask);
+ writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+ writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+ return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+ struct sdo_device *sdev = dev_data;
+
+ /* clear interrupt */
+ sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+ return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+ dev_info(sdev->dev, #reg_id " = %08x\n", \
+ sdo_read(sdev, reg_id))
+
+ DBGREG(SDO_CLKCON);
+ DBGREG(SDO_CONFIG);
+ DBGREG(SDO_VBI);
+ DBGREG(SDO_DAC);
+ DBGREG(SDO_IRQ);
+ DBGREG(SDO_IRQMASK);
+ DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+ { V4L2_STD_PAL_N, .height = 576, .cookie = SDO_PAL_N },
+ { V4L2_STD_PAL_Nc, .height = 576, .cookie = SDO_PAL_NC },
+ { V4L2_STD_PAL_M, .height = 480, .cookie = SDO_PAL_M },
+ { V4L2_STD_PAL_60, .height = 480, .cookie = SDO_PAL_60 },
+ { V4L2_STD_NTSC_443, .height = 480, .cookie = SDO_NTSC_443 },
+ { V4L2_STD_PAL, .height = 576, .cookie = SDO_PAL_BGHID },
+ { V4L2_STD_NTSC_M, .height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+ if (sdo_format[i].id & id)
+ return &sdo_format[i];
+ return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+ V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+ V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+ return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ const struct sdo_format *fmt;
+ fmt = sdo_find_format(std);
+ if (fmt == NULL)
+ return -EINVAL;
+ sdev->fmt = fmt;
+ return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ *std = sd_to_sdev(sd)->fmt->id;
+ return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ if (!sdev->fmt)
+ return -ENXIO;
+ /* all modes are 720 pixels wide */
+ fmt->width = 720;
+ fmt->height = sdev->fmt->height;
+ fmt->code = V4L2_MBUS_FMT_FIXED;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
+ return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ struct device *dev = sdev->dev;
+ int ret;
+
+ dev_info(dev, "sdo_s_power(%d)\n", on);
+
+ if (on)
+ ret = pm_runtime_get_sync(dev);
+ else
+ ret = pm_runtime_put_sync(dev);
+
+ /* only values < 0 indicate errors */
+ return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+ /* set proper clock for Timing Generator */
+ clk_set_rate(sdev->fout_vpll, 54000000);
+ dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+ clk_get_rate(sdev->fout_vpll));
+ /* enable clock in SDO */
+ sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+ clk_enable(sdev->dacphy);
+ /* enable DAC */
+ sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+ sdo_reg_debug(sdev);
+ return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+ int tries;
+
+ sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+ clk_disable(sdev->dacphy);
+ sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+ for (tries = 100; tries; --tries) {
+ if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+ break;
+ mdelay(1);
+ }
+ if (tries == 0)
+ dev_err(sdev->dev, "failed to stop streaming\n");
+ return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+ .s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+ .s_std_output = sdo_s_std_output,
+ .g_std_output = sdo_g_std_output,
+ .g_tvnorms_output = sdo_g_tvnorms_output,
+ .g_mbus_fmt = sdo_g_mbus_fmt,
+ .s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+ .core = &sdo_sd_core_ops,
+ .video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ dev_info(dev, "suspend\n");
+ regulator_disable(sdev->vdet);
+ regulator_disable(sdev->vdac);
+ clk_disable(sdev->sclk_dac);
+ return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ dev_info(dev, "resume\n");
+ clk_enable(sdev->sclk_dac);
+ regulator_enable(sdev->vdac);
+ regulator_enable(sdev->vdet);
+
+ /* software reset */
+ sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+ mdelay(10);
+ sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+ /* setting TV mode */
+ sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+ /* XXX: forcing interlaced mode using undocumented bit */
+ sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+ /* turn all VBI off */
+ sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+ SDO_CVBS_CLOSED_CAPTION_MASK);
+ /* turn all post processing off */
+ sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+ SDO_COMPENSATION_CVBS_COMP_OFF);
+ sdo_reg_debug(sdev);
+ return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+ .runtime_suspend = sdo_runtime_suspend,
+ .runtime_resume = sdo_runtime_resume,
+};
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sdo_device *sdev;
+ struct resource *res;
+ int ret = 0;
+ struct clk *sclk_vpll;
+
+ dev_info(dev, "probe start\n");
+ sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
+ if (!sdev) {
+ dev_err(dev, "not enough memory.\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ sdev->dev = dev;
+
+ /* mapping registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ 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;
+ }
+
+ /* acquiring interrupt */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+ 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;
+ }
+ sdev->irq = res->start;
+
+ /* acquire clocks */
+ sdev->sclk_dac = clk_get(dev, "sclk_dac");
+ if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+ dev_err(dev, "failed to get clock 'sclk_dac'\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+ sdev->dac = clk_get(dev, "dac");
+ if (IS_ERR_OR_NULL(sdev->dac)) {
+ dev_err(dev, "failed to get clock 'dac'\n");
+ ret = -ENXIO;
+ goto fail_sclk_dac;
+ }
+ sdev->dacphy = clk_get(dev, "dacphy");
+ if (IS_ERR_OR_NULL(sdev->dacphy)) {
+ dev_err(dev, "failed to get clock 'dacphy'\n");
+ ret = -ENXIO;
+ goto fail_dac;
+ }
+ sclk_vpll = clk_get(dev, "sclk_vpll");
+ if (IS_ERR_OR_NULL(sclk_vpll)) {
+ dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+ ret = -ENXIO;
+ goto fail_dacphy;
+ }
+ clk_set_parent(sdev->sclk_dac, sclk_vpll);
+ clk_put(sclk_vpll);
+ sdev->fout_vpll = clk_get(dev, "fout_vpll");
+ if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+ dev_err(dev, "failed to get clock 'fout_vpll'\n");
+ goto fail_dacphy;
+ }
+ dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+ /* acquire regulator */
+ sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
+ if (IS_ERR_OR_NULL(sdev->vdac)) {
+ dev_err(dev, "failed to get regulator 'vdac'\n");
+ goto fail_fout_vpll;
+ }
+ sdev->vdet = devm_regulator_get(dev, "vdet");
+ if (IS_ERR_OR_NULL(sdev->vdet)) {
+ dev_err(dev, "failed to get regulator 'vdet'\n");
+ goto fail_fout_vpll;
+ }
+
+ /* enable gate for dac clock, because mixer uses it */
+ clk_enable(sdev->dac);
+
+ /* configure power management */
+ pm_runtime_enable(dev);
+
+ /* configuration of interface subdevice */
+ v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
+ sdev->sd.owner = THIS_MODULE;
+ strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+
+ /* set default format */
+ sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+ BUG_ON(sdev->fmt == NULL);
+
+ /* keeping subdev in device's private for use by other drivers */
+ dev_set_drvdata(dev, &sdev->sd);
+
+ dev_info(dev, "probe succeeded\n");
+ return 0;
+
+fail_fout_vpll:
+ clk_put(sdev->fout_vpll);
+fail_dacphy:
+ clk_put(sdev->dacphy);
+fail_dac:
+ clk_put(sdev->dac);
+fail_sclk_dac:
+ clk_put(sdev->sclk_dac);
+fail:
+ dev_info(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ pm_runtime_disable(&pdev->dev);
+ clk_disable(sdev->dac);
+ clk_put(sdev->fout_vpll);
+ clk_put(sdev->dacphy);
+ clk_put(sdev->dac);
+ clk_put(sdev->sclk_dac);
+
+ dev_info(&pdev->dev, "remove successful\n");
+ return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+ .probe = sdo_probe,
+ .remove = __devexit_p(sdo_remove),
+ .driver = {
+ .name = "s5p-sdo",
+ .owner = THIS_MODULE,
+ .pm = &sdo_pm_ops,
+ }
+};
+
+module_platform_driver(sdo_driver);
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
new file mode 100644
index 000000000000..716d4846f8bd
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -0,0 +1,413 @@
+/*
+ * 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 = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ dev_err(dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ ctx->client = client;
+
+ ctx->power = devm_regulator_get(dev, "hdmi-en");
+ if (IS_ERR(ctx->power)) {
+ dev_err(dev, "failed to acquire regulator hdmi-en\n");
+ return PTR_ERR(ctx->power);
+ }
+
+ 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");
+ return ret;
+ }
+
+ 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:
+ 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);
+
+ 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,
+};
+
+module_i2c_driver(sii9234_driver);
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
new file mode 100644
index 000000000000..9f62fd89ab57
--- /dev/null
+++ b/drivers/media/platform/sh_vou.c
@@ -0,0 +1,1510 @@
+/*
+ * SuperH Video Output Unit (VOU) driver
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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/dma-mapping.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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/sh_vou.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf-dma-contig.h>
+
+/* Mirror addresses are not available for all registers */
+#define VOUER 0
+#define VOUCR 4
+#define VOUSTR 8
+#define VOUVCR 0xc
+#define VOUISR 0x10
+#define VOUBCR 0x14
+#define VOUDPR 0x18
+#define VOUDSR 0x1c
+#define VOUVPR 0x20
+#define VOUIR 0x24
+#define VOUSRR 0x28
+#define VOUMSR 0x2c
+#define VOUHIR 0x30
+#define VOUDFR 0x34
+#define VOUAD1R 0x38
+#define VOUAD2R 0x3c
+#define VOUAIR 0x40
+#define VOUSWR 0x44
+#define VOURCR 0x48
+#define VOURPR 0x50
+
+enum sh_vou_status {
+ SH_VOU_IDLE,
+ SH_VOU_INITIALISING,
+ SH_VOU_RUNNING,
+};
+
+#define VOU_MAX_IMAGE_WIDTH 720
+#define VOU_MAX_IMAGE_HEIGHT 576
+
+struct sh_vou_device {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vdev;
+ atomic_t use_count;
+ struct sh_vou_pdata *pdata;
+ spinlock_t lock;
+ void __iomem *base;
+ /* State information */
+ struct v4l2_pix_format pix;
+ struct v4l2_rect rect;
+ struct list_head queue;
+ v4l2_std_id std;
+ int pix_idx;
+ struct videobuf_buffer *active;
+ enum sh_vou_status status;
+ struct mutex fop_lock;
+};
+
+struct sh_vou_file {
+ struct videobuf_queue vbq;
+};
+
+/* Register access routines for sides A, B and mirror addresses */
+static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value)
+{
+ __raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value)
+{
+ __raw_writel(value, vou_dev->base + reg);
+ __raw_writel(value, vou_dev->base + reg + 0x1000);
+}
+
+static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value)
+{
+ __raw_writel(value, vou_dev->base + reg + 0x2000);
+}
+
+static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
+{
+ return __raw_readl(vou_dev->base + reg);
+}
+
+static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value, u32 mask)
+{
+ u32 old = __raw_readl(vou_dev->base + reg);
+
+ value = (value & mask) | (old & ~mask);
+ __raw_writel(value, vou_dev->base + reg);
+}
+
+static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value, u32 mask)
+{
+ sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
+}
+
+static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
+ u32 value, u32 mask)
+{
+ sh_vou_reg_a_set(vou_dev, reg, value, mask);
+ sh_vou_reg_b_set(vou_dev, reg, value, mask);
+}
+
+struct sh_vou_fmt {
+ u32 pfmt;
+ char *desc;
+ unsigned char bpp;
+ unsigned char rgb;
+ unsigned char yf;
+ unsigned char pkf;
+};
+
+/* Further pixel formats can be added */
+static struct sh_vou_fmt vou_fmt[] = {
+ {
+ .pfmt = V4L2_PIX_FMT_NV12,
+ .bpp = 12,
+ .desc = "YVU420 planar",
+ .yf = 0,
+ .rgb = 0,
+ },
+ {
+ .pfmt = V4L2_PIX_FMT_NV16,
+ .bpp = 16,
+ .desc = "YVYU planar",
+ .yf = 1,
+ .rgb = 0,
+ },
+ {
+ .pfmt = V4L2_PIX_FMT_RGB24,
+ .bpp = 24,
+ .desc = "RGB24",
+ .pkf = 2,
+ .rgb = 1,
+ },
+ {
+ .pfmt = V4L2_PIX_FMT_RGB565,
+ .bpp = 16,
+ .desc = "RGB565",
+ .pkf = 3,
+ .rgb = 1,
+ },
+ {
+ .pfmt = V4L2_PIX_FMT_RGB565X,
+ .bpp = 16,
+ .desc = "RGB565 byteswapped",
+ .pkf = 3,
+ .rgb = 1,
+ },
+};
+
+static void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
+ struct videobuf_buffer *vb)
+{
+ dma_addr_t addr1, addr2;
+
+ addr1 = videobuf_to_dma_contig(vb);
+ switch (vou_dev->pix.pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
+ break;
+ default:
+ addr2 = 0;
+ }
+
+ sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
+ sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
+}
+
+static void sh_vou_stream_start(struct sh_vou_device *vou_dev,
+ struct videobuf_buffer *vb)
+{
+ unsigned int row_coeff;
+#ifdef __LITTLE_ENDIAN
+ u32 dataswap = 7;
+#else
+ u32 dataswap = 0;
+#endif
+
+ switch (vou_dev->pix.pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ row_coeff = 1;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ dataswap ^= 1;
+ case V4L2_PIX_FMT_RGB565X:
+ row_coeff = 2;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ row_coeff = 3;
+ break;
+ }
+
+ sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
+ sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
+ sh_vou_schedule_next(vou_dev, vb);
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ BUG_ON(in_interrupt());
+
+ /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
+ videobuf_waiton(vq, vb, 0, 0);
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* Locking: caller holds fop_lock mutex */
+static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct video_device *vdev = vq->priv_data;
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width *
+ vou_dev->pix.height / 8;
+
+ if (*count < 2)
+ *count = 2;
+
+ /* Taking into account maximum frame size, *count will stay >= 2 */
+ if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
+ *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
+
+ dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
+
+ return 0;
+}
+
+/* Locking: caller holds fop_lock mutex */
+static int sh_vou_buf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct video_device *vdev = vq->priv_data;
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct v4l2_pix_format *pix = &vou_dev->pix;
+ int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
+ int ret;
+
+ dev_dbg(vq->dev, "%s()\n", __func__);
+
+ if (vb->width != pix->width ||
+ vb->height != pix->height ||
+ vb->field != pix->field) {
+ vb->width = pix->width;
+ vb->height = pix->height;
+ vb->field = field;
+ if (vb->state != VIDEOBUF_NEEDS_INIT)
+ free_buffer(vq, vb);
+ }
+
+ vb->size = vb->height * bytes_per_line;
+ if (vb->baddr && vb->bsize < vb->size) {
+ /* User buffer too small */
+ dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
+ vb->bsize, vb->baddr);
+ return -EINVAL;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret < 0) {
+ dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n",
+ vb->memory, ret);
+ return ret;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ dev_dbg(vq->dev,
+ "%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
+ __func__, vou_dev->pix_idx, bytes_per_line,
+ videobuf_to_dma_contig(vb), vb->memory, vb->state);
+
+ return 0;
+}
+
+/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
+static void sh_vou_buf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct video_device *vdev = vq->priv_data;
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ dev_dbg(vq->dev, "%s()\n", __func__);
+
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &vou_dev->queue);
+
+ if (vou_dev->status == SH_VOU_RUNNING) {
+ return;
+ } else if (!vou_dev->active) {
+ vou_dev->active = vb;
+ /* Start from side A: we use mirror addresses, so, set B */
+ sh_vou_reg_a_write(vou_dev, VOURPR, 1);
+ dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
+ sh_vou_reg_a_read(vou_dev, VOUSTR));
+ sh_vou_schedule_next(vou_dev, vb);
+ /* Only activate VOU after the second buffer */
+ } else if (vou_dev->active->queue.next == &vb->queue) {
+ /* Second buffer - initialise register side B */
+ sh_vou_reg_a_write(vou_dev, VOURPR, 0);
+ sh_vou_stream_start(vou_dev, vb);
+
+ /* Register side switching with frame VSYNC */
+ sh_vou_reg_a_write(vou_dev, VOURCR, 5);
+ dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
+ sh_vou_reg_a_read(vou_dev, VOUSTR));
+
+ /* Enable End-of-Frame (VSYNC) interrupts */
+ sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
+ /* Two buffers on the queue - activate the hardware */
+
+ vou_dev->status = SH_VOU_RUNNING;
+ sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
+ }
+}
+
+static void sh_vou_buf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct video_device *vdev = vq->priv_data;
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ unsigned long flags;
+
+ dev_dbg(vq->dev, "%s()\n", __func__);
+
+ spin_lock_irqsave(&vou_dev->lock, flags);
+
+ if (vou_dev->active == vb) {
+ /* disable output */
+ sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+ /* ...but the current frame will complete */
+ sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+ vou_dev->active = NULL;
+ }
+
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) {
+ vb->state = VIDEOBUF_ERROR;
+ list_del(&vb->queue);
+ }
+
+ spin_unlock_irqrestore(&vou_dev->lock, flags);
+
+ free_buffer(vq, vb);
+}
+
+static struct videobuf_queue_ops sh_vou_video_qops = {
+ .buf_setup = sh_vou_buf_setup,
+ .buf_prepare = sh_vou_buf_prepare,
+ .buf_queue = sh_vou_buf_queue,
+ .buf_release = sh_vou_buf_release,
+};
+
+/* Video IOCTLs */
+static int sh_vou_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+/* Enumerate formats, that the device can accept from the user */
+static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ if (fmt->index >= ARRAY_SIZE(vou_fmt))
+ return -EINVAL;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ strlcpy(fmt->description, vou_fmt[fmt->index].desc,
+ sizeof(fmt->description));
+ fmt->pixelformat = vou_fmt[fmt->index].pfmt;
+
+ return 0;
+}
+
+static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ fmt->fmt.pix = vou_dev->pix;
+
+ return 0;
+}
+
+static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
+static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
+static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
+static const unsigned char vou_scale_v_num[] = {1, 2, 4};
+static const unsigned char vou_scale_v_den[] = {1, 1, 1};
+static const unsigned char vou_scale_v_fld[] = {0, 1};
+
+static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
+ int pix_idx, int w_idx, int h_idx)
+{
+ struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
+ unsigned int black_left, black_top, width_max, height_max,
+ frame_in_height, frame_out_height, frame_out_top;
+ struct v4l2_rect *rect = &vou_dev->rect;
+ struct v4l2_pix_format *pix = &vou_dev->pix;
+ u32 vouvcr = 0, dsr_h, dsr_v;
+
+ if (vou_dev->std & V4L2_STD_525_60) {
+ width_max = 858;
+ height_max = 262;
+ } else {
+ width_max = 864;
+ height_max = 312;
+ }
+
+ frame_in_height = pix->height / 2;
+ frame_out_height = rect->height / 2;
+ frame_out_top = rect->top / 2;
+
+ /*
+ * Cropping scheme: max useful image is 720x480, and the total video
+ * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
+ * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
+ * of which the first 33 / 25 clocks HSYNC must be held active. This
+ * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
+ * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
+ * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
+ * beyond DSR, specified on the left and top by the VPR register "black
+ * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
+ * at 138 / 144 : 20, because that's the HSYNC timing, that our first
+ * client requires, and that's exactly what leaves us 720 pixels for the
+ * image; we leave VPR[VVP] at default 20 for now, because the client
+ * doesn't seem to have any special requirements for it. Otherwise we
+ * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
+ * the selected standard, and DPR and DSR are selected according to
+ * cropping. Q: how does the client detect the first valid line? Does
+ * HSYNC stay inactive during invalid (black) lines?
+ */
+ black_left = width_max - VOU_MAX_IMAGE_WIDTH;
+ black_top = 20;
+
+ dsr_h = rect->width + rect->left;
+ dsr_v = frame_out_height + frame_out_top;
+
+ dev_dbg(vou_dev->v4l2_dev.dev,
+ "image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
+ pix->width, frame_in_height, black_left, black_top,
+ rect->left, frame_out_top, dsr_h, dsr_v);
+
+ /* VOUISR height - half of a frame height in frame mode */
+ sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
+ sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
+ sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
+ sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
+
+ /*
+ * if necessary, we could set VOUHIR to
+ * max(black_left + dsr_h, width_max) here
+ */
+
+ if (w_idx)
+ vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
+ if (h_idx)
+ vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
+
+ /* To produce a colour bar for testing set bit 23 of VOUVCR */
+ sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
+ sh_vou_reg_ab_write(vou_dev, VOUDFR,
+ fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
+}
+
+struct sh_vou_geometry {
+ struct v4l2_rect output;
+ unsigned int in_width;
+ unsigned int in_height;
+ int scale_idx_h;
+ int scale_idx_v;
+};
+
+/*
+ * Find input geometry, that we can use to produce output, closest to the
+ * requested rectangle, using VOU scaling
+ */
+static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+ /* The compiler cannot know, that best and idx will indeed be set */
+ unsigned int best_err = UINT_MAX, best = 0, img_height_max;
+ int i, idx = 0;
+
+ if (std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
+ /* Image width must be a multiple of 4 */
+ v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+ &geo->in_height, 0, img_height_max, 1, 0);
+
+ /* Select scales to come as close as possible to the output image */
+ for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
+ unsigned int err;
+ unsigned int found = geo->output.width * vou_scale_h_den[i] /
+ vou_scale_h_num[i];
+
+ if (found > VOU_MAX_IMAGE_WIDTH)
+ /* scales increase */
+ break;
+
+ err = abs(found - geo->in_width);
+ if (err < best_err) {
+ best_err = err;
+ idx = i;
+ best = found;
+ }
+ if (!err)
+ break;
+ }
+
+ geo->in_width = best;
+ geo->scale_idx_h = idx;
+
+ best_err = UINT_MAX;
+
+ /* This loop can be replaced with one division */
+ for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
+ unsigned int err;
+ unsigned int found = geo->output.height * vou_scale_v_den[i] /
+ vou_scale_v_num[i];
+
+ if (found > img_height_max)
+ /* scales increase */
+ break;
+
+ err = abs(found - geo->in_height);
+ if (err < best_err) {
+ best_err = err;
+ idx = i;
+ best = found;
+ }
+ if (!err)
+ break;
+ }
+
+ geo->in_height = best;
+ geo->scale_idx_v = idx;
+}
+
+/*
+ * Find output geometry, that we can produce, using VOU scaling, closest to
+ * the requested rectangle
+ */
+static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
+{
+ unsigned int best_err = UINT_MAX, best, width_max, height_max,
+ img_height_max;
+ int i, idx;
+
+ if (std & V4L2_STD_525_60) {
+ width_max = 858;
+ height_max = 262 * 2;
+ img_height_max = 480;
+ } else {
+ width_max = 864;
+ height_max = 312 * 2;
+ img_height_max = 576;
+ }
+
+ /* Select scales to come as close as possible to the output image */
+ for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
+ unsigned int err;
+ unsigned int found = geo->in_width * vou_scale_h_num[i] /
+ vou_scale_h_den[i];
+
+ if (found > VOU_MAX_IMAGE_WIDTH)
+ /* scales increase */
+ break;
+
+ err = abs(found - geo->output.width);
+ if (err < best_err) {
+ best_err = err;
+ idx = i;
+ best = found;
+ }
+ if (!err)
+ break;
+ }
+
+ geo->output.width = best;
+ geo->scale_idx_h = idx;
+ if (geo->output.left + best > width_max)
+ geo->output.left = width_max - best;
+
+ pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
+ vou_scale_h_num[idx], vou_scale_h_den[idx], best);
+
+ best_err = UINT_MAX;
+
+ /* This loop can be replaced with one division */
+ for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
+ unsigned int err;
+ unsigned int found = geo->in_height * vou_scale_v_num[i] /
+ vou_scale_v_den[i];
+
+ if (found > img_height_max)
+ /* scales increase */
+ break;
+
+ err = abs(found - geo->output.height);
+ if (err < best_err) {
+ best_err = err;
+ idx = i;
+ best = found;
+ }
+ if (!err)
+ break;
+ }
+
+ geo->output.height = best;
+ geo->scale_idx_v = idx;
+ if (geo->output.top + best > height_max)
+ geo->output.top = height_max - best;
+
+ pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
+ vou_scale_v_num[idx], vou_scale_v_den[idx], best);
+}
+
+static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ unsigned int img_height_max;
+ int pix_idx;
+ struct sh_vou_geometry geo;
+ struct v4l2_mbus_framefmt mbfmt = {
+ /* Revisit: is this the correct code? */
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .field = V4L2_FIELD_INTERLACED,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ };
+ int ret;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+ vou_dev->rect.width, vou_dev->rect.height,
+ pix->width, pix->height);
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
+ if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
+ break;
+
+ if (pix_idx == ARRAY_SIZE(vou_fmt))
+ return -EINVAL;
+
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
+ /* Image width must be a multiple of 4 */
+ v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
+ &pix->height, 0, img_height_max, 1, 0);
+
+ geo.in_width = pix->width;
+ geo.in_height = pix->height;
+ geo.output = vou_dev->rect;
+
+ vou_adjust_output(&geo, vou_dev->std);
+
+ mbfmt.width = geo.output.width;
+ mbfmt.height = geo.output.height;
+ ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+ s_mbus_fmt, &mbfmt);
+ /* Must be implemented, so, don't check for -ENOIOCTLCMD */
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
+ geo.output.width, geo.output.height, mbfmt.width, mbfmt.height);
+
+ /* Sanity checks */
+ if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+ return -EIO;
+
+ if (mbfmt.width != geo.output.width ||
+ mbfmt.height != geo.output.height) {
+ geo.output.width = mbfmt.width;
+ geo.output.height = mbfmt.height;
+
+ vou_adjust_input(&geo, vou_dev->std);
+ }
+
+ /* We tried to preserve output rectangle, but it could have changed */
+ vou_dev->rect = geo.output;
+ pix->width = geo.in_width;
+ pix->height = geo.in_height;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
+ pix->width, pix->height);
+
+ vou_dev->pix_idx = pix_idx;
+
+ vou_dev->pix = *pix;
+
+ sh_vou_configure_geometry(vou_dev, pix_idx,
+ geo.scale_idx_h, geo.scale_idx_v);
+
+ return 0;
+}
+
+static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct sh_vou_file *vou_file = priv;
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ int i;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ pix->field = V4L2_FIELD_NONE;
+
+ v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+ &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+
+ for (i = 0; ARRAY_SIZE(vou_fmt); i++)
+ if (vou_fmt[i].pfmt == pix->pixelformat)
+ return 0;
+
+ pix->pixelformat = vou_fmt[0].pfmt;
+
+ return 0;
+}
+
+static int sh_vou_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ return videobuf_reqbufs(&vou_file->vbq, req);
+}
+
+static int sh_vou_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ return videobuf_querybuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ return videobuf_qbuf(&vou_file->vbq, b);
+}
+
+static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int sh_vou_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = priv;
+ int ret;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
+ video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ /* This calls our .buf_queue() (== sh_vou_buf_queue) */
+ return videobuf_streamon(&vou_file->vbq);
+}
+
+static int sh_vou_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ /*
+ * This calls buf_release from host driver's videobuf_queue_ops for all
+ * remaining buffers. When the last buffer is freed, stop streaming
+ */
+ videobuf_streamoff(&vou_file->vbq);
+ v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0);
+
+ return 0;
+}
+
+static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
+{
+ switch (bus_fmt) {
+ default:
+ pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n",
+ __func__, bus_fmt);
+ case SH_VOU_BUS_8BIT:
+ return 1;
+ case SH_VOU_BUS_16BIT:
+ return 0;
+ case SH_VOU_BUS_BT656:
+ return 3;
+ }
+}
+
+static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ int ret;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
+
+ if (*std_id & ~vdev->tvnorms)
+ return -EINVAL;
+
+ ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+ s_std_output, *std_id);
+ /* Shall we continue, if the subdev doesn't support .s_std_output()? */
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ if (*std_id & V4L2_STD_525_60)
+ sh_vou_reg_ab_set(vou_dev, VOUCR,
+ sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
+ else
+ sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
+
+ vou_dev->std = *std_id;
+
+ return 0;
+}
+
+static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+ *std = vou_dev->std;
+
+ return 0;
+}
+
+static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+ a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ a->c = vou_dev->rect;
+
+ return 0;
+}
+
+/* Assume a dull encoder, do all the work ourselves. */
+static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
+ struct v4l2_pix_format *pix = &vou_dev->pix;
+ struct sh_vou_geometry geo;
+ struct v4l2_mbus_framefmt mbfmt = {
+ /* Revisit: is this the correct code? */
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .field = V4L2_FIELD_INTERLACED,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ };
+ unsigned int img_height_max;
+ int ret;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
+ rect->width, rect->height, rect->left, rect->top);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
+ v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
+ &rect->height, 0, img_height_max, 1, 0);
+
+ if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
+ rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
+
+ if (rect->height + rect->top > img_height_max)
+ rect->top = img_height_max - rect->height;
+
+ geo.output = *rect;
+ geo.in_width = pix->width;
+ geo.in_height = pix->height;
+
+ /* Configure the encoder one-to-one, position at 0, ignore errors */
+ sd_crop.c.width = geo.output.width;
+ sd_crop.c.height = geo.output.height;
+ /*
+ * We first issue a S_CROP, so that the subsequent S_FMT delivers the
+ * final encoder configuration.
+ */
+ v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+ s_crop, &sd_crop);
+ mbfmt.width = geo.output.width;
+ mbfmt.height = geo.output.height;
+ ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
+ s_mbus_fmt, &mbfmt);
+ /* Must be implemented, so, don't check for -ENOIOCTLCMD */
+ if (ret < 0)
+ return ret;
+
+ /* Sanity checks */
+ if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+ return -EIO;
+
+ geo.output.width = mbfmt.width;
+ geo.output.height = mbfmt.height;
+
+ /*
+ * No down-scaling. According to the API, current call has precedence:
+ * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
+ */
+ vou_adjust_input(&geo, vou_dev->std);
+
+ /* We tried to preserve output rectangle, but it could have changed */
+ vou_dev->rect = geo.output;
+ pix->width = geo.in_width;
+ pix->height = geo.in_height;
+
+ sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
+ geo.scale_idx_h, geo.scale_idx_v);
+
+ return 0;
+}
+
+/*
+ * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle
+ * is the initial register values, height takes the interlaced format into
+ * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can
+ * actually only meaningfully contain values <= 720 and <= 240 respectively, and
+ * not <= 864 and <= 312.
+ */
+static int sh_vou_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *a)
+{
+ struct sh_vou_file *vou_file = priv;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = VOU_MAX_IMAGE_WIDTH;
+ a->bounds.height = VOU_MAX_IMAGE_HEIGHT;
+ /* Default = max, set VOUDPR = 0, which is not hardware default */
+ a->defrect.left = 0;
+ a->defrect.top = 0;
+ a->defrect.width = VOU_MAX_IMAGE_WIDTH;
+ a->defrect.height = VOU_MAX_IMAGE_HEIGHT;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static irqreturn_t sh_vou_isr(int irq, void *dev_id)
+{
+ struct sh_vou_device *vou_dev = dev_id;
+ static unsigned long j;
+ struct videobuf_buffer *vb;
+ static int cnt;
+ static int side;
+ u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
+ u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
+
+ if (!(irq_status & 0x300)) {
+ if (printk_timed_ratelimit(&j, 500))
+ dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
+ irq_status);
+ return IRQ_NONE;
+ }
+
+ spin_lock(&vou_dev->lock);
+ if (!vou_dev->active || list_empty(&vou_dev->queue)) {
+ if (printk_timed_ratelimit(&j, 500))
+ dev_warn(vou_dev->v4l2_dev.dev,
+ "IRQ without active buffer: %x!\n", irq_status);
+ /* Just ack: buf_release will disable further interrupts */
+ sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
+ spin_unlock(&vou_dev->lock);
+ return IRQ_HANDLED;
+ }
+
+ masked = ~(0x300 & irq_status) & irq_status & 0x30304;
+ dev_dbg(vou_dev->v4l2_dev.dev,
+ "IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
+ irq_status, masked, vou_status, cnt);
+
+ cnt++;
+ side = vou_status & 0x10000;
+
+ /* Clear only set interrupts */
+ sh_vou_reg_a_write(vou_dev, VOUIR, masked);
+
+ vb = vou_dev->active;
+ list_del(&vb->queue);
+
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+
+ if (list_empty(&vou_dev->queue)) {
+ /* Stop VOU */
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n",
+ __func__, cnt);
+ sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
+ vou_dev->active = NULL;
+ vou_dev->status = SH_VOU_INITIALISING;
+ /* Disable End-of-Frame (VSYNC) interrupts */
+ sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
+ spin_unlock(&vou_dev->lock);
+ return IRQ_HANDLED;
+ }
+
+ vou_dev->active = list_entry(vou_dev->queue.next,
+ struct videobuf_buffer, queue);
+
+ if (vou_dev->active->queue.next != &vou_dev->queue) {
+ struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next,
+ struct videobuf_buffer, queue);
+ sh_vou_schedule_next(vou_dev, new);
+ }
+
+ spin_unlock(&vou_dev->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
+{
+ struct sh_vou_pdata *pdata = vou_dev->pdata;
+ u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
+ int i = 100;
+
+ /* Disable all IRQs */
+ sh_vou_reg_a_write(vou_dev, VOUIR, 0);
+
+ /* Reset VOU interfaces - registers unaffected */
+ sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
+ while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
+ udelay(1);
+
+ if (!i)
+ return -ETIMEDOUT;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
+
+ if (pdata->flags & SH_VOU_PCLK_FALLING)
+ voucr |= 1 << 28;
+ if (pdata->flags & SH_VOU_HSYNC_LOW)
+ voucr |= 1 << 27;
+ if (pdata->flags & SH_VOU_VSYNC_LOW)
+ voucr |= 1 << 26;
+ sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
+
+ /* Manual register side switching at first */
+ sh_vou_reg_a_write(vou_dev, VOURCR, 4);
+ /* Default - fixed HSYNC length, can be made configurable is required */
+ sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
+
+ return 0;
+}
+
+/* File operations */
+static int sh_vou_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
+ GFP_KERNEL);
+
+ if (!vou_file)
+ return -ENOMEM;
+
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
+
+ file->private_data = vou_file;
+
+ if (mutex_lock_interruptible(&vou_dev->fop_lock))
+ return -ERESTARTSYS;
+ if (atomic_inc_return(&vou_dev->use_count) == 1) {
+ int ret;
+ /* First open */
+ vou_dev->status = SH_VOU_INITIALISING;
+ pm_runtime_get_sync(vdev->v4l2_dev->dev);
+ ret = sh_vou_hw_init(vou_dev);
+ if (ret < 0) {
+ atomic_dec(&vou_dev->use_count);
+ pm_runtime_put(vdev->v4l2_dev->dev);
+ vou_dev->status = SH_VOU_IDLE;
+ mutex_unlock(&vou_dev->fop_lock);
+ return ret;
+ }
+ }
+
+ videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops,
+ vou_dev->v4l2_dev.dev, &vou_dev->lock,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), vdev,
+ &vou_dev->fop_lock);
+ mutex_unlock(&vou_dev->fop_lock);
+
+ return 0;
+}
+
+static int sh_vou_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = file->private_data;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ if (!atomic_dec_return(&vou_dev->use_count)) {
+ mutex_lock(&vou_dev->fop_lock);
+ /* Last close */
+ vou_dev->status = SH_VOU_IDLE;
+ sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
+ pm_runtime_put(vdev->v4l2_dev->dev);
+ mutex_unlock(&vou_dev->fop_lock);
+ }
+
+ file->private_data = NULL;
+ kfree(vou_file);
+
+ return 0;
+}
+
+static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = file->private_data;
+ int ret;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ if (mutex_lock_interruptible(&vou_dev->fop_lock))
+ return -ERESTARTSYS;
+ ret = videobuf_mmap_mapper(&vou_file->vbq, vma);
+ mutex_unlock(&vou_dev->fop_lock);
+ return ret;
+}
+
+static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
+{
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_file *vou_file = file->private_data;
+ unsigned int res;
+
+ dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+
+ mutex_lock(&vou_dev->fop_lock);
+ res = videobuf_poll_stream(file, &vou_file->vbq, wait);
+ mutex_unlock(&vou_dev->fop_lock);
+ return res;
+}
+
+static int sh_vou_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sh_vou_g_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
+}
+
+static int sh_vou_s_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+
+ return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
+}
+#endif
+
+/* sh_vou display ioctl operations */
+static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
+ .vidioc_querycap = sh_vou_querycap,
+ .vidioc_enum_fmt_vid_out = sh_vou_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out,
+ .vidioc_reqbufs = sh_vou_reqbufs,
+ .vidioc_querybuf = sh_vou_querybuf,
+ .vidioc_qbuf = sh_vou_qbuf,
+ .vidioc_dqbuf = sh_vou_dqbuf,
+ .vidioc_streamon = sh_vou_streamon,
+ .vidioc_streamoff = sh_vou_streamoff,
+ .vidioc_s_std = sh_vou_s_std,
+ .vidioc_g_std = sh_vou_g_std,
+ .vidioc_cropcap = sh_vou_cropcap,
+ .vidioc_g_crop = sh_vou_g_crop,
+ .vidioc_s_crop = sh_vou_s_crop,
+ .vidioc_g_chip_ident = sh_vou_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = sh_vou_g_register,
+ .vidioc_s_register = sh_vou_s_register,
+#endif
+};
+
+static const struct v4l2_file_operations sh_vou_fops = {
+ .owner = THIS_MODULE,
+ .open = sh_vou_open,
+ .release = sh_vou_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = sh_vou_mmap,
+ .poll = sh_vou_poll,
+};
+
+static const struct video_device sh_vou_video_template = {
+ .name = "sh_vou",
+ .fops = &sh_vou_fops,
+ .ioctl_ops = &sh_vou_ioctl_ops,
+ .tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int __devinit sh_vou_probe(struct platform_device *pdev)
+{
+ struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
+ struct v4l2_rect *rect;
+ struct v4l2_pix_format *pix;
+ struct i2c_adapter *i2c_adap;
+ struct video_device *vdev;
+ struct sh_vou_device *vou_dev;
+ struct resource *reg_res, *region;
+ struct v4l2_subdev *subdev;
+ int irq, ret;
+
+ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+
+ if (!vou_pdata || !reg_res || irq <= 0) {
+ dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
+ return -ENODEV;
+ }
+
+ vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL);
+ if (!vou_dev)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&vou_dev->queue);
+ spin_lock_init(&vou_dev->lock);
+ mutex_init(&vou_dev->fop_lock);
+ atomic_set(&vou_dev->use_count, 0);
+ vou_dev->pdata = vou_pdata;
+ vou_dev->status = SH_VOU_IDLE;
+
+ rect = &vou_dev->rect;
+ pix = &vou_dev->pix;
+
+ /* Fill in defaults */
+ vou_dev->std = sh_vou_video_template.current_norm;
+ rect->left = 0;
+ rect->top = 0;
+ rect->width = VOU_MAX_IMAGE_WIDTH;
+ rect->height = 480;
+ pix->width = VOU_MAX_IMAGE_WIDTH;
+ pix->height = 480;
+ pix->pixelformat = V4L2_PIX_FMT_YVYU;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2;
+ pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ region = request_mem_region(reg_res->start, resource_size(reg_res),
+ pdev->name);
+ if (!region) {
+ dev_err(&pdev->dev, "VOU region already claimed\n");
+ ret = -EBUSY;
+ goto ereqmemreg;
+ }
+
+ vou_dev->base = ioremap(reg_res->start, resource_size(reg_res));
+ if (!vou_dev->base) {
+ ret = -ENOMEM;
+ goto emap;
+ }
+
+ ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev);
+ if (ret < 0)
+ goto ereqirq;
+
+ ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error registering v4l2 device\n");
+ goto ev4l2devreg;
+ }
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto evdevalloc;
+ }
+
+ *vdev = sh_vou_video_template;
+ if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
+ vdev->tvnorms |= V4L2_STD_PAL;
+ vdev->v4l2_dev = &vou_dev->v4l2_dev;
+ vdev->release = video_device_release;
+ vdev->lock = &vou_dev->fop_lock;
+
+ vou_dev->vdev = vdev;
+ video_set_drvdata(vdev, vou_dev);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_resume(&pdev->dev);
+
+ i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
+ if (!i2c_adap) {
+ ret = -ENODEV;
+ goto ei2cgadap;
+ }
+
+ ret = sh_vou_hw_init(vou_dev);
+ if (ret < 0)
+ goto ereset;
+
+ subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
+ vou_pdata->board_info, NULL);
+ if (!subdev) {
+ ret = -ENOMEM;
+ goto ei2cnd;
+ }
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0)
+ goto evregdev;
+
+ return 0;
+
+evregdev:
+ei2cnd:
+ereset:
+ i2c_put_adapter(i2c_adap);
+ei2cgadap:
+ video_device_release(vdev);
+ pm_runtime_disable(&pdev->dev);
+evdevalloc:
+ v4l2_device_unregister(&vou_dev->v4l2_dev);
+ev4l2devreg:
+ free_irq(irq, vou_dev);
+ereqirq:
+ iounmap(vou_dev->base);
+emap:
+ release_mem_region(reg_res->start, resource_size(reg_res));
+ereqmemreg:
+ kfree(vou_dev);
+ return ret;
+}
+
+static int __devexit sh_vou_remove(struct platform_device *pdev)
+{
+ int irq = platform_get_irq(pdev, 0);
+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+ struct sh_vou_device *vou_dev = container_of(v4l2_dev,
+ struct sh_vou_device, v4l2_dev);
+ struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct resource *reg_res;
+
+ if (irq > 0)
+ free_irq(irq, vou_dev);
+ pm_runtime_disable(&pdev->dev);
+ video_unregister_device(vou_dev->vdev);
+ i2c_put_adapter(client->adapter);
+ v4l2_device_unregister(&vou_dev->v4l2_dev);
+ iounmap(vou_dev->base);
+ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (reg_res)
+ release_mem_region(reg_res->start, resource_size(reg_res));
+ kfree(vou_dev);
+ return 0;
+}
+
+static struct platform_driver __refdata sh_vou = {
+ .remove = __devexit_p(sh_vou_remove),
+ .driver = {
+ .name = "sh-vou",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_vou_init(void)
+{
+ return platform_driver_probe(&sh_vou, sh_vou_probe);
+}
+
+static void __exit sh_vou_exit(void)
+{
+ platform_driver_unregister(&sh_vou);
+}
+
+module_init(sh_vou_init);
+module_exit(sh_vou_exit);
+
+MODULE_DESCRIPTION("SuperH VOU driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1.0");
+MODULE_ALIAS("platform:sh-vou");
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
new file mode 100644
index 000000000000..9afe1e7bde74
--- /dev/null
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -0,0 +1,87 @@
+config SOC_CAMERA
+ tristate "SoC camera support"
+ depends on VIDEO_V4L2 && HAS_DMA && I2C
+ select VIDEOBUF_GEN
+ select VIDEOBUF2_CORE
+ help
+ SoC Camera is a common API to several cameras, not connecting
+ over a bus like PCI or USB. For example some i2c camera connected
+ directly to the data bus of an SoC.
+
+config SOC_CAMERA_PLATFORM
+ tristate "platform camera support"
+ depends on SOC_CAMERA
+ help
+ This is a generic SoC camera platform driver, useful for testing
+
+config MX1_VIDEO
+ bool
+
+config VIDEO_MX1
+ tristate "i.MX1/i.MXL CMOS Sensor Interface driver"
+ depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA
+ select FIQ
+ select VIDEOBUF_DMA_CONTIG
+ select MX1_VIDEO
+ ---help---
+ This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
+
+config MX3_VIDEO
+ bool
+
+config VIDEO_MX3
+ tristate "i.MX3x Camera Sensor Interface driver"
+ depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+ select VIDEOBUF2_DMA_CONTIG
+ select MX3_VIDEO
+ ---help---
+ This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
+config VIDEO_PXA27x
+ tristate "PXA27x Quick Capture Interface driver"
+ depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the PXA27x Quick Capture Interface
+
+config VIDEO_SH_MOBILE_CSI2
+ tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+ ---help---
+ This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
+config VIDEO_SH_MOBILE_CEU
+ tristate "SuperH Mobile CEU Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the SuperH Mobile CEU Interface
+
+config VIDEO_OMAP1
+ tristate "OMAP1 Camera Interface driver"
+ depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP1 camera interface
+
+config VIDEO_MX2_HOSTSUPPORT
+ bool
+
+config VIDEO_MX2
+ tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || (ARCH_MX25 && BROKEN))
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_MX2_HOSTSUPPORT
+ ---help---
+ This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
+ Interface
+
+config VIDEO_ATMEL_ISI
+ tristate "ATMEL Image Sensor Interface (ISI) support"
+ depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This module makes the ATMEL Image Sensor Interface available
+ as a v4l2 device.
+
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
new file mode 100644
index 000000000000..136b7f8ff10d
--- /dev/null
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
+
+# soc-camera host drivers have to be linked after camera drivers
+obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
+obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
+obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
+obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
+obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
+obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
+
+ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 6274a91c25c7..6274a91c25c7 100644
--- a/drivers/media/video/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index 560a65aa7038..560a65aa7038 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
new file mode 100644
index 000000000000..256187f30a6c
--- /dev/null
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -0,0 +1,1924 @@
+/*
+ * V4L2 Driver for i.MX27/i.MX25 camera host
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#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/math64.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.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>
+#include <mach/hardware.h>
+
+#include <asm/dma.h>
+
+#define MX2_CAM_DRV_NAME "mx2-camera"
+#define MX2_CAM_VERSION "0.0.6"
+#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
+
+/* reset values */
+#define CSICR1_RESET_VAL 0x40000800
+#define CSICR2_RESET_VAL 0x0
+#define CSICR3_RESET_VAL 0x0
+
+/* csi control reg 1 */
+#define CSICR1_SWAP16_EN (1 << 31)
+#define CSICR1_EXT_VSYNC (1 << 30)
+#define CSICR1_EOF_INTEN (1 << 29)
+#define CSICR1_PRP_IF_EN (1 << 28)
+#define CSICR1_CCIR_MODE (1 << 27)
+#define CSICR1_COF_INTEN (1 << 26)
+#define CSICR1_SF_OR_INTEN (1 << 25)
+#define CSICR1_RF_OR_INTEN (1 << 24)
+#define CSICR1_STATFF_LEVEL (3 << 22)
+#define CSICR1_STATFF_INTEN (1 << 21)
+#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */
+#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */
+#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */
+#define CSICR1_RXFF_INTEN (1 << 18)
+#define CSICR1_SOF_POL (1 << 17)
+#define CSICR1_SOF_INTEN (1 << 16)
+#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12)
+#define CSICR1_HSYNC_POL (1 << 11)
+#define CSICR1_CCIR_EN (1 << 10)
+#define CSICR1_MCLKEN (1 << 9)
+#define CSICR1_FCC (1 << 8)
+#define CSICR1_PACK_DIR (1 << 7)
+#define CSICR1_CLR_STATFIFO (1 << 6)
+#define CSICR1_CLR_RXFIFO (1 << 5)
+#define CSICR1_GCLK_MODE (1 << 4)
+#define CSICR1_INV_DATA (1 << 3)
+#define CSICR1_INV_PCLK (1 << 2)
+#define CSICR1_REDGE (1 << 1)
+#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN)
+
+#define SHIFT_STATFF_LEVEL 22
+#define SHIFT_RXFF_LEVEL 19
+#define SHIFT_MCLKDIV 12
+
+/* control reg 3 */
+#define CSICR3_FRMCNT (0xFFFF << 16)
+#define CSICR3_FRMCNT_RST (1 << 15)
+#define CSICR3_DMA_REFLASH_RFF (1 << 14)
+#define CSICR3_DMA_REFLASH_SFF (1 << 13)
+#define CSICR3_DMA_REQ_EN_RFF (1 << 12)
+#define CSICR3_DMA_REQ_EN_SFF (1 << 11)
+#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */
+#define CSICR3_CSI_SUP (1 << 3)
+#define CSICR3_ZERO_PACK_EN (1 << 2)
+#define CSICR3_ECC_INT_EN (1 << 1)
+#define CSICR3_ECC_AUTO_EN (1 << 0)
+
+#define SHIFT_FRMCNT 16
+
+/* csi status reg */
+#define CSISR_SFF_OR_INT (1 << 25)
+#define CSISR_RFF_OR_INT (1 << 24)
+#define CSISR_STATFF_INT (1 << 21)
+#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */
+#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */
+#define CSISR_RXFF_INT (1 << 18)
+#define CSISR_EOF_INT (1 << 17)
+#define CSISR_SOF_INT (1 << 16)
+#define CSISR_F2_INT (1 << 15)
+#define CSISR_F1_INT (1 << 14)
+#define CSISR_COF_INT (1 << 13)
+#define CSISR_ECC_INT (1 << 1)
+#define CSISR_DRDY (1 << 0)
+
+#define CSICR1 0x00
+#define CSICR2 0x04
+#define CSISR (cpu_is_mx27() ? 0x08 : 0x18)
+#define CSISTATFIFO 0x0c
+#define CSIRFIFO 0x10
+#define CSIRXCNT 0x14
+#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08)
+#define CSIDMASA_STATFIFO 0x20
+#define CSIDMATA_STATFIFO 0x24
+#define CSIDMASA_FB1 0x28
+#define CSIDMASA_FB2 0x2c
+#define CSIFBUF_PARA 0x30
+#define CSIIMAG_PARA 0x34
+
+/* 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)
+
+/* 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)
+
+/* 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;
+ u32 csicr1;
+};
+
+/* 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;
+ struct soc_camera_device *icd;
+ struct clk *clk_csi, *clk_emma_ahb, *clk_emma_ipg;
+
+ unsigned int irq_csi, irq_emma;
+ void __iomem *base_csi, *base_emma;
+ unsigned long base_dma;
+
+ struct mx2_camera_platform_data *pdata;
+ struct resource *res_csi, *res_emma;
+ unsigned long platform_flags;
+
+ struct list_head capture;
+ struct list_head active_bufs;
+ struct list_head discard;
+
+ spinlock_t lock;
+
+ int dma;
+ struct mx2_buffer *active;
+ struct mx2_buffer *fb1_active;
+ struct mx2_buffer *fb2_active;
+
+ 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;
+};
+
+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
+{
+ return container_of(int_buf, struct mx2_buffer, internal);
+}
+
+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,
+ .csicr1 = 0,
+ }
+ },
+ {
+ .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8,
+ .out_fmt = V4L2_PIX_FMT_YUYV,
+ .cfg = {
+ .channel = 1,
+ .in_fmt = PRP_CNTL_DATA_IN_YUV422,
+ .out_fmt = PRP_CNTL_CH1_OUT_YUV422,
+ .src_pixel = 0x22000888, /* YUV422 (YUYV) */
+ .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+ PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+ .csicr1 = CSICR1_SWAP16_EN,
+ }
+ },
+ {
+ .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8,
+ .out_fmt = V4L2_PIX_FMT_YUYV,
+ .cfg = {
+ .channel = 1,
+ .in_fmt = PRP_CNTL_DATA_IN_YUV422,
+ .out_fmt = PRP_CNTL_CH1_OUT_YUV422,
+ .src_pixel = 0x22000888, /* YUV422 (YUYV) */
+ .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+ PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+ .csicr1 = CSICR1_PACK_DIR,
+ }
+ },
+ {
+ .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,
+ .csicr1 = CSICR1_PACK_DIR,
+ }
+ },
+ {
+ .in_fmt = V4L2_MBUS_FMT_UYVY8_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,
+ .csicr1 = CSICR1_SWAP16_EN,
+ }
+ },
+};
+
+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_unprepare(pcdev->clk_csi);
+ writel(0, pcdev->base_csi + CSICR1);
+ if (cpu_is_mx27()) {
+ writel(0, pcdev->base_emma + PRP_CNTL);
+ } else if (cpu_is_mx25()) {
+ spin_lock_irqsave(&pcdev->lock, flags);
+ pcdev->fb1_active = NULL;
+ pcdev->fb2_active = NULL;
+ writel(0, pcdev->base_csi + CSIDMASA_FB1);
+ writel(0, pcdev->base_csi + CSIDMASA_FB2);
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ }
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on mx2 camera sensor interface
+ */
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ int ret;
+ u32 csicr1;
+
+ if (pcdev->icd)
+ return -EBUSY;
+
+ ret = clk_prepare_enable(pcdev->clk_csi);
+ if (ret < 0)
+ return ret;
+
+ csicr1 = CSICR1_MCLKEN;
+
+ if (cpu_is_mx27()) {
+ csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
+ CSICR1_RXFF_LEVEL(0);
+ } else if (cpu_is_mx27())
+ csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
+
+ pcdev->csicr1 = csicr1;
+ 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);
+
+ return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+
+ BUG_ON(icd != pcdev->icd);
+
+ dev_info(icd->parent, "Camera driver detached from camera %d\n",
+ icd->devnum);
+
+ mx2_camera_deactivate(pcdev);
+
+ pcdev->icd = NULL;
+}
+
+static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
+ int state)
+{
+ struct vb2_buffer *vb;
+ struct mx2_buffer *buf;
+ struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
+ &pcdev->fb2_active;
+ u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (*fb_active == NULL)
+ goto out;
+
+ vb = &(*fb_active)->vb;
+ 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));
+
+ 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_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+ vb = &buf->vb;
+ 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;
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
+{
+ struct mx2_camera_dev *pcdev = data;
+ u32 status = readl(pcdev->base_csi + CSISR);
+
+ if (status & CSISR_DMA_TSF_FB1_INT)
+ mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
+ else if (status & CSISR_DMA_TSF_FB2_INT)
+ mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
+
+ /* FIXME: handle CSISR_RFF_OR_INT */
+
+ writel(status, pcdev->base_csi + CSISR);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Videobuf operations
+ */
+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 = soc_camera_from_vb2q(vq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+
+ 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;
+
+ alloc_ctxs[0] = pcdev->alloc_ctx;
+
+ sizes[0] = icd->sizeimage;
+
+ if (0 == *count)
+ *count = 32;
+ if (!*num_planes &&
+ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+ *num_planes = 1;
+
+ return 0;
+}
+
+static int mx2_videobuf_prepare(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+ int ret = 0;
+
+ 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));
+
+#ifdef DEBUG
+ /*
+ * This can be useful if you want to see if we actually fill
+ * the buffer with something
+ */
+ memset((void *)vb2_plane_vaddr(vb, 0),
+ 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+ vb2_set_plane_payload(vb, 0, icd->sizeimage);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void mx2_videobuf_queue(struct vb2_buffer *vb)
+{
+ 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%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ buf->state = MX2_STATE_QUEUED;
+ list_add_tail(&buf->internal.queue, &pcdev->capture);
+
+ if (cpu_is_mx25()) {
+ u32 csicr3, dma_inten = 0;
+
+ if (pcdev->fb1_active == NULL) {
+ 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(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(&buf->internal.queue);
+ buf->state = MX2_STATE_ACTIVE;
+
+ csicr3 = readl(pcdev->base_csi + CSICR3);
+
+ /* Reflash DMA */
+ writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
+ pcdev->base_csi + CSICR3);
+
+ /* clear & enable interrupts */
+ writel(dma_inten, pcdev->base_csi + CSISR);
+ pcdev->csicr1 |= dma_inten;
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+ /* enable DMA */
+ csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
+ writel(csicr3, pcdev->base_csi + CSICR3);
+ }
+ }
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx2_videobuf_release(struct vb2_buffer *vb)
+{
+ 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%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+ switch (buf->state) {
+ case MX2_STATE_ACTIVE:
+ dev_info(icd->parent, "%s (active)\n", __func__);
+ break;
+ case MX2_STATE_QUEUED:
+ dev_info(icd->parent, "%s (queued)\n", __func__);
+ break;
+ default:
+ dev_info(icd->parent, "%s (unknown) %d\n", __func__,
+ buf->state);
+ break;
+ }
+#endif
+
+ /*
+ * Terminate only queued but inactive buffers. Active buffers are
+ * released when they become inactive after videobuf_waiton().
+ *
+ * FIXME: implement forced termination of active buffers for mx27 and
+ * mx27 eMMA, so that the user won't get stuck in an uninterruptible
+ * state. This requires a specific handling for each of the these DMA
+ * types.
+ */
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+ 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);
+ pcdev->fb1_active = NULL;
+ } else if (pcdev->fb2_active == buf) {
+ pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
+ writel(0, pcdev->base_csi + CSIDMASA_FB2);
+ pcdev->fb2_active = NULL;
+ }
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+ }
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+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 void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
+{
+ int dir;
+
+ 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_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);
+
+ 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 | \
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+ V4L2_MBUS_VSYNC_ACTIVE_LOW | \
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
+ V4L2_MBUS_HSYNC_ACTIVE_LOW | \
+ V4L2_MBUS_PCLK_SAMPLE_RISING | \
+ V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+ V4L2_MBUS_DATA_ACTIVE_HIGH | \
+ V4L2_MBUS_DATA_ACTIVE_LOW)
+
+static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+{
+ u32 cntl;
+ int count = 0;
+
+ cntl = readl(pcdev->base_emma + PRP_CNTL);
+ writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+ while (count++ < 100) {
+ if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
+ return 0;
+ barrier();
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+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);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+ unsigned long common_flags;
+ int ret;
+ int bytesperline;
+ u32 csicr1 = pcdev->csicr1;
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+ if (!ret) {
+ common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS);
+ if (!common_flags) {
+ dev_warn(icd->parent,
+ "Flags incompatible: camera 0x%x, host 0x%x\n",
+ cfg.flags, MX2_BUS_FLAGS);
+ return -EINVAL;
+ }
+ } else if (ret != -ENOIOCTLCMD) {
+ return ret;
+ } else {
+ common_flags = MX2_BUS_FLAGS;
+ }
+
+ if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
+ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+ else
+ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+ }
+
+ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ else
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+ }
+
+ cfg.flags = common_flags;
+ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
+ common_flags, ret);
+ return ret;
+ }
+
+ csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1;
+
+ if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ csicr1 |= CSICR1_REDGE;
+ if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ csicr1 |= CSICR1_SOF_POL;
+ if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ csicr1 |= CSICR1_HSYNC_POL;
+ if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
+ csicr1 |= CSICR1_EXT_VSYNC;
+ if (pcdev->platform_flags & MX2_CAMERA_CCIR)
+ csicr1 |= CSICR1_CCIR_EN;
+ if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
+ csicr1 |= CSICR1_CCIR_MODE;
+ if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
+ csicr1 |= CSICR1_GCLK_MODE;
+ if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
+ csicr1 |= CSICR1_INV_DATA;
+
+ pcdev->csicr1 = csicr1;
+
+ bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytesperline < 0)
+ return bytesperline;
+
+ if (cpu_is_mx27()) {
+ ret = mx27_camera_emma_prp_reset(pcdev);
+ if (ret)
+ return ret;
+ } else if (cpu_is_mx25()) {
+ writel((bytesperline * icd->user_height) >> 2,
+ pcdev->base_csi + CSIRXCNT);
+ writel((bytesperline << 16) | icd->user_height,
+ pcdev->base_csi + CSIIMAG_PARA);
+ }
+
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+ return 0;
+}
+
+static int mx2_camera_set_crop(struct soc_camera_device *icd,
+ struct v4l2_crop *a)
+{
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
+ if (ret < 0)
+ return ret;
+
+ /* The capture device might have changed its output */
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
+ mf.width, mf.height);
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+
+ 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 ||
+ code == V4L2_MBUS_FMT_UYVY8_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++;
+ }
+ }
+
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ formats++;
+ if (xlate) {
+ xlate->host_fmt =
+ soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
+ 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",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ 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;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ 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;
+}
+
+static int mx2_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ 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;
+ __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);
+ return -EINVAL;
+ }
+
+ /* FIXME: implement MX27 limits */
+
+ /* limit to MX25 hardware capabilities */
+ if (cpu_is_mx25()) {
+ if (xlate->host_fmt->bits_per_sample <= 8)
+ width_limit = 0xffff * 4;
+ else
+ width_limit = 0xffff * 2;
+ /* CSIIMAG_PARA limit */
+ if (pix->width > width_limit)
+ pix->width = width_limit;
+ if (pix->height > 0xffff)
+ pix->height = 0xffff;
+
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ if (pix->bytesperline < 0)
+ return pix->bytesperline;
+ pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+ pix->bytesperline, pix->height);
+ /* Check against the CSIRXCNT limit */
+ if (pix->sizeimage > 4 * 0x3ffff) {
+ /* Adjust geometry, preserve aspect ratio */
+ unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
+ 4 * pix->height, pix->bytesperline));
+ pix->width = new_height * pix->width / pix->height;
+ pix->height = new_height;
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ BUG_ON(pix->bytesperline < 0);
+ pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+ pix->bytesperline, pix->height);
+ }
+ }
+
+ /* limit to sensor capabilities */
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ 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;
+ /*
+ * 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;
+ }
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ 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;
+}
+
+static int mx2_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+
+ return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = mx2_camera_add_device,
+ .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_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, bool err)
+{
+#ifdef DEBUG
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+#endif
+ struct mx2_buf_internal *ibuf;
+ struct mx2_buffer *buf;
+ struct vb2_buffer *vb;
+ unsigned long phys;
+
+ ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
+ queue);
+
+ 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 = 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_Y_PTR - 0x14 * bufnum));
+ }
+ }
+#endif
+ 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));
+
+ 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)) {
+ 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_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+
+ buf->internal.bufnum = bufnum;
+
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+ vb = &buf->vb;
+ buf->state = MX2_STATE_ACTIVE;
+
+ 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_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 = 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);
+
+ 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
+ */
+ 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);
+ }
+
+ spin_unlock(&pcdev->lock);
+ writel(status, pcdev->base_emma + PRP_INTRSTATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
+{
+ struct resource *res_emma = pcdev->res_emma;
+ int err = 0;
+
+ if (!request_mem_region(res_emma->start, resource_size(res_emma),
+ MX2_CAM_DRV_NAME)) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
+ if (!pcdev->base_emma) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+
+ err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
+ MX2_CAM_DRV_NAME, pcdev);
+ if (err) {
+ dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
+ goto exit_iounmap;
+ }
+
+ pcdev->clk_emma_ipg = clk_get(pcdev->dev, "emma-ipg");
+ if (IS_ERR(pcdev->clk_emma_ipg)) {
+ err = PTR_ERR(pcdev->clk_emma_ipg);
+ goto exit_free_irq;
+ }
+
+ clk_prepare_enable(pcdev->clk_emma_ipg);
+
+ pcdev->clk_emma_ahb = clk_get(pcdev->dev, "emma-ahb");
+ if (IS_ERR(pcdev->clk_emma_ahb)) {
+ err = PTR_ERR(pcdev->clk_emma_ahb);
+ goto exit_clk_emma_ipg_put;
+ }
+
+ clk_prepare_enable(pcdev->clk_emma_ahb);
+
+ err = mx27_camera_emma_prp_reset(pcdev);
+ if (err)
+ goto exit_clk_emma_ahb_put;
+
+ return err;
+
+exit_clk_emma_ahb_put:
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
+ clk_put(pcdev->clk_emma_ahb);
+exit_clk_emma_ipg_put:
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ clk_put(pcdev->clk_emma_ipg);
+exit_free_irq:
+ free_irq(pcdev->irq_emma, pcdev);
+exit_iounmap:
+ iounmap(pcdev->base_emma);
+exit_release:
+ release_mem_region(res_emma->start, resource_size(res_emma));
+out:
+ return err;
+}
+
+static int __devinit mx2_camera_probe(struct platform_device *pdev)
+{
+ struct mx2_camera_dev *pcdev;
+ struct resource *res_csi, *res_emma;
+ void __iomem *base_csi;
+ int irq_csi, irq_emma;
+ int err = 0;
+
+ dev_dbg(&pdev->dev, "initialising\n");
+
+ res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_csi = platform_get_irq(pdev, 0);
+ if (res_csi == NULL || irq_csi < 0) {
+ dev_err(&pdev->dev, "Missing platform resources data\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+ if (!pcdev) {
+ dev_err(&pdev->dev, "Could not allocate pcdev\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pcdev->clk_csi = clk_get(&pdev->dev, "ahb");
+ 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;
+ }
+
+ pcdev->res_csi = res_csi;
+ pcdev->pdata = pdev->dev.platform_data;
+ if (pcdev->pdata) {
+ long rate;
+
+ pcdev->platform_flags = pcdev->pdata->flags;
+
+ rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
+ if (rate <= 0) {
+ err = -ENODEV;
+ goto exit_dma_free;
+ }
+ err = clk_set_rate(pcdev->clk_csi, rate);
+ if (err < 0)
+ goto exit_dma_free;
+ }
+
+ INIT_LIST_HEAD(&pcdev->capture);
+ INIT_LIST_HEAD(&pcdev->active_bufs);
+ INIT_LIST_HEAD(&pcdev->discard);
+ spin_lock_init(&pcdev->lock);
+
+ /*
+ * Request the regions.
+ */
+ if (!request_mem_region(res_csi->start, resource_size(res_csi),
+ MX2_CAM_DRV_NAME)) {
+ err = -EBUSY;
+ goto exit_dma_free;
+ }
+
+ base_csi = ioremap(res_csi->start, resource_size(res_csi));
+ if (!base_csi) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ pcdev->irq_csi = irq_csi;
+ pcdev->base_csi = base_csi;
+ pcdev->base_dma = res_csi->start;
+ pcdev->dev = &pdev->dev;
+
+ 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()) {
+ /* EMMA support */
+ res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ irq_emma = platform_get_irq(pdev, 1);
+
+ 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,
+ pcdev->soc_host.ops = &mx2_soc_camera_host_ops,
+ pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
+ pcdev->soc_host.nr = pdev->id;
+ if (cpu_is_mx25())
+ pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
+
+ 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;
+
+ dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
+ clk_get_rate(pcdev->clk_csi));
+
+ return 0;
+
+exit_free_emma:
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+eallocctx:
+ if (cpu_is_mx27()) {
+ free_irq(pcdev->irq_emma, pcdev);
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ clk_put(pcdev->clk_emma_ipg);
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
+ clk_put(pcdev->clk_emma_ahb);
+ iounmap(pcdev->base_emma);
+ release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
+ }
+exit_free_irq:
+ 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:
+ clk_put(pcdev->clk_csi);
+exit_kfree:
+ kfree(pcdev);
+exit:
+ return err;
+}
+
+static int __devexit mx2_camera_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct mx2_camera_dev *pcdev = container_of(soc_host,
+ struct mx2_camera_dev, soc_host);
+ struct resource *res;
+
+ clk_put(pcdev->clk_csi);
+ if (cpu_is_mx25())
+ free_irq(pcdev->irq_csi, pcdev);
+ if (cpu_is_mx27())
+ 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 (cpu_is_mx27()) {
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ clk_put(pcdev->clk_emma_ipg);
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
+ clk_put(pcdev->clk_emma_ahb);
+ iounmap(pcdev->base_emma);
+ res = pcdev->res_emma;
+ release_mem_region(res->start, resource_size(res));
+ }
+
+ res = pcdev->res_csi;
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(pcdev);
+
+ dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver mx2_camera_driver = {
+ .driver = {
+ .name = MX2_CAM_DRV_NAME,
+ },
+ .remove = __devexit_p(mx2_camera_remove),
+};
+
+
+static int __init mx2_camera_init(void)
+{
+ return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
+}
+
+static void __exit mx2_camera_exit(void)
+{
+ return platform_driver_unregister(&mx2_camera_driver);
+}
+
+module_init(mx2_camera_init);
+module_exit(mx2_camera_exit);
+
+MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
+MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MX2_CAM_VERSION);
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
new file mode 100644
index 000000000000..16975c6e6905
--- /dev/null
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -0,0 +1,1290 @@
+/*
+ * V4L2 Driver for i.MX3x camera host
+ *
+ * Copyright (C) 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <mach/ipu.h>
+#include <mach/mx3_camera.h>
+#include <mach/dma.h>
+
+#define MX3_CAM_DRV_NAME "mx3-camera"
+
+/* CMOS Sensor Interface Registers */
+#define CSI_REG_START 0x60
+
+#define CSI_SENS_CONF (0x60 - CSI_REG_START)
+#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START)
+#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START)
+#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START)
+#define CSI_TST_CTRL (0x70 - CSI_REG_START)
+#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START)
+#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START)
+#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START)
+#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START)
+#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START)
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
+#define CSI_SENS_CONF_DATA_POL_SHIFT 2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
+#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7
+#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
+
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+
+#define MAX_VIDEO_MEM 16
+
+struct mx3_camera_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ struct list_head queue;
+
+ /* One descriptot per scatterlist (per frame) */
+ struct dma_async_tx_descriptor *txd;
+
+ /* We have to "build" a scatterlist ourselves - one element per frame */
+ struct scatterlist sg;
+};
+
+/**
+ * struct mx3_camera_dev - i.MX3x camera (CSI) object
+ * @dev: camera device, to which the coherent buffer is attached
+ * @icd: currently attached camera sensor
+ * @clk: pointer to clock
+ * @base: remapped register base address
+ * @pdata: platform data
+ * @platform_flags: platform flags
+ * @mclk: master clock frequency in Hz
+ * @capture: list of capture videobuffers
+ * @lock: protects video buffer lists
+ * @active: active video buffer
+ * @idmac_channel: array of pointers to IPU DMAC DMA channels
+ * @soc_host: embedded soc_host object
+ */
+struct mx3_camera_dev {
+ /*
+ * i.MX3x is only supposed to handle one camera on its Camera Sensor
+ * Interface. If anyone ever builds hardware to enable more than one
+ * camera _simultaneously_, they will have to modify this driver too
+ */
+ struct soc_camera_device *icd;
+ struct clk *clk;
+
+ void __iomem *base;
+
+ struct mx3_camera_pdata *pdata;
+
+ unsigned long platform_flags;
+ unsigned long mclk;
+ u16 width_flags; /* max 15 bits */
+
+ struct list_head capture;
+ spinlock_t lock; /* Protects video buffer lists */
+ struct mx3_camera_buffer *active;
+ size_t buf_total;
+ struct vb2_alloc_ctx *alloc_ctx;
+ enum v4l2_field field;
+ int sequence;
+
+ /* IDMAC / dmaengine interface */
+ struct idmac_channel *idmac_channel[1]; /* We need one channel */
+
+ struct soc_camera_host soc_host;
+};
+
+struct dma_chan_request {
+ struct mx3_camera_dev *mx3_cam;
+ enum ipu_channel id;
+};
+
+static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
+{
+ return __raw_readl(mx3->base + reg);
+}
+
+static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
+{
+ __raw_writel(value, mx3->base + reg);
+}
+
+static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct mx3_camera_buffer, vb);
+}
+
+/* Called from the IPU IDMAC ISR */
+static void mx3_cam_dma_done(void *arg)
+{
+ struct idmac_tx_desc *desc = to_tx_desc(arg);
+ struct dma_chan *chan = desc->txd.chan;
+ struct idmac_channel *ichannel = to_idmac_chan(chan);
+ struct mx3_camera_dev *mx3_cam = ichannel->client;
+
+ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+ desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
+
+ spin_lock(&mx3_cam->lock);
+ if (mx3_cam->active) {
+ struct vb2_buffer *vb = &mx3_cam->active->vb;
+ struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+
+ list_del_init(&buf->queue);
+ do_gettimeofday(&vb->v4l2_buf.timestamp);
+ vb->v4l2_buf.field = mx3_cam->field;
+ vb->v4l2_buf.sequence = mx3_cam->sequence++;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+
+ if (list_empty(&mx3_cam->capture)) {
+ mx3_cam->active = NULL;
+ spin_unlock(&mx3_cam->lock);
+
+ /*
+ * stop capture - without further buffers IPU_CHA_BUF0_RDY will
+ * not get updated
+ */
+ return;
+ }
+
+ mx3_cam->active = list_entry(mx3_cam->capture.next,
+ struct mx3_camera_buffer, queue);
+ spin_unlock(&mx3_cam->lock);
+}
+
+/*
+ * Videobuf operations
+ */
+
+/*
+ * Calculate the __buffer__ (not data) size and number of buffers.
+ */
+static int mx3_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 = soc_camera_from_vb2q(vq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+
+ if (!mx3_cam->idmac_channel[0])
+ return -EINVAL;
+
+ if (fmt) {
+ const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
+ fmt->fmt.pix.pixelformat);
+ unsigned int bytes_per_line;
+ int ret;
+
+ if (!xlate)
+ return -EINVAL;
+
+ ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+ xlate->host_fmt);
+ if (ret < 0)
+ return ret;
+
+ bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+ ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+ fmt->fmt.pix.height);
+ if (ret < 0)
+ return ret;
+
+ sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
+ } else {
+ /* Called from VIDIOC_REQBUFS or in compatibility mode */
+ sizes[0] = icd->sizeimage;
+ }
+
+ alloc_ctxs[0] = mx3_cam->alloc_ctx;
+
+ if (!vq->num_buffers)
+ mx3_cam->sequence = 0;
+
+ if (!*count)
+ *count = 2;
+
+ /* If *num_planes != 0, we have already verified *count. */
+ if (!*num_planes &&
+ sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
+ sizes[0];
+
+ *num_planes = 1;
+
+ return 0;
+}
+
+static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
+{
+ /* Add more formats as need arises and test possibilities appear... */
+ switch (fourcc) {
+ case V4L2_PIX_FMT_RGB24:
+ return IPU_PIX_FMT_RGB24;
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_RGB565:
+ default:
+ return IPU_PIX_FMT_GENERIC;
+ }
+}
+
+static void mx3_videobuf_queue(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+ struct scatterlist *sg = &buf->sg;
+ struct dma_async_tx_descriptor *txd;
+ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+ struct idmac_video_param *video = &ichan->params.video;
+ const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
+ unsigned long flags;
+ dma_cookie_t cookie;
+ size_t new_size;
+
+ new_size = icd->sizeimage;
+
+ if (vb2_plane_size(vb, 0) < new_size) {
+ dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
+ vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size);
+ goto error;
+ }
+
+ if (!buf->txd) {
+ sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
+ sg_dma_len(sg) = new_size;
+
+ txd = dmaengine_prep_slave_sg(
+ &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!txd)
+ goto error;
+
+ txd->callback_param = txd;
+ txd->callback = mx3_cam_dma_done;
+
+ buf->txd = txd;
+ } else {
+ txd = buf->txd;
+ }
+
+ vb2_set_plane_payload(vb, 0, new_size);
+
+ /* This is the configuration of one sg-element */
+ video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
+
+ if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
+ /*
+ * If the IPU DMA channel is configured to transfer generic
+ * 8-bit data, we have to set up the geometry parameters
+ * correctly, according to the current pixel format. The DMA
+ * horizontal parameters in this case are expressed in bytes,
+ * not in pixels.
+ */
+ video->out_width = icd->bytesperline;
+ video->out_height = icd->user_height;
+ video->out_stride = icd->bytesperline;
+ } else {
+ /*
+ * For IPU known formats the pixel unit will be managed
+ * successfully by the IPU code
+ */
+ video->out_width = icd->user_width;
+ video->out_height = icd->user_height;
+ video->out_stride = icd->user_width;
+ }
+
+#ifdef DEBUG
+ /* helps to see what DMA actually has written */
+ if (vb2_plane_vaddr(vb, 0))
+ memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+ list_add_tail(&buf->queue, &mx3_cam->capture);
+
+ if (!mx3_cam->active)
+ mx3_cam->active = buf;
+
+ spin_unlock_irq(&mx3_cam->lock);
+
+ cookie = txd->tx_submit(txd);
+ dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
+ cookie, sg_dma_address(&buf->sg));
+
+ if (cookie >= 0)
+ return;
+
+ spin_lock_irq(&mx3_cam->lock);
+
+ /* Submit error */
+ list_del_init(&buf->queue);
+
+ if (mx3_cam->active == buf)
+ mx3_cam->active = NULL;
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+error:
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+}
+
+static void mx3_videobuf_release(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+ struct dma_async_tx_descriptor *txd = buf->txd;
+ unsigned long flags;
+
+ dev_dbg(icd->parent,
+ "Release%s DMA 0x%08x, queue %sempty\n",
+ mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
+ list_empty(&buf->queue) ? "" : "not ");
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ if (mx3_cam->active == buf)
+ mx3_cam->active = NULL;
+
+ /* Doesn't hurt also if the list is empty */
+ list_del_init(&buf->queue);
+
+ if (txd) {
+ buf->txd = NULL;
+ if (mx3_cam->idmac_channel[0])
+ async_tx_ack(txd);
+ }
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+ mx3_cam->buf_total -= vb2_plane_size(vb, 0);
+}
+
+static int mx3_videobuf_init(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+
+ if (!buf->txd) {
+ /* This is for locking debugging only */
+ INIT_LIST_HEAD(&buf->queue);
+ sg_init_table(&buf->sg, 1);
+
+ mx3_cam->buf_total += vb2_plane_size(vb, 0);
+ }
+
+ return 0;
+}
+
+static int mx3_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 mx3_camera_dev *mx3_cam = ici->priv;
+ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+ struct mx3_camera_buffer *buf, *tmp;
+ unsigned long flags;
+
+ if (ichan) {
+ struct dma_chan *chan = &ichan->dma_chan;
+ chan->device->device_control(chan, DMA_PAUSE, 0);
+ }
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ mx3_cam->active = NULL;
+
+ list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
+ list_del_init(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+ return 0;
+}
+
+static struct vb2_ops mx3_videobuf_ops = {
+ .queue_setup = mx3_videobuf_setup,
+ .buf_queue = mx3_videobuf_queue,
+ .buf_cleanup = mx3_videobuf_release,
+ .buf_init = mx3_videobuf_init,
+ .wait_prepare = soc_camera_unlock,
+ .wait_finish = soc_camera_lock,
+ .stop_streaming = mx3_stop_streaming,
+};
+
+static int mx3_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 = &mx3_videobuf_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mx3_camera_buffer);
+
+ return vb2_queue_init(q);
+}
+
+/* First part of ipu_csi_init_interface() */
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
+ struct soc_camera_device *icd)
+{
+ u32 conf;
+ long rate;
+
+ /* Set default size: ipu_csi_set_window_size() */
+ csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
+ /* ...and position to 0:0: ipu_csi_set_window_pos() */
+ conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+ csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
+
+ /* We use only gated clock synchronisation mode so far */
+ conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+
+ /* Set generic data, platform-biggest bus-width */
+ conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+ conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+ conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+ conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
+ conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+
+ if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
+ conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
+ conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+ conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+ conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+ conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+ conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+
+ /* ipu_csi_init_interface() */
+ csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
+
+ clk_prepare_enable(mx3_cam->clk);
+ rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
+ dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+ if (rate)
+ clk_set_rate(mx3_cam->clk, rate);
+}
+
+/* Called with .video_lock held */
+static int mx3_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+
+ if (mx3_cam->icd)
+ return -EBUSY;
+
+ mx3_camera_activate(mx3_cam, icd);
+
+ mx3_cam->buf_total = 0;
+ mx3_cam->icd = icd;
+
+ dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+/* Called with .video_lock held */
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+
+ BUG_ON(icd != mx3_cam->icd);
+
+ if (*ichan) {
+ dma_release_channel(&(*ichan)->dma_chan);
+ *ichan = NULL;
+ }
+
+ clk_disable_unprepare(mx3_cam->clk);
+
+ mx3_cam->icd = NULL;
+
+ dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
+static int test_platform_param(struct mx3_camera_dev *mx3_cam,
+ unsigned char buswidth, unsigned long *flags)
+{
+ /*
+ * If requested data width is supported by the platform, use it or any
+ * possible lower value - i.MX31 is smart enough to shift bits
+ */
+ if (buswidth > fls(mx3_cam->width_flags))
+ return -EINVAL;
+
+ /*
+ * Platform specified synchronization and pixel clock polarities are
+ * only a recommendation and are only used during probing. MX3x
+ * camera interface only works in master mode, i.e., uses HSYNC and
+ * VSYNC signals from the sensor
+ */
+ *flags = V4L2_MBUS_MASTER |
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_HSYNC_ACTIVE_LOW |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_VSYNC_ACTIVE_LOW |
+ V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_PCLK_SAMPLE_FALLING |
+ V4L2_MBUS_DATA_ACTIVE_HIGH |
+ V4L2_MBUS_DATA_ACTIVE_LOW;
+
+ return 0;
+}
+
+static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
+ const unsigned int depth)
+{
+ 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,};
+ unsigned long bus_flags, common_flags;
+ int ret = test_platform_param(mx3_cam, depth, &bus_flags);
+
+ dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
+
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+ if (!ret) {
+ common_flags = soc_mbus_config_compatible(&cfg,
+ bus_flags);
+ if (!common_flags) {
+ dev_warn(icd->parent,
+ "Flags incompatible: camera 0x%x, host 0x%lx\n",
+ cfg.flags, bus_flags);
+ return -EINVAL;
+ }
+ } else if (ret != -ENOIOCTLCMD) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ struct dma_chan_request *rq = arg;
+ struct mx3_camera_pdata *pdata;
+
+ if (!imx_dma_is_ipu(chan))
+ return false;
+
+ if (!rq)
+ return false;
+
+ pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data;
+
+ return rq->id == chan->chan_id &&
+ pdata->dma_dev == chan->device->dev;
+}
+
+static const struct soc_mbus_pixelfmt mx3_camera_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .name = "Bayer BGGR (sRGB) 8 bit",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .name = "Monochrome 8 bit",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+};
+
+/* This will be corrected as we get more formats */
+static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+ return fmt->packing == SOC_MBUS_PACKING_NONE ||
+ (fmt->bits_per_sample == 8 &&
+ fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+ (fmt->bits_per_sample > 8 &&
+ fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static int mx3_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);
+ struct device *dev = icd->parent;
+ int formats = 0, ret;
+ enum v4l2_mbus_pixelcode code;
+ const struct soc_mbus_pixelfmt *fmt;
+
+ 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_warn(icd->parent,
+ "Unsupported format code #%u: %d\n", idx, code);
+ return 0;
+ }
+
+ /* This also checks support for the requested bits-per-sample */
+ ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample);
+ if (ret < 0)
+ return 0;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &mx3_camera_formats[0];
+ xlate->code = code;
+ xlate++;
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ mx3_camera_formats[0].name, code);
+ }
+ break;
+ case V4L2_MBUS_FMT_Y10_1X10:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &mx3_camera_formats[1];
+ xlate->code = code;
+ xlate++;
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ mx3_camera_formats[1].name, code);
+ }
+ break;
+ default:
+ if (!mx3_camera_packing_supported(fmt))
+ return 0;
+ }
+
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = fmt;
+ xlate->code = code;
+ dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n",
+ (fmt->fourcc >> (0*8)) & 0xFF,
+ (fmt->fourcc >> (1*8)) & 0xFF,
+ (fmt->fourcc >> (2*8)) & 0xFF,
+ (fmt->fourcc >> (3*8)) & 0xFF);
+ xlate++;
+ }
+
+ return formats;
+}
+
+static void configure_geometry(struct mx3_camera_dev *mx3_cam,
+ unsigned int width, unsigned int height,
+ const struct soc_mbus_pixelfmt *fmt)
+{
+ u32 ctrl, width_field, height_field;
+
+ if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
+ /*
+ * As the CSI will be configured to output BAYER, here
+ * the width parameter count the number of samples to
+ * capture to complete the whole image width.
+ */
+ unsigned int num, den;
+ int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
+ BUG_ON(ret < 0);
+ width = width * num / den;
+ }
+
+ /* Setup frame size - this cannot be changed on-the-fly... */
+ width_field = width - 1;
+ height_field = height - 1;
+ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
+
+ csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
+ csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
+
+ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
+
+ /* ...and position */
+ ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+ /* Sensor does the cropping */
+ csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
+}
+
+static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+ /* We have to use IDMAC_IC_7 for Bayer / generic data */
+ struct dma_chan_request rq = {.mx3_cam = mx3_cam,
+ .id = IDMAC_IC_7};
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, &rq);
+ if (!chan)
+ return -EBUSY;
+
+ *ichan = to_idmac_chan(chan);
+ (*ichan)->client = mx3_cam;
+
+ return 0;
+}
+
+/*
+ * FIXME: learn to use stride != width, then we can keep stride properly aligned
+ * and support arbitrary (even) widths.
+ */
+static inline void stride_align(__u32 *width)
+{
+ if (ALIGN(*width, 8) < 4096)
+ *width = ALIGN(*width, 8);
+ else
+ *width = *width & ~7;
+}
+
+/*
+ * As long as we don't implement host-side cropping and scaling, we can use
+ * default g_crop and cropcap from soc_camera.c
+ */
+static int mx3_camera_set_crop(struct soc_camera_device *icd,
+ struct v4l2_crop *a)
+{
+ struct v4l2_rect *rect = &a->c;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
+ if (ret < 0)
+ return ret;
+
+ /* The capture device might have changed its output sizes */
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ if (mf.code != icd->current_fmt->code)
+ return -EINVAL;
+
+ if (mf.width & 7) {
+ /* Ouch! We can only handle 8-byte aligned width... */
+ stride_align(&mf.width);
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (mf.width != icd->user_width || mf.height != icd->user_height)
+ configure_geometry(mx3_cam, mf.width, mf.height,
+ icd->current_fmt->host_fmt);
+
+ dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
+ mf.width, mf.height);
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+
+ return ret;
+}
+
+static int mx3_camera_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx3_camera_dev *mx3_cam = 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;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(icd->parent, "Format %x not found\n",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ stride_align(&pix->width);
+ dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height);
+
+ /*
+ * Might have to perform a complete interface initialisation like in
+ * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
+ * mxc_v4l2_s_fmt()
+ */
+
+ configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ if (mf.code != xlate->code)
+ return -EINVAL;
+
+ if (!mx3_cam->idmac_channel[0]) {
+ ret = acquire_dma_channel(mx3_cam);
+ if (ret < 0)
+ return ret;
+ }
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ mx3_cam->field = mf.field;
+ pix->colorspace = mf.colorspace;
+ icd->current_fmt = xlate;
+
+ dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height);
+
+ return ret;
+}
+
+static int mx3_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ 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;
+ __u32 pixfmt = pix->pixelformat;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (pixfmt && !xlate) {
+ dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ /* limit to MX3 hardware capabilities */
+ if (pix->height > 4096)
+ pix->height = 4096;
+ if (pix->width > 4096)
+ pix->width = 4096;
+
+ /* limit to sensor capabilities */
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->colorspace = mf.colorspace;
+
+ switch (mf.field) {
+ case V4L2_FIELD_ANY:
+ pix->field = V4L2_FIELD_NONE;
+ break;
+ case V4L2_FIELD_NONE:
+ break;
+ default:
+ dev_err(icd->parent, "Field type %d unsupported.\n",
+ mf.field);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int mx3_camera_reqbufs(struct soc_camera_device *icd,
+ struct v4l2_requestbuffers *p)
+{
+ return 0;
+}
+
+static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+
+ return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int mx3_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the firendly caller:-> */
+ strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+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;
+ int buswidth;
+ int ret;
+ const struct soc_camera_format_xlate *xlate;
+ struct device *dev = icd->parent;
+
+ fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
+ if (!fmt)
+ return -EINVAL;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ buswidth = fmt->bits_per_sample;
+ ret = test_platform_param(mx3_cam, buswidth, &bus_flags);
+
+ dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret);
+
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+ if (!ret) {
+ common_flags = soc_mbus_config_compatible(&cfg,
+ bus_flags);
+ if (!common_flags) {
+ dev_warn(icd->parent,
+ "Flags incompatible: camera 0x%x, host 0x%lx\n",
+ cfg.flags, bus_flags);
+ return -EINVAL;
+ }
+ } else if (ret != -ENOIOCTLCMD) {
+ return ret;
+ } else {
+ common_flags = bus_flags;
+ }
+
+ dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n",
+ cfg.flags, bus_flags, common_flags);
+
+ /* Make choices, based on platform preferences */
+ if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
+ (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
+ (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
+ else
+ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
+ }
+
+ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ }
+
+ cfg.flags = common_flags;
+ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
+ common_flags, ret);
+ return ret;
+ }
+
+ /*
+ * So far only gated clock mode is supported. Add a line
+ * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
+ * below and select the required mode when supporting other
+ * synchronisation protocols.
+ */
+ sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
+ ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
+ (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
+ (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
+
+ /* TODO: Support RGB and YUV formats */
+
+ /* This has been set in mx3_camera_activate(), but we clear it above */
+ sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+ if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+ if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+ if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+ if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+
+ /* Just do what we're asked to do */
+ switch (xlate->host_fmt->bits_per_sample) {
+ case 4:
+ dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ case 8:
+ dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ case 10:
+ dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ default:
+ /*
+ * Actually it can only be 15 now, default is just to silence
+ * compiler warnings
+ */
+ case 15:
+ dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ }
+
+ csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
+
+ dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+
+ return 0;
+}
+
+static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = mx3_camera_add_device,
+ .remove = mx3_camera_remove_device,
+ .set_crop = mx3_camera_set_crop,
+ .set_fmt = mx3_camera_set_fmt,
+ .try_fmt = mx3_camera_try_fmt,
+ .get_formats = mx3_camera_get_formats,
+ .init_videobuf2 = mx3_camera_init_videobuf,
+ .reqbufs = mx3_camera_reqbufs,
+ .poll = mx3_camera_poll,
+ .querycap = mx3_camera_querycap,
+ .set_bus_param = mx3_camera_set_bus_param,
+};
+
+static int __devinit mx3_camera_probe(struct platform_device *pdev)
+{
+ struct mx3_camera_dev *mx3_cam;
+ struct resource *res;
+ void __iomem *base;
+ int err = 0;
+ struct soc_camera_host *soc_host;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto egetres;
+ }
+
+ mx3_cam = vzalloc(sizeof(*mx3_cam));
+ if (!mx3_cam) {
+ dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
+ err = -ENOMEM;
+ goto ealloc;
+ }
+
+ mx3_cam->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mx3_cam->clk)) {
+ err = PTR_ERR(mx3_cam->clk);
+ goto eclkget;
+ }
+
+ mx3_cam->pdata = pdev->dev.platform_data;
+ mx3_cam->platform_flags = mx3_cam->pdata->flags;
+ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) {
+ /*
+ * Platform hasn't set available data widths. This is bad.
+ * Warn and use a default.
+ */
+ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+ "data widths, using default 8 bit\n");
+ mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
+ }
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)
+ mx3_cam->width_flags = 1 << 3;
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+ mx3_cam->width_flags |= 1 << 7;
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+ mx3_cam->width_flags |= 1 << 9;
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+ mx3_cam->width_flags |= 1 << 14;
+
+ mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
+ if (!mx3_cam->mclk) {
+ dev_warn(&pdev->dev,
+ "mclk_10khz == 0! Please, fix your platform data. "
+ "Using default 20MHz\n");
+ mx3_cam->mclk = 20000000;
+ }
+
+ /* list of video-buffers */
+ INIT_LIST_HEAD(&mx3_cam->capture);
+ spin_lock_init(&mx3_cam->lock);
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
+ err = -ENOMEM;
+ goto eioremap;
+ }
+
+ mx3_cam->base = base;
+
+ soc_host = &mx3_cam->soc_host;
+ soc_host->drv_name = MX3_CAM_DRV_NAME;
+ soc_host->ops = &mx3_soc_camera_host_ops;
+ soc_host->priv = mx3_cam;
+ soc_host->v4l2_dev.dev = &pdev->dev;
+ soc_host->nr = pdev->id;
+
+ mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(mx3_cam->alloc_ctx)) {
+ err = PTR_ERR(mx3_cam->alloc_ctx);
+ goto eallocctx;
+ }
+
+ err = soc_camera_host_register(soc_host);
+ if (err)
+ goto ecamhostreg;
+
+ /* IDMAC interface */
+ dmaengine_get();
+
+ return 0;
+
+ecamhostreg:
+ vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+eallocctx:
+ iounmap(base);
+eioremap:
+ clk_put(mx3_cam->clk);
+eclkget:
+ vfree(mx3_cam);
+ealloc:
+egetres:
+ return err;
+}
+
+static int __devexit mx3_camera_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct mx3_camera_dev *mx3_cam = container_of(soc_host,
+ struct mx3_camera_dev, soc_host);
+
+ clk_put(mx3_cam->clk);
+
+ soc_camera_host_unregister(soc_host);
+
+ iounmap(mx3_cam->base);
+
+ /*
+ * The channel has either not been allocated,
+ * or should have been released
+ */
+ if (WARN_ON(mx3_cam->idmac_channel[0]))
+ dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
+
+ vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+
+ vfree(mx3_cam);
+
+ dmaengine_put();
+
+ return 0;
+}
+
+static struct platform_driver mx3_camera_driver = {
+ .driver = {
+ .name = MX3_CAM_DRV_NAME,
+ },
+ .probe = mx3_camera_probe,
+ .remove = __devexit_p(mx3_camera_remove),
+};
+
+module_platform_driver(mx3_camera_driver);
+
+MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2.3");
+MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
new file mode 100644
index 000000000000..fa08c7695ccb
--- /dev/null
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -0,0 +1,1723 @@
+/*
+ * V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA SoC camera driver
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/platform/omap/omap1510cam.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/omap1_camera.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
+
+#include <plat/dma.h>
+
+
+#define DRIVER_NAME "omap1-camera"
+#define DRIVER_VERSION "0.0.2"
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * OMAP1 Camera Interface registers
+ * ---------------------------------------------------------------------------
+ */
+
+#define REG_CTRLCLOCK 0x00
+#define REG_IT_STATUS 0x04
+#define REG_MODE 0x08
+#define REG_STATUS 0x0C
+#define REG_CAMDATA 0x10
+#define REG_GPIO 0x14
+#define REG_PEAK_COUNTER 0x18
+
+/* CTRLCLOCK bit shifts */
+#define LCLK_EN BIT(7)
+#define DPLL_EN BIT(6)
+#define MCLK_EN BIT(5)
+#define CAMEXCLK_EN BIT(4)
+#define POLCLK BIT(3)
+#define FOSCMOD_SHIFT 0
+#define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT)
+#define FOSCMOD_12MHz 0x0
+#define FOSCMOD_6MHz 0x2
+#define FOSCMOD_9_6MHz 0x4
+#define FOSCMOD_24MHz 0x5
+#define FOSCMOD_8MHz 0x6
+
+/* IT_STATUS bit shifts */
+#define DATA_TRANSFER BIT(5)
+#define FIFO_FULL BIT(4)
+#define H_DOWN BIT(3)
+#define H_UP BIT(2)
+#define V_DOWN BIT(1)
+#define V_UP BIT(0)
+
+/* MODE bit shifts */
+#define RAZ_FIFO BIT(18)
+#define EN_FIFO_FULL BIT(17)
+#define EN_NIRQ BIT(16)
+#define THRESHOLD_SHIFT 9
+#define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT)
+#define DMA BIT(8)
+#define EN_H_DOWN BIT(7)
+#define EN_H_UP BIT(6)
+#define EN_V_DOWN BIT(5)
+#define EN_V_UP BIT(4)
+#define ORDERCAMD BIT(3)
+
+#define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \
+ EN_NIRQ | EN_FIFO_FULL)
+
+/* STATUS bit shifts */
+#define HSTATUS BIT(1)
+#define VSTATUS BIT(0)
+
+/* GPIO bit shifts */
+#define CAM_RST BIT(0)
+
+/* end of OMAP1 Camera Interface registers */
+
+
+#define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \
+ V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+ V4L2_MBUS_DATA_ACTIVE_HIGH)
+
+
+#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
+#define FIFO_SHIFT __fls(FIFO_SIZE)
+
+#define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4)
+#define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT)
+
+#define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32
+#define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT)
+
+#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1)
+#define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT
+
+#define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \
+ DMA_FRAME_SHIFT_CONTIG : \
+ DMA_FRAME_SHIFT_SG)
+#define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x))
+#define DMA_SYNC OMAP_DMA_SYNC_FRAME
+#define THRESHOLD_LEVEL DMA_FRAME_SIZE
+
+
+#define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */
+
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct omap1_cam_buf {
+ struct videobuf_buffer vb;
+ enum v4l2_mbus_pixelcode code;
+ int inwork;
+ struct scatterlist *sgbuf;
+ int sgcount;
+ int bytes_left;
+ enum videobuf_state result;
+};
+
+struct omap1_cam_dev {
+ struct soc_camera_host soc_host;
+ struct soc_camera_device *icd;
+ struct clk *clk;
+
+ unsigned int irq;
+ void __iomem *base;
+
+ int dma_ch;
+
+ struct omap1_cam_platform_data *pdata;
+ struct resource *res;
+ unsigned long pflags;
+ unsigned long camexclk;
+
+ struct list_head capture;
+
+ /* lock used to protect videobuf */
+ spinlock_t lock;
+
+ /* Pointers to DMA buffers */
+ struct omap1_cam_buf *active;
+ struct omap1_cam_buf *ready;
+
+ enum omap1_cam_vb_mode vb_mode;
+ int (*mmap_mapper)(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ struct vm_area_struct *vma);
+
+ u32 reg_cache[0];
+};
+
+
+static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val)
+{
+ pcdev->reg_cache[reg / sizeof(u32)] = val;
+ __raw_writel(val, pcdev->base + reg);
+}
+
+static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache)
+{
+ return !from_cache ? __raw_readl(pcdev->base + reg) :
+ pcdev->reg_cache[reg / sizeof(u32)];
+}
+
+#define CAM_READ(pcdev, reg) \
+ cam_read(pcdev, REG_##reg, false)
+#define CAM_WRITE(pcdev, reg, val) \
+ cam_write(pcdev, REG_##reg, val)
+#define CAM_READ_CACHE(pcdev, reg) \
+ cam_read(pcdev, REG_##reg, true)
+
+/*
+ * Videobuf operations
+ */
+static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ *size = icd->sizeimage;
+
+ if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
+ *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
+
+ if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+ dev_dbg(icd->parent,
+ "%s: count=%d, size=%d\n", __func__, *count, *size);
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(vq, vb, 0, 0);
+
+ if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ videobuf_dma_contig_free(vq, vb);
+ } else {
+ struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->parent;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ videobuf_dma_unmap(dev, dma);
+ videobuf_dma_free(dma);
+ }
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int omap1_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ int ret;
+
+ WARN_ON(!list_empty(&vb->queue));
+
+ BUG_ON(NULL == icd->current_fmt);
+
+ buf->inwork = 1;
+
+ if (buf->code != icd->current_fmt->code || vb->field != field ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height) {
+ 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 = icd->sizeimage;
+
+ if (vb->baddr && vb->bsize < vb->size) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+ buf->inwork = 0;
+
+ return 0;
+fail:
+ free_buffer(vq, buf, pcdev->vb_mode);
+out:
+ buf->inwork = 0;
+ return ret;
+}
+
+static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ dma_addr_t dma_addr;
+ unsigned int block_size;
+
+ if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ dma_addr = videobuf_to_dma_contig(&buf->vb);
+ block_size = buf->vb.size;
+ } else {
+ if (WARN_ON(!buf->sgbuf)) {
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ dma_addr = sg_dma_address(buf->sgbuf);
+ if (WARN_ON(!dma_addr)) {
+ buf->sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ block_size = sg_dma_len(buf->sgbuf);
+ if (WARN_ON(!block_size)) {
+ buf->sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ if (unlikely(buf->bytes_left < block_size))
+ block_size = buf->bytes_left;
+ if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE - 1))) {
+ dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE);
+ block_size &= ~(DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE - 1);
+ }
+ buf->bytes_left -= block_size;
+ buf->sgcount++;
+ }
+
+ omap_set_dma_dest_params(dma_ch,
+ OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0);
+ omap_set_dma_transfer_params(dma_ch,
+ OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode),
+ block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT),
+ DMA_SYNC, 0, 0);
+}
+
+static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev)
+{
+ struct omap1_cam_buf *buf;
+
+ /*
+ * If there is already a buffer pointed out by the pcdev->ready,
+ * (re)use it, otherwise try to fetch and configure a new one.
+ */
+ buf = pcdev->ready;
+ if (!buf) {
+ if (list_empty(&pcdev->capture))
+ return buf;
+ buf = list_entry(pcdev->capture.next,
+ struct omap1_cam_buf, vb.queue);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ pcdev->ready = buf;
+ list_del_init(&buf->vb.queue);
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, we can safely enter next buffer parameters
+ * into the DMA programming register set after the DMA
+ * has already been activated on the previous buffer
+ */
+ set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode);
+ } else {
+ /*
+ * In SG mode, the above is not safe since there are probably
+ * a bunch of sgbufs from previous sglist still pending.
+ * Instead, mark the sglist fresh for the upcoming
+ * try_next_sgbuf().
+ */
+ buf->sgbuf = NULL;
+ }
+
+ return buf;
+}
+
+static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf)
+{
+ struct scatterlist *sgbuf;
+
+ if (likely(buf->sgbuf)) {
+ /* current sglist is active */
+ if (unlikely(!buf->bytes_left)) {
+ /* indicate sglist complete */
+ sgbuf = NULL;
+ } else {
+ /* process next sgbuf */
+ sgbuf = sg_next(buf->sgbuf);
+ if (WARN_ON(!sgbuf)) {
+ buf->result = VIDEOBUF_ERROR;
+ } else if (WARN_ON(!sg_dma_len(sgbuf))) {
+ sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ }
+ }
+ buf->sgbuf = sgbuf;
+ } else {
+ /* sglist is fresh, initialize it before using */
+ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+ sgbuf = dma->sglist;
+ if (!(WARN_ON(!sgbuf))) {
+ buf->sgbuf = sgbuf;
+ buf->sgcount = 0;
+ buf->bytes_left = buf->vb.size;
+ buf->result = VIDEOBUF_DONE;
+ }
+ }
+ if (sgbuf)
+ /*
+ * Put our next sgbuf parameters (address, size)
+ * into the DMA programming register set.
+ */
+ set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG);
+
+ return sgbuf;
+}
+
+static void start_capture(struct omap1_cam_dev *pcdev)
+{
+ struct omap1_cam_buf *buf = pcdev->active;
+ u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;
+
+ if (WARN_ON(!buf))
+ return;
+
+ /*
+ * Enable start of frame interrupt, which we will use for activating
+ * our end of frame watchdog when capture actually starts.
+ */
+ mode |= EN_V_UP;
+
+ if (unlikely(ctrlclock & LCLK_EN))
+ /* stop pixel clock before FIFO reset */
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+ /* reset FIFO */
+ CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);
+
+ omap_start_dma(pcdev->dma_ch);
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, it's a good moment for fetching next sgbuf
+ * from the current sglist and, if available, already putting
+ * its parameters into the DMA programming register set.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ /* (re)enable pixel clock */
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
+ /* release FIFO reset */
+ CAM_WRITE(pcdev, MODE, mode);
+}
+
+static void suspend_capture(struct omap1_cam_dev *pcdev)
+{
+ u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+ omap_stop_dma(pcdev->dma_ch);
+}
+
+static void disable_capture(struct omap1_cam_dev *pcdev)
+{
+ u32 mode = CAM_READ_CACHE(pcdev, MODE);
+
+ CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
+}
+
+static void omap1_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ struct omap1_cam_buf *buf;
+ u32 mode;
+
+ list_add_tail(&vb->queue, &pcdev->capture);
+ vb->state = VIDEOBUF_QUEUED;
+
+ if (pcdev->active) {
+ /*
+ * Capture in progress, so don't touch pcdev->ready even if
+ * empty. Since the transfer of the DMA programming register set
+ * content to the DMA working register set is done automatically
+ * by the DMA hardware, this can pretty well happen while we
+ * are keeping the lock here. Leave fetching it from the queue
+ * to be done when a next DMA interrupt occures instead.
+ */
+ return;
+ }
+
+ WARN_ON(pcdev->ready);
+
+ buf = prepare_next_vb(pcdev);
+ if (WARN_ON(!buf))
+ return;
+
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+
+ dev_dbg(icd->parent,
+ "%s: capture not active, setup FIFO, start DMA\n", __func__);
+ mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
+ mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
+ CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, the above prepare_next_vb() didn't actually
+ * put anything into the DMA programming register set,
+ * so we have to do it now, before activating DMA.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ start_capture(pcdev);
+}
+
+static void omap1_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct omap1_cam_buf *buf =
+ container_of(vb, struct omap1_cam_buf, vb);
+ struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->parent;
+ struct soc_camera_host *ici = to_soc_camera_host(dev);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ switch (vb->state) {
+ case VIDEOBUF_DONE:
+ dev_dbg(dev, "%s (done)\n", __func__);
+ break;
+ case VIDEOBUF_ACTIVE:
+ dev_dbg(dev, "%s (active)\n", __func__);
+ break;
+ case VIDEOBUF_QUEUED:
+ dev_dbg(dev, "%s (queued)\n", __func__);
+ break;
+ case VIDEOBUF_PREPARED:
+ dev_dbg(dev, "%s (prepared)\n", __func__);
+ break;
+ default:
+ dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state);
+ break;
+ }
+
+ free_buffer(vq, buf, pcdev->vb_mode);
+}
+
+static void videobuf_done(struct omap1_cam_dev *pcdev,
+ enum videobuf_state result)
+{
+ struct omap1_cam_buf *buf = pcdev->active;
+ struct videobuf_buffer *vb;
+ struct device *dev = pcdev->icd->parent;
+
+ if (WARN_ON(!buf)) {
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ return;
+ }
+
+ if (result == VIDEOBUF_ERROR)
+ suspend_capture(pcdev);
+
+ vb = &buf->vb;
+ if (waitqueue_active(&vb->done)) {
+ if (!pcdev->ready && result != VIDEOBUF_ERROR) {
+ /*
+ * No next buffer has been entered into the DMA
+ * programming register set on time (could be done only
+ * while the previous DMA interurpt was processed, not
+ * later), so the last DMA block, be it a whole buffer
+ * if in CONTIG or its last sgbuf if in SG mode, is
+ * about to be reused by the just autoreinitialized DMA
+ * engine, and overwritten with next frame data. Best we
+ * can do is stopping the capture as soon as possible,
+ * hopefully before the next frame start.
+ */
+ suspend_capture(pcdev);
+ }
+ vb->state = result;
+ do_gettimeofday(&vb->ts);
+ if (result != VIDEOBUF_ERROR)
+ vb->field_count++;
+ wake_up(&vb->done);
+
+ /* shift in next buffer */
+ buf = pcdev->ready;
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+
+ if (!buf) {
+ /*
+ * No next buffer was ready on time (see above), so
+ * indicate error condition to force capture restart or
+ * stop, depending on next buffer already queued or not.
+ */
+ result = VIDEOBUF_ERROR;
+ prepare_next_vb(pcdev);
+
+ buf = pcdev->ready;
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+ }
+ } else if (pcdev->ready) {
+ /*
+ * In both CONTIG and SG mode, the DMA engine has possibly
+ * been already autoreinitialized with the preprogrammed
+ * pcdev->ready buffer. We can either accept this fact
+ * and just swap the buffers, or provoke an error condition
+ * and restart capture. The former seems less intrusive.
+ */
+ dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
+ __func__);
+ pcdev->active = pcdev->ready;
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, we have to make sure that the buffer we
+ * are putting back into the pcdev->ready is marked
+ * fresh.
+ */
+ buf->sgbuf = NULL;
+ }
+ pcdev->ready = buf;
+
+ buf = pcdev->active;
+ } else {
+ /*
+ * No next buffer has been entered into
+ * the DMA programming register set on time.
+ */
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the DMA engine has already been
+ * reinitialized with the current buffer. Best we can do
+ * is not touching it.
+ */
+ dev_dbg(dev,
+ "%s: nobody waiting on videobuf, reuse it\n",
+ __func__);
+ } else {
+ /*
+ * In SG mode, the DMA engine has just been
+ * autoreinitialized with the last sgbuf from the
+ * current list. Restart capture in order to transfer
+ * next frame start into the first sgbuf, not the last
+ * one.
+ */
+ if (result != VIDEOBUF_ERROR) {
+ suspend_capture(pcdev);
+ result = VIDEOBUF_ERROR;
+ }
+ }
+ }
+
+ if (!buf) {
+ dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
+ disable_capture(pcdev);
+ return;
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the current buffer parameters had already
+ * been entered into the DMA programming register set while the
+ * buffer was fetched with prepare_next_vb(), they may have also
+ * been transferred into the runtime set and already active if
+ * the DMA still running.
+ */
+ } else {
+ /* In SG mode, extra steps are required */
+ if (result == VIDEOBUF_ERROR)
+ /* make sure we (re)use sglist from start on error */
+ buf->sgbuf = NULL;
+
+ /*
+ * In any case, enter the next sgbuf parameters into the DMA
+ * programming register set. They will be used either during
+ * nearest DMA autoreinitialization or, in case of an error,
+ * on DMA startup below.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ if (result == VIDEOBUF_ERROR) {
+ dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
+ __func__);
+ start_capture(pcdev);
+ /*
+ * In SG mode, the above also resulted in the next sgbuf
+ * parameters being entered into the DMA programming register
+ * set, making them ready for next DMA autoreinitialization.
+ */
+ }
+
+ /*
+ * Finally, try fetching next buffer.
+ * In CONTIG mode, it will also enter it into the DMA programming
+ * register set, making it ready for next DMA autoreinitialization.
+ */
+ prepare_next_vb(pcdev);
+}
+
+static void dma_isr(int channel, unsigned short status, void *data)
+{
+ struct omap1_cam_dev *pcdev = data;
+ struct omap1_cam_buf *buf = pcdev->active;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (WARN_ON(!buf)) {
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ goto out;
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, assume we have just managed to collect the
+ * whole frame, hopefully before our end of frame watchdog is
+ * triggered. Then, all we have to do is disabling the watchdog
+ * for this frame, and calling videobuf_done() with success
+ * indicated.
+ */
+ CAM_WRITE(pcdev, MODE,
+ CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
+ videobuf_done(pcdev, VIDEOBUF_DONE);
+ } else {
+ /*
+ * In SG mode, we have to process every sgbuf from the current
+ * sglist, one after another.
+ */
+ if (buf->sgbuf) {
+ /*
+ * Current sglist not completed yet, try fetching next
+ * sgbuf, hopefully putting it into the DMA programming
+ * register set, making it ready for next DMA
+ * autoreinitialization.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ if (buf->sgbuf)
+ goto out;
+
+ /*
+ * No more sgbufs left in the current sglist. This
+ * doesn't mean that the whole videobuffer is already
+ * complete, but only that the last sgbuf from the
+ * current sglist is about to be filled. It will be
+ * ready on next DMA interrupt, signalled with the
+ * buf->sgbuf set back to NULL.
+ */
+ if (buf->result != VIDEOBUF_ERROR) {
+ /*
+ * Video frame collected without errors so far,
+ * we can prepare for collecting a next one
+ * as soon as DMA gets autoreinitialized
+ * after the current (last) sgbuf is completed.
+ */
+ buf = prepare_next_vb(pcdev);
+ if (!buf)
+ goto out;
+
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ goto out;
+ }
+ }
+ /* end of videobuf */
+ videobuf_done(pcdev, buf->result);
+ }
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t cam_isr(int irq, void *data)
+{
+ struct omap1_cam_dev *pcdev = data;
+ struct device *dev = pcdev->icd->parent;
+ struct omap1_cam_buf *buf = pcdev->active;
+ u32 it_status;
+ unsigned long flags;
+
+ it_status = CAM_READ(pcdev, IT_STATUS);
+ if (!it_status)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (WARN_ON(!buf)) {
+ dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+ __func__, it_status);
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ goto out;
+ }
+
+ if (unlikely(it_status & FIFO_FULL)) {
+ dev_warn(dev, "%s: FIFO overflow\n", __func__);
+
+ } else if (it_status & V_DOWN) {
+ /* end of video frame watchdog */
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the watchdog is disabled with
+ * successful DMA end of block interrupt, and reenabled
+ * on next frame start. If we get here, there is nothing
+ * to check, we must be out of sync.
+ */
+ } else {
+ if (buf->sgcount == 2) {
+ /*
+ * If exactly 2 sgbufs from the next sglist have
+ * been programmed into the DMA engine (the
+ * first one already transferred into the DMA
+ * runtime register set, the second one still
+ * in the programming set), then we are in sync.
+ */
+ goto out;
+ }
+ }
+ dev_notice(dev, "%s: unexpected end of video frame\n",
+ __func__);
+
+ } else if (it_status & V_UP) {
+ u32 mode;
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, we need this interrupt every frame
+ * in oredr to reenable our end of frame watchdog.
+ */
+ mode = CAM_READ_CACHE(pcdev, MODE);
+ } else {
+ /*
+ * In SG mode, the below enabled end of frame watchdog
+ * is kept on permanently, so we can turn this one shot
+ * setup off.
+ */
+ mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
+ }
+
+ if (!(mode & EN_V_DOWN)) {
+ /* (re)enable end of frame watchdog interrupt */
+ mode |= EN_V_DOWN;
+ }
+ CAM_WRITE(pcdev, MODE, mode);
+ goto out;
+
+ } else {
+ dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+ __func__, it_status);
+ goto out;
+ }
+
+ videobuf_done(pcdev, VIDEOBUF_ERROR);
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct videobuf_queue_ops omap1_videobuf_ops = {
+ .buf_setup = omap1_videobuf_setup,
+ .buf_prepare = omap1_videobuf_prepare,
+ .buf_queue = omap1_videobuf_queue,
+ .buf_release = omap1_videobuf_release,
+};
+
+
+/*
+ * SOC Camera host operations
+ */
+
+static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
+{
+ /* apply/release camera sensor reset if requested by platform data */
+ if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH)
+ CAM_WRITE(pcdev, GPIO, reset);
+ else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW)
+ CAM_WRITE(pcdev, GPIO, !reset);
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on OMAP1 camera sensor interface
+ */
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ u32 ctrlclock;
+
+ if (pcdev->icd)
+ return -EBUSY;
+
+ clk_enable(pcdev->clk);
+
+ /* setup sensor clock */
+ ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
+ ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ ctrlclock &= ~FOSCMOD_MASK;
+ switch (pcdev->camexclk) {
+ case 6000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
+ break;
+ case 8000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
+ break;
+ case 9600000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
+ break;
+ case 12000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
+ break;
+ case 24000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
+ default:
+ break;
+ }
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);
+
+ /* enable internal clock */
+ ctrlclock |= MCLK_EN;
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ sensor_reset(pcdev, false);
+
+ pcdev->icd = icd;
+
+ dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
+ icd->devnum);
+ return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ u32 ctrlclock;
+
+ BUG_ON(icd != pcdev->icd);
+
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+
+ sensor_reset(pcdev, true);
+
+ /* disable and release system clocks */
+ ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);
+
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
+
+ clk_disable(pcdev->clk);
+
+ pcdev->icd = NULL;
+
+ dev_dbg(icd->parent,
+ "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
+/* Duplicate standard formats based on host capability of byte swapping */
+static const struct soc_mbus_lookup omap1_cam_formats[] = {
+{
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUYV",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YVYU",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "UYVY",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "VYUY",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .name = "RGB555",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .name = "RGB555X",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .name = "RGB565",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .name = "RGB565X",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
+},
+};
+
+static int omap1_cam_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);
+ struct device *dev = icd->parent;
+ int formats = 0, ret;
+ enum v4l2_mbus_pixelcode code;
+ const struct soc_mbus_pixelfmt *fmt;
+
+ 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_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
+ idx, code);
+ return 0;
+ }
+
+ /* Check support for the requested bits-per-sample */
+ if (fmt->bits_per_sample != 8)
+ return 0;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = soc_mbus_find_fmtdesc(code,
+ omap1_cam_formats,
+ ARRAY_SIZE(omap1_cam_formats));
+ xlate->code = code;
+ xlate++;
+ dev_dbg(dev,
+ "%s: providing format %s as byte swapped code #%d\n",
+ __func__, xlate->host_fmt->name, code);
+ }
+ default:
+ if (xlate)
+ dev_dbg(dev,
+ "%s: providing format %s in pass-through mode\n",
+ __func__, fmt->name);
+ }
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = fmt;
+ xlate->code = code;
+ xlate++;
+ }
+
+ return formats;
+}
+
+static bool is_dma_aligned(s32 bytes_per_line, unsigned int height,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ int size = bytes_per_line * height;
+
+ return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) &&
+ IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE);
+}
+
+static int dma_align(int *width, int *height,
+ const struct soc_mbus_pixelfmt *fmt,
+ enum omap1_cam_vb_mode vb_mode, bool enlarge)
+{
+ s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt);
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) {
+ unsigned int pxalign = __fls(bytes_per_line / *width);
+ unsigned int salign = DMA_FRAME_SHIFT(vb_mode) +
+ DMA_ELEMENT_SHIFT - pxalign;
+ unsigned int incr = enlarge << salign;
+
+ v4l_bound_align_image(width, 1, *width + incr, 0,
+ height, 1, *height + incr, 0, salign);
+ return 0;
+ }
+ return 1;
+}
+
+#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \
+({ \
+ struct soc_camera_sense sense = { \
+ .master_clock = pcdev->camexclk, \
+ .pixel_clock_max = 0, \
+ }; \
+ int __ret; \
+ \
+ if (pcdev->pdata) \
+ sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \
+ icd->sense = &sense; \
+ __ret = v4l2_subdev_call(sd, video, function, ##args); \
+ icd->sense = NULL; \
+ \
+ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \
+ if (sense.pixel_clock > sense.pixel_clock_max) { \
+ dev_err(dev, \
+ "%s: pixel clock %lu set by the camera too high!\n", \
+ __func__, sense.pixel_clock); \
+ __ret = -EINVAL; \
+ } \
+ } \
+ __ret; \
+})
+
+static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
+ struct soc_camera_device *icd, struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf,
+ const struct soc_camera_format_xlate *xlate)
+{
+ s32 bytes_per_line;
+ int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf);
+
+ if (ret < 0) {
+ dev_err(dev, "%s: s_mbus_fmt failed\n", __func__);
+ return ret;
+ }
+
+ if (mf->code != xlate->code) {
+ dev_err(dev, "%s: unexpected pixel code change\n", __func__);
+ return -EINVAL;
+ }
+
+ bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt);
+ if (bytes_per_line < 0) {
+ dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n",
+ __func__);
+ return bytes_per_line;
+ }
+
+ if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) {
+ dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n",
+ __func__, mf->width, mf->height);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int omap1_cam_set_crop(struct soc_camera_device *icd,
+ struct v4l2_crop *crop)
+{
+ struct v4l2_rect *rect = &crop->c;
+ const struct soc_camera_format_xlate *xlate = icd->current_fmt;
+ 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;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop);
+ if (ret < 0) {
+ dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__,
+ rect->width, rect->height, rect->left, rect->top);
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+ if (ret < 0) {
+ dev_warn(dev, "%s: failed to fetch current format\n", __func__);
+ return ret;
+ }
+
+ ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+ false);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+ __func__, mf.width, mf.height,
+ xlate->host_fmt->name);
+ return ret;
+ }
+
+ if (!ret) {
+ /* sensor returned geometry not DMA aligned, trying to fix */
+ ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to set format\n", __func__);
+ return ret;
+ }
+ }
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+
+ return 0;
+}
+
+static int omap1_cam_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct device *dev = icd->parent;
+ struct soc_camera_host *ici = to_soc_camera_host(dev);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(dev, "%s: format %#x not found\n", __func__,
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+ true);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+ __func__, pix->width, pix->height,
+ xlate->host_fmt->name);
+ return ret;
+ }
+
+ ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to set format\n", __func__);
+ return ret;
+ }
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+ icd->current_fmt = xlate;
+
+ return 0;
+}
+
+static int omap1_cam_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ 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;
+ /* TODO: limit to mx1 hardware capabilities */
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(icd->parent, "Format %#x not found\n",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ /* limit to sensor capabilities */
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+
+ return 0;
+}
+
+static bool sg_mode;
+
+/*
+ * Local mmap_mapper wrapper,
+ * used for detecting videobuf-dma-contig buffer allocation failures
+ * and switching to videobuf-dma-sg automatically for future attempts.
+ */
+static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ struct vm_area_struct *vma)
+{
+ struct soc_camera_device *icd = q->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ int ret;
+
+ ret = pcdev->mmap_mapper(q, buf, vma);
+
+ if (ret == -ENOMEM)
+ sg_mode = true;
+
+ return ret;
+}
+
+static void omap1_cam_init_videobuf(struct videobuf_queue *q,
+ struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ if (!sg_mode)
+ videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
+ icd->parent, &pcdev->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+ else
+ videobuf_queue_sg_init(q, &omap1_videobuf_ops,
+ icd->parent, &pcdev->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+
+ /* use videobuf mode (auto)selected with the module parameter */
+ pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
+
+ /*
+ * Ensure we substitute the videobuf-dma-contig version of the
+ * mmap_mapper() callback with our own wrapper, used for switching
+ * automatically to videobuf-dma-sg on buffer allocation failure.
+ */
+ if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) {
+ pcdev->mmap_mapper = q->int_ops->mmap_mapper;
+ q->int_ops->mmap_mapper = omap1_cam_mmap_mapper;
+ }
+}
+
+static int omap1_cam_reqbufs(struct soc_camera_device *icd,
+ struct v4l2_requestbuffers *p)
+{
+ int i;
+
+ /*
+ * This is for locking debugging only. I removed spinlocks and now I
+ * check whether .prepare is ever called on a linked buffer, or whether
+ * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+ * it hadn't triggered
+ */
+ for (i = 0; i < p->count; i++) {
+ struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
+ struct omap1_cam_buf, vb);
+ buf->inwork = 0;
+ INIT_LIST_HEAD(&buf->vb.queue);
+ }
+
+ return 0;
+}
+
+static int omap1_cam_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+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,};
+ unsigned long common_flags;
+ u32 ctrlclock, mode;
+ int ret;
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
+ if (!ret) {
+ common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS);
+ if (!common_flags) {
+ dev_warn(dev,
+ "Flags incompatible: camera 0x%x, host 0x%x\n",
+ cfg.flags, SOCAM_BUS_FLAGS);
+ return -EINVAL;
+ }
+ } else if (ret != -ENOIOCTLCMD) {
+ return ret;
+ } else {
+ common_flags = SOCAM_BUS_FLAGS;
+ }
+
+ /* Make choices, possibly based on platform configuration */
+ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
+ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
+ if (!pcdev->pdata ||
+ pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ else
+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
+ }
+
+ cfg.flags = common_flags;
+ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
+ common_flags, ret);
+ return ret;
+ }
+
+ ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ if (ctrlclock & LCLK_EN)
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+ if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) {
+ dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
+ ctrlclock |= POLCLK;
+ } else {
+ dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
+ ctrlclock &= ~POLCLK;
+ }
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+ if (ctrlclock & LCLK_EN)
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ /* select bus endianess */
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ fmt = xlate->host_fmt;
+
+ mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
+ if (fmt->order == SOC_MBUS_ORDER_LE) {
+ dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
+ CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
+ } else {
+ dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
+ CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
+ }
+
+ return 0;
+}
+
+static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct omap1_cam_buf *buf;
+
+ buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
+ vb.stream);
+
+ poll_wait(file, &buf->vb.done, pt);
+
+ if (buf->vb.state == VIDEOBUF_DONE ||
+ buf->vb.state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static struct soc_camera_host_ops omap1_host_ops = {
+ .owner = THIS_MODULE,
+ .add = omap1_cam_add_device,
+ .remove = omap1_cam_remove_device,
+ .get_formats = omap1_cam_get_formats,
+ .set_crop = omap1_cam_set_crop,
+ .set_fmt = omap1_cam_set_fmt,
+ .try_fmt = omap1_cam_try_fmt,
+ .init_videobuf = omap1_cam_init_videobuf,
+ .reqbufs = omap1_cam_reqbufs,
+ .querycap = omap1_cam_querycap,
+ .set_bus_param = omap1_cam_set_bus_param,
+ .poll = omap1_cam_poll,
+};
+
+static int __init omap1_cam_probe(struct platform_device *pdev)
+{
+ struct omap1_cam_dev *pcdev;
+ struct resource *res;
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int irq;
+ int err = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || (int)irq <= 0) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ clk = clk_get(&pdev->dev, "armper_ck");
+ if (IS_ERR(clk)) {
+ err = PTR_ERR(clk);
+ goto exit;
+ }
+
+ pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL);
+ if (!pcdev) {
+ dev_err(&pdev->dev, "Could not allocate pcdev\n");
+ err = -ENOMEM;
+ goto exit_put_clk;
+ }
+
+ pcdev->res = res;
+ pcdev->clk = clk;
+
+ pcdev->pdata = pdev->dev.platform_data;
+ if (pcdev->pdata) {
+ pcdev->pflags = pcdev->pdata->flags;
+ pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
+ }
+
+ switch (pcdev->camexclk) {
+ case 6000000:
+ case 8000000:
+ case 9600000:
+ case 12000000:
+ case 24000000:
+ break;
+ default:
+ /* pcdev->camexclk != 0 => pcdev->pdata != NULL */
+ dev_warn(&pdev->dev,
+ "Incorrect sensor clock frequency %ld kHz, "
+ "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
+ "please correct your platform data\n",
+ pcdev->pdata->camexclk_khz);
+ pcdev->camexclk = 0;
+ case 0:
+ dev_info(&pdev->dev, "Not providing sensor clock\n");
+ }
+
+ INIT_LIST_HEAD(&pcdev->capture);
+ spin_lock_init(&pcdev->lock);
+
+ /*
+ * Request the region.
+ */
+ if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
+ err = -EBUSY;
+ goto exit_kfree;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ pcdev->irq = irq;
+ pcdev->base = base;
+
+ sensor_reset(pcdev, true);
+
+ err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME,
+ dma_isr, (void *)pcdev, &pcdev->dma_ch);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n");
+ err = -EBUSY;
+ goto exit_iounmap;
+ }
+ dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch);
+
+ /* preconfigure DMA */
+ omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB,
+ OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA,
+ 0, 0);
+ omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4);
+ /* setup DMA autoinitialization */
+ omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch);
+
+ err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev);
+ if (err) {
+ dev_err(&pdev->dev, "Camera interrupt register failed\n");
+ goto exit_free_dma;
+ }
+
+ pcdev->soc_host.drv_name = DRIVER_NAME;
+ pcdev->soc_host.ops = &omap1_host_ops;
+ pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
+ pcdev->soc_host.nr = pdev->id;
+
+ err = soc_camera_host_register(&pcdev->soc_host);
+ if (err)
+ goto exit_free_irq;
+
+ dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n");
+
+ return 0;
+
+exit_free_irq:
+ free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+ omap_free_dma(pcdev->dma_ch);
+exit_iounmap:
+ iounmap(base);
+exit_release:
+ release_mem_region(res->start, resource_size(res));
+exit_kfree:
+ kfree(pcdev);
+exit_put_clk:
+ clk_put(clk);
+exit:
+ return err;
+}
+
+static int __exit omap1_cam_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct omap1_cam_dev *pcdev = container_of(soc_host,
+ struct omap1_cam_dev, soc_host);
+ struct resource *res;
+
+ free_irq(pcdev->irq, pcdev);
+
+ omap_free_dma(pcdev->dma_ch);
+
+ soc_camera_host_unregister(soc_host);
+
+ iounmap(pcdev->base);
+
+ res = pcdev->res;
+ release_mem_region(res->start, resource_size(res));
+
+ clk_put(pcdev->clk);
+
+ kfree(pcdev);
+
+ dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver omap1_cam_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = omap1_cam_probe,
+ .remove = __exit_p(omap1_cam_remove),
+};
+
+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");
+
+MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 9c21e01f2c24..9c21e01f2c24 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 0baaf94db7e0..0baaf94db7e0 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index 05286500b4d4..05286500b4d4 100644
--- a/drivers/media/video/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
new file mode 100644
index 000000000000..10b57f8e7ec8
--- /dev/null
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -0,0 +1,1605 @@
+/*
+ * camera image capture (abstract) bus driver
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This driver provides an interface between platform-specific camera
+ * busses and camera devices. It should be used if the camera is
+ * connected not over a "proper" bus like PCI or USB, but over a
+ * special bus, like, for example, the Quick Capture interface on PXA270
+ * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
+ * It can handle multiple cameras and / or multiple busses, which can
+ * be used, e.g., in stereo-vision applications.
+ *
+ * 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/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/vmalloc.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
+#include <media/soc_mediabus.h>
+
+/* Default to VGA resolution */
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+
+#define is_streaming(ici, icd) \
+ (((ici)->ops->init_videobuf) ? \
+ (icd)->vb_vidq.streaming : \
+ vb2_is_streaming(&(icd)->vb2_vidq))
+
+static LIST_HEAD(hosts);
+static LIST_HEAD(devices);
+static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
+
+int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl)
+{
+ int ret = regulator_bulk_enable(icl->num_regulators,
+ icl->regulators);
+ if (ret < 0) {
+ dev_err(dev, "Cannot enable regulators\n");
+ return ret;
+ }
+
+ if (icl->power) {
+ ret = icl->power(dev, 1);
+ if (ret < 0) {
+ dev_err(dev,
+ "Platform failed to power-on the camera.\n");
+ regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_power_on);
+
+int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl)
+{
+ int ret = 0;
+ int err;
+
+ if (icl->power) {
+ err = icl->power(dev, 0);
+ if (err < 0) {
+ dev_err(dev,
+ "Platform failed to power-off the camera.\n");
+ ret = err;
+ }
+ }
+
+ err = regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ if (err < 0) {
+ dev_err(dev, "Cannot disable regulators\n");
+ ret = ret ? : err;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_power_off);
+
+static int __soc_camera_power_on(struct soc_camera_device *icd)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
+
+ ret = v4l2_subdev_call(sd, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+
+ return 0;
+}
+
+static int __soc_camera_power_off(struct soc_camera_device *icd)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
+
+ ret = v4l2_subdev_call(sd, core, s_power, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+
+ return 0;
+}
+
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < icd->num_user_formats; i++)
+ if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+ return icd->user_formats + i;
+ return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
+
+/**
+ * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
+ * @icl: camera platform parameters
+ * @cfg: media bus configuration
+ * @return: resulting flags
+ */
+unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
+ const struct v4l2_mbus_config *cfg)
+{
+ unsigned long f, flags = cfg->flags;
+
+ /* If only one of the two polarities is supported, switch to the opposite */
+ if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+ f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW);
+ if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW;
+ }
+
+ if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+ f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW);
+ if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW;
+ }
+
+ if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+ f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING);
+ if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ }
+
+ return flags;
+}
+EXPORT_SYMBOL(soc_camera_apply_board_flags);
+
+#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
+ ((x) >> 24) & 0xff
+
+static int soc_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+ pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+ if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+ !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
+ pix->bytesperline = 0;
+ pix->sizeimage = 0;
+ }
+
+ ret = ici->ops->try_fmt(icd, f);
+ if (ret < 0)
+ return ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate)
+ return -EINVAL;
+
+ ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt);
+ if (ret < 0)
+ return ret;
+
+ pix->bytesperline = max_t(u32, pix->bytesperline, ret);
+
+ ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline,
+ pix->height);
+ if (ret < 0)
+ return ret;
+
+ pix->sizeimage = max_t(u32, pix->sizeimage, ret);
+
+ return 0;
+}
+
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_device *icd = file->private_data;
+
+ WARN_ON(priv != file->private_data);
+
+ /* Only single-plane capture is supported so far */
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* limit format to hardware capabilities */
+ return soc_camera_try_fmt(icd, f);
+}
+
+static int soc_camera_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ /* default is camera */
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_UNKNOWN;
+ strcpy(inp->name, "Camera");
+
+ return 0;
+}
+
+static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, core, s_std, *a);
+}
+
+static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, core, g_std, a);
+}
+
+static int soc_camera_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ return ici->ops->enum_framesizes(icd, fsize);
+}
+
+static int soc_camera_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int ret;
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
+
+ if (ici->ops->init_videobuf) {
+ ret = videobuf_reqbufs(&icd->vb_vidq, p);
+ if (ret < 0)
+ return ret;
+
+ ret = ici->ops->reqbufs(icd, p);
+ } else {
+ ret = vb2_reqbufs(&icd->vb2_vidq, p);
+ }
+
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
+
+ return ret;
+}
+
+static int soc_camera_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ if (ici->ops->init_videobuf)
+ return videobuf_querybuf(&icd->vb_vidq, p);
+ else
+ return vb2_querybuf(&icd->vb2_vidq, p);
+}
+
+static int soc_camera_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ if (ici->ops->init_videobuf)
+ return videobuf_qbuf(&icd->vb_vidq, p);
+ else
+ return vb2_qbuf(&icd->vb2_vidq, p);
+}
+
+static int soc_camera_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ if (ici->ops->init_videobuf)
+ return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ else
+ return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int soc_camera_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *create)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ /* videobuf2 only */
+ if (ici->ops->init_videobuf)
+ return -EINVAL;
+ else
+ return vb2_create_bufs(&icd->vb2_vidq, create);
+}
+
+static int soc_camera_prepare_buf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ /* videobuf2 only */
+ if (ici->ops->init_videobuf)
+ return -EINVAL;
+ else
+ return vb2_prepare_buf(&icd->vb2_vidq, b);
+}
+
+/* Always entered with .video_lock held */
+static int soc_camera_init_user_formats(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);
+ unsigned int i, fmts = 0, raw_fmts = 0;
+ int ret;
+ enum v4l2_mbus_pixelcode code;
+
+ while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
+ raw_fmts++;
+
+ if (!ici->ops->get_formats)
+ /*
+ * Fallback mode - the host will have to serve all
+ * sensor-provided formats one-to-one to the user
+ */
+ fmts = raw_fmts;
+ else
+ /*
+ * First pass - only count formats this host-sensor
+ * configuration can provide
+ */
+ for (i = 0; i < raw_fmts; i++) {
+ ret = ici->ops->get_formats(icd, i, NULL);
+ if (ret < 0)
+ return ret;
+ fmts += ret;
+ }
+
+ if (!fmts)
+ return -ENXIO;
+
+ icd->user_formats =
+ vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+ if (!icd->user_formats)
+ return -ENOMEM;
+
+ dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
+
+ /* Second pass - actually fill data formats */
+ fmts = 0;
+ for (i = 0; i < raw_fmts; i++)
+ if (!ici->ops->get_formats) {
+ v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
+ icd->user_formats[fmts].host_fmt =
+ soc_mbus_get_fmtdesc(code);
+ if (icd->user_formats[fmts].host_fmt)
+ icd->user_formats[fmts++].code = code;
+ } else {
+ ret = ici->ops->get_formats(icd, i,
+ &icd->user_formats[fmts]);
+ if (ret < 0)
+ goto egfmt;
+ fmts += ret;
+ }
+
+ icd->num_user_formats = fmts;
+ icd->current_fmt = &icd->user_formats[0];
+
+ return 0;
+
+egfmt:
+ vfree(icd->user_formats);
+ return ret;
+}
+
+/* Always entered with .video_lock held */
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ if (ici->ops->put_formats)
+ ici->ops->put_formats(icd);
+ icd->current_fmt = NULL;
+ icd->num_user_formats = 0;
+ vfree(icd->user_formats);
+ icd->user_formats = NULL;
+}
+
+/* Called with .vb_lock held, or from the first open(2), see comment there */
+static int soc_camera_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
+ pixfmtstr(pix->pixelformat), pix->width, pix->height);
+
+ /* We always call try_fmt() before set_fmt() or set_crop() */
+ ret = soc_camera_try_fmt(icd, f);
+ if (ret < 0)
+ return ret;
+
+ ret = ici->ops->set_fmt(icd, f);
+ if (ret < 0) {
+ return ret;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
+ dev_err(icd->pdev,
+ "Host driver hasn't set up current format correctly!\n");
+ return -EINVAL;
+ }
+
+ icd->user_width = pix->width;
+ icd->user_height = pix->height;
+ icd->bytesperline = pix->bytesperline;
+ icd->sizeimage = pix->sizeimage;
+ icd->colorspace = pix->colorspace;
+ icd->field = pix->field;
+ if (ici->ops->init_videobuf)
+ icd->vb_vidq.field = pix->field;
+
+ dev_dbg(icd->pdev, "set width: %d height: %d\n",
+ icd->user_width, icd->user_height);
+
+ /* set physical bus parameters */
+ return ici->ops->set_bus_param(icd);
+}
+
+static int soc_camera_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct soc_camera_host *ici;
+ int ret;
+
+ if (!to_soc_camera_control(icd))
+ /* No device driver attached */
+ return -ENODEV;
+
+ ici = to_soc_camera_host(icd->parent);
+
+ if (mutex_lock_interruptible(&icd->video_lock))
+ return -ERESTARTSYS;
+ if (!try_module_get(ici->ops->owner)) {
+ dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
+ ret = -EINVAL;
+ goto emodule;
+ }
+
+ icd->use_count++;
+
+ /* Now we really have to activate the camera */
+ if (icd->use_count == 1) {
+ /* Restore parameters before the last close() per V4L2 API */
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = icd->user_width,
+ .height = icd->user_height,
+ .field = icd->field,
+ .colorspace = icd->colorspace,
+ .pixelformat =
+ icd->current_fmt->host_fmt->fourcc,
+ },
+ };
+
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
+ /* Don't mess with the host during probe */
+ mutex_lock(&ici->host_lock);
+ ret = ici->ops->add(icd);
+ mutex_unlock(&ici->host_lock);
+ if (ret < 0) {
+ dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
+ goto eiciadd;
+ }
+
+ ret = __soc_camera_power_on(icd);
+ if (ret < 0)
+ goto epower;
+
+ pm_runtime_enable(&icd->vdev->dev);
+ ret = pm_runtime_resume(&icd->vdev->dev);
+ if (ret < 0 && ret != -ENOSYS)
+ goto eresume;
+
+ /*
+ * Try to configure with default parameters. Notice: this is the
+ * very first open, so, we cannot race against other calls,
+ * apart from someone else calling open() simultaneously, but
+ * .video_lock is protecting us against it.
+ */
+ ret = soc_camera_set_fmt(icd, &f);
+ if (ret < 0)
+ goto esfmt;
+
+ if (ici->ops->init_videobuf) {
+ ici->ops->init_videobuf(&icd->vb_vidq, icd);
+ } else {
+ ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd);
+ if (ret < 0)
+ goto einitvb;
+ }
+ v4l2_ctrl_handler_setup(&icd->ctrl_handler);
+ }
+ mutex_unlock(&icd->video_lock);
+
+ file->private_data = icd;
+ dev_dbg(icd->pdev, "camera device open\n");
+
+ return 0;
+
+ /*
+ * First four errors are entered with the .video_lock held
+ * and use_count == 1
+ */
+einitvb:
+esfmt:
+ pm_runtime_disable(&icd->vdev->dev);
+eresume:
+ __soc_camera_power_off(icd);
+epower:
+ ici->ops->remove(icd);
+eiciadd:
+ icd->use_count--;
+ module_put(ici->ops->owner);
+emodule:
+ mutex_unlock(&icd->video_lock);
+
+ return ret;
+}
+
+static int soc_camera_close(struct file *file)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ mutex_lock(&icd->video_lock);
+ icd->use_count--;
+ if (!icd->use_count) {
+ pm_runtime_suspend(&icd->vdev->dev);
+ pm_runtime_disable(&icd->vdev->dev);
+
+ if (ici->ops->init_videobuf2)
+ vb2_queue_release(&icd->vb2_vidq);
+ ici->ops->remove(icd);
+
+ __soc_camera_power_off(icd);
+ }
+
+ if (icd->streamer == file)
+ icd->streamer = NULL;
+ mutex_unlock(&icd->video_lock);
+
+ module_put(ici->ops->owner);
+
+ dev_dbg(icd->pdev, "camera device close\n");
+
+ return 0;
+}
+
+static ssize_t soc_camera_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct soc_camera_device *icd = file->private_data;
+ int err = -EINVAL;
+
+ dev_err(icd->pdev, "camera device read not implemented\n");
+
+ return err;
+}
+
+static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ int err;
+
+ dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&icd->video_lock))
+ return -ERESTARTSYS;
+ if (ici->ops->init_videobuf)
+ err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
+ else
+ err = vb2_mmap(&icd->vb2_vidq, vma);
+ mutex_unlock(&icd->video_lock);
+
+ dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+ err);
+
+ return err;
+}
+
+static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ unsigned res = POLLERR;
+
+ if (icd->streamer != file)
+ return POLLERR;
+
+ mutex_lock(&icd->video_lock);
+ if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream))
+ dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
+ else
+ res = ici->ops->poll(file, pt);
+ mutex_unlock(&icd->video_lock);
+ return res;
+}
+
+void soc_camera_lock(struct vb2_queue *vq)
+{
+ struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+ mutex_lock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_lock);
+
+void soc_camera_unlock(struct vb2_queue *vq)
+{
+ struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+ mutex_unlock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_unlock);
+
+static struct v4l2_file_operations soc_camera_fops = {
+ .owner = THIS_MODULE,
+ .open = soc_camera_open,
+ .release = soc_camera_close,
+ .unlocked_ioctl = video_ioctl2,
+ .read = soc_camera_read,
+ .mmap = soc_camera_mmap,
+ .poll = soc_camera_poll,
+};
+
+static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_device *icd = file->private_data;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type);
+ return -EINVAL;
+ }
+
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
+
+ if (is_streaming(to_soc_camera_host(icd->parent), icd)) {
+ dev_err(icd->pdev, "S_FMT denied: queue initialised\n");
+ return -EBUSY;
+ }
+
+ ret = soc_camera_set_fmt(icd, f);
+
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
+
+ return ret;
+}
+
+static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct soc_camera_device *icd = file->private_data;
+ const struct soc_mbus_pixelfmt *format;
+
+ WARN_ON(priv != file->private_data);
+
+ if (f->index >= icd->num_user_formats)
+ return -EINVAL;
+
+ format = icd->user_formats[f->index].host_fmt;
+
+ if (format->name)
+ strlcpy(f->description, format->name, sizeof(f->description));
+ f->pixelformat = format->fourcc;
+ return 0;
+}
+
+static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ WARN_ON(priv != file->private_data);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pix->width = icd->user_width;
+ pix->height = icd->user_height;
+ pix->bytesperline = icd->bytesperline;
+ pix->sizeimage = icd->sizeimage;
+ pix->field = icd->field;
+ pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
+ pix->colorspace = icd->colorspace;
+ dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n",
+ icd->current_fmt->host_fmt->fourcc);
+ return 0;
+}
+
+static int soc_camera_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
+ return ici->ops->querycap(ici, cap);
+}
+
+static int soc_camera_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ /* This calls buf_queue from host driver's videobuf_queue_ops */
+ if (ici->ops->init_videobuf)
+ ret = videobuf_streamon(&icd->vb_vidq);
+ else
+ ret = vb2_streamon(&icd->vb2_vidq, i);
+
+ if (!ret)
+ v4l2_subdev_call(sd, video, s_stream, 1);
+
+ return ret;
+}
+
+static int soc_camera_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ /*
+ * This calls buf_release from host driver's videobuf_queue_ops for all
+ * remaining buffers. When the last buffer is freed, stop capture
+ */
+ if (ici->ops->init_videobuf)
+ videobuf_streamoff(&icd->vb_vidq);
+ else
+ vb2_streamoff(&icd->vb2_vidq, i);
+
+ v4l2_subdev_call(sd, video, s_stream, 0);
+
+ return 0;
+}
+
+static int soc_camera_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ return ici->ops->cropcap(icd, a);
+}
+
+static int soc_camera_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ int ret;
+
+ ret = ici->ops->get_crop(icd, a);
+
+ return ret;
+}
+
+/*
+ * According to the V4L2 API, drivers shall not update the struct v4l2_crop
+ * argument with the actual geometry, instead, the user shall use G_CROP to
+ * retrieve it.
+ */
+static int soc_camera_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop current_crop;
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
+ rect->width, rect->height, rect->left, rect->top);
+
+ /* If get_crop fails, we'll let host and / or client drivers decide */
+ ret = ici->ops->get_crop(icd, &current_crop);
+
+ /* Prohibit window size change with initialised buffers */
+ if (ret < 0) {
+ dev_err(icd->pdev,
+ "S_CROP denied: getting current crop failed\n");
+ } else if ((a->c.width == current_crop.c.width &&
+ a->c.height == current_crop.c.height) ||
+ !is_streaming(ici, icd)) {
+ /* same size or not streaming - use .set_crop() */
+ ret = ici->ops->set_crop(icd, a);
+ } else if (ici->ops->set_livecrop) {
+ ret = ici->ops->set_livecrop(icd, a);
+ } else {
+ dev_err(icd->pdev,
+ "S_CROP denied: queue initialised and sizes differ\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+static int soc_camera_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ /* With a wrong type no need to try to fall back to cropping */
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!ici->ops->get_selection)
+ return -ENOTTY;
+
+ return ici->ops->get_selection(icd, s);
+}
+
+static int soc_camera_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ int ret;
+
+ /* In all these cases cropping emulation will not help */
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE &&
+ s->target != V4L2_SEL_TGT_CROP_ACTIVE))
+ return -EINVAL;
+
+ if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+ /* No output size change during a running capture! */
+ if (is_streaming(ici, icd) &&
+ (icd->user_width != s->r.width ||
+ icd->user_height != s->r.height))
+ return -EBUSY;
+
+ /*
+ * Only one user is allowed to change the output format, touch
+ * buffers, start / stop streaming, poll for data
+ */
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
+ }
+
+ if (!ici->ops->set_selection)
+ return -ENOTTY;
+
+ ret = ici->ops->set_selection(icd, s);
+ if (!ret &&
+ s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+ icd->user_width = s->r.width;
+ icd->user_height = s->r.height;
+ if (!icd->streamer)
+ icd->streamer = file;
+ }
+
+ return ret;
+}
+
+static int soc_camera_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ if (ici->ops->get_parm)
+ return ici->ops->get_parm(icd, a);
+
+ return -ENOIOCTLCMD;
+}
+
+static int soc_camera_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+ if (ici->ops->set_parm)
+ return ici->ops->set_parm(icd, a);
+
+ return -ENOIOCTLCMD;
+}
+
+static int soc_camera_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, core, g_chip_ident, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int soc_camera_g_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, core, g_register, reg);
+}
+
+static int soc_camera_s_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, core, s_register, reg);
+}
+#endif
+
+static int soc_camera_probe(struct soc_camera_device *icd);
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
+{
+ struct soc_camera_device *icd;
+
+ mutex_lock(&ici->host_lock);
+
+ list_for_each_entry(icd, &devices, list) {
+ if (icd->iface == ici->nr) {
+ int ret;
+
+ icd->parent = ici->v4l2_dev.dev;
+ ret = soc_camera_probe(icd);
+ }
+ }
+
+ mutex_unlock(&ici->host_lock);
+}
+
+#ifdef CONFIG_I2C_BOARDINFO
+static int soc_camera_init_i2c(struct soc_camera_device *icd,
+ struct soc_camera_link *icl)
+{
+ struct i2c_client *client;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+ struct v4l2_subdev *subdev;
+
+ if (!adap) {
+ dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
+ icl->i2c_adapter_id);
+ goto ei2cga;
+ }
+
+ icl->board_info->platform_data = icl;
+
+ subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+ icl->board_info, NULL);
+ if (!subdev)
+ goto ei2cnd;
+
+ client = v4l2_get_subdevdata(subdev);
+
+ /* Use to_i2c_client(dev) to recover the i2c client */
+ icd->control = &client->dev;
+
+ return 0;
+ei2cnd:
+ i2c_put_adapter(adap);
+ei2cga:
+ return -ENODEV;
+}
+
+static void soc_camera_free_i2c(struct soc_camera_device *icd)
+{
+ struct i2c_client *client =
+ to_i2c_client(to_soc_camera_control(icd));
+ struct i2c_adapter *adap = client->adapter;
+
+ icd->control = NULL;
+ v4l2_device_unregister_subdev(i2c_get_clientdata(client));
+ i2c_unregister_device(client);
+ i2c_put_adapter(adap);
+}
+#else
+#define soc_camera_init_i2c(icd, icl) (-ENODEV)
+#define soc_camera_free_i2c(icd) do {} while (0)
+#endif
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
+/* Called during host-driver probe */
+static int soc_camera_probe(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct device *control = NULL;
+ struct v4l2_subdev *sd;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
+
+ /*
+ * Currently the subdev with the largest number of controls (13) is
+ * ov6550. So let's pick 16 as a hint for the control handler. Note
+ * that this is a hint only: too large and you waste some memory, too
+ * small and there is a (very) small performance hit when looking up
+ * controls in the internal hash.
+ */
+ ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
+ icl->regulators);
+ 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;
+
+ /* Must have icd->vdev before registering the device */
+ ret = video_dev_create(icd);
+ if (ret < 0)
+ goto evdc;
+
+ /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
+ if (icl->board_info) {
+ ret = soc_camera_init_i2c(icd, icl);
+ if (ret < 0)
+ goto eadddev;
+ } else if (!icl->add_device || !icl->del_device) {
+ ret = -EINVAL;
+ goto eadddev;
+ } else {
+ if (icl->module_name)
+ ret = request_module(icl->module_name);
+
+ ret = icl->add_device(icd);
+ if (ret < 0)
+ goto eadddev;
+
+ /*
+ * FIXME: this is racy, have to use driver-binding notification,
+ * when it is available
+ */
+ control = to_soc_camera_control(icd);
+ if (!control || !control->driver || !dev_get_drvdata(control) ||
+ !try_module_get(control->driver->owner)) {
+ icl->del_device(icd);
+ ret = -ENODEV;
+ goto enodrv;
+ }
+ }
+
+ sd = soc_camera_to_subdev(icd);
+ sd->grp_id = soc_camera_grp_id(icd);
+ v4l2_set_subdev_hostdata(sd, icd);
+
+ if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler))
+ goto ectrl;
+
+ /* At this point client .probe() should have run already */
+ ret = soc_camera_init_user_formats(icd);
+ if (ret < 0)
+ goto eiufmt;
+
+ icd->field = V4L2_FIELD_ANY;
+
+ /*
+ * ..._video_start() will create a device node, video_register_device()
+ * itself is protected against concurrent open() calls, but we also have
+ * to protect our data.
+ */
+ mutex_lock(&icd->video_lock);
+
+ ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ goto evidstart;
+
+ /* Try to improve our guess of a reasonable window format */
+ if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+ icd->colorspace = mf.colorspace;
+ icd->field = mf.field;
+ }
+
+ ici->ops->remove(icd);
+
+ mutex_unlock(&icd->video_lock);
+
+ return 0;
+
+evidstart:
+ mutex_unlock(&icd->video_lock);
+ soc_camera_free_user_formats(icd);
+eiufmt:
+ectrl:
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ icl->del_device(icd);
+ module_put(control->driver->owner);
+ }
+enodrv:
+eadddev:
+ video_device_release(icd->vdev);
+ icd->vdev = NULL;
+evdc:
+ ici->ops->remove(icd);
+eadd:
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+ereg:
+ v4l2_ctrl_handler_free(&icd->ctrl_handler);
+ return ret;
+}
+
+/*
+ * This is called on device_unregister, which only means we have to disconnect
+ * from the host, but not remove ourselves from the device list
+ */
+static int soc_camera_remove(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct video_device *vdev = icd->vdev;
+
+ BUG_ON(!icd->parent);
+
+ v4l2_ctrl_handler_free(&icd->ctrl_handler);
+ if (vdev) {
+ video_unregister_device(vdev);
+ icd->vdev = NULL;
+ }
+
+ if (icl->board_info) {
+ soc_camera_free_i2c(icd);
+ } else {
+ struct device_driver *drv = to_soc_camera_control(icd)->driver;
+ if (drv) {
+ icl->del_device(icd);
+ module_put(drv->owner);
+ }
+ }
+ soc_camera_free_user_formats(icd);
+
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+
+ return 0;
+}
+
+static int default_cropcap(struct soc_camera_device *icd,
+ struct v4l2_cropcap *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, cropcap, a);
+}
+
+static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, g_crop, a);
+}
+
+static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, s_crop, a);
+}
+
+static int default_g_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int default_s_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
+static int default_enum_framesizes(struct soc_camera_device *icd,
+ struct v4l2_frmsizeenum *fsize)
+{
+ int ret;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ __u32 pixfmt = fsize->pixel_format;
+ struct v4l2_frmsizeenum fsize_mbus = *fsize;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate)
+ return -EINVAL;
+ /* map xlate-code to pixel_format, sensor only handle xlate-code*/
+ fsize_mbus.pixel_format = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
+ if (ret < 0)
+ return ret;
+
+ *fsize = fsize_mbus;
+ fsize->pixel_format = pixfmt;
+
+ return 0;
+}
+
+int soc_camera_host_register(struct soc_camera_host *ici)
+{
+ struct soc_camera_host *ix;
+ int ret;
+
+ if (!ici || !ici->ops ||
+ !ici->ops->try_fmt ||
+ !ici->ops->set_fmt ||
+ !ici->ops->set_bus_param ||
+ !ici->ops->querycap ||
+ ((!ici->ops->init_videobuf ||
+ !ici->ops->reqbufs) &&
+ !ici->ops->init_videobuf2) ||
+ !ici->ops->add ||
+ !ici->ops->remove ||
+ !ici->ops->poll ||
+ !ici->v4l2_dev.dev)
+ return -EINVAL;
+
+ if (!ici->ops->set_crop)
+ ici->ops->set_crop = default_s_crop;
+ if (!ici->ops->get_crop)
+ ici->ops->get_crop = default_g_crop;
+ if (!ici->ops->cropcap)
+ ici->ops->cropcap = default_cropcap;
+ if (!ici->ops->set_parm)
+ ici->ops->set_parm = default_s_parm;
+ if (!ici->ops->get_parm)
+ ici->ops->get_parm = default_g_parm;
+ if (!ici->ops->enum_framesizes)
+ ici->ops->enum_framesizes = default_enum_framesizes;
+
+ mutex_lock(&list_lock);
+ list_for_each_entry(ix, &hosts, list) {
+ if (ix->nr == ici->nr) {
+ ret = -EBUSY;
+ goto edevreg;
+ }
+ }
+
+ ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
+ if (ret < 0)
+ goto edevreg;
+
+ list_add_tail(&ici->list, &hosts);
+ mutex_unlock(&list_lock);
+
+ mutex_init(&ici->host_lock);
+ scan_add_host(ici);
+
+ return 0;
+
+edevreg:
+ mutex_unlock(&list_lock);
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_host_register);
+
+/* Unregister all clients! */
+void soc_camera_host_unregister(struct soc_camera_host *ici)
+{
+ struct soc_camera_device *icd;
+
+ mutex_lock(&list_lock);
+
+ list_del(&ici->list);
+ list_for_each_entry(icd, &devices, list)
+ if (icd->iface == ici->nr && to_soc_camera_control(icd))
+ soc_camera_remove(icd);
+
+ mutex_unlock(&list_lock);
+
+ v4l2_device_unregister(&ici->v4l2_dev);
+}
+EXPORT_SYMBOL(soc_camera_host_unregister);
+
+/* Image capture device */
+static int soc_camera_device_register(struct soc_camera_device *icd)
+{
+ struct soc_camera_device *ix;
+ int num = -1, i;
+
+ for (i = 0; i < 256 && num < 0; i++) {
+ num = i;
+ /* Check if this index is available on this interface */
+ list_for_each_entry(ix, &devices, list) {
+ if (ix->iface == icd->iface && ix->devnum == i) {
+ num = -1;
+ break;
+ }
+ }
+ }
+
+ if (num < 0)
+ /*
+ * ok, we have 256 cameras on this host...
+ * man, stay reasonable...
+ */
+ return -ENOMEM;
+
+ icd->devnum = num;
+ icd->use_count = 0;
+ icd->host_priv = NULL;
+ mutex_init(&icd->video_lock);
+
+ list_add_tail(&icd->list, &devices);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
+ .vidioc_querycap = soc_camera_querycap,
+ .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
+ .vidioc_enum_input = soc_camera_enum_input,
+ .vidioc_g_input = soc_camera_g_input,
+ .vidioc_s_input = soc_camera_s_input,
+ .vidioc_s_std = soc_camera_s_std,
+ .vidioc_g_std = soc_camera_g_std,
+ .vidioc_enum_framesizes = soc_camera_enum_framesizes,
+ .vidioc_reqbufs = soc_camera_reqbufs,
+ .vidioc_querybuf = soc_camera_querybuf,
+ .vidioc_qbuf = soc_camera_qbuf,
+ .vidioc_dqbuf = soc_camera_dqbuf,
+ .vidioc_create_bufs = soc_camera_create_bufs,
+ .vidioc_prepare_buf = soc_camera_prepare_buf,
+ .vidioc_streamon = soc_camera_streamon,
+ .vidioc_streamoff = soc_camera_streamoff,
+ .vidioc_cropcap = soc_camera_cropcap,
+ .vidioc_g_crop = soc_camera_g_crop,
+ .vidioc_s_crop = soc_camera_s_crop,
+ .vidioc_g_selection = soc_camera_g_selection,
+ .vidioc_s_selection = soc_camera_s_selection,
+ .vidioc_g_parm = soc_camera_g_parm,
+ .vidioc_s_parm = soc_camera_s_parm,
+ .vidioc_g_chip_ident = soc_camera_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = soc_camera_g_register,
+ .vidioc_s_register = soc_camera_s_register,
+#endif
+};
+
+static int video_dev_create(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct video_device *vdev = video_device_alloc();
+
+ if (!vdev)
+ return -ENOMEM;
+
+ strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
+
+ vdev->parent = icd->pdev;
+ vdev->current_norm = V4L2_STD_UNKNOWN;
+ vdev->fops = &soc_camera_fops;
+ vdev->ioctl_ops = &soc_camera_ioctl_ops;
+ vdev->release = video_device_release;
+ vdev->tvnorms = V4L2_STD_UNKNOWN;
+ vdev->ctrl_handler = &icd->ctrl_handler;
+ vdev->lock = &icd->video_lock;
+
+ icd->vdev = vdev;
+
+ return 0;
+}
+
+/*
+ * Called from soc_camera_probe() above (with .video_lock held???)
+ */
+static int soc_camera_video_start(struct soc_camera_device *icd)
+{
+ const struct device_type *type = icd->vdev->dev.type;
+ int ret;
+
+ if (!icd->parent)
+ return -ENODEV;
+
+ ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Restore device type, possibly set by the subdevice driver */
+ icd->vdev->dev.type = type;
+
+ return 0;
+}
+
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+{
+ struct soc_camera_link *icl = pdev->dev.platform_data;
+ struct soc_camera_device *icd;
+ int ret;
+
+ if (!icl)
+ return -EINVAL;
+
+ icd = kzalloc(sizeof(*icd), GFP_KERNEL);
+ if (!icd)
+ return -ENOMEM;
+
+ icd->iface = icl->bus_id;
+ icd->link = icl;
+ icd->pdev = &pdev->dev;
+ platform_set_drvdata(pdev, icd);
+
+ ret = soc_camera_device_register(icd);
+ if (ret < 0)
+ goto escdevreg;
+
+ icd->user_width = DEFAULT_WIDTH;
+ icd->user_height = DEFAULT_HEIGHT;
+
+ return 0;
+
+escdevreg:
+ kfree(icd);
+
+ return ret;
+}
+
+/*
+ * Only called on rmmod for each platform device, since they are not
+ * hot-pluggable. Now we know, that all our users - hosts and devices have
+ * been unloaded already
+ */
+static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+{
+ struct soc_camera_device *icd = platform_get_drvdata(pdev);
+
+ if (!icd)
+ return -EINVAL;
+
+ list_del(&icd->list);
+
+ kfree(icd);
+
+ return 0;
+}
+
+static struct platform_driver __refdata soc_camera_pdrv = {
+ .probe = soc_camera_pdrv_probe,
+ .remove = __devexit_p(soc_camera_pdrv_remove),
+ .driver = {
+ .name = "soc-camera-pdrv",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init soc_camera_init(void)
+{
+ return platform_driver_register(&soc_camera_pdrv);
+}
+
+static void __exit soc_camera_exit(void)
+{
+ platform_driver_unregister(&soc_camera_pdrv);
+}
+
+module_init(soc_camera_init);
+module_exit(soc_camera_exit);
+
+MODULE_DESCRIPTION("Image capture bus driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-camera-pdrv");
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
new file mode 100644
index 000000000000..7cf7fd16481f
--- /dev/null
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -0,0 +1,206 @@
+/*
+ * Generic Platform Camera Driver
+ *
+ * Copyright (C) 2008 Magnus Damm
+ * Based on mt9m001 driver,
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/soc_camera.h>
+#include <media/soc_camera_platform.h>
+
+struct soc_camera_platform_priv {
+ struct v4l2_subdev subdev;
+};
+
+static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+ return container_of(subdev, struct soc_camera_platform_priv, subdev);
+}
+
+static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+ return p->set_capture(p, enable);
+}
+
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ mf->width = p->format.width;
+ mf->height = p->format.height;
+ mf->code = p->format.code;
+ mf->colorspace = p->format.colorspace;
+ mf->field = p->format.field;
+
+ return 0;
+}
+
+static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ return soc_camera_set_power(p->icd->control, p->icd->link, on);
+}
+
+static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
+ .s_power = soc_camera_platform_s_power,
+};
+
+static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ if (index)
+ return -EINVAL;
+
+ *code = p->format.code;
+ return 0;
+}
+
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+ struct v4l2_crop *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = p->format.width;
+ a->c.height = p->format.height;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+ struct v4l2_cropcap *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = p->format.width;
+ a->bounds.height = p->format.height;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ cfg->flags = p->mbus_param;
+ cfg->type = p->mbus_type;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
+ .s_stream = soc_camera_platform_s_stream,
+ .enum_mbus_fmt = soc_camera_platform_enum_fmt,
+ .cropcap = soc_camera_platform_cropcap,
+ .g_crop = soc_camera_platform_g_crop,
+ .try_mbus_fmt = soc_camera_platform_fill_fmt,
+ .g_mbus_fmt = soc_camera_platform_fill_fmt,
+ .s_mbus_fmt = soc_camera_platform_fill_fmt,
+ .g_mbus_config = soc_camera_platform_g_mbus_config,
+};
+
+static struct v4l2_subdev_ops platform_subdev_ops = {
+ .core = &platform_subdev_core_ops,
+ .video = &platform_subdev_video_ops,
+};
+
+static int soc_camera_platform_probe(struct platform_device *pdev)
+{
+ struct soc_camera_host *ici;
+ struct soc_camera_platform_priv *priv;
+ struct soc_camera_platform_info *p = pdev->dev.platform_data;
+ struct soc_camera_device *icd;
+ int ret;
+
+ if (!p)
+ return -EINVAL;
+
+ if (!p->icd) {
+ dev_err(&pdev->dev,
+ "Platform has not set soc_camera_device pointer!\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ icd = p->icd;
+
+ /* soc-camera convention: control's drvdata points to the subdev */
+ platform_set_drvdata(pdev, &priv->subdev);
+ /* Set the control device reference */
+ icd->control = &pdev->dev;
+
+ ici = to_soc_camera_host(icd->parent);
+
+ v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
+ v4l2_set_subdevdata(&priv->subdev, p);
+ strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
+
+ ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
+ if (ret)
+ goto evdrs;
+
+ return ret;
+
+evdrs:
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+ return ret;
+}
+
+static int soc_camera_platform_remove(struct platform_device *pdev)
+{
+ struct soc_camera_platform_priv *priv = get_priv(pdev);
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev);
+
+ p->icd->control = NULL;
+ v4l2_device_unregister_subdev(&priv->subdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver soc_camera_platform_driver = {
+ .driver = {
+ .name = "soc_camera_platform",
+ .owner = THIS_MODULE,
+ },
+ .probe = soc_camera_platform_probe,
+ .remove = soc_camera_platform_remove,
+};
+
+module_platform_driver(soc_camera_platform_driver);
+
+MODULE_DESCRIPTION("SoC Camera Platform driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index a397812635d6..a397812635d6 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/platform/timblogiw.c
index 02194c056b00..02194c056b00 100644
--- a/drivers/media/video/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
diff --git a/drivers/media/video/via-camera.c b/drivers/media/platform/via-camera.c
index eb404c2ce270..eb404c2ce270 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/platform/via-camera.c
diff --git a/drivers/media/video/via-camera.h b/drivers/media/platform/via-camera.h
index b12a4b3d616f..b12a4b3d616f 100644
--- a/drivers/media/video/via-camera.h
+++ b/drivers/media/platform/via-camera.h
diff --git a/drivers/media/video/vino.c b/drivers/media/platform/vino.c
index aae1720b2f2d..aae1720b2f2d 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/platform/vino.c
diff --git a/drivers/media/video/vino.h b/drivers/media/platform/vino.h
index de2d615ae7c9..de2d615ae7c9 100644
--- a/drivers/media/video/vino.h
+++ b/drivers/media/platform/vino.h
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
new file mode 100644
index 000000000000..a6351c49bfd3
--- /dev/null
+++ b/drivers/media/platform/vivi.c
@@ -0,0 +1,1409 @@
+/*
+ * Virtual Video driver - This code emulates a real video device with v4l2 api
+ *
+ * Copyright (c) 2006 by:
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD Licence, 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <media/videobuf2-vmalloc.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/v4l2-common.h>
+
+#define VIVI_MODULE_NAME "vivi"
+
+/* Wake up at about 30 fps */
+#define WAKE_NUMERATOR 30
+#define WAKE_DENOMINATOR 1001
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+#define MAX_WIDTH 1920
+#define MAX_HEIGHT 1200
+
+#define VIVI_VERSION "0.8.1"
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(VIVI_VERSION);
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0644);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, uint, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+#define dprintk(dev, level, fmt, arg...) \
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* ------------------------------------------------------------------
+ Basic structures
+ ------------------------------------------------------------------*/
+
+struct vivi_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ u8 depth;
+ bool is_yuv;
+};
+
+static struct vivi_fmt formats[] = {
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .is_yuv = true,
+ },
+ {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .is_yuv = true,
+ },
+ {
+ .name = "4:2:2, packed, YVYU",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ .is_yuv = true,
+ },
+ {
+ .name = "4:2:2, packed, VYUY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .is_yuv = true,
+ },
+ {
+ .name = "RGB565 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+ .depth = 16,
+ },
+ {
+ .name = "RGB565 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .depth = 16,
+ },
+ {
+ .name = "RGB555 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+ .depth = 16,
+ },
+ {
+ .name = "RGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+ .depth = 16,
+ },
+ {
+ .name = "RGB24 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
+ .depth = 24,
+ },
+ {
+ .name = "RGB24 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
+ .depth = 24,
+ },
+ {
+ .name = "RGB32 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
+ .depth = 32,
+ },
+ {
+ .name = "RGB32 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
+ .depth = 32,
+ },
+};
+
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+ struct vivi_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == ARRAY_SIZE(formats))
+ return NULL;
+
+ return &formats[k];
+}
+
+/* buffer for one video frame */
+struct vivi_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ struct list_head list;
+ struct vivi_fmt *fmt;
+};
+
+struct vivi_dmaqueue {
+ struct list_head active;
+
+ /* thread for generating video stream*/
+ struct task_struct *kthread;
+ wait_queue_head_t wq;
+ /* Counters to control fps rate */
+ int frame;
+ int ini_jiffies;
+};
+
+static LIST_HEAD(vivi_devlist);
+
+struct vivi_dev {
+ struct list_head vivi_devlist;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct video_device vdev;
+
+ /* controls */
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *hue;
+ struct {
+ /* autogain/gain cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ };
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *alpha;
+ struct v4l2_ctrl *button;
+ struct v4l2_ctrl *boolean;
+ struct v4l2_ctrl *int32;
+ struct v4l2_ctrl *int64;
+ struct v4l2_ctrl *menu;
+ struct v4l2_ctrl *string;
+ struct v4l2_ctrl *bitmask;
+ struct v4l2_ctrl *int_menu;
+
+ spinlock_t slock;
+ struct mutex mutex;
+
+ struct vivi_dmaqueue vidq;
+
+ /* Several counters */
+ unsigned ms;
+ unsigned long jiffies;
+ unsigned button_pressed;
+
+ int mv_count; /* Controls bars movement */
+
+ /* Input Number */
+ int input;
+
+ /* video capture */
+ struct vivi_fmt *fmt;
+ unsigned int width, height;
+ struct vb2_queue vb_vidq;
+ unsigned int field_count;
+
+ u8 bars[9][3];
+ u8 line[MAX_WIDTH * 8];
+ unsigned int pixelsize;
+ u8 alpha_component;
+};
+
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+/* Bars and Colors should match positions */
+
+enum colors {
+ WHITE,
+ AMBER,
+ CYAN,
+ GREEN,
+ MAGENTA,
+ RED,
+ BLUE,
+ BLACK,
+ TEXT_BLACK,
+};
+
+/* R G B */
+#define COLOR_WHITE {204, 204, 204}
+#define COLOR_AMBER {208, 208, 0}
+#define COLOR_CYAN { 0, 206, 206}
+#define COLOR_GREEN { 0, 239, 0}
+#define COLOR_MAGENTA {239, 0, 239}
+#define COLOR_RED {205, 0, 0}
+#define COLOR_BLUE { 0, 0, 255}
+#define COLOR_BLACK { 0, 0, 0}
+
+struct bar_std {
+ u8 bar[9][3];
+};
+
+/* Maximum number of bars are 10 - otherwise, the input print code
+ should be modified */
+static struct bar_std bars[] = {
+ { /* Standard ITU-R color bar sequence */
+ { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
+ COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
+ }, {
+ { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
+ COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
+ }, {
+ { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
+ COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
+ }, {
+ { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
+ COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
+ },
+};
+
+#define NUM_INPUTS ARRAY_SIZE(bars)
+
+#define TO_Y(r, g, b) \
+ (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
+/* RGB to V(Cr) Color transform */
+#define TO_V(r, g, b) \
+ (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
+/* RGB to U(Cb) Color transform */
+#define TO_U(r, g, b) \
+ (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_bars(struct vivi_dev *dev)
+{
+ u8 r, g, b;
+ int k, is_yuv;
+
+ for (k = 0; k < 9; k++) {
+ r = bars[dev->input].bar[k][0];
+ g = bars[dev->input].bar[k][1];
+ b = bars[dev->input].bar[k][2];
+ is_yuv = dev->fmt->is_yuv;
+
+ switch (dev->fmt->fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ r >>= 3;
+ g >>= 2;
+ b >>= 3;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ case V4L2_PIX_FMT_RGB555X:
+ r >>= 3;
+ g >>= 3;
+ b >>= 3;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ break;
+ }
+
+ if (is_yuv) {
+ dev->bars[k][0] = TO_Y(r, g, b); /* Luma */
+ dev->bars[k][1] = TO_U(r, g, b); /* Cb */
+ dev->bars[k][2] = TO_V(r, g, b); /* Cr */
+ } else {
+ dev->bars[k][0] = r;
+ dev->bars[k][1] = g;
+ dev->bars[k][2] = b;
+ }
+ }
+}
+
+#define TSTAMP_MIN_Y 24
+#define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15)
+#define TSTAMP_INPUT_X 10
+#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
+{
+ u8 r_y, g_u, b_v;
+ u8 alpha = dev->alpha_component;
+ int color;
+ u8 *p;
+
+ r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
+ g_u = dev->bars[colorpos][1]; /* G or precalculated U */
+ b_v = dev->bars[colorpos][2]; /* B or precalculated V */
+
+ for (color = 0; color < dev->pixelsize; color++) {
+ p = buf + color;
+
+ switch (dev->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUYV:
+ switch (color) {
+ case 0:
+ *p = r_y;
+ break;
+ case 1:
+ *p = odd ? b_v : g_u;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ switch (color) {
+ case 0:
+ *p = odd ? b_v : g_u;
+ break;
+ case 1:
+ *p = r_y;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ switch (color) {
+ case 0:
+ *p = r_y;
+ break;
+ case 1:
+ *p = odd ? g_u : b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ switch (color) {
+ case 0:
+ *p = odd ? g_u : b_v;
+ break;
+ case 1:
+ *p = r_y;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ switch (color) {
+ case 0:
+ *p = (g_u << 5) | b_v;
+ break;
+ case 1:
+ *p = (r_y << 3) | (g_u >> 3);
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ switch (color) {
+ case 0:
+ *p = (r_y << 3) | (g_u >> 3);
+ break;
+ case 1:
+ *p = (g_u << 5) | b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ switch (color) {
+ case 0:
+ *p = (g_u << 5) | b_v;
+ break;
+ case 1:
+ *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB555X:
+ switch (color) {
+ case 0:
+ *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+ break;
+ case 1:
+ *p = (g_u << 5) | b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ switch (color) {
+ case 0:
+ *p = r_y;
+ break;
+ case 1:
+ *p = g_u;
+ break;
+ case 2:
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ switch (color) {
+ case 0:
+ *p = b_v;
+ break;
+ case 1:
+ *p = g_u;
+ break;
+ case 2:
+ *p = r_y;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ switch (color) {
+ case 0:
+ *p = alpha;
+ break;
+ case 1:
+ *p = r_y;
+ break;
+ case 2:
+ *p = g_u;
+ break;
+ case 3:
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ switch (color) {
+ case 0:
+ *p = b_v;
+ break;
+ case 1:
+ *p = g_u;
+ break;
+ case 2:
+ *p = r_y;
+ break;
+ case 3:
+ *p = alpha;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static void precalculate_line(struct vivi_dev *dev)
+{
+ int w;
+
+ for (w = 0; w < dev->width * 2; w++) {
+ int colorpos = w / (dev->width / 8) % 8;
+
+ gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
+ }
+}
+
+static void gen_text(struct vivi_dev *dev, char *basep,
+ int y, int x, char *text)
+{
+ int line;
+
+ /* Checks if it is possible to show string */
+ if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
+ return;
+
+ /* Print stream time */
+ for (line = y; line < y + 16; line++) {
+ int j = 0;
+ char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
+ char *s;
+
+ for (s = text; *s; s++) {
+ u8 chr = font8x16[*s * 16 + line - y];
+ int i;
+
+ for (i = 0; i < 7; i++, j++) {
+ /* Draw white font on black background */
+ if (chr & (1 << (7 - i)))
+ gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
+ else
+ gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
+ }
+ }
+ }
+}
+
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+{
+ int wmax = dev->width;
+ int hmax = dev->height;
+ struct timeval ts;
+ void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+ unsigned ms;
+ char str[100];
+ int h, line = 1;
+ s32 gain;
+
+ if (!vbuf)
+ return;
+
+ for (h = 0; h < hmax; h++)
+ memcpy(vbuf + h * wmax * dev->pixelsize,
+ dev->line + (dev->mv_count % wmax) * dev->pixelsize,
+ wmax * dev->pixelsize);
+
+ /* Updates stream time */
+
+ dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
+ dev->jiffies = jiffies;
+ ms = dev->ms;
+ snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
+ (ms / (60 * 60 * 1000)) % 24,
+ (ms / (60 * 1000)) % 60,
+ (ms / 1000) % 60,
+ ms % 1000);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " %dx%d, input %d ",
+ dev->width, dev->height, dev->input);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+
+ gain = v4l2_ctrl_g_ctrl(dev->gain);
+ mutex_lock(dev->ctrl_handler.lock);
+ snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+ dev->brightness->cur.val,
+ dev->contrast->cur.val,
+ dev->saturation->cur.val,
+ dev->hue->cur.val);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
+ dev->autogain->cur.val, gain, dev->volume->cur.val,
+ dev->alpha->cur.val);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
+ dev->int32->cur.val,
+ dev->int64->cur.val64,
+ dev->bitmask->cur.val);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+ dev->boolean->cur.val,
+ dev->menu->qmenu[dev->menu->cur.val],
+ dev->string->cur.string);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+ dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+ dev->int_menu->cur.val);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ mutex_unlock(dev->ctrl_handler.lock);
+ if (dev->button_pressed) {
+ dev->button_pressed--;
+ snprintf(str, sizeof(str), " button pressed!");
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ }
+
+ dev->mv_count += 2;
+
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ dev->field_count++;
+ buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+ do_gettimeofday(&ts);
+ buf->vb.v4l2_buf.timestamp = ts;
+}
+
+static void vivi_thread_tick(struct vivi_dev *dev)
+{
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
+ struct vivi_buffer *buf;
+ unsigned long flags = 0;
+
+ dprintk(dev, 1, "Thread tick\n");
+
+ spin_lock_irqsave(&dev->slock, flags);
+ if (list_empty(&dma_q->active)) {
+ dprintk(dev, 1, "No active queue to serve\n");
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return;
+ }
+
+ buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+ list_del(&buf->list);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+
+ /* Fill buffer */
+ vivi_fillbuff(dev, buf);
+ dprintk(dev, 1, "filled buffer %p\n", buf);
+
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+}
+
+#define frames_to_ms(frames) \
+ ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
+static void vivi_sleep(struct vivi_dev *dev)
+{
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
+ int timeout;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
+ (unsigned long)dma_q);
+
+ add_wait_queue(&dma_q->wq, &wait);
+ if (kthread_should_stop())
+ goto stop_task;
+
+ /* Calculate time to wake up */
+ timeout = msecs_to_jiffies(frames_to_ms(1));
+
+ vivi_thread_tick(dev);
+
+ schedule_timeout_interruptible(timeout);
+
+stop_task:
+ remove_wait_queue(&dma_q->wq, &wait);
+ try_to_freeze();
+}
+
+static int vivi_thread(void *data)
+{
+ struct vivi_dev *dev = data;
+
+ dprintk(dev, 1, "thread started\n");
+
+ set_freezable();
+
+ for (;;) {
+ vivi_sleep(dev);
+
+ if (kthread_should_stop())
+ break;
+ }
+ dprintk(dev, 1, "thread: exit\n");
+ return 0;
+}
+
+static int vivi_start_generating(struct vivi_dev *dev)
+{
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ /* Resets frame counters */
+ dev->ms = 0;
+ dev->mv_count = 0;
+ dev->jiffies = jiffies;
+
+ dma_q->frame = 0;
+ dma_q->ini_jiffies = jiffies;
+ dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
+
+ if (IS_ERR(dma_q->kthread)) {
+ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+ return PTR_ERR(dma_q->kthread);
+ }
+ /* Wakes thread */
+ wake_up_interruptible(&dma_q->wq);
+
+ dprintk(dev, 1, "returning from %s\n", __func__);
+ return 0;
+}
+
+static void vivi_stop_generating(struct vivi_dev *dev)
+{
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ /* shutdown control thread */
+ if (dma_q->kthread) {
+ kthread_stop(dma_q->kthread);
+ dma_q->kthread = NULL;
+ }
+
+ /*
+ * Typical driver might need to wait here until dma engine stops.
+ * In this case we can abort imiedetly, so it's just a noop.
+ */
+
+ /* Release all active buffers */
+ while (!list_empty(&dma_q->active)) {
+ struct vivi_buffer *buf;
+ buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+ }
+}
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ unsigned long size;
+
+ if (fmt)
+ size = fmt->fmt.pix.sizeimage;
+ else
+ size = dev->width * dev->height * dev->pixelsize;
+
+ if (size == 0)
+ return -EINVAL;
+
+ if (0 == *nbuffers)
+ *nbuffers = 32;
+
+ while (size * *nbuffers > vid_limit * 1024 * 1024)
+ (*nbuffers)--;
+
+ *nplanes = 1;
+
+ sizes[0] = size;
+
+ /*
+ * videobuf2-vmalloc allocator is context-less so no need to set
+ * alloc_ctxs array.
+ */
+
+ dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+ *nbuffers, size);
+
+ return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
+ unsigned long size;
+
+ dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
+
+ BUG_ON(NULL == dev->fmt);
+
+ /*
+ * Theses properties only change when queue is idle, see s_fmt.
+ * The below checks should not be performed here, on each
+ * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+ * should thus be moved to buffer_init and s_fmt.
+ */
+ if (dev->width < 48 || dev->width > MAX_WIDTH ||
+ dev->height < 32 || dev->height > MAX_HEIGHT)
+ return -EINVAL;
+
+ size = dev->width * dev->height * dev->pixelsize;
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(&buf->vb, 0, size);
+
+ buf->fmt = dev->fmt;
+
+ precalculate_bars(dev);
+ precalculate_line(dev);
+
+ return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
+ struct vivi_dmaqueue *vidq = &dev->vidq;
+ unsigned long flags = 0;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vidq->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ dprintk(dev, 1, "%s\n", __func__);
+ return vivi_start_generating(dev);
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ dprintk(dev, 1, "%s\n", __func__);
+ vivi_stop_generating(dev);
+ return 0;
+}
+
+static void vivi_lock(struct vb2_queue *vq)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ mutex_lock(&dev->mutex);
+}
+
+static void vivi_unlock(struct vb2_queue *vq)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ mutex_unlock(&dev->mutex);
+}
+
+
+static struct vb2_ops vivi_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vivi_unlock,
+ .wait_finish = vivi_lock,
+};
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+
+ strcpy(cap->driver, "vivi");
+ strcpy(cap->card, "vivi");
+ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct vivi_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * dev->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ if (dev->fmt->is_yuv)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+ struct vivi_fmt *fmt;
+
+ fmt = get_format(f);
+ if (!fmt) {
+ dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+ f->fmt.pix.pixelformat);
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ fmt = get_format(f);
+ }
+
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+ &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ if (fmt->is_yuv)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ f->fmt.pix.priv = 0;
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+ struct vb2_queue *q = &dev->vb_vidq;
+
+ int ret = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ if (vb2_is_busy(q)) {
+ dprintk(dev, 1, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ dev->fmt = get_format(f);
+ dev->pixelsize = dev->fmt->depth / 8;
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+
+ return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ static const struct v4l2_frmsize_stepwise sizes = {
+ 48, MAX_WIDTH, 4,
+ 32, MAX_HEIGHT, 1
+ };
+ int i;
+
+ if (fsize->index)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(formats); i++)
+ if (formats[i].fourcc == fsize->pixel_format)
+ break;
+ if (i == ARRAY_SIZE(formats))
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = sizes;
+ return 0;
+}
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index >= NUM_INPUTS)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ sprintf(inp->name, "Camera %u", inp->index);
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+
+ *i = dev->input;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+
+ if (i >= NUM_INPUTS)
+ return -EINVAL;
+
+ if (i == dev->input)
+ return 0;
+
+ dev->input = i;
+ precalculate_bars(dev);
+ precalculate_line(dev);
+ return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+
+static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+ if (ctrl == dev->autogain)
+ dev->gain->val = jiffies & 0xff;
+ return 0;
+}
+
+static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ dev->alpha_component = ctrl->val;
+ break;
+ default:
+ if (ctrl == dev->button)
+ dev->button_pressed = 30;
+ break;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ File operations for the device
+ ------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+ .g_volatile_ctrl = vivi_g_volatile_ctrl,
+ .s_ctrl = vivi_s_ctrl,
+};
+
+#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
+
+static const struct v4l2_ctrl_config vivi_ctrl_button = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 0,
+ .name = "Button",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 1,
+ .name = "Boolean",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 2,
+ .name = "Integer 32 Bits",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0x80000000,
+ .max = 0x7fffffff,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 3,
+ .name = "Integer 64 Bits",
+ .type = V4L2_CTRL_TYPE_INTEGER64,
+};
+
+static const char * const vivi_ctrl_menu_strings[] = {
+ "Menu Item 0 (Skipped)",
+ "Menu Item 1",
+ "Menu Item 2 (Skipped)",
+ "Menu Item 3",
+ "Menu Item 4",
+ "Menu Item 5 (Skipped)",
+ NULL,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_menu = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 4,
+ .name = "Menu",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 1,
+ .max = 4,
+ .def = 3,
+ .menu_skip_mask = 0x04,
+ .qmenu = vivi_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 5,
+ .name = "String",
+ .type = V4L2_CTRL_TYPE_STRING,
+ .min = 2,
+ .max = 4,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 6,
+ .name = "Bitmask",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .def = 0x80002000,
+ .min = 0,
+ .max = 0x80402010,
+ .step = 0,
+};
+
+static const s64 vivi_ctrl_int_menu_values[] = {
+ 1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 7,
+ .name = "Integer menu",
+ .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+ .min = 1,
+ .max = 8,
+ .def = 4,
+ .menu_skip_mask = 0x02,
+ .qmenu_int = vivi_ctrl_int_menu_values,
+};
+
+static const struct v4l2_file_operations vivi_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops vivi_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_framesizes = vidioc_enum_framesizes,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static struct video_device vivi_template = {
+ .name = "vivi",
+ .fops = &vivi_fops,
+ .ioctl_ops = &vivi_ioctl_ops,
+ .release = video_device_release_empty,
+};
+
+/* -----------------------------------------------------------------
+ Initialization and module stuff
+ ------------------------------------------------------------------*/
+
+static int vivi_release(void)
+{
+ struct vivi_dev *dev;
+ struct list_head *list;
+
+ while (!list_empty(&vivi_devlist)) {
+ list = vivi_devlist.next;
+ list_del(list);
+ dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->vdev));
+ video_unregister_device(&dev->vdev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ kfree(dev);
+ }
+
+ return 0;
+}
+
+static int __init vivi_create_instance(int inst)
+{
+ struct vivi_dev *dev;
+ struct video_device *vfd;
+ struct v4l2_ctrl_handler *hdl;
+ struct vb2_queue *q;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s-%03d", VIVI_MODULE_NAME, inst);
+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+ if (ret)
+ goto free_dev;
+
+ dev->fmt = &formats[0];
+ dev->width = 640;
+ dev->height = 480;
+ dev->pixelsize = dev->fmt->depth / 8;
+ hdl = &dev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 11);
+ dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+ dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+ dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 16);
+ dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 127);
+ dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_GAIN, 0, 255, 1, 100);
+ dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+ dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
+ dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
+ dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
+ dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
+ dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
+ dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+ dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
+ dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
+ if (hdl->error) {
+ ret = hdl->error;
+ goto unreg_dev;
+ }
+ v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+ dev->v4l2_dev.ctrl_handler = hdl;
+
+ /* initialize locks */
+ spin_lock_init(&dev->slock);
+
+ /* initialize queue */
+ q = &dev->vb_vidq;
+ memset(q, 0, sizeof(dev->vb_vidq));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivi_buffer);
+ q->ops = &vivi_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ vb2_queue_init(q);
+
+ mutex_init(&dev->mutex);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ init_waitqueue_head(&dev->vidq.wq);
+
+ vfd = &dev->vdev;
+ *vfd = vivi_template;
+ vfd->debug = debug;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = q;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+ /*
+ * Provide a mutex to v4l2 core. It will be used to protect
+ * all fops and v4l2 ioctls.
+ */
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+ if (ret < 0)
+ goto unreg_dev;
+
+ /* Now that everything is fine, let's add it to device list */
+ list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+
+ v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+ video_device_node_name(vfd));
+ return 0;
+
+unreg_dev:
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+ kfree(dev);
+ return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+ The real maximum number of virtual drivers will depend on how many drivers
+ will succeed. This is limited to the maximum number of devices that
+ videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivi_init(void)
+{
+ const struct font_desc *font = find_font("VGA8x16");
+ int ret = 0, i;
+
+ if (font == NULL) {
+ printk(KERN_ERR "vivi: could not find font\n");
+ return -ENODEV;
+ }
+ font8x16 = font->data;
+
+ if (n_devs <= 0)
+ n_devs = 1;
+
+ for (i = 0; i < n_devs; i++) {
+ ret = vivi_create_instance(i);
+ if (ret) {
+ /* If some instantiations succeeded, keep driver */
+ if (i)
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret < 0) {
+ printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
+ return ret;
+ }
+
+ printk(KERN_INFO "Video Technology Magazine Virtual Video "
+ "Capture Board ver %s successfully loaded.\n",
+ VIVI_VERSION);
+
+ /* n_devs will reflect the actual number of allocated devices */
+ n_devs = i;
+
+ return ret;
+}
+
+static void __exit vivi_exit(void)
+{
+ vivi_release();
+}
+
+module_init(vivi_init);
+module_exit(vivi_exit);
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index 7b4efdfaae28..7c730a0277ab 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -86,12 +86,8 @@ static int shark_write_reg(struct radio_tea5777 *tea, u64 reg)
for (i = 0; i < 6; i++)
shark->transfer_buffer[i + 1] = (reg >> (40 - i * 8)) & 0xff;
- v4l2_dbg(1, debug, tea->v4l2_dev,
- "shark2-write: %02x %02x %02x %02x %02x %02x %02x\n",
- shark->transfer_buffer[0], shark->transfer_buffer[1],
- shark->transfer_buffer[2], shark->transfer_buffer[3],
- shark->transfer_buffer[4], shark->transfer_buffer[5],
- shark->transfer_buffer[6]);
+ v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-write: %*ph\n",
+ 7, shark->transfer_buffer);
res = usb_interrupt_msg(shark->usbdev,
usb_sndintpipe(shark->usbdev, SHARK_OUT_EP),
@@ -134,9 +130,8 @@ static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret)
for (i = 0; i < 3; i++)
reg |= shark->transfer_buffer[i] << (16 - i * 8);
- v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %02x %02x %02x\n",
- shark->transfer_buffer[0], shark->transfer_buffer[1],
- shark->transfer_buffer[2]);
+ v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %*ph\n",
+ 3, shark->transfer_buffer);
*reg_ret = reg;
return 0;
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index c54210c7fef9..5f366d16be26 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -268,7 +268,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto exit;
}
- rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL);
+ rsdev = devm_kzalloc(&pdev->dev, sizeof(*rsdev), GFP_KERNEL);
if (!rsdev) {
dev_err(&pdev->dev, "Failed to alloc video device.\n");
rval = -ENOMEM;
@@ -278,7 +278,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
if (rval) {
dev_err(&pdev->dev, "Failed to register v4l2 device.\n");
- goto free_rsdev;
+ goto exit;
}
adapter = i2c_get_adapter(pdata->i2c_bus);
@@ -322,8 +322,6 @@ put_adapter:
i2c_put_adapter(adapter);
unregister_v4l2_dev:
v4l2_device_unregister(&rsdev->v4l2_dev);
-free_rsdev:
- kfree(rsdev);
exit:
return rval;
}
@@ -342,7 +340,6 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
video_unregister_device(rsdev->radio_dev);
i2c_put_adapter(client->adapter);
v4l2_device_unregister(&rsdev->v4l2_dev);
- kfree(rsdev);
return 0;
}
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 7052adc0c0b0..09fc56052d35 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -157,7 +157,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
goto err;
}
- tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+ tr = devm_kzalloc(&pdev->dev, sizeof(*tr), GFP_KERNEL);
if (!tr) {
err = -ENOMEM;
goto err;
@@ -177,7 +177,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
if (err)
- goto err_v4l2_dev;
+ goto err;
tr->video_dev.v4l2_dev = &tr->v4l2_dev;
@@ -195,8 +195,6 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
err_video_req:
video_device_release_empty(&tr->video_dev);
v4l2_device_unregister(&tr->v4l2_dev);
-err_v4l2_dev:
- kfree(tr);
err:
dev_err(&pdev->dev, "Failed to register: %d\n", err);
@@ -212,8 +210,6 @@ static int __devexit timbradio_remove(struct platform_device *pdev)
v4l2_device_unregister(&tr->v4l2_dev);
- kfree(tr);
-
return 0;
}
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index e8428f573ccd..a22ad1c1f3d5 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1983,9 +1983,6 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
v4l2_ctrl_handler_free(&radio->ctrl_handler);
video_unregister_device(&radio->videodev);
v4l2_device_unregister(&radio->v4l2dev);
- kfree(radio->buffer);
- kfree(radio->write_buf);
- kfree(radio);
return 0;
}
@@ -2005,7 +2002,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
goto pdata_err;
}
- radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+ radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
if (!radio) {
r = -ENOMEM;
goto pdata_err;
@@ -2013,11 +2010,11 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
/* RDS buffer allocation */
radio->buf_size = rds_buf * RDS_BLOCK_SIZE;
- radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+ radio->buffer = devm_kzalloc(&pdev->dev, radio->buf_size, GFP_KERNEL);
if (!radio->buffer) {
pr_err("Cannot allocate memory for RDS buffer.\n");
r = -ENOMEM;
- goto err_kmalloc;
+ goto pdata_err;
}
radio->core = *core;
@@ -2043,7 +2040,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
if (r) {
dev_err(radio->dev, WL1273_FM_DRIVER_NAME
": Cannot get platform data\n");
- goto err_resources;
+ goto pdata_err;
}
dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq);
@@ -2061,13 +2058,13 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ"
" not configured");
r = -EINVAL;
- goto err_resources;
+ goto pdata_err;
}
init_completion(&radio->busy);
init_waitqueue_head(&radio->read_queue);
- radio->write_buf = kmalloc(256, GFP_KERNEL);
+ radio->write_buf = devm_kzalloc(&pdev->dev, 256, GFP_KERNEL);
if (!radio->write_buf) {
r = -ENOMEM;
goto write_buf_err;
@@ -2080,7 +2077,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
r = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
if (r) {
dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
- goto device_register_err;
+ goto write_buf_err;
}
/* V4L2 configuration */
@@ -2135,16 +2132,10 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
handler_init_err:
v4l2_ctrl_handler_free(&radio->ctrl_handler);
v4l2_device_unregister(&radio->v4l2dev);
-device_register_err:
- kfree(radio->write_buf);
write_buf_err:
free_irq(radio->core->client->irq, radio);
err_request_irq:
radio->core->pdata->free_resources();
-err_resources:
- kfree(radio->buffer);
-err_kmalloc:
- kfree(radio);
pdata_err:
return r;
}
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 49a11ec1f449..db2248ee9498 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -56,23 +56,29 @@ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
return -EIO;
}
- /* Turn on RDS mode , if it is disabled */
+ if (mutex_lock_interruptible(&fmdev->mutex))
+ return -ERESTARTSYS;
+
+ /* Turn on RDS mode if it is disabled */
ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
if (ret < 0) {
fmerr("Unable to read current rds mode\n");
- return ret;
+ goto read_unlock;
}
if (rds_mode == FM_RDS_DISABLE) {
ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
if (ret < 0) {
fmerr("Failed to enable rds mode\n");
- return ret;
+ goto read_unlock;
}
}
/* Copy RDS data from internal buffer to user buffer */
- return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+ ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+read_unlock:
+ mutex_unlock(&fmdev->mutex);
+ return ret;
}
/* Write TX RDS data */
@@ -91,8 +97,11 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
return -EFAULT;
fmdev = video_drvdata(file);
+ if (mutex_lock_interruptible(&fmdev->mutex))
+ return -ERESTARTSYS;
fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
fm_tx_set_af(fmdev, rds.af_freq);
+ mutex_unlock(&fmdev->mutex);
return sizeof(rds);
}
@@ -103,7 +112,9 @@ static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
struct fmdev *fmdev;
fmdev = video_drvdata(file);
+ mutex_lock(&fmdev->mutex);
ret = fmc_is_rds_data_available(fmdev, file, pts);
+ mutex_unlock(&fmdev->mutex);
if (ret < 0)
return POLLIN | POLLRDNORM;
@@ -127,10 +138,12 @@ static int fm_v4l2_fops_open(struct file *file)
fmdev = video_drvdata(file);
+ if (mutex_lock_interruptible(&fmdev->mutex))
+ return -ERESTARTSYS;
ret = fmc_prepare(fmdev);
if (ret < 0) {
fmerr("Unable to prepare FM CORE\n");
- return ret;
+ goto open_unlock;
}
fmdbg("Load FM RX firmware..\n");
@@ -138,10 +151,12 @@ static int fm_v4l2_fops_open(struct file *file)
ret = fmc_set_mode(fmdev, FM_MODE_RX);
if (ret < 0) {
fmerr("Unable to load FM RX firmware\n");
- return ret;
+ goto open_unlock;
}
radio_disconnected = 1;
+open_unlock:
+ mutex_unlock(&fmdev->mutex);
return ret;
}
@@ -156,19 +171,22 @@ static int fm_v4l2_fops_release(struct file *file)
return 0;
}
+ mutex_lock(&fmdev->mutex);
ret = fmc_set_mode(fmdev, FM_MODE_OFF);
if (ret < 0) {
fmerr("Unable to turn off the chip\n");
- return ret;
+ goto release_unlock;
}
ret = fmc_release(fmdev);
if (ret < 0) {
fmerr("FM CORE release failed\n");
- return ret;
+ goto release_unlock;
}
radio_disconnected = 0;
+release_unlock:
+ mutex_unlock(&fmdev->mutex);
return ret;
}
@@ -520,10 +538,6 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
video_set_drvdata(gradio_dev, fmdev);
gradio_dev->lock = &fmdev->mutex;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &gradio_dev->flags);
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8be57634ba60..02ce43c79148 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -265,12 +265,39 @@ config IR_IGUANA
depends on RC_CORE
select USB
---help---
- Say Y here if you want to use the IgaunaWorks USB IR Transceiver.
- Both infrared receive and send are supported.
+ Say Y here if you want to use the IguanaWorks USB IR Transceiver.
+ Both infrared receive and send are supported. If you want to
+ change the ID or the pin config, use the user space driver from
+ IguanaWorks.
+
+ Only firmware 0x0205 and later is supported.
To compile this driver as a module, choose M here: the module will
be called iguanair.
+config IR_TTUSBIR
+ tristate "TechnoTrend USB IR Receiver"
+ depends on RC_CORE
+ select USB
+ select NEW_LEDS
+ select LEDS_CLASS
+ ---help---
+ Say Y here if you want to use the TechnoTrend USB IR Receiver. The
+ driver can control the led.
+
+ To compile this driver as a module, choose M here: the module will
+ be called ttusbir.
+
+config IR_RX51
+ tristate "Nokia N900 IR transmitter diode"
+ depends on MACH_NOKIA_RX51 && OMAP_DM_TIMER
+ ---help---
+ Say Y or M here if you want to enable support for the IR
+ transmitter diode built in the Nokia N900 (RX51) device.
+
+ The driver uses omap DM timers for gereating the carrier
+ wave and pulses.
+
config RC_LOOPBACK
tristate "Remote Control Loopback Driver"
depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f871d1986c21..56bacf07b361 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -23,8 +23,10 @@ obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
+obj-$(CONFIG_IR_RX51) += ir-rx51.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
obj-$(CONFIG_IR_IGUANA) += iguanair.o
+obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 8fa72e2dacb1..08aede5ffaeb 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -331,13 +331,9 @@ static void ati_remote_dump(struct device *dev, unsigned char *data,
if (data[0] != (unsigned char)0xff && data[0] != 0x00)
dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
} else if (len == 4)
- dev_warn(dev, "Weird key %02x %02x %02x %02x\n",
- data[0], data[1], data[2], data[3]);
+ dev_warn(dev, "Weird key %*ph\n", 4, data);
else
- dev_warn(dev,
- "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n",
- len, data[0], data[1], data[2], data[3], data[4],
- data[5]);
+ dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data);
}
/*
@@ -519,8 +515,7 @@ static void ati_remote_input_report(struct urb *urb)
if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) {
dbginfo(&ati_remote->interface->dev,
- "wrong checksum in input: %02x %02x %02x %02x\n",
- data[0], data[1], data[2], data[3]);
+ "wrong checksum in input: %*ph\n", 4, data);
return;
}
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index ab30c64f8124..52fd7696b1ba 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -295,6 +295,7 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
{
DEFINE_IR_RAW_EVENT(rawir);
u8 sample;
+ bool event = false;
int i;
for (i = 0; i < fintek->pkts; i++) {
@@ -332,7 +333,9 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
fit_dbg("Storing %s with duration %d",
rawir.pulse ? "pulse" : "space",
rawir.duration);
- ir_raw_event_store_with_filter(fintek->rdev, &rawir);
+ if (ir_raw_event_store_with_filter(fintek->rdev,
+ &rawir))
+ event = true;
break;
}
@@ -342,8 +345,10 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
fintek->pkts = 0;
- fit_dbg("Calling ir_raw_event_handle");
- ir_raw_event_handle(fintek->rdev);
+ if (event) {
+ fit_dbg("Calling ir_raw_event_handle");
+ ir_raw_event_handle(fintek->rdev);
+ }
}
/* copy data from hardware rx register into driver buffer */
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 5e2eaf8ba73e..66ba23738601 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -35,9 +35,9 @@ struct iguanair {
struct device *dev;
struct usb_device *udev;
- int pipe_in, pipe_out;
+ int pipe_out;
+ uint16_t version;
uint8_t bufsize;
- uint8_t version[2];
struct mutex lock;
@@ -75,6 +75,7 @@ struct iguanair {
#define MAX_PACKET_SIZE 8u
#define TIMEOUT 1000
+#define RX_RESOLUTION 21333
struct packet {
uint16_t start;
@@ -82,11 +83,6 @@ struct packet {
uint8_t cmd;
};
-struct response_packet {
- struct packet header;
- uint8_t data[4];
-};
-
struct send_packet {
struct packet header;
uint8_t length;
@@ -100,6 +96,25 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
{
if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
switch (ir->buf_in[3]) {
+ case CMD_GET_VERSION:
+ if (len == 6) {
+ ir->version = (ir->buf_in[5] << 8) |
+ ir->buf_in[4];
+ complete(&ir->completion);
+ }
+ break;
+ case CMD_GET_BUFSIZE:
+ if (len >= 5) {
+ ir->bufsize = ir->buf_in[4];
+ complete(&ir->completion);
+ }
+ break;
+ case CMD_GET_FEATURES:
+ if (len > 5) {
+ ir->cycle_overhead = ir->buf_in[5];
+ complete(&ir->completion);
+ }
+ break;
case CMD_TX_OVERFLOW:
ir->tx_overflow = true;
case CMD_RECEIVER_OFF:
@@ -109,6 +124,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
break;
case CMD_RX_OVERFLOW:
dev_warn(ir->dev, "receive overflow\n");
+ ir_raw_event_reset(ir->rc);
break;
default:
dev_warn(ir->dev, "control code %02x received\n",
@@ -118,6 +134,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
} else if (len >= 7) {
DEFINE_IR_RAW_EVENT(rawir);
unsigned i;
+ bool event = false;
init_ir_raw_event(&rawir);
@@ -128,19 +145,22 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
} else {
rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
- 21330;
+ RX_RESOLUTION;
}
- ir_raw_event_store_with_filter(ir->rc, &rawir);
+ if (ir_raw_event_store_with_filter(ir->rc, &rawir))
+ event = true;
}
- ir_raw_event_handle(ir->rc);
+ if (event)
+ ir_raw_event_handle(ir->rc);
}
}
static void iguanair_rx(struct urb *urb)
{
struct iguanair *ir;
+ int rc;
if (!urb)
return;
@@ -166,34 +186,27 @@ static void iguanair_rx(struct urb *urb)
break;
}
- usb_submit_urb(urb, GFP_ATOMIC);
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc && rc != -ENODEV)
+ dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
}
-static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
- struct response_packet *response, unsigned *res_len)
+static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
{
- unsigned offset, len;
int rc, transferred;
- for (offset = 0; offset < size; offset += MAX_PACKET_SIZE) {
- len = min(size - offset, MAX_PACKET_SIZE);
+ INIT_COMPLETION(ir->completion);
- if (ir->tx_overflow)
- return -EOVERFLOW;
+ rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size,
+ &transferred, TIMEOUT);
+ if (rc)
+ return rc;
- rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data + offset,
- len, &transferred, TIMEOUT);
- if (rc)
- return rc;
+ if (transferred != size)
+ return -EIO;
- if (transferred != len)
- return -EIO;
- }
-
- if (response) {
- rc = usb_interrupt_msg(ir->udev, ir->pipe_in, response,
- sizeof(*response), res_len, TIMEOUT);
- }
+ if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
+ return -ETIMEDOUT;
return rc;
}
@@ -201,66 +214,43 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
static int iguanair_get_features(struct iguanair *ir)
{
struct packet packet;
- struct response_packet response;
- int rc, len;
+ int rc;
packet.start = 0;
packet.direction = DIR_OUT;
packet.cmd = CMD_GET_VERSION;
- rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+ rc = iguanair_send(ir, &packet, sizeof(packet));
if (rc) {
dev_info(ir->dev, "failed to get version\n");
goto out;
}
- if (len != 6) {
- dev_info(ir->dev, "failed to get version\n");
- rc = -EIO;
+ if (ir->version < 0x205) {
+ dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version);
+ rc = -ENODEV;
goto out;
}
- ir->version[0] = response.data[0];
- ir->version[1] = response.data[1];
ir->bufsize = 150;
ir->cycle_overhead = 65;
packet.cmd = CMD_GET_BUFSIZE;
- rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+ rc = iguanair_send(ir, &packet, sizeof(packet));
if (rc) {
dev_info(ir->dev, "failed to get buffer size\n");
goto out;
}
- if (len != 5) {
- dev_info(ir->dev, "failed to get buffer size\n");
- rc = -EIO;
- goto out;
- }
-
- ir->bufsize = response.data[0];
-
- if (ir->version[0] == 0 || ir->version[1] == 0)
- goto out;
-
packet.cmd = CMD_GET_FEATURES;
- rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
+ rc = iguanair_send(ir, &packet, sizeof(packet));
if (rc) {
dev_info(ir->dev, "failed to get features\n");
goto out;
}
- if (len < 5) {
- dev_info(ir->dev, "failed to get features\n");
- rc = -EIO;
- goto out;
- }
-
- if (len > 5 && ir->version[0] >= 4)
- ir->cycle_overhead = response.data[1];
-
out:
return rc;
}
@@ -269,17 +259,11 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
{
struct packet packet = { 0, DIR_OUT, enable ?
CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
- int rc;
- INIT_COMPLETION(ir->completion);
+ if (enable)
+ ir_raw_event_reset(ir->rc);
- rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL);
- if (rc)
- return rc;
-
- wait_for_completion_timeout(&ir->completion, TIMEOUT);
-
- return 0;
+ return iguanair_send(ir, &packet, sizeof(packet));
}
/*
@@ -351,7 +335,7 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
{
struct iguanair *ir = dev->priv;
uint8_t space, *payload;
- unsigned i, size, rc;
+ unsigned i, size, rc, bytes;
struct send_packet *packet;
mutex_lock(&ir->lock);
@@ -359,17 +343,22 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* convert from us to carrier periods */
for (i = size = 0; i < count; i++) {
txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
- size += (txbuf[i] + 126) / 127;
+ bytes = (txbuf[i] + 126) / 127;
+ if (size + bytes > ir->bufsize) {
+ count = i;
+ break;
+ }
+ size += bytes;
}
- packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
- if (!packet) {
- rc = -ENOMEM;
+ if (count == 0) {
+ rc = -EINVAL;
goto out;
}
- if (size > ir->bufsize) {
- rc = -E2BIG;
+ packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
+ if (!packet) {
+ rc = -ENOMEM;
goto out;
}
@@ -400,34 +389,28 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
rc = iguanair_receiver(ir, false);
if (rc) {
dev_warn(ir->dev, "disable receiver before transmit failed\n");
- goto out;
+ goto out_kfree;
}
}
ir->tx_overflow = false;
- INIT_COMPLETION(ir->completion);
+ rc = iguanair_send(ir, packet, size + 8);
- rc = iguanair_send(ir, packet, size + 8, NULL, NULL);
-
- if (rc == 0) {
- wait_for_completion_timeout(&ir->completion, TIMEOUT);
- if (ir->tx_overflow)
- rc = -EOVERFLOW;
- }
-
- ir->tx_overflow = false;
+ if (rc == 0 && ir->tx_overflow)
+ rc = -EOVERFLOW;
if (ir->receiver_on) {
if (iguanair_receiver(ir, true))
dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
}
+out_kfree:
+ kfree(packet);
out:
mutex_unlock(&ir->lock);
- kfree(packet);
- return rc;
+ return rc ? rc : count;
}
static int iguanair_open(struct rc_dev *rdev)
@@ -437,8 +420,6 @@ static int iguanair_open(struct rc_dev *rdev)
mutex_lock(&ir->lock);
- usb_submit_urb(ir->urb_in, GFP_KERNEL);
-
BUG_ON(ir->receiver_on);
rc = iguanair_receiver(ir, true);
@@ -459,11 +440,9 @@ static void iguanair_close(struct rc_dev *rdev)
rc = iguanair_receiver(ir, false);
ir->receiver_on = false;
- if (rc)
+ if (rc && rc != -ENODEV)
dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
- usb_kill_urb(ir->urb_in);
-
mutex_unlock(&ir->lock);
}
@@ -473,22 +452,22 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
struct usb_device *udev = interface_to_usbdev(intf);
struct iguanair *ir;
struct rc_dev *rc;
- int ret;
+ int ret, pipein;
struct usb_host_interface *idesc;
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
rc = rc_allocate_device();
if (!ir || !rc) {
- ret = ENOMEM;
+ ret = -ENOMEM;
goto out;
}
- ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_ATOMIC,
+ ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL,
&ir->dma_in);
ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
if (!ir->buf_in || !ir->urb_in) {
- ret = ENOMEM;
+ ret = -ENOMEM;
goto out;
}
@@ -502,28 +481,29 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
ir->rc = rc;
ir->dev = &intf->dev;
ir->udev = udev;
- ir->pipe_in = usb_rcvintpipe(udev,
- idesc->endpoint[0].desc.bEndpointAddress);
ir->pipe_out = usb_sndintpipe(udev,
idesc->endpoint[1].desc.bEndpointAddress);
mutex_init(&ir->lock);
init_completion(&ir->completion);
- ret = iguanair_get_features(ir);
+ pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
+ usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE,
+ iguanair_rx, ir, 1);
+ ir->urb_in->transfer_dma = ir->dma_in;
+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ ret = usb_submit_urb(ir->urb_in, GFP_KERNEL);
if (ret) {
- dev_warn(&intf->dev, "failed to get device features");
+ dev_warn(&intf->dev, "failed to submit urb: %d\n", ret);
goto out;
}
- usb_fill_int_urb(ir->urb_in, ir->udev, ir->pipe_in, ir->buf_in,
- MAX_PACKET_SIZE, iguanair_rx, ir,
- idesc->endpoint[0].desc.bInterval);
- ir->urb_in->transfer_dma = ir->dma_in;
- ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ ret = iguanair_get_features(ir);
+ if (ret)
+ goto out2;
snprintf(ir->name, sizeof(ir->name),
- "IguanaWorks USB IR Transceiver version %d.%d",
- ir->version[0], ir->version[1]);
+ "IguanaWorks USB IR Transceiver version 0x%04x", ir->version);
usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
@@ -540,21 +520,23 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
rc->s_tx_carrier = iguanair_set_tx_carrier;
rc->tx_ir = iguanair_tx;
rc->driver_name = DRIVER_NAME;
- rc->map_name = RC_MAP_EMPTY;
+ rc->map_name = RC_MAP_RC6_MCE;
+ rc->timeout = MS_TO_NS(100);
+ rc->rx_resolution = RX_RESOLUTION;
iguanair_set_tx_carrier(rc, 38000);
ret = rc_register_device(rc);
if (ret < 0) {
dev_err(&intf->dev, "failed to register rc device %d", ret);
- goto out;
+ goto out2;
}
usb_set_intfdata(intf, ir);
- dev_info(&intf->dev, "Registered %s", ir->name);
-
return 0;
+out2:
+ usb_kill_urb(ir->urb_in);
out:
if (ir) {
usb_free_urb(ir->urb_in);
@@ -570,12 +552,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf)
{
struct iguanair *ir = usb_get_intfdata(intf);
+ rc_unregister_device(ir->rc);
usb_set_intfdata(intf, NULL);
-
usb_kill_urb(ir->urb_in);
usb_free_urb(ir->urb_in);
usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in);
- rc_unregister_device(ir->rc);
kfree(ir);
}
@@ -592,6 +573,8 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
dev_warn(ir->dev, "failed to disable receiver for suspend\n");
}
+ usb_kill_urb(ir->urb_in);
+
mutex_unlock(&ir->lock);
return rc;
@@ -604,6 +587,10 @@ static int iguanair_resume(struct usb_interface *intf)
mutex_lock(&ir->lock);
+ rc = usb_submit_urb(ir->urb_in, GFP_KERNEL);
+ if (rc)
+ dev_warn(&intf->dev, "failed to submit urb: %d\n", rc);
+
if (ir->receiver_on) {
rc = iguanair_receiver(ir, true);
if (rc)
@@ -627,7 +614,8 @@ static struct usb_driver iguanair_driver = {
.suspend = iguanair_suspend,
.resume = iguanair_resume,
.reset_resume = iguanair_resume,
- .id_table = iguanair_table
+ .id_table = iguanair_table,
+ .soft_unbind = 1 /* we want to disable receiver on unbind */
};
module_usb_driver(iguanair_driver);
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 5faba2a2fdd3..6ad4a0770613 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -105,8 +105,14 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
struct lirc_codec *lirc;
struct rc_dev *dev;
unsigned int *txbuf; /* buffer with values to transmit */
- ssize_t ret = 0;
+ ssize_t ret = -EINVAL;
size_t count;
+ ktime_t start;
+ s64 towait;
+ unsigned int duration = 0; /* signal duration in us */
+ int i;
+
+ start = ktime_get();
lirc = lirc_get_pdata(file);
if (!lirc)
@@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
goto out;
}
- if (dev->tx_ir)
- ret = dev->tx_ir(dev, txbuf, count);
+ if (!dev->tx_ir) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ ret = dev->tx_ir(dev, txbuf, (u32)n);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < ret; i++)
+ duration += txbuf[i];
- if (ret > 0)
- ret *= sizeof(unsigned);
+ ret *= sizeof(unsigned int);
+
+ /*
+ * The lircd gap calculation expects the write function to
+ * wait for the actual IR signal to be transmitted before
+ * returning.
+ */
+ towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
+ if (towait > 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(towait));
+ }
out:
kfree(txbuf);
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 3c9431a9f62d..2ca509e6e16b 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -70,7 +70,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!ev.pulse)
break;
- if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
+ if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
data->is_nec_x = false;
data->necx_repeat = false;
} else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
@@ -86,7 +86,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (ev.pulse)
break;
- if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
+ if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {
data->state = STATE_BIT_PULSE;
return 0;
} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index a82025121345..97dc8d13b06b 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -157,7 +157,9 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
* This routine (which may be called from an interrupt context) works
* in similar manner to ir_raw_event_store_edge.
* This routine is intended for devices with limited internal buffer
- * It automerges samples of same type, and handles timeouts
+ * It automerges samples of same type, and handles timeouts. Returns non-zero
+ * if the event was added, and zero if the event was ignored due to idle
+ * processing.
*/
int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
{
@@ -184,7 +186,7 @@ int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
dev->raw->this_ev.duration >= dev->timeout)
ir_raw_event_set_idle(dev, true);
- return 0;
+ return 1;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
new file mode 100644
index 000000000000..9487dd33a89a
--- /dev/null
+++ b/drivers/media/rc/ir-rx51.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Based on lirc_serial.c
+ *
+ * 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
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include <plat/dmtimer.h>
+#include <plat/clock.h>
+#include <plat/omap-pm.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/ir-rx51.h>
+
+#define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE | \
+ LIRC_CAN_SET_SEND_CARRIER | \
+ LIRC_CAN_SEND_PULSE)
+
+#define DRIVER_NAME "lirc_rx51"
+
+#define WBUF_LEN 256
+
+#define TIMER_MAX_VALUE 0xffffffff
+
+struct lirc_rx51 {
+ struct omap_dm_timer *pwm_timer;
+ struct omap_dm_timer *pulse_timer;
+ struct device *dev;
+ struct lirc_rx51_platform_data *pdata;
+ wait_queue_head_t wqueue;
+
+ unsigned long fclk_khz;
+ unsigned int freq; /* carrier frequency */
+ unsigned int duty_cycle; /* carrier duty cycle */
+ unsigned int irq_num;
+ unsigned int match;
+ int wbuf[WBUF_LEN];
+ int wbuf_index;
+ unsigned long device_is_open;
+ unsigned int pwm_timer_num;
+};
+
+static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
+{
+ omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+}
+
+static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
+{
+ omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
+ OMAP_TIMER_TRIGGER_NONE);
+}
+
+static int init_timing_params(struct lirc_rx51 *lirc_rx51)
+{
+ u32 load, match;
+
+ load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq);
+ match = -(lirc_rx51->duty_cycle * -load / 100);
+ omap_dm_timer_set_load(lirc_rx51->pwm_timer, 1, load);
+ omap_dm_timer_set_match(lirc_rx51->pwm_timer, 1, match);
+ omap_dm_timer_write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2);
+ omap_dm_timer_start(lirc_rx51->pwm_timer);
+ omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+ omap_dm_timer_start(lirc_rx51->pulse_timer);
+
+ lirc_rx51->match = 0;
+
+ return 0;
+}
+
+#define tics_after(a, b) ((long)(b) - (long)(a) < 0)
+
+static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec)
+{
+ int counter;
+
+ BUG_ON(usec < 0);
+
+ if (lirc_rx51->match == 0)
+ counter = omap_dm_timer_read_counter(lirc_rx51->pulse_timer);
+ else
+ counter = lirc_rx51->match;
+
+ counter += (u32)(lirc_rx51->fclk_khz * usec / (1000));
+ omap_dm_timer_set_match(lirc_rx51->pulse_timer, 1, counter);
+ omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer,
+ OMAP_TIMER_INT_MATCH);
+ if (tics_after(omap_dm_timer_read_counter(lirc_rx51->pulse_timer),
+ counter)) {
+ return 1;
+ }
+ return 0;
+}
+
+static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
+{
+ unsigned int retval;
+ struct lirc_rx51 *lirc_rx51 = ptr;
+
+ retval = omap_dm_timer_read_status(lirc_rx51->pulse_timer);
+ if (!retval)
+ return IRQ_NONE;
+
+ if ((retval & ~OMAP_TIMER_INT_MATCH))
+ dev_err_ratelimited(lirc_rx51->dev,
+ ": Unexpected interrupt source: %x\n", retval);
+
+ omap_dm_timer_write_status(lirc_rx51->pulse_timer, 7);
+ if (lirc_rx51->wbuf_index < 0) {
+ dev_err_ratelimited(lirc_rx51->dev,
+ ": BUG wbuf_index has value of %i\n",
+ lirc_rx51->wbuf_index);
+ goto end;
+ }
+
+ /*
+ * If we happen to hit an odd latency spike, loop through the
+ * pulses until we catch up.
+ */
+ do {
+ if (lirc_rx51->wbuf_index >= WBUF_LEN)
+ goto end;
+ if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
+ goto end;
+
+ if (lirc_rx51->wbuf_index % 2)
+ lirc_rx51_off(lirc_rx51);
+ else
+ lirc_rx51_on(lirc_rx51);
+
+ retval = pulse_timer_set_timeout(lirc_rx51,
+ lirc_rx51->wbuf[lirc_rx51->wbuf_index]);
+ lirc_rx51->wbuf_index++;
+
+ } while (retval);
+
+ return IRQ_HANDLED;
+end:
+ /* Stop TX here */
+ lirc_rx51_off(lirc_rx51);
+ lirc_rx51->wbuf_index = -1;
+ omap_dm_timer_stop(lirc_rx51->pwm_timer);
+ omap_dm_timer_stop(lirc_rx51->pulse_timer);
+ omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+ wake_up_interruptible(&lirc_rx51->wqueue);
+
+ return IRQ_HANDLED;
+}
+
+static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
+{
+ struct clk *clk_fclk;
+ int retval, pwm_timer = lirc_rx51->pwm_timer_num;
+
+ lirc_rx51->pwm_timer = omap_dm_timer_request_specific(pwm_timer);
+ if (lirc_rx51->pwm_timer == NULL) {
+ dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n",
+ pwm_timer);
+ return -EBUSY;
+ }
+
+ lirc_rx51->pulse_timer = omap_dm_timer_request();
+ if (lirc_rx51->pulse_timer == NULL) {
+ dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ omap_dm_timer_set_source(lirc_rx51->pwm_timer, OMAP_TIMER_SRC_SYS_CLK);
+ omap_dm_timer_set_source(lirc_rx51->pulse_timer,
+ OMAP_TIMER_SRC_SYS_CLK);
+
+ omap_dm_timer_enable(lirc_rx51->pwm_timer);
+ omap_dm_timer_enable(lirc_rx51->pulse_timer);
+
+ lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
+ retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
+ IRQF_DISABLED | IRQF_SHARED,
+ "lirc_pulse_timer", lirc_rx51);
+ if (retval) {
+ dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
+ goto err2;
+ }
+
+ clk_fclk = omap_dm_timer_get_fclk(lirc_rx51->pwm_timer);
+ lirc_rx51->fclk_khz = clk_fclk->rate / 1000;
+
+ return 0;
+
+err2:
+ omap_dm_timer_free(lirc_rx51->pulse_timer);
+err1:
+ omap_dm_timer_free(lirc_rx51->pwm_timer);
+
+ return retval;
+}
+
+static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51)
+{
+ omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
+ free_irq(lirc_rx51->irq_num, lirc_rx51);
+ lirc_rx51_off(lirc_rx51);
+ omap_dm_timer_disable(lirc_rx51->pwm_timer);
+ omap_dm_timer_disable(lirc_rx51->pulse_timer);
+ omap_dm_timer_free(lirc_rx51->pwm_timer);
+ omap_dm_timer_free(lirc_rx51->pulse_timer);
+ lirc_rx51->wbuf_index = -1;
+
+ return 0;
+}
+
+static ssize_t lirc_rx51_write(struct file *file, const char *buf,
+ size_t n, loff_t *ppos)
+{
+ int count, i;
+ struct lirc_rx51 *lirc_rx51 = file->private_data;
+
+ if (n % sizeof(int))
+ return -EINVAL;
+
+ count = n / sizeof(int);
+ if ((count > WBUF_LEN) || (count % 2 == 0))
+ return -EINVAL;
+
+ /* Wait any pending transfers to finish */
+ wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
+
+ if (copy_from_user(lirc_rx51->wbuf, buf, n))
+ return -EFAULT;
+
+ /* Sanity check the input pulses */
+ for (i = 0; i < count; i++)
+ if (lirc_rx51->wbuf[i] < 0)
+ return -EINVAL;
+
+ init_timing_params(lirc_rx51);
+ if (count < WBUF_LEN)
+ lirc_rx51->wbuf[count] = -1; /* Insert termination mark */
+
+ /*
+ * Adjust latency requirements so the device doesn't go in too
+ * deep sleep states
+ */
+ lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, 50);
+
+ lirc_rx51_on(lirc_rx51);
+ lirc_rx51->wbuf_index = 1;
+ pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]);
+
+ /*
+ * Don't return back to the userspace until the transfer has
+ * finished
+ */
+ wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
+
+ /* We can sleep again */
+ lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, -1);
+
+ return n;
+}
+
+static long lirc_rx51_ioctl(struct file *filep,
+ unsigned int cmd, unsigned long arg)
+{
+ int result;
+ unsigned long value;
+ unsigned int ivalue;
+ struct lirc_rx51 *lirc_rx51 = filep->private_data;
+
+ switch (cmd) {
+ case LIRC_GET_SEND_MODE:
+ result = put_user(LIRC_MODE_PULSE, (unsigned long *)arg);
+ if (result)
+ return result;
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ result = get_user(value, (unsigned long *)arg);
+ if (result)
+ return result;
+
+ /* only LIRC_MODE_PULSE supported */
+ if (value != LIRC_MODE_PULSE)
+ return -ENOSYS;
+ break;
+
+ case LIRC_GET_REC_MODE:
+ result = put_user(0, (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+
+ case LIRC_GET_LENGTH:
+ return -ENOSYS;
+ break;
+
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ result = get_user(ivalue, (unsigned int *) arg);
+ if (result)
+ return result;
+
+ if (ivalue <= 0 || ivalue > 100) {
+ dev_err(lirc_rx51->dev, ": invalid duty cycle %d\n",
+ ivalue);
+ return -EINVAL;
+ }
+
+ lirc_rx51->duty_cycle = ivalue;
+ break;
+
+ case LIRC_SET_SEND_CARRIER:
+ result = get_user(ivalue, (unsigned int *) arg);
+ if (result)
+ return result;
+
+ if (ivalue > 500000 || ivalue < 20000) {
+ dev_err(lirc_rx51->dev, ": invalid carrier freq %d\n",
+ ivalue);
+ return -EINVAL;
+ }
+
+ lirc_rx51->freq = ivalue;
+ break;
+
+ case LIRC_GET_FEATURES:
+ result = put_user(LIRC_RX51_DRIVER_FEATURES,
+ (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int lirc_rx51_open(struct inode *inode, struct file *file)
+{
+ struct lirc_rx51 *lirc_rx51 = lirc_get_pdata(file);
+ BUG_ON(!lirc_rx51);
+
+ file->private_data = lirc_rx51;
+
+ if (test_and_set_bit(1, &lirc_rx51->device_is_open))
+ return -EBUSY;
+
+ return lirc_rx51_init_port(lirc_rx51);
+}
+
+static int lirc_rx51_release(struct inode *inode, struct file *file)
+{
+ struct lirc_rx51 *lirc_rx51 = file->private_data;
+
+ lirc_rx51_free_port(lirc_rx51);
+
+ clear_bit(1, &lirc_rx51->device_is_open);
+
+ return 0;
+}
+
+static struct lirc_rx51 lirc_rx51 = {
+ .freq = 38000,
+ .duty_cycle = 50,
+ .wbuf_index = -1,
+};
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .write = lirc_rx51_write,
+ .unlocked_ioctl = lirc_rx51_ioctl,
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_rx51_open,
+ .release = lirc_rx51_release,
+};
+
+static struct lirc_driver lirc_rx51_driver = {
+ .name = DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .data = &lirc_rx51,
+ .fops = &lirc_fops,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_PM
+
+static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /*
+ * In case the device is still open, do not suspend. Normally
+ * this should not be a problem as lircd only keeps the device
+ * open only for short periods of time. We also don't want to
+ * get involved with race conditions that might happen if we
+ * were in a middle of a transmit. Thus, we defer any suspend
+ * actions until transmit has completed.
+ */
+ if (test_and_set_bit(1, &lirc_rx51.device_is_open))
+ return -EAGAIN;
+
+ clear_bit(1, &lirc_rx51.device_is_open);
+
+ return 0;
+}
+
+static int lirc_rx51_resume(struct platform_device *dev)
+{
+ return 0;
+}
+
+#else
+
+#define lirc_rx51_suspend NULL
+#define lirc_rx51_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int __devinit lirc_rx51_probe(struct platform_device *dev)
+{
+ lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
+ lirc_rx51.pdata = dev->dev.platform_data;
+ lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer;
+ lirc_rx51.dev = &dev->dev;
+ lirc_rx51_driver.dev = &dev->dev;
+ lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
+ init_waitqueue_head(&lirc_rx51.wqueue);
+
+ if (lirc_rx51_driver.minor < 0) {
+ dev_err(lirc_rx51.dev, ": lirc_register_driver failed: %d\n",
+ lirc_rx51_driver.minor);
+ return lirc_rx51_driver.minor;
+ }
+ dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n",
+ lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num);
+
+ return 0;
+}
+
+static int __exit lirc_rx51_remove(struct platform_device *dev)
+{
+ return lirc_unregister_driver(lirc_rx51_driver.minor);
+}
+
+struct platform_driver lirc_rx51_platform_driver = {
+ .probe = lirc_rx51_probe,
+ .remove = __exit_p(lirc_rx51_remove),
+ .suspend = lirc_rx51_suspend,
+ .resume = lirc_rx51_resume,
+ .remove = __exit_p(lirc_rx51_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lirc_rx51_init(void)
+{
+ return platform_driver_register(&lirc_rx51_platform_driver);
+}
+module_init(lirc_rx51_init);
+
+static void __exit lirc_rx51_exit(void)
+{
+ platform_driver_unregister(&lirc_rx51_platform_driver);
+}
+module_exit(lirc_rx51_exit);
+
+MODULE_DESCRIPTION("LIRC TX driver for Nokia RX51");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
index caeff85603e3..80217ffc91db 100644
--- a/drivers/media/rc/keymaps/rc-tt-1500.c
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -61,7 +61,7 @@ static struct rc_map_list tt_1500_map = {
.map = {
.scan = tt_1500,
.size = ARRAY_SIZE(tt_1500),
- .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_TT_1500,
}
};
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index f38d9a8c6880..a5c6c1c2af82 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -791,10 +791,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
int i, ret = 0;
int cmdcount = 0;
unsigned char *cmdbuf; /* MCE command buffer */
- long signal_duration = 0; /* Singnal length in us */
- struct timeval start_time, end_time;
-
- do_gettimeofday(&start_time);
cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
if (!cmdbuf)
@@ -807,7 +803,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* Generate mce packet data */
for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
- signal_duration += txbuf[i];
txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
@@ -850,19 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* Transmit the command to the mce device */
mce_async_out(ir, cmdbuf, cmdcount);
- /*
- * The lircd gap calculation expects the write function to
- * wait the time it takes for the ircommand to be sent before
- * it returns.
- */
- do_gettimeofday(&end_time);
- signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
- (end_time.tv_sec - start_time.tv_sec) * 1000000;
-
- /* delay with the closest number of ticks */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(signal_duration));
-
out:
kfree(cmdbuf);
return ret ? ret : count;
@@ -974,6 +956,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
DEFINE_IR_RAW_EVENT(rawir);
+ bool event = false;
int i = 0;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
@@ -1004,7 +987,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.pulse ? "pulse" : "space",
rawir.duration);
- ir_raw_event_store_with_filter(ir->rc, &rawir);
+ if (ir_raw_event_store_with_filter(ir->rc, &rawir))
+ event = true;
break;
case CMD_DATA:
ir->rem--;
@@ -1032,8 +1016,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
if (ir->parser_state != CMD_HEADER && !ir->rem)
ir->parser_state = CMD_HEADER;
}
- mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
- ir_raw_event_handle(ir->rc);
+ if (event) {
+ mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+ ir_raw_event_handle(ir->rc);
+ }
}
static void mceusb_dev_recv(struct urb *urb)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index fae1615e0ff2..f9be68132c67 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -105,18 +105,9 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
{
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
- unsigned total_duration = 0;
unsigned i;
DEFINE_IR_RAW_EVENT(rawir);
- for (i = 0; i < count; i++)
- total_duration += abs(txbuf[i]);
-
- if (total_duration == 0) {
- dprintk("invalid tx data, total duration zero\n");
- return -EINVAL;
- }
-
if (lodev->txcarrier < lodev->rxcarriermin ||
lodev->txcarrier > lodev->rxcarriermax) {
dprintk("ignoring tx, carrier out of range\n");
@@ -148,9 +139,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
ir_raw_event_handle(dev);
out:
- /* Lirc expects this function to take as long as the total duration */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(total_duration));
return count;
}
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
new file mode 100644
index 000000000000..1aee57fd2f32
--- /dev/null
+++ b/drivers/media/rc/ttusbir.c
@@ -0,0 +1,407 @@
+/*
+ * TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2012 Sean Young <sean@mess.org>
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <media/rc-core.h>
+
+#define DRIVER_NAME "ttusbir"
+#define DRIVER_DESC "TechnoTrend USB IR Receiver"
+/*
+ * The Windows driver uses 8 URBS, the original lirc drivers has a
+ * configurable amount (2 default, 4 max). This device generates about 125
+ * messages per second (!), whether IR is idle or not.
+ */
+#define NUM_URBS 4
+#define NS_PER_BYTE 62500
+#define NS_PER_BIT (NS_PER_BYTE/8)
+
+struct ttusbir {
+ struct rc_dev *rc;
+ struct device *dev;
+ struct usb_device *udev;
+
+ struct urb *urb[NUM_URBS];
+
+ struct led_classdev led;
+ struct urb *bulk_urb;
+ uint8_t bulk_buffer[5];
+ int bulk_out_endp, iso_in_endp;
+ bool led_on, is_led_on;
+ atomic_t led_complete;
+
+ char phys[64];
+};
+
+static enum led_brightness ttusbir_brightness_get(struct led_classdev *led_dev)
+{
+ struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
+
+ return tt->led_on ? LED_FULL : LED_OFF;
+}
+
+static void ttusbir_set_led(struct ttusbir *tt)
+{
+ int ret;
+
+ smp_mb();
+
+ if (tt->led_on != tt->is_led_on &&
+ atomic_add_unless(&tt->led_complete, 1, 1)) {
+ tt->bulk_buffer[4] = tt->is_led_on = tt->led_on;
+ ret = usb_submit_urb(tt->bulk_urb, GFP_ATOMIC);
+ if (ret && ret != -ENODEV) {
+ dev_warn(tt->dev, "failed to submit bulk urb: %d\n",
+ ret);
+ atomic_dec(&tt->led_complete);
+ }
+ }
+}
+
+static void ttusbir_brightness_set(struct led_classdev *led_dev, enum
+ led_brightness brightness)
+{
+ struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
+
+ tt->led_on = brightness != LED_OFF;
+
+ ttusbir_set_led(tt);
+}
+
+/*
+ * The urb cannot be reused until the urb completes
+ */
+static void ttusbir_bulk_complete(struct urb *urb)
+{
+ struct ttusbir *tt = urb->context;
+
+ atomic_dec(&tt->led_complete);
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+ case -EPIPE:
+ default:
+ dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
+ break;
+ }
+
+ ttusbir_set_led(tt);
+}
+
+/*
+ * The data is one bit per sample, a set bit signifying silence and samples
+ * being MSB first. Bit 0 can contain garbage so take it to be whatever
+ * bit 1 is, so we don't have unexpected edges.
+ */
+static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
+{
+ struct ir_raw_event rawir;
+ unsigned i, v, b;
+ bool event = false;
+
+ init_ir_raw_event(&rawir);
+
+ for (i = 0; i < 128; i++) {
+ v = buf[i] & 0xfe;
+ switch (v) {
+ case 0xfe:
+ rawir.pulse = false;
+ rawir.duration = NS_PER_BYTE;
+ if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+ event = true;
+ break;
+ case 0:
+ rawir.pulse = true;
+ rawir.duration = NS_PER_BYTE;
+ if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+ event = true;
+ break;
+ default:
+ /* one edge per byte */
+ if (v & 2) {
+ b = ffz(v | 1);
+ rawir.pulse = true;
+ } else {
+ b = ffs(v) - 1;
+ rawir.pulse = false;
+ }
+
+ rawir.duration = NS_PER_BIT * (8 - b);
+ if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+ event = true;
+
+ rawir.pulse = !rawir.pulse;
+ rawir.duration = NS_PER_BIT * b;
+ if (ir_raw_event_store_with_filter(tt->rc, &rawir))
+ event = true;
+ break;
+ }
+ }
+
+ /* don't wakeup when there's nothing to do */
+ if (event)
+ ir_raw_event_handle(tt->rc);
+}
+
+static void ttusbir_urb_complete(struct urb *urb)
+{
+ struct ttusbir *tt = urb->context;
+ int rc;
+
+ switch (urb->status) {
+ case 0:
+ ttusbir_process_ir_data(tt, urb->transfer_buffer);
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+ case -EPIPE:
+ default:
+ dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
+ break;
+ }
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc && rc != -ENODEV)
+ dev_warn(tt->dev, "failed to resubmit urb: %d\n", rc);
+}
+
+static int __devinit ttusbir_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct ttusbir *tt;
+ struct usb_interface_descriptor *idesc;
+ struct usb_endpoint_descriptor *desc;
+ struct rc_dev *rc;
+ int i, j, ret;
+ int altsetting = -1;
+
+ tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+ rc = rc_allocate_device();
+ if (!tt || !rc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* find the correct alt setting */
+ for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
+ int bulk_out_endp = -1, iso_in_endp = -1;
+
+ idesc = &intf->altsetting[i].desc;
+
+ for (j = 0; j < idesc->bNumEndpoints; j++) {
+ desc = &intf->altsetting[i].endpoint[j].desc;
+ if (usb_endpoint_dir_in(desc) &&
+ usb_endpoint_xfer_isoc(desc) &&
+ desc->wMaxPacketSize == 0x10)
+ iso_in_endp = j;
+ else if (usb_endpoint_dir_out(desc) &&
+ usb_endpoint_xfer_bulk(desc) &&
+ desc->wMaxPacketSize == 0x20)
+ bulk_out_endp = j;
+
+ if (bulk_out_endp != -1 && iso_in_endp != -1) {
+ tt->bulk_out_endp = bulk_out_endp;
+ tt->iso_in_endp = iso_in_endp;
+ altsetting = i;
+ break;
+ }
+ }
+ }
+
+ if (altsetting == -1) {
+ dev_err(&intf->dev, "cannot find expected altsetting\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ tt->dev = &intf->dev;
+ tt->udev = interface_to_usbdev(intf);
+ tt->rc = rc;
+
+ ret = usb_set_interface(tt->udev, 0, altsetting);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < NUM_URBS; i++) {
+ struct urb *urb = usb_alloc_urb(8, GFP_KERNEL);
+ void *buffer;
+
+ if (!urb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ urb->dev = tt->udev;
+ urb->context = tt;
+ urb->pipe = usb_rcvisocpipe(tt->udev, tt->iso_in_endp);
+ urb->interval = 1;
+ buffer = usb_alloc_coherent(tt->udev, 128, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buffer) {
+ usb_free_urb(urb);
+ ret = -ENOMEM;
+ goto out;
+ }
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP | URB_ISO_ASAP;
+ urb->transfer_buffer = buffer;
+ urb->complete = ttusbir_urb_complete;
+ urb->number_of_packets = 8;
+ urb->transfer_buffer_length = 128;
+
+ for (j = 0; j < 8; j++) {
+ urb->iso_frame_desc[j].offset = j * 16;
+ urb->iso_frame_desc[j].length = 16;
+ }
+
+ tt->urb[i] = urb;
+ }
+
+ tt->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!tt->bulk_urb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tt->bulk_buffer[0] = 0xaa;
+ tt->bulk_buffer[1] = 0x01;
+ tt->bulk_buffer[2] = 0x05;
+ tt->bulk_buffer[3] = 0x01;
+
+ usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
+ tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
+ ttusbir_bulk_complete, tt);
+
+ tt->led.name = "ttusbir:yellow:power";
+ tt->led.brightness_set = ttusbir_brightness_set;
+ tt->led.brightness_get = ttusbir_brightness_get;
+ tt->is_led_on = tt->led_on = true;
+ atomic_set(&tt->led_complete, 0);
+ ret = led_classdev_register(&intf->dev, &tt->led);
+ if (ret)
+ goto out;
+
+ usb_make_path(tt->udev, tt->phys, sizeof(tt->phys));
+
+ rc->input_name = DRIVER_DESC;
+ rc->input_phys = tt->phys;
+ usb_to_input_id(tt->udev, &rc->input_id);
+ rc->dev.parent = &intf->dev;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->priv = tt;
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = RC_MAP_TT_1500;
+ rc->timeout = MS_TO_NS(100);
+ /*
+ * The precision is NS_PER_BIT, but since every 8th bit can be
+ * overwritten with garbage the accuracy is at best 2 * NS_PER_BIT.
+ */
+ rc->rx_resolution = NS_PER_BIT;
+
+ ret = rc_register_device(rc);
+ if (ret) {
+ dev_err(&intf->dev, "failed to register rc device %d\n", ret);
+ goto out2;
+ }
+
+ usb_set_intfdata(intf, tt);
+
+ for (i = 0; i < NUM_URBS; i++) {
+ ret = usb_submit_urb(tt->urb[i], GFP_KERNEL);
+ if (ret) {
+ dev_err(tt->dev, "failed to submit urb %d\n", ret);
+ goto out3;
+ }
+ }
+
+ return 0;
+out3:
+ rc_unregister_device(rc);
+out2:
+ led_classdev_unregister(&tt->led);
+out:
+ if (tt) {
+ for (i = 0; i < NUM_URBS && tt->urb[i]; i++) {
+ struct urb *urb = tt->urb[i];
+
+ usb_kill_urb(urb);
+ usb_free_coherent(tt->udev, 128, urb->transfer_buffer,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+ usb_kill_urb(tt->bulk_urb);
+ usb_free_urb(tt->bulk_urb);
+ kfree(tt);
+ }
+ rc_free_device(rc);
+
+ return ret;
+}
+
+static void __devexit ttusbir_disconnect(struct usb_interface *intf)
+{
+ struct ttusbir *tt = usb_get_intfdata(intf);
+ int i;
+
+ rc_unregister_device(tt->rc);
+ led_classdev_unregister(&tt->led);
+ for (i = 0; i < NUM_URBS; i++) {
+ usb_kill_urb(tt->urb[i]);
+ usb_free_coherent(tt->udev, 128, tt->urb[i]->transfer_buffer,
+ tt->urb[i]->transfer_dma);
+ usb_free_urb(tt->urb[i]);
+ }
+ usb_kill_urb(tt->bulk_urb);
+ usb_free_urb(tt->bulk_urb);
+ usb_set_intfdata(intf, NULL);
+ kfree(tt);
+}
+
+static const struct usb_device_id ttusbir_table[] = {
+ { USB_DEVICE(0x0b48, 0x2003) },
+ { }
+};
+
+static struct usb_driver ttusbir_driver = {
+ .name = DRIVER_NAME,
+ .id_table = ttusbir_table,
+ .probe = ttusbir_probe,
+ .disconnect = __devexit_p(ttusbir_disconnect)
+};
+
+module_usb_driver(ttusbir_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, ttusbir_table);
+
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
new file mode 100644
index 000000000000..80238b9063b0
--- /dev/null
+++ b/drivers/media/tuners/Kconfig
@@ -0,0 +1,231 @@
+config MEDIA_ATTACH
+ bool "Load and attach frontend and tuner driver modules as needed"
+ depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+ depends on MODULES
+ default y if !EXPERT
+ help
+ Remove the static dependency of DVB card drivers on all
+ frontend modules for all possible card variants. Instead,
+ allow the card drivers to only load the frontend modules
+ they require.
+
+ Also, tuner module will automatically load a tuner driver
+ when needed, for analog mode.
+
+ This saves several KBytes of memory.
+
+ Note: You will need module-init-tools v3.2 or later for this feature.
+
+ If unsure say Y.
+
+# Analog TV tuners, auto-loaded via tuner.ko
+config MEDIA_TUNER
+ tristate
+ depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
+ default y
+ select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT20XX if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TEA5761 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
+ select MEDIA_TUNER_TEA5767 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA9887 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT
+
+menu "Customize TV tuners"
+ visible if !MEDIA_SUBDRV_AUTOSELECT
+ depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+
+config MEDIA_TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on MEDIA_SUPPORT && I2C
+ select MEDIA_TUNER_TDA9887
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for various simple tuners.
+
+config MEDIA_TUNER_TDA8290
+ tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+ depends on MEDIA_SUPPORT && I2C
+ select MEDIA_TUNER_TDA827X
+ select MEDIA_TUNER_TDA18271
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config MEDIA_TUNER_TDA827X
+ tristate "Philips TDA827X silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA18271
+ tristate "NXP TDA18271 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA9887
+ tristate "TDA 9885/6/7 analog IF demodulator"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for Philips TDA9885/6/7
+ analog IF demodulator.
+
+config MEDIA_TUNER_TEA5761
+ tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on MEDIA_SUPPORT && I2C
+ depends on EXPERIMENTAL
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config MEDIA_TUNER_TEA5767
+ tristate "TEA 5767 radio tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config MEDIA_TUNER_MT20XX
+ tristate "Microtune 2032 / 2050 tuners"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config MEDIA_TUNER_MT2060
+ tristate "Microtune MT2060 silicon IF tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon IF tuner MT2060 from Microtune.
+
+config MEDIA_TUNER_MT2063
+ tristate "Microtune MT2063 silicon IF tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon IF tuner MT2063 from Microtune.
+
+config MEDIA_TUNER_MT2266
+ tristate "Microtune MT2266 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config MEDIA_TUNER_MT2131
+ tristate "Microtune MT2131 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config MEDIA_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
+config MEDIA_TUNER_XC2028
+ tristate "XCeive xc2028/xc3028 tuners"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to include support for the xc2028/xc3028 tuners.
+
+config MEDIA_TUNER_XC5000
+ tristate "Xceive XC5000 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner XC5000 from Xceive.
+ This device is only used inside a SiP called together with a
+ demodulator for now.
+
+config MEDIA_TUNER_XC4000
+ tristate "Xceive XC4000 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner XC4000 from Xceive.
+ This device is only used inside a SiP called together with a
+ demodulator for now.
+
+config MEDIA_TUNER_MXL5005S
+ tristate "MaxLinear MSL5005S silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner MXL5005S from MaxLinear.
+
+config MEDIA_TUNER_MXL5007T
+ tristate "MaxLinear MxL5007T silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner MxL5007T from MaxLinear.
+
+config MEDIA_TUNER_MC44S803
+ tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Freescale MC44S803 based tuners
+
+config MEDIA_TUNER_MAX2165
+ tristate "Maxim MAX2165 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the silicon tuner MAX2165 from Maxim.
+
+config MEDIA_TUNER_TDA18218
+ tristate "NXP TDA18218 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ NXP TDA18218 silicon tuner driver.
+
+config MEDIA_TUNER_FC0011
+ tristate "Fitipower FC0011 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Fitipower FC0011 silicon tuner driver.
+
+config MEDIA_TUNER_FC0012
+ tristate "Fitipower FC0012 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Fitipower FC0012 silicon tuner driver.
+
+config MEDIA_TUNER_FC0013
+ tristate "Fitipower FC0013 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Fitipower FC0013 silicon tuner driver.
+
+config MEDIA_TUNER_TDA18212
+ tristate "NXP TDA18212 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ NXP TDA18212 silicon tuner driver.
+
+config MEDIA_TUNER_TUA9001
+ tristate "Infineon TUA 9001 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Infineon TUA 9001 silicon tuner driver.
+endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
new file mode 100644
index 000000000000..112aeee90202
--- /dev/null
+++ b/drivers/media/tuners/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for common V4L/DVB tuners
+#
+
+tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
+
+obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
+obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
+obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
+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
+obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
+obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
+obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
+obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
+obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/common/tuners/fc0011.c b/drivers/media/tuners/fc0011.c
index e4882546c283..e4882546c283 100644
--- a/drivers/media/common/tuners/fc0011.c
+++ b/drivers/media/tuners/fc0011.c
diff --git a/drivers/media/common/tuners/fc0011.h b/drivers/media/tuners/fc0011.h
index 0ee581f122d2..0ee581f122d2 100644
--- a/drivers/media/common/tuners/fc0011.h
+++ b/drivers/media/tuners/fc0011.h
diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/tuners/fc0012-priv.h
index 4577c917e616..4577c917e616 100644
--- a/drivers/media/common/tuners/fc0012-priv.h
+++ b/drivers/media/tuners/fc0012-priv.h
diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/tuners/fc0012.c
index 308135abd54c..308135abd54c 100644
--- a/drivers/media/common/tuners/fc0012.c
+++ b/drivers/media/tuners/fc0012.c
diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/tuners/fc0012.h
index 4dbd5efe8845..4dbd5efe8845 100644
--- a/drivers/media/common/tuners/fc0012.h
+++ b/drivers/media/tuners/fc0012.h
diff --git a/drivers/media/common/tuners/fc0013-priv.h b/drivers/media/tuners/fc0013-priv.h
index bfd49dedea22..bfd49dedea22 100644
--- a/drivers/media/common/tuners/fc0013-priv.h
+++ b/drivers/media/tuners/fc0013-priv.h
diff --git a/drivers/media/common/tuners/fc0013.c b/drivers/media/tuners/fc0013.c
index bd8f0f1e8f3b..bd8f0f1e8f3b 100644
--- a/drivers/media/common/tuners/fc0013.c
+++ b/drivers/media/tuners/fc0013.c
diff --git a/drivers/media/common/tuners/fc0013.h b/drivers/media/tuners/fc0013.h
index 594efd64aeec..594efd64aeec 100644
--- a/drivers/media/common/tuners/fc0013.h
+++ b/drivers/media/tuners/fc0013.h
diff --git a/drivers/media/common/tuners/fc001x-common.h b/drivers/media/tuners/fc001x-common.h
index 718818156934..718818156934 100644
--- a/drivers/media/common/tuners/fc001x-common.h
+++ b/drivers/media/tuners/fc001x-common.h
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/tuners/max2165.c
index ba84936aafd6..ba84936aafd6 100644
--- a/drivers/media/common/tuners/max2165.c
+++ b/drivers/media/tuners/max2165.c
diff --git a/drivers/media/common/tuners/max2165.h b/drivers/media/tuners/max2165.h
index c063c36a93d3..c063c36a93d3 100644
--- a/drivers/media/common/tuners/max2165.h
+++ b/drivers/media/tuners/max2165.h
diff --git a/drivers/media/common/tuners/max2165_priv.h b/drivers/media/tuners/max2165_priv.h
index 91bbe021a08d..91bbe021a08d 100644
--- a/drivers/media/common/tuners/max2165_priv.h
+++ b/drivers/media/tuners/max2165_priv.h
diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c
index 5ddce7e326f7..5ddce7e326f7 100644
--- a/drivers/media/common/tuners/mc44s803.c
+++ b/drivers/media/tuners/mc44s803.c
diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h
index 34f3892d3f6d..34f3892d3f6d 100644
--- a/drivers/media/common/tuners/mc44s803.h
+++ b/drivers/media/tuners/mc44s803.h
diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/tuners/mc44s803_priv.h
index 14a92780906d..14a92780906d 100644
--- a/drivers/media/common/tuners/mc44s803_priv.h
+++ b/drivers/media/tuners/mc44s803_priv.h
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/tuners/mt2060.c
index 13381de58a84..13381de58a84 100644
--- a/drivers/media/common/tuners/mt2060.c
+++ b/drivers/media/tuners/mt2060.c
diff --git a/drivers/media/common/tuners/mt2060.h b/drivers/media/tuners/mt2060.h
index cb60caffb6b6..cb60caffb6b6 100644
--- a/drivers/media/common/tuners/mt2060.h
+++ b/drivers/media/tuners/mt2060.h
diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/tuners/mt2060_priv.h
index 2b60de6c707d..2b60de6c707d 100644
--- a/drivers/media/common/tuners/mt2060_priv.h
+++ b/drivers/media/tuners/mt2060_priv.h
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index 0ed9091ff48e..0ed9091ff48e 100644
--- a/drivers/media/common/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/tuners/mt2063.h
index 3f5cfd93713f..3f5cfd93713f 100644
--- a/drivers/media/common/tuners/mt2063.h
+++ b/drivers/media/tuners/mt2063.h
diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c
index 0e74e97e0d1a..0e74e97e0d1a 100644
--- a/drivers/media/common/tuners/mt20xx.c
+++ b/drivers/media/tuners/mt20xx.c
diff --git a/drivers/media/common/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h
index 259553a24903..259553a24903 100644
--- a/drivers/media/common/tuners/mt20xx.h
+++ b/drivers/media/tuners/mt20xx.h
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/tuners/mt2131.c
index f83b0c1ea6c8..f83b0c1ea6c8 100644
--- a/drivers/media/common/tuners/mt2131.c
+++ b/drivers/media/tuners/mt2131.c
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/tuners/mt2131.h
index 6632de640df0..6632de640df0 100644
--- a/drivers/media/common/tuners/mt2131.h
+++ b/drivers/media/tuners/mt2131.h
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h
index 62aeedf5c550..62aeedf5c550 100644
--- a/drivers/media/common/tuners/mt2131_priv.h
+++ b/drivers/media/tuners/mt2131_priv.h
diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/tuners/mt2266.c
index bca4d75e42d4..bca4d75e42d4 100644
--- a/drivers/media/common/tuners/mt2266.c
+++ b/drivers/media/tuners/mt2266.c
diff --git a/drivers/media/common/tuners/mt2266.h b/drivers/media/tuners/mt2266.h
index 4d083882d044..4d083882d044 100644
--- a/drivers/media/common/tuners/mt2266.h
+++ b/drivers/media/tuners/mt2266.h
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
index 6133315fb0e3..6133315fb0e3 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/tuners/mxl5005s.c
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h
index fc8a1ffc53b4..fc8a1ffc53b4 100644
--- a/drivers/media/common/tuners/mxl5005s.h
+++ b/drivers/media/tuners/mxl5005s.h
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c
index 69e453ef0a1a..69e453ef0a1a 100644
--- a/drivers/media/common/tuners/mxl5007t.c
+++ b/drivers/media/tuners/mxl5007t.c
diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h
index aa3eea0b5262..aa3eea0b5262 100644
--- a/drivers/media/common/tuners/mxl5007t.h
+++ b/drivers/media/tuners/mxl5007t.h
diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c
new file mode 100644
index 000000000000..bdc39e11030e
--- /dev/null
+++ b/drivers/media/tuners/qt1010.c
@@ -0,0 +1,480 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.org>
+ *
+ * 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 "qt1010.h"
+#include "qt1010_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "QT1010: " args); \
+ } while (0)
+
+/* read single register */
+static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "qt1010 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* write single register */
+static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "qt1010 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* dump all registers */
+static void qt1010_dump_regs(struct qt1010_priv *priv)
+{
+ u8 reg, val;
+
+ for (reg = 0; ; reg++) {
+ if (reg % 16 == 0) {
+ if (reg)
+ printk(KERN_CONT "\n");
+ printk(KERN_DEBUG "%02x:", reg);
+ }
+ if (qt1010_readreg(priv, reg, &val) == 0)
+ printk(KERN_CONT " %02x", val);
+ else
+ printk(KERN_CONT " --");
+ if (reg == 0x2f)
+ break;
+ }
+ printk(KERN_CONT "\n");
+}
+
+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;
+ u8 i, tmpval, reg05;
+ qt1010_i2c_oper_t rd[48] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x05, 0xff }, /* 02 c write */
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0xff }, /* 04 c write */
+ { QT1010_WR, 0x08, 0x08 },
+ { QT1010_WR, 0x09, 0xff }, /* 06 c write */
+ { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
+ { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
+ { QT1010_WR, 0x0c, 0xe1 },
+ { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
+ { QT1010_WR, 0x1b, 0x00 },
+ { QT1010_WR, 0x1c, 0x89 },
+ { QT1010_WR, 0x11, 0xff }, /* 13 c write */
+ { QT1010_WR, 0x12, 0xff }, /* 14 c write */
+ { QT1010_WR, 0x22, 0xff }, /* 15 c write */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff }, /* 16 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_RD, 0x05, 0xff }, /* 20 c read */
+ { QT1010_RD, 0x22, 0xff }, /* 21 c read */
+ { QT1010_WR, 0x23, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xe0 },
+ { QT1010_RD, 0x23, 0xff }, /* 25 c read */
+ { QT1010_RD, 0x23, 0xff }, /* 26 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x24, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xf0 },
+ { QT1010_RD, 0x24, 0xff }, /* 31 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x14, 0x7f },
+ { QT1010_WR, 0x15, 0x7f },
+ { QT1010_WR, 0x05, 0xff }, /* 35 c write */
+ { QT1010_WR, 0x06, 0x00 },
+ { QT1010_WR, 0x15, 0x1f },
+ { QT1010_WR, 0x16, 0xff },
+ { QT1010_WR, 0x18, 0xff },
+ { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
+ { QT1010_WR, 0x20, 0xff }, /* 41 c write */
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_WR, 0x25, 0xff }, /* 43 c write */
+ { QT1010_WR, 0x26, 0x15 },
+ { QT1010_WR, 0x00, 0xff }, /* 45 c write */
+ { QT1010_WR, 0x02, 0x00 },
+ { QT1010_WR, 0x01, 0x00 }
+ };
+
+#define FREQ1 32000000 /* 32 MHz */
+#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
+
+ priv = fe->tuner_priv;
+ 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->frequency = freq;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ /* reg 05 base value */
+ if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
+ else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
+ else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
+ else reg05 = 0x74;
+
+ /* 0x5 */
+ rd[2].val = reg05;
+
+ /* 07 - set frequency: 32 MHz scale */
+ rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
+
+ /* 09 - changes every 8/24 MHz */
+ if (mod1 < 8000000) rd[6].val = 0x1d;
+ else rd[6].val = 0x1c;
+
+ /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
+ if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
+ else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
+ else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
+ else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
+ else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
+ else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
+ else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
+ else rd[7].val = 0x0a; /* +28 MHz */
+
+ /* 0b - changes every 2/2 MHz */
+ if (mod2 < 2000000) rd[8].val = 0x45;
+ else rd[8].val = 0x44;
+
+ /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
+ tmpval = 0x78; /* byte, overflows intentionally */
+ rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
+
+ /* 11 */
+ rd[13].val = 0xfd; /* TODO: correct value calculation */
+
+ /* 12 */
+ rd[14].val = 0x91; /* TODO: correct value calculation */
+
+ /* 22 */
+ if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
+ else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
+ else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
+ else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
+ else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
+ else rd[15].val = 0xd0;
+
+ /* 05 */
+ rd[35].val = (reg05 & 0xf0);
+
+ /* 1f */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 16000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
+
+ /* 20 */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 20000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
+
+ /* 25 */
+ rd[43].val = priv->reg25_init_val;
+
+ /* 00 */
+ rd[45].val = 0x92; /* TODO: correct value calculation */
+
+ dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
+ "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
+ "20:%02x 25:%02x 00:%02x", \
+ freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
+ rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
+ rd[40].val, rd[41].val, rd[43].val, rd[45].val);
+
+ for (i = 0; i < ARRAY_SIZE(rd); i++) {
+ if (rd[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
+ } else { /* read is required to proper locking */
+ err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+ }
+ if (err) return err;
+ }
+
+ if (debug)
+ qt1010_dump_regs(priv);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return 0;
+}
+
+static int qt1010_init_meas1(struct qt1010_priv *priv,
+ u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
+{
+ u8 i, val1, val2;
+ int err;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, reg, reg_init_val },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, oper },
+ { QT1010_RD, reg, 0xff }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
+ }
+ if (err) return err;
+ }
+
+ do {
+ val1 = val2;
+ err = qt1010_readreg(priv, reg, &val2);
+ if (err) return err;
+ dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
+ } while (val1 != val2);
+ *retval = val1;
+
+ return qt1010_writereg(priv, 0x1e, 0x00);
+}
+
+static int qt1010_init_meas2(struct qt1010_priv *priv,
+ u8 reg_init_val, u8 *retval)
+{
+ u8 i, val;
+ int err;
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x07, reg_init_val },
+ { QT1010_WR, 0x22, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x22, 0xff }
+ };
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val);
+ }
+ if (err) return err;
+ }
+ *retval = val;
+ return 0;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int err = 0;
+ u8 i, tmpval, *valptr = NULL;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x0d, 0x84 },
+ { QT1010_WR, 0x0e, 0xb7 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_WR, 0x2c, 0xdc },
+ { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
+ { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
+ { QT1010_WR, 0x2b, 0x70 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_M1, 0x26, 0x08 },
+ { QT1010_M1, 0x82, 0xff },
+ { QT1010_WR, 0x05, 0x14 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0x28 },
+ { QT1010_WR, 0x08, 0x0b },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_M1, 0x22, 0x0d },
+ { QT1010_M1, 0xd0, 0xff },
+ { QT1010_WR, 0x06, 0x40 },
+ { QT1010_WR, 0x16, 0xf0 },
+ { QT1010_WR, 0x02, 0x38 },
+ { QT1010_WR, 0x03, 0x18 },
+ { QT1010_WR, 0x20, 0xe0 },
+ { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
+ { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
+ { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
+ { QT1010_WR, 0x03, 0x19 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_RD, 0x21, 0xff },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_WR, 0x05, 0x34 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x08, 0x08 }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ switch (i2c_data[i].oper) {
+ case QT1010_WR:
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ break;
+ case QT1010_RD:
+ if (i2c_data[i].val == 0x20)
+ valptr = &priv->reg20_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+ break;
+ case QT1010_M1:
+ if (i2c_data[i].val == 0x25)
+ valptr = &priv->reg25_init_val;
+ else if (i2c_data[i].val == 0x1f)
+ valptr = &priv->reg1f_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
+ i2c_data[i].reg,
+ i2c_data[i].val, valptr);
+ i++;
+ break;
+ }
+ if (err) return err;
+ }
+
+ for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
+ if ((err = qt1010_init_meas2(priv, i, &tmpval)))
+ return err;
+
+ c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+ /* MSI Megasky 580 GL861 533000000 */
+ return qt1010_set_params(fe);
+}
+
+static int qt1010_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ *frequency = 36125000;
+ return 0;
+}
+
+static const struct dvb_tuner_ops qt1010_tuner_ops = {
+ .info = {
+ .name = "Quantek QT1010",
+ .frequency_min = QT1010_MIN_FREQ,
+ .frequency_max = QT1010_MAX_FREQ,
+ .frequency_step = QT1010_STEP,
+ },
+
+ .release = qt1010_release,
+ .init = qt1010_init,
+ /* TODO: implement sleep */
+
+ .set_params = qt1010_set_params,
+ .get_frequency = qt1010_get_frequency,
+ .get_if_frequency = qt1010_get_if_frequency,
+};
+
+struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg)
+{
+ struct qt1010_priv *priv = NULL;
+ u8 id;
+
+ priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+
+ /* Try to detect tuner chip. Probably this is not correct register. */
+ if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
+ kfree(priv);
+ return NULL;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
+ memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(qt1010_attach);
+
+MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/qt1010.h b/drivers/media/tuners/qt1010.h
index 807fb7b6146b..807fb7b6146b 100644
--- a/drivers/media/common/tuners/qt1010.h
+++ b/drivers/media/tuners/qt1010.h
diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/tuners/qt1010_priv.h
index 2c42d3f01636..2c42d3f01636 100644
--- a/drivers/media/common/tuners/qt1010_priv.h
+++ b/drivers/media/tuners/qt1010_priv.h
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
new file mode 100644
index 000000000000..5d9f02842501
--- /dev/null
+++ b/drivers/media/tuners/tda18212.c
@@ -0,0 +1,319 @@
+/*
+ * NXP TDA18212HN silicon tuner 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.
+ */
+
+#include "tda18212.h"
+
+struct tda18212_priv {
+ struct tda18212_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 if_frequency;
+};
+
+/* write multiple registers */
+static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[len+1];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
+ "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* read multiple registers */
+static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[len];
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg,
+ }, {
+ .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, buf, len);
+ ret = 0;
+ } else {
+ dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
+ "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
+{
+ return tda18212_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
+{
+ return tda18212_rd_regs(priv, reg, val, 1);
+}
+
+#if 0 /* keep, useful when developing driver */
+static void tda18212_dump_regs(struct tda18212_priv *priv)
+{
+ int i;
+ u8 buf[256];
+
+ #define TDA18212_RD_LEN 32
+ for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
+ tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
+
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
+ sizeof(buf), true);
+
+ return;
+}
+#endif
+
+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] = {
+ /* 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 },
+ };
+
+ dev_dbg(&priv->i2c->dev,
+ "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ __func__, c->delivery_system, c->frequency,
+ c->bandwidth_hz);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ if_khz = priv->cfg->if_dvbt_6;
+ i = DVBT_6;
+ break;
+ case 7000000:
+ if_khz = priv->cfg->if_dvbt_7;
+ i = DVBT_7;
+ break;
+ case 8000000:
+ if_khz = priv->cfg->if_dvbt_8;
+ i = DVBT_8;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+ break;
+ 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 = DVBC_8;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+ if (ret)
+ goto error;
+
+ ret = tda18212_wr_reg(priv, 0x06, 0x00);
+ if (ret)
+ goto error;
+
+ ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+ if (ret)
+ goto error;
+
+ buf[0] = 0x02;
+ buf[1] = bw_params[i][1];
+ buf[2] = 0x03; /* default value */
+ 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;
+ buf[7] = 0xc1;
+ buf[8] = 0x01;
+ ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+ 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 */
+
+ return ret;
+
+error:
+ dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ 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);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18212_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18212",
+
+ .frequency_min = 48000000,
+ .frequency_max = 864000000,
+ .frequency_step = 1000,
+ },
+
+ .release = tda18212_release,
+
+ .set_params = tda18212_set_params,
+ .get_if_frequency = tda18212_get_if_frequency,
+};
+
+struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+ struct tda18212_priv *priv = NULL;
+ int ret;
+ u8 uninitialized_var(val);
+
+ priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* check if the tuner is there */
+ ret = tda18212_rd_reg(priv, 0x00, &val);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret,
+ val);
+ if (ret || val != 0xc7) {
+ kfree(priv);
+ return NULL;
+ }
+
+ dev_info(&priv->i2c->dev,
+ "%s: NXP TDA18212HN successfully identified\n",
+ KBUILD_MODNAME);
+
+ memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18212_attach);
+
+MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/tuners/tda18212.h
index 9bd5da4aabb7..9bd5da4aabb7 100644
--- a/drivers/media/common/tuners/tda18212.h
+++ b/drivers/media/tuners/tda18212.h
diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c
new file mode 100644
index 000000000000..8a6f9ca788f0
--- /dev/null
+++ b/drivers/media/tuners/tda18218.c
@@ -0,0 +1,342 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 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 "tda18218.h"
+#include "tda18218_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret = 0;
+ u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ }
+ };
+
+ msg_len_max = priv->cfg->i2c_wr_max - 1;
+ quotient = len / msg_len_max;
+ remainder = len % msg_len_max;
+ msg_len = msg_len_max;
+ for (i = 0; (i <= quotient && remainder); i++) {
+ if (i == quotient) /* set len of the last msg */
+ msg_len = remainder;
+
+ msg[0].len = msg_len + 1;
+ buf[0] = reg + i * msg_len_max;
+ memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret != 1)
+ break;
+ }
+
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* read multiple registers */
+static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret;
+ u8 buf[reg+len]; /* we must start read always from reg 0x00 */
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x00",
+ }, {
+ .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, &buf[reg], len);
+ ret = 0;
+ } else {
+ warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
+{
+ return tda18218_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+
+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 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;
+ /* TODO: find out correct AGC algorithm */
+ u8 agc[][2] = {
+ { R20_AGC11, 0x60 },
+ { R23_AGC21, 0x02 },
+ { R20_AGC11, 0xa0 },
+ { R23_AGC21, 0x09 },
+ { R20_AGC11, 0xe0 },
+ { R23_AGC21, 0x0c },
+ { R20_AGC11, 0x40 },
+ { R23_AGC21, 0x01 },
+ { R20_AGC11, 0x80 },
+ { R23_AGC21, 0x08 },
+ { R20_AGC11, 0xc0 },
+ { R23_AGC21, 0x0b },
+ { R24_AGC22, 0x1c },
+ { R24_AGC22, 0x0c },
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* low-pass filter cut-off frequency */
+ if (bw <= 6000000) {
+ LP_Fc = 0;
+ priv->if_frequency = 3000000;
+ } else if (bw <= 7000000) {
+ LP_Fc = 1;
+ priv->if_frequency = 3500000;
+ } else {
+ LP_Fc = 2;
+ priv->if_frequency = 4000000;
+ }
+
+ LO_Frac = c->frequency + priv->if_frequency;
+
+ /* band-pass filter */
+ if (LO_Frac < 188000000)
+ BP_Filter = 3;
+ else if (LO_Frac < 253000000)
+ BP_Filter = 4;
+ else if (LO_Frac < 343000000)
+ BP_Filter = 5;
+ else
+ BP_Filter = 6;
+
+ buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
+ buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
+ buf[2] = priv->regs[R1C_AGC2B];
+ ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
+ buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
+ buf[2] = (LO_Frac / 1000) << 4 |
+ (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
+ ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ /* trigger AGC */
+ for (i = 0; i < ARRAY_SIZE(agc); i++) {
+ ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
+ if (ret)
+ goto error;
+ }
+
+error:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ 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;
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+
+ /* TODO: calibrations */
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18218",
+
+ .frequency_min = 174000000,
+ .frequency_max = 864000000,
+ .frequency_step = 1000,
+ },
+
+ .release = tda18218_release,
+ .init = tda18218_init,
+ .sleep = tda18218_sleep,
+
+ .set_params = tda18218_set_params,
+
+ .get_if_frequency = tda18218_get_if_frequency,
+};
+
+struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+ struct tda18218_priv *priv = NULL;
+ u8 uninitialized_var(val);
+ int ret;
+ /* chip default registers values */
+ static u8 def_regs[] = {
+ 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
+ 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
+ 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
+ 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
+ 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
+ 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
+ };
+
+ priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* check if the tuner is there */
+ ret = tda18218_rd_reg(priv, R00_ID, &val);
+ dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+ if (ret || val != def_regs[R00_ID]) {
+ kfree(priv);
+ return NULL;
+ }
+
+ info("NXP TDA18218HN successfully identified.");
+
+ memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ memcpy(priv->regs, def_regs, sizeof(def_regs));
+
+ /* loop-through enabled chip default register values */
+ if (priv->cfg->loop_through) {
+ priv->regs[R17_PD1] = 0xb0;
+ priv->regs[R18_PD2] = 0x59;
+ }
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/tuners/tda18218.h
index b4180d180029..b4180d180029 100644
--- a/drivers/media/common/tuners/tda18218.h
+++ b/drivers/media/tuners/tda18218.h
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/tuners/tda18218_priv.h
index dc52b72e1407..dc52b72e1407 100644
--- a/drivers/media/common/tuners/tda18218_priv.h
+++ b/drivers/media/tuners/tda18218_priv.h
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c
index 39c645787b62..39c645787b62 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/tuners/tda18271-common.c
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index 2e67f4459904..2e67f4459904 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c
index fb881c667c94..fb881c667c94 100644
--- a/drivers/media/common/tuners/tda18271-maps.c
+++ b/drivers/media/tuners/tda18271-maps.c
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h
index 454c152ccaa0..454c152ccaa0 100644
--- a/drivers/media/common/tuners/tda18271-priv.h
+++ b/drivers/media/tuners/tda18271-priv.h
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/tuners/tda18271.h
index 640bae4e6a5a..640bae4e6a5a 100644
--- a/drivers/media/common/tuners/tda18271.h
+++ b/drivers/media/tuners/tda18271.h
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/tuners/tda827x.c
index a0d176267470..a0d176267470 100644
--- a/drivers/media/common/tuners/tda827x.c
+++ b/drivers/media/tuners/tda827x.c
diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/tuners/tda827x.h
index 7d72ce0a0c2d..7d72ce0a0c2d 100644
--- a/drivers/media/common/tuners/tda827x.h
+++ b/drivers/media/tuners/tda827x.h
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/tuners/tda8290.c
index 8c4852114eeb..8c4852114eeb 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/tuners/tda8290.c
diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/tuners/tda8290.h
index 7e288b26fcc3..7e288b26fcc3 100644
--- a/drivers/media/common/tuners/tda8290.h
+++ b/drivers/media/tuners/tda8290.h
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/tuners/tda9887.c
index cdb645d57438..cdb645d57438 100644
--- a/drivers/media/common/tuners/tda9887.c
+++ b/drivers/media/tuners/tda9887.c
diff --git a/drivers/media/common/tuners/tda9887.h b/drivers/media/tuners/tda9887.h
index acc419e8c4fc..acc419e8c4fc 100644
--- a/drivers/media/common/tuners/tda9887.h
+++ b/drivers/media/tuners/tda9887.h
diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/tuners/tea5761.c
index bf78cb9fc52c..bf78cb9fc52c 100644
--- a/drivers/media/common/tuners/tea5761.c
+++ b/drivers/media/tuners/tea5761.c
diff --git a/drivers/media/common/tuners/tea5761.h b/drivers/media/tuners/tea5761.h
index 2e2ff82c95a4..2e2ff82c95a4 100644
--- a/drivers/media/common/tuners/tea5761.h
+++ b/drivers/media/tuners/tea5761.h
diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/tuners/tea5767.c
index 36e85d81acb2..36e85d81acb2 100644
--- a/drivers/media/common/tuners/tea5767.c
+++ b/drivers/media/tuners/tea5767.c
diff --git a/drivers/media/common/tuners/tea5767.h b/drivers/media/tuners/tea5767.h
index d30ab1b483de..d30ab1b483de 100644
--- a/drivers/media/common/tuners/tea5767.h
+++ b/drivers/media/tuners/tea5767.h
diff --git a/drivers/media/common/tuners/tua9001.c b/drivers/media/tuners/tua9001.c
index de2607084672..de2607084672 100644
--- a/drivers/media/common/tuners/tua9001.c
+++ b/drivers/media/tuners/tua9001.c
diff --git a/drivers/media/common/tuners/tua9001.h b/drivers/media/tuners/tua9001.h
index 38d6ae76b1d6..38d6ae76b1d6 100644
--- a/drivers/media/common/tuners/tua9001.h
+++ b/drivers/media/tuners/tua9001.h
diff --git a/drivers/media/common/tuners/tua9001_priv.h b/drivers/media/tuners/tua9001_priv.h
index 73cc1ce0575c..73cc1ce0575c 100644
--- a/drivers/media/common/tuners/tua9001_priv.h
+++ b/drivers/media/tuners/tua9001_priv.h
diff --git a/drivers/media/common/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h
index 18f005634c67..18f005634c67 100644
--- a/drivers/media/common/tuners/tuner-i2c.h
+++ b/drivers/media/tuners/tuner-i2c.h
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
index 39e7e583c8c0..39e7e583c8c0 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/tuners/tuner-simple.c
diff --git a/drivers/media/common/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h
index 381fa5d35a9b..381fa5d35a9b 100644
--- a/drivers/media/common/tuners/tuner-simple.h
+++ b/drivers/media/tuners/tuner-simple.h
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c
index 2da4440c16ee..2da4440c16ee 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/tuners/tuner-types.c
diff --git a/drivers/media/common/tuners/tuner-xc2028-types.h b/drivers/media/tuners/tuner-xc2028-types.h
index 74dc46a71f64..74dc46a71f64 100644
--- a/drivers/media/common/tuners/tuner-xc2028-types.h
+++ b/drivers/media/tuners/tuner-xc2028-types.h
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
new file mode 100644
index 000000000000..7bcb6b0ff1df
--- /dev/null
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -0,0 +1,1509 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
+ *
+ * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
+ * - frontend interface
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <asm/div64.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include "tuner-i2c.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
+
+#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);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+ "1 keep device energized and with tuner ready all the times.\n"
+ " Faster, but consumes more power and keeps the device hotter\n");
+
+static char audio_std[8];
+module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
+MODULE_PARM_DESC(audio_std,
+ "Audio standard. XC3028 audio decoder explicitly "
+ "needs to know what audio\n"
+ "standard is needed for some video standards with audio A2 or NICAM.\n"
+ "The valid values are:\n"
+ "A2\n"
+ "A2/A\n"
+ "A2/B\n"
+ "NICAM\n"
+ "NICAM/A\n"
+ "NICAM/B\n");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+ "default firmware name\n");
+
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(xc2028_list_mutex);
+
+/* struct for storing firmware table */
+struct firmware_description {
+ unsigned int type;
+ v4l2_std_id id;
+ __u16 int_freq;
+ unsigned char *ptr;
+ unsigned int size;
+};
+
+struct firmware_properties {
+ unsigned int type;
+ v4l2_std_id id;
+ v4l2_std_id std_req;
+ __u16 int_freq;
+ unsigned int scode_table;
+ int scode_nr;
+};
+
+enum xc2028_state {
+ XC2028_NO_FIRMWARE = 0,
+ XC2028_WAITING_FIRMWARE,
+ XC2028_ACTIVE,
+ XC2028_SLEEP,
+ XC2028_NODEV,
+};
+
+struct xc2028_data {
+ struct list_head hybrid_tuner_instance_list;
+ struct tuner_i2c_props i2c_props;
+ __u32 frequency;
+
+ enum xc2028_state state;
+ const char *fname;
+
+ struct firmware_description *firm;
+ int firm_size;
+ __u16 firm_version;
+
+ __u16 hwmodel;
+ __u16 hwvers;
+
+ struct xc2028_ctrl ctrl;
+
+ struct firmware_properties cur_fw;
+
+ struct mutex lock;
+};
+
+#define i2c_send(priv, buf, size) ({ \
+ int _rc; \
+ _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \
+ if (size != _rc) \
+ tuner_info("i2c output error: rc = %d (should be %d)\n",\
+ _rc, (int)size); \
+ if (priv->ctrl.msleep) \
+ msleep(priv->ctrl.msleep); \
+ _rc; \
+})
+
+#define i2c_rcv(priv, buf, size) ({ \
+ int _rc; \
+ _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \
+ if (size != _rc) \
+ tuner_err("i2c input error: rc = %d (should be %d)\n", \
+ _rc, (int)size); \
+ _rc; \
+})
+
+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \
+ int _rc; \
+ _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \
+ ibuf, isize); \
+ if (isize != _rc) \
+ tuner_err("i2c input error: rc = %d (should be %d)\n", \
+ _rc, (int)isize); \
+ if (priv->ctrl.msleep) \
+ msleep(priv->ctrl.msleep); \
+ _rc; \
+})
+
+#define send_seq(priv, data...) ({ \
+ static u8 _val[] = data; \
+ int _rc; \
+ if (sizeof(_val) != \
+ (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \
+ _val, sizeof(_val)))) { \
+ tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
+ } else if (priv->ctrl.msleep) \
+ msleep(priv->ctrl.msleep); \
+ _rc; \
+})
+
+static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+{
+ unsigned char buf[2];
+ unsigned char ibuf[2];
+
+ tuner_dbg("%s %04x called\n", __func__, reg);
+
+ buf[0] = reg >> 8;
+ buf[1] = (unsigned char) reg;
+
+ if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
+ return -EIO;
+
+ *val = (ibuf[1]) | (ibuf[0] << 8);
+ return 0;
+}
+
+#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+ if (type & BASE)
+ printk("BASE ");
+ if (type & INIT1)
+ printk("INIT1 ");
+ if (type & F8MHZ)
+ printk("F8MHZ ");
+ if (type & MTS)
+ printk("MTS ");
+ if (type & D2620)
+ printk("D2620 ");
+ if (type & D2633)
+ printk("D2633 ");
+ if (type & DTV6)
+ printk("DTV6 ");
+ if (type & QAM)
+ printk("QAM ");
+ if (type & DTV7)
+ printk("DTV7 ");
+ if (type & DTV78)
+ printk("DTV78 ");
+ if (type & DTV8)
+ printk("DTV8 ");
+ if (type & FM)
+ printk("FM ");
+ if (type & INPUT1)
+ printk("INPUT1 ");
+ if (type & LCD)
+ printk("LCD ");
+ if (type & NOGD)
+ printk("NOGD ");
+ if (type & MONO)
+ printk("MONO ");
+ if (type & ATSC)
+ printk("ATSC ");
+ if (type & IF)
+ printk("IF ");
+ if (type & LG60)
+ printk("LG60 ");
+ if (type & ATI638)
+ printk("ATI638 ");
+ if (type & OREN538)
+ printk("OREN538 ");
+ if (type & OREN36)
+ printk("OREN36 ");
+ if (type & TOYOTA388)
+ printk("TOYOTA388 ");
+ if (type & TOYOTA794)
+ printk("TOYOTA794 ");
+ if (type & DIBCOM52)
+ printk("DIBCOM52 ");
+ if (type & ZARLINK456)
+ printk("ZARLINK456 ");
+ if (type & CHINA)
+ printk("CHINA ");
+ if (type & F6MHZ)
+ printk("F6MHZ ");
+ if (type & INPUT2)
+ printk("INPUT2 ");
+ if (type & SCODE)
+ printk("SCODE ");
+ if (type & HAS_IF)
+ printk("HAS_IF_%d ", int_freq);
+}
+
+static v4l2_std_id parse_audio_std_option(void)
+{
+ if (strcasecmp(audio_std, "A2") == 0)
+ return V4L2_STD_A2;
+ if (strcasecmp(audio_std, "A2/A") == 0)
+ return V4L2_STD_A2_A;
+ if (strcasecmp(audio_std, "A2/B") == 0)
+ return V4L2_STD_A2_B;
+ if (strcasecmp(audio_std, "NICAM") == 0)
+ return V4L2_STD_NICAM;
+ if (strcasecmp(audio_std, "NICAM/A") == 0)
+ return V4L2_STD_NICAM_A;
+ if (strcasecmp(audio_std, "NICAM/B") == 0)
+ return V4L2_STD_NICAM_B;
+
+ return 0;
+}
+
+static int check_device_status(struct xc2028_data *priv)
+{
+ switch (priv->state) {
+ case XC2028_NO_FIRMWARE:
+ case XC2028_WAITING_FIRMWARE:
+ return -EAGAIN;
+ case XC2028_ACTIVE:
+ case XC2028_SLEEP:
+ return 0;
+ case XC2028_NODEV:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void free_firmware(struct xc2028_data *priv)
+{
+ int i;
+ tuner_dbg("%s called\n", __func__);
+
+ if (!priv->firm)
+ return;
+
+ for (i = 0; i < priv->firm_size; i++)
+ kfree(priv->firm[i].ptr);
+
+ kfree(priv->firm);
+
+ priv->firm = NULL;
+ priv->firm_size = 0;
+ priv->state = XC2028_NO_FIRMWARE;
+
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+}
+
+static int load_all_firmwares(struct dvb_frontend *fe,
+ const struct firmware *fw)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ const unsigned char *p, *endp;
+ int rc = 0;
+ int n, n_array;
+ char name[33];
+
+ tuner_dbg("%s called\n", __func__);
+
+ p = fw->data;
+ endp = p + fw->size;
+
+ if (fw->size < sizeof(name) - 1 + 2 + 2) {
+ tuner_err("Error: firmware file %s has invalid size!\n",
+ priv->fname);
+ goto corrupt;
+ }
+
+ memcpy(name, p, sizeof(name) - 1);
+ name[sizeof(name) - 1] = 0;
+ p += sizeof(name) - 1;
+
+ priv->firm_version = get_unaligned_le16(p);
+ p += 2;
+
+ n_array = get_unaligned_le16(p);
+ p += 2;
+
+ tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+ n_array, priv->fname, name,
+ priv->firm_version >> 8, priv->firm_version & 0xff);
+
+ 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;
+ goto err;
+ }
+ priv->firm_size = n_array;
+
+ n = -1;
+ while (p < endp) {
+ __u32 type, size;
+ v4l2_std_id id;
+ __u16 int_freq = 0;
+
+ n++;
+ if (n >= n_array) {
+ tuner_err("More firmware images in file than "
+ "were expected!\n");
+ goto corrupt;
+ }
+
+ /* Checks if there's enough bytes to read */
+ if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+ goto header;
+
+ type = get_unaligned_le32(p);
+ p += sizeof(type);
+
+ id = get_unaligned_le64(p);
+ p += sizeof(id);
+
+ if (type & HAS_IF) {
+ int_freq = get_unaligned_le16(p);
+ p += sizeof(int_freq);
+ if (endp - p < sizeof(size))
+ goto header;
+ }
+
+ size = get_unaligned_le32(p);
+ p += sizeof(size);
+
+ if (!size || size > endp - p) {
+ tuner_err("Firmware type ");
+ dump_firm_type(type);
+ printk("(%x), id %llx is corrupted "
+ "(size=%d, expected %d)\n",
+ type, (unsigned long long)id,
+ (unsigned)(endp - p), size);
+ goto corrupt;
+ }
+
+ priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+ if (priv->firm[n].ptr == NULL) {
+ tuner_err("Not enough memory to load firmware file.\n");
+ rc = -ENOMEM;
+ goto err;
+ }
+ tuner_dbg("Reading firmware type ");
+ if (debug) {
+ dump_firm_type_and_int_freq(type, int_freq);
+ printk("(%x), id %llx, size=%d.\n",
+ type, (unsigned long long)id, size);
+ }
+
+ memcpy(priv->firm[n].ptr, p, size);
+ priv->firm[n].type = type;
+ priv->firm[n].id = id;
+ priv->firm[n].size = size;
+ priv->firm[n].int_freq = int_freq;
+
+ p += size;
+ }
+
+ if (n + 1 != priv->firm_size) {
+ tuner_err("Firmware file is incomplete!\n");
+ goto corrupt;
+ }
+
+ goto done;
+
+header:
+ tuner_err("Firmware header is incomplete!\n");
+corrupt:
+ rc = -EINVAL;
+ tuner_err("Error: firmware file is corrupted!\n");
+
+err:
+ tuner_info("Releasing partially loaded firmware file.\n");
+ free_firmware(priv);
+
+done:
+ if (rc == 0)
+ tuner_dbg("Firmware files loaded.\n");
+ else
+ priv->state = XC2028_NODEV;
+
+ return rc;
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int i, best_i = -1, best_nr_matches = 0;
+ unsigned int type_mask = 0;
+
+ tuner_dbg("%s called, want type=", __func__);
+ if (debug) {
+ dump_firm_type(type);
+ printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+ }
+
+ if (!priv->firm) {
+ tuner_err("Error! firmware not loaded\n");
+ return -EINVAL;
+ }
+
+ if (((type & ~SCODE) == 0) && (*id == 0))
+ *id = V4L2_STD_PAL;
+
+ if (type & BASE)
+ type_mask = BASE_TYPES;
+ else if (type & SCODE) {
+ type &= SCODE_TYPES;
+ type_mask = SCODE_TYPES & ~HAS_IF;
+ } else if (type & DTV_TYPES)
+ type_mask = DTV_TYPES;
+ else if (type & STD_SPECIFIC_TYPES)
+ type_mask = STD_SPECIFIC_TYPES;
+
+ type &= type_mask;
+
+ if (!(type & SCODE))
+ type_mask = ~0;
+
+ /* Seek for exact match */
+ for (i = 0; i < priv->firm_size; i++) {
+ if ((type == (priv->firm[i].type & type_mask)) &&
+ (*id == priv->firm[i].id))
+ goto found;
+ }
+
+ /* Seek for generic video standard match */
+ for (i = 0; i < priv->firm_size; i++) {
+ v4l2_std_id match_mask;
+ int nr_matches;
+
+ if (type != (priv->firm[i].type & type_mask))
+ continue;
+
+ match_mask = *id & priv->firm[i].id;
+ if (!match_mask)
+ continue;
+
+ if ((*id & match_mask) == *id)
+ goto found; /* Supports all the requested standards */
+
+ nr_matches = hweight64(match_mask);
+ if (nr_matches > best_nr_matches) {
+ best_nr_matches = nr_matches;
+ best_i = i;
+ }
+ }
+
+ if (best_nr_matches > 0) {
+ tuner_dbg("Selecting best matching firmware (%d bits) for "
+ "type=", best_nr_matches);
+ dump_firm_type(type);
+ printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
+ i = best_i;
+ goto found;
+ }
+
+ /*FIXME: Would make sense to seek for type "hint" match ? */
+
+ i = -ENOENT;
+ goto ret;
+
+found:
+ *id = priv->firm[i].id;
+
+ret:
+ tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
+ if (debug) {
+ dump_firm_type(type);
+ printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+ }
+ return i;
+}
+
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+
+ /* analog side (tuner-core) uses i2c_adap->algo_data.
+ * digital side is not guaranteed to have algo_data defined.
+ *
+ * digital side will always have fe->dvb defined.
+ * analog side (tuner-core) doesn't (yet) define fe->dvb.
+ */
+
+ return (!fe->callback) ? -EINVAL :
+ fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv : priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int pos, rc;
+ unsigned char *p, *endp, buf[priv->ctrl.max_len];
+
+ tuner_dbg("%s called\n", __func__);
+
+ pos = seek_firmware(fe, type, id);
+ if (pos < 0)
+ return pos;
+
+ tuner_info("Loading firmware for type=");
+ dump_firm_type(priv->firm[pos].type);
+ printk("(%x), id %016llx.\n", priv->firm[pos].type,
+ (unsigned long long)*id);
+
+ p = priv->firm[pos].ptr;
+ endp = p + priv->firm[pos].size;
+
+ while (p < endp) {
+ __u16 size;
+
+ /* Checks if there's enough bytes to read */
+ if (p + sizeof(size) > endp) {
+ tuner_err("Firmware chunk size is wrong\n");
+ return -EINVAL;
+ }
+
+ size = le16_to_cpu(*(__u16 *) p);
+ p += sizeof(size);
+
+ if (size == 0xffff)
+ return 0;
+
+ if (!size) {
+ /* Special callback command received */
+ rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
+ if (rc < 0) {
+ tuner_err("Error at RESET code %d\n",
+ (*p) & 0x7f);
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (size >= 0xff00) {
+ switch (size) {
+ case 0xff00:
+ rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
+ if (rc < 0) {
+ tuner_err("Error at RESET code %d\n",
+ (*p) & 0x7f);
+ return -EINVAL;
+ }
+ break;
+ default:
+ tuner_info("Invalid RESET code %d\n",
+ size & 0x7f);
+ return -EINVAL;
+
+ }
+ continue;
+ }
+
+ /* Checks for a sleep command */
+ if (size & 0x8000) {
+ msleep(size & 0x7fff);
+ continue;
+ }
+
+ if ((size + p > endp)) {
+ tuner_err("missing bytes: need %d, have %d\n",
+ size, (int)(endp - p));
+ return -EINVAL;
+ }
+
+ buf[0] = *p;
+ p++;
+ size--;
+
+ /* Sends message chunks */
+ while (size > 0) {
+ int len = (size < priv->ctrl.max_len - 1) ?
+ size : priv->ctrl.max_len - 1;
+
+ memcpy(buf + 1, p, len);
+
+ rc = i2c_send(priv, buf, len + 1);
+ if (rc < 0) {
+ tuner_err("%d returned from send\n", rc);
+ return -EINVAL;
+ }
+
+ p += len;
+ size -= len;
+ }
+
+ /* silently fail if the frontend doesn't support I2C flush */
+ rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
+ if ((rc < 0) && (rc != -EINVAL)) {
+ tuner_err("error executing flush: %d\n", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id, __u16 int_freq, int scode)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int pos, rc;
+ unsigned char *p;
+
+ tuner_dbg("%s called\n", __func__);
+
+ if (!int_freq) {
+ pos = seek_firmware(fe, type, id);
+ if (pos < 0)
+ return pos;
+ } else {
+ for (pos = 0; pos < priv->firm_size; pos++) {
+ if ((priv->firm[pos].int_freq == int_freq) &&
+ (priv->firm[pos].type & HAS_IF))
+ break;
+ }
+ if (pos == priv->firm_size)
+ return -ENOENT;
+ }
+
+ p = priv->firm[pos].ptr;
+
+ if (priv->firm[pos].type & HAS_IF) {
+ if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+ return -EINVAL;
+ p += 12 * scode;
+ } else {
+ /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+ * has a 2-byte size header in the firmware format. */
+ if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+ le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+ return -EINVAL;
+ p += 14 * scode + 2;
+ }
+
+ tuner_info("Loading SCODE for type=");
+ dump_firm_type_and_int_freq(priv->firm[pos].type,
+ priv->firm[pos].int_freq);
+ printk("(%x), id %016llx.\n", priv->firm[pos].type,
+ (unsigned long long)*id);
+
+ if (priv->firm_version < 0x0202)
+ rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
+ else
+ rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
+ if (rc < 0)
+ return -EIO;
+
+ rc = i2c_send(priv, p, 12);
+ if (rc < 0)
+ return -EIO;
+
+ rc = send_seq(priv, {0x00, 0x8c});
+ if (rc < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id std, __u16 int_freq)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ struct firmware_properties new_fw;
+ int rc, retry_count = 0;
+ u16 version, hwmodel;
+ v4l2_std_id std0;
+
+ tuner_dbg("%s called\n", __func__);
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ if (priv->ctrl.mts && !(type & FM))
+ type |= MTS;
+
+retry:
+ new_fw.type = type;
+ new_fw.id = std;
+ new_fw.std_req = std;
+ new_fw.scode_table = SCODE | priv->ctrl.scode_table;
+ new_fw.scode_nr = 0;
+ new_fw.int_freq = int_freq;
+
+ tuner_dbg("checking firmware, user requested type=");
+ if (debug) {
+ dump_firm_type(new_fw.type);
+ printk("(%x), id %016llx, ", new_fw.type,
+ (unsigned long long)new_fw.std_req);
+ if (!int_freq) {
+ printk("scode_tbl ");
+ dump_firm_type(priv->ctrl.scode_table);
+ printk("(%x), ", priv->ctrl.scode_table);
+ } else
+ printk("int_freq %d, ", new_fw.int_freq);
+ printk("scode_nr %d\n", new_fw.scode_nr);
+ }
+
+ /*
+ * No need to reload base firmware if it matches and if the tuner
+ * is not at sleep mode
+ */
+ if ((priv->state == XC2028_ACTIVE) &&
+ (((BASE | new_fw.type) & BASE_TYPES) ==
+ (priv->cur_fw.type & BASE_TYPES))) {
+ tuner_dbg("BASE firmware not changed.\n");
+ goto skip_base;
+ }
+
+ /* Updating BASE - forget about all currently loaded firmware */
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+ /* Reset is needed before loading firmware */
+ rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
+ if (rc < 0)
+ goto fail;
+
+ /* BASE firmwares are all std0 */
+ std0 = 0;
+ rc = load_firmware(fe, BASE | new_fw.type, &std0);
+ if (rc < 0) {
+ tuner_err("Error %d while loading base firmware\n",
+ rc);
+ goto fail;
+ }
+
+ /* Load INIT1, if needed */
+ tuner_dbg("Load init1 firmware, if exists\n");
+
+ rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
+ if (rc == -ENOENT)
+ rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
+ &std0);
+ if (rc < 0 && rc != -ENOENT) {
+ tuner_err("Error %d while loading init1 firmware\n",
+ rc);
+ goto fail;
+ }
+
+skip_base:
+ /*
+ * No need to reload standard specific firmware if base firmware
+ * was not reloaded and requested video standards have not changed.
+ */
+ if (priv->cur_fw.type == (BASE | new_fw.type) &&
+ priv->cur_fw.std_req == std) {
+ tuner_dbg("Std-specific firmware already loaded.\n");
+ goto skip_std_specific;
+ }
+
+ /* Reloading std-specific firmware forces a SCODE update */
+ priv->cur_fw.scode_table = 0;
+
+ rc = load_firmware(fe, new_fw.type, &new_fw.id);
+ if (rc == -ENOENT)
+ rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
+
+ if (rc < 0)
+ goto fail;
+
+skip_std_specific:
+ if (priv->cur_fw.scode_table == new_fw.scode_table &&
+ priv->cur_fw.scode_nr == new_fw.scode_nr) {
+ tuner_dbg("SCODE firmware already loaded.\n");
+ goto check_device;
+ }
+
+ if (new_fw.type & FM)
+ goto check_device;
+
+ /* Load SCODE firmware, if exists */
+ tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
+
+ rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+ new_fw.int_freq, new_fw.scode_nr);
+
+check_device:
+ if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
+ xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
+ tuner_err("Unable to read tuner registers.\n");
+ goto fail;
+ }
+
+ tuner_dbg("Device is Xceive %d version %d.%d, "
+ "firmware version %d.%d\n",
+ hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+ (version & 0xf0) >> 4, version & 0xf);
+
+
+ if (priv->ctrl.read_not_reliable)
+ goto read_not_reliable;
+
+ /* Check firmware version against what we downloaded. */
+ if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
+ if (!priv->ctrl.read_not_reliable) {
+ tuner_err("Incorrect readback of firmware version.\n");
+ goto fail;
+ } else {
+ tuner_err("Returned an incorrect version. However, "
+ "read is not reliable enough. Ignoring it.\n");
+ hwmodel = 3028;
+ }
+ }
+
+ /* Check that the tuner hardware model remains consistent over time. */
+ if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
+ priv->hwmodel = hwmodel;
+ priv->hwvers = version & 0xff00;
+ } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+ priv->hwvers != (version & 0xff00)) {
+ tuner_err("Read invalid device hardware information - tuner "
+ "hung?\n");
+ goto fail;
+ }
+
+read_not_reliable:
+ memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+ /*
+ * By setting BASE in cur_fw.type only after successfully loading all
+ * firmwares, we can:
+ * 1. Identify that BASE firmware with type=0 has been loaded;
+ * 2. Tell whether BASE firmware was just changed the next time through.
+ */
+ priv->cur_fw.type |= BASE;
+ priv->state = XC2028_ACTIVE;
+
+ return 0;
+
+fail:
+ priv->state = XC2028_SLEEP;
+
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+ if (retry_count < 8) {
+ msleep(50);
+ retry_count++;
+ tuner_dbg("Retrying firmware load\n");
+ goto retry;
+ }
+
+ if (rc == -ENOENT)
+ rc = -EINVAL;
+ return rc;
+}
+
+static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ u16 frq_lock, signal = 0;
+ int rc, i;
+
+ tuner_dbg("%s called\n", __func__);
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&priv->lock);
+
+ /* Sync Lock Indicator */
+ for (i = 0; i < 3; i++) {
+ rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+ if (rc < 0)
+ goto ret;
+
+ if (frq_lock)
+ break;
+ msleep(6);
+ }
+
+ /* Frequency didn't lock */
+ if (frq_lock == 2)
+ goto ret;
+
+ /* Get SNR of the video signal */
+ rc = xc2028_get_reg(priv, XREG_SNR, &signal);
+ if (rc < 0)
+ goto ret;
+
+ /* Signal level is 3 bits only */
+
+ signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
+
+ret:
+ mutex_unlock(&priv->lock);
+
+ *strength = signal;
+
+ tuner_dbg("signal strength is %d\n", signal);
+
+ return rc;
+}
+
+static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int i, rc;
+ u16 frq_lock = 0;
+ s16 afc_reg = 0;
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&priv->lock);
+
+ /* Sync Lock Indicator */
+ for (i = 0; i < 3; i++) {
+ rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+ if (rc < 0)
+ goto ret;
+
+ if (frq_lock)
+ break;
+ msleep(6);
+ }
+
+ /* Frequency didn't lock */
+ if (frq_lock == 2)
+ goto ret;
+
+ /* Get AFC */
+ rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
+ if (rc < 0)
+ goto ret;
+
+ *afc = afc_reg * 15625; /* Hz */
+
+ tuner_dbg("AFC is %d Hz\n", *afc);
+
+ret:
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+#define DIV 15625
+
+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
+ enum v4l2_tuner_type new_type,
+ unsigned int type,
+ v4l2_std_id std,
+ u16 int_freq)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int rc = -EINVAL;
+ unsigned char buf[4];
+ u32 div, offset = 0;
+
+ tuner_dbg("%s called\n", __func__);
+
+ mutex_lock(&priv->lock);
+
+ tuner_dbg("should set frequency %d kHz\n", freq / 1000);
+
+ if (check_firmware(fe, type, std, int_freq) < 0)
+ goto ret;
+
+ /* On some cases xc2028 can disable video output, if
+ * very weak signals are received. By sending a soft
+ * reset, this is re-enabled. So, it is better to always
+ * send a soft reset before changing channels, to be sure
+ * that xc2028 will be in a safe state.
+ * Maybe this might also be needed for DTV.
+ */
+ switch (new_type) {
+ case V4L2_TUNER_ANALOG_TV:
+ rc = send_seq(priv, {0x00, 0x00});
+
+ /* Analog mode requires offset = 0 */
+ break;
+ case V4L2_TUNER_RADIO:
+ /* Radio mode requires offset = 0 */
+ break;
+ case V4L2_TUNER_DIGITAL_TV:
+ /*
+ * Digital modes require an offset to adjust to the
+ * proper frequency. The offset depends on what
+ * firmware version is used.
+ */
+
+ /*
+ * Adjust to the center frequency. This is calculated by the
+ * formula: offset = 1.25MHz - BW/2
+ * 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 /* DTV7 or DTV8 or DTV78 */
+ offset = 2750000;
+
+ /*
+ * xc3028 additional "magic"
+ * Depending on the firmware version, it needs some adjustments
+ * to properly centralize the frequency. This seems to be
+ * needed to compensate the SCODE table adjustments made by
+ * newer firmwares
+ */
+
+ /*
+ * 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 0
+ /*
+ * Still need tests for XC3028L (firmware 3.2 or upper)
+ * So, for now, let's just comment the per-firmware
+ * version of this change. Reports with xc3028l working
+ * with and without the lines bellow are welcome
+ */
+
+ if (priv->firm_version < 0x0302) {
+ if (priv->cur_fw.type & DTV7)
+ offset += 500000;
+ } else {
+ if (priv->cur_fw.type & DTV7)
+ offset -= 300000;
+ else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
+ offset += 200000;
+ }
+#endif
+ }
+
+ div = (freq - offset + DIV / 2) / DIV;
+
+ /* CMD= Set frequency */
+ if (priv->firm_version < 0x0202)
+ rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
+ else
+ rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
+ if (rc < 0)
+ goto ret;
+
+ /* Return code shouldn't be checked.
+ The reset CLK is needed only with tm6000.
+ Driver should work fine even if this fails.
+ */
+ if (priv->ctrl.msleep)
+ msleep(priv->ctrl.msleep);
+ do_tuner_callback(fe, XC2028_RESET_CLK, 1);
+
+ msleep(10);
+
+ buf[0] = 0xff & (div >> 24);
+ buf[1] = 0xff & (div >> 16);
+ buf[2] = 0xff & (div >> 8);
+ buf[3] = 0xff & (div);
+
+ rc = i2c_send(priv, buf, sizeof(buf));
+ if (rc < 0)
+ goto ret;
+ msleep(100);
+
+ priv->frequency = freq;
+
+ tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf,
+ freq / 1000000, (freq % 1000000) / 1000);
+
+ rc = 0;
+
+ret:
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
+ struct analog_parameters *p)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ unsigned int type=0;
+
+ tuner_dbg("%s called\n", __func__);
+
+ if (p->mode == V4L2_TUNER_RADIO) {
+ type |= FM;
+ if (priv->ctrl.input1)
+ type |= INPUT1;
+ return generic_set_freq(fe, (625l * p->frequency) / 10,
+ V4L2_TUNER_RADIO, type, 0, 0);
+ }
+
+ /* if std is not defined, choose one */
+ if (!p->std)
+ p->std = V4L2_STD_MN;
+
+ /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
+ if (!(p->std & V4L2_STD_MN))
+ type |= F8MHZ;
+
+ /* Add audio hack to std mask */
+ p->std |= parse_audio_std_option();
+
+ return generic_set_freq(fe, 62500l * p->frequency,
+ V4L2_TUNER_ANALOG_TV, type, p->std, 0);
+}
+
+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;
+ int rc;
+ unsigned int type = 0;
+ u16 demod = 0;
+
+ tuner_dbg("%s called\n", __func__);
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ 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 <= 6000000)
+ type |= QAM;
+
+ switch (priv->ctrl.type) {
+ case XC2028_D2633:
+ type |= D2633;
+ break;
+ case XC2028_D2620:
+ type |= D2620;
+ break;
+ case XC2028_AUTO:
+ default:
+ /* Zarlink seems to need D2633 */
+ if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+ type |= D2633;
+ 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 */
+ if (priv->ctrl.demod) {
+ demod = priv->ctrl.demod;
+
+ /*
+ * Newer firmwares require a 200 kHz offset only for ATSC
+ */
+ if (type == ATSC || priv->firm_version < 0x0302)
+ demod += 200;
+ /*
+ * The DTV7 S-code table needs a 700 kHz shift.
+ *
+ * DTV7 is only used in Australia. Germany or Italy may also
+ * use this firmware after initialization, but a tune to a UHF
+ * channel should then cause DTV78 to be used.
+ *
+ * Unfortunately, on real-field tests, the s-code offset
+ * didn't work as expected, as reported by
+ * Robert Lowery <rglowery@exemail.com.au>
+ */
+ }
+
+ return generic_set_freq(fe, c->frequency,
+ V4L2_TUNER_DIGITAL_TV, type, 0, demod);
+}
+
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int rc;
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ /* Avoid firmware reload on slow devices or if PM disabled */
+ if (no_poweroff || priv->ctrl.disable_power_mgmt)
+ return 0;
+
+ tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+ if (debug > 1) {
+ tuner_dbg("Printing sleep stack trace:\n");
+ dump_stack();
+ }
+
+ mutex_lock(&priv->lock);
+
+ if (priv->firm_version < 0x0202)
+ rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
+ else
+ rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
+
+ priv->state = XC2028_SLEEP;
+
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+static int xc2028_dvb_release(struct dvb_frontend *fe)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+
+ tuner_dbg("%s called\n", __func__);
+
+ mutex_lock(&xc2028_list_mutex);
+
+ /* only perform final cleanup if this is the last instance */
+ if (hybrid_tuner_report_instance_count(priv) == 1) {
+ free_firmware(priv);
+ kfree(priv->ctrl.fname);
+ priv->ctrl.fname = NULL;
+ }
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc2028_list_mutex);
+
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("%s called\n", __func__);
+
+ rc = check_device_status(priv);
+ if (rc < 0)
+ return rc;
+
+ *frequency = priv->frequency;
+
+ return 0;
+}
+
+static void load_firmware_cb(const struct firmware *fw,
+ void *context)
+{
+ struct dvb_frontend *fe = context;
+ struct xc2028_data *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
+ if (!fw) {
+ tuner_err("Could not load firmware %s.\n", priv->fname);
+ priv->state = XC2028_NODEV;
+ return;
+ }
+
+ rc = load_all_firmwares(fe, fw);
+
+ release_firmware(fw);
+
+ if (rc < 0)
+ return;
+ priv->state = XC2028_SLEEP;
+}
+
+static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ struct xc2028_ctrl *p = priv_cfg;
+ int rc = 0;
+
+ tuner_dbg("%s called\n", __func__);
+
+ mutex_lock(&priv->lock);
+
+ /*
+ * Copy the config data.
+ * For the firmware name, keep a local copy of the string,
+ * in order to avoid troubles during device release.
+ */
+ if (priv->ctrl.fname)
+ kfree(priv->ctrl.fname);
+ memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
+ if (p->fname) {
+ priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
+ if (priv->ctrl.fname == NULL)
+ rc = -ENOMEM;
+ }
+
+ /*
+ * If firmware name changed, frees firmware. As free_firmware will
+ * reset the status to NO_FIRMWARE, this forces a new request_firmware
+ */
+ if (!firmware_name[0] && p->fname &&
+ priv->fname && strcmp(p->fname, priv->fname))
+ free_firmware(priv);
+
+ if (priv->ctrl.max_len < 9)
+ priv->ctrl.max_len = 13;
+
+ if (priv->state == XC2028_NO_FIRMWARE) {
+ if (!firmware_name[0])
+ priv->fname = priv->ctrl.fname;
+ else
+ priv->fname = firmware_name;
+
+ rc = request_firmware_nowait(THIS_MODULE, 1,
+ priv->fname,
+ priv->i2c_props.adap->dev.parent,
+ GFP_KERNEL,
+ fe, load_firmware_cb);
+ if (rc < 0) {
+ tuner_err("Failed to request firmware %s\n",
+ priv->fname);
+ priv->state = XC2028_NODEV;
+ } else
+ priv->state = XC2028_WAITING_FIRMWARE;
+ }
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
+ .info = {
+ .name = "Xceive XC3028",
+ .frequency_min = 42000000,
+ .frequency_max = 864000000,
+ .frequency_step = 50000,
+ },
+
+ .set_config = xc2028_set_config,
+ .set_analog_params = xc2028_set_analog_freq,
+ .release = xc2028_dvb_release,
+ .get_frequency = xc2028_get_frequency,
+ .get_rf_strength = xc2028_signal,
+ .get_afc = xc2028_get_afc,
+ .set_params = xc2028_set_params,
+ .sleep = xc2028_sleep,
+};
+
+struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+ struct xc2028_config *cfg)
+{
+ struct xc2028_data *priv;
+ int instance;
+
+ if (debug)
+ printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
+
+ if (NULL == cfg)
+ return NULL;
+
+ if (!fe) {
+ printk(KERN_ERR "xc2028: No frontend!\n");
+ return NULL;
+ }
+
+ mutex_lock(&xc2028_list_mutex);
+
+ instance = hybrid_tuner_request_state(struct xc2028_data, priv,
+ hybrid_tuner_instance_list,
+ cfg->i2c_adap, cfg->i2c_addr,
+ "xc2028");
+ switch (instance) {
+ case 0:
+ /* memory allocation failure */
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->ctrl.max_len = 13;
+
+ mutex_init(&priv->lock);
+
+ fe->tuner_priv = priv;
+ break;
+ case 2:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
+
+ memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
+ sizeof(xc2028_dvb_tuner_ops));
+
+ tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
+
+ if (cfg->ctrl)
+ xc2028_set_config(fe, cfg->ctrl);
+
+ mutex_unlock(&xc2028_list_mutex);
+
+ return fe;
+fail:
+ mutex_unlock(&xc2028_list_mutex);
+
+ xc2028_dvb_release(fe);
+ return NULL;
+}
+
+EXPORT_SYMBOL(xc2028_attach);
+
+MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
+MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
+MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h
index 9ebfb2d0ff14..9ebfb2d0ff14 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/tuners/tuner-xc2028.h
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
new file mode 100644
index 000000000000..4937712278f6
--- /dev/null
+++ b/drivers/media/tuners/xc4000.c
@@ -0,0 +1,1757 @@
+/*
+ * Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2007 Xceive Corporation
+ * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
+ * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/unaligned.h>
+
+#include "dvb_frontend.h"
+
+#include "xc4000.h"
+#include "tuner-i2c.h"
+#include "tuner-xc2028-types.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
+ "0 (default): use device-specific default mode).");
+
+static int audio_std;
+module_param(audio_std, int, 0644);
+MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
+ "needs to know what audio standard is needed for some video standards "
+ "with audio A2 or NICAM. The valid settings are a sum of:\n"
+ " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
+ " 2: use A2 instead of NICAM or BTSC\n"
+ " 4: use SECAM/K3 instead of K1\n"
+ " 8: use PAL-D/K audio for SECAM-D/K\n"
+ "16: use FM radio input 1 instead of input 2\n"
+ "32: use mono audio (the lower three bits are ignored)");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+ "default firmware name.");
+
+static DEFINE_MUTEX(xc4000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
+
+/* struct for storing firmware table */
+struct firmware_description {
+ unsigned int type;
+ v4l2_std_id id;
+ __u16 int_freq;
+ unsigned char *ptr;
+ unsigned int size;
+};
+
+struct firmware_properties {
+ unsigned int type;
+ v4l2_std_id id;
+ v4l2_std_id std_req;
+ __u16 int_freq;
+ unsigned int scode_table;
+ int scode_nr;
+};
+
+struct xc4000_priv {
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+ struct firmware_description *firm;
+ int firm_size;
+ u32 if_khz;
+ u32 freq_hz;
+ u32 bandwidth;
+ u8 video_standard;
+ u8 rf_mode;
+ u8 default_pm;
+ u8 dvb_amplitude;
+ u8 set_smoothedcvbs;
+ u8 ignore_i2c_write_errors;
+ __u16 firm_version;
+ struct firmware_properties cur_fw;
+ __u16 hwmodel;
+ __u16 hwvers;
+ struct mutex lock;
+};
+
+#define XC4000_AUDIO_STD_B 1
+#define XC4000_AUDIO_STD_A2 2
+#define XC4000_AUDIO_STD_K3 4
+#define XC4000_AUDIO_STD_L 8
+#define XC4000_AUDIO_STD_INPUT1 16
+#define XC4000_AUDIO_STD_MONO 32
+
+#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
+
+/* Misc Defines */
+#define MAX_TV_STANDARD 24
+#define XC_MAX_I2C_WRITE_LENGTH 64
+#define XC_POWERED_DOWN 0x80000000U
+
+/* Signal Types */
+#define XC_RF_MODE_AIR 0
+#define XC_RF_MODE_CABLE 1
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
+#define XC_PRODUCT_ID_XC4000 0x0FA0
+#define XC_PRODUCT_ID_XC4100 0x1004
+
+/* Registers (Write-only) */
+#define XREG_INIT 0x00
+#define XREG_VIDEO_MODE 0x01
+#define XREG_AUDIO_MODE 0x02
+#define XREG_RF_FREQ 0x03
+#define XREG_D_CODE 0x04
+#define XREG_DIRECTSITTING_MODE 0x05
+#define XREG_SEEK_MODE 0x06
+#define XREG_POWER_DOWN 0x08
+#define XREG_SIGNALSOURCE 0x0A
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_AMPLITUDE 0x10
+
+/* Registers (Read-only) */
+#define XREG_ADC_ENV 0x00
+#define XREG_QUALITY 0x01
+#define XREG_FRAME_LINES 0x02
+#define XREG_HSYNC_FREQ 0x03
+#define XREG_LOCK 0x04
+#define XREG_FREQ_ERROR 0x05
+#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
+ the driver for documentation purposes.
+
+ This represents an I2C firmware file encoded as a
+ string of unsigned char. Format is as follows:
+
+ char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB
+ char[1 ]=len0_LSB -> length of first write transaction
+ char[2 ]=data0 -> first byte to be sent
+ char[3 ]=data1
+ char[4 ]=data2
+ char[ ]=...
+ char[M ]=dataN -> last byte to be sent
+ char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB
+ char[M+2]=len1_LSB -> length of second write transaction
+ char[M+3]=data0
+ char[M+4]=data1
+ ...
+ etc.
+
+ The [len] value should be interpreted as follows:
+
+ len= len_MSB _ len_LSB
+ len=1111_1111_1111_1111 : End of I2C_SEQUENCE
+ len=0000_0000_0000_0000 : Reset command: Do hardware reset
+ len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767)
+ len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms
+
+ For the RESET and WAIT commands, the two following bytes will contain
+ immediately the length of the following transaction.
+*/
+
+struct XC_TV_STANDARD {
+ const char *Name;
+ u16 audio_mode;
+ u16 video_mode;
+ u16 int_freq;
+};
+
+/* Tuner standards */
+#define XC4000_MN_NTSC_PAL_BTSC 0
+#define XC4000_MN_NTSC_PAL_A2 1
+#define XC4000_MN_NTSC_PAL_EIAJ 2
+#define XC4000_MN_NTSC_PAL_Mono 3
+#define XC4000_BG_PAL_A2 4
+#define XC4000_BG_PAL_NICAM 5
+#define XC4000_BG_PAL_MONO 6
+#define XC4000_I_PAL_NICAM 7
+#define XC4000_I_PAL_NICAM_MONO 8
+#define XC4000_DK_PAL_A2 9
+#define XC4000_DK_PAL_NICAM 10
+#define XC4000_DK_PAL_MONO 11
+#define XC4000_DK_SECAM_A2DK1 12
+#define XC4000_DK_SECAM_A2LDK3 13
+#define XC4000_DK_SECAM_A2MONO 14
+#define XC4000_DK_SECAM_NICAM 15
+#define XC4000_L_SECAM_NICAM 16
+#define XC4000_LC_SECAM_NICAM 17
+#define XC4000_DTV6 18
+#define XC4000_DTV8 19
+#define XC4000_DTV7_8 20
+#define XC4000_DTV7 21
+#define XC4000_FM_Radio_INPUT2 22
+#define XC4000_FM_Radio_INPUT1 23
+
+static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
+ {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500},
+ {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600},
+ {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500},
+ {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500},
+ {"B/G-PAL-A2", 0x0000, 0x8159, 5640},
+ {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740},
+ {"B/G-PAL-MONO", 0x0078, 0x8159, 5500},
+ {"I-PAL-NICAM", 0x0080, 0x8049, 6240},
+ {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000},
+ {"D/K-PAL-A2", 0x0000, 0x8049, 6380},
+ {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200},
+ {"D/K-PAL-MONO", 0x0078, 0x8049, 6500},
+ {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340},
+ {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000},
+ {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500},
+ {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200},
+ {"L-SECAM-NICAM", 0x8080, 0x0009, 6200},
+ {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200},
+ {"DTV6", 0x00C0, 0x8002, 0},
+ {"DTV8", 0x00C0, 0x800B, 0},
+ {"DTV7/8", 0x00C0, 0x801B, 0},
+ {"DTV7", 0x00C0, 0x8007, 0},
+ {"FM Radio-INPUT2", 0x0008, 0x9800, 10700},
+ {"FM Radio-INPUT1", 0x0008, 0x9000, 10700}
+};
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
+static int xc4000_tuner_reset(struct dvb_frontend *fe);
+static void xc_debug_dump(struct xc4000_priv *priv);
+
+static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
+{
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = buf, .len = len };
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ if (priv->ignore_i2c_write_errors == 0) {
+ printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
+ len);
+ if (len == 4) {
+ printk(KERN_ERR "bytes %*ph\n", 4, buf);
+ }
+ return -EREMOTEIO;
+ }
+ }
+ return 0;
+}
+
+static int xc4000_tuner_reset(struct dvb_frontend *fe)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (fe->callback) {
+ ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv :
+ priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER,
+ XC4000_TUNER_RESET, 0);
+ if (ret) {
+ printk(KERN_ERR "xc4000: reset failed\n");
+ return -EREMOTEIO;
+ }
+ } else {
+ printk(KERN_ERR "xc4000: no tuner reset callback function, "
+ "fatal\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
+{
+ u8 buf[4];
+ int result;
+
+ buf[0] = (regAddr >> 8) & 0xFF;
+ buf[1] = regAddr & 0xFF;
+ buf[2] = (i2cData >> 8) & 0xFF;
+ buf[3] = i2cData & 0xFF;
+ result = xc_send_i2c_data(priv, buf, 4);
+
+ return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+
+ int i, nbytes_to_send, result;
+ unsigned int len, pos, index;
+ u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+ index = 0;
+ while ((i2c_sequence[index] != 0xFF) ||
+ (i2c_sequence[index + 1] != 0xFF)) {
+ len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+ if (len == 0x0000) {
+ /* RESET command */
+ /* NOTE: this is ignored, as the reset callback was */
+ /* already called by check_firmware() */
+ index += 2;
+ } else if (len & 0x8000) {
+ /* WAIT command */
+ msleep(len & 0x7FFF);
+ index += 2;
+ } else {
+ /* Send i2c data whilst ensuring individual transactions
+ * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+ */
+ index += 2;
+ buf[0] = i2c_sequence[index];
+ buf[1] = i2c_sequence[index + 1];
+ pos = 2;
+ while (pos < len) {
+ if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+ nbytes_to_send =
+ XC_MAX_I2C_WRITE_LENGTH;
+ else
+ nbytes_to_send = (len - pos + 2);
+ for (i = 2; i < nbytes_to_send; i++) {
+ buf[i] = i2c_sequence[index + pos +
+ i - 2];
+ }
+ result = xc_send_i2c_data(priv, buf,
+ nbytes_to_send);
+
+ if (result != 0)
+ return result;
+
+ pos += nbytes_to_send - 2;
+ }
+ index += len;
+ }
+ }
+ return 0;
+}
+
+static int xc_set_tv_standard(struct xc4000_priv *priv,
+ u16 video_mode, u16 audio_mode)
+{
+ int ret;
+ dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
+ dprintk(1, "%s() Standard = %s\n",
+ __func__,
+ xc4000_standard[priv->video_standard].Name);
+
+ /* Don't complain when the request fails because of i2c stretching */
+ priv->ignore_i2c_write_errors = 1;
+
+ ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
+ if (ret == 0)
+ ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
+
+ priv->ignore_i2c_write_errors = 0;
+
+ return ret;
+}
+
+static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
+{
+ dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+ rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+ if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+ rf_mode = XC_RF_MODE_CABLE;
+ printk(KERN_ERR
+ "%s(), Invalid mode, defaulting to CABLE",
+ __func__);
+ }
+ return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops;
+
+static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
+{
+ u16 freq_code;
+
+ dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+ if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
+ (freq_hz < xc4000_tuner_ops.info.frequency_min))
+ return -EINVAL;
+
+ freq_code = (u16)(freq_hz / 15625);
+
+ /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
+ FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+ only be used for fast scanning for channel lock) */
+ /* WAS: XREG_FINERFREQ */
+ return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
+{
+ return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
+{
+ int result;
+ u16 regData;
+ u32 tmp;
+
+ result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
+ if (result != 0)
+ return result;
+
+ tmp = (u32)regData & 0xFFFFU;
+ tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
+ (*freq_error_hz) = tmp * 15625;
+ return result;
+}
+
+static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
+{
+ return xc4000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc4000_priv *priv,
+ u8 *hw_majorversion, u8 *hw_minorversion,
+ u8 *fw_majorversion, u8 *fw_minorversion)
+{
+ u16 data;
+ int result;
+
+ result = xc4000_readreg(priv, XREG_VERSION, &data);
+ if (result != 0)
+ return result;
+
+ (*hw_majorversion) = (data >> 12) & 0x0F;
+ (*hw_minorversion) = (data >> 8) & 0x0F;
+ (*fw_majorversion) = (data >> 4) & 0x0F;
+ (*fw_minorversion) = data & 0x0F;
+
+ return 0;
+}
+
+static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
+{
+ u16 regData;
+ int result;
+
+ result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+ if (result != 0)
+ return result;
+
+ (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+ return result;
+}
+
+static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
+{
+ return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+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;
+ int watchdog_count = 40;
+
+ while ((lock_state == 0) && (watchdog_count > 0)) {
+ xc_get_lock_status(priv, &lock_state);
+ if (lock_state != 1) {
+ msleep(5);
+ watchdog_count--;
+ }
+ }
+ return lock_state;
+}
+
+static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
+{
+ int found = 1;
+ int result;
+
+ dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+ /* Don't complain when the request fails because of i2c stretching */
+ priv->ignore_i2c_write_errors = 1;
+ result = xc_set_rf_frequency(priv, freq_hz);
+ priv->ignore_i2c_write_errors = 0;
+
+ if (result != 0)
+ return 0;
+
+ /* wait for lock only in analog TV mode */
+ if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
+ if (xc_wait_for_lock(priv) != 1)
+ found = 0;
+ }
+
+ /* Wait for stats to stabilize.
+ * Frame Lines needs two frame times after initial lock
+ * before it is valid.
+ */
+ msleep(debug ? 100 : 10);
+
+ if (debug)
+ xc_debug_dump(priv);
+
+ return found;
+}
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
+{
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ u8 bval[2] = { 0, 0 };
+ struct i2c_msg msg[2] = {
+ { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = &buf[0], .len = 2 },
+ { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+ };
+
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+ printk(KERN_ERR "xc4000: I2C read failed\n");
+ return -EREMOTEIO;
+ }
+
+ *val = (bval[0] << 8) | bval[1];
+ return 0;
+}
+
+#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+ if (type & BASE)
+ printk(KERN_CONT "BASE ");
+ if (type & INIT1)
+ printk(KERN_CONT "INIT1 ");
+ if (type & F8MHZ)
+ printk(KERN_CONT "F8MHZ ");
+ if (type & MTS)
+ printk(KERN_CONT "MTS ");
+ if (type & D2620)
+ printk(KERN_CONT "D2620 ");
+ if (type & D2633)
+ printk(KERN_CONT "D2633 ");
+ if (type & DTV6)
+ printk(KERN_CONT "DTV6 ");
+ if (type & QAM)
+ printk(KERN_CONT "QAM ");
+ if (type & DTV7)
+ printk(KERN_CONT "DTV7 ");
+ if (type & DTV78)
+ printk(KERN_CONT "DTV78 ");
+ if (type & DTV8)
+ printk(KERN_CONT "DTV8 ");
+ if (type & FM)
+ printk(KERN_CONT "FM ");
+ if (type & INPUT1)
+ printk(KERN_CONT "INPUT1 ");
+ if (type & LCD)
+ printk(KERN_CONT "LCD ");
+ if (type & NOGD)
+ printk(KERN_CONT "NOGD ");
+ if (type & MONO)
+ printk(KERN_CONT "MONO ");
+ if (type & ATSC)
+ printk(KERN_CONT "ATSC ");
+ if (type & IF)
+ printk(KERN_CONT "IF ");
+ if (type & LG60)
+ printk(KERN_CONT "LG60 ");
+ if (type & ATI638)
+ printk(KERN_CONT "ATI638 ");
+ if (type & OREN538)
+ printk(KERN_CONT "OREN538 ");
+ if (type & OREN36)
+ printk(KERN_CONT "OREN36 ");
+ if (type & TOYOTA388)
+ printk(KERN_CONT "TOYOTA388 ");
+ if (type & TOYOTA794)
+ printk(KERN_CONT "TOYOTA794 ");
+ if (type & DIBCOM52)
+ printk(KERN_CONT "DIBCOM52 ");
+ if (type & ZARLINK456)
+ printk(KERN_CONT "ZARLINK456 ");
+ if (type & CHINA)
+ printk(KERN_CONT "CHINA ");
+ if (type & F6MHZ)
+ printk(KERN_CONT "F6MHZ ");
+ if (type & INPUT2)
+ printk(KERN_CONT "INPUT2 ");
+ if (type & SCODE)
+ printk(KERN_CONT "SCODE ");
+ if (type & HAS_IF)
+ printk(KERN_CONT "HAS_IF_%d ", int_freq);
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ int i, best_i = -1;
+ unsigned int best_nr_diffs = 255U;
+
+ if (!priv->firm) {
+ printk(KERN_ERR "Error! firmware not loaded\n");
+ return -EINVAL;
+ }
+
+ if (((type & ~SCODE) == 0) && (*id == 0))
+ *id = V4L2_STD_PAL;
+
+ /* Seek for generic video standard match */
+ for (i = 0; i < priv->firm_size; i++) {
+ v4l2_std_id id_diff_mask =
+ (priv->firm[i].id ^ (*id)) & (*id);
+ unsigned int type_diff_mask =
+ (priv->firm[i].type ^ type)
+ & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
+ unsigned int nr_diffs;
+
+ if (type_diff_mask
+ & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
+ continue;
+
+ nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
+ if (!nr_diffs) /* Supports all the requested standards */
+ goto found;
+
+ if (nr_diffs < best_nr_diffs) {
+ best_nr_diffs = nr_diffs;
+ best_i = i;
+ }
+ }
+
+ /* FIXME: Would make sense to seek for type "hint" match ? */
+ if (best_i < 0) {
+ i = -ENOENT;
+ goto ret;
+ }
+
+ if (best_nr_diffs > 0U) {
+ printk(KERN_WARNING
+ "Selecting best matching firmware (%u bits differ) for "
+ "type=(%x), id %016llx:\n",
+ best_nr_diffs, type, (unsigned long long)*id);
+ i = best_i;
+ }
+
+found:
+ *id = priv->firm[i].id;
+
+ret:
+ if (debug) {
+ printk(KERN_DEBUG "%s firmware for type=",
+ (i < 0) ? "Can't find" : "Found");
+ dump_firm_type(type);
+ printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
+ }
+ return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ int pos, rc;
+ unsigned char *p;
+
+ pos = seek_firmware(fe, type, id);
+ if (pos < 0)
+ return pos;
+
+ p = priv->firm[pos].ptr;
+
+ /* Don't complain when the request fails because of i2c stretching */
+ priv->ignore_i2c_write_errors = 1;
+
+ rc = xc_load_i2c_sequence(fe, p);
+
+ priv->ignore_i2c_write_errors = 0;
+
+ return rc;
+}
+
+static int xc4000_fwupload(struct dvb_frontend *fe)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ const struct firmware *fw = NULL;
+ const unsigned char *p, *endp;
+ int rc = 0;
+ int n, n_array;
+ char name[33];
+ const char *fname;
+
+ if (firmware_name[0] != '\0')
+ fname = firmware_name;
+ else
+ fname = XC4000_DEFAULT_FIRMWARE;
+
+ dprintk(1, "Reading firmware %s\n", fname);
+ rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
+ if (rc < 0) {
+ if (rc == -ENOENT)
+ printk(KERN_ERR "Error: firmware %s not found.\n", fname);
+ else
+ printk(KERN_ERR "Error %d while requesting firmware %s\n",
+ rc, fname);
+
+ return rc;
+ }
+ p = fw->data;
+ endp = p + fw->size;
+
+ if (fw->size < sizeof(name) - 1 + 2 + 2) {
+ printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
+ fname);
+ goto corrupt;
+ }
+
+ memcpy(name, p, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ p += sizeof(name) - 1;
+
+ priv->firm_version = get_unaligned_le16(p);
+ p += 2;
+
+ n_array = get_unaligned_le16(p);
+ p += 2;
+
+ dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+ n_array, fname, name,
+ priv->firm_version >> 8, priv->firm_version & 0xff);
+
+ 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;
+ goto done;
+ }
+ priv->firm_size = n_array;
+
+ n = -1;
+ while (p < endp) {
+ __u32 type, size;
+ v4l2_std_id id;
+ __u16 int_freq = 0;
+
+ n++;
+ if (n >= n_array) {
+ printk(KERN_ERR "More firmware images in file than "
+ "were expected!\n");
+ goto corrupt;
+ }
+
+ /* Checks if there's enough bytes to read */
+ if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+ goto header;
+
+ type = get_unaligned_le32(p);
+ p += sizeof(type);
+
+ id = get_unaligned_le64(p);
+ p += sizeof(id);
+
+ if (type & HAS_IF) {
+ int_freq = get_unaligned_le16(p);
+ p += sizeof(int_freq);
+ if (endp - p < sizeof(size))
+ goto header;
+ }
+
+ size = get_unaligned_le32(p);
+ p += sizeof(size);
+
+ if (!size || size > endp - p) {
+ printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
+ type, (unsigned long long)id,
+ (unsigned)(endp - p), size);
+ goto corrupt;
+ }
+
+ priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+ if (priv->firm[n].ptr == NULL) {
+ printk(KERN_ERR "Not enough memory to load firmware file.\n");
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (debug) {
+ printk(KERN_DEBUG "Reading firmware type ");
+ dump_firm_type_and_int_freq(type, int_freq);
+ printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
+ type, (unsigned long long)id, size);
+ }
+
+ memcpy(priv->firm[n].ptr, p, size);
+ priv->firm[n].type = type;
+ priv->firm[n].id = id;
+ priv->firm[n].size = size;
+ priv->firm[n].int_freq = int_freq;
+
+ p += size;
+ }
+
+ if (n + 1 != priv->firm_size) {
+ printk(KERN_ERR "Firmware file is incomplete!\n");
+ goto corrupt;
+ }
+
+ goto done;
+
+header:
+ printk(KERN_ERR "Firmware header is incomplete!\n");
+corrupt:
+ rc = -EINVAL;
+ printk(KERN_ERR "Error: firmware file is corrupted!\n");
+
+done:
+ release_firmware(fw);
+ if (rc == 0)
+ dprintk(1, "Firmware files loaded.\n");
+
+ return rc;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id *id, __u16 int_freq, int scode)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ int pos, rc;
+ unsigned char *p;
+ u8 scode_buf[13];
+ u8 indirect_mode[5];
+
+ dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
+
+ if (!int_freq) {
+ pos = seek_firmware(fe, type, id);
+ if (pos < 0)
+ return pos;
+ } else {
+ for (pos = 0; pos < priv->firm_size; pos++) {
+ if ((priv->firm[pos].int_freq == int_freq) &&
+ (priv->firm[pos].type & HAS_IF))
+ break;
+ }
+ if (pos == priv->firm_size)
+ return -ENOENT;
+ }
+
+ p = priv->firm[pos].ptr;
+
+ if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+ return -EINVAL;
+ p += 12 * scode;
+
+ if (debug) {
+ tuner_info("Loading SCODE for type=");
+ dump_firm_type_and_int_freq(priv->firm[pos].type,
+ priv->firm[pos].int_freq);
+ printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
+ (unsigned long long)*id);
+ }
+
+ scode_buf[0] = 0x00;
+ memcpy(&scode_buf[1], p, 12);
+
+ /* Enter direct-mode */
+ rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
+ if (rc < 0) {
+ printk(KERN_ERR "failed to put device into direct mode!\n");
+ return -EIO;
+ }
+
+ rc = xc_send_i2c_data(priv, scode_buf, 13);
+ if (rc != 0) {
+ /* Even if the send failed, make sure we set back to indirect
+ mode */
+ printk(KERN_ERR "Failed to set scode %d\n", rc);
+ }
+
+ /* Switch back to indirect-mode */
+ memset(indirect_mode, 0, sizeof(indirect_mode));
+ indirect_mode[4] = 0x88;
+ xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
+ msleep(10);
+
+ return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id std, __u16 int_freq)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ struct firmware_properties new_fw;
+ int rc = 0, is_retry = 0;
+ u16 hwmodel;
+ v4l2_std_id std0;
+ u8 hw_major, hw_minor, fw_major, fw_minor;
+
+ dprintk(1, "%s called\n", __func__);
+
+ if (!priv->firm) {
+ rc = xc4000_fwupload(fe);
+ if (rc < 0)
+ return rc;
+ }
+
+retry:
+ new_fw.type = type;
+ new_fw.id = std;
+ new_fw.std_req = std;
+ new_fw.scode_table = SCODE;
+ new_fw.scode_nr = 0;
+ new_fw.int_freq = int_freq;
+
+ dprintk(1, "checking firmware, user requested type=");
+ if (debug) {
+ dump_firm_type(new_fw.type);
+ printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
+ (unsigned long long)new_fw.std_req);
+ if (!int_freq)
+ printk(KERN_CONT "scode_tbl ");
+ else
+ printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
+ printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
+ }
+
+ /* No need to reload base firmware if it matches */
+ if (priv->cur_fw.type & BASE) {
+ dprintk(1, "BASE firmware not changed.\n");
+ goto skip_base;
+ }
+
+ /* Updating BASE - forget about all currently loaded firmware */
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+ /* Reset is needed before loading firmware */
+ rc = xc4000_tuner_reset(fe);
+ if (rc < 0)
+ goto fail;
+
+ /* BASE firmwares are all std0 */
+ std0 = 0;
+ rc = load_firmware(fe, BASE, &std0);
+ if (rc < 0) {
+ printk(KERN_ERR "Error %d while loading base firmware\n", rc);
+ goto fail;
+ }
+
+ /* Load INIT1, if needed */
+ dprintk(1, "Load init1 firmware, if exists\n");
+
+ rc = load_firmware(fe, BASE | INIT1, &std0);
+ if (rc == -ENOENT)
+ rc = load_firmware(fe, BASE | INIT1, &std0);
+ if (rc < 0 && rc != -ENOENT) {
+ tuner_err("Error %d while loading init1 firmware\n",
+ rc);
+ goto fail;
+ }
+
+skip_base:
+ /*
+ * No need to reload standard specific firmware if base firmware
+ * was not reloaded and requested video standards have not changed.
+ */
+ if (priv->cur_fw.type == (BASE | new_fw.type) &&
+ priv->cur_fw.std_req == std) {
+ dprintk(1, "Std-specific firmware already loaded.\n");
+ goto skip_std_specific;
+ }
+
+ /* Reloading std-specific firmware forces a SCODE update */
+ priv->cur_fw.scode_table = 0;
+
+ /* Load the standard firmware */
+ rc = load_firmware(fe, new_fw.type, &new_fw.id);
+
+ if (rc < 0)
+ goto fail;
+
+skip_std_specific:
+ if (priv->cur_fw.scode_table == new_fw.scode_table &&
+ priv->cur_fw.scode_nr == new_fw.scode_nr) {
+ dprintk(1, "SCODE firmware already loaded.\n");
+ goto check_device;
+ }
+
+ /* Load SCODE firmware, if exists */
+ rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+ new_fw.int_freq, new_fw.scode_nr);
+ if (rc != 0)
+ dprintk(1, "load scode failed %d\n", rc);
+
+check_device:
+ rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
+
+ if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
+ &fw_minor) != 0) {
+ printk(KERN_ERR "Unable to read tuner registers.\n");
+ goto fail;
+ }
+
+ dprintk(1, "Device is Xceive %d version %d.%d, "
+ "firmware version %d.%d\n",
+ hwmodel, hw_major, hw_minor, fw_major, fw_minor);
+
+ /* Check firmware version against what we downloaded. */
+ if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
+ printk(KERN_WARNING
+ "Incorrect readback of firmware version %d.%d.\n",
+ fw_major, fw_minor);
+ goto fail;
+ }
+
+ /* Check that the tuner hardware model remains consistent over time. */
+ if (priv->hwmodel == 0 &&
+ (hwmodel == XC_PRODUCT_ID_XC4000 ||
+ hwmodel == XC_PRODUCT_ID_XC4100)) {
+ priv->hwmodel = hwmodel;
+ priv->hwvers = (hw_major << 8) | hw_minor;
+ } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+ priv->hwvers != ((hw_major << 8) | hw_minor)) {
+ printk(KERN_WARNING
+ "Read invalid device hardware information - tuner "
+ "hung?\n");
+ goto fail;
+ }
+
+ memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+ /*
+ * By setting BASE in cur_fw.type only after successfully loading all
+ * firmwares, we can:
+ * 1. Identify that BASE firmware with type=0 has been loaded;
+ * 2. Tell whether BASE firmware was just changed the next time through.
+ */
+ priv->cur_fw.type |= BASE;
+
+ return 0;
+
+fail:
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+ if (!is_retry) {
+ msleep(50);
+ is_retry = 1;
+ dprintk(1, "Retrying firmware load\n");
+ goto retry;
+ }
+
+ if (rc == -ENOENT)
+ rc = -EINVAL;
+ return rc;
+}
+
+static void xc_debug_dump(struct xc4000_priv *priv)
+{
+ u16 adc_envelope;
+ u32 freq_error_hz = 0;
+ u16 lock_status;
+ 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;
+
+ xc_get_adc_envelope(priv, &adc_envelope);
+ dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+ xc_get_frequency_error(priv, &freq_error_hz);
+ dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+ xc_get_lock_status(priv, &lock_status);
+ dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+ lock_status);
+
+ xc_get_version(priv, &hw_majorversion, &hw_minorversion,
+ &fw_majorversion, &fw_minorversion);
+ dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+ hw_majorversion, hw_minorversion,
+ fw_majorversion, fw_minorversion);
+
+ if (priv->video_standard < XC4000_DTV6) {
+ xc_get_hsync_freq(priv, &hsync_freq_hz);
+ dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
+ hsync_freq_hz);
+
+ xc_get_frame_lines(priv, &frame_lines);
+ dprintk(1, "*** Frame lines = %d\n", frame_lines);
+ }
+
+ 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 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__, c->frequency);
+
+ mutex_lock(&priv->lock);
+
+ 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__);
+ 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 = c->frequency - 1750000;
+ type = DTV6;
+ } else if (bw <= 7000000) {
+ priv->video_standard = XC4000_DTV7;
+ priv->freq_hz = c->frequency - 2250000;
+ type = DTV7;
+ } else {
+ priv->video_standard = XC4000_DTV8;
+ priv->freq_hz = c->frequency - 2750000;
+ type = DTV8;
+ }
+ priv->rf_mode = XC_RF_MODE_AIR;
+ break;
+ default:
+ printk(KERN_ERR "xc4000 delivery system not supported!\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ dprintk(1, "%s() frequency=%d (compensated)\n",
+ __func__, priv->freq_hz);
+
+ /* Make sure the correct firmware type is loaded */
+ 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",
+ priv->rf_mode);
+ goto fail;
+ } else {
+ u16 video_mode, audio_mode;
+ video_mode = xc4000_standard[priv->video_standard].video_mode;
+ audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+ if (type == DTV6 && priv->firm_version != 0x0102)
+ video_mode |= 0x0001;
+ ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+ if (ret != 0) {
+ printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+ /* DJH - do not return when it fails... */
+ /* goto fail; */
+ }
+ }
+
+ if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+ ret = 0;
+ if (priv->dvb_amplitude != 0) {
+ if (xc_write_reg(priv, XREG_AMPLITUDE,
+ (priv->firm_version != 0x0102 ||
+ priv->dvb_amplitude != 134 ?
+ priv->dvb_amplitude : 132)) != 0)
+ ret = -EREMOTEIO;
+ }
+ if (priv->set_smoothedcvbs != 0) {
+ if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+ ret = -EREMOTEIO;
+ }
+ if (ret != 0) {
+ printk(KERN_ERR "xc4000: setting registers failed\n");
+ /* goto fail; */
+ }
+
+ xc_tune_channel(priv, priv->freq_hz);
+
+ ret = 0;
+
+fail:
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static int xc4000_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ unsigned int type = 0;
+ int ret = -EREMOTEIO;
+
+ if (params->mode == V4L2_TUNER_RADIO) {
+ dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
+ __func__, params->frequency);
+
+ mutex_lock(&priv->lock);
+
+ params->std = 0;
+ priv->freq_hz = params->frequency * 125L / 2;
+
+ if (audio_std & XC4000_AUDIO_STD_INPUT1) {
+ priv->video_standard = XC4000_FM_Radio_INPUT1;
+ type = FM | INPUT1;
+ } else {
+ priv->video_standard = XC4000_FM_Radio_INPUT2;
+ type = FM | INPUT2;
+ }
+
+ goto tune_channel;
+ }
+
+ dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+ __func__, params->frequency);
+
+ mutex_lock(&priv->lock);
+
+ /* params->frequency is in units of 62.5khz */
+ priv->freq_hz = params->frequency * 62500;
+
+ params->std &= V4L2_STD_ALL;
+ /* if std is not defined, choose one */
+ if (!params->std)
+ params->std = V4L2_STD_PAL_BG;
+
+ if (audio_std & XC4000_AUDIO_STD_MONO)
+ type = MONO;
+
+ if (params->std & V4L2_STD_MN) {
+ params->std = V4L2_STD_MN;
+ if (audio_std & XC4000_AUDIO_STD_MONO) {
+ priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
+ } else if (audio_std & XC4000_AUDIO_STD_A2) {
+ params->std |= V4L2_STD_A2;
+ priv->video_standard = XC4000_MN_NTSC_PAL_A2;
+ } else {
+ params->std |= V4L2_STD_BTSC;
+ priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
+ }
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_BG) {
+ params->std = V4L2_STD_PAL_BG;
+ if (audio_std & XC4000_AUDIO_STD_MONO) {
+ priv->video_standard = XC4000_BG_PAL_MONO;
+ } else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
+ if (!(audio_std & XC4000_AUDIO_STD_B)) {
+ params->std |= V4L2_STD_NICAM_A;
+ priv->video_standard = XC4000_BG_PAL_NICAM;
+ } else {
+ params->std |= V4L2_STD_NICAM_B;
+ priv->video_standard = XC4000_BG_PAL_NICAM;
+ }
+ } else {
+ if (!(audio_std & XC4000_AUDIO_STD_B)) {
+ params->std |= V4L2_STD_A2_A;
+ priv->video_standard = XC4000_BG_PAL_A2;
+ } else {
+ params->std |= V4L2_STD_A2_B;
+ priv->video_standard = XC4000_BG_PAL_A2;
+ }
+ }
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_I) {
+ /* default to NICAM audio standard */
+ params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
+ if (audio_std & XC4000_AUDIO_STD_MONO)
+ priv->video_standard = XC4000_I_PAL_NICAM_MONO;
+ else
+ priv->video_standard = XC4000_I_PAL_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_DK) {
+ params->std = V4L2_STD_PAL_DK;
+ if (audio_std & XC4000_AUDIO_STD_MONO) {
+ priv->video_standard = XC4000_DK_PAL_MONO;
+ } else if (audio_std & XC4000_AUDIO_STD_A2) {
+ params->std |= V4L2_STD_A2;
+ priv->video_standard = XC4000_DK_PAL_A2;
+ } else {
+ params->std |= V4L2_STD_NICAM;
+ priv->video_standard = XC4000_DK_PAL_NICAM;
+ }
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_DK) {
+ /* default to A2 audio standard */
+ params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
+ if (audio_std & XC4000_AUDIO_STD_L) {
+ type = 0;
+ priv->video_standard = XC4000_DK_SECAM_NICAM;
+ } else if (audio_std & XC4000_AUDIO_STD_MONO) {
+ priv->video_standard = XC4000_DK_SECAM_A2MONO;
+ } else if (audio_std & XC4000_AUDIO_STD_K3) {
+ params->std |= V4L2_STD_SECAM_K3;
+ priv->video_standard = XC4000_DK_SECAM_A2LDK3;
+ } else {
+ priv->video_standard = XC4000_DK_SECAM_A2DK1;
+ }
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_L) {
+ /* default to NICAM audio standard */
+ type = 0;
+ params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
+ priv->video_standard = XC4000_L_SECAM_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_LC) {
+ /* default to NICAM audio standard */
+ type = 0;
+ params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
+ priv->video_standard = XC4000_LC_SECAM_NICAM;
+ goto tune_channel;
+ }
+
+tune_channel:
+ /* FIXME: it could be air. */
+ priv->rf_mode = XC_RF_MODE_CABLE;
+
+ if (check_firmware(fe, type, params->std,
+ xc4000_standard[priv->video_standard].int_freq) != 0)
+ goto fail;
+
+ ret = xc_set_signal_source(priv, priv->rf_mode);
+ if (ret != 0) {
+ printk(KERN_ERR
+ "xc4000: xc_set_signal_source(%d) failed\n",
+ priv->rf_mode);
+ goto fail;
+ } else {
+ u16 video_mode, audio_mode;
+ video_mode = xc4000_standard[priv->video_standard].video_mode;
+ audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+ if (priv->video_standard < XC4000_BG_PAL_A2) {
+ if (type & NOGD)
+ video_mode &= 0xFF7F;
+ } else if (priv->video_standard < XC4000_I_PAL_NICAM) {
+ if (priv->firm_version == 0x0102)
+ video_mode &= 0xFEFF;
+ if (audio_std & XC4000_AUDIO_STD_B)
+ video_mode |= 0x0080;
+ }
+ ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+ if (ret != 0) {
+ printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+ goto fail;
+ }
+ }
+
+ if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+ ret = 0;
+ if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
+ ret = -EREMOTEIO;
+ if (priv->set_smoothedcvbs != 0) {
+ if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+ ret = -EREMOTEIO;
+ }
+ if (ret != 0) {
+ printk(KERN_ERR "xc4000: setting registers failed\n");
+ goto fail;
+ }
+
+ xc_tune_channel(priv, priv->freq_hz);
+
+ ret = 0;
+
+fail:
+ mutex_unlock(&priv->lock);
+
+ 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;
+
+ *freq = priv->freq_hz;
+
+ if (debug) {
+ mutex_lock(&priv->lock);
+ if ((priv->cur_fw.type
+ & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
+ u16 snr = 0;
+ if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
+ mutex_unlock(&priv->lock);
+ dprintk(1, "%s() freq = %u, SNR = %d\n",
+ __func__, *freq, snr);
+ return 0;
+ }
+ }
+ mutex_unlock(&priv->lock);
+ }
+
+ dprintk(1, "%s()\n", __func__);
+
+ return 0;
+}
+
+static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+
+ *bw = priv->bandwidth;
+ return 0;
+}
+
+static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ u16 lock_status = 0;
+
+ mutex_lock(&priv->lock);
+
+ if (priv->cur_fw.type & BASE)
+ xc_get_lock_status(priv, &lock_status);
+
+ *status = (lock_status == 1 ?
+ TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
+ if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
+ *status &= (~TUNER_STATUS_STEREO);
+
+ mutex_unlock(&priv->lock);
+
+ dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
+
+ return 0;
+}
+
+static int xc4000_sleep(struct dvb_frontend *fe)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ mutex_lock(&priv->lock);
+
+ /* Avoid firmware reload on slow devices */
+ if ((no_poweroff == 2 ||
+ (no_poweroff == 0 && priv->default_pm != 0)) &&
+ (priv->cur_fw.type & BASE) != 0) {
+ /* force reset and firmware reload */
+ priv->cur_fw.type = XC_POWERED_DOWN;
+
+ if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
+ printk(KERN_ERR
+ "xc4000: %s() unable to shutdown tuner\n",
+ __func__);
+ ret = -EREMOTEIO;
+ }
+ msleep(20);
+ }
+
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static int xc4000_init(struct dvb_frontend *fe)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ return 0;
+}
+
+static int xc4000_release(struct dvb_frontend *fe)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ mutex_lock(&xc4000_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc4000_list_mutex);
+
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops = {
+ .info = {
+ .name = "Xceive XC4000",
+ .frequency_min = 1000000,
+ .frequency_max = 1023000000,
+ .frequency_step = 50000,
+ },
+
+ .release = xc4000_release,
+ .init = xc4000_init,
+ .sleep = xc4000_sleep,
+
+ .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
+};
+
+struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct xc4000_config *cfg)
+{
+ struct xc4000_priv *priv = NULL;
+ int instance;
+ u16 id = 0;
+
+ dprintk(1, "%s(%d-%04x)\n", __func__,
+ i2c ? i2c_adapter_id(i2c) : -1,
+ cfg ? cfg->i2c_address : -1);
+
+ mutex_lock(&xc4000_list_mutex);
+
+ instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_address, "xc4000");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = 6000000;
+ /* set default configuration */
+ priv->if_khz = 4560;
+ priv->default_pm = 0;
+ priv->dvb_amplitude = 134;
+ priv->set_smoothedcvbs = 1;
+ mutex_init(&priv->lock);
+ fe->tuner_priv = priv;
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
+
+ if (cfg->if_khz != 0) {
+ /* copy configuration if provided by the caller */
+ priv->if_khz = cfg->if_khz;
+ priv->default_pm = cfg->default_pm;
+ priv->dvb_amplitude = cfg->dvb_amplitude;
+ priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
+ }
+
+ /* Check if firmware has been loaded. It is possible that another
+ instance of the driver has loaded the firmware.
+ */
+
+ if (instance == 1) {
+ if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+ goto fail;
+ } else {
+ id = ((priv->cur_fw.type & BASE) != 0 ?
+ priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
+ }
+
+ switch (id) {
+ case XC_PRODUCT_ID_XC4000:
+ case XC_PRODUCT_ID_XC4100:
+ printk(KERN_INFO
+ "xc4000: Successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ printk(KERN_INFO
+ "xc4000: Firmware has been loaded previously\n");
+ break;
+ case XC_PRODUCT_ID_FW_NOT_LOADED:
+ printk(KERN_INFO
+ "xc4000: Successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ printk(KERN_INFO
+ "xc4000: Firmware has not been loaded previously\n");
+ break;
+ default:
+ printk(KERN_ERR
+ "xc4000: Device not found at addr 0x%02x (0x%x)\n",
+ cfg->i2c_address, id);
+ goto fail;
+ }
+
+ mutex_unlock(&xc4000_list_mutex);
+
+ memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ if (instance == 1) {
+ int ret;
+ mutex_lock(&priv->lock);
+ ret = xc4000_fwupload(fe);
+ mutex_unlock(&priv->lock);
+ if (ret != 0)
+ goto fail2;
+ }
+
+ return fe;
+fail:
+ mutex_unlock(&xc4000_list_mutex);
+fail2:
+ xc4000_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL(xc4000_attach);
+
+MODULE_AUTHOR("Steven Toth, Davide Ferri");
+MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/tuners/xc4000.h
index e6a44d151cbd..e6a44d151cbd 100644
--- a/drivers/media/common/tuners/xc4000.h
+++ b/drivers/media/tuners/xc4000.h
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
new file mode 100644
index 000000000000..dc93cf338f36
--- /dev/null
+++ b/drivers/media/tuners/xc5000.c
@@ -0,0 +1,1366 @@
+/*
+ * Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2007 Xceive Corporation
+ * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "tuner-i2c.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+ "\t\t1 keep device energized and with tuner ready all the times.\n"
+ "\t\tFaster, but consumes more power and keeps the device hotter");
+
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+struct xc5000_priv {
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+
+ u32 if_khz;
+ u16 xtal_khz;
+ u32 freq_hz;
+ u32 bandwidth;
+ u8 video_standard;
+ u8 rf_mode;
+ u8 radio_input;
+
+ int chip_id;
+ u16 pll_register_no;
+ u8 init_status_supported;
+ u8 fw_checksum_supported;
+};
+
+/* Misc Defines */
+#define MAX_TV_STANDARD 24
+#define XC_MAX_I2C_WRITE_LENGTH 64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR 0
+#define XC_RF_MODE_CABLE 1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS 0
+#define XC_RESULT_RESET_FAILURE 1
+#define XC_RESULT_I2C_WRITE_FAILURE 2
+#define XC_RESULT_I2C_READ_FAILURE 3
+#define XC_RESULT_OUT_OF_RANGE 5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
+#define XC_PRODUCT_ID_FW_LOADED 0x1388
+
+/* Registers */
+#define XREG_INIT 0x00
+#define XREG_VIDEO_MODE 0x01
+#define XREG_AUDIO_MODE 0x02
+#define XREG_RF_FREQ 0x03
+#define XREG_D_CODE 0x04
+#define XREG_IF_OUT 0x05
+#define XREG_SEEK_MODE 0x07
+#define XREG_POWER_DOWN 0x0A /* Obsolete */
+/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
+#define XREG_OUTPUT_AMP 0x0B
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ 0x0F
+#define XREG_FINERFREQ 0x10
+#define XREG_DDIMODE 0x11
+
+#define XREG_ADC_ENV 0x00
+#define XREG_QUALITY 0x01
+#define XREG_FRAME_LINES 0x02
+#define XREG_HSYNC_FREQ 0x03
+#define XREG_LOCK 0x04
+#define XREG_FREQ_ERROR 0x05
+#define XREG_SNR 0x06
+#define XREG_VERSION 0x07
+#define XREG_PRODUCT_ID 0x08
+#define XREG_BUSY 0x09
+#define XREG_BUILD 0x0D
+#define XREG_TOTALGAIN 0x0F
+#define XREG_FW_CHECKSUM 0x12
+#define XREG_INIT_STATUS 0x13
+
+/*
+ Basic firmware description. This will remain with
+ the driver for documentation purposes.
+
+ This represents an I2C firmware file encoded as a
+ string of unsigned char. Format is as follows:
+
+ char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB
+ char[1 ]=len0_LSB -> length of first write transaction
+ char[2 ]=data0 -> first byte to be sent
+ char[3 ]=data1
+ char[4 ]=data2
+ char[ ]=...
+ char[M ]=dataN -> last byte to be sent
+ char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB
+ char[M+2]=len1_LSB -> length of second write transaction
+ char[M+3]=data0
+ char[M+4]=data1
+ ...
+ etc.
+
+ The [len] value should be interpreted as follows:
+
+ len= len_MSB _ len_LSB
+ len=1111_1111_1111_1111 : End of I2C_SEQUENCE
+ len=0000_0000_0000_0000 : Reset command: Do hardware reset
+ len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767)
+ len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms
+
+ For the RESET and WAIT commands, the two following bytes will contain
+ immediately the length of the following transaction.
+
+*/
+struct XC_TV_STANDARD {
+ char *Name;
+ u16 AudioMode;
+ u16 VideoMode;
+};
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC 0
+#define MN_NTSC_PAL_A2 1
+#define MN_NTSC_PAL_EIAJ 2
+#define MN_NTSC_PAL_Mono 3
+#define BG_PAL_A2 4
+#define BG_PAL_NICAM 5
+#define BG_PAL_MONO 6
+#define I_PAL_NICAM 7
+#define I_PAL_NICAM_MONO 8
+#define DK_PAL_A2 9
+#define DK_PAL_NICAM 10
+#define DK_PAL_MONO 11
+#define DK_SECAM_A2DK1 12
+#define DK_SECAM_A2LDK3 13
+#define DK_SECAM_A2MONO 14
+#define L_SECAM_NICAM 15
+#define LC_SECAM_NICAM 16
+#define DTV6 17
+#define DTV8 18
+#define DTV7_8 19
+#define DTV7 20
+#define FM_Radio_INPUT2 21
+#define FM_Radio_INPUT1 22
+#define FM_Radio_INPUT1_MONO 23
+
+static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+ {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+ {"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
+ {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+ {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+ {"B/G-PAL-A2", 0x0A00, 0x8049},
+ {"B/G-PAL-NICAM", 0x0C04, 0x8049},
+ {"B/G-PAL-MONO", 0x0878, 0x8059},
+ {"I-PAL-NICAM", 0x1080, 0x8009},
+ {"I-PAL-NICAM-MONO", 0x0E78, 0x8009},
+ {"D/K-PAL-A2", 0x1600, 0x8009},
+ {"D/K-PAL-NICAM", 0x0E80, 0x8009},
+ {"D/K-PAL-MONO", 0x1478, 0x8009},
+ {"D/K-SECAM-A2 DK1", 0x1200, 0x8009},
+ {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
+ {"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+ {"L-SECAM-NICAM", 0x8E82, 0x0009},
+ {"L'-SECAM-NICAM", 0x8E82, 0x4009},
+ {"DTV6", 0x00C0, 0x8002},
+ {"DTV8", 0x00C0, 0x800B},
+ {"DTV7/8", 0x00C0, 0x801B},
+ {"DTV7", 0x00C0, 0x8007},
+ {"FM Radio-INPUT2", 0x9802, 0x9002},
+ {"FM Radio-INPUT1", 0x0208, 0x9002},
+ {"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
+};
+
+
+struct xc5000_fw_cfg {
+ char *name;
+ u16 size;
+ u16 pll_reg;
+ u8 init_status_supported;
+ u8 fw_checksum_supported;
+};
+
+#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
+ .name = XC5000A_FIRMWARE,
+ .size = 12401,
+ .pll_reg = 0x806c,
+};
+
+#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw"
+static const struct xc5000_fw_cfg xc5000c_41_024_5 = {
+ .name = XC5000C_FIRMWARE,
+ .size = 16497,
+ .pll_reg = 0x13,
+ .init_status_supported = 1,
+ .fw_checksum_supported = 1,
+};
+
+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;
+ }
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = buf, .len = len };
+
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+ return XC_RESULT_I2C_WRITE_FAILURE;
+ }
+ return XC_RESULT_SUCCESS;
+}
+
+#if 0
+/* This routine is never used because the only time we read data from the
+ i2c bus is when we read registers, and we want that to be an atomic i2c
+ transaction in case we are on a multi-master bus */
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = buf, .len = len };
+
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ u8 bval[2] = { 0, 0 };
+ struct i2c_msg msg[2] = {
+ { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = &buf[0], .len = 2 },
+ { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+ };
+
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+ printk(KERN_WARNING "xc5000: I2C read failed\n");
+ return -EREMOTEIO;
+ }
+
+ *val = (bval[0] << 8) | bval[1];
+ return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+ msleep(wait_ms);
+}
+
+static int xc5000_TunerReset(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (fe->callback) {
+ ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv :
+ priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER,
+ XC5000_TUNER_RESET, 0);
+ if (ret) {
+ printk(KERN_ERR "xc5000: reset failed\n");
+ return XC_RESULT_RESET_FAILURE;
+ }
+ } else {
+ printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+ return XC_RESULT_RESET_FAILURE;
+ }
+ return XC_RESULT_SUCCESS;
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+ u8 buf[4];
+ int WatchDogTimer = 100;
+ int result;
+
+ buf[0] = (regAddr >> 8) & 0xFF;
+ buf[1] = regAddr & 0xFF;
+ buf[2] = (i2cData >> 8) & 0xFF;
+ buf[3] = i2cData & 0xFF;
+ result = xc_send_i2c_data(priv, buf, 4);
+ if (result == XC_RESULT_SUCCESS) {
+ /* wait for busy flag to clear */
+ while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+ result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
+ if (result == XC_RESULT_SUCCESS) {
+ if ((buf[0] == 0) && (buf[1] == 0)) {
+ /* busy flag cleared */
+ break;
+ } else {
+ xc_wait(5); /* wait 5 ms */
+ WatchDogTimer--;
+ }
+ }
+ }
+ }
+ if (WatchDogTimer <= 0)
+ result = XC_RESULT_I2C_WRITE_FAILURE;
+
+ return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
+ int i, nbytes_to_send, result;
+ unsigned int len, pos, index;
+ u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+ index = 0;
+ while ((i2c_sequence[index] != 0xFF) ||
+ (i2c_sequence[index + 1] != 0xFF)) {
+ len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+ if (len == 0x0000) {
+ /* RESET command */
+ result = xc5000_TunerReset(fe);
+ index += 2;
+ if (result != XC_RESULT_SUCCESS)
+ return result;
+ } else if (len & 0x8000) {
+ /* WAIT command */
+ xc_wait(len & 0x7FFF);
+ index += 2;
+ } else {
+ /* Send i2c data whilst ensuring individual transactions
+ * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+ */
+ index += 2;
+ buf[0] = i2c_sequence[index];
+ buf[1] = i2c_sequence[index + 1];
+ pos = 2;
+ while (pos < len) {
+ if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+ nbytes_to_send =
+ XC_MAX_I2C_WRITE_LENGTH;
+ else
+ nbytes_to_send = (len - pos + 2);
+ for (i = 2; i < nbytes_to_send; i++) {
+ buf[i] = i2c_sequence[index + pos +
+ i - 2];
+ }
+ result = xc_send_i2c_data(priv, buf,
+ nbytes_to_send);
+
+ if (result != XC_RESULT_SUCCESS)
+ return result;
+
+ pos += nbytes_to_send - 2;
+ }
+ index += len;
+ }
+ }
+ return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+ dprintk(1, "%s()\n", __func__);
+ return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+ u16 VideoMode, u16 AudioMode)
+{
+ int ret;
+ dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
+ dprintk(1, "%s() Standard = %s\n",
+ __func__,
+ XC5000_Standard[priv->video_standard].Name);
+
+ ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+ if (ret == XC_RESULT_SUCCESS)
+ ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+ return ret;
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+ dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+ rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+ if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+ rf_mode = XC_RF_MODE_CABLE;
+ printk(KERN_ERR
+ "%s(), Invalid mode, defaulting to CABLE",
+ __func__);
+ }
+ return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+ u16 freq_code;
+
+ dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+ if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+ (freq_hz < xc5000_tuner_ops.info.frequency_min))
+ return XC_RESULT_OUT_OF_RANGE;
+
+ freq_code = (u16)(freq_hz / 15625);
+
+ /* Starting in firmware version 1.1.44, Xceive recommends using the
+ FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+ only be used for fast scanning for channel lock) */
+ return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
+}
+
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+ u32 freq_code = (freq_khz * 1024)/1000;
+ dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+ __func__, freq_khz, freq_code);
+
+ return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+ return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+ int result;
+ u16 regData;
+ u32 tmp;
+
+ result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+ if (result != XC_RESULT_SUCCESS)
+ return result;
+
+ tmp = (u32)regData;
+ (*freq_error_hz) = (tmp * 15625) / 1000;
+ return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+ return xc5000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+ u8 *hw_majorversion, u8 *hw_minorversion,
+ u8 *fw_majorversion, u8 *fw_minorversion)
+{
+ u16 data;
+ int result;
+
+ result = xc5000_readreg(priv, XREG_VERSION, &data);
+ if (result != XC_RESULT_SUCCESS)
+ return result;
+
+ (*hw_majorversion) = (data >> 12) & 0x0F;
+ (*hw_minorversion) = (data >> 8) & 0x0F;
+ (*fw_majorversion) = (data >> 4) & 0x0F;
+ (*fw_minorversion) = data & 0x0F;
+
+ return 0;
+}
+
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+ return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+ u16 regData;
+ int result;
+
+ result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+ if (result != XC_RESULT_SUCCESS)
+ return result;
+
+ (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+ return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+ return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+ return xc5000_readreg(priv, XREG_QUALITY, quality);
+}
+
+static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr)
+{
+ return xc5000_readreg(priv, XREG_SNR, snr);
+}
+
+static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain)
+{
+ return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+ u16 lockState = 0;
+ int watchDogCount = 40;
+
+ while ((lockState == 0) && (watchDogCount > 0)) {
+ xc_get_lock_status(priv, &lockState);
+ if (lockState != 1) {
+ xc_wait(5);
+ watchDogCount--;
+ }
+ }
+ return lockState;
+}
+
+#define XC_TUNE_ANALOG 0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
+{
+ int found = 0;
+
+ dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+ if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+ return 0;
+
+ if (mode == XC_TUNE_ANALOG) {
+ if (WaitForLock(priv) == 1)
+ found = 1;
+ }
+
+ return found;
+}
+
+static int xc_set_xtal(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret = XC_RESULT_SUCCESS;
+
+ switch (priv->chip_id) {
+ default:
+ case XC5000A:
+ /* 32.000 MHz xtal is default */
+ break;
+ case XC5000C:
+ switch (priv->xtal_khz) {
+ default:
+ case 32000:
+ /* 32.000 MHz xtal is default */
+ break;
+ case 31875:
+ /* 31.875 MHz xtal configuration */
+ ret = xc_write_reg(priv, 0x000f, 0x8081);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
+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);
+ priv->pll_register_no = desired_fw->pll_reg;
+ priv->init_status_supported = desired_fw->init_status_supported;
+ priv->fw_checksum_supported = desired_fw->fw_checksum_supported;
+
+ /* request the firmware, this will block and timeout */
+ printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+ desired_fw->name);
+
+ 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");
+ ret = XC_RESULT_RESET_FAILURE;
+ goto out;
+ } else {
+ printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
+ fw->size);
+ ret = XC_RESULT_SUCCESS;
+ }
+
+ if (fw->size != desired_fw->size) {
+ printk(KERN_ERR "xc5000: firmware incorrect size\n");
+ ret = XC_RESULT_RESET_FAILURE;
+ } else {
+ printk(KERN_INFO "xc5000: firmware uploading...\n");
+ ret = xc_load_i2c_sequence(fe, fw->data);
+ if (XC_RESULT_SUCCESS == ret)
+ ret = xc_set_xtal(fe);
+ if (XC_RESULT_SUCCESS == ret)
+ printk(KERN_INFO "xc5000: firmware upload complete...\n");
+ else
+ printk(KERN_ERR "xc5000: firmware upload failed...\n");
+ }
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+ u16 adc_envelope;
+ u32 freq_error_hz = 0;
+ u16 lock_status;
+ u32 hsync_freq_hz = 0;
+ u16 frame_lines;
+ u16 quality;
+ u16 snr;
+ u16 totalgain;
+ u8 hw_majorversion = 0, hw_minorversion = 0;
+ u8 fw_majorversion = 0, fw_minorversion = 0;
+ u16 fw_buildversion = 0;
+ u16 regval;
+
+ /* Wait for stats to stabilize.
+ * Frame Lines needs two frame times after initial lock
+ * before it is valid.
+ */
+ xc_wait(100);
+
+ xc_get_ADC_Envelope(priv, &adc_envelope);
+ dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+ xc_get_frequency_error(priv, &freq_error_hz);
+ dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+ xc_get_lock_status(priv, &lock_status);
+ dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+ lock_status);
+
+ xc_get_version(priv, &hw_majorversion, &hw_minorversion,
+ &fw_majorversion, &fw_minorversion);
+ xc_get_buildversion(priv, &fw_buildversion);
+ dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n",
+ hw_majorversion, hw_minorversion,
+ fw_majorversion, fw_minorversion, fw_buildversion);
+
+ xc_get_hsync_freq(priv, &hsync_freq_hz);
+ dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+ xc_get_frame_lines(priv, &frame_lines);
+ dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+ xc_get_quality(priv, &quality);
+ dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07);
+
+ xc_get_analogsnr(priv, &snr);
+ dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f);
+
+ xc_get_totalgain(priv, &totalgain);
+ dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256,
+ (totalgain % 256) * 100 / 256);
+
+ if (priv->pll_register_no) {
+ xc5000_readreg(priv, priv->pll_register_no, &regval);
+ dprintk(1, "*** PLL lock status = 0x%04x\n", regval);
+ }
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe)
+{
+ int ret, b;
+ struct xc5000_priv *priv = fe->tuner_priv;
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ u32 freq = fe->dtv_property_cache.frequency;
+ u32 delsys = fe->dtv_property_cache.delivery_system;
+
+ if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ dprintk(1, "Unable to load firmware and init tuner\n");
+ return -EINVAL;
+ }
+
+ 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_ISDBT:
+ /* All ISDB-T are currently for 6 MHz bw */
+ if (!bw)
+ bw = 6000000;
+ /* fall to OFDM handling */
+ case SYS_DMBTH:
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ dprintk(1, "%s() OFDM\n", __func__);
+ switch (bw) {
+ case 6000000:
+ priv->video_standard = DTV6;
+ priv->freq_hz = freq - 1750000;
+ break;
+ case 7000000:
+ priv->video_standard = DTV7;
+ priv->freq_hz = freq - 2250000;
+ break;
+ case 8000000:
+ priv->video_standard = DTV8;
+ priv->freq_hz = freq - 2750000;
+ break;
+ default:
+ printk(KERN_ERR "xc5000 bandwidth not set!\n");
+ return -EINVAL;
+ }
+ priv->rf_mode = XC_RF_MODE_AIR;
+ 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;
+ }
+ 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 to %d)\n",
+ __func__, freq, priv->freq_hz);
+
+ ret = xc_SetSignalSource(priv, priv->rf_mode);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR
+ "xc5000: xc_SetSignalSource(%d) failed\n",
+ priv->rf_mode);
+ return -EREMOTEIO;
+ }
+
+ ret = xc_SetTVStandard(priv,
+ XC5000_Standard[priv->video_standard].VideoMode,
+ XC5000_Standard[priv->video_standard].AudioMode);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ return -EREMOTEIO;
+ }
+
+ ret = xc_set_IF_frequency(priv, priv->if_khz);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+ priv->if_khz);
+ return -EIO;
+ }
+
+ xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
+ xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
+
+ if (debug)
+ xc_debug_dump(priv);
+
+ priv->bandwidth = bw;
+
+ return 0;
+}
+
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret;
+ u16 id;
+
+ ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
+ if (ret == XC_RESULT_SUCCESS) {
+ if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
+ ret = XC_RESULT_RESET_FAILURE;
+ else
+ ret = XC_RESULT_SUCCESS;
+ }
+
+ dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
+ ret == XC_RESULT_SUCCESS ? "True" : "False", id);
+ return ret;
+}
+
+static int xc5000_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ u16 pll_lock_status;
+ int ret;
+
+ dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+ __func__, params->frequency);
+
+ /* Fix me: it could be air. */
+ priv->rf_mode = params->mode;
+ if (params->mode > XC_RF_MODE_CABLE)
+ priv->rf_mode = XC_RF_MODE_CABLE;
+
+ /* params->frequency is in units of 62.5khz */
+ priv->freq_hz = params->frequency * 62500;
+
+ /* FIX ME: Some video standards may have several possible audio
+ standards. We simply default to one of them here.
+ */
+ if (params->std & V4L2_STD_MN) {
+ /* default to BTSC audio standard */
+ priv->video_standard = MN_NTSC_PAL_BTSC;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_BG) {
+ /* default to NICAM audio standard */
+ priv->video_standard = BG_PAL_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_I) {
+ /* default to NICAM audio standard */
+ priv->video_standard = I_PAL_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_PAL_DK) {
+ /* default to NICAM audio standard */
+ priv->video_standard = DK_PAL_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_DK) {
+ /* default to A2 DK1 audio standard */
+ priv->video_standard = DK_SECAM_A2DK1;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_L) {
+ priv->video_standard = L_SECAM_NICAM;
+ goto tune_channel;
+ }
+
+ if (params->std & V4L2_STD_SECAM_LC) {
+ priv->video_standard = LC_SECAM_NICAM;
+ goto tune_channel;
+ }
+
+tune_channel:
+ ret = xc_SetSignalSource(priv, priv->rf_mode);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR
+ "xc5000: xc_SetSignalSource(%d) failed\n",
+ priv->rf_mode);
+ return -EREMOTEIO;
+ }
+
+ ret = xc_SetTVStandard(priv,
+ XC5000_Standard[priv->video_standard].VideoMode,
+ XC5000_Standard[priv->video_standard].AudioMode);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ return -EREMOTEIO;
+ }
+
+ xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+
+ xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
+
+ if (debug)
+ xc_debug_dump(priv);
+
+ if (priv->pll_register_no != 0) {
+ msleep(20);
+ xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status);
+ if (pll_lock_status > 63) {
+ /* PLL is unlocked, force reload of the firmware */
+ dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n",
+ pll_lock_status);
+ if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: Unable to reload fw\n");
+ return -EREMOTEIO;
+ }
+ goto tune_channel;
+ }
+ }
+
+ return 0;
+}
+
+static int xc5000_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+ u8 radio_input;
+
+ dprintk(1, "%s() frequency=%d (in units of khz)\n",
+ __func__, params->frequency);
+
+ if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
+ dprintk(1, "%s() radio input not configured\n", __func__);
+ return -EINVAL;
+ }
+
+ if (priv->radio_input == XC5000_RADIO_FM1)
+ radio_input = FM_Radio_INPUT1;
+ else if (priv->radio_input == XC5000_RADIO_FM2)
+ radio_input = FM_Radio_INPUT2;
+ else if (priv->radio_input == XC5000_RADIO_FM1_MONO)
+ radio_input = FM_Radio_INPUT1_MONO;
+ else {
+ dprintk(1, "%s() unknown radio input %d\n", __func__,
+ priv->radio_input);
+ return -EINVAL;
+ }
+
+ priv->freq_hz = params->frequency * 125 / 2;
+
+ priv->rf_mode = XC_RF_MODE_AIR;
+
+ ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
+ XC5000_Standard[radio_input].AudioMode);
+
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ return -EREMOTEIO;
+ }
+
+ ret = xc_SetSignalSource(priv, priv->rf_mode);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR
+ "xc5000: xc_SetSignalSource(%d) failed\n",
+ priv->rf_mode);
+ return -EREMOTEIO;
+ }
+
+ if ((priv->radio_input == XC5000_RADIO_FM1) ||
+ (priv->radio_input == XC5000_RADIO_FM2))
+ xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+ else if (priv->radio_input == XC5000_RADIO_FM1_MONO)
+ xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
+
+ xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
+
+ return 0;
+}
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ dprintk(1, "Unable to load firmware and init tuner\n");
+ return -EINVAL;
+ }
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = xc5000_set_radio_freq(fe, params);
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = xc5000_set_tv_freq(fe, params);
+ break;
+ }
+
+ return ret;
+}
+
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+ *freq = priv->freq_hz;
+ 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;
+ dprintk(1, "%s()\n", __func__);
+
+ *bw = priv->bandwidth;
+ return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ u16 lock_status = 0;
+
+ xc_get_lock_status(priv, &lock_status);
+
+ dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
+
+ *status = lock_status;
+
+ return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret = XC_RESULT_SUCCESS;
+ u16 pll_lock_status;
+ u16 fw_ck;
+
+ if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+
+fw_retry:
+
+ ret = xc5000_fwupload(fe);
+ if (ret != XC_RESULT_SUCCESS)
+ return ret;
+
+ msleep(20);
+
+ if (priv->fw_checksum_supported) {
+ if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)
+ != XC_RESULT_SUCCESS) {
+ dprintk(1, "%s() FW checksum reading failed.\n",
+ __func__);
+ goto fw_retry;
+ }
+
+ if (fw_ck == 0) {
+ dprintk(1, "%s() FW checksum failed = 0x%04x\n",
+ __func__, fw_ck);
+ goto fw_retry;
+ }
+ }
+
+ /* Start the tuner self-calibration process */
+ ret |= xc_initialize(priv);
+
+ if (ret != XC_RESULT_SUCCESS)
+ goto fw_retry;
+
+ /* Wait for calibration to complete.
+ * We could continue but XC5000 will clock stretch subsequent
+ * I2C transactions until calibration is complete. This way we
+ * don't have to rely on clock stretching working.
+ */
+ xc_wait(100);
+
+ if (priv->init_status_supported) {
+ if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) {
+ dprintk(1, "%s() FW failed reading init status.\n",
+ __func__);
+ goto fw_retry;
+ }
+
+ if (fw_ck == 0) {
+ dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck);
+ goto fw_retry;
+ }
+ }
+
+ if (priv->pll_register_no) {
+ xc5000_readreg(priv, priv->pll_register_no,
+ &pll_lock_status);
+ if (pll_lock_status > 63) {
+ /* PLL is unlocked, force reload of the firmware */
+ printk(KERN_ERR "xc5000: PLL not running after fwload.\n");
+ goto fw_retry;
+ }
+ }
+
+ /* Default to "CABLE" mode */
+ ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+ }
+
+ return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Avoid firmware reload on slow devices */
+ if (no_poweroff)
+ return 0;
+
+ /* According to Xceive technical support, the "powerdown" register
+ was removed in newer versions of the firmware. The "supported"
+ way to sleep the tuner is to pull the reset pin low for 10ms */
+ ret = xc5000_TunerReset(fe);
+ if (ret != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR
+ "xc5000: %s() unable to shutdown tuner\n",
+ __func__);
+ return -EREMOTEIO;
+ } else
+ return XC_RESULT_SUCCESS;
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+
+ if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+ return -EREMOTEIO;
+ }
+
+ if (debug)
+ xc_debug_dump(priv);
+
+ return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ mutex_lock(&xc5000_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc5000_list_mutex);
+
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ struct xc5000_config *p = priv_cfg;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (p->if_khz)
+ priv->if_khz = p->if_khz;
+
+ if (p->radio_input)
+ priv->radio_input = p->radio_input;
+
+ return 0;
+}
+
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+ .info = {
+ .name = "Xceive XC5000",
+ .frequency_min = 1000000,
+ .frequency_max = 1023000000,
+ .frequency_step = 50000,
+ },
+
+ .release = xc5000_release,
+ .init = xc5000_init,
+ .sleep = xc5000_sleep,
+
+ .set_config = xc5000_set_config,
+ .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
+};
+
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct xc5000_config *cfg)
+{
+ struct xc5000_priv *priv = NULL;
+ int instance;
+ u16 id = 0;
+
+ dprintk(1, "%s(%d-%04x)\n", __func__,
+ i2c ? i2c_adapter_id(i2c) : -1,
+ cfg ? cfg->i2c_address : -1);
+
+ mutex_lock(&xc5000_list_mutex);
+
+ instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_address, "xc5000");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = 6000000;
+ fe->tuner_priv = priv;
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
+
+ if (priv->if_khz == 0) {
+ /* If the IF hasn't been set yet, use the value provided by
+ the caller (occurs in hybrid devices where the analog
+ call to xc5000_attach occurs before the digital side) */
+ priv->if_khz = cfg->if_khz;
+ }
+
+ if (priv->xtal_khz == 0)
+ priv->xtal_khz = cfg->xtal_khz;
+
+ 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.
+ */
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
+ goto fail;
+
+ switch (id) {
+ case XC_PRODUCT_ID_FW_LOADED:
+ printk(KERN_INFO
+ "xc5000: Successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ printk(KERN_INFO
+ "xc5000: Firmware has been loaded previously\n");
+ break;
+ case XC_PRODUCT_ID_FW_NOT_LOADED:
+ printk(KERN_INFO
+ "xc5000: Successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ printk(KERN_INFO
+ "xc5000: Firmware has not been loaded previously\n");
+ break;
+ default:
+ printk(KERN_ERR
+ "xc5000: Device not found at addr 0x%02x (0x%x)\n",
+ cfg->i2c_address, id);
+ goto fail;
+ }
+
+ mutex_unlock(&xc5000_list_mutex);
+
+ memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+fail:
+ mutex_unlock(&xc5000_list_mutex);
+
+ xc5000_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC5000A_FIRMWARE);
+MODULE_FIRMWARE(XC5000C_FIRMWARE);
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/tuners/xc5000.h
index b1a547494625..b1a547494625 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/tuners/xc5000.h
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
new file mode 100644
index 000000000000..6746994d03fe
--- /dev/null
+++ b/drivers/media/usb/Kconfig
@@ -0,0 +1,54 @@
+menuconfig MEDIA_USB_SUPPORT
+ bool "Media USB Adapters"
+ depends on USB && MEDIA_SUPPORT
+ help
+ Enable media drivers for USB bus.
+ If you have such devices, say Y.
+
+if MEDIA_USB_SUPPORT
+
+if MEDIA_CAMERA_SUPPORT
+ comment "Webcam devices"
+source "drivers/media/usb/uvc/Kconfig"
+source "drivers/media/usb/gspca/Kconfig"
+source "drivers/media/usb/pwc/Kconfig"
+source "drivers/media/usb/cpia2/Kconfig"
+source "drivers/media/usb/zr364xx/Kconfig"
+source "drivers/media/usb/stkwebcam/Kconfig"
+source "drivers/media/usb/s2255/Kconfig"
+source "drivers/media/usb/sn9c102/Kconfig"
+endif
+
+if MEDIA_ANALOG_TV_SUPPORT
+ comment "Analog TV USB devices"
+source "drivers/media/usb/au0828/Kconfig"
+source "drivers/media/usb/pvrusb2/Kconfig"
+source "drivers/media/usb/hdpvr/Kconfig"
+source "drivers/media/usb/tlg2300/Kconfig"
+source "drivers/media/usb/usbvision/Kconfig"
+source "drivers/media/usb/stk1160/Kconfig"
+endif
+
+if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
+ comment "Analog/digital TV USB devices"
+source "drivers/media/usb/cx231xx/Kconfig"
+source "drivers/media/usb/tm6000/Kconfig"
+endif
+
+
+if I2C && MEDIA_DIGITAL_TV_SUPPORT
+ comment "Digital TV USB devices"
+source "drivers/media/usb/dvb-usb/Kconfig"
+source "drivers/media/usb/dvb-usb-v2/Kconfig"
+source "drivers/media/usb/ttusb-budget/Kconfig"
+source "drivers/media/usb/ttusb-dec/Kconfig"
+source "drivers/media/usb/siano/Kconfig"
+source "drivers/media/usb/b2c2/Kconfig"
+endif
+
+if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
+ comment "Webcam, TV (analog/digital) USB devices"
+source "drivers/media/usb/em28xx/Kconfig"
+endif
+
+endif #MEDIA_USB_SUPPORT
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
new file mode 100644
index 000000000000..7f51d7e5f739
--- /dev/null
+++ b/drivers/media/usb/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the USB media device drivers
+#
+
+# DVB USB-only drivers
+obj-y += ttusb-dec/ ttusb-budget/ dvb-usb/ dvb-usb-v2/ siano/ b2c2/
+obj-y += zr364xx/ stkwebcam/ s2255/
+
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
+obj-$(CONFIG_USB_GSPCA) += gspca/
+obj-$(CONFIG_USB_PWC) += pwc/
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_USB_SN9C102) += sn9c102/
+obj-$(CONFIG_VIDEO_AU0828) += au0828/
+obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
+obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
+obj-$(CONFIG_VIDEO_STK1160) += stk1160/
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
+obj-$(CONFIG_VIDEO_TM6000) += tm6000/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
new file mode 100644
index 000000000000..385e557ba910
--- /dev/null
+++ b/drivers/media/usb/au0828/Kconfig
@@ -0,0 +1,18 @@
+
+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
+ select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called au0828
diff --git a/drivers/media/usb/au0828/Makefile b/drivers/media/usb/au0828/Makefile
new file mode 100644
index 000000000000..98cc20cc0ffb
--- /dev/null
+++ b/drivers/media/usb/au0828/Makefile
@@ -0,0 +1,9 @@
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
new file mode 100644
index 000000000000..448361c6a13e
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -0,0 +1,339 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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 "au0828.h"
+#include "au0828-cards.h"
+#include "au8522.h"
+#include "media/tuner.h"
+#include "media/v4l2-common.h"
+
+void hvr950q_cs5340_audio(void *priv, int enable)
+{
+ /* Because the HVR-950q shares an i2s bus between the cs5340 and the
+ au8522, we need to hold cs5340 in reset when using the au8522 */
+ struct au0828_dev *dev = priv;
+ if (enable == 1)
+ au0828_set(dev, REG_000, 0x10);
+ else
+ au0828_clear(dev, REG_000, 0x10);
+}
+
+struct au0828_board au0828_boards[] = {
+ [AU0828_BOARD_UNKNOWN] = {
+ .name = "Unknown board",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR850] = {
+ .name = "Hauppauge HVR850",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+ .input = {
+ {
+ .type = AU0828_VMUX_TELEVISION,
+ .vmux = AU8522_COMPOSITE_CH4_SIF,
+ .amux = AU8522_AUDIO_SIF,
+ },
+ {
+ .type = AU0828_VMUX_COMPOSITE,
+ .vmux = AU8522_COMPOSITE_CH1,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ {
+ .type = AU0828_VMUX_SVIDEO,
+ .vmux = AU8522_SVIDEO_CH13,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ },
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+ .name = "Hauppauge HVR950Q",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ /* The au0828 hardware i2c implementation does not properly
+ support the xc5000's i2c clock stretching. So we need to
+ lower the clock frequency enough where the 15us clock
+ stretch fits inside of a normal clock cycle, or else the
+ au0828 fails to set the STOP bit. A 30 KHz clock puts the
+ clock pulse width at 18us */
+ .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+ .input = {
+ {
+ .type = AU0828_VMUX_TELEVISION,
+ .vmux = AU8522_COMPOSITE_CH4_SIF,
+ .amux = AU8522_AUDIO_SIF,
+ },
+ {
+ .type = AU0828_VMUX_COMPOSITE,
+ .vmux = AU8522_COMPOSITE_CH1,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ {
+ .type = AU0828_VMUX_SVIDEO,
+ .vmux = AU8522_SVIDEO_CH13,
+ .amux = AU8522_AUDIO_NONE,
+ .audio_setup = hvr950q_cs5340_audio,
+ },
+ },
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
+ .name = "Hauppauge HVR950Q rev xxF8",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ },
+ [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+ .name = "DViCO FusionHDTV USB",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ },
+ [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+ .name = "Hauppauge Woodbury",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ },
+};
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int component, int command, int arg)
+{
+ struct au0828_dev *dev = priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ if (command == 0) {
+ /* Tuner Reset Command from xc5000 */
+ /* Drive the tuner into reset and out */
+ au0828_clear(dev, REG_001, 2);
+ mdelay(10);
+ au0828_set(dev, REG_001, 2);
+ mdelay(10);
+ return 0;
+ } else {
+ printk(KERN_ERR
+ "%s(): Unknown command.\n", __func__);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+ dev->board.tuner_type = tv.tuner_type;
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
+ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+ case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+ case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
+ case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
+ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n", __func__, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+ static u8 eeprom[256];
+ struct tuner_setup tun_setup;
+ struct v4l2_subdev *sd;
+ unsigned int mode_mask = T_ANALOG_TV;
+
+ dprintk(1, "%s()\n", __func__);
+
+ memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+
+ if (dev->i2c_rc == 0) {
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+ if (dev->i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0xa0);
+ break;
+ }
+
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ /* Load the analog demodulator driver (note this would need to
+ be abstracted out if we ever need to support a different
+ demod) */
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "au8522", 0x8e >> 1, NULL);
+ if (sd == NULL)
+ printk(KERN_ERR "analog subdev registration failed\n");
+ }
+
+ /* Setup tuners */
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ /* Load the tuner module, which does the attach */
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "tuner", dev->board.tuner_addr, NULL);
+ if (sd == NULL)
+ printk(KERN_ERR "tuner subdev registration fail\n");
+
+ tun_setup.mode_mask = mode_mask;
+ tun_setup.type = dev->board.tuner_type;
+ tun_setup.addr = dev->board.tuner_addr;
+ tun_setup.tuner_callback = au0828_tuner_callback;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
+ &tun_setup);
+ }
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+ /* GPIO's
+ * 4 - CS5340
+ * 5 - AU8522 Demodulator
+ * 6 - eeprom W/P
+ * 7 - power supply
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset (leave the cs5340 in reset until needed) */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+ au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+
+ msleep(250);
+ break;
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ /* GPIO's
+ * 6 - ?
+ * 8 - AU8522 Demodulator
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_000, 0xa0);
+ msleep(250);
+ break;
+ }
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table[] = {
+ { USB_DEVICE(0x2040, 0x7200),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7240),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+ { USB_DEVICE(0x0fe9, 0xd620),
+ .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+ { USB_DEVICE(0x2040, 0x7210),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7217),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721b),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721e),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721f),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7280),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x0fd9, 0x0008),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7201),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+ { USB_DEVICE(0x2040, 0x7211),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+ { USB_DEVICE(0x2040, 0x7281),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+ { USB_DEVICE(0x05e1, 0x0480),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
+ { USB_DEVICE(0x2040, 0x8200),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
+ { USB_DEVICE(0x2040, 0x7260),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7213),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/usb/au0828/au0828-cards.h
index 48a1882c2b6b..48a1882c2b6b 100644
--- a/drivers/media/video/au0828/au0828-cards.h
+++ b/drivers/media/usb/au0828/au0828-cards.h
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
new file mode 100644
index 000000000000..745a80a798c8
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -0,0 +1,282 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+ "override min bandwidth requirement of 480M bps");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN 0x00
+#define CMD_REQUEST_OUT 0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+ u8 result = 0;
+
+ recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
+ dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
+
+ return result;
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+ dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
+ return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index)
+{
+ int status = -ENODEV;
+
+ if (dev->usbdev) {
+
+ /* cp must be memory that has been allocated by kmalloc */
+ status = usb_control_msg(dev->usbdev,
+ usb_sndctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE,
+ value, index, NULL, 0, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+ __func__, status);
+ }
+
+ }
+
+ return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size)
+{
+ int status = -ENODEV;
+ mutex_lock(&dev->mutex);
+ if (dev->usbdev) {
+ status = usb_control_msg(dev->usbdev,
+ usb_rcvctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ dev->ctrlmsg, size, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+ __func__, status);
+ }
+
+ /* the host controller requires heap allocated memory, which
+ is why we didn't just pass "cp" into usb_control_msg */
+ memcpy(cp, dev->ctrlmsg, size);
+ }
+ mutex_unlock(&dev->mutex);
+ return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+ struct au0828_dev *dev = usb_get_intfdata(interface);
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Digital TV */
+ au0828_dvb_unregister(dev);
+
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+ au0828_analog_unregister(dev);
+
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+ dev->usbdev = NULL;
+ mutex_unlock(&dev->mutex);
+
+ kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ifnum, retval;
+ struct au0828_dev *dev;
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+ if (ifnum != 0)
+ return -ENODEV;
+
+ dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct),
+ ifnum);
+
+ /*
+ * Make sure we have 480 Mbps of bandwidth, otherwise things like
+ * video stream wouldn't likely work, since 12 Mbps is generally
+ * not enough even for most Digital TV streams.
+ */
+ if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+ printk(KERN_ERR "au0828: Device initialization failed.\n");
+ printk(KERN_ERR "au0828: Device must be connected to a "
+ "high-speed USB 2.0 port.\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&dev->lock);
+ mutex_lock(&dev->lock);
+ mutex_init(&dev->mutex);
+ mutex_init(&dev->dvb.lock);
+ dev->usbdev = usbdev;
+ dev->boardnr = id->driver_info;
+
+ /* Create the v4l2_device */
+ retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+ if (retval) {
+ printk(KERN_ERR "%s() v4l2_device_register failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return -EIO;
+ }
+
+ /* Power Up the bridge */
+ au0828_write(dev, REG_600, 1 << 4);
+
+ /* Bring up the GPIO's and supporting devices */
+ au0828_gpio_setup(dev);
+
+ /* I2C */
+ au0828_i2c_register(dev);
+
+ /* Setup */
+ au0828_card_setup(dev);
+
+ /* Analog TV */
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
+ au0828_analog_register(dev, interface);
+
+ /* Digital TV */
+ au0828_dvb_register(dev);
+
+ /* Store the pointer to the au0828_dev so it can be accessed in
+ au0828_usb_disconnect */
+ usb_set_intfdata(interface, dev);
+
+ printk(KERN_INFO "Registered device AU0828 [%s]\n",
+ dev->board.name == NULL ? "Unset" : dev->board.name);
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+ .name = DRIVER_NAME,
+ .probe = au0828_usb_probe,
+ .disconnect = au0828_usb_disconnect,
+ .id_table = au0828_usb_id_table,
+};
+
+static int __init au0828_init(void)
+{
+ int ret;
+
+ if (au0828_debug & 1)
+ printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 2)
+ printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 4)
+ printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 8)
+ printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+ __func__);
+
+ printk(KERN_INFO "au0828 driver loaded\n");
+
+ ret = usb_register(&au0828_usb_driver);
+ if (ret)
+ printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+ usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
new file mode 100644
index 000000000000..b328f6550d0b
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -0,0 +1,500 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+#include "mxl5007t.h"
+#include "tda18271.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static u8 hauppauge_hvr950q_led_states[] = {
+ 0x00, /* off */
+ 0x02, /* yellow */
+ 0x04, /* green */
+};
+
+static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
+ .gpio_output = 0x00e0,
+ .gpio_output_enable = 0x6006,
+ .gpio_output_disable = 0x0660,
+
+ .gpio_leds = 0x00e2,
+ .led_states = hauppauge_hvr950q_led_states,
+ .num_led_states = sizeof(hauppauge_hvr950q_led_states),
+
+ .vsb8_strong = 20 /* dB */ * 10,
+ .qam64_strong = 25 /* dB */ * 10,
+ .qam256_strong = 32 /* dB */ * 10,
+};
+
+static struct au8522_config hauppauge_hvr950q_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_6MHZ,
+ .vsb_if = AU8522_IF_6MHZ,
+ .led_cfg = &hauppauge_hvr950q_led_cfg,
+};
+
+static struct au8522_config fusionhdtv7usb_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_6MHZ,
+ .vsb_if = AU8522_IF_6MHZ,
+};
+
+static struct au8522_config hauppauge_woodbury_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_4MHZ,
+ .vsb_if = AU8522_IF_3_25MHZ,
+};
+
+static struct xc5000_config hauppauge_xc5000a_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6000,
+ .chip_id = XC5000A,
+};
+
+static struct xc5000_config hauppauge_xc5000c_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6000,
+ .chip_id = XC5000C,
+};
+
+static struct mxl5007t_config mxl5007t_hvr950q_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_6_MHZ,
+};
+
+static struct tda18271_config hauppauge_woodbury_tunerconfig = {
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
+static void au0828_restart_dvb_streaming(struct work_struct *work);
+
+/*-------------------------------------------------------------------*/
+static void urb_completion(struct urb *purb)
+{
+ struct au0828_dev *dev = purb->context;
+ int ptype = usb_pipetype(purb->pipe);
+ unsigned char *ptr;
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (!dev)
+ return;
+
+ if (dev->urb_streaming == 0)
+ return;
+
+ if (ptype != PIPE_BULK) {
+ printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ __func__, ptype);
+ return;
+ }
+
+ /* See if the stream is corrupted (to work around a hardware
+ bug where the stream gets misaligned */
+ ptr = purb->transfer_buffer;
+ if (purb->actual_length > 0 && ptr[0] != 0x47) {
+ dprintk(1, "Need to restart streaming %02x len=%d!\n",
+ ptr[0], purb->actual_length);
+ schedule_work(&dev->restart_streaming);
+ return;
+ }
+
+ /* Feed the transport payload into the kernel demux */
+ dvb_dmx_swfilter_packets(&dev->dvb.demux,
+ purb->transfer_buffer, purb->actual_length / 188);
+
+ /* Clean the buffer before we requeue */
+ memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+ /* Requeue URB */
+ usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ dev->urb_streaming = 0;
+ for (i = 0; i < URB_COUNT; i++) {
+ usb_kill_urb(dev->urbs[i]);
+ kfree(dev->urbs[i]->transfer_buffer);
+ usb_free_urb(dev->urbs[i]);
+ }
+
+ return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+ struct urb *purb;
+ int i, ret = -ENOMEM;
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (dev->urb_streaming) {
+ dprintk(2, "%s: bulk xfer already running!\n", __func__);
+ return 0;
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+
+ dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->urbs[i])
+ goto err;
+
+ purb = dev->urbs[i];
+
+ purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+ if (!purb->transfer_buffer) {
+ usb_free_urb(purb);
+ dev->urbs[i] = NULL;
+ goto err;
+ }
+
+ purb->status = -EINPROGRESS;
+ usb_fill_bulk_urb(purb,
+ dev->usbdev,
+ usb_rcvbulkpipe(dev->usbdev,
+ _AU0828_BULKPIPE),
+ purb->transfer_buffer,
+ URB_BUFSIZE,
+ urb_completion,
+ dev);
+
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+ ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+ if (ret != 0) {
+ stop_urb_transfer(dev);
+ printk(KERN_ERR "%s: failed urb submission, "
+ "err = %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ dev->urb_streaming = 1;
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (dvb->feeding++ == 0) {
+ /* Start transport */
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+ ret = start_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (--dvb->feeding == 0) {
+ /* Stop transport */
+ ret = stop_urb_transfer(dev);
+ au0828_write(dev, 0x60b, 0x00);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+static void au0828_restart_dvb_streaming(struct work_struct *work)
+{
+ struct au0828_dev *dev = container_of(work, struct au0828_dev,
+ restart_streaming);
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret;
+
+ if (dev->urb_streaming == 0)
+ return;
+
+ dprintk(1, "Restarting streaming...!\n");
+
+ mutex_lock(&dvb->lock);
+
+ /* Stop transport */
+ ret = stop_urb_transfer(dev);
+ au0828_write(dev, 0x608, 0x00);
+ au0828_write(dev, 0x609, 0x00);
+ au0828_write(dev, 0x60a, 0x00);
+ au0828_write(dev, 0x60b, 0x00);
+
+ /* Start transport */
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+ ret = start_urb_transfer(dev);
+
+ mutex_unlock(&dvb->lock);
+}
+
+static int dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int result;
+
+ dprintk(1, "%s()\n", __func__);
+
+ INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+ &dev->usbdev->dev, adapter_nr);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_adapter failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_adapter;
+ }
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_frontend failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dev;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = au0828_dvb_start_feed;
+ dvb->demux.stop_feed = au0828_dvb_stop_feed;
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+ return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb->frontend == NULL)
+ return;
+
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* init frontend */
+ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_hvr950q_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ switch (dev->board.tuner_type) {
+ default:
+ case TUNER_XC5000:
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_xc5000a_config);
+ break;
+ case TUNER_XC5000C:
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_xc5000c_config);
+ break;
+ }
+ break;
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_hvr950q_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(mxl5007t_attach, dvb->frontend,
+ &dev->i2c_adap, 0x60,
+ &mxl5007t_hvr950q_config);
+ break;
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_woodbury_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(tda18271_attach, dvb->frontend,
+ 0x60, &dev->i2c_adap,
+ &hauppauge_woodbury_tunerconfig);
+ break;
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &fusionhdtv7usb_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL) {
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_xc5000a_config);
+ }
+ break;
+ default:
+ printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+ "isn't supported yet\n");
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR "%s() Frontend initialization failed\n",
+ __func__);
+ return -1;
+ }
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = au0828_tuner_callback;
+
+ /* register everything */
+ ret = dvb_register(dev);
+ if (ret < 0) {
+ if (dvb->frontend->ops.release)
+ dvb->frontend->ops.release(dvb->frontend);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
new file mode 100644
index 000000000000..4ded17fe1957
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -0,0 +1,401 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "au0828.h"
+#include "media/tuner.h"
+#include <media/v4l2-common.h>
+
+static int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 25
+#define I2C_WAIT_RETRY 1000
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, AU0828_I2C_STATUS_201) &
+ AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, AU0828_I2C_STATUS_201) &
+ AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_slave_did_read_ack(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, AU0828_I2C_STATUS_201) &
+ AU0828_I2C_STATUS_READ_DONE ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_read_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, AU0828_I2C_STATUS_201) &
+ AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (i2c_is_write_done(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, AU0828_I2C_STATUS_201) &
+ AU0828_I2C_STATUS_BUSY ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined_rlen)
+{
+ int i, strobe = 0;
+ struct au0828_dev *dev = i2c_adap->algo_data;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+
+ /* Set the I2C clock */
+ if (((dev->board.tuner_type == TUNER_XC5000) ||
+ (dev->board.tuner_type == TUNER_XC5000C)) &&
+ (dev->board.tuner_addr == msg->addr) &&
+ (msg->len == 64)) {
+ /* Hack to speed up firmware load. The xc5000 lets us do up
+ to 400 KHz when in firmware download mode */
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+ AU0828_I2C_CLK_250KHZ);
+ } else {
+ /* Use the i2c clock speed in the board configuration */
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+ dev->board.i2c_clk_divider);
+ }
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+
+ dprintk(4, "SEND: %02x\n", msg->addr);
+
+ /* Deal with i2c_scan */
+ if (msg->len == 0) {
+ /* The analog tuner detection code makes use of the SMBUS_QUICK
+ message (which involves a zero length i2c write). To avoid
+ checking the status register when we didn't strobe out any
+ actual bytes to the bus, just do a read check. This is
+ consistent with how I saw i2c device checking done in the
+ USB trace of the Windows driver */
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_READ);
+
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ if (i2c_wait_read_ack(i2c_adap))
+ return -EIO;
+
+ return 0;
+ }
+
+ for (i = 0; i < msg->len;) {
+
+ dprintk(4, " %02x\n", msg->buf[i]);
+
+ au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
+
+ strobe++;
+ i++;
+
+ if ((strobe >= 4) || (i >= msg->len)) {
+
+ /* Strobe the byte into the bus */
+ if (i < msg->len)
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_WRITE |
+ AU0828_I2C_TRIGGER_HOLD);
+ else
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_WRITE);
+
+ /* Reset strobe trigger */
+ strobe = 0;
+
+ if (!i2c_wait_write_done(i2c_adap))
+ return -EIO;
+
+ }
+
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ int i;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+
+ /* Set the I2C clock */
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+ dev->board.i2c_clk_divider);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+
+ dprintk(4, " RECV:\n");
+
+ /* Deal with i2c_scan */
+ if (msg->len == 0) {
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_READ);
+
+ if (i2c_wait_read_ack(i2c_adap))
+ return -EIO;
+ return 0;
+ }
+
+ for (i = 0; i < msg->len;) {
+
+ i++;
+
+ if (i < msg->len)
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_READ |
+ AU0828_I2C_TRIGGER_HOLD);
+ else
+ au0828_write(dev, AU0828_I2C_TRIGGER_200,
+ AU0828_I2C_TRIGGER_READ);
+
+ if (!i2c_wait_read_done(i2c_adap))
+ return -EIO;
+
+ msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
+ 0xff;
+
+ dprintk(4, " %02x\n", msg->buf[i-1]);
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ int i, retval = 0;
+
+ dprintk(4, "%s(num = %d)\n", __func__, num);
+
+ for (i = 0; i < num; i++) {
+ dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
+ __func__, num, msgs[i].addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read */
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+ } 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);
+ if (retval < 0)
+ goto err;
+ i++;
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+ } else {
+ /* write */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+ }
+ if (retval < 0)
+ goto err;
+ }
+ return num;
+
+err:
+ return retval;
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+ .master_xfer = i2c_xfer,
+ .functionality = au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .algo = &au0828_i2c_algo_template,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+ .name = "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+ [0x8e >> 1] = "au8522",
+ [0xa0 >> 1] = "eeprom",
+ [0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
+ name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/* init + register i2c adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+ sizeof(dev->i2c_adap));
+ memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+ sizeof(dev->i2c_algo));
+ memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+ sizeof(dev->i2c_client));
+
+ dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+ strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+ sizeof(dev->i2c_adap.name));
+
+ dev->i2c_adap.algo = &dev->i2c_algo;
+ dev->i2c_adap.algo_data = dev;
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ if (0 == dev->i2c_rc) {
+ printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+ if (i2c_scan)
+ do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+ } else
+ printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+ return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
+
diff --git a/drivers/media/usb/au0828/au0828-reg.h b/drivers/media/usb/au0828/au0828-reg.h
new file mode 100644
index 000000000000..2140f4cfb645
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-reg.h
@@ -0,0 +1,66 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define AU0828_SENSORCTRL_100 0x100
+#define AU0828_SENSORCTRL_VBI_103 0x103
+
+/* I2C registers */
+#define AU0828_I2C_TRIGGER_200 0x200
+#define AU0828_I2C_STATUS_201 0x201
+#define AU0828_I2C_CLK_DIVIDER_202 0x202
+#define AU0828_I2C_DEST_ADDR_203 0x203
+#define AU0828_I2C_WRITE_FIFO_205 0x205
+#define AU0828_I2C_READ_FIFO_209 0x209
+#define AU0828_I2C_MULTIBYTE_MODE_2FF 0x2ff
+
+/* Audio registers */
+#define AU0828_AUDIOCTRL_50C 0x50C
+
+#define REG_600 0x600
+
+/*********************************************************************/
+/* Here are constants for values associated with the above registers */
+
+/* I2C Trigger (Reg 0x200) */
+#define AU0828_I2C_TRIGGER_WRITE 0x01
+#define AU0828_I2C_TRIGGER_READ 0x20
+#define AU0828_I2C_TRIGGER_HOLD 0x40
+
+/* I2C Status (Reg 0x201) */
+#define AU0828_I2C_STATUS_READ_DONE 0x01
+#define AU0828_I2C_STATUS_NO_READ_ACK 0x02
+#define AU0828_I2C_STATUS_WRITE_DONE 0x04
+#define AU0828_I2C_STATUS_NO_WRITE_ACK 0x08
+#define AU0828_I2C_STATUS_BUSY 0x10
+
+/* I2C Clock Divider (Reg 0x202) */
+#define AU0828_I2C_CLK_250KHZ 0x07
+#define AU0828_I2C_CLK_100KHZ 0x14
+#define AU0828_I2C_CLK_30KHZ 0x40
+#define AU0828_I2C_CLK_20KHZ 0x60
diff --git a/drivers/media/video/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index 63f593070ee8..63f593070ee8 100644
--- a/drivers/media/video/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
new file mode 100644
index 000000000000..fa0fa9ae91c7
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -0,0 +1,2034 @@
+/*
+ * Auvitek AU0828 USB Bridge (Analog video support)
+ *
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
+ * Copyright (C) 2005-2008 Auvitek International, Ltd.
+ *
+ * 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.
+ */
+
+/* Developer Notes:
+ *
+ * VBI support is not yet working
+ * The hardware scaler supported is unimplemented
+ * AC97 audio support is unimplemented (only i2s audio mode)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/tuner.h>
+#include "au0828.h"
+#include "au0828-reg.h"
+
+static DEFINE_MUTEX(au0828_sysfs_lock);
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define au0828_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "au0828 %s :"fmt, \
+ __func__ , ##arg); \
+ } \
+ } while (0)
+
+static inline void print_err_status(struct au0828_dev *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ au0828_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static int check_dev(struct au0828_dev *dev)
+{
+ if (dev->dev_state & DEV_DISCONNECTED) {
+ printk(KERN_INFO "v4l2 ioctl: device not present\n");
+ return -ENODEV;
+ }
+
+ if (dev->dev_state & DEV_MISCONFIGURED) {
+ printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+ "close and open it again\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void au0828_irq_callback(struct urb *urb)
+{
+ struct au0828_dmaqueue *dma_q = urb->context;
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+ unsigned long flags = 0;
+ int i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ au0828_isocdbg("au0828_irq_callback called: status kill\n");
+ return;
+ default: /* unknown error */
+ au0828_isocdbg("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock_irqsave(&dev->slock, flags);
+ dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ urb->status = 0;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ au0828_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void au0828_uninit_isoc(struct au0828_dev *dev)
+{
+ struct urb *urb;
+ int i;
+
+ au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
+
+ dev->isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+
+ if (dev->isoc_ctl.transfer_buffer[i]) {
+ usb_free_coherent(dev->usbdev,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
+ }
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
+{
+ struct au0828_dmaqueue *dma_q = &dev->vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ au0828_uninit_isoc(dev);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ au0828_isocdbg("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) {
+ au0828_isocdbg("cannot allocate memory for usb transfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->isoc_ctl.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);
+ if (!urb) {
+ au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
+ au0828_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ printk("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ au0828_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ pipe = usb_rcvisocpipe(dev->usbdev,
+ dev->isoc_in_endpointaddr),
+
+ usb_fill_int_urb(urb, dev->usbdev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ au0828_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+ k = 0;
+ for (j = 0; j < max_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;
+ }
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* 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);
+ if (rc) {
+ au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+ i, rc);
+ au0828_uninit_isoc(dev);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vbi_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void au0828_copy_video(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+
+ if (len == 0)
+ return;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ remain = len;
+
+ /* Interlaces frame */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+ offset = linesdone * bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ lencopy = remain;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp +
+ buf->vb.size) {
+ au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ if (offset > 1440) {
+ /* We have enough data to check for greenscreen */
+ if (outp[0] < 0x60 && outp[1440] < 0x60)
+ dev->greenscreen_detected = 1;
+ }
+
+ dma_q->pos += len;
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer **buf)
+{
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+
+ if (list_empty(&dma_q->active)) {
+ au0828_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ dev->isoc_ctl.buf = *buf;
+
+ return;
+}
+
+static void au0828_copy_vbi(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ unsigned char *startwrite, *startread;
+ int bytesperline;
+ int i, j = 0;
+
+ if (dev == NULL) {
+ au0828_isocdbg("dev is null\n");
+ return;
+ }
+
+ if (dma_q == NULL) {
+ au0828_isocdbg("dma_q is null\n");
+ return;
+ }
+ if (buf == NULL)
+ return;
+ if (p == NULL) {
+ au0828_isocdbg("p is null\n");
+ return;
+ }
+ if (outp == NULL) {
+ au0828_isocdbg("outp is null\n");
+ return;
+ }
+
+ bytesperline = dev->vbi_width;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ startwrite = outp + (dma_q->pos / 2);
+
+ /* Make sure the bottom field populates the second half of the frame */
+ if (buf->top_field == 0)
+ startwrite += bytesperline * dev->vbi_height;
+
+ for (i = 0; i < len; i += 2)
+ startwrite[j++] = startread[i+1];
+
+ dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer **buf)
+{
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ au0828_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vbi_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0x00, (*buf)->vb.size);
+
+ dev->isoc_ctl.vbi_buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
+{
+ struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
+ struct au0828_dmaqueue *dma_q = urb->context;
+ struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq;
+ unsigned char *outp = NULL;
+ unsigned char *vbioutp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+ unsigned char fbyte;
+ unsigned int vbi_field_size;
+ unsigned int remain, lencopy;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->dev_state & DEV_DISCONNECTED) ||
+ (dev->dev_state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ vbi_buf = dev->isoc_ctl.vbi_buf;
+ if (vbi_buf != NULL)
+ vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ if (urb->iso_frame_desc[i].actual_length <= 0)
+ continue;
+
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ au0828_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ fbyte = p[0];
+ len = urb->iso_frame_desc[i].actual_length - 4;
+ p += 4;
+
+ if (fbyte & 0x80) {
+ len -= 4;
+ p += 4;
+ au0828_isocdbg("Video frame %s\n",
+ (fbyte & 0x40) ? "odd" : "even");
+ if (fbyte & 0x40) {
+ /* VBI */
+ if (vbi_buf != NULL)
+ vbi_buffer_filled(dev,
+ vbi_dma_q,
+ vbi_buf);
+ vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+ if (vbi_buf == NULL)
+ vbioutp = NULL;
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
+
+ /* Video */
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ /* As long as isoc traffic is arriving, keep
+ resetting the timer */
+ if (dev->vid_timeout_running)
+ mod_timer(&dev->vid_timeout,
+ jiffies + (HZ / 10));
+ if (dev->vbi_timeout_running)
+ mod_timer(&dev->vbi_timeout,
+ jiffies + (HZ / 10));
+ }
+
+ if (buf != NULL) {
+ if (fbyte & 0x40)
+ buf->top_field = 1;
+ else
+ buf->top_field = 0;
+ }
+
+ if (vbi_buf != NULL) {
+ if (fbyte & 0x40)
+ vbi_buf->top_field = 1;
+ else
+ vbi_buf->top_field = 0;
+ }
+
+ dev->vbi_read = 0;
+ vbi_dma_q->pos = 0;
+ dma_q->pos = 0;
+ }
+
+ vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+ if (dev->vbi_read < vbi_field_size) {
+ remain = vbi_field_size - dev->vbi_read;
+ if (len < remain)
+ lencopy = len;
+ else
+ lencopy = remain;
+
+ if (vbi_buf != NULL)
+ au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, len);
+
+ len -= lencopy;
+ p += lencopy;
+ dev->vbi_read += lencopy;
+ }
+
+ if (dev->vbi_read >= vbi_field_size && buf != NULL)
+ au0828_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+ if (0 == *count)
+ *count = AU0828_DEF_BUF;
+
+ if (*count < AU0828_MIN_BUF)
+ *count = AU0828_MIN_BUF;
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ struct au0828_dev *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0) {
+ printk(KERN_INFO "videobuf_iolock failed\n");
+ goto fail;
+ }
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
+ AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
+ au0828_isoc_copy);
+ if (rc < 0) {
+ printk(KERN_INFO "au0828_init_isoc failed\n");
+ goto fail;
+ }
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops au0828_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ V4L2 interface
+ ------------------------------------------------------------------*/
+
+static int au0828_i2s_init(struct au0828_dev *dev)
+{
+ /* Enable i2s mode */
+ au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
+ return 0;
+}
+
+/*
+ * Auvitek au0828 analog stream enable
+ * Please set interface0 to AS5 before enable the stream
+ */
+int au0828_analog_stream_enable(struct au0828_dev *d)
+{
+ dprintk(1, "au0828_analog_stream_enable called\n");
+ au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
+ au0828_writereg(d, 0x106, 0x00);
+ /* set x position */
+ au0828_writereg(d, 0x110, 0x00);
+ au0828_writereg(d, 0x111, 0x00);
+ au0828_writereg(d, 0x114, 0xa0);
+ au0828_writereg(d, 0x115, 0x05);
+ /* set y position */
+ au0828_writereg(d, 0x112, 0x00);
+ au0828_writereg(d, 0x113, 0x00);
+ au0828_writereg(d, 0x116, 0xf2);
+ au0828_writereg(d, 0x117, 0x00);
+ au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
+
+ return 0;
+}
+
+int au0828_analog_stream_disable(struct au0828_dev *d)
+{
+ dprintk(1, "au0828_analog_stream_disable called\n");
+ au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
+ return 0;
+}
+
+void au0828_analog_stream_reset(struct au0828_dev *dev)
+{
+ dprintk(1, "au0828_analog_stream_reset called\n");
+ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
+ mdelay(30);
+ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
+}
+
+/*
+ * Some operations needs to stop current streaming
+ */
+static int au0828_stream_interrupt(struct au0828_dev *dev)
+{
+ int ret = 0;
+
+ dev->stream_state = STREAM_INTERRUPT;
+ if (dev->dev_state == DEV_DISCONNECTED)
+ return -ENODEV;
+ else if (ret) {
+ dev->dev_state = DEV_MISCONFIGURED;
+ dprintk(1, "%s device is misconfigured!\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * au0828_release_resources
+ * unregister v4l2 devices
+ */
+void au0828_analog_unregister(struct au0828_dev *dev)
+{
+ dprintk(1, "au0828_release_resources called\n");
+ mutex_lock(&au0828_sysfs_lock);
+
+ if (dev->vdev)
+ video_unregister_device(dev->vdev);
+ if (dev->vbi_dev)
+ video_unregister_device(dev->vbi_dev);
+
+ mutex_unlock(&au0828_sysfs_lock);
+}
+
+
+/* Usage lock check functions */
+static int res_get(struct au0828_fh *fh, unsigned int bit)
+{
+ struct au0828_dev *dev = fh->dev;
+
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
+
+ /* is it free? */
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ dprintk(1, "res: get %d\n", bit);
+
+ return 1;
+}
+
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
+}
+
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
+{
+ return dev->resources & bit;
+}
+
+static void res_free(struct au0828_fh *fh, unsigned int bits)
+{
+ struct au0828_dev *dev = fh->dev;
+
+ BUG_ON((fh->resources & bits) != bits);
+
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ dprintk(1, "res: put %d\n", bits);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return AU0828_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return AU0828_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* This function ensures that video frames continue to be delivered even if
+ the ITU-656 input isn't receiving any data (thereby preventing applications
+ such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vidq;
+ struct au0828_buffer *buf;
+ unsigned char *vid_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL) {
+ vid_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+ buffer_filled(dev, dma_q, buf);
+ }
+ get_next_buf(dma_q, &buf);
+
+ if (dev->vid_timeout_running == 1)
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vbiq;
+ struct au0828_buffer *buf;
+ unsigned char *vbi_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.vbi_buf;
+ if (buf != NULL) {
+ vbi_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vbi_data, 0x00, buf->vb.size);
+ vbi_buffer_filled(dev, dma_q, buf);
+ }
+ vbi_get_next_buf(dma_q, &buf);
+
+ if (dev->vbi_timeout_running == 1)
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+static int au0828_v4l2_open(struct file *filp)
+{
+ int ret = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct au0828_dev *dev = video_drvdata(filp);
+ struct au0828_fh *fh;
+ int type;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
+ type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ dprintk(1, "Failed allocate au0828_fh struct!\n");
+ return -ENOMEM;
+ }
+
+ fh->type = type;
+ fh->dev = dev;
+ filp->private_data = fh;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ /* set au0828 interface0 to AS5 here again */
+ ret = usb_set_interface(dev->usbdev, 0, 5);
+ if (ret < 0) {
+ printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+ return -EBUSY;
+ }
+ dev->width = NTSC_STD_W;
+ dev->height = NTSC_STD_H;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->width * dev->height;
+ dev->bytesperline = dev->width * 2;
+
+ au0828_analog_stream_enable(dev);
+ au0828_analog_stream_reset(dev);
+
+ /* If we were doing ac97 instead of i2s, it would go here...*/
+ au0828_i2s_init(dev);
+
+ dev->stream_state = STREAM_OFF;
+ dev->dev_state |= DEV_INITIALIZED;
+ }
+
+ dev->users++;
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct au0828_buffer), fh,
+ &dev->lock);
+
+ /* VBI Setup */
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct au0828_buffer), fh,
+ &dev->lock);
+ return ret;
+}
+
+static int au0828_v4l2_close(struct file *filp)
+{
+ int ret;
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+
+ if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
+ videobuf_stop(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ }
+
+ if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
+
+ if (dev->users == 1) {
+ if (dev->dev_state & DEV_DISCONNECTED) {
+ au0828_analog_unregister(dev);
+ kfree(dev);
+ return 0;
+ }
+
+ au0828_analog_stream_disable(dev);
+
+ au0828_uninit_isoc(dev);
+
+ /* Save some power by putting tuner to sleep */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+ /* When close the device, set the usb intf0 into alt0 to free
+ USB bandwidth */
+ ret = usb_set_interface(dev->usbdev, 0, 0);
+ if (ret < 0)
+ printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+ }
+
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ return 0;
+}
+
+static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+ return -EBUSY;
+
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return -EBUSY;
+
+ if (dev->vbi_timeout_running == 0) {
+ /* Handle case where caller tries to read without
+ calling streamon first */
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
+
+ return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
+ return 0;
+}
+
+static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+ } else {
+ return POLLERR;
+ }
+}
+
+static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct au0828_fh *fh = filp->private_data;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
+
+ return rc;
+}
+
+static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
+ struct v4l2_format *format)
+{
+ int ret;
+ int width = format->fmt.pix.width;
+ int height = format->fmt.pix.height;
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* If they are demanding a format other than the one we support,
+ bail out (tvtime asks for UYVY and then retries with YUYV) */
+ if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
+ return -EINVAL;
+
+ /* format->fmt.pix.width only support 720 and height 480 */
+ if (width != 720)
+ width = 720;
+ if (height != 480)
+ height = 480;
+
+ format->fmt.pix.width = width;
+ format->fmt.pix.height = height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ format->fmt.pix.bytesperline = width * 2;
+ format->fmt.pix.sizeimage = width * height * 2;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if (cmd == VIDIOC_TRY_FMT)
+ return 0;
+
+ /* maybe set new image format, driver current only support 720*480 */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = width * height * 2;
+ dev->field_size = width * height;
+ dev->bytesperline = width * 2;
+
+ if (dev->stream_state == STREAM_ON) {
+ dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
+ ret = au0828_stream_interrupt(dev);
+ if (ret != 0) {
+ dprintk(1, "error interrupting video stream!\n");
+ return ret;
+ }
+ }
+
+ /* set au0828 interface0 to AS5 here again */
+ ret = usb_set_interface(dev->usbdev, 0, 5);
+ if (ret < 0) {
+ printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+ return -EBUSY;
+ }
+
+ au0828_analog_stream_enable(dev);
+
+ return 0;
+}
+
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ strlcpy(cap->driver, "au0828", sizeof(cap->driver));
+ strlcpy(cap->card, dev->board.name, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+
+ /*set the device capabilities */
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(f->description, "Packed YUV2");
+
+ f->flags = 0;
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ f->fmt.pix.bytesperline = dev->bytesperline;
+ f->fmt.pix.sizeimage = dev->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ printk(KERN_INFO "%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
+
+ rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
+out:
+ return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+ /* FIXME: when we support something other than NTSC, we are going to
+ have to make the au0828 bridge adjust the size of its capture
+ buffer, which is currently hardcoded at 720x480 */
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
+ dev->std_set_in_tuner_core = 1;
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ unsigned int tmp;
+
+ static const char *inames[] = {
+ [AU0828_VMUX_UNDEFINED] = "Undefined",
+ [AU0828_VMUX_COMPOSITE] = "Composite",
+ [AU0828_VMUX_SVIDEO] = "S-Video",
+ [AU0828_VMUX_CABLE] = "Cable TV",
+ [AU0828_VMUX_TELEVISION] = "Television",
+ [AU0828_VMUX_DVB] = "DVB",
+ [AU0828_VMUX_DEBUG] = "tv debug"
+ };
+
+ tmp = input->index;
+
+ if (tmp >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(tmp).type == 0)
+ return -EINVAL;
+
+ input->index = tmp;
+ strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
+ if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
+ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+ input->type |= V4L2_INPUT_TYPE_TUNER;
+ else
+ input->type |= V4L2_INPUT_TYPE_CAMERA;
+
+ input->std = dev->vdev->tvnorms;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ *i = dev->ctrl_input;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int i;
+
+ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+ index);
+ if (index >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(index).type == 0)
+ return -EINVAL;
+ dev->ctrl_input = index;
+
+ switch (AUVI_INPUT(index).type) {
+ case AU0828_VMUX_SVIDEO:
+ dev->input_type = AU0828_VMUX_SVIDEO;
+ break;
+ case AU0828_VMUX_COMPOSITE:
+ dev->input_type = AU0828_VMUX_COMPOSITE;
+ break;
+ case AU0828_VMUX_TELEVISION:
+ dev->input_type = AU0828_VMUX_TELEVISION;
+ break;
+ default:
+ dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+ AUVI_INPUT(index).type);
+ break;
+ }
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ AUVI_INPUT(index).vmux, 0, 0);
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ int enable = 0;
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+
+ if (i == index)
+ enable = 1;
+ else
+ enable = 0;
+ if (enable) {
+ (AUVI_INPUT(i).audio_setup)(dev, enable);
+ } else {
+ /* Make sure we leave it turned on if some
+ other input is routed to this callback */
+ if ((AUVI_INPUT(i).audio_setup) !=
+ ((AUVI_INPUT(index).audio_setup))) {
+ (AUVI_INPUT(i).audio_setup)(dev, enable);
+ }
+ }
+ }
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ AUVI_INPUT(index).amux, 0, 0);
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ unsigned int index = a->index;
+
+ if (a->index > 1)
+ return -EINVAL;
+
+ index = dev->ctrl_ainput;
+ if (index == 0)
+ strcpy(a->name, "Television");
+ else
+ strcpy(a->name, "Line in");
+
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->index = index;
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ if (a->index != dev->ctrl_ainput)
+ return -EINVAL;
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ return 0;
+
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (t->index != 0)
+ return -EINVAL;
+
+ strcpy(t->name, "Auvitek tuner");
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (t->index != 0)
+ return -EINVAL;
+
+ t->type = V4L2_TUNER_ANALOG_TV;
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+ dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
+ t->afc);
+
+ return 0;
+
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ freq->frequency = dev->ctrl_freq;
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (freq->tuner != 0)
+ return -EINVAL;
+ if (freq->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+
+ dev->ctrl_freq = freq->frequency;
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+ if (dev->std_set_in_tuner_core == 0) {
+ /* If we've never sent the standard in tuner core, do so now. We
+ don't do this at device probe because we don't want to incur
+ the cost of a firmware load */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ dev->vdev->tvnorms);
+ dev->std_set_in_tuner_core = 1;
+ }
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
+ au0828_analog_stream_reset(dev);
+
+ return 0;
+}
+
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
+ format->fmt.vbi.start[0] = 21;
+ format->fmt.vbi.start[1] = 284;
+
+ return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+
+ if (v4l2_chip_match_host(&chip->match)) {
+ chip->ident = V4L2_IDENT_AU0828;
+ return 0;
+ }
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+ if (chip->ident == V4L2_IDENT_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+
+ cc->defrect = cc->bounds;
+
+ cc->pixelaspect.numerator = 54;
+ cc->pixelaspect.denominator = 59;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc = -EINVAL;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (unlikely(type != fh->type))
+ return -EINVAL;
+
+ dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ au0828_analog_stream_enable(dev);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+ }
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ rc = videobuf_streamon(&fh->vb_vidq);
+ dev->vid_timeout_running = 1;
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ rc = videobuf_streamon(&fh->vb_vbiq);
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
+
+ return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+ int i;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
+ return -EINVAL;
+
+ dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+ rc = au0828_stream_interrupt(dev);
+ if (rc != 0)
+ return rc;
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+ (AUVI_INPUT(i).audio_setup)(dev, 0);
+ }
+
+ if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ }
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
+ if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ reg->val = au0828_read(dev, reg->reg);
+ return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+ return au0828_writereg(dev, reg->reg, reg->val);
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_reqbufs(&fh->vb_vidq, rb);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
+
+ return rc;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_querybuf(&fh->vb_vidq, b);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_querybuf(&fh->vb_vbiq, b);
+
+ return rc;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_qbuf(&fh->vb_vidq, b);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_qbuf(&fh->vb_vbiq, b);
+
+ return rc;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ /* Workaround for a bug in the au0828 hardware design that sometimes
+ results in the colorspace being inverted */
+ if (dev->greenscreen_detected == 1) {
+ dprintk(1, "Detected green frame. Resetting stream...\n");
+ au0828_analog_stream_reset(dev);
+ dev->greenscreen_detected = 0;
+ }
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
+
+ return rc;
+}
+
+static struct v4l2_file_operations au0828_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = au0828_v4l2_open,
+ .release = au0828_v4l2_close,
+ .read = au0828_v4l2_read,
+ .poll = au0828_v4l2_poll,
+ .mmap = au0828_v4l2_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
+};
+
+static const struct video_device au0828_video_template = {
+ .fops = &au0828_v4l_fops,
+ .release = video_device_release,
+ .ioctl_ops = &video_ioctl_ops,
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+/**************************************************************************/
+
+int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface)
+{
+ int retval = -ENOMEM;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i, ret;
+
+ dprintk(1, "au0828_analog_register called!\n");
+
+ /* set au0828 usb interface0 to as5 */
+ retval = usb_set_interface(dev->usbdev,
+ interface->cur_altsetting->desc.bInterfaceNumber, 5);
+ if (retval != 0) {
+ printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+ return retval;
+ }
+
+ /* Figure out which endpoint has the isoc interface */
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_ISOC)) {
+
+ /* we find our isoc in endpoint */
+ u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->max_pkt_size = (tmp & 0x07ff) *
+ (((tmp & 0x1800) >> 11) + 1);
+ dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+ }
+ }
+ if (!(dev->isoc_in_endpointaddr)) {
+ printk(KERN_INFO "Could not locate isoc endpoint\n");
+ kfree(dev);
+ return -ENODEV;
+ }
+
+ init_waitqueue_head(&dev->open);
+ spin_lock_init(&dev->slock);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+ INIT_LIST_HEAD(&dev->vbiq.active);
+ INIT_LIST_HEAD(&dev->vbiq.queued);
+
+ dev->vid_timeout.function = au0828_vid_buffer_timeout;
+ dev->vid_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vid_timeout);
+
+ dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+ dev->vbi_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vbi_timeout);
+
+ dev->width = NTSC_STD_W;
+ dev->height = NTSC_STD_H;
+ dev->field_size = dev->width * dev->height;
+ dev->frame_size = dev->field_size << 1;
+ dev->bytesperline = dev->width << 1;
+ dev->ctrl_ainput = 0;
+
+ /* allocate and fill v4l2 video struct */
+ dev->vdev = video_device_alloc();
+ if (NULL == dev->vdev) {
+ dprintk(1, "Can't allocate video_device.\n");
+ return -ENOMEM;
+ }
+
+ /* allocate the VBI struct */
+ dev->vbi_dev = video_device_alloc();
+ if (NULL == dev->vbi_dev) {
+ dprintk(1, "Can't allocate vbi_device.\n");
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ /* Fill the video capture device struct */
+ *dev->vdev = au0828_video_template;
+ dev->vdev->parent = &dev->usbdev->dev;
+ dev->vdev->lock = &dev->lock;
+ strcpy(dev->vdev->name, "au0828a video");
+
+ /* Setup the VBI device */
+ *dev->vbi_dev = au0828_video_template;
+ dev->vbi_dev->parent = &dev->usbdev->dev;
+ dev->vbi_dev->lock = &dev->lock;
+ strcpy(dev->vbi_dev->name, "au0828a vbi");
+
+ /* Register the v4l2 device */
+ video_set_drvdata(dev->vdev, dev);
+ retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (retval != 0) {
+ dprintk(1, "unable to register video device (error = %d).\n",
+ retval);
+ ret = -ENODEV;
+ goto err_vbi_dev;
+ }
+
+ /* Register the vbi device */
+ video_set_drvdata(dev->vbi_dev, dev);
+ retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+ if (retval != 0) {
+ dprintk(1, "unable to register vbi device (error = %d).\n",
+ retval);
+ ret = -ENODEV;
+ goto err_vbi_dev;
+ }
+
+ dprintk(1, "%s completed!\n", __func__);
+
+ return 0;
+
+err_vbi_dev:
+ video_device_release(dev->vbi_dev);
+err_vdev:
+ video_device_release(dev->vdev);
+ return ret;
+}
+
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
new file mode 100644
index 000000000000..66a56ef7bbe4
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828.h
@@ -0,0 +1,304 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *
+ * 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/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+
+/* Analog */
+#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT 16
+#define URB_BUFSIZE (0xe522)
+
+/* Analog constants */
+#define NTSC_STD_W 720
+#define NTSC_STD_H 480
+
+#define AU0828_INTERLACED_DEFAULT 1
+#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
+
+/* Defination for AU0828 USB transfer */
+#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
+#define AU0828_ISO_PACKETS_PER_URB 128
+
+#define AU0828_MIN_BUF 4
+#define AU0828_DEF_BUF 8
+
+#define AU0828_MAX_INPUT 4
+
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI 0x02
+
+enum au0828_itype {
+ AU0828_VMUX_UNDEFINED = 0,
+ AU0828_VMUX_COMPOSITE,
+ AU0828_VMUX_SVIDEO,
+ AU0828_VMUX_CABLE,
+ AU0828_VMUX_TELEVISION,
+ AU0828_VMUX_DVB,
+ AU0828_VMUX_DEBUG
+};
+
+struct au0828_input {
+ enum au0828_itype type;
+ unsigned int vmux;
+ unsigned int amux;
+ void (*audio_setup) (void *priv, int enable);
+};
+
+struct au0828_board {
+ char *name;
+ unsigned int tuner_type;
+ unsigned char tuner_addr;
+ unsigned char i2c_clk_divider;
+ struct au0828_input input[AU0828_MAX_INPUT];
+
+};
+
+struct au0828_dvb {
+ struct mutex lock;
+ struct dvb_adapter adapter;
+ struct dvb_frontend *frontend;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+ int feeding;
+};
+
+enum au0828_stream_state {
+ STREAM_OFF,
+ STREAM_INTERRUPT,
+ STREAM_ON
+};
+
+#define AUVI_INPUT(nr) (dev->board.input[nr])
+
+/* device state */
+enum au0828_dev_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04
+};
+
+struct au0828_fh {
+ struct au0828_dev *dev;
+ unsigned int resources;
+
+ struct videobuf_queue vb_vidq;
+ struct videobuf_queue vb_vbiq;
+ enum v4l2_buf_type type;
+};
+
+struct au0828_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
+
+};
+
+/* buffer for one video frame */
+struct au0828_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ struct list_head frame;
+ int top_field;
+ int receiving;
+};
+
+struct au0828_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
+};
+
+struct au0828_dev {
+ struct mutex mutex;
+ struct usb_device *usbdev;
+ int boardnr;
+ struct au0828_board board;
+ u8 ctrlmsg[64];
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algorithm i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* Digital */
+ struct au0828_dvb dvb;
+ struct work_struct restart_streaming;
+
+ /* Analog */
+ struct v4l2_device v4l2_dev;
+ int users;
+ unsigned int resources; /* resources in use */
+ struct video_device *vdev;
+ struct video_device *vbi_dev;
+ struct timer_list vid_timeout;
+ int vid_timeout_running;
+ struct timer_list vbi_timeout;
+ int vbi_timeout_running;
+ int width;
+ int height;
+ int vbi_width;
+ int vbi_height;
+ u32 vbi_read;
+ u32 field_size;
+ u32 frame_size;
+ u32 bytesperline;
+ int type;
+ u8 ctrl_ainput;
+ __u8 isoc_in_endpointaddr;
+ u8 isoc_init_ok;
+ int greenscreen_detected;
+ unsigned int frame_count;
+ int ctrl_freq;
+ int input_type;
+ int std_set_in_tuner_core;
+ unsigned int ctrl_input;
+ enum au0828_dev_state dev_state;
+ enum au0828_stream_state stream_state;
+ wait_queue_head_t open;
+
+ struct mutex lock;
+
+ /* Isoc control struct */
+ struct au0828_dmaqueue vidq;
+ struct au0828_dmaqueue vbiq;
+ struct au0828_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
+ /* usb transfer */
+ int alt; /* alternate */
+ 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[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
+ char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
+ transfer */
+
+ /* USB / URB Related */
+ int urb_streaming;
+ struct urb *urbs[URB_COUNT];
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) \
+ au0828_writereg(dev, reg, \
+ (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern int au0828_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int component,
+ int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-video.c */
+int au0828_analog_register(struct au0828_dev *dev,
+ struct usb_interface *interface);
+int au0828_analog_stream_disable(struct au0828_dev *d);
+void au0828_analog_unregister(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
+#define dprintk(level, fmt, arg...)\
+ do { if (au0828_debug & level)\
+ printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+ } while (0)
diff --git a/drivers/media/usb/b2c2/Kconfig b/drivers/media/usb/b2c2/Kconfig
new file mode 100644
index 000000000000..17d35833980c
--- /dev/null
+++ b/drivers/media/usb/b2c2/Kconfig
@@ -0,0 +1,15 @@
+config DVB_B2C2_FLEXCOP_USB
+ tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
+ depends on DVB_CORE && I2C
+ help
+ Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_USB_DEBUG
+ bool "Enable debug for the B2C2 FlexCop drivers"
+ depends on DVB_B2C2_FLEXCOP_USB
+ select DVB_B2C2_FLEXCOP_DEBUG
+ help
+ Say Y if you want to enable the module option to control debug messages
+ of all B2C2 FlexCop drivers.
diff --git a/drivers/media/usb/b2c2/Makefile b/drivers/media/usb/b2c2/Makefile
new file mode 100644
index 000000000000..2778c19a45eb
--- /dev/null
+++ b/drivers/media/usb/b2c2/Makefile
@@ -0,0 +1,5 @@
+b2c2-flexcop-usb-objs := flexcop-usb.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/common/b2c2/
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
new file mode 100644
index 000000000000..8b6275f85908
--- /dev/null
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -0,0 +1,587 @@
+/*
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-usb.c - covers the USB part
+ * see flexcop.c for copyright information
+ */
+#define FC_LOG_PREFIX "flexcop_usb"
+#include "flexcop-usb.h"
+#include "flexcop-common.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+ do { if ((debug & level)) printk(args); } while (0)
+
+#define debug_dump(b, l, method) do {\
+ int i; \
+ for (i = 0; i < l; i++) \
+ method("%02x ", b[i]); \
+ method("\n"); \
+} while (0)
+
+#define DEBSTATUS ""
+#else
+#define dprintk(level, args...)
+#define debug_dump(b, l, method)
+#define DEBSTATUS " (debugging is not enabled)"
+#endif
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
+ "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+#undef DEBSTATUS
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_ts(args...) dprintk(0x02, args)
+#define deb_ctrl(args...) dprintk(0x04, args)
+#define deb_i2c(args...) dprintk(0x08, args)
+#define deb_v8(args...) dprintk(0x10, args)
+
+/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
+ * in the IBI address, to make the V8 code simpler.
+ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
+ * in general: 0000 0HHH 000L LL00
+ * IBI ADDRESS FORMAT: RHHH BLLL
+ *
+ * where R is the read(1)/write(0) bit, B is the busy bit
+ * and HHH and LLL are the two sets of three bits from the PCI address.
+ */
+#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
+ (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
+ (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+
+/*
+ * DKT 020228
+ * - forget about this VENDOR_BUFFER_SIZE, read and write register
+ * deal with DWORD or 4 bytes, that should be should from now on
+ * - from now on, we don't support anything older than firm 1.00
+ * I eliminated the write register as a 2 trip of writing hi word and lo word
+ * and force this to write only 4 bytes at a time.
+ * NOTE: this should work with all the firmware from 1.00 and newer
+ */
+static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
+{
+ struct flexcop_usb *fc_usb = fc->bus_specific;
+ u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
+ u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
+ u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
+ (read ? 0x80 : 0);
+
+ int len = usb_control_msg(fc_usb->udev,
+ read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
+ request,
+ request_type, /* 0xc0 read or 0x40 write */
+ wAddress,
+ 0,
+ val,
+ sizeof(u32),
+ B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+ if (len != sizeof(u32)) {
+ err("error while %s dword from %d (%d).", read ? "reading" :
+ "writing", wAddress, wRegOffsPCI);
+ return -EIO;
+ }
+ return 0;
+}
+/*
+ * DKT 010817 - add support for V8 memory read/write and flash update
+ */
+static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
+ flexcop_usb_request_t req, u8 page, u16 wAddress,
+ u8 *pbBuffer, u32 buflen)
+{
+ u8 request_type = USB_TYPE_VENDOR;
+ u16 wIndex;
+ int nWaitTime, pipe, len;
+ wIndex = page << 8;
+
+ switch (req) {
+ case B2C2_USB_READ_V8_MEM:
+ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+ request_type |= USB_DIR_IN;
+ pipe = B2C2_USB_CTRL_PIPE_IN;
+ break;
+ case B2C2_USB_WRITE_V8_MEM:
+ wIndex |= pbBuffer[0];
+ request_type |= USB_DIR_OUT;
+ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+ pipe = B2C2_USB_CTRL_PIPE_OUT;
+ break;
+ case B2C2_USB_FLASH_BLOCK:
+ request_type |= USB_DIR_OUT;
+ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+ pipe = B2C2_USB_CTRL_PIPE_OUT;
+ break;
+ default:
+ deb_info("unsupported request for v8_mem_req %x.\n", req);
+ return -EINVAL;
+ }
+ deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
+ wAddress, wIndex, buflen);
+
+ len = usb_control_msg(fc_usb->udev, pipe,
+ req,
+ request_type,
+ wAddress,
+ wIndex,
+ pbBuffer,
+ buflen,
+ nWaitTime * HZ);
+
+ debug_dump(pbBuffer, len, deb_v8);
+ return len == buflen ? 0 : -EIO;
+}
+
+#define bytes_left_to_read_on_page(paddr,buflen) \
+ ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
+ ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
+
+static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
+ flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
+ u32 addr, int extended, u8 *buf, u32 len)
+{
+ int i,ret = 0;
+ u16 wMax;
+ u32 pagechunk = 0;
+
+ switch(req) {
+ case B2C2_USB_READ_V8_MEM:
+ wMax = USB_MEM_READ_MAX;
+ break;
+ case B2C2_USB_WRITE_V8_MEM:
+ wMax = USB_MEM_WRITE_MAX;
+ break;
+ case B2C2_USB_FLASH_BLOCK:
+ wMax = USB_FLASH_MAX;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ for (i = 0; i < len;) {
+ pagechunk =
+ wMax < bytes_left_to_read_on_page(addr, len) ?
+ wMax :
+ bytes_left_to_read_on_page(addr, len);
+ deb_info("%x\n",
+ (addr & V8_MEMORY_PAGE_MASK) |
+ (V8_MEMORY_EXTENDED*extended));
+
+ ret = flexcop_usb_v8_memory_req(fc_usb, req,
+ page_start + (addr / V8_MEMORY_PAGE_SIZE),
+ (addr & V8_MEMORY_PAGE_MASK) |
+ (V8_MEMORY_EXTENDED*extended),
+ &buf[i], pagechunk);
+
+ if (ret < 0)
+ return ret;
+ addr += pagechunk;
+ len -= pagechunk;
+ }
+ return 0;
+}
+
+static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
+{
+ return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
+ V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
+ fc->dvb_adapter.proposed_mac, 6);
+}
+
+#if 0
+static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
+ flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
+ u16 buflen, u8 *pvBuffer)
+{
+ u16 wValue;
+ u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
+ int nWaitTime = 2,
+ pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
+ wValue = (func << 8) | extra;
+
+ len = usb_control_msg(fc_usb->udev,pipe,
+ B2C2_USB_UTILITY,
+ request_type,
+ wValue,
+ wIndex,
+ pvBuffer,
+ buflen,
+ nWaitTime * HZ);
+ return len == buflen ? 0 : -EIO;
+}
+#endif
+
+/* usb i2c stuff */
+static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
+ flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
+ u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
+{
+ struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
+ u16 wValue, wIndex;
+ int nWaitTime,pipe,len;
+ u8 request_type = USB_TYPE_VENDOR;
+
+ switch (func) {
+ case USB_FUNC_I2C_WRITE:
+ case USB_FUNC_I2C_MULTIWRITE:
+ case USB_FUNC_I2C_REPEATWRITE:
+ /* DKT 020208 - add this to support special case of DiSEqC */
+ case USB_FUNC_I2C_CHECKWRITE:
+ pipe = B2C2_USB_CTRL_PIPE_OUT;
+ nWaitTime = 2;
+ request_type |= USB_DIR_OUT;
+ break;
+ case USB_FUNC_I2C_READ:
+ case USB_FUNC_I2C_REPEATREAD:
+ pipe = B2C2_USB_CTRL_PIPE_IN;
+ nWaitTime = 2;
+ request_type |= USB_DIR_IN;
+ break;
+ default:
+ deb_info("unsupported function for i2c_req %x\n", func);
+ return -EINVAL;
+ }
+ wValue = (func << 8) | (i2c->port << 4);
+ wIndex = (chipaddr << 8 ) | addr;
+
+ deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
+ func, request_type, req,
+ wValue & 0xff, wValue >> 8,
+ wIndex & 0xff, wIndex >> 8);
+
+ len = usb_control_msg(fc_usb->udev,pipe,
+ req,
+ request_type,
+ wValue,
+ wIndex,
+ buf,
+ buflen,
+ nWaitTime * HZ);
+ return len == buflen ? 0 : -EREMOTEIO;
+}
+
+/* actual bus specific access functions,
+ make sure prototype are/will be equal to pci */
+static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
+ flexcop_ibi_register reg)
+{
+ flexcop_ibi_value val;
+ val.raw = 0;
+ flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
+ return val;
+}
+
+static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
+ flexcop_ibi_register reg, flexcop_ibi_value val)
+{
+ return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
+}
+
+static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
+ flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+{
+ if (op == FC_READ)
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+ USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
+ else
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+ USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
+}
+
+static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
+ u8 *buffer, int buffer_length)
+{
+ u8 *b;
+ int l;
+
+ deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
+ fc_usb->tmp_buffer_length, buffer_length);
+
+ if (fc_usb->tmp_buffer_length > 0) {
+ memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
+ buffer_length);
+ fc_usb->tmp_buffer_length += buffer_length;
+ b = fc_usb->tmp_buffer;
+ l = fc_usb->tmp_buffer_length;
+ } else {
+ b=buffer;
+ l=buffer_length;
+ }
+
+ while (l >= 190) {
+ if (*b == 0xff) {
+ switch (*(b+1) & 0x03) {
+ case 0x01: /* media packet */
+ if (*(b+2) == 0x47)
+ flexcop_pass_dmx_packets(
+ fc_usb->fc_dev, b+2, 1);
+ else
+ deb_ts("not ts packet %*ph\n", 4, b+2);
+ b += 190;
+ l -= 190;
+ break;
+ default:
+ deb_ts("wrong packet type\n");
+ l = 0;
+ break;
+ }
+ } else {
+ deb_ts("wrong header\n");
+ l = 0;
+ }
+ }
+
+ if (l>0)
+ memcpy(fc_usb->tmp_buffer, b, l);
+ fc_usb->tmp_buffer_length = l;
+}
+
+static void flexcop_usb_urb_complete(struct urb *urb)
+{
+ struct flexcop_usb *fc_usb = urb->context;
+ int i;
+
+ if (urb->actual_length > 0)
+ deb_ts("urb completed, bufsize: %d actlen; %d\n",
+ urb->transfer_buffer_length, urb->actual_length);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ err("iso frame descriptor %d has an error: %d\n", i,
+ urb->iso_frame_desc[i].status);
+ } else
+ if (urb->iso_frame_desc[i].actual_length > 0) {
+ deb_ts("passed %d bytes to the demux\n",
+ urb->iso_frame_desc[i].actual_length);
+
+ flexcop_usb_process_frame(fc_usb,
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
+{
+ /* submit/kill iso packets */
+ return 0;
+}
+
+static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
+{
+ int i;
+ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+ if (fc_usb->iso_urb[i] != NULL) {
+ deb_ts("unlinking/killing urb no. %d\n",i);
+ usb_kill_urb(fc_usb->iso_urb[i]);
+ usb_free_urb(fc_usb->iso_urb[i]);
+ }
+
+ if (fc_usb->iso_buffer != NULL)
+ pci_free_consistent(NULL,
+ fc_usb->buffer_size, fc_usb->iso_buffer,
+ fc_usb->dma_addr);
+}
+
+static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
+{
+ u16 frame_size = le16_to_cpu(
+ fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
+ int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
+ frame_size, i, j, ret;
+ int buffer_offset = 0;
+
+ deb_ts("creating %d iso-urbs with %d frames "
+ "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
+ B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
+
+ fc_usb->iso_buffer = pci_alloc_consistent(NULL,
+ bufsize, &fc_usb->dma_addr);
+ if (fc_usb->iso_buffer == NULL)
+ return -ENOMEM;
+
+ memset(fc_usb->iso_buffer, 0, bufsize);
+ fc_usb->buffer_size = bufsize;
+
+ /* creating iso urbs */
+ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+ fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
+ GFP_ATOMIC);
+ if (fc_usb->iso_urb[i] == NULL) {
+ ret = -ENOMEM;
+ goto urb_error;
+ }
+ }
+
+ /* initialising and submitting iso urbs */
+ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+ int frame_offset = 0;
+ struct urb *urb = fc_usb->iso_urb[i];
+ deb_ts("initializing and submitting urb no. %d "
+ "(buf_offset: %d).\n", i, buffer_offset);
+
+ urb->dev = fc_usb->udev;
+ urb->context = fc_usb;
+ urb->complete = flexcop_usb_urb_complete;
+ urb->pipe = B2C2_USB_DATA_PIPE;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
+ urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
+ urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
+
+ buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
+ for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
+ deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
+ i, j, frame_offset);
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length = frame_size;
+ frame_offset += frame_size;
+ }
+
+ if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+ err("submitting urb %d failed with %d.", i, ret);
+ goto urb_error;
+ }
+ deb_ts("submitted urb no. %d.\n",i);
+ }
+
+ /* SRAM */
+ flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
+ FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
+ FC_SRAM_DEST_TARGET_WAN_USB);
+ flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
+ flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
+ return 0;
+
+urb_error:
+ flexcop_usb_transfer_exit(fc_usb);
+ return ret;
+}
+
+static int flexcop_usb_init(struct flexcop_usb *fc_usb)
+{
+ /* use the alternate setting with the larges buffer */
+ usb_set_interface(fc_usb->udev,0,1);
+ switch (fc_usb->udev->speed) {
+ case USB_SPEED_LOW:
+ err("cannot handle USB speed because it is too slow.");
+ return -ENODEV;
+ break;
+ case USB_SPEED_FULL:
+ info("running at FULL speed.");
+ break;
+ case USB_SPEED_HIGH:
+ info("running at HIGH speed.");
+ break;
+ case USB_SPEED_UNKNOWN: /* fall through */
+ default:
+ err("cannot handle USB speed because it is unknown.");
+ return -ENODEV;
+ }
+ usb_set_intfdata(fc_usb->uintf, fc_usb);
+ return 0;
+}
+
+static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
+{
+ usb_set_intfdata(fc_usb->uintf, NULL);
+}
+
+static int flexcop_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct flexcop_usb *fc_usb = NULL;
+ struct flexcop_device *fc = NULL;
+ int ret;
+
+ if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
+ err("out of memory\n");
+ return -ENOMEM;
+ }
+
+ /* general flexcop init */
+ fc_usb = fc->bus_specific;
+ fc_usb->fc_dev = fc;
+
+ fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
+ fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
+ fc->i2c_request = flexcop_usb_i2c_request;
+ fc->get_mac_addr = flexcop_usb_get_mac_addr;
+
+ fc->stream_control = flexcop_usb_stream_control;
+
+ fc->pid_filtering = 1;
+ fc->bus_type = FC_USB;
+
+ fc->dev = &udev->dev;
+ fc->owner = THIS_MODULE;
+
+ /* bus specific part */
+ fc_usb->udev = udev;
+ fc_usb->uintf = intf;
+ if ((ret = flexcop_usb_init(fc_usb)) != 0)
+ goto err_kfree;
+
+ /* init flexcop */
+ if ((ret = flexcop_device_initialize(fc)) != 0)
+ goto err_usb_exit;
+
+ /* xfer init */
+ if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
+ goto err_fc_exit;
+
+ info("%s successfully initialized and connected.", DRIVER_NAME);
+ return 0;
+
+err_fc_exit:
+ flexcop_device_exit(fc);
+err_usb_exit:
+ flexcop_usb_exit(fc_usb);
+err_kfree:
+ flexcop_device_kfree(fc);
+ return ret;
+}
+
+static void flexcop_usb_disconnect(struct usb_interface *intf)
+{
+ struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
+ flexcop_usb_transfer_exit(fc_usb);
+ flexcop_device_exit(fc_usb->fc_dev);
+ flexcop_usb_exit(fc_usb);
+ flexcop_device_kfree(fc_usb->fc_dev);
+ info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
+}
+
+static struct usb_device_id flexcop_usb_table [] = {
+ { USB_DEVICE(0x0af7, 0x0101) },
+ { }
+};
+MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver flexcop_usb_driver = {
+ .name = "b2c2_flexcop_usb",
+ .probe = flexcop_usb_probe,
+ .disconnect = flexcop_usb_disconnect,
+ .id_table = flexcop_usb_table,
+};
+
+module_usb_driver(flexcop_usb_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/usb/b2c2/flexcop-usb.h
index 92529a9c4475..92529a9c4475 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.h
+++ b/drivers/media/usb/b2c2/flexcop-usb.h
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/usb/cpia2/Kconfig
index 66e9283f5993..66e9283f5993 100644
--- a/drivers/media/video/cpia2/Kconfig
+++ b/drivers/media/usb/cpia2/Kconfig
diff --git a/drivers/media/video/cpia2/Makefile b/drivers/media/usb/cpia2/Makefile
index 828cf1b1df86..828cf1b1df86 100644
--- a/drivers/media/video/cpia2/Makefile
+++ b/drivers/media/usb/cpia2/Makefile
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/usb/cpia2/cpia2.h
index cdef677d57ec..cdef677d57ec 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/usb/cpia2/cpia2.h
diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/media/usb/cpia2/cpia2_core.c
new file mode 100644
index 000000000000..187012ce444b
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_core.c
@@ -0,0 +1,2417 @@
+/****************************************************************************
+ *
+ * Filename: cpia2_core.c
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This is a USB driver for CPia2 based video cameras.
+ * The infrastructure of this driver is based on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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.
+ *
+ * Stripped of 2.4 stuff ready for main kernel submit by
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ ****************************************************************************/
+
+#include "cpia2.h"
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#define FIRMWARE "cpia2/stv0672_vp4.bin"
+MODULE_FIRMWARE(FIRMWARE);
+
+/* #define _CPIA2_DEBUG_ */
+
+#ifdef _CPIA2_DEBUG_
+
+static const char *block_name[] = {
+ "System",
+ "VC",
+ "VP",
+ "IDATA"
+};
+#endif
+
+static unsigned int debugs_on; /* default 0 - DEBUG_REG */
+
+
+/******************************************************************************
+ *
+ * Forward Declarations
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam);
+static int set_default_user_mode(struct camera_data *cam);
+static int set_vw_size(struct camera_data *cam, int size);
+static int configure_sensor(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int config_sensor_410(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int config_sensor_500(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int set_all_properties(struct camera_data *cam);
+static void wake_system(struct camera_data *cam);
+static void set_lowlight_boost(struct camera_data *cam);
+static void reset_camera_struct(struct camera_data *cam);
+static int cpia2_set_high_power(struct camera_data *cam);
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+ kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+ ret = __pa(kva);
+ return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+ /* Round it off to PAGE_SIZE */
+ size = PAGE_ALIGN(size);
+
+ mem = vmalloc_32(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+
+ while ((long)size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ size = PAGE_ALIGN(size);
+
+ adr = (unsigned long) mem;
+ while ((long)size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
+}
+
+/******************************************************************************
+ *
+ * cpia2_do_command
+ *
+ * Send an arbitrary command to the camera. For commands that read from
+ * the camera, copy the buffers into the proper param structures.
+ *****************************************************************************/
+int cpia2_do_command(struct camera_data *cam,
+ u32 command, u8 direction, u8 param)
+{
+ int retval = 0;
+ struct cpia2_command cmd;
+ unsigned int device = cam->params.pnp_id.device_type;
+
+ cmd.command = command;
+ cmd.reg_count = 2; /* default */
+ cmd.direction = direction;
+
+ /***
+ * Set up the command.
+ ***/
+ switch (command) {
+ case CPIA2_CMD_GET_VERSION:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.start = CPIA2_SYSTEM_DEVICE_HI;
+ break;
+ case CPIA2_CMD_GET_PNP_ID:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 8;
+ cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
+ break;
+ case CPIA2_CMD_GET_ASIC_TYPE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.start = CPIA2_VC_ASIC_ID;
+ break;
+ case CPIA2_CMD_GET_SENSOR:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.start = CPIA2_VP_SENSOR_FLAGS;
+ break;
+ case CPIA2_CMD_GET_VP_DEVICE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.start = CPIA2_VP_DEVICEH;
+ break;
+ case CPIA2_CMD_SET_VP_BRIGHTNESS:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_BRIGHTNESS:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
+ else
+ cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+ break;
+ case CPIA2_CMD_SET_CONTRAST:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_CONTRAST:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_YRANGE;
+ break;
+ case CPIA2_CMD_SET_VP_SATURATION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_SATURATION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP_SATURATION;
+ else
+ cmd.start = CPIA2_VP5_MCUVSATURATION;
+ break;
+ case CPIA2_CMD_SET_VP_GPIO_DATA:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_GPIO_DATA:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_GPIO_DATA;
+ break;
+ case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_GPIO_DIRECTION;
+ break;
+ case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_MP_DATA;
+ break;
+ case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_MP_DIR;
+ break;
+ case CPIA2_CMD_ENABLE_PACKET_CTRL:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
+ cmd.reg_count = 1;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_FLICKER_MODES:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_FLICKER_MODES:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_FLICKER_MODES;
+ break;
+ case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 2;
+ cmd.start = 0;
+ cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+ cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB |
+ CPIA2_VC_ST_CTRL_EOF_DETECT |
+ CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+ break;
+ case CPIA2_CMD_SET_HI_POWER:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 2;
+ cmd.buffer.registers[0].index =
+ CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.registers[1].index =
+ CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+ cmd.buffer.registers[1].value =
+ CPIA2_SYSTEM_CONTROL_HIGH_POWER;
+ break;
+ case CPIA2_CMD_SET_LOW_POWER:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.block_data[0] = 0;
+ break;
+ case CPIA2_CMD_CLEAR_V2W_ERR:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+ break;
+ case CPIA2_CMD_SET_USER_MODE: /* Then fall through */
+ cmd.buffer.block_data[0] = param;
+ case CPIA2_CMD_GET_USER_MODE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_USER_MODE;
+ else
+ cmd.start = CPIA2_VP5_USER_MODE;
+ break;
+ case CPIA2_CMD_FRAMERATE_REQ:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
+ else
+ cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_WAKEUP:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_WAKEUP:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_WAKEUP;
+ break;
+ case CPIA2_CMD_SET_PW_CONTROL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_PW_CONTROL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_PW_CTRL;
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_SYSTEMSTATE;
+ break;
+ case CPIA2_CMD_SET_SYSTEM_CTRL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_SYSTEM_CTRL:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ break;
+ case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_SYSTEMCTRL;
+ break;
+ case CPIA2_CMD_SET_VP_EXP_MODES:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_EXP_MODES:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_EXPOSURE_MODES;
+ break;
+ case CPIA2_CMD_SET_DEVICE_CONFIG:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_DEVICE_CONFIG:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_DEVICE_CONFIG;
+ break;
+ case CPIA2_CMD_SET_SERIAL_ADDR:
+ cmd.buffer.block_data[0] = param;
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
+ break;
+ case CPIA2_CMD_SET_SENSOR_CR1:
+ cmd.buffer.block_data[0] = param;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SENSOR_CR1;
+ break;
+ case CPIA2_CMD_SET_VC_CONTROL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_CONTROL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_VC_CTRL;
+ break;
+ case CPIA2_CMD_SET_TARGET_KB:
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
+ cmd.buffer.registers[0].value = param;
+ break;
+ case CPIA2_CMD_SET_DEF_JPEG_OPT:
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 4;
+ cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
+ cmd.buffer.registers[0].value =
+ CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
+ cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
+ cmd.buffer.registers[1].value = 20;
+ cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
+ cmd.buffer.registers[2].value = 2;
+ cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
+ cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+ break;
+ case CPIA2_CMD_REHASH_VP4:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_REHASH_VALUES;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as
+ this register can also affect
+ flicker modes */
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_USER_EFFECTS:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_USER_EFFECTS;
+ else
+ cmd.start = CPIA2_VP5_USER_EFFECTS;
+ break;
+ default:
+ LOG("DoCommand received invalid command\n");
+ return -EINVAL;
+ }
+
+ retval = cpia2_send_command(cam, &cmd);
+ if (retval) {
+ return retval;
+ }
+
+ /***
+ * Now copy any results from a read into the appropriate param struct.
+ ***/
+ switch (command) {
+ case CPIA2_CMD_GET_VERSION:
+ cam->params.version.firmware_revision_hi =
+ cmd.buffer.block_data[0];
+ cam->params.version.firmware_revision_lo =
+ cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_PNP_ID:
+ cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
+ cmd.buffer.block_data[1];
+ cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
+ cmd.buffer.block_data[3];
+ cam->params.pnp_id.device_revision =
+ (cmd.buffer.block_data[4] << 8) |
+ cmd.buffer.block_data[5];
+ if (cam->params.pnp_id.vendor == 0x553) {
+ if (cam->params.pnp_id.product == 0x100) {
+ cam->params.pnp_id.device_type = DEVICE_STV_672;
+ } else if (cam->params.pnp_id.product == 0x140 ||
+ cam->params.pnp_id.product == 0x151) {
+ cam->params.pnp_id.device_type = DEVICE_STV_676;
+ }
+ }
+ break;
+ case CPIA2_CMD_GET_ASIC_TYPE:
+ cam->params.version.asic_id = cmd.buffer.block_data[0];
+ cam->params.version.asic_rev = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_SENSOR:
+ cam->params.version.sensor_flags = cmd.buffer.block_data[0];
+ cam->params.version.sensor_rev = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_VP_DEVICE:
+ cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
+ cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_VP_GPIO_DATA:
+ cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+ cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+ cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+ cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_FLICKER_MODES:
+ cam->params.flicker_control.cam_register =
+ cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_WAKEUP:
+ cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_PW_CONTROL:
+ cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_SYSTEM_CTRL:
+ cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+ cam->params.vp_params.system_state = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+ cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_EXP_MODES:
+ cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_DEVICE_CONFIG:
+ cam->params.vp_params.device_config = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_CONTROL:
+ cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_USER_MODE:
+ cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_USER_EFFECTS:
+ cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_send_command
+ *
+ *****************************************************************************/
+
+#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read")
+#define BINDEX(cmd) (cmd->req_mode & 0x03)
+
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
+{
+ u8 count;
+ u8 start;
+ u8 *buffer;
+ int retval;
+
+ switch (cmd->req_mode & 0x0c) {
+ case CAMERAACCESS_TYPE_RANDOM:
+ count = cmd->reg_count * sizeof(struct cpia2_register);
+ start = 0;
+ buffer = (u8 *) & cmd->buffer;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Random: Register block %s\n", DIR(cmd),
+ block_name[BINDEX(cmd)]);
+ break;
+ case CAMERAACCESS_TYPE_BLOCK:
+ count = cmd->reg_count;
+ start = cmd->start;
+ buffer = cmd->buffer.block_data;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Block: Register block %s\n", DIR(cmd),
+ block_name[BINDEX(cmd)]);
+ break;
+ case CAMERAACCESS_TYPE_MASK:
+ count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
+ start = 0;
+ buffer = (u8 *) & cmd->buffer;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Mask: Register block %s\n", DIR(cmd),
+ block_name[BINDEX(cmd)]);
+ break;
+ case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */
+ count = cmd->reg_count;
+ start = cmd->start;
+ buffer = cmd->buffer.block_data;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Repeat: Register block %s\n", DIR(cmd),
+ block_name[BINDEX(cmd)]);
+ break;
+ default:
+ LOG("%s: invalid request mode\n",__func__);
+ return -EINVAL;
+ }
+
+ retval = cpia2_usb_transfer_cmd(cam,
+ buffer,
+ cmd->req_mode,
+ start, count, cmd->direction);
+#ifdef _CPIA2_DEBUG_
+ if (debugs_on & DEBUG_REG) {
+ int i;
+ for (i = 0; i < cmd->reg_count; i++) {
+ if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
+ KINFO("%s Block: [0x%02X] = 0x%02X\n",
+ DIR(cmd), start + i, buffer[i]);
+ if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
+ KINFO("%s Random: [0x%02X] = 0x%02X\n",
+ DIR(cmd), cmd->buffer.registers[i].index,
+ cmd->buffer.registers[i].value);
+ }
+ }
+#endif
+
+ return retval;
+};
+
+/*************
+ * Functions to implement camera functionality
+ *************/
+/******************************************************************************
+ *
+ * cpia2_get_version_info
+ *
+ *****************************************************************************/
+static void cpia2_get_version_info(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ * cpia2_reset_camera
+ *
+ * Called at least during the open process, sets up initial params.
+ *****************************************************************************/
+int cpia2_reset_camera(struct camera_data *cam)
+{
+ u8 tmp_reg;
+ int retval = 0;
+ int target_kb;
+ int i;
+ struct cpia2_command cmd;
+
+ /***
+ * VC setup
+ ***/
+ retval = configure_sensor(cam,
+ cam->params.roi.width,
+ cam->params.roi.height);
+ if (retval < 0) {
+ ERR("Couldn't configure sensor, error=%d\n", retval);
+ return retval;
+ }
+
+ /* Clear FIFO and route/enable stream block */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+ cmd.reg_count = 2;
+ cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+ cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB |
+ CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+
+ cpia2_send_command(cam, &cmd);
+
+ cpia2_set_high_power(cam);
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ /* Enable button notification */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+ cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
+ cmd.buffer.registers[0].value =
+ CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ retval = apply_vp_patch(cam);
+
+ /* wait for vp to go to sleep */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ /***
+ * If this is a 676, apply VP5 fixes before we start streaming
+ ***/
+ if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+
+ /* The following writes improve the picture */
+ cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
+ cmd.buffer.registers[0].value = 0; /* reduce from the default
+ * rec 601 pedestal of 16 */
+ cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
+ cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
+ * (256/256 - 31) to fill
+ * available range */
+ cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
+ cmd.buffer.registers[2].value = 0xFF; /* Increase from the
+ * default rec 601 ceiling
+ * of 240 */
+ cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
+ cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
+ * 601 100% level (128)
+ * to 145-192 */
+ cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
+ cmd.buffer.registers[4].value = 0x80; /* Inhibit the
+ * anti-flicker */
+
+ /* The following 4 writes are a fix to allow QVGA to work at 30 fps */
+ cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
+ cmd.buffer.registers[5].value = 0x01;
+ cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
+ cmd.buffer.registers[6].value = 0xE3;
+ cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
+ cmd.buffer.registers[7].value = 0x02;
+ cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
+ cmd.buffer.registers[8].value = 0xFC;
+
+ cmd.direction = TRANSFER_WRITE;
+ cmd.reg_count = 9;
+
+ cpia2_send_command(cam, &cmd);
+ }
+
+ /* Activate all settings and start the data stream */
+ /* Set user mode */
+ set_default_user_mode(cam);
+
+ /* Give VP time to wake up */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ set_all_properties(cam);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+ DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
+ cam->params.vp_params.video_mode);
+
+ /***
+ * Set audio regulator off. This and the code to set the compresison
+ * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
+ * intertwined. This stuff came straight from the windows driver.
+ ***/
+ /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+ tmp_reg = cam->params.vp_params.system_ctrl;
+ cmd.buffer.registers[0].value = tmp_reg &
+ (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+ cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
+ CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
+ cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
+ cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+ cmd.reg_count = 2;
+ cmd.direction = TRANSFER_WRITE;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+
+ /* Set the correct I2C address in the CPiA-2 system register */
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
+
+ /* Now have sensor access - set bit to turn the audio regulator off */
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SENSOR_CR1,
+ TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
+
+ /* Set the correct I2C address in the CPiA-2 system register */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
+ else
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
+
+ /* increase signal drive strength */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_VP_EXP_MODES,
+ TRANSFER_WRITE,
+ CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
+
+ /* Start autoexposure */
+ cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+ cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
+ (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+ cmd.buffer.registers[1].value =
+ cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
+
+ cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
+ cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+ cmd.reg_count = 2;
+ cmd.direction = TRANSFER_WRITE;
+
+ cpia2_send_command(cam, &cmd);
+
+ /* Set compression state */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
+ if (cam->params.compression.inhibit_htables) {
+ tmp_reg = cam->params.vc_params.vc_control |
+ CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+ } else {
+ tmp_reg = cam->params.vc_params.vc_control &
+ ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+ }
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ /* Set target size (kb) on vc
+ This is a heuristic based on the quality parameter and the raw
+ framesize in kB divided by 16 (the compression factor when the
+ quality is 100%) */
+ target_kb = (cam->width * cam->height * 2 / 16384) *
+ cam->params.vc_params.quality / 100;
+ if (target_kb < 1)
+ target_kb = 1;
+ cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
+ TRANSFER_WRITE, target_kb);
+
+ /* Wiggle VC Reset */
+ /***
+ * First read and wait a bit.
+ ***/
+ for (i = 0; i < 50; i++) {
+ cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
+ TRANSFER_READ, 0);
+ }
+
+ tmp_reg = cam->params.vc_params.pw_control;
+ tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
+
+ cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
+ cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+ DBG("After VC RESET, user mode is 0x%0X\n",
+ cam->params.vp_params.video_mode);
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_high_power
+ *
+ *****************************************************************************/
+static int cpia2_set_high_power(struct camera_data *cam)
+{
+ int i;
+ for (i = 0; i <= 50; i++) {
+ /* Read system status */
+ cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
+
+ /* If there is an error, clear it */
+ if(cam->params.camera_state.system_ctrl &
+ CPIA2_SYSTEM_CONTROL_V2W_ERR)
+ cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
+ TRANSFER_WRITE, 0);
+
+ /* Try to set high power mode */
+ cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
+ TRANSFER_WRITE, 1);
+
+ /* Try to read something in VP to check if everything is awake */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
+ TRANSFER_READ, 0);
+ if (cam->params.vp_params.system_state &
+ CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
+ break;
+ } else if (i == 50) {
+ cam->params.camera_state.power_mode = LO_POWER_MODE;
+ ERR("Camera did not wake up\n");
+ return -EIO;
+ }
+ }
+
+ DBG("System now in high power state\n");
+ cam->params.camera_state.power_mode = HI_POWER_MODE;
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_low_power
+ *
+ *****************************************************************************/
+int cpia2_set_low_power(struct camera_data *cam)
+{
+ cam->params.camera_state.power_mode = LO_POWER_MODE;
+ cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * apply_vp_patch
+ *
+ *****************************************************************************/
+static int cpia2_send_onebyte_command(struct camera_data *cam,
+ struct cpia2_command *cmd,
+ u8 start, u8 datum)
+{
+ cmd->buffer.block_data[0] = datum;
+ cmd->start = start;
+ cmd->reg_count = 1;
+ return cpia2_send_command(cam, cmd);
+}
+
+static int apply_vp_patch(struct camera_data *cam)
+{
+ const struct firmware *fw;
+ const char fw_name[] = FIRMWARE;
+ int i, ret;
+ struct cpia2_command cmd;
+
+ ret = request_firmware(&fw, fw_name, &cam->dev->dev);
+ if (ret) {
+ printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n",
+ fw_name);
+ return ret;
+ }
+
+ cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
+ cmd.direction = TRANSFER_WRITE;
+
+ /* First send the start address... */
+ cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
+ cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
+
+ /* ... followed by the data payload */
+ for (i = 2; i < fw->size; i += 64) {
+ cmd.start = 0x0C; /* Data */
+ cmd.reg_count = min_t(int, 64, fw->size - i);
+ memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count);
+ cpia2_send_command(cam, &cmd);
+ }
+
+ /* Next send the start address... */
+ cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
+ cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
+
+ /* ... followed by the 'goto' command */
+ cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1);
+
+ release_firmware(fw);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * set_default_user_mode
+ *
+ *****************************************************************************/
+static int set_default_user_mode(struct camera_data *cam)
+{
+ unsigned char user_mode;
+ unsigned char frame_rate;
+ int width = cam->params.roi.width;
+ int height = cam->params.roi.height;
+
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ if ((width > STV_IMAGE_QCIF_COLS)
+ || (height > STV_IMAGE_QCIF_ROWS)) {
+ user_mode = CPIA2_VP_USER_MODE_CIF;
+ } else {
+ user_mode = CPIA2_VP_USER_MODE_QCIFDS;
+ }
+ frame_rate = CPIA2_VP_FRAMERATE_30;
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ if ((width > STV_IMAGE_CIF_COLS)
+ || (height > STV_IMAGE_CIF_ROWS)) {
+ user_mode = CPIA2_VP_USER_MODE_VGA;
+ } else {
+ user_mode = CPIA2_VP_USER_MODE_QVGADS;
+ }
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ frame_rate = CPIA2_VP_FRAMERATE_15;
+ else
+ frame_rate = CPIA2_VP_FRAMERATE_30;
+ break;
+ default:
+ LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
+ cam->params.version.sensor_flags);
+ return -EINVAL;
+ }
+
+ DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
+ cam->params.version.sensor_flags, user_mode, frame_rate);
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
+ user_mode);
+ if(cam->params.vp_params.frame_rate > 0 &&
+ frame_rate > cam->params.vp_params.frame_rate)
+ frame_rate = cam->params.vp_params.frame_rate;
+
+ cpia2_set_fps(cam, frame_rate);
+
+// if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+// cpia2_do_command(cam,
+// CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+// TRANSFER_WRITE,
+// CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
+// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_match_video_size
+ *
+ * return the best match, where 'best' is as always
+ * the largest that is not bigger than what is requested.
+ *****************************************************************************/
+int cpia2_match_video_size(int width, int height)
+{
+ if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
+ return VIDEOSIZE_VGA;
+
+ if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
+ return VIDEOSIZE_CIF;
+
+ if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
+ return VIDEOSIZE_QVGA;
+
+ if (width >= 288 && height >= 216)
+ return VIDEOSIZE_288_216;
+
+ if (width >= 256 && height >= 192)
+ return VIDEOSIZE_256_192;
+
+ if (width >= 224 && height >= 168)
+ return VIDEOSIZE_224_168;
+
+ if (width >= 192 && height >= 144)
+ return VIDEOSIZE_192_144;
+
+ if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
+ return VIDEOSIZE_QCIF;
+
+ return -1;
+}
+
+/******************************************************************************
+ *
+ * SetVideoSize
+ *
+ *****************************************************************************/
+static int set_vw_size(struct camera_data *cam, int size)
+{
+ int retval = 0;
+
+ cam->params.vp_params.video_size = size;
+
+ switch (size) {
+ case VIDEOSIZE_VGA:
+ DBG("Setting size to VGA\n");
+ cam->params.roi.width = STV_IMAGE_VGA_COLS;
+ cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+ cam->width = STV_IMAGE_VGA_COLS;
+ cam->height = STV_IMAGE_VGA_ROWS;
+ break;
+ case VIDEOSIZE_CIF:
+ DBG("Setting size to CIF\n");
+ cam->params.roi.width = STV_IMAGE_CIF_COLS;
+ cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+ cam->width = STV_IMAGE_CIF_COLS;
+ cam->height = STV_IMAGE_CIF_ROWS;
+ break;
+ case VIDEOSIZE_QVGA:
+ DBG("Setting size to QVGA\n");
+ cam->params.roi.width = STV_IMAGE_QVGA_COLS;
+ cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
+ cam->width = STV_IMAGE_QVGA_COLS;
+ cam->height = STV_IMAGE_QVGA_ROWS;
+ break;
+ case VIDEOSIZE_288_216:
+ cam->params.roi.width = 288;
+ cam->params.roi.height = 216;
+ cam->width = 288;
+ cam->height = 216;
+ break;
+ case VIDEOSIZE_256_192:
+ cam->width = 256;
+ cam->height = 192;
+ cam->params.roi.width = 256;
+ cam->params.roi.height = 192;
+ break;
+ case VIDEOSIZE_224_168:
+ cam->width = 224;
+ cam->height = 168;
+ cam->params.roi.width = 224;
+ cam->params.roi.height = 168;
+ break;
+ case VIDEOSIZE_192_144:
+ cam->width = 192;
+ cam->height = 144;
+ cam->params.roi.width = 192;
+ cam->params.roi.height = 144;
+ break;
+ case VIDEOSIZE_QCIF:
+ DBG("Setting size to QCIF\n");
+ cam->params.roi.width = STV_IMAGE_QCIF_COLS;
+ cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
+ cam->width = STV_IMAGE_QCIF_COLS;
+ cam->height = STV_IMAGE_QCIF_ROWS;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * configure_sensor
+ *
+ *****************************************************************************/
+static int configure_sensor(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ int retval;
+
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ retval = config_sensor_410(cam, req_width, req_height);
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ retval = config_sensor_500(cam, req_width, req_height);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * config_sensor_410
+ *
+ *****************************************************************************/
+static int config_sensor_410(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ struct cpia2_command cmd;
+ int i = 0;
+ int image_size;
+ int image_type;
+ int width = req_width;
+ int height = req_height;
+
+ /***
+ * Make sure size doesn't exceed CIF.
+ ***/
+ if (width > STV_IMAGE_CIF_COLS)
+ width = STV_IMAGE_CIF_COLS;
+ if (height > STV_IMAGE_CIF_ROWS)
+ height = STV_IMAGE_CIF_ROWS;
+
+ image_size = cpia2_match_video_size(width, height);
+
+ DBG("Config 410: width = %d, height = %d\n", width, height);
+ DBG("Image size returned is %d\n", image_size);
+ if (image_size >= 0) {
+ set_vw_size(cam, image_size);
+ width = cam->params.roi.width;
+ height = cam->params.roi.height;
+
+ DBG("After set_vw_size(), width = %d, height = %d\n",
+ width, height);
+ if (width <= 176 && height <= 144) {
+ DBG("image type = VIDEOSIZE_QCIF\n");
+ image_type = VIDEOSIZE_QCIF;
+ }
+ else if (width <= 320 && height <= 240) {
+ DBG("image type = VIDEOSIZE_QVGA\n");
+ image_type = VIDEOSIZE_QVGA;
+ }
+ else {
+ DBG("image type = VIDEOSIZE_CIF\n");
+ image_type = VIDEOSIZE_CIF;
+ }
+ } else {
+ ERR("ConfigSensor410 failed\n");
+ return -EINVAL;
+ }
+
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+
+ /* VC Format */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+ if (image_type == VIDEOSIZE_CIF) {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
+ CPIA2_VC_VC_FORMAT_SHORTLINE);
+ } else {
+ cmd.buffer.registers[i++].value =
+ (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+ }
+
+ /* VC Clocks */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+ if (image_type == VIDEOSIZE_QCIF) {
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.buffer.registers[i++].value=
+ (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_672_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ DBG("VC_Clocks (0xc4) should be B\n");
+ }
+ else {
+ cmd.buffer.registers[i++].value=
+ (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ }
+ } else {
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_CLOCKS_LOGDIV0);
+ }
+ else {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_676_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV0);
+ }
+ }
+ DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
+
+ /* Input reqWidth from VC */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (STV_IMAGE_QCIF_COLS / 4);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (STV_IMAGE_CIF_COLS / 4);
+
+ /* Timings */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 208;
+ else
+ cmd.buffer.registers[i++].value = (u8) 160;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 160;
+ else
+ cmd.buffer.registers[i++].value = (u8) 64;
+
+ /* Output Image Size */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+ cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+ cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
+
+ /* Cropping */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+
+ /* Scaling registers (defaults) */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+ cmd.reg_count = i;
+
+ cpia2_send_command(cam, &cmd);
+
+ return i;
+}
+
+
+/******************************************************************************
+ *
+ * config_sensor_500(cam)
+ *
+ *****************************************************************************/
+static int config_sensor_500(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ struct cpia2_command cmd;
+ int i = 0;
+ int image_size = VIDEOSIZE_CIF;
+ int image_type = VIDEOSIZE_VGA;
+ int width = req_width;
+ int height = req_height;
+ unsigned int device = cam->params.pnp_id.device_type;
+
+ image_size = cpia2_match_video_size(width, height);
+
+ if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
+ image_type = VIDEOSIZE_VGA;
+ else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
+ image_type = VIDEOSIZE_CIF;
+ else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
+ image_type = VIDEOSIZE_QVGA;
+ else
+ image_type = VIDEOSIZE_QCIF;
+
+ if (image_size >= 0) {
+ set_vw_size(cam, image_size);
+ width = cam->params.roi.width;
+ height = cam->params.roi.height;
+ } else {
+ ERR("ConfigSensor500 failed\n");
+ return -EINVAL;
+ }
+
+ DBG("image_size = %d, width = %d, height = %d, type = %d\n",
+ image_size, width, height, image_type);
+
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+ i = 0;
+
+ /* VC Format */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+ cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
+ i++;
+
+ /* VC Clocks */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+ if (device == DEVICE_STV_672) {
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
+ else
+ cmd.buffer.registers[i].value =
+ (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV3);
+ } else {
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
+ else
+ cmd.buffer.registers[i].value =
+ (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ }
+ i++;
+
+ DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
+
+ /* Input width from VP */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8) (STV_IMAGE_VGA_COLS / 4);
+ else
+ cmd.buffer.registers[i].value =
+ (u8) (STV_IMAGE_QVGA_COLS / 4);
+ i++;
+ DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
+
+ /* Timings */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 2;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 250;
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value = (u8) 125;
+ else
+ cmd.buffer.registers[i++].value = (u8) 160;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 2;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 12;
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value = (u8) 64;
+ else
+ cmd.buffer.registers[i++].value = (u8) 6;
+
+ /* Output Image Size */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4;
+ else
+ cmd.buffer.registers[i++].value = width / 4;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4;
+ else
+ cmd.buffer.registers[i++].value = height / 4;
+
+ /* Cropping */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
+ else if (image_type == VIDEOSIZE_CIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+ else /*if (image_type == VIDEOSIZE_QCIF)*/
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
+ else if (image_type == VIDEOSIZE_CIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+ else /*if (image_type == VIDEOSIZE_QCIF)*/
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+
+ /* Scaling registers (defaults) */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 36;
+ else
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 32;
+ else
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 26;
+ else
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 21;
+ else
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */
+ else
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */
+ else
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
+
+ cmd.reg_count = i;
+
+ cpia2_send_command(cam, &cmd);
+
+ return i;
+}
+
+
+/******************************************************************************
+ *
+ * setallproperties
+ *
+ * This sets all user changeable properties to the values in cam->params.
+ *****************************************************************************/
+static int set_all_properties(struct camera_data *cam)
+{
+ /**
+ * Don't set target_kb here, it will be set later.
+ * framerate and user_mode were already set (set_default_user_mode).
+ **/
+
+ cpia2_usb_change_streaming_alternate(cam,
+ cam->params.camera_state.stream_mode);
+
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
+ cam->params.vp_params.gpio_data);
+
+ v4l2_ctrl_handler_setup(&cam->hdl);
+
+ wake_system(cam);
+
+ set_lowlight_boost(cam);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_save_camera_state
+ *
+ *****************************************************************************/
+void cpia2_save_camera_state(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
+ 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
+ /* Don't get framerate or target_kb. Trust the values we already have */
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_set_flicker_mode
+ *
+ *****************************************************************************/
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
+{
+ unsigned char cam_reg;
+ int err = 0;
+
+ if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+ return -EINVAL;
+
+ /* Set the appropriate bits in FLICKER_MODES, preserving the rest */
+ if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+ TRANSFER_READ, 0)))
+ return err;
+ cam_reg = cam->params.flicker_control.cam_register;
+
+ switch(mode) {
+ case NEVER_FLICKER:
+ cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ case FLICKER_60:
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ case FLICKER_50:
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
+ TRANSFER_WRITE, cam_reg)))
+ return err;
+
+ /* Set the appropriate bits in EXP_MODES, preserving the rest */
+ if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
+ TRANSFER_READ, 0)))
+ return err;
+ cam_reg = cam->params.vp_params.exposure_modes;
+
+ if (mode == NEVER_FLICKER) {
+ cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+ } else {
+ cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+ }
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
+ TRANSFER_WRITE, cam_reg)))
+ return err;
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
+ TRANSFER_WRITE, 1)))
+ return err;
+
+ switch(mode) {
+ case NEVER_FLICKER:
+ case FLICKER_60:
+ case FLICKER_50:
+ cam->params.flicker_control.flicker_mode_req = mode;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_property_flip
+ *
+ *****************************************************************************/
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
+{
+ unsigned char cam_reg;
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cam_reg = cam->params.vp_params.user_effects;
+
+ if (prop_val)
+ {
+ cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
+ }
+ else
+ {
+ cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
+ }
+ cam->params.vp_params.user_effects = cam_reg;
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam_reg);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_property_mirror
+ *
+ *****************************************************************************/
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
+{
+ unsigned char cam_reg;
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cam_reg = cam->params.vp_params.user_effects;
+
+ if (prop_val)
+ {
+ cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
+ }
+ else
+ {
+ cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
+ }
+ cam->params.vp_params.user_effects = cam_reg;
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam_reg);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_gpio
+ *
+ *****************************************************************************/
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
+{
+ int ret;
+
+ /* Set the microport direction (register 0x90, should be defined
+ * already) to 1 (user output), and set the microport data (0x91) to
+ * the value in the ioctl argument.
+ */
+
+ ret = cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ CPIA2_VC_MP_DIR_OUTPUT,
+ 255);
+ if (ret < 0)
+ return ret;
+ cam->params.vp_params.gpio_direction = 255;
+
+ ret = cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+ CPIA2_VC_MP_DIR_OUTPUT,
+ setting);
+ if (ret < 0)
+ return ret;
+ cam->params.vp_params.gpio_data = setting;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_fps
+ *
+ *****************************************************************************/
+int cpia2_set_fps(struct camera_data *cam, int framerate)
+{
+ int retval;
+
+ switch(framerate) {
+ case CPIA2_VP_FRAMERATE_30:
+ case CPIA2_VP_FRAMERATE_25:
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags ==
+ CPIA2_VP_SENSOR_FLAGS_500) {
+ return -EINVAL;
+ }
+ /* Fall through */
+ case CPIA2_VP_FRAMERATE_15:
+ case CPIA2_VP_FRAMERATE_12_5:
+ case CPIA2_VP_FRAMERATE_7_5:
+ case CPIA2_VP_FRAMERATE_6_25:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ framerate == CPIA2_VP_FRAMERATE_15)
+ framerate = 0; /* Work around bug in VP4 */
+
+ retval = cpia2_do_command(cam,
+ CPIA2_CMD_FRAMERATE_REQ,
+ TRANSFER_WRITE,
+ framerate);
+
+ if(retval == 0)
+ cam->params.vp_params.frame_rate = framerate;
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_brightness
+ *
+ *****************************************************************************/
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
+{
+ /***
+ * Don't let the register be set to zero - bug in VP4 - flash of full
+ * brightness
+ ***/
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
+ value++;
+ DBG("Setting brightness to %d (0x%0x)\n", value, value);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_contrast
+ *
+ *****************************************************************************/
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
+{
+ DBG("Setting contrast to %d (0x%0x)\n", value, value);
+ cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_saturation
+ *
+ *****************************************************************************/
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
+{
+ DBG("Setting saturation to %d (0x%0x)\n", value, value);
+ cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ * wake_system
+ *
+ *****************************************************************************/
+static void wake_system(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
+}
+
+/******************************************************************************
+ *
+ * set_lowlight_boost
+ *
+ * Valid for STV500 sensor only
+ *****************************************************************************/
+static void set_lowlight_boost(struct camera_data *cam)
+{
+ struct cpia2_command cmd;
+
+ if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
+ cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
+ return;
+
+ cmd.direction = TRANSFER_WRITE;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 3;
+ cmd.start = CPIA2_VP_RAM_ADDR_H;
+
+ cmd.buffer.block_data[0] = 0; /* High byte of address to write to */
+ cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */
+ cmd.buffer.block_data[2] = 0; /* High byte of data to write */
+
+ cpia2_send_command(cam, &cmd);
+
+ if (cam->params.vp_params.lowlight_boost) {
+ cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */
+ } else {
+ cmd.buffer.block_data[0] = 0x06;
+ }
+ cmd.start = CPIA2_VP_RAM_DATA;
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+
+ /* Rehash the VP4 values */
+ cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_format
+ *
+ * Assumes that new size is already set in param struct.
+ *****************************************************************************/
+void cpia2_set_format(struct camera_data *cam)
+{
+ cam->flush = true;
+
+ cpia2_usb_stream_pause(cam);
+
+ /* reset camera to new size */
+ cpia2_set_low_power(cam);
+ cpia2_reset_camera(cam);
+ cam->flush = false;
+
+ cpia2_dbg_dump_registers(cam);
+
+ cpia2_usb_stream_resume(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_dbg_dump_registers
+ *
+ *****************************************************************************/
+void cpia2_dbg_dump_registers(struct camera_data *cam)
+{
+#ifdef _CPIA2_DEBUG_
+ struct cpia2_command cmd;
+
+ if (!(debugs_on & DEBUG_DUMP_REGS))
+ return;
+
+ cmd.direction = TRANSFER_READ;
+
+ /* Start with bank 0 (SYSTEM) */
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 3;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "System Device Hi = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "System Device Lo = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "System_system control = 0x%X\n",
+ cmd.buffer.block_data[2]);
+
+ /* Bank 1 (VC) */
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 4;
+ cmd.start = 0x80;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "ASIC_ID = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "ASIC_REV = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "PW_CONTRL = 0x%X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "WAKEUP = 0x%X\n",
+ cmd.buffer.block_data[3]);
+
+ cmd.start = 0xA0; /* ST_CTRL */
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "Stream ctrl = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xA4; /* Stream status */
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "Stream status = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xA8; /* USB status */
+ cmd.reg_count = 3;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "USB_CTRL = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "USB_STRM = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "USB_STATUS = 0x%X\n",
+ cmd.buffer.block_data[2]);
+
+ cmd.start = 0xAF; /* USB settings */
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "USB settings = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xC0; /* VC stuff */
+ cmd.reg_count = 26;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VC Control = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VC Format = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VC Clocks = 0x%0X\n",
+ cmd.buffer.block_data[4]);
+ printk(KERN_DEBUG "VC IHSize = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+ printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n",
+ cmd.buffer.block_data[9]);
+ printk(KERN_DEBUG "VC OHSize = 0x%0X\n",
+ cmd.buffer.block_data[10]);
+ printk(KERN_DEBUG "VC OVSize = 0x%0X\n",
+ cmd.buffer.block_data[11]);
+ printk(KERN_DEBUG "VC HCrop = 0x%0X\n",
+ cmd.buffer.block_data[12]);
+ printk(KERN_DEBUG "VC VCrop = 0x%0X\n",
+ cmd.buffer.block_data[13]);
+ printk(KERN_DEBUG "VC HPhase = 0x%0X\n",
+ cmd.buffer.block_data[14]);
+ printk(KERN_DEBUG "VC VPhase = 0x%0X\n",
+ cmd.buffer.block_data[15]);
+ printk(KERN_DEBUG "VC HIspan = 0x%0X\n",
+ cmd.buffer.block_data[16]);
+ printk(KERN_DEBUG "VC VIspan = 0x%0X\n",
+ cmd.buffer.block_data[17]);
+ printk(KERN_DEBUG "VC HiCrop = 0x%0X\n",
+ cmd.buffer.block_data[18]);
+ printk(KERN_DEBUG "VC ViCrop = 0x%0X\n",
+ cmd.buffer.block_data[19]);
+ printk(KERN_DEBUG "VC HiFract = 0x%0X\n",
+ cmd.buffer.block_data[20]);
+ printk(KERN_DEBUG "VC ViFract = 0x%0X\n",
+ cmd.buffer.block_data[21]);
+ printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n",
+ cmd.buffer.block_data[22]);
+ printk(KERN_DEBUG "VC Creep Per = 0x%0X\n",
+ cmd.buffer.block_data[23]);
+ printk(KERN_DEBUG "VC User Sq. = 0x%0X\n",
+ cmd.buffer.block_data[24]);
+ printk(KERN_DEBUG "VC Target KB = 0x%0X\n",
+ cmd.buffer.block_data[25]);
+
+ /*** VP ***/
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 14;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+
+ printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Sys State = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+ printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n",
+ cmd.buffer.block_data[9]);
+ printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
+ cmd.buffer.block_data[10]);
+ printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
+ cmd.buffer.block_data[11]);
+ printk(KERN_DEBUG "VP RAM Data = 0x%0X\n",
+ cmd.buffer.block_data[12]);
+ printk(KERN_DEBUG "Do Call = 0x%0X\n",
+ cmd.buffer.block_data[13]);
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.reg_count = 9;
+ cmd.start = 0x0E;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+ cmd.buffer.block_data[4]);
+ printk(KERN_DEBUG "VP White Bal = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP WB thresh = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+
+ cmd.reg_count = 1;
+ cmd.start = 0x1B;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ } else {
+ cmd.reg_count = 8 ;
+ cmd.start = 0x0E;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.reg_count = 4;
+ cmd.start = 0x3A;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ }
+#endif
+}
+
+/******************************************************************************
+ *
+ * reset_camera_struct
+ *
+ * Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct(struct camera_data *cam)
+{
+ /***
+ * The following parameter values are the defaults from the register map.
+ ***/
+ cam->params.vp_params.lowlight_boost = 0;
+
+ /* FlickerModes */
+ cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
+
+ /* jpeg params */
+ cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+ cam->params.compression.creep_period = 2;
+ cam->params.compression.user_squeeze = 20;
+ cam->params.compression.inhibit_htables = false;
+
+ /* gpio params */
+ cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */
+ cam->params.vp_params.gpio_data = 0;
+
+ /* Target kb params */
+ cam->params.vc_params.quality = 100;
+
+ /***
+ * Set Sensor FPS as fast as possible.
+ ***/
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
+ else
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+ } else {
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+ }
+
+ /***
+ * Set default video mode as large as possible :
+ * for vga sensor set to vga, for cif sensor set to CIF.
+ ***/
+ if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
+ cam->sensor_type = CPIA2_SENSOR_500;
+ cam->video_size = VIDEOSIZE_VGA;
+ cam->params.roi.width = STV_IMAGE_VGA_COLS;
+ cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+ } else {
+ cam->sensor_type = CPIA2_SENSOR_410;
+ cam->video_size = VIDEOSIZE_CIF;
+ cam->params.roi.width = STV_IMAGE_CIF_COLS;
+ cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+ }
+
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
+}
+
+/******************************************************************************
+ *
+ * cpia2_init_camera_struct
+ *
+ * Initializes camera struct, does not call reset to fill in defaults.
+ *****************************************************************************/
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
+{
+ struct camera_data *cam;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+
+ if (!cam) {
+ ERR("couldn't kmalloc cpia2 struct\n");
+ return NULL;
+ }
+
+ cam->v4l2_dev.release = cpia2_camera_release;
+ if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
+ v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
+ kfree(cam);
+ return NULL;
+ }
+
+ mutex_init(&cam->v4l2_lock);
+ init_waitqueue_head(&cam->wq_stream);
+
+ return cam;
+}
+
+/******************************************************************************
+ *
+ * cpia2_init_camera
+ *
+ * Initializes camera.
+ *****************************************************************************/
+int cpia2_init_camera(struct camera_data *cam)
+{
+ DBG("Start\n");
+
+ cam->mmapped = false;
+
+ /* Get sensor and asic types before reset. */
+ cpia2_set_high_power(cam);
+ cpia2_get_version_info(cam);
+ if (cam->params.version.asic_id != CPIA2_ASIC_672) {
+ ERR("Device IO error (asicID has incorrect value of 0x%X\n",
+ cam->params.version.asic_id);
+ return -ENODEV;
+ }
+
+ /* Set GPIO direction and data to a safe state. */
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ TRANSFER_WRITE, 0);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+ TRANSFER_WRITE, 0);
+
+ /* resetting struct requires version info for sensor and asic types */
+ reset_camera_struct(cam);
+
+ cpia2_set_low_power(cam);
+
+ DBG("End\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_allocate_buffers
+ *
+ *****************************************************************************/
+int cpia2_allocate_buffers(struct camera_data *cam)
+{
+ int i;
+
+ if(!cam->buffers) {
+ u32 size = cam->num_frames*sizeof(struct framebuf);
+ cam->buffers = kmalloc(size, GFP_KERNEL);
+ if(!cam->buffers) {
+ ERR("couldn't kmalloc frame buffer structures\n");
+ return -ENOMEM;
+ }
+ }
+
+ if(!cam->frame_buffer) {
+ cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
+ if (!cam->frame_buffer) {
+ ERR("couldn't vmalloc frame buffer data area\n");
+ kfree(cam->buffers);
+ cam->buffers = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ for(i=0; i<cam->num_frames-1; ++i) {
+ cam->buffers[i].next = &cam->buffers[i+1];
+ cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+ cam->buffers[i].status = FRAME_EMPTY;
+ cam->buffers[i].length = 0;
+ cam->buffers[i].max_length = 0;
+ cam->buffers[i].num = i;
+ }
+ cam->buffers[i].next = cam->buffers;
+ cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+ cam->buffers[i].status = FRAME_EMPTY;
+ cam->buffers[i].length = 0;
+ cam->buffers[i].max_length = 0;
+ cam->buffers[i].num = i;
+ cam->curbuff = cam->buffers;
+ cam->workbuff = cam->curbuff->next;
+ DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
+ cam->workbuff);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_free_buffers
+ *
+ *****************************************************************************/
+void cpia2_free_buffers(struct camera_data *cam)
+{
+ if(cam->buffers) {
+ kfree(cam->buffers);
+ cam->buffers = NULL;
+ }
+ if(cam->frame_buffer) {
+ rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
+ cam->frame_buffer = NULL;
+ }
+}
+
+/******************************************************************************
+ *
+ * cpia2_read
+ *
+ *****************************************************************************/
+long cpia2_read(struct camera_data *cam,
+ char __user *buf, unsigned long count, int noblock)
+{
+ struct framebuf *frame;
+
+ if (!count)
+ return 0;
+
+ if (!buf) {
+ ERR("%s: buffer NULL\n",__func__);
+ return -EINVAL;
+ }
+
+ if (!cam) {
+ ERR("%s: Internal error, camera_data NULL!\n",__func__);
+ return -EINVAL;
+ }
+
+ if (!cam->streaming) {
+ /* Start streaming */
+ cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ }
+
+ /* Copy cam->curbuff in case it changes while we're processing */
+ frame = cam->curbuff;
+ if (noblock && frame->status != FRAME_READY) {
+ return -EAGAIN;
+ }
+
+ if (frame->status != FRAME_READY) {
+ mutex_unlock(&cam->v4l2_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !video_is_registered(&cam->vdev) ||
+ (frame = cam->curbuff)->status == FRAME_READY);
+ mutex_lock(&cam->v4l2_lock);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ if (!video_is_registered(&cam->vdev))
+ return 0;
+ }
+
+ /* copy data to user space */
+ if (frame->length > count)
+ return -EFAULT;
+ if (copy_to_user(buf, frame->data, frame->length))
+ return -EFAULT;
+
+ count = frame->length;
+
+ frame->status = FRAME_EMPTY;
+
+ return count;
+}
+
+/******************************************************************************
+ *
+ * cpia2_poll
+ *
+ *****************************************************************************/
+unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
+ poll_table *wait)
+{
+ unsigned int status = v4l2_ctrl_poll(filp, wait);
+
+ if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
+ !cam->streaming) {
+ /* Start streaming */
+ cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ }
+
+ poll_wait(filp, &cam->wq_stream, wait);
+
+ if (cam->curbuff->status == FRAME_READY)
+ status |= POLLIN | POLLRDNORM;
+
+ return status;
+}
+
+/******************************************************************************
+ *
+ * cpia2_remap_buffer
+ *
+ *****************************************************************************/
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
+{
+ const char *adr = (const char *)vma->vm_start;
+ unsigned long size = vma->vm_end-vma->vm_start;
+ unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long start = (unsigned long) adr;
+ unsigned long page, pos;
+
+ DBG("mmap offset:%ld size:%ld\n", start_offset, size);
+
+ if (!video_is_registered(&cam->vdev))
+ return -ENODEV;
+
+ if (size > cam->frame_size*cam->num_frames ||
+ (start_offset % cam->frame_size) != 0 ||
+ (start_offset+size > cam->frame_size*cam->num_frames))
+ return -EINVAL;
+
+ pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ cam->mmapped = true;
+ return 0;
+}
diff --git a/drivers/media/video/cpia2/cpia2_registers.h b/drivers/media/usb/cpia2/cpia2_registers.h
index 3bbec514a967..3bbec514a967 100644
--- a/drivers/media/video/cpia2/cpia2_registers.h
+++ b/drivers/media/usb/cpia2/cpia2_registers.h
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index 95b5d6e7cdc4..95b5d6e7cdc4 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
new file mode 100644
index 000000000000..5ca6f44b4c63
--- /dev/null
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -0,0 +1,1267 @@
+/****************************************************************************
+ *
+ * Filename: cpia2_v4l.c
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ * Contact: steve.miller@st.com
+ * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
+ *
+ * Description:
+ * This is a USB driver for CPia2 based video cameras.
+ * The infrastructure of this driver is based on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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.
+ *
+ * Stripped of 2.4 stuff ready for main kernel submit by
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
+ ****************************************************************************/
+
+#define CPIA_VERSION "3.0.1"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/videodev2.h>
+#include <linux/stringify.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+
+#include "cpia2.h"
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
+
+static int buffer_size = 68 * 1024;
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
+
+static int num_buffers = 3;
+module_param(num_buffers, int, 0);
+MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
+ __stringify(VIDEO_MAX_FRAME) ", default 3)");
+
+static int alternate = DEFAULT_ALT;
+module_param(alternate, int, 0);
+MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
+ __stringify(USBIF_ISO_6) ", default "
+ __stringify(DEFAULT_ALT) ")");
+
+static int flicker_mode;
+module_param(flicker_mode, int, 0);
+MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
+ __stringify(60) ", default 0)");
+
+MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
+MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CPIA_VERSION);
+
+#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
+#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
+
+/******************************************************************************
+ *
+ * cpia2_open
+ *
+ *****************************************************************************/
+static int cpia2_open(struct file *file)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int retval;
+
+ if (mutex_lock_interruptible(&cam->v4l2_lock))
+ return -ERESTARTSYS;
+ retval = v4l2_fh_open(file);
+ if (retval)
+ goto open_unlock;
+
+ if (v4l2_fh_is_singular_file(file)) {
+ if (cpia2_allocate_buffers(cam)) {
+ v4l2_fh_release(file);
+ retval = -ENOMEM;
+ goto open_unlock;
+ }
+
+ /* reset the camera */
+ if (cpia2_reset_camera(cam) < 0) {
+ v4l2_fh_release(file);
+ retval = -EIO;
+ goto open_unlock;
+ }
+
+ cam->APP_len = 0;
+ cam->COM_len = 0;
+ }
+
+ cpia2_dbg_dump_registers(cam);
+open_unlock:
+ mutex_unlock(&cam->v4l2_lock);
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_close
+ *
+ *****************************************************************************/
+static int cpia2_close(struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+
+ mutex_lock(&cam->v4l2_lock);
+ if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
+ cpia2_usb_stream_stop(cam);
+
+ /* save camera state for later open */
+ cpia2_save_camera_state(cam);
+
+ cpia2_set_low_power(cam);
+ cpia2_free_buffers(cam);
+ }
+
+ if (cam->stream_fh == file->private_data) {
+ cam->stream_fh = NULL;
+ cam->mmapped = 0;
+ }
+ mutex_unlock(&cam->v4l2_lock);
+ return v4l2_fh_release(file);
+}
+
+/******************************************************************************
+ *
+ * cpia2_v4l_read
+ *
+ *****************************************************************************/
+static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
+ loff_t *off)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int noblock = file->f_flags&O_NONBLOCK;
+ ssize_t ret;
+
+ if(!cam)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&cam->v4l2_lock))
+ return -ERESTARTSYS;
+ ret = cpia2_read(cam, buf, count, noblock);
+ mutex_unlock(&cam->v4l2_lock);
+ return ret;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_v4l_poll
+ *
+ *****************************************************************************/
+static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
+{
+ struct camera_data *cam = video_drvdata(filp);
+ unsigned int res;
+
+ mutex_lock(&cam->v4l2_lock);
+ res = cpia2_poll(cam, filp, wait);
+ mutex_unlock(&cam->v4l2_lock);
+ return res;
+}
+
+
+static int sync(struct camera_data *cam, int frame_nr)
+{
+ struct framebuf *frame = &cam->buffers[frame_nr];
+
+ while (1) {
+ if (frame->status == FRAME_READY)
+ return 0;
+
+ if (!cam->streaming) {
+ frame->status = FRAME_READY;
+ frame->length = 0;
+ return 0;
+ }
+
+ mutex_unlock(&cam->v4l2_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !cam->streaming ||
+ frame->status == FRAME_READY);
+ mutex_lock(&cam->v4l2_lock);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ if (!video_is_registered(&cam->vdev))
+ return -ENOTTY;
+ }
+}
+
+/******************************************************************************
+ *
+ * ioctl_querycap
+ *
+ * V4L2 device capabilities
+ *
+ *****************************************************************************/
+
+static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ strcpy(vc->driver, "cpia2");
+
+ if (cam->params.pnp_id.product == 0x151)
+ strcpy(vc->card, "QX5 Microscope");
+ else
+ strcpy(vc->card, "CPiA2 Camera");
+ switch (cam->params.pnp_id.device_type) {
+ case DEVICE_STV_672:
+ strcat(vc->card, " (672/");
+ break;
+ case DEVICE_STV_676:
+ strcat(vc->card, " (676/");
+ break;
+ default:
+ strcat(vc->card, " (XXX/");
+ break;
+ }
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ strcat(vc->card, "404)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ strcat(vc->card, "407)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ strcat(vc->card, "409)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ strcat(vc->card, "410)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ strcat(vc->card, "500)");
+ break;
+ default:
+ strcat(vc->card, "XXX)");
+ break;
+ }
+
+ if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
+ memset(vc->bus_info,0, sizeof(vc->bus_info));
+
+ vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ vc->capabilities = vc->device_caps |
+ V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_input
+ *
+ * V4L2 input get/set/enumerate
+ *
+ *****************************************************************************/
+
+static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+ if (i->index)
+ return -EINVAL;
+ strcpy(i->name, "Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ return 0;
+}
+
+static int cpia2_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
+{
+ return i ? -EINVAL : 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_enum_fmt
+ *
+ * V4L2 format enumerate
+ *
+ *****************************************************************************/
+
+static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+
+ if (index < 0 || index > 1)
+ return -EINVAL;
+
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ switch(index) {
+ case 0:
+ strcpy(f->description, "MJPEG");
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
+ break;
+ case 1:
+ strcpy(f->description, "JPEG");
+ f->pixelformat = V4L2_PIX_FMT_JPEG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_try_fmt
+ *
+ * V4L2 format try
+ *
+ *****************************************************************************/
+
+static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = cam->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ f->fmt.pix.priv = 0;
+
+ switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
+ case VIDEOSIZE_VGA:
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
+ break;
+ case VIDEOSIZE_CIF:
+ f->fmt.pix.width = 352;
+ f->fmt.pix.height = 288;
+ break;
+ case VIDEOSIZE_QVGA:
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ break;
+ case VIDEOSIZE_288_216:
+ f->fmt.pix.width = 288;
+ f->fmt.pix.height = 216;
+ break;
+ case VIDEOSIZE_256_192:
+ f->fmt.pix.width = 256;
+ f->fmt.pix.height = 192;
+ break;
+ case VIDEOSIZE_224_168:
+ f->fmt.pix.width = 224;
+ f->fmt.pix.height = 168;
+ break;
+ case VIDEOSIZE_192_144:
+ f->fmt.pix.width = 192;
+ f->fmt.pix.height = 144;
+ break;
+ case VIDEOSIZE_QCIF:
+ default:
+ f->fmt.pix.width = 176;
+ f->fmt.pix.height = 144;
+ break;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_set_fmt
+ *
+ * V4L2 format set
+ *
+ *****************************************************************************/
+
+static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
+ struct v4l2_format *f)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int err, frame;
+
+ err = cpia2_try_fmt_vid_cap(file, _fh, f);
+ if(err != 0)
+ return err;
+
+ cam->pixelformat = f->fmt.pix.pixelformat;
+
+ /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
+ * the missing Huffman table properly. */
+ cam->params.compression.inhibit_htables = 0;
+ /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
+
+ /* we set the video window to something smaller or equal to what
+ * is requested by the user???
+ */
+ DBG("Requested width = %d, height = %d\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ if (f->fmt.pix.width != cam->width ||
+ f->fmt.pix.height != cam->height) {
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
+ cam->params.roi.width = f->fmt.pix.width;
+ cam->params.roi.height = f->fmt.pix.height;
+ cpia2_set_format(cam);
+ }
+
+ for (frame = 0; frame < cam->num_frames; ++frame) {
+ if (cam->buffers[frame].status == FRAME_READING)
+ if ((err = sync(cam, frame)) < 0)
+ return err;
+
+ cam->buffers[frame].status = FRAME_EMPTY;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_get_fmt
+ *
+ * V4L2 format get
+ *
+ *****************************************************************************/
+
+static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ f->fmt.pix.width = cam->width;
+ f->fmt.pix.height = cam->height;
+ f->fmt.pix.pixelformat = cam->pixelformat;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = cam->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ f->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_cropcap
+ *
+ * V4L2 query cropping capabilities
+ * NOTE: cropping is currently disabled
+ *
+ *****************************************************************************/
+
+static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ c->bounds.left = 0;
+ c->bounds.top = 0;
+ c->bounds.width = cam->width;
+ c->bounds.height = cam->height;
+ c->defrect.left = 0;
+ c->defrect.top = 0;
+ c->defrect.width = cam->width;
+ c->defrect.height = cam->height;
+ c->pixelaspect.numerator = 1;
+ c->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+struct framerate_info {
+ int value;
+ struct v4l2_fract period;
+};
+
+static const struct framerate_info framerate_controls[] = {
+ { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
+ { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } },
+ { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
+ { CPIA2_VP_FRAMERATE_15, { 1, 15 } },
+ { CPIA2_VP_FRAMERATE_25, { 1, 25 } },
+ { CPIA2_VP_FRAMERATE_30, { 1, 30 } },
+};
+
+static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
+{
+ struct camera_data *cam = video_drvdata(file);
+ struct v4l2_captureparm *cap = &p->parm.capture;
+ int i;
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cap->capability = V4L2_CAP_TIMEPERFRAME;
+ cap->readbuffers = cam->num_frames;
+ for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
+ if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
+ cap->timeperframe = framerate_controls[i].period;
+ break;
+ }
+ return 0;
+}
+
+static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
+{
+ struct camera_data *cam = video_drvdata(file);
+ struct v4l2_captureparm *cap = &p->parm.capture;
+ struct v4l2_fract tpf = cap->timeperframe;
+ int max = ARRAY_SIZE(framerate_controls) - 1;
+ int ret;
+ int i;
+
+ ret = cpia2_g_parm(file, fh, p);
+ if (ret || !tpf.denominator || !tpf.numerator)
+ return ret;
+
+ /* Maximum 15 fps for this model */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ max -= 2;
+ for (i = 0; i <= max; i++) {
+ struct v4l2_fract f1 = tpf;
+ struct v4l2_fract f2 = framerate_controls[i].period;
+
+ f1.numerator *= f2.denominator;
+ f2.numerator *= f1.denominator;
+ if (f1.numerator >= f2.numerator)
+ break;
+ }
+ if (i > max)
+ i = max;
+ cap->timeperframe = framerate_controls[i].period;
+ return cpia2_set_fps(cam, framerate_controls[i].value);
+}
+
+static const struct {
+ u32 width;
+ u32 height;
+} cpia2_framesizes[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 288, 216 },
+ { 256, 192 },
+ { 224, 168 },
+ { 192, 144 },
+ { 176, 144 },
+};
+
+static int cpia2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+
+ if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
+ fsize->pixel_format != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+ if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = cpia2_framesizes[fsize->index].width;
+ fsize->discrete.height = cpia2_framesizes[fsize->index].height;
+
+ return 0;
+}
+
+static int cpia2_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int max = ARRAY_SIZE(framerate_controls) - 1;
+ int i;
+
+ if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
+ fival->pixel_format != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+
+ /* Maximum 15 fps for this model */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ max -= 2;
+ if (fival->index > max)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
+ if (fival->width == cpia2_framesizes[i].width &&
+ fival->height == cpia2_framesizes[i].height)
+ break;
+ if (i == ARRAY_SIZE(cpia2_framesizes))
+ return -EINVAL;
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = framerate_controls[fival->index].period;
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_s_ctrl
+ *
+ * V4L2 set the value of a control variable
+ *
+ *****************************************************************************/
+
+static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct camera_data *cam =
+ container_of(ctrl->handler, struct camera_data, hdl);
+ static const int flicker_table[] = {
+ NEVER_FLICKER,
+ FLICKER_50,
+ FLICKER_60,
+ };
+
+ DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ cpia2_set_brightness(cam, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ cpia2_set_contrast(cam, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ cpia2_set_saturation(cam, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ cpia2_set_property_mirror(cam, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ cpia2_set_property_flip(cam, ctrl->val);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
+ case V4L2_CID_ILLUMINATORS_1:
+ return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
+ (cam->bottom_light->val << 7));
+ case V4L2_CID_JPEG_ACTIVE_MARKER:
+ cam->params.compression.inhibit_htables =
+ !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ cam->params.vc_params.quality = ctrl->val;
+ break;
+ case CPIA2_CID_USB_ALT:
+ cam->params.camera_state.stream_mode = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_g_jpegcomp
+ *
+ * V4L2 get the JPEG compression parameters
+ *
+ *****************************************************************************/
+
+static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ memset(parms, 0, sizeof(*parms));
+
+ parms->quality = 80; // TODO: Can this be made meaningful?
+
+ parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
+ if(!cam->params.compression.inhibit_htables) {
+ parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
+ }
+
+ parms->APPn = cam->APPn;
+ parms->APP_len = cam->APP_len;
+ if(cam->APP_len > 0) {
+ memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
+ parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
+ }
+
+ parms->COM_len = cam->COM_len;
+ if(cam->COM_len > 0) {
+ memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
+ parms->jpeg_markers |= JPEG_MARKER_COM;
+ }
+
+ DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
+ parms->APP_len, parms->COM_len);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_s_jpegcomp
+ *
+ * V4L2 set the JPEG compression parameters
+ * NOTE: quality and some jpeg_markers are ignored.
+ *
+ *****************************************************************************/
+
+static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
+ parms->APP_len, parms->COM_len);
+
+ cam->params.compression.inhibit_htables =
+ !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+ parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
+ V4L2_JPEG_MARKER_DHT;
+
+ if(parms->APP_len != 0) {
+ if(parms->APP_len > 0 &&
+ parms->APP_len <= sizeof(cam->APP_data) &&
+ parms->APPn >= 0 && parms->APPn <= 15) {
+ cam->APPn = parms->APPn;
+ cam->APP_len = parms->APP_len;
+ memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
+ } else {
+ LOG("Bad APPn Params n=%d len=%d\n",
+ parms->APPn, parms->APP_len);
+ return -EINVAL;
+ }
+ } else {
+ cam->APP_len = 0;
+ }
+
+ if(parms->COM_len != 0) {
+ if(parms->COM_len > 0 &&
+ parms->COM_len <= sizeof(cam->COM_data)) {
+ cam->COM_len = parms->COM_len;
+ memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
+ } else {
+ LOG("Bad COM_len=%d\n", parms->COM_len);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_reqbufs
+ *
+ * V4L2 Initiate memory mapping.
+ * NOTE: The user's request is ignored. For now the buffers are fixed.
+ *
+ *****************************************************************************/
+
+static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
+ req->count = cam->num_frames;
+ memset(&req->reserved, 0, sizeof(req->reserved));
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_querybuf
+ *
+ * V4L2 Query memory buffer status.
+ *
+ *****************************************************************************/
+
+static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->index > cam->num_frames)
+ return -EINVAL;
+
+ buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+ buf->length = cam->frame_size;
+
+ buf->memory = V4L2_MEMORY_MMAP;
+
+ if(cam->mmapped)
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ else
+ buf->flags = 0;
+
+ switch (cam->buffers[buf->index].status) {
+ case FRAME_EMPTY:
+ case FRAME_ERROR:
+ case FRAME_READING:
+ buf->bytesused = 0;
+ buf->flags = V4L2_BUF_FLAG_QUEUED;
+ break;
+ case FRAME_READY:
+ buf->bytesused = cam->buffers[buf->index].length;
+ buf->timestamp = cam->buffers[buf->index].timestamp;
+ buf->sequence = cam->buffers[buf->index].seq;
+ buf->flags = V4L2_BUF_FLAG_DONE;
+ break;
+ }
+
+ DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
+ buf->index, buf->m.offset, buf->flags, buf->sequence,
+ buf->bytesused);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_qbuf
+ *
+ * V4L2 User is freeing buffer
+ *
+ *****************************************************************************/
+
+static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct camera_data *cam = video_drvdata(file);
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP ||
+ buf->index > cam->num_frames)
+ return -EINVAL;
+
+ DBG("QBUF #%d\n", buf->index);
+
+ if(cam->buffers[buf->index].status == FRAME_READY)
+ cam->buffers[buf->index].status = FRAME_EMPTY;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * find_earliest_filled_buffer
+ *
+ * Helper for ioctl_dqbuf. Find the next ready buffer.
+ *
+ *****************************************************************************/
+
+static int find_earliest_filled_buffer(struct camera_data *cam)
+{
+ int i;
+ int found = -1;
+ for (i=0; i<cam->num_frames; i++) {
+ if(cam->buffers[i].status == FRAME_READY) {
+ if(found < 0) {
+ found = i;
+ } else {
+ /* find which buffer is earlier */
+ struct timeval *tv1, *tv2;
+ tv1 = &cam->buffers[i].timestamp;
+ tv2 = &cam->buffers[found].timestamp;
+ if(tv1->tv_sec < tv2->tv_sec ||
+ (tv1->tv_sec == tv2->tv_sec &&
+ tv1->tv_usec < tv2->tv_usec))
+ found = i;
+ }
+ }
+ }
+ return found;
+}
+
+/******************************************************************************
+ *
+ * ioctl_dqbuf
+ *
+ * V4L2 User is asking for a filled buffer.
+ *
+ *****************************************************************************/
+
+static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int frame;
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ frame = find_earliest_filled_buffer(cam);
+
+ if(frame < 0 && file->f_flags&O_NONBLOCK)
+ return -EAGAIN;
+
+ if(frame < 0) {
+ /* Wait for a frame to become available */
+ struct framebuf *cb=cam->curbuff;
+ mutex_unlock(&cam->v4l2_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !video_is_registered(&cam->vdev) ||
+ (cb=cam->curbuff)->status == FRAME_READY);
+ mutex_lock(&cam->v4l2_lock);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ if (!video_is_registered(&cam->vdev))
+ return -ENOTTY;
+ frame = cb->num;
+ }
+
+
+ buf->index = frame;
+ buf->bytesused = cam->buffers[buf->index].length;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = cam->buffers[buf->index].timestamp;
+ buf->sequence = cam->buffers[buf->index].seq;
+ buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+ buf->length = cam->frame_size;
+ buf->reserved2 = 0;
+ buf->reserved = 0;
+ memset(&buf->timecode, 0, sizeof(buf->timecode));
+
+ DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
+ cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
+
+ return 0;
+}
+
+static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int ret = -EINVAL;
+
+ DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+ if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!cam->streaming) {
+ ret = cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ if (!ret)
+ v4l2_ctrl_grab(cam->usb_alt, true);
+ }
+ return ret;
+}
+
+static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int ret = -EINVAL;
+
+ DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+ if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (cam->streaming) {
+ ret = cpia2_usb_stream_stop(cam);
+ if (!ret)
+ v4l2_ctrl_grab(cam->usb_alt, false);
+ }
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * cpia2_mmap
+ *
+ *****************************************************************************/
+static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
+{
+ struct camera_data *cam = video_drvdata(file);
+ int retval;
+
+ if (mutex_lock_interruptible(&cam->v4l2_lock))
+ return -ERESTARTSYS;
+ retval = cpia2_remap_buffer(cam, area);
+
+ if(!retval)
+ cam->stream_fh = file->private_data;
+ mutex_unlock(&cam->v4l2_lock);
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * reset_camera_struct_v4l
+ *
+ * Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct_v4l(struct camera_data *cam)
+{
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
+
+ cam->frame_size = buffer_size;
+ cam->num_frames = num_buffers;
+
+ /* Flicker modes */
+ cam->params.flicker_control.flicker_mode_req = flicker_mode;
+
+ /* stream modes */
+ cam->params.camera_state.stream_mode = alternate;
+
+ cam->pixelformat = V4L2_PIX_FMT_JPEG;
+}
+
+static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
+ .vidioc_querycap = cpia2_querycap,
+ .vidioc_enum_input = cpia2_enum_input,
+ .vidioc_g_input = cpia2_g_input,
+ .vidioc_s_input = cpia2_s_input,
+ .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap,
+ .vidioc_g_jpegcomp = cpia2_g_jpegcomp,
+ .vidioc_s_jpegcomp = cpia2_s_jpegcomp,
+ .vidioc_cropcap = cpia2_cropcap,
+ .vidioc_reqbufs = cpia2_reqbufs,
+ .vidioc_querybuf = cpia2_querybuf,
+ .vidioc_qbuf = cpia2_qbuf,
+ .vidioc_dqbuf = cpia2_dqbuf,
+ .vidioc_streamon = cpia2_streamon,
+ .vidioc_streamoff = cpia2_streamoff,
+ .vidioc_s_parm = cpia2_s_parm,
+ .vidioc_g_parm = cpia2_g_parm,
+ .vidioc_enum_framesizes = cpia2_enum_framesizes,
+ .vidioc_enum_frameintervals = cpia2_enum_frameintervals,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/***
+ * The v4l video device structure initialized for this device
+ ***/
+static const struct v4l2_file_operations cpia2_fops = {
+ .owner = THIS_MODULE,
+ .open = cpia2_open,
+ .release = cpia2_close,
+ .read = cpia2_v4l_read,
+ .poll = cpia2_v4l_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = cpia2_mmap,
+};
+
+static struct video_device cpia2_template = {
+ /* I could not find any place for the old .initialize initializer?? */
+ .name = "CPiA2 Camera",
+ .fops = &cpia2_fops,
+ .ioctl_ops = &cpia2_ioctl_ops,
+ .release = video_device_release_empty,
+};
+
+void cpia2_camera_release(struct v4l2_device *v4l2_dev)
+{
+ struct camera_data *cam =
+ container_of(v4l2_dev, struct camera_data, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&cam->hdl);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ kfree(cam);
+}
+
+static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
+ .s_ctrl = cpia2_s_ctrl,
+};
+
+/******************************************************************************
+ *
+ * cpia2_register_camera
+ *
+ *****************************************************************************/
+int cpia2_register_camera(struct camera_data *cam)
+{
+ struct v4l2_ctrl_handler *hdl = &cam->hdl;
+ struct v4l2_ctrl_config cpia2_usb_alt = {
+ .ops = &cpia2_ctrl_ops,
+ .id = CPIA2_CID_USB_ALT,
+ .name = "USB Alternate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = USBIF_ISO_1,
+ .max = USBIF_ISO_6,
+ .step = 1,
+ };
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 12);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_BRIGHTNESS,
+ cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+ 255, 1, DEFAULT_BRIGHTNESS);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+ 100, 1, 100);
+ cpia2_usb_alt.def = alternate;
+ cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
+ /* VP5 Only */
+ if (cam->params.pnp_id.device_type != DEVICE_STV_672)
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ /* Flicker control only valid for 672 */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+ /* Light control only valid for the QX5 Microscope */
+ if (cam->params.pnp_id.product == 0x151) {
+ cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+ cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &cam->top_light);
+ }
+
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ cam->vdev = cpia2_template;
+ video_set_drvdata(&cam->vdev, cam);
+ cam->vdev.lock = &cam->v4l2_lock;
+ cam->vdev.ctrl_handler = hdl;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+
+ reset_camera_struct_v4l(cam);
+
+ /* register v4l device */
+ if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+ ERR("video_register_device failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_unregister_camera
+ *
+ *****************************************************************************/
+void cpia2_unregister_camera(struct camera_data *cam)
+{
+ video_unregister_device(&cam->vdev);
+}
+
+/******************************************************************************
+ *
+ * check_parameters
+ *
+ * Make sure that all user-supplied parameters are sensible
+ *****************************************************************************/
+static void __init check_parameters(void)
+{
+ if(buffer_size < PAGE_SIZE) {
+ buffer_size = PAGE_SIZE;
+ LOG("buffer_size too small, setting to %d\n", buffer_size);
+ } else if(buffer_size > 1024*1024) {
+ /* arbitrary upper limiit */
+ buffer_size = 1024*1024;
+ LOG("buffer_size ridiculously large, setting to %d\n",
+ buffer_size);
+ } else {
+ buffer_size += PAGE_SIZE-1;
+ buffer_size &= ~(PAGE_SIZE-1);
+ }
+
+ if(num_buffers < 1) {
+ num_buffers = 1;
+ LOG("num_buffers too small, setting to %d\n", num_buffers);
+ } else if(num_buffers > VIDEO_MAX_FRAME) {
+ num_buffers = VIDEO_MAX_FRAME;
+ LOG("num_buffers too large, setting to %d\n", num_buffers);
+ }
+
+ if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+ alternate = DEFAULT_ALT;
+ LOG("alternate specified is invalid, using %d\n", alternate);
+ }
+
+ if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
+ flicker_mode = 0;
+ LOG("Flicker mode specified is invalid, using %d\n",
+ flicker_mode);
+ }
+
+ DBG("Using %d buffers, each %d bytes, alternate=%d\n",
+ num_buffers, buffer_size, alternate);
+}
+
+/************ Module Stuff ***************/
+
+
+/******************************************************************************
+ *
+ * cpia2_init/module_init
+ *
+ *****************************************************************************/
+static int __init cpia2_init(void)
+{
+ LOG("%s v%s\n",
+ ABOUT, CPIA_VERSION);
+ check_parameters();
+ cpia2_usb_init();
+ return 0;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_exit/module_exit
+ *
+ *****************************************************************************/
+static void __exit cpia2_exit(void)
+{
+ cpia2_usb_cleanup();
+ schedule_timeout(2 * HZ);
+}
+
+module_init(cpia2_init);
+module_exit(cpia2_exit);
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
new file mode 100644
index 000000000000..77913dfbd238
--- /dev/null
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -0,0 +1,51 @@
+config VIDEO_CX231XX
+ tristate "Conexant cx231xx USB video capture support"
+ depends on VIDEO_DEV && I2C
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ depends on RC_CORE
+ select VIDEOBUF_VMALLOC
+ select VIDEO_CX25840
+ select VIDEO_CX2341X
+
+ ---help---
+ This is a video4linux driver for Conexant 231xx USB based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx231xx
+
+config VIDEO_CX231XX_RC
+ bool "Conexant cx231xx Remote Controller additional support"
+ depends on RC_CORE
+ depends on VIDEO_CX231XX
+ default y
+ ---help---
+ cx231xx hardware has a builtin RX/TX support. However, a few
+ designs opted to not use it, but, instead, some other hardware.
+ This module enables the usage of those other hardware, like the
+ ones used with ISDB-T boards.
+
+ On most cases, all you need for IR is mceusb module.
+
+config VIDEO_CX231XX_ALSA
+ tristate "Conexant Cx231xx ALSA audio module"
+ depends on VIDEO_CX231XX && SND
+ select SND_PCM
+
+ ---help---
+ This is an ALSA driver for Cx231xx USB based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx231xx-alsa
+
+config VIDEO_CX231XX_DVB
+ tristate "DVB/ATSC Support for Cx231xx based TV cards"
+ depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS
+ select VIDEOBUF_DVB
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
+
+ ---help---
+ This adds support for DVB cards based on the
+ Conexant cx231xx chips.
diff --git a/drivers/media/usb/cx231xx/Makefile b/drivers/media/usb/cx231xx/Makefile
new file mode 100644
index 000000000000..52cf76935e69
--- /dev/null
+++ b/drivers/media/usb/cx231xx/Makefile
@@ -0,0 +1,15 @@
+cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o
+cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o
+
+cx231xx-alsa-objs := cx231xx-audio.o
+
+obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
+obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
+obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/usb/dvb-usb
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
new file mode 100644
index 000000000000..b024e5197a75
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -0,0 +1,2197 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx231xx host port.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.us>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2008 Steven Toth <stoth@linuxtv.org>
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+#include <linux/usb.h>
+
+#include "cx231xx.h"
+/*#include "cx23885-ioctl.h"*/
+
+#define CX231xx_FIRM_IMAGE_SIZE 376836
+#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+/* for polaris ITVC */
+#define ITVC_WRITE_DIR 0x03FDFC00
+#define ITVC_READ_DIR 0x0001FC00
+
+#define MCI_MEMORY_DATA_BYTE0 0x00
+#define MCI_MEMORY_DATA_BYTE1 0x08
+#define MCI_MEMORY_DATA_BYTE2 0x10
+#define MCI_MEMORY_DATA_BYTE3 0x18
+
+#define MCI_MEMORY_ADDRESS_BYTE2 0x20
+#define MCI_MEMORY_ADDRESS_BYTE1 0x28
+#define MCI_MEMORY_ADDRESS_BYTE0 0x30
+
+#define MCI_REGISTER_DATA_BYTE0 0x40
+#define MCI_REGISTER_DATA_BYTE1 0x48
+#define MCI_REGISTER_DATA_BYTE2 0x50
+#define MCI_REGISTER_DATA_BYTE3 0x58
+
+#define MCI_REGISTER_ADDRESS_BYTE0 0x60
+#define MCI_REGISTER_ADDRESS_BYTE1 0x68
+
+#define MCI_REGISTER_MODE 0x70
+
+/* Read and write modes for polaris ITVC */
+#define MCI_MODE_REGISTER_READ 0x000
+#define MCI_MODE_REGISTER_WRITE 0x100
+#define MCI_MODE_MEMORY_READ 0x000
+#define MCI_MODE_MEMORY_WRITE 0x4000
+
+static unsigned int mpegbufs = 8;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 128;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+ "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug = 1;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+struct cx231xx_dmaqueue *dma_qq;
+#define dprintk(level, fmt, arg...)\
+ do { if (v4l_debug >= level) \
+ printk(KERN_INFO "%s: " fmt, \
+ (dev) ? dev->name : "cx231xx[?]", ## arg); \
+ } while (0)
+
+static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }, {
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ }, {
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ }, {
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }, {
+ .name = "PAL-N",
+ .id = V4L2_STD_PAL_N,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ }, {
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ }, {
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx231xx_capture_type {
+ CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_CAPTURE,
+ CX231xx_RAW_PASSTHRU_CAPTURE
+};
+enum cx231xx_capture_bits {
+ CX231xx_RAW_BITS_NONE = 0x00,
+ CX231xx_RAW_BITS_YUV_CAPTURE = 0x01,
+ CX231xx_RAW_BITS_PCM_CAPTURE = 0x02,
+ CX231xx_RAW_BITS_VBI_CAPTURE = 0x04,
+ CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+enum cx231xx_capture_end {
+ CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
+ CX231xx_END_NOW, /* stop immediately, no irq */
+};
+enum cx231xx_framerate {
+ CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+enum cx231xx_stream_port {
+ CX231xx_OUTPUT_PORT_MEMORY,
+ CX231xx_OUTPUT_PORT_STREAMING,
+ CX231xx_OUTPUT_PORT_SERIAL
+};
+enum cx231xx_data_xfer_status {
+ CX231xx_MORE_BUFFERS_FOLLOW,
+ CX231xx_LAST_BUFFER,
+};
+enum cx231xx_picture_mask {
+ CX231xx_PICTURE_MASK_NONE,
+ CX231xx_PICTURE_MASK_I_FRAMES,
+ CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
+ CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx231xx_vbi_mode_bits {
+ CX231xx_VBI_BITS_SLICED,
+ CX231xx_VBI_BITS_RAW,
+};
+enum cx231xx_vbi_insertion_bits {
+ CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx231xx_dma_unit {
+ CX231xx_DMA_BYTES,
+ CX231xx_DMA_FRAMES,
+};
+enum cx231xx_dma_transfer_status_bits {
+ CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
+ CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
+ CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx231xx_pause {
+ CX231xx_PAUSE_ENCODING,
+ CX231xx_RESUME_ENCODING,
+};
+enum cx231xx_copyright {
+ CX231xx_COPYRIGHT_OFF,
+ CX231xx_COPYRIGHT_ON,
+};
+enum cx231xx_notification_type {
+ CX231xx_NOTIFICATION_REFRESH,
+};
+enum cx231xx_notification_status {
+ CX231xx_NOTIFICATION_OFF,
+ CX231xx_NOTIFICATION_ON,
+};
+enum cx231xx_notification_mailbox {
+ CX231xx_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx231xx_field1_lines {
+ CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx231xx_field2_lines {
+ CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx231xx_custom_data_type {
+ CX231xx_CUSTOM_EXTENSION_USR_DATA,
+ CX231xx_CUSTOM_PRIVATE_PACKET,
+};
+enum cx231xx_mute {
+ CX231xx_UNMUTE,
+ CX231xx_MUTE,
+};
+enum cx231xx_mute_video_mask {
+ CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx231xx_mute_video_shift {
+ CX231xx_MUTE_VIDEO_V_SHIFT = 8,
+ CX231xx_MUTE_VIDEO_U_SHIFT = 16,
+ CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/*
+ * Bit definitions for MC417_RWD and MC417_OEN registers
+ *
+ * bits 31-16
+ *+-----------+
+ *| Reserved |
+ *|+-----------+
+ *| bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *| bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define MC417_MIWR 0x8000
+#define MC417_MIRD 0x4000
+#define MC417_MICS 0x2000
+#define MC417_MIRDY 0x1000
+#define MC417_MIADDR 0x0F00
+#define MC417_MIDATA 0x00FF
+
+
+/* Bit definitions for MC417_CTL register ****
+ *bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
+ *+--------+-------------+--------+--------------+------------+
+ *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
+ *+--------+-------------+--------+--------------+------------+
+ */
+#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN 0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW 0x1
+#define MC417_SPD_CTL_MEDIUM 0x0
+#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3 0x3
+#define MC417_GPIO_SEL_GPIO2 0x2
+#define MC417_GPIO_SEL_GPIO1 0x1
+#define MC417_GPIO_SEL_GPIO0 0x0
+
+
+#define CX23417_GPIO_MASK 0xFC0003FF
+static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+{
+ int status = 0;
+ u32 _gpio_direction = 0;
+
+ _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+ _gpio_direction = _gpio_direction|gpio_direction;
+ status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+ (u8 *)&value, 4, 0, 0);
+ return status;
+}
+static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+{
+ int status = 0;
+ u32 _gpio_direction = 0;
+
+ _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+ _gpio_direction = _gpio_direction|gpio_direction;
+
+ status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+ (u8 *)pValue, 4, 0, 1);
+ return status;
+}
+
+static int waitForMciComplete(struct cx231xx *dev)
+{
+ u32 gpio;
+ u32 gpio_driection = 0;
+ u8 count = 0;
+ getITVCReg(dev, gpio_driection, &gpio);
+
+ while (!(gpio&0x020000)) {
+ msleep(10);
+
+ getITVCReg(dev, gpio_driection, &gpio);
+
+ if (count++ > 100) {
+ dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
+{
+ u32 temp;
+ int status = 0;
+
+ temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
+ temp = temp<<10;
+ status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (status < 0)
+ return status;
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 1;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 0;*/
+ temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1;*/
+ temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*Write that the mode is write.*/
+ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ return waitForMciComplete(dev);
+}
+
+static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
+{
+ /*write address byte 0;*/
+ u32 temp;
+ u32 return_value = 0;
+ int ret = 0;
+
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1;*/
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write that the mode is read;*/
+ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*wait for the MIRDY line to be asserted ,
+ signalling that the read is done;*/
+ ret = waitForMciComplete(dev);
+
+ /*switch the DATA- GPIO to input mode;*/
+
+ /*Read data byte 0;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 18);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /* Read data byte 1;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+
+ return_value |= ((temp & 0x03FC0000) >> 10);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /*Read data byte 2;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 2);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /*Read data byte 3;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) << 6);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ *value = return_value;
+
+
+ return ret;
+}
+
+static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
+{
+ /*write data byte 0;*/
+
+ u32 temp;
+ int ret = 0;
+
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+ temp = temp << 10;
+ ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (ret < 0)
+ return ret;
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 1;*/
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 1;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 0;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*wait for MIRDY line;*/
+ waitForMciComplete(dev);
+
+ return 0;
+}
+
+static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
+{
+ u32 temp = 0;
+ u32 return_value = 0;
+ int ret = 0;
+
+ /*write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (ret < 0)
+ return ret;
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 0*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*Wait for MIRDY line*/
+ ret = waitForMciComplete(dev);
+
+
+ /*Read data byte 3;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)<<6);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /*Read data byte 2;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>2);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /* Read data byte 1;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>10);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /*Read data byte 0;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>18);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ *value = return_value;
+ return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+ switch (cmd) {
+ case CX2341X_ENC_PING_FW:
+ return "PING_FW";
+ case CX2341X_ENC_START_CAPTURE:
+ return "START_CAPTURE";
+ case CX2341X_ENC_STOP_CAPTURE:
+ return "STOP_CAPTURE";
+ case CX2341X_ENC_SET_AUDIO_ID:
+ return "SET_AUDIO_ID";
+ case CX2341X_ENC_SET_VIDEO_ID:
+ return "SET_VIDEO_ID";
+ case CX2341X_ENC_SET_PCR_ID:
+ return "SET_PCR_PID";
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return "SET_FRAME_RATE";
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return "SET_FRAME_SIZE";
+ case CX2341X_ENC_SET_BIT_RATE:
+ return "SET_BIT_RATE";
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return "SET_GOP_PROPERTIES";
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return "SET_ASPECT_RATIO";
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return "SET_CORING_LEVELS";
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return "SET_SPATIAL_FILTER_TYPE";
+ case CX2341X_ENC_SET_VBI_LINE:
+ return "SET_VBI_LINE";
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return "SET_STREAM_TYPE";
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return "SET_OUTPUT_PORT";
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return "SET_AUDIO_PROPERTIES";
+ case CX2341X_ENC_HALT_FW:
+ return "HALT_FW";
+ case CX2341X_ENC_GET_VERSION:
+ return "GET_VERSION";
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return "SET_GOP_CLOSURE";
+ case CX2341X_ENC_GET_SEQ_END:
+ return "GET_SEQ_END";
+ case CX2341X_ENC_SET_PGM_INDEX_INFO:
+ return "SET_PGM_INDEX_INFO";
+ case CX2341X_ENC_SET_VBI_CONFIG:
+ return "SET_VBI_CONFIG";
+ case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+ return "SET_DMA_BLOCK_SIZE";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+ return "GET_PREV_DMA_INFO_MB_10";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+ return "GET_PREV_DMA_INFO_MB_9";
+ case CX2341X_ENC_SCHED_DMA_TO_HOST:
+ return "SCHED_DMA_TO_HOST";
+ case CX2341X_ENC_INITIALIZE_INPUT:
+ return "INITIALIZE_INPUT";
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return "SET_FRAME_DROP_RATE";
+ case CX2341X_ENC_PAUSE_ENCODER:
+ return "PAUSE_ENCODER";
+ case CX2341X_ENC_REFRESH_INPUT:
+ return "REFRESH_INPUT";
+ case CX2341X_ENC_SET_COPYRIGHT:
+ return "SET_COPYRIGHT";
+ case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+ return "SET_EVENT_NOTIFICATION";
+ case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+ return "SET_NUM_VSYNC_LINES";
+ case CX2341X_ENC_SET_PLACEHOLDER:
+ return "SET_PLACEHOLDER";
+ case CX2341X_ENC_MUTE_VIDEO:
+ return "MUTE_VIDEO";
+ case CX2341X_ENC_MUTE_AUDIO:
+ return "MUTE_AUDIO";
+ case CX2341X_ENC_MISC:
+ return "MISC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int cx231xx_mbox_func(void *priv,
+ u32 command,
+ int in,
+ int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx231xx *dev = priv;
+ unsigned long timeout;
+ u32 value, flag, retval = 0;
+ int i;
+
+ dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+ cmd_to_str(command));
+
+ /* this may not be 100% safe if we can't read any memory location
+ without side effects */
+ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ dprintk(3,
+ "Firmware and/or mailbox pointer not initialized "
+ "or corrupted, signature = 0x%x, cmd = %s\n", value,
+ cmd_to_str(command));
+ return -1;
+ }
+
+ /* This read looks at 32 bits, but flag is only 8 bits.
+ * Seems we also bail if CMD or TIMEOUT bytes are set???
+ */
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (flag) {
+ dprintk(3, "ERROR: Mailbox appears to be in use "
+ "(%x), cmd = %s\n", flag, cmd_to_str(command));
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* write command + args + fill remaining with zeros */
+ /* command code */
+ mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+ mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+ IVTV_API_STD_TIMEOUT); /* timeout */
+ for (i = 0; i < in; i++) {
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+ dprintk(3, "API Input %d = %d\n", i, data[i]);
+ }
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+ flag |= 3; /* tell 'em we're done writing */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (0 != (flag & 4))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dprintk(3, "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
+ udelay(10);
+ }
+
+ /* read output values */
+ for (i = 0; i < out; i++) {
+ mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+ dprintk(3, "API Output %d = %d\n", i, data[i]);
+ }
+
+ mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+ dprintk(3, "API result = %d\n", retval);
+
+ flag = 0;
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx231xx_api_cmd(struct cx231xx *dev,
+ u32 command,
+ u32 inputcnt,
+ u32 outputcnt,
+ ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+ va_start(vargs, outputcnt);
+ for (i = 0; i < inputcnt; i++)
+ data[i] = va_arg(vargs, int);
+
+ err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+
+ return err;
+}
+
+static int cx231xx_find_mailbox(struct cx231xx *dev)
+{
+ u32 signature[4] = {
+ 0x12345678, 0x34567812, 0x56781234, 0x78123456
+ };
+ int signaturecnt = 0;
+ u32 value;
+ int i;
+ int ret = 0;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
+ ret = mc417_memory_read(dev, i, &value);
+ if (ret < 0)
+ return ret;
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+ return i+1;
+ }
+ }
+ dprintk(3, "Mailbox signature values not found!\n");
+ return -1;
+}
+
+static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+ u32 *p_fw_image)
+{
+
+ u32 temp = 0;
+ int i = 0;
+
+ temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 1;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 1;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 0;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ for (i = 0; i < 6; i++) {
+ *p_fw_image = 0xFFFFFFFF;
+ p_fw_image++;
+ }
+}
+
+
+static int cx231xx_load_firmware(struct cx231xx *dev)
+{
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
+ int i, retval = 0;
+ u32 value = 0;
+ u32 gpio_output = 0;
+ /*u32 checksum = 0;*/
+ /*u32 *dataptr;*/
+ u32 transfer_size = 0;
+ u32 fw_data = 0;
+ u32 address = 0;
+ /*u32 current_fw[800];*/
+ u32 *p_current_fw, *p_fw;
+ u32 *p_fw_data;
+ int frame = 0;
+ u16 _buffer_size = 4096;
+ u8 *p_buffer;
+
+ p_current_fw = vmalloc(1884180 * 4);
+ p_fw = p_current_fw;
+ if (p_current_fw == NULL) {
+ dprintk(2, "FAIL!!!\n");
+ return -1;
+ }
+
+ p_buffer = vmalloc(4096);
+ if (p_buffer == NULL) {
+ dprintk(2, "FAIL!!!\n");
+ return -1;
+ }
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Save GPIO settings before reset of APU */
+ retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+ retval |= mc417_memory_read(dev, 0x900C, &value);
+
+ retval = mc417_register_write(dev,
+ IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_APU, 0);
+
+ if (retval != 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return -1;
+ }
+
+ retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
+ &dev->udev->dev);
+
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+ CX231xx_FIRM_IMAGE_NAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+ }
+
+ if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
+ printk(KERN_ERR "ERROR: Firmware size mismatch "
+ "(have %zd, expected %d)\n",
+ firmware->size, CX231xx_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
+ return -1;
+ }
+
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ printk(KERN_ERR
+ "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
+ return -1;
+ }
+
+ initGPIO(dev);
+
+ /* transfer to the chip */
+ dprintk(2, "Loading firmware to GPIO...\n");
+ p_fw_data = (u32 *)firmware->data;
+ dprintk(2, "firmware->size=%zd\n", firmware->size);
+ for (transfer_size = 0; transfer_size < firmware->size;
+ transfer_size += 4) {
+ fw_data = *p_fw_data;
+
+ mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+ address = address + 1;
+ p_current_fw += 20;
+ p_fw_data += 1;
+ }
+
+ /*download the firmware by ep5-out*/
+
+ for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
+ frame++) {
+ for (i = 0; i < _buffer_size; i++) {
+ *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
+ }
+ cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
+ }
+
+ p_current_fw = p_fw;
+ vfree(p_current_fw);
+ p_current_fw = NULL;
+ uninitGPIO(dev);
+ release_firmware(firmware);
+ dprintk(1, "Firmware upload successful.\n");
+
+ retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+ IVTV_CMD_HW_BLOCKS_RST);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return retval;
+ }
+ /* 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_read(dev, IVTV_REG_VPU, &value);
+ retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+ if (retval < 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return retval;
+ }
+ return 0;
+}
+
+static void cx231xx_417_check_encoder(struct cx231xx *dev)
+{
+ u32 status, seq;
+
+ status = 0;
+ seq = 0;
+ cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+ dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx231xx_codec_settings(struct cx231xx *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ /* assign frame size */
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->ts1.height, dev->ts1.width);
+
+ dev->mpeg_params.width = dev->ts1.width;
+ dev->mpeg_params.height = dev->ts1.height;
+
+ cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+
+ cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+ cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx231xx_initialize_codec(struct cx231xx *dev)
+{
+ int version;
+ int retval;
+ u32 i;
+ u32 val = 0;
+
+ dprintk(1, "%s()\n", __func__);
+ cx231xx_disable656(dev);
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(2, "%s() PING OK\n", __func__);
+ retval = cx231xx_load_firmware(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ return retval;
+ }
+ retval = cx231xx_find_mailbox(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() mailbox < 0, error\n",
+ __func__);
+ return -1;
+ }
+ dev->cx23417_mailbox = retval;
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "ERROR: cx23417 firmware ping failed!\n");
+ return -1;
+ }
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+ &version);
+ if (retval < 0) {
+ printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+ "version failed!\n");
+ return -1;
+ }
+ dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+ msleep(200);
+ }
+
+ for (i = 0; i < 1; i++) {
+ retval = mc417_register_read(dev, 0x20f8, &val);
+ dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+ val);
+ if (retval < 0)
+ return retval;
+ }
+
+ cx231xx_enable656(dev);
+ /* stop mpeg capture */
+ cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
+ 3, 0, 1, 3, 4);
+
+ cx231xx_codec_settings(dev);
+ msleep(60);
+
+/* cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0);
+*/
+
+#if 0
+ /* TODO */
+ u32 data[7];
+
+ /* Setup to capture VBI */
+ data[0] = 0x0001BD00;
+ data[1] = 1; /* frames per interrupt */
+ data[2] = 4; /* total bufs */
+ data[3] = 0x91559155; /* start codes */
+ data[4] = 0x206080C0; /* stop codes */
+ data[5] = 6; /* lines */
+ data[6] = 64; /* BPL */
+
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6]);
+
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ valid = ((i >= 19) && (i <= 21));
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+ valid, 0 , 0, 0);
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+ i | 0x80000000, valid, 0, 0, 0);
+ }
+#endif
+/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
+ msleep(60);
+*/
+ /* initialize the video input */
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+ if (retval < 0)
+ return retval;
+ msleep(60);
+
+ /* Enable VIP style pixel invalidation so we work with scaled mode */
+ mc417_memory_write(dev, 2120, 0x00000080);
+
+ /* start capturing to the host interface */
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
+ if (retval < 0)
+ return retval;
+ msleep(10);
+
+ for (i = 0; i < 1; i++) {
+ mc417_register_read(dev, 0x20f8, &val);
+ dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+
+ fh->dev->ts1.ts_packet_size = mpeglinesize;
+ fh->dev->ts1.ts_packet_count = mpeglines;
+
+ *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+ *count = mpegbufs;
+
+ return 0;
+}
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned long flags = 0;
+
+ if (in_interrupt())
+ BUG();
+
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
+ if (dev->USE_ISO) {
+ if (dev->video_mode.isoc_ctl.buf == buf)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ } else {
+ if (dev->video_mode.bulk_ctl.buf == buf)
+ dev->video_mode.bulk_ctl.buf = NULL;
+ }
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+ videobuf_waiton(vq, &buf->vb, 0, 0);
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+ u32 tail_data = 0;
+ char *p_data;
+
+ if (dma_q->mpeg_buffer_done == 0) {
+ if (list_empty(&dma_q->active))
+ return;
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+ dev->video_mode.isoc_ctl.buf = buf;
+ dma_q->mpeg_buffer_done = 1;
+ }
+ /* Fill buffer */
+ buf = dev->video_mode.isoc_ctl.buf;
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+
+ if ((dma_q->mpeg_buffer_completed+len) <
+ mpeglines*mpeglinesize) {
+ if (dma_q->add_ps_package_head ==
+ CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ dma_q->ps_head, 3);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + 3;
+ dma_q->add_ps_package_head =
+ CX231XX_NONEED_PS_PACKAGE_HEAD;
+ }
+ memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + len;
+ } else {
+ dma_q->mpeg_buffer_done = 0;
+
+ tail_data =
+ mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ data, tail_data);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ dma_q->mpeg_buffer_completed = 0;
+
+ if (len - tail_data > 0) {
+ p_data = data + tail_data;
+ dma_q->left_data_count = len - tail_data;
+ memcpy(dma_q->p_left_data,
+ p_data, len - tail_data);
+ }
+
+ }
+
+ return;
+}
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+
+ if (list_empty(&dma_q->active))
+ return;
+
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+
+
+ /* Fill buffer */
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+ memcpy(vbuf, data, len);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+
+ return;
+}
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *p_buffer;
+ u32 buffer_size = 0;
+ u32 i = 0;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (dma_q->left_data_count > 0) {
+ buffer_copy(dev, dma_q->p_left_data,
+ dma_q->left_data_count, urb, dma_q);
+ dma_q->mpeg_buffer_completed = dma_q->left_data_count;
+ dma_q->left_data_count = 0;
+ }
+
+ p_buffer = urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ buffer_size = urb->iso_frame_desc[i].actual_length;
+
+ if (buffer_size > 0)
+ buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
+ }
+
+ return 0;
+}
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+
+ /*char *outp;*/
+ /*struct cx231xx_buffer *buf;*/
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *p_buffer, *buffer;
+ u32 buffer_size = 0;
+
+ p_buffer = urb->transfer_buffer;
+ buffer_size = urb->actual_length;
+
+ buffer = kmalloc(buffer_size, GFP_ATOMIC);
+
+ memcpy(buffer, dma_q->ps_head, 3);
+ memcpy(buffer+3, p_buffer, buffer_size-3);
+ memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
+
+ p_buffer = buffer;
+ buffer_filled(p_buffer, buffer_size, urb, dma_q);
+
+ kfree(buffer);
+ return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+ int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+
+ dma_qq = &dev->video_mode.vidq;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ return -EINVAL;
+ buf->vb.width = fh->dev->ts1.ts_packet_size;
+ buf->vb.height = fh->dev->ts1.ts_packet_count;
+ buf->vb.size = size;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (dev->USE_ISO) {
+ if (!dev->video_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+ } else {
+ if (!dev->video_mode.bulk_ctl.num_bufs)
+ urb_init = 1;
+ }
+ /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);*/
+ dev->mode_tv = 1;
+
+ if (urb_init) {
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ rc = cx231xx_unmute_audio(dev);
+ if (dev->USE_ISO) {
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+ rc = cx231xx_init_isoc(dev, mpeglines,
+ mpegbufs,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ } else {
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ rc = cx231xx_init_bulk(dev, mpeglines,
+ mpegbufs,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(q, buf);
+ return rc;
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ /*struct cx231xx_fh *fh = q->priv_data;*/
+ /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
+
+ free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx231xx_queryctrl(struct cx231xx *dev,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+ return 0;
+}
+
+static int cx231xx_querymenu(struct cx231xx *dev,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx231xx_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
+}
+
+static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ *norm = dev->encodernorm.id;
+ return 0;
+}
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
+ if (*id & cx231xx_tvnorms[i].id)
+ break;
+ if (i == ARRAY_SIZE(cx231xx_tvnorms))
+ return -EINVAL;
+ dev->encodernorm = cx231xx_tvnorms[i];
+
+ if (dev->encodernorm.id & 0xb000) {
+ dprintk(3, "encodernorm set to NTSC\n");
+ dev->norm = V4L2_STD_NTSC;
+ dev->ts1.height = 480;
+ dev->mpeg_params.is_50hz = 0;
+ } else {
+ dprintk(3, "encodernorm set to PAL\n");
+ dev->norm = V4L2_STD_PAL_B;
+ dev->ts1.height = 576;
+ dev->mpeg_params.is_50hz = 1;
+ }
+ call_all(dev, core, s_std, dev->norm);
+ /* do mode control overrides */
+ cx231xx_do_mode_ctrl_overrides(dev);
+
+ dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
+ return 0;
+}
+static int vidioc_g_audio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ struct v4l2_audio *vin = a;
+
+ int ret = -EINVAL;
+ if (vin->index > 0)
+ return ret;
+ strncpy(vin->name, "VideoGrabber Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+return 0;
+}
+static int vidioc_enumaudio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ struct v4l2_audio *vin = a;
+
+ int ret = -EINVAL;
+
+ if (vin->index > 0)
+ return ret;
+ strncpy(vin->name, "VideoGrabber Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+
+
+return 0;
+}
+static const char *iname[] = {
+ [CX231XX_VMUX_COMPOSITE1] = "Composite1",
+ [CX231XX_VMUX_SVIDEO] = "S-Video",
+ [CX231XX_VMUX_TELEVISION] = "Television",
+ [CX231XX_VMUX_CABLE] = "Cable TV",
+ [CX231XX_VMUX_DVB] = "DVB",
+ [CX231XX_VMUX_DEBUG] = "for debug only",
+};
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_input *input;
+ int n;
+ dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
+
+ if (i->index >= 4)
+ return -EINVAL;
+
+
+ input = &cx231xx_boards[dev->model].input[i->index];
+
+ if (input->type == 0)
+ return -EINVAL;
+
+ /* FIXME
+ * strcpy(i->name, input->name); */
+
+ n = i->index;
+ strcpy(i->name, iname[INPUT(n)->type]);
+
+ if (input->type == CX231XX_VMUX_TELEVISION ||
+ input->type == CX231XX_VMUX_CABLE)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(3, "enter vidioc_s_input() i=%d\n", i);
+
+ mutex_lock(&dev->lock);
+
+ video_mux(dev, i);
+
+ mutex_unlock(&dev->lock);
+
+ if (i >= 4)
+ return -EINVAL;
+ dev->input = i;
+ dprintk(3, "exit vidioc_s_input()\n");
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_s_ctrl()\n");
+ /* Update the A/V core */
+ call_all(dev, core, s_ctrl, ctl);
+ dprintk(3, "exit vidioc_s_ctrl()\n");
+ return 0;
+}
+static struct v4l2_capability pvr_capability = {
+ .driver = "cx231xx",
+ .card = "VideoGrabber",
+ .bus_info = "usb",
+ .version = 1,
+ .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
+};
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+
+
+
+ memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->vidq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_reqbufs(&fh->vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_querybuf(&fh->vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_qbuf(&fh->vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_streamon()\n");
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (dev->USE_ISO)
+ cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else {
+ cx231xx_init_bulk(dev, 320,
+ 5,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
+ dprintk(3, "exit vidioc_streamon()\n");
+ return videobuf_streamon(&fh->vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_streamoff(&fh->vidq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_g_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ dprintk(3, "exit vidioc_g_ext_ctrls()\n");
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+ dprintk(3, "enter vidioc_s_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ if (err == 0) {
+ err = cx2341x_update(dev, cx231xx_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
+ }
+
+ return err;
+
+
+return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+ dprintk(3, "enter vidioc_try_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
+ return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ dprintk(3,
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ call_all(dev, core, log_status);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ dprintk(3,
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_querymenu()\n");
+ dprintk(3, "exit vidioc_querymenu()\n");
+ return cx231xx_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_queryctrl()\n");
+ dprintk(3, "exit vidioc_queryctrl()\n");
+ return cx231xx_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+ int minor = video_devdata(file)->minor;
+ struct cx231xx *h, *dev = NULL;
+ /*struct list_head *list;*/
+ struct cx231xx_fh *fh;
+ /*u32 value = 0;*/
+
+ dprintk(2, "%s()\n", __func__);
+
+ list_for_each_entry(h, &cx231xx_devlist, devlist) {
+ if (h->v4l_device->minor == minor)
+ dev = h;
+ }
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ mutex_lock(&dev->lock);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh) {
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+
+ videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
+ NULL, &dev->video_mode.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer), fh, NULL);
+/*
+ videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
+ &dev->udev->dev, &dev->ts1.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer),
+ fh, NULL);
+*/
+
+
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+ cx231xx_set_gpio_value(dev, 2, 0);
+
+ cx231xx_initialize_codec(dev);
+
+ mutex_unlock(&dev->lock);
+ cx231xx_start_TS1(dev);
+
+ return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
+
+ if (!dev) {
+ dprintk(3, "abort!!!\n");
+ return 0;
+ }
+
+ mutex_lock(&dev->lock);
+
+ cx231xx_stop_TS1(dev);
+
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+ cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_BITS_NONE);
+
+ /* FIXME: Review this crap */
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+ /* stop mpeg capture */
+
+ msleep(500);
+ cx231xx_417_check_encoder(dev);
+
+ }
+ }
+
+ if (fh->vidq.streaming)
+ videobuf_streamoff(&fh->vidq);
+ if (fh->vidq.reading)
+ videobuf_read_stop(&fh->vidq);
+
+ videobuf_mmap_free(&fh->vidq);
+ file->private_data = NULL;
+ kfree(fh);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+
+ /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+ /* 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 (cx231xx_initialize_codec(dev) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ /*struct cx231xx *dev = fh->dev;*/
+
+ /*dprintk(2, "%s\n", __func__);*/
+
+ return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enumaudio = vidioc_enumaudio,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .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_s_ctrl = vidioc_s_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,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .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_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_querymenu = vidioc_querymenu,
+ .vidioc_queryctrl = vidioc_queryctrl,
+/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* .vidioc_g_register = cx231xx_g_register,*/
+/* .vidioc_s_register = cx231xx_s_register,*/
+#endif
+};
+
+static struct video_device cx231xx_mpeg_template = {
+ .name = "cx231xx",
+ .fops = &mpeg_fops,
+ .ioctl_ops = &mpeg_ioctl_ops,
+ .minor = -1,
+ .tvnorms = CX231xx_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+void cx231xx_417_unregister(struct cx231xx *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+ dprintk(3, "%s()\n", __func__);
+
+ if (dev->v4l_device) {
+ if (-1 != dev->v4l_device->minor)
+ video_unregister_device(dev->v4l_device);
+ else
+ video_device_release(dev->v4l_device);
+ dev->v4l_device = NULL;
+ }
+}
+
+static struct video_device *cx231xx_video_dev_alloc(
+ struct cx231xx *dev,
+ struct usb_device *usbdev,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+
+ dprintk(1, "%s()\n", __func__);
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, cx231xx_boards[dev->model].name);
+
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+
+ return vfd;
+
+}
+
+int cx231xx_417_register(struct cx231xx *dev)
+{
+ /* FIXME: Port1 hardcoded here */
+ int err = -ENODEV;
+ struct cx231xx_tsport *tsport = &dev->ts1;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Set default TV standard */
+ dev->encodernorm = cx231xx_tvnorms[0];
+
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ tsport->height = 480;
+ else
+ tsport->height = 576;
+
+ tsport->width = 720;
+ cx2341x_fill_defaults(&dev->mpeg_params);
+ dev->norm = V4L2_STD_NTSC;
+
+ dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+ /* Allocate and initialize V4L video device */
+ dev->v4l_device = cx231xx_video_dev_alloc(dev,
+ dev->udev, &cx231xx_mpeg_template, "mpeg");
+ err = video_register_device(dev->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ dprintk(3, "%s: can't register mpeg device\n", dev->name);
+ return err;
+ }
+
+ dprintk(3, "%s: registered device video%d [mpeg]\n",
+ dev->name, dev->v4l_device->num);
+
+ return 0;
+}
+
+MODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index b4c99c7270cf..b4c99c7270cf 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 447148eff958..447148eff958 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 02d4d36735d3..02d4d36735d3 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
diff --git a/drivers/media/video/cx231xx/cx231xx-conf-reg.h b/drivers/media/usb/cx231xx/cx231xx-conf-reg.h
index 25593f212abf..25593f212abf 100644
--- a/drivers/media/video/cx231xx/cx231xx-conf-reg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-conf-reg.h
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 05358d486135..05358d486135 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
diff --git a/drivers/media/video/cx231xx/cx231xx-dif.h b/drivers/media/usb/cx231xx/cx231xx-dif.h
index 2b63c2f6d3b0..2b63c2f6d3b0 100644
--- a/drivers/media/video/cx231xx/cx231xx-dif.h
+++ b/drivers/media/usb/cx231xx/cx231xx-dif.h
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 7c4e360ba9bc..7c4e360ba9bc 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 781feed406f7..781feed406f7 100644
--- a/drivers/media/video/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 96176e9db5a2..96176e9db5a2 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
diff --git a/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index 7473c33e823e..7473c33e823e 100644
--- a/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
diff --git a/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
index f5e46e89f3ab..f5e46e89f3ab 100644
--- a/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
diff --git a/drivers/media/video/cx231xx/cx231xx-reg.h b/drivers/media/usb/cx231xx/cx231xx-reg.h
index 750c5d37d569..750c5d37d569 100644
--- a/drivers/media/video/cx231xx/cx231xx-reg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-reg.h
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index ac7db52f404f..ac7db52f404f 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.h b/drivers/media/usb/cx231xx/cx231xx-vbi.h
index 16c7d20a22a4..16c7d20a22a4 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.h
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.h
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
new file mode 100644
index 000000000000..790b28d7f764
--- /dev/null
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -0,0 +1,2670 @@
+/*
+ cx231xx-video.c - driver for Conexant Cx23100/101/102
+ USB video capture devices
+
+ Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ Based on em28xx driver
+ Based on cx23885 driver
+ Based on cx88 driver
+
+ 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#include "dvb_frontend.h"
+
+#include "cx231xx.h"
+#include "cx231xx-vbi.h"
+
+#define CX231XX_VERSION "0.0.2"
+
+#define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
+#define DRIVER_DESC "Conexant cx231xx based USB video device driver"
+
+#define cx231xx_videodbg(fmt, arg...) do {\
+ if (video_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define cx231xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CX231XX_VERSION);
+
+static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card, int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(card, "card type");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+/* supported video standards */
+static struct cx231xx_fmt format[] = {
+ {
+ .name = "16bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .reg = 0,
+ },
+};
+
+/* supported controls */
+/* Common to all boards */
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+ .name = "42",
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx231xx_ctrl cx231xx_ctls[] = {
+ /* --- video --- */
+ {
+ .v = {
+ .id = V4L2_CID_BRIGHTNESS,
+ .name = "Brightness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 128,
+ .reg = LUMA_CTRL,
+ .mask = 0x00ff,
+ .shift = 0,
+ }, {
+ .v = {
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x3f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 0,
+ .reg = LUMA_CTRL,
+ .mask = 0xff00,
+ .shift = 8,
+ }, {
+ .v = {
+ .id = V4L2_CID_HUE,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 128,
+ .reg = CHROMA_CTRL,
+ .mask = 0xff0000,
+ .shift = 16,
+ }, {
+ /* strictly, this only describes only U saturation.
+ * V saturation is handled specially through code.
+ */
+ .v = {
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x7f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .off = 0,
+ .reg = CHROMA_CTRL,
+ .mask = 0x00ff,
+ .shift = 0,
+ }, {
+ /* --- audio --- */
+ .v = {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+ .reg = PATH1_CTL1,
+ .mask = (0x1f << 24),
+ .shift = 24,
+ }, {
+ .v = {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ .default_value = 0x3f,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+ .reg = PATH1_VOL_CTL,
+ .mask = 0xff,
+ .shift = 0,
+ }
+};
+static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
+
+static const u32 cx231xx_user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+#if 0
+ V4L2_CID_AUDIO_BALANCE,
+#endif
+ V4L2_CID_AUDIO_MUTE,
+ 0
+};
+
+static const u32 *ctrl_classes[] = {
+ cx231xx_user_ctrls,
+ NULL
+};
+
+/* ------------------------------------------------------------------
+ Video buffer and parser functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ else
+ dev->video_mode.bulk_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static inline void print_err_status(struct cx231xx *dev, int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
+ struct cx231xx_buffer **buf)
+{
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ cx231xx_isocdbg("No active queue to serve\n");
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ else
+ dev->video_mode.bulk_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = *buf;
+ else
+ dev->video_mode.bulk_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ int i, rc = 1;
+ unsigned char *p_buffer;
+ u32 bytes_parsed = 0, buffer_size = 0;
+ u8 sav_eav = 0;
+
+ if (!dev)
+ return 0;
+
+ if (dev->state & DEV_DISCONNECTED)
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* cx231xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->video_mode.max_pkt_size) {
+ cx231xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ /* get buffer pointer and length */
+ p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ buffer_size = urb->iso_frame_desc[i].actual_length;
+ bytes_parsed = 0;
+
+ if (dma_q->is_partial_line) {
+ /* Handle the case of a partial line */
+ sav_eav = dma_q->last_sav;
+ } else {
+ /* Check for a SAV/EAV overlapping
+ the buffer boundary */
+ sav_eav =
+ cx231xx_find_boundary_SAV_EAV(p_buffer,
+ dma_q->partial_buf,
+ &bytes_parsed);
+ }
+
+ sav_eav &= 0xF0;
+ /* Get the first line if we have some portion of an SAV/EAV from
+ the last buffer or a partial line */
+ if (sav_eav) {
+ bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+ sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed);/* buf size */
+ }
+
+ /* Now parse data that is completely in this buffer */
+ /* dma_q->is_partial_line = 0; */
+
+ while (bytes_parsed < buffer_size) {
+ u32 bytes_used = 0;
+
+ sav_eav = cx231xx_find_next_SAV_EAV(
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed, /* buf size */
+ &bytes_used);/* bytes used to get SAV/EAV */
+
+ bytes_parsed += bytes_used;
+
+ sav_eav &= 0xF0;
+ if (sav_eav && (bytes_parsed < buffer_size)) {
+ bytes_parsed += cx231xx_get_video_line(dev,
+ dma_q, sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed,/* p_buffer */
+ buffer_size - bytes_parsed);/*buf size*/
+ }
+ }
+
+ /* Save the last four bytes of the buffer so we can check the
+ buffer boundary condition next time */
+ memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+ bytes_parsed = 0;
+
+ }
+ return rc;
+}
+
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ int rc = 1;
+ unsigned char *p_buffer;
+ u32 bytes_parsed = 0, buffer_size = 0;
+ u8 sav_eav = 0;
+
+ if (!dev)
+ return 0;
+
+ if (dev->state & DEV_DISCONNECTED)
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ if (1) {
+
+ /* get buffer pointer and length */
+ p_buffer = urb->transfer_buffer;
+ buffer_size = urb->actual_length;
+ bytes_parsed = 0;
+
+ if (dma_q->is_partial_line) {
+ /* Handle the case of a partial line */
+ sav_eav = dma_q->last_sav;
+ } else {
+ /* Check for a SAV/EAV overlapping
+ the buffer boundary */
+ sav_eav =
+ cx231xx_find_boundary_SAV_EAV(p_buffer,
+ dma_q->partial_buf,
+ &bytes_parsed);
+ }
+
+ sav_eav &= 0xF0;
+ /* Get the first line if we have some portion of an SAV/EAV from
+ the last buffer or a partial line */
+ if (sav_eav) {
+ bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+ sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed);/* buf size */
+ }
+
+ /* Now parse data that is completely in this buffer */
+ /* dma_q->is_partial_line = 0; */
+
+ while (bytes_parsed < buffer_size) {
+ u32 bytes_used = 0;
+
+ sav_eav = cx231xx_find_next_SAV_EAV(
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed, /* buf size */
+ &bytes_used);/* bytes used to get SAV/EAV */
+
+ bytes_parsed += bytes_used;
+
+ sav_eav &= 0xF0;
+ if (sav_eav && (bytes_parsed < buffer_size)) {
+ bytes_parsed += cx231xx_get_video_line(dev,
+ dma_q, sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed,/* p_buffer */
+ buffer_size - bytes_parsed);/*buf size*/
+ }
+ }
+
+ /* Save the last four bytes of the buffer so we can check the
+ buffer boundary condition next time */
+ memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+ bytes_parsed = 0;
+
+ }
+ return rc;
+}
+
+
+u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
+ u32 *p_bytes_used)
+{
+ u32 bytes_used;
+ u8 boundary_bytes[8];
+ u8 sav_eav = 0;
+
+ *p_bytes_used = 0;
+
+ /* Create an array of the last 4 bytes of the last buffer and the first
+ 4 bytes of the current buffer. */
+
+ memcpy(boundary_bytes, partial_buf, 4);
+ memcpy(boundary_bytes + 4, p_buffer, 4);
+
+ /* Check for the SAV/EAV in the boundary buffer */
+ sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
+ &bytes_used);
+
+ if (sav_eav) {
+ /* found a boundary SAV/EAV. Updates the bytes used to reflect
+ only those used in the new buffer */
+ *p_bytes_used = bytes_used - 4;
+ }
+
+ return sav_eav;
+}
+
+u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
+{
+ u32 i;
+ u8 sav_eav = 0;
+
+ /*
+ * Don't search if the buffer size is less than 4. It causes a page
+ * fault since buffer_size - 4 evaluates to a large number in that
+ * case.
+ */
+ if (buffer_size < 4) {
+ *p_bytes_used = buffer_size;
+ return 0;
+ }
+
+ for (i = 0; i < (buffer_size - 3); i++) {
+
+ if ((p_buffer[i] == 0xFF) &&
+ (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
+
+ *p_bytes_used = i + 4;
+ sav_eav = p_buffer[i + 3];
+ return sav_eav;
+ }
+ }
+
+ *p_bytes_used = buffer_size;
+ return 0;
+}
+
+u32 cx231xx_get_video_line(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
+ u8 *p_buffer, u32 buffer_size)
+{
+ u32 bytes_copied = 0;
+ int current_field = -1;
+
+ switch (sav_eav) {
+ case SAV_ACTIVE_VIDEO_FIELD1:
+ /* looking for skipped line which occurred in PAL 720x480 mode.
+ In this case, there will be no active data contained
+ between the SAV and EAV */
+ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+ (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+ ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+ (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD1) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD2)))
+ return bytes_copied;
+ current_field = 1;
+ break;
+
+ case SAV_ACTIVE_VIDEO_FIELD2:
+ /* looking for skipped line which occurred in PAL 720x480 mode.
+ In this case, there will be no active data contained between
+ the SAV and EAV */
+ if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
+ (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
+ ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
+ (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD1) ||
+ (p_buffer[3] == EAV_VBLANK_FIELD2)))
+ return bytes_copied;
+ current_field = 2;
+ break;
+ }
+
+ dma_q->last_sav = sav_eav;
+
+ bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
+ buffer_size, current_field);
+
+ return bytes_copied;
+}
+
+u32 cx231xx_copy_video_line(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q, u8 *p_line,
+ u32 length, int field_number)
+{
+ u32 bytes_to_copy;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width * 2;
+
+ if (dma_q->current_field != field_number)
+ cx231xx_reset_video_buffer(dev, dma_q);
+
+ /* get the buffer pointer */
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
+
+ /* Remember the field number for next time */
+ dma_q->current_field = field_number;
+
+ bytes_to_copy = dma_q->bytes_left_in_line;
+ if (bytes_to_copy > length)
+ bytes_to_copy = length;
+
+ if (dma_q->lines_completed >= dma_q->lines_per_field) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
+ 0 : 1;
+ return 0;
+ }
+
+ dma_q->is_partial_line = 1;
+
+ /* If we don't have a buffer, just return the number of bytes we would
+ have copied if we had a buffer. */
+ if (!buf) {
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+ dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
+ ? 0 : 1;
+ return bytes_to_copy;
+ }
+
+ /* copy the data to video buffer */
+ cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
+
+ dma_q->pos += bytes_to_copy;
+ dma_q->bytes_left_in_line -= bytes_to_copy;
+
+ if (dma_q->bytes_left_in_line == 0) {
+ dma_q->bytes_left_in_line = _line_size;
+ dma_q->lines_completed++;
+ dma_q->is_partial_line = 0;
+
+ if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
+ buffer_filled(dev, dma_q, buf);
+
+ dma_q->pos = 0;
+ buf = NULL;
+ dma_q->lines_completed = 0;
+ }
+ }
+
+ return bytes_to_copy;
+}
+
+void cx231xx_reset_video_buffer(struct cx231xx *dev,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ struct cx231xx_buffer *buf;
+
+ /* handle the switch from field 1 to field 2 */
+ if (dma_q->current_field == 1) {
+ if (dma_q->lines_completed >= dma_q->lines_per_field)
+ dma_q->field1_done = 1;
+ else
+ dma_q->field1_done = 0;
+ }
+
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
+
+ if (buf == NULL) {
+ /* first try to get the buffer */
+ get_next_buf(dma_q, &buf);
+
+ dma_q->pos = 0;
+ dma_q->field1_done = 0;
+ dma_q->current_field = -1;
+ }
+
+ /* reset the counters */
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_completed = 0;
+}
+
+int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
+ u8 *p_buffer, u32 bytes_to_copy)
+{
+ u8 *p_out_buffer = NULL;
+ u32 current_line_bytes_copied = 0;
+ struct cx231xx_buffer *buf;
+ u32 _line_size = dev->width << 1;
+ void *startwrite;
+ int offset, lencopy;
+
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
+
+ if (buf == NULL)
+ return -1;
+
+ p_out_buffer = videobuf_to_vmalloc(&buf->vb);
+
+ current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
+
+ /* Offset field 2 one line from the top of the buffer */
+ offset = (dma_q->current_field == 1) ? 0 : _line_size;
+
+ /* Offset for field 2 */
+ startwrite = p_out_buffer + offset;
+
+ /* lines already completed in the current field */
+ startwrite += (dma_q->lines_completed * _line_size * 2);
+
+ /* bytes already completed in the current line */
+ startwrite += current_line_bytes_copied;
+
+ lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
+ bytes_to_copy : dma_q->bytes_left_in_line;
+
+ if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size))
+ return 0;
+
+ /* The below copies the UYVY data straight into video buffer */
+ cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
+
+ return 0;
+}
+
+void cx231xx_swab(u16 *from, u16 *to, u16 len)
+{
+ u16 i;
+
+ if (len <= 0)
+ return;
+
+ for (i = 0; i < len / 2; i++)
+ to[i] = (from[i] << 8) | (from[i] >> 8);
+}
+
+u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
+{
+ u8 buffer_complete = 0;
+
+ /* Dual field stream */
+ buffer_complete = ((dma_q->current_field == 2) &&
+ (dma_q->lines_completed >= dma_q->lines_per_field) &&
+ dma_q->field1_done);
+
+ return buffer_complete;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
+ if (0 == *count)
+ *count = CX231XX_DEF_BUF;
+
+ if (*count < CX231XX_MIN_BUF)
+ *count = CX231XX_MIN_BUF;
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned long flags = 0;
+
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
+ if (dev->USE_ISO) {
+ if (dev->video_mode.isoc_ctl.buf == buf)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ } else {
+ if (dev->video_mode.bulk_ctl.buf == buf)
+ dev->video_mode.bulk_ctl.buf = NULL;
+ }
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+ + 7) >> 3;
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (dev->USE_ISO) {
+ if (!dev->video_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+ } else {
+ if (!dev->video_mode.bulk_ctl.num_bufs)
+ urb_init = 1;
+ }
+ /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);*/
+ if (urb_init) {
+ dev->mode_tv = 0;
+ if (dev->USE_ISO)
+ rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else
+ rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = (struct cx231xx *)fh->dev;
+
+ cx231xx_isocdbg("cx231xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
+
+void video_mux(struct cx231xx *dev, int index)
+{
+ dev->video_input = index;
+ dev->ctl_ainput = INPUT(index)->amux;
+
+ cx231xx_set_video_input_mux(dev, index);
+
+ cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0);
+
+ cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+ cx231xx_info("video_mux : %d\n", index);
+
+ /* do mode control overrides if required */
+ cx231xx_do_mode_ctrl_overrides(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct cx231xx_fh *fh)
+{
+ struct cx231xx *dev = fh->dev;
+ int rc = 0;
+
+ /* This instance already has stream_on */
+ if (fh->stream_on)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (dev->stream_on)
+ return -EBUSY;
+ dev->stream_on = 1;
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (dev->vbi_stream_on)
+ return -EBUSY;
+ dev->vbi_stream_on = 1;
+ } else
+ return -EINVAL;
+
+ fh->stream_on = 1;
+
+ return rc;
+}
+
+static int res_check(struct cx231xx_fh *fh)
+{
+ return fh->stream_on;
+}
+
+static void res_free(struct cx231xx_fh *fh)
+{
+ struct cx231xx *dev = fh->dev;
+
+ fh->stream_on = 0;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ dev->stream_on = 0;
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ dev->vbi_stream_on = 0;
+}
+
+static int check_dev(struct cx231xx *dev)
+{
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_errdev("v4l2 ioctl: device not present\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return &format[i];
+
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ unsigned int width = f->fmt.pix.width;
+ unsigned int height = f->fmt.pix.height;
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+ struct cx231xx_fmt *fmt;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ /* width must even because of the YUYV format
+ height must be even because of interlacing */
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
+
+ f->fmt.pix.width = width;
+ f->fmt.pix.height = height;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+ struct cx231xx_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ vidioc_try_fmt_vid_cap(file, priv, f);
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt)
+ return -EINVAL;
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ cx231xx_errdev("%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ if (dev->stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ return -EBUSY;
+ }
+
+ /* set new image size */
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->format = fmt;
+
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+
+ return rc;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ *id = dev->norm;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct v4l2_format f;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
+
+ dev->norm = *norm;
+
+ /* Adjusts width/height, if needed */
+ f.fmt.pix.width = dev->width;
+ f.fmt.pix.height = dev->height;
+ vidioc_try_fmt_vid_cap(file, priv, &f);
+
+ call_all(dev, core, s_std, dev->norm);
+
+ /* We need to reset basic properties in the decoder related to
+ resolution (since a standard change effects things like the number
+ of lines in VACT, etc) */
+ v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
+
+ /* set new image size */
+ dev->width = f.fmt.pix.width;
+ dev->height = f.fmt.pix.height;
+
+ /* do mode control overrides */
+ cx231xx_do_mode_ctrl_overrides(dev);
+
+ return 0;
+}
+
+static const char *iname[] = {
+ [CX231XX_VMUX_COMPOSITE1] = "Composite1",
+ [CX231XX_VMUX_SVIDEO] = "S-Video",
+ [CX231XX_VMUX_TELEVISION] = "Television",
+ [CX231XX_VMUX_CABLE] = "Cable TV",
+ [CX231XX_VMUX_DVB] = "DVB",
+ [CX231XX_VMUX_DEBUG] = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ u32 gen_stat;
+ unsigned int ret, n;
+
+ n = i->index;
+ if (n >= MAX_CX231XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strcpy(i->name, iname[INPUT(n)->type]);
+
+ if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (CX231XX_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ i->std = dev->vdev->tvnorms;
+
+ /* If they are asking about the active input, read signal status */
+ if (n == dev->video_input) {
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ GEN_STAT, 2, &gen_stat, 4);
+ if (ret > 0) {
+ if ((gen_stat & FLD_VPRES) == 0x00)
+ i->status |= V4L2_IN_ST_NO_SIGNAL;
+ if ((gen_stat & FLD_HLOCK) == 0x00)
+ i->status |= V4L2_IN_ST_NO_H_LOCK;
+ }
+ }
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ *i = dev->video_input;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ dev->mode_tv = 0;
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (i >= MAX_CX231XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(i)->type)
+ return -EINVAL;
+
+ video_mux(dev, i);
+
+ if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
+ INPUT(i)->type == CX231XX_VMUX_CABLE) {
+ /* There's a tuner, so reset the standard and put it on the
+ last known frequency (since it was probably powered down
+ until now */
+ call_all(dev, core, s_std, dev->norm);
+ }
+
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ switch (a->index) {
+ case CX231XX_AMUX_VIDEO:
+ strcpy(a->name, "Television");
+ break;
+ case CX231XX_AMUX_LINE_IN:
+ strcpy(a->name, "Line In");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ a->index = dev->ctl_ainput;
+ a->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int status = 0;
+
+ /* Doesn't allow manual routing */
+ if (a->index != dev->ctl_ainput)
+ return -EINVAL;
+
+ dev->ctl_ainput = INPUT(a->index)->amux;
+ status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
+
+ return status;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int id = qc->id;
+ int i;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
+ if (unlikely(qc->id == 0))
+ return -EINVAL;
+
+ memset(qc, 0, sizeof(*qc));
+
+ qc->id = id;
+
+ if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+
+ for (i = 0; i < CX231XX_CTLS; i++)
+ if (cx231xx_ctls[i].v.id == qc->id)
+ break;
+
+ if (i == CX231XX_CTLS) {
+ *qc = no_ctl;
+ return 0;
+ }
+ *qc = cx231xx_ctls[i].v;
+
+ call_all(dev, core, queryctrl, qc);
+
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ call_all(dev, core, g_ctrl, ctrl);
+ return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ call_all(dev, core, s_ctrl, ctrl);
+ return rc;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "Tuner");
+
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+ t->signal = 0xffff; /* LOCKED */
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+#if 0
+ call_all(dev, tuner, s_tuner, t);
+#endif
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
+
+ call_all(dev, tuner, g_frequency, f);
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+ u32 if_frequency = 5400000;
+
+ cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+ f->frequency, f->type);
+ /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ 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;
+
+ /* set pre channel change settings in DIF first */
+ rc = cx231xx_tuner_pre_channel_change(dev);
+
+ dev->ctl_freq = f->frequency;
+ call_all(dev, tuner, s_frequency, f);
+
+ /* set post channel change settings in DIF first */
+ rc = cx231xx_tuner_post_channel_change(dev);
+
+ if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
+ if_frequency = 5400000; /*5.4MHz */
+ else if (dev->norm & V4L2_STD_B)
+ if_frequency = 6000000; /*6.0MHz */
+ else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
+ if_frequency = 6900000; /*6.9MHz */
+ else if (dev->norm & V4L2_STD_GH)
+ if_frequency = 7100000; /*7.1MHz */
+ else if (dev->norm & V4L2_STD_PAL_I)
+ if_frequency = 7250000; /*7.25MHz */
+ else if (dev->norm & V4L2_STD_SECAM_L)
+ if_frequency = 6900000; /*6.9MHz */
+ else if (dev->norm & V4L2_STD_SECAM_LC)
+ if_frequency = 1250000; /*1.25MHz */
+
+ cx231xx_info("if_frequency is set to %d\n", if_frequency);
+ cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
+
+ update_HH_register_after_set_DIF(dev);
+ }
+
+ cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
+
+ return rc;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+ -R, --list-registers=type=<host/i2cdrv/i2caddr>,
+ chip=<chip>[,min=<addr>,max=<addr>]
+ dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
+ -r, --set-register=type=<host/i2cdrv/i2caddr>,
+ chip=<chip>,reg=<addr>,val=<val>
+ set the register [VIDIOC_DBG_S_REGISTER]
+
+ if type == host, then <chip> is the hosts chip ID (default 0)
+ if type == i2cdrv (default), then <chip> is the I2C driver name or ID
+ if type == i2caddr, then <chip> is the 7-bit I2C address
+*/
+
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int ret = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+ u32 data = 0;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ switch (reg->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ (u16)reg->reg, value, 4);
+ reg->val = value[0] | value[1] << 8 |
+ value[2] << 16 | value[3] << 24;
+ break;
+ case 1: /* AFE - read byte */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 14: /* AFE - read dword */
+ ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 2: /* Video Block - read byte */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 24: /* Video Block - read dword */
+ ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 3: /* I2S block - read byte */
+ ret = cx231xx_read_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ &data, 1);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 34: /* I2S Block - read dword */
+ ret =
+ cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1, &data, 4);
+ reg->val = le32_to_cpu(data);
+ break;
+ }
+ return ret < 0 ? ret : 0;
+
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ call_all(dev, core, g_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
+ switch (reg->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ (u16)reg->reg, value, 4);
+ reg->val = value[0] | value[1] << 8 |
+ value[2] << 16 | value[3] << 24;
+
+ break;
+ case 0x600:/* AFE - read byte */
+ ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+
+ case 0x880:/* Video Block - read byte */
+ if (reg->reg < 0x0b) {
+ ret = cx231xx_read_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ } else {
+ ret = cx231xx_read_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 4 , 0);
+ reg->val = le32_to_cpu(data);
+ }
+ break;
+ case 0x980:
+ ret = cx231xx_read_i2c_master(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0x400:
+ ret =
+ cx231xx_read_i2c_master(dev, 0x40,
+ (u16)reg->reg, 1,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0xc01:
+ ret =
+ cx231xx_read_i2c_master(dev, 0xc0,
+ (u16)reg->reg, 2,
+ &data, 38, 1);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 0x022:
+ ret =
+ cx231xx_read_i2c_master(dev, 0x02,
+ (u16)reg->reg, 1,
+ &data, 1, 2);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0x322:
+ ret = cx231xx_read_i2c_master(dev,
+ 0x32,
+ (u16)reg->reg, 1,
+ &data, 4 , 2);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 0x342:
+ ret = cx231xx_read_i2c_master(dev,
+ 0x34,
+ (u16)reg->reg, 1,
+ &data, 4 , 2);
+ reg->val = le32_to_cpu(data);
+ break;
+
+ default:
+ cx231xx_info("no match device address!!\n");
+ break;
+ }
+ return ret < 0 ? ret : 0;
+ /*return -EINVAL;*/
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ call_all(dev, core, g_register, reg);
+
+ return ret;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int ret = 0;
+ __le64 buf;
+ u32 value;
+ u8 data[4] = { 0, 0, 0, 0 };
+
+ buf = cpu_to_le64(reg->val);
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ {
+ value = (u32) buf & 0xffffffff;
+
+ switch (reg->match.addr) {
+ case 0: /* cx231xx internal registers */
+ data[0] = (u8) value;
+ data[1] = (u8) (value >> 8);
+ data[2] = (u8) (value >> 16);
+ data[3] = (u8) (value >> 24);
+ ret = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ (u16)reg->reg, data,
+ 4);
+ break;
+ case 1: /* AFE - read byte */
+ ret = cx231xx_write_i2c_data(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1);
+ break;
+ case 14: /* AFE - read dword */
+ ret = cx231xx_write_i2c_data(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4);
+ break;
+ case 2: /* Video Block - read byte */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1);
+ break;
+ case 24: /* Video Block - read dword */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4);
+ break;
+ case 3: /* I2S block - read byte */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 1);
+ break;
+ case 34: /* I2S block - read dword */
+ ret =
+ cx231xx_write_i2c_data(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 4);
+ break;
+ }
+ }
+ return ret < 0 ? ret : 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ {
+ value = (u32) buf & 0xffffffff;
+
+ switch (reg->match.addr) {
+ case 0:/*cx231xx internal registers*/
+ data[0] = (u8) value;
+ data[1] = (u8) (value >> 8);
+ data[2] = (u8) (value >> 16);
+ data[3] = (u8) (value >> 24);
+ ret = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ (u16)reg->reg, data,
+ 4);
+ break;
+ case 0x600:/* AFE - read byte */
+ ret = cx231xx_write_i2c_master(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1 , 0);
+ break;
+
+ case 0x880:/* Video Block - read byte */
+ if (reg->reg < 0x0b)
+ cx231xx_write_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1, 0);
+ else
+ cx231xx_write_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4, 0);
+ break;
+ case 0x980:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 1, 0);
+ break;
+ case 0x400:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x40,
+ (u16)reg->reg, 1,
+ value, 1, 0);
+ break;
+ case 0xc01:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0xc0,
+ (u16)reg->reg, 1,
+ value, 1, 1);
+ break;
+
+ case 0x022:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x02,
+ (u16)reg->reg, 1,
+ value, 1, 2);
+ case 0x322:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x32,
+ (u16)reg->reg, 1,
+ value, 4, 2);
+ break;
+
+ case 0x342:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x34,
+ (u16)reg->reg, 1,
+ value, 4, 2);
+ break;
+ default:
+ cx231xx_info("no match device address, "
+ "the value is %x\n", reg->match.addr);
+ break;
+
+ }
+
+ }
+ default:
+ break;
+ }
+
+ call_all(dev, core, s_register, reg);
+
+ return ret;
+}
+#endif
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ rc = res_get(fh);
+
+ if (likely(rc >= 0))
+ rc = videobuf_streamon(&fh->vb_vidq);
+
+ call_all(dev, video, s_stream, 1);
+
+ return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+ if (type != fh->type)
+ return -EINVAL;
+
+ cx25840_call(dev, video, s_stream, 0);
+
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
+
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->capabilities = V4L2_CAP_VBI_CAPTURE |
+#if 0
+ V4L2_CAP_SLICED_VBI_CAPTURE |
+#endif
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
+ return -EINVAL;
+
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+
+ return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ f->fmt.sliced.service_set = 0;
+
+ call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+ if (f->fmt.sliced.service_set == 0)
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+ if (f->fmt.sliced.service_set == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ f->fmt.vbi.sampling_rate = 6750000 * 4;
+ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 0;
+ f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+ f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES;
+ f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+ f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+ return 0;
+
+}
+
+static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (dev->vbi_stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ return -EBUSY;
+ }
+
+ f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ f->fmt.vbi.sampling_rate = 6750000 * 4;
+ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 0;
+ f->fmt.vbi.flags = 0;
+ f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
+ f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_LINES : NTSC_VBI_LINES;
+ f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
+ PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
+ f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+
+ return 0;
+
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ if (unlikely(t->index > 0))
+ return -EINVAL;
+
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+ call_all(dev, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name, "Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
+
+ strcpy(a->name, "Radio");
+ return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+ struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ call_all(dev, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+ return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ int i;
+
+ if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX231XX_CTLS; i++) {
+ if (cx231xx_ctls[i].v.id == c->id)
+ break;
+ }
+ if (i == CX231XX_CTLS)
+ return -EINVAL;
+ *c = cx231xx_ctls[i].v;
+ } else
+ *c = no_ctl;
+ return 0;
+}
+
+/*
+ * cx231xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int cx231xx_v4l2_open(struct file *filp)
+{
+ int errCode = 0, radio = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct cx231xx *dev = video_drvdata(filp);
+ struct cx231xx_fh *fh;
+ enum v4l2_buf_type fh_type = 0;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+ case VFL_TYPE_RADIO:
+ radio = 1;
+ break;
+ }
+
+ cx231xx_videodbg("open dev=%s type=%s users=%d\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type],
+ dev->users);
+
+#if 0
+ errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("Device locked on digital mode. Can't open analog\n");
+ return -EBUSY;
+ }
+#endif
+
+ fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
+ if (!fh) {
+ cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
+ return -ENOMEM;
+ }
+ if (mutex_lock_interruptible(&dev->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ fh->dev = dev;
+ fh->radio = radio;
+ fh->type = fh_type;
+ filp->private_data = fh;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+
+ /* Power up in Analog TV mode */
+ if (dev->board.external_av)
+ cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ENXTERNAL_AV);
+ else
+ cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+
+#if 0
+ cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
+#endif
+
+ /* set video alternate setting */
+ cx231xx_set_video_alternate(dev);
+
+ /* Needed, since GPIO might have disabled power of
+ some i2c device */
+ cx231xx_config_i2c(dev);
+
+ /* device needs to be initialized before isoc transfer */
+ dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+ }
+ if (fh->radio) {
+ cx231xx_videodbg("video_open: setting radio device\n");
+
+ /* cx231xx_start_radio(dev); */
+
+ call_all(dev, tuner, s_radio);
+ }
+
+ dev->users++;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
+ NULL, &dev->video_mode.slock,
+ fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer),
+ fh, &dev->lock);
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ /* Set the required alternate setting VBI interface works in
+ Bulk mode only */
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
+ NULL, &dev->vbi_mode.slock,
+ fh->type, V4L2_FIELD_SEQ_TB,
+ sizeof(struct cx231xx_buffer),
+ fh, &dev->lock);
+ }
+ mutex_unlock(&dev->lock);
+
+ return errCode;
+}
+
+/*
+ * cx231xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void cx231xx_release_analog_resources(struct cx231xx *dev)
+{
+
+ /*FIXME: I2C IR should be disconnected */
+
+ if (dev->radio_dev) {
+ if (video_is_registered(dev->radio_dev))
+ video_unregister_device(dev->radio_dev);
+ else
+ video_device_release(dev->radio_dev);
+ dev->radio_dev = NULL;
+ }
+ if (dev->vbi_dev) {
+ cx231xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vbi_dev));
+ if (video_is_registered(dev->vbi_dev))
+ video_unregister_device(dev->vbi_dev);
+ else
+ video_device_release(dev->vbi_dev);
+ dev->vbi_dev = NULL;
+ }
+ if (dev->vdev) {
+ cx231xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vdev));
+
+ if (dev->board.has_417)
+ cx231xx_417_unregister(dev);
+
+ if (video_is_registered(dev->vdev))
+ video_unregister_device(dev->vdev);
+ else
+ video_device_release(dev->vdev);
+ dev->vdev = NULL;
+ }
+}
+
+/*
+ * cx231xx_close()
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
+ */
+static int cx231xx_close(struct file *filp)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ cx231xx_videodbg("users=%d\n", dev->users);
+
+ cx231xx_videodbg("users=%d\n", dev->users);
+ if (res_check(fh))
+ res_free(fh);
+
+ /*
+ * To workaround error number=-71 on EP0 for VideoGrabber,
+ * need exclude following.
+ * FIXME: It is probably safe to remove most of these, as we're
+ * now avoiding the alternate setting for INDEX_VANC
+ */
+ if (!dev->board.no_alt_vanc)
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ if (atomic_read(&dev->devlist_count) > 0) {
+ cx231xx_release_resources(dev);
+ fh->dev = NULL;
+ return 0;
+ }
+ return 0;
+ }
+
+ /* do this before setting alternate! */
+ cx231xx_uninit_vbi_isoc(dev);
+
+ /* set alternate 0 */
+ if (!dev->vbi_or_sliced_cc_mode)
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+ else
+ cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ return 0;
+ }
+
+ dev->users--;
+ if (!dev->users) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_release_resources(dev);
+ fh->dev = NULL;
+ return 0;
+ }
+
+ /* Save some power by putting tuner to sleep */
+ call_all(dev, core, s_power, 0);
+
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+ /* set alternate 0 */
+ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
+ }
+ kfree(fh);
+ wake_up_interruptible_nr(&dev->open, 1);
+ return 0;
+}
+
+static int cx231xx_v4l2_close(struct file *filp)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ mutex_lock(&dev->lock);
+ rc = cx231xx_close(filp);
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+/*
+ * cx231xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
+ rc = res_get(fh);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ mutex_unlock(&dev->lock);
+ return rc;
+ }
+ return 0;
+}
+
+/*
+ * cx231xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ rc = res_get(fh);
+
+ if (unlikely(rc < 0))
+ return POLLERR;
+
+ if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
+ (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
+ unsigned int res;
+
+ mutex_lock(&dev->lock);
+ res = videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ mutex_unlock(&dev->lock);
+ return res;
+ }
+ return POLLERR;
+}
+
+/*
+ * cx231xx_v4l2_mmap()
+ */
+static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct cx231xx_fh *fh = filp->private_data;
+ struct cx231xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ rc = res_get(fh);
+
+ if (unlikely(rc < 0))
+ return rc;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ mutex_unlock(&dev->lock);
+
+ cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end -
+ (unsigned long)vma->vm_start, rc);
+
+ return rc;
+}
+
+static const struct v4l2_file_operations cx231xx_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = cx231xx_v4l2_open,
+ .release = cx231xx_v4l2_close,
+ .read = cx231xx_v4l2_read,
+ .poll = cx231xx_v4l2_poll,
+ .mmap = cx231xx_v4l2_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
+ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device cx231xx_vbi_template;
+
+static const struct video_device cx231xx_video_template = {
+ .fops = &cx231xx_v4l_fops,
+ .release = video_device_release,
+ .ioctl_ops = &video_ioctl_ops,
+ .tvnorms = V4L2_STD_ALL,
+ .current_norm = V4L2_STD_PAL,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = cx231xx_v4l2_open,
+ .release = cx231xx_v4l2_close,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device cx231xx_radio_template = {
+ .name = "cx231xx-radio",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+};
+
+/******************************** usb interface ******************************/
+
+static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
+ const struct video_device
+ *template, const char *type_name)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = video_debug;
+ vfd->lock = &dev->lock;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+ video_set_drvdata(vfd, dev);
+ return vfd;
+}
+
+int cx231xx_register_analog_devices(struct cx231xx *dev)
+{
+ int ret;
+
+ cx231xx_info("%s: v4l2 driver version %s\n",
+ dev->name, CX231XX_VERSION);
+
+ /* set default norm */
+ /*dev->norm = cx231xx_video_template.current_norm; */
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->interlaced = 0;
+
+ /* Analog specific initialization */
+ dev->format = &format[0];
+
+ /* Set the initial input */
+ video_mux(dev, dev->video_input);
+
+ /* Audio defaults */
+ dev->mute = 1;
+ dev->volume = 0x1f;
+
+ /* enable vbi capturing */
+ /* write code here... */
+
+ /* allocate and fill video video_device struct */
+ dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
+ if (!dev->vdev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+
+ /* register v4l2 video video_device */
+ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ video_nr[dev->devno]);
+ if (ret) {
+ cx231xx_errdev("unable to register video device (error=%i).\n",
+ ret);
+ return ret;
+ }
+
+ cx231xx_info("%s/0: registered device %s [v4l2]\n",
+ dev->name, video_device_node_name(dev->vdev));
+
+ /* Initialize VBI template */
+ memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
+ sizeof(cx231xx_vbi_template));
+ strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
+
+ /* Allocate and fill vbi video_device struct */
+ dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+
+ /* register v4l2 vbi video_device */
+ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]);
+ if (ret < 0) {
+ cx231xx_errdev("unable to register vbi device\n");
+ return ret;
+ }
+
+ cx231xx_info("%s/0: registered device %s\n",
+ dev->name, video_device_node_name(dev->vbi_dev));
+
+ if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
+ dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
+ "radio");
+ if (!dev->radio_dev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+ ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ radio_nr[dev->devno]);
+ if (ret < 0) {
+ cx231xx_errdev("can't register radio device\n");
+ return ret;
+ }
+ cx231xx_info("Registered radio device as %s\n",
+ video_device_node_name(dev->radio_dev));
+ }
+
+ cx231xx_info("V4L2 device registered as %s and %s\n",
+ video_device_node_name(dev->vdev),
+ video_device_node_name(dev->vbi_dev));
+
+ return 0;
+}
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index a89d020de948..a89d020de948 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
new file mode 100644
index 000000000000..967115104047
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -0,0 +1,146 @@
+config DVB_USB_V2
+ tristate "Support for various USB DVB devices v2"
+ depends on DVB_CORE && USB && I2C && RC_CORE
+ help
+ By enabling this you will be able to choose the various supported
+ USB1.1 and USB2.0 DVB devices.
+
+ Almost every USB device needs a firmware, please look into
+ <file:Documentation/dvb/README.dvb-usb>.
+
+ For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+ <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+ Say Y if you own a USB DVB device.
+
+config DVB_USB_CYPRESS_FIRMWARE
+ tristate "Cypress firmware helper routines"
+ depends on DVB_USB_V2
+
+config DVB_USB_AF9015
+ tristate "Afatech AF9015 DVB-T USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_AF9013
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
+
+config DVB_USB_AF9035
+ tristate "Afatech AF9035 DVB-T USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_AF9033
+ select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Afatech AF9035 based DVB USB receiver.
+
+config DVB_USB_ANYSEE
+ tristate "Anysee DVB-T/C USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Anysee E30, Anysee E30 Plus or
+ Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_AU6610
+ tristate "Alcor Micro AU6610 USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
+config DVB_USB_AZ6007
+ tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_USB_CYPRESS_FIRMWARE
+ select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the AZ6007 receivers like Terratec H7.
+
+config DVB_USB_CE6230
+ tristate "Intel CE6230 DVB-T USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_ZL10353
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
+
+config DVB_USB_EC168
+ tristate "E3C EC168 DVB-T USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_EC100
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+
+config DVB_USB_GL861
+ tristate "Genesys Logic GL861 USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+ receiver with USB ID 0db0:5581.
+
+config DVB_USB_IT913X
+ tristate "ITE IT913X DVB-T USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_IT913X_FE
+ help
+ Say Y here to support the ITE IT913X DVB-T USB2.0
+
+config DVB_USB_LME2510
+ tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_IX2505V if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the LME DM04/QQBOX DVB-S USB2.0
+
+config DVB_USB_MXL111SF
+ tristate "MxL111SF DTV USB2.0 support"
+ depends on DVB_USB_V2
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LG2160 if MEDIA_SUBDRV_AUTOSELECT
+ 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_V2 && EXPERIMENTAL
+ select DVB_RTL2830
+ select DVB_RTL2832
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Realtek RTL28xxU DVB USB receiver.
+
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
new file mode 100644
index 000000000000..58027fd43a08
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -0,0 +1,49 @@
+dvb_usbv2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o
+obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o
+
+dvb_usb_cypress_firmware-objs := cypress_firmware.o
+obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o
+
+dvb-usb-af9015-objs := af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-af9035-objs := af9035.o
+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
+
+dvb-usb-anysee-objs := anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
+dvb-usb-au6610-objs := au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
+dvb-usb-az6007-objs := az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
+dvb-usb-ce6230-objs := ce6230.o
+obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
+
+dvb-usb-ec168-objs := ec168.o
+obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+
+dvb-usb-it913x-objs := it913x.o
+obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
+
+dvb-usb-lmedm04-objs := lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
+dvb-usb-gl861-objs := gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-mxl111sf-objs += mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o
+dvb-usb-mxl111sf-objs += mxl111sf-gpio.o
+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
+
+dvb-usb-rtl28xxu-objs := rtl28xxu.o
+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/tuners
+
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
new file mode 100644
index 000000000000..9afceedc9d1f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -0,0 +1,1435 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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 "af9015.h"
+
+static int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+static int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+#define BUF_LEN 63
+#define REQ_HDR_LEN 8 /* send header size */
+#define ACK_HDR_LEN 2 /* rece header size */
+ struct af9015_state *state = d_to_priv(d);
+ int ret, wlen, rlen;
+ u8 buf[BUF_LEN];
+ u8 write = 1;
+
+ buf[0] = req->cmd;
+ buf[1] = state->seq++;
+ buf[2] = req->i2c_addr;
+ buf[3] = req->addr >> 8;
+ buf[4] = req->addr & 0xff;
+ buf[5] = req->mbox;
+ buf[6] = req->addr_len;
+ buf[7] = req->data_len;
+
+ switch (req->cmd) {
+ case GET_CONFIG:
+ case READ_MEMORY:
+ case RECONNECT_USB:
+ write = 0;
+ break;
+ case READ_I2C:
+ write = 0;
+ buf[2] |= 0x01; /* set I2C direction */
+ case WRITE_I2C:
+ buf[0] = READ_WRITE_I2C;
+ break;
+ case WRITE_MEMORY:
+ if (((req->addr & 0xff00) == 0xff00) ||
+ ((req->addr & 0xff00) == 0xae00))
+ buf[0] = WRITE_VIRTUAL_MEMORY;
+ case WRITE_VIRTUAL_MEMORY:
+ case COPY_FIRMWARE:
+ case DOWNLOAD_FIRMWARE:
+ case BOOT:
+ break;
+ default:
+ err("unknown command:%d", req->cmd);
+ ret = -1;
+ goto error;
+ }
+
+ /* buffer overflow check */
+ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
+ (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
+ err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* write receives seq + status = 2 bytes
+ read receives seq + status + data = 2 + N bytes */
+ wlen = REQ_HDR_LEN;
+ rlen = ACK_HDR_LEN;
+ if (write) {
+ wlen += req->data_len;
+ memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
+ } else {
+ rlen += req->data_len;
+ }
+
+ /* no ack for these packets */
+ if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+ rlen = 0;
+
+ ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ if (ret)
+ goto error;
+
+ /* check status */
+ if (rlen && buf[1]) {
+ err("command failed:%d", buf[1]);
+ ret = -1;
+ goto error;
+ }
+
+ /* read request, copy returned data to return buf */
+ if (!write)
+ memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
+error:
+ return ret;
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+ u8 len)
+{
+ struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+ val};
+ return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
+{
+ struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+ val};
+ return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+ return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+ return af9015_read_regs(d, addr, val, 1);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+ u8 val)
+{
+ struct af9015_state *state = d_to_priv(d);
+ struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+ if (addr == state->af9013_config[0].i2c_addr ||
+ addr == state->af9013_config[1].i2c_addr)
+ req.addr_len = 3;
+
+ return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+ u8 *val)
+{
+ struct af9015_state *state = d_to_priv(d);
+ struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+ if (addr == state->af9013_config[0].i2c_addr ||
+ addr == state->af9013_config[1].i2c_addr)
+ req.addr_len = 3;
+
+ return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+ int ret;
+ u8 val, mask = 0x01;
+
+ ret = af9015_read_reg(d, addr, &val);
+ if (ret)
+ return ret;
+
+ mask <<= bit;
+ if (op) {
+ /* set bit */
+ val |= mask;
+ } else {
+ /* clear bit */
+ mask ^= 0xff;
+ val &= mask;
+ }
+
+ return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+ return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+ return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct af9015_state *state = d_to_priv(d);
+ int ret = 0, i = 0;
+ u16 addr;
+ u8 uninitialized_var(mbox), addr_len;
+ struct req_t req;
+
+/*
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________ ____________ . ____________
+.| uC | | demod | . | tuner |
+.|------------| |------------| . |------------|
+.| AF9015 | | AF9013/5 | . | MXL5003 |
+.| |--+----I2C-------|-----/ -----|-.-----I2C-------| |
+.| | | | addr 0x38 | . | addr 0xc6 |
+.|____________| | |____________| . |____________|
+.................|..............................
+ | ____________ ____________
+ | | demod | | tuner |
+ | |------------| |------------|
+ | | AF9013 | | MXL5003 |
+ +----I2C-------|-----/ -----|-------I2C-------| |
+ | addr 0x3a | | addr 0xc6 |
+ |____________| |____________|
+*/
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ while (i < num) {
+ if (msg[i].addr == state->af9013_config[0].i2c_addr ||
+ msg[i].addr == state->af9013_config[1].i2c_addr) {
+ addr = msg[i].buf[0] << 8;
+ addr += msg[i].buf[1];
+ mbox = msg[i].buf[2];
+ addr_len = 3;
+ } else {
+ addr = msg[i].buf[0];
+ addr_len = 1;
+ /* mbox is don't care in that case */
+ }
+
+ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+ if (msg[i].len > 3 || msg[i+1].len > 61) {
+ ret = -EOPNOTSUPP;
+ goto error;
+ }
+ if (msg[i].addr == state->af9013_config[0].i2c_addr)
+ req.cmd = READ_MEMORY;
+ else
+ req.cmd = READ_I2C;
+ req.i2c_addr = msg[i].addr;
+ req.addr = addr;
+ req.mbox = mbox;
+ req.addr_len = addr_len;
+ req.data_len = msg[i+1].len;
+ req.data = &msg[i+1].buf[0];
+ ret = af9015_ctrl_msg(d, &req);
+ i += 2;
+ } else if (msg[i].flags & I2C_M_RD) {
+ if (msg[i].len > 61) {
+ ret = -EOPNOTSUPP;
+ goto error;
+ }
+ if (msg[i].addr == state->af9013_config[0].i2c_addr) {
+ ret = -EINVAL;
+ goto error;
+ }
+ req.cmd = READ_I2C;
+ req.i2c_addr = msg[i].addr;
+ req.addr = addr;
+ req.mbox = mbox;
+ req.addr_len = addr_len;
+ req.data_len = msg[i].len;
+ req.data = &msg[i].buf[0];
+ ret = af9015_ctrl_msg(d, &req);
+ i += 1;
+ } else {
+ if (msg[i].len > 21) {
+ ret = -EOPNOTSUPP;
+ goto error;
+ }
+ if (msg[i].addr == state->af9013_config[0].i2c_addr)
+ req.cmd = WRITE_MEMORY;
+ else
+ req.cmd = WRITE_I2C;
+ req.i2c_addr = msg[i].addr;
+ req.addr = addr;
+ req.mbox = mbox;
+ req.addr_len = addr_len;
+ req.data_len = msg[i].len-addr_len;
+ req.data = &msg[i].buf[addr_len];
+ ret = af9015_ctrl_msg(d, &req);
+ i += 1;
+ }
+ if (ret)
+ goto error;
+
+ }
+ ret = i;
+
+error:
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+ .master_xfer = af9015_i2c_xfer,
+ .functionality = af9015_i2c_func,
+};
+
+static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ int ret;
+ u8 reply;
+ struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ return ret;
+
+ deb_info("%s: reply:%02x\n", __func__, reply);
+ if (reply == 0x02)
+ ret = WARM;
+ else
+ ret = COLD;
+
+ return ret;
+}
+
+static int af9015_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int i, len, remaining, ret;
+ struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+ u16 checksum = 0;
+
+ deb_info("%s:\n", __func__);
+
+ /* calc checksum */
+ for (i = 0; i < fw->size; i++)
+ checksum += fw->data[i];
+
+ state->firmware_size = fw->size;
+ state->firmware_checksum = checksum;
+
+ #define FW_ADDR 0x5100 /* firmware start address */
+ #define LEN_MAX 55 /* max packet size */
+ for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+ len = remaining;
+ if (len > LEN_MAX)
+ len = LEN_MAX;
+
+ req.data_len = len;
+ req.data = (u8 *) &fw->data[fw->size - remaining];
+ req.addr = FW_ADDR + fw->size - remaining;
+
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret) {
+ err("firmware download failed:%d", ret);
+ goto error;
+ }
+ }
+
+ /* firmware loaded, request boot */
+ req.cmd = BOOT;
+ req.data_len = 0;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret) {
+ err("firmware boot failed:%d", ret);
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/* hash (and dump) eeprom */
+static int af9015_eeprom_hash(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ static const unsigned int eeprom_size = 256;
+ unsigned int reg;
+ u8 val, *eeprom;
+ struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+ eeprom = kmalloc(eeprom_size, GFP_KERNEL);
+ if (eeprom == NULL)
+ return -ENOMEM;
+
+ for (reg = 0; reg < eeprom_size; reg++) {
+ req.addr = reg;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto free;
+
+ eeprom[reg] = val;
+ }
+
+ if (dvb_usb_af9015_debug & 0x01)
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
+ eeprom_size);
+
+ BUG_ON(eeprom_size % 4);
+
+ state->eeprom_sum = 0;
+ for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
+ state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
+ state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
+ }
+
+ deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum);
+
+ ret = 0;
+free:
+ kfree(eeprom);
+ return ret;
+}
+
+static int af9015_read_config(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ u8 val, i, offset = 0;
+ struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+ deb_info("%s:\n", __func__);
+
+ /* IR remote controller */
+ req.addr = AF9015_EEPROM_IR_MODE;
+ /* first message will timeout often due to possible hw bug */
+ for (i = 0; i < 4; i++) {
+ ret = af9015_ctrl_msg(d, &req);
+ if (!ret)
+ break;
+ }
+ if (ret)
+ goto error;
+
+ ret = af9015_eeprom_hash(d);
+ if (ret)
+ goto error;
+
+ deb_info("%s: IR mode=%d\n", __func__, val);
+ state->ir_mode = val;
+
+ /* TS mode - one or two receivers */
+ req.addr = AF9015_EEPROM_TS_MODE;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ state->dual_mode = val;
+ deb_info("%s: TS mode=%d\n", __func__, state->dual_mode);
+
+ /* disable 2nd adapter because we don't have PID-filters */
+ if (d->udev->speed == USB_SPEED_FULL)
+ state->dual_mode = 0;
+
+ if (state->dual_mode) {
+ /* read 2nd demodulator I2C address */
+ req.addr = AF9015_EEPROM_DEMOD2_I2C;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ state->af9013_config[1].i2c_addr = val;
+ }
+
+ for (i = 0; i < state->dual_mode + 1; i++) {
+ if (i == 1)
+ offset = AF9015_EEPROM_OFFSET;
+ /* xtal */
+ req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+ switch (val) {
+ case 0:
+ state->af9013_config[i].clock = 28800000;
+ break;
+ case 1:
+ state->af9013_config[i].clock = 20480000;
+ break;
+ case 2:
+ state->af9013_config[i].clock = 28000000;
+ break;
+ case 3:
+ state->af9013_config[i].clock = 25000000;
+ break;
+ };
+ deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
+ val, state->af9013_config[i].clock);
+
+ /* IF frequency */
+ req.addr = AF9015_EEPROM_IF1H + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ state->af9013_config[i].if_frequency = val << 8;
+
+ req.addr = AF9015_EEPROM_IF1L + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ state->af9013_config[i].if_frequency += val;
+ state->af9013_config[i].if_frequency *= 1000;
+ deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
+ state->af9013_config[i].if_frequency);
+
+ /* MT2060 IF1 */
+ req.addr = AF9015_EEPROM_MT2060_IF1H + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+ state->mt2060_if1[i] = val << 8;
+ req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+ state->mt2060_if1[i] += val;
+ deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
+ state->mt2060_if1[i]);
+
+ /* tuner */
+ req.addr = AF9015_EEPROM_TUNER_ID1 + offset;
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+ switch (val) {
+ case AF9013_TUNER_ENV77H11D5:
+ case AF9013_TUNER_MT2060:
+ case AF9013_TUNER_QT1010:
+ case AF9013_TUNER_UNKNOWN:
+ case AF9013_TUNER_MT2060_2:
+ case AF9013_TUNER_TDA18271:
+ case AF9013_TUNER_QT1010A:
+ case AF9013_TUNER_TDA18218:
+ state->af9013_config[i].spec_inv = 1;
+ break;
+ case AF9013_TUNER_MXL5003D:
+ case AF9013_TUNER_MXL5005D:
+ case AF9013_TUNER_MXL5005R:
+ case AF9013_TUNER_MXL5007T:
+ state->af9013_config[i].spec_inv = 0;
+ break;
+ case AF9013_TUNER_MC44S803:
+ state->af9013_config[i].gpio[1] = AF9013_GPIO_LO;
+ state->af9013_config[i].spec_inv = 1;
+ break;
+ default:
+ warn("tuner id=%d not supported, please report!", val);
+ return -ENODEV;
+ };
+
+ state->af9013_config[i].tuner = val;
+ deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
+ }
+
+error:
+ if (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
+ AVerTV Red HD+ (A850T) device. */
+ if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
+ ((le16_to_cpu(d->udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850) ||
+ (le16_to_cpu(d->udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850T))) {
+ deb_info("%s: AverMedia A850: overriding config\n", __func__);
+ /* disable dual mode */
+ state->dual_mode = 0;
+
+ /* set correct IF */
+ state->af9013_config[0].if_frequency = 4570000;
+ }
+
+ return ret;
+}
+
+static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+ struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+
+ if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL)
+ stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE;
+
+ return 0;
+}
+
+static int af9015_get_adapter_count(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ return state->dual_mode + 1;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
+{
+ int ret;
+ struct af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->set_frontend[fe_to_adap(fe)->id](fe);
+
+ mutex_unlock(&state->fe_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 af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->read_status[fe_to_adap(fe)->id](fe, status);
+
+ mutex_unlock(&state->fe_mutex);
+
+ return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->init[fe_to_adap(fe)->id](fe);
+
+ mutex_unlock(&state->fe_mutex);
+
+ return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->sleep[fe_to_adap(fe)->id](fe);
+
+ mutex_unlock(&state->fe_mutex);
+
+ return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->tuner_init[fe_to_adap(fe)->id](fe);
+
+ mutex_unlock(&state->fe_mutex);
+
+ return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct af9015_state *state = fe_to_priv(fe);
+
+ if (mutex_lock_interruptible(&state->fe_mutex))
+ return -EAGAIN;
+
+ ret = state->tuner_sleep[fe_to_adap(fe)->id](fe);
+
+ mutex_unlock(&state->fe_mutex);
+
+ return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ u8 fw_params[4];
+ u8 val, i;
+ struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+ fw_params };
+ deb_info("%s:\n", __func__);
+
+ fw_params[0] = state->firmware_size >> 8;
+ fw_params[1] = state->firmware_size & 0xff;
+ fw_params[2] = state->firmware_checksum >> 8;
+ fw_params[3] = state->firmware_checksum & 0xff;
+
+ /* wait 2nd demodulator ready */
+ msleep(100);
+
+ ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+ 0x98be, &val);
+ if (ret)
+ goto error;
+ else
+ deb_info("%s: firmware status:%02x\n", __func__, val);
+
+ if (val == 0x0c) /* fw is running, no need for download */
+ goto exit;
+
+ /* set I2C master clock to fast (to speed up firmware copy) */
+ ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+ if (ret)
+ goto error;
+
+ msleep(50);
+
+ /* copy firmware */
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ err("firmware copy cmd failed:%d", ret);
+ deb_info("%s: firmware copy done\n", __func__);
+
+ /* set I2C master clock back to normal */
+ ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+ if (ret)
+ goto error;
+
+ /* request boot firmware */
+ ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr,
+ 0xe205, 1);
+ deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < 15; i++) {
+ msleep(100);
+
+ /* check firmware status */
+ ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+ 0x98be, &val);
+ deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+ __func__, ret, val);
+ if (ret)
+ goto error;
+
+ if (val == 0x0c || val == 0x04) /* success or fail */
+ break;
+ }
+
+ if (val == 0x04) {
+ err("firmware did not run");
+ ret = -1;
+ } else if (val != 0x0c) {
+ err("firmware boot timeout");
+ ret = -1;
+ }
+
+error:
+exit:
+ return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct af9015_state *state = adap_to_priv(adap);
+
+ if (adap->id == 0) {
+ state->af9013_config[0].ts_mode = AF9013_TS_USB;
+ memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4);
+ state->af9013_config[0].gpio[0] = AF9013_GPIO_HI;
+ state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON;
+ } else if (adap->id == 1) {
+ state->af9013_config[1].ts_mode = AF9013_TS_SERIAL;
+ memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4);
+ state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON;
+ state->af9013_config[1].gpio[1] = AF9013_GPIO_LO;
+
+ /* copy firmware to 2nd demodulator */
+ if (state->dual_mode) {
+ ret = af9015_copy_firmware(adap_to_d(adap));
+ if (ret) {
+ err("firmware copy to 2nd frontend " \
+ "failed, will disable it");
+ state->dual_mode = 0;
+ return -ENODEV;
+ }
+ } else {
+ return -ENODEV;
+ }
+ }
+
+ /* attach demodulator */
+ adap->fe[0] = dvb_attach(af9013_attach,
+ &state->af9013_config[adap->id], &adap_to_d(adap)->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.
+ */
+ if (adap->fe[0]) {
+ state->set_frontend[adap->id] =
+ adap->fe[0]->ops.set_frontend;
+ adap->fe[0]->ops.set_frontend =
+ af9015_af9013_set_frontend;
+
+ state->read_status[adap->id] =
+ adap->fe[0]->ops.read_status;
+ adap->fe[0]->ops.read_status =
+ af9015_af9013_read_status;
+
+ state->init[adap->id] = adap->fe[0]->ops.init;
+ adap->fe[0]->ops.init = af9015_af9013_init;
+
+ state->sleep[adap->id] = adap->fe[0]->ops.sleep;
+ adap->fe[0]->ops.sleep = af9015_af9013_sleep;
+ }
+
+ return adap->fe[0] == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+ .i2c_address = 0xc0,
+ .clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+ .i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+ .gate = TDA18271_GATE_DIGITAL,
+ .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+ .i2c_address = 0xc6,
+ .if_freq = IF_FREQ_4570000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_DEFAULT,
+ .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 struct mxl5005s_config af9015_mxl5005_config = {
+ .i2c_address = 0xc6,
+ .if_freq = IF_FREQ_4570000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_OFF,
+ .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 struct mc44s803_config af9015_mc44s803_config = {
+ .i2c_address = 0xc0,
+ .dig_out = 1,
+};
+
+static struct tda18218_config af9015_tda18218_config = {
+ .i2c_address = 0xc0,
+ .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct af9015_state *state = adap_to_priv(adap);
+ int ret;
+ deb_info("%s:\n", __func__);
+
+ switch (state->af9013_config[adap->id].tuner) {
+ case AF9013_TUNER_MT2060:
+ case AF9013_TUNER_MT2060_2:
+ ret = dvb_attach(mt2060_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config,
+ state->mt2060_if1[adap->id])
+ == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_QT1010:
+ case AF9013_TUNER_QT1010A:
+ ret = dvb_attach(qt1010_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_qt1010_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_TDA18271:
+ ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0,
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_tda18271_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_TDA18218:
+ ret = dvb_attach(tda18218_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_MXL5003D:
+ ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_MXL5005D:
+ case AF9013_TUNER_MXL5005R:
+ ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_ENV77H11D5:
+ ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0,
+ &adap_to_d(adap)->i2c_adap,
+ DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_MC44S803:
+ ret = dvb_attach(mc44s803_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_MXL5007T:
+ ret = dvb_attach(mxl5007t_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_UNKNOWN:
+ default:
+ ret = -ENODEV;
+ err("Unknown tuner id:%d",
+ state->af9013_config[adap->id].tuner);
+ }
+
+ if (adap->fe[0]->ops.tuner_ops.init) {
+ state->tuner_init[adap->id] =
+ adap->fe[0]->ops.tuner_ops.init;
+ adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init;
+ }
+
+ if (adap->fe[0]->ops.tuner_ops.sleep) {
+ state->tuner_sleep[adap->id] =
+ adap->fe[0]->ops.tuner_ops.sleep;
+ adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep;
+ }
+
+ return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ deb_info("%s: onoff:%d\n", __func__, onoff);
+
+ if (onoff)
+ ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0);
+ else
+ ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0);
+
+ return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ int ret;
+ u8 idx;
+
+ deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+ __func__, index, pid, onoff);
+
+ ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff));
+ if (ret)
+ goto error;
+
+ ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8));
+ if (ret)
+ goto error;
+
+ idx = ((index & 0x1f) | (1 << 5));
+ ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx);
+
+error:
+ return ret;
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ u16 frame_size;
+ u8 packet_size;
+ deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+ if (d->udev->speed == USB_SPEED_FULL) {
+ frame_size = TS_USB11_FRAME_SIZE/4;
+ packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+ } else {
+ frame_size = TS_USB20_FRAME_SIZE/4;
+ packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+ }
+
+ ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+ if (ret)
+ goto error;
+ ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+ if (ret)
+ goto error;
+ ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+ if (ret)
+ goto error;
+ ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+ if (ret)
+ goto error;
+ ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+ if (ret)
+ goto error;
+ if (state->dual_mode) {
+ ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+ if (ret)
+ goto error;
+ }
+ ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+ if (ret)
+ goto error;
+ if (state->dual_mode) {
+ ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+ if (ret)
+ goto error;
+ }
+ /* EP4 xfer length */
+ ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+ if (ret)
+ goto error;
+ ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+ if (ret)
+ goto error;
+ /* EP5 xfer length */
+ ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+ if (ret)
+ goto error;
+ ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+ if (ret)
+ goto error;
+ ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+ if (ret)
+ goto error;
+ ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+ if (ret)
+ goto error;
+ ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+ if (ret)
+ goto error;
+ if (state->dual_mode) {
+ ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+ if (ret)
+ goto error;
+ }
+
+ /* enable / disable mp2if2 */
+ if (state->dual_mode)
+ ret = af9015_set_reg_bit(d, 0xd50b, 0);
+ else
+ ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+
+error:
+ if (ret)
+ err("endpoint init failed:%d", ret);
+ return ret;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ deb_info("%s:\n", __func__);
+
+ mutex_init(&state->fe_mutex);
+
+ /* init RC canary */
+ ret = af9015_write_reg(d, 0x98e9, 0xff);
+ if (ret)
+ goto error;
+
+ ret = af9015_init_endpoint(d);
+ if (ret)
+ goto error;
+
+error:
+ return ret;
+}
+
+struct af9015_rc_setup {
+ unsigned int id;
+ char *rc_codes;
+};
+
+static char *af9015_rc_setup_match(unsigned int id,
+ const struct af9015_rc_setup *table)
+{
+ for (; table->rc_codes; table++)
+ if (table->id == id)
+ return table->rc_codes;
+ return NULL;
+}
+
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+ { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+ { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+ { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+ { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+ { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
+ { }
+};
+
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+ { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+ { 0xa3703d00, RC_MAP_ALINK_DTU_M },
+ { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
+ { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
+ { }
+};
+
+static int af9015_rc_query(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ int ret;
+ u8 buf[17];
+
+ deb_info("%s:\n", __func__);
+
+ /* read registers needed to detect remote controller code */
+ ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ /* If any of these are non-zero, assume invalid data */
+ if (buf[1] || buf[2] || buf[3])
+ return ret;
+
+ /* Check for repeat of previous code */
+ if ((state->rc_repeat != buf[6] || buf[0]) &&
+ !memcmp(&buf[12], state->rc_last, 4)) {
+ deb_rc("%s: key repeated\n", __func__);
+ rc_keydown(d->rc_dev, state->rc_keycode, 0);
+ state->rc_repeat = buf[6];
+ return ret;
+ }
+
+ /* Only process key if canary killed */
+ if (buf[16] != 0xff && buf[0] != 0x01) {
+ deb_rc("%s: key pressed %*ph\n", __func__, 4, buf + 12);
+
+ /* Reset the canary */
+ ret = af9015_write_reg(d, 0x98e9, 0xff);
+ if (ret)
+ goto error;
+
+ /* Remember this key */
+ memcpy(state->rc_last, &buf[12], 4);
+ if (buf[14] == (u8) ~buf[15]) {
+ if (buf[12] == (u8) ~buf[13]) {
+ /* NEC */
+ state->rc_keycode = buf[12] << 8 | buf[14];
+ } else {
+ /* NEC extended*/
+ state->rc_keycode = buf[12] << 16 |
+ buf[13] << 8 | buf[14];
+ }
+ } else {
+ /* 32 bit NEC */
+ state->rc_keycode = buf[12] << 24 | buf[13] << 16 |
+ buf[14] << 8 | buf[15];
+ }
+ rc_keydown(d->rc_dev, state->rc_keycode, 0);
+ } else {
+ deb_rc("%s: no key press\n", __func__);
+ /* Invalidate last keypress */
+ /* Not really needed, but helps with debug */
+ state->rc_last[2] = state->rc_last[3];
+ }
+
+ state->rc_repeat = buf[6];
+ state->rc_failed = false;
+
+error:
+ if (ret) {
+ err("%s: failed:%d", __func__, ret);
+
+ /* allow random errors as dvb-usb will stop polling on error */
+ if (!state->rc_failed)
+ ret = 0;
+
+ state->rc_failed = true;
+ }
+
+ return ret;
+}
+
+static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ struct af9015_state *state = d_to_priv(d);
+ u16 vid = le16_to_cpu(d->udev->descriptor.idVendor);
+
+ if (state->ir_mode == AF9015_IR_MODE_DISABLED)
+ return 0;
+
+ /* try to load remote based module param */
+ if (!rc->map_name)
+ rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote,
+ af9015_rc_setup_modparam);
+
+ /* try to load remote based eeprom hash */
+ if (!rc->map_name)
+ rc->map_name = af9015_rc_setup_match(state->eeprom_sum,
+ af9015_rc_setup_hashes);
+
+ /* try to load remote based USB iManufacturer string */
+ if (!rc->map_name && vid == USB_VID_AFATECH) {
+ /* Check USB manufacturer and product strings and try
+ to determine correct remote in case of chip vendor
+ reference IDs are used.
+ DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+ char manufacturer[10];
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(d->udev, d->udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ if (!strcmp("MSI", manufacturer)) {
+ /* iManufacturer 1 MSI
+ iProduct 2 MSI K-VOX */
+ rc->map_name = af9015_rc_setup_match(
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_rc_setup_modparam);
+ }
+ }
+
+ /* load empty to enable rc */
+ if (!rc->map_name)
+ rc->map_name = RC_MAP_EMPTY;
+
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = af9015_rc_query;
+ rc->interval = 500;
+
+ return 0;
+}
+
+/* interface 0 is used by DVB-T receiver and
+ interface 1 is for remote controller (HID) */
+static struct dvb_usb_device_properties af9015_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct af9015_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .identify_state = af9015_identify_state,
+ .firmware = "dvb-usb-af9015.fw",
+ .download_firmware = af9015_download_firmware,
+
+ .i2c_algo = &af9015_i2c_algo,
+ .read_config = af9015_read_config,
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .init = af9015_init,
+ .get_rc_config = af9015_get_rc_config,
+ .get_stream_config = af9015_get_stream_config,
+
+ .get_adapter_count = af9015_get_adapter_count,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = af9015_pid_filter,
+ .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+ .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE),
+ }, {
+ .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE),
+ },
+ },
+};
+
+static const struct usb_device_id af9015_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015,
+ &af9015_props, "Afatech AF9015 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016,
+ &af9015_props, "Afatech AF9015 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD,
+ &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) },
+ { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E,
+ &af9015_props, "Pinnacle PCTV 71e", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U,
+ &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN,
+ &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) },
+ { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700,
+ &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2,
+ &af9015_props, "TerraTec Cinergy T USB XE", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T,
+ &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X,
+ &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) },
+ { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380,
+ &af9015_props, "Xtensions XD-380", NULL) },
+ { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO,
+ &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2,
+ &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2,
+ &af9015_props, "Telestar Starstick 2", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309,
+ &af9015_props, "AVerMedia A309", NULL) },
+ { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III,
+ &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U,
+ &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2,
+ &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3,
+ &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT,
+ &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850,
+ &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805,
+ &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU,
+ &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810,
+ &af9015_props, "KWorld Digial MC-810", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03,
+ &af9015_props, "Genius TVGo DVB-T03", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2,
+ &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T,
+ &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20,
+ &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2,
+ &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS,
+ &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T,
+ &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4,
+ &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M,
+ &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC,
+ &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+ &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T,
+ &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3,
+ &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22,
+ &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, af9015_id_table);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9015_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = af9015_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .reset_resume = dvb_usbv2_reset_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(af9015_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9015 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h
new file mode 100644
index 000000000000..c6b304d962ad
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9015.h
@@ -0,0 +1,170 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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 AF9015_H
+#define AF9015_H
+
+#include <linux/hash.h>
+#include "dvb_usb.h"
+#include "af9013.h"
+#include "dvb-pll.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
+
+#define DVB_USB_LOG_PREFIX "af9015"
+
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var, level, args...) \
+ do { if ((var & level)) printk(args); } while (0)
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+#endif
+
+#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
+#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args)
+
+#undef err
+#define err(format, arg...) \
+ printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) \
+ printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
+ We use smaller - about 1/4 from the original, 5 and 87. */
+#define TS_PACKET_SIZE 188
+
+#define TS_USB20_PACKET_COUNT 87
+#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT 5
+#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE 512
+#define TS_USB11_MAX_PACKET_SIZE 64
+
+#define AF9015_I2C_EEPROM 0xa0
+#define AF9015_I2C_DEMOD 0x38
+#define AF9015_USB_TIMEOUT 2000
+
+/* EEPROM locations */
+#define AF9015_EEPROM_IR_MODE 0x18
+#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
+#define AF9015_EEPROM_TS_MODE 0x31
+#define AF9015_EEPROM_DEMOD2_I2C 0x32
+
+#define AF9015_EEPROM_SAW_BW1 0x35
+#define AF9015_EEPROM_XTAL_TYPE1 0x36
+#define AF9015_EEPROM_SPEC_INV1 0x37
+#define AF9015_EEPROM_IF1L 0x38
+#define AF9015_EEPROM_IF1H 0x39
+#define AF9015_EEPROM_MT2060_IF1L 0x3a
+#define AF9015_EEPROM_MT2060_IF1H 0x3b
+#define AF9015_EEPROM_TUNER_ID1 0x3c
+
+#define AF9015_EEPROM_SAW_BW2 0x45
+#define AF9015_EEPROM_XTAL_TYPE2 0x46
+#define AF9015_EEPROM_SPEC_INV2 0x47
+#define AF9015_EEPROM_IF2L 0x48
+#define AF9015_EEPROM_IF2H 0x49
+#define AF9015_EEPROM_MT2060_IF2L 0x4a
+#define AF9015_EEPROM_MT2060_IF2H 0x4b
+#define AF9015_EEPROM_TUNER_ID2 0x4c
+
+#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
+
+struct req_t {
+ u8 cmd; /* [0] */
+ /* seq */ /* [1] */
+ u8 i2c_addr; /* [2] */
+ u16 addr; /* [3|4] */
+ u8 mbox; /* [5] */
+ u8 addr_len; /* [6] */
+ u8 data_len; /* [7] */
+ u8 *data;
+};
+
+enum af9015_cmd {
+ GET_CONFIG = 0x10,
+ DOWNLOAD_FIRMWARE = 0x11,
+ BOOT = 0x13,
+ READ_MEMORY = 0x20,
+ WRITE_MEMORY = 0x21,
+ READ_WRITE_I2C = 0x22,
+ COPY_FIRMWARE = 0x23,
+ RECONNECT_USB = 0x5a,
+ WRITE_VIRTUAL_MEMORY = 0x26,
+ GET_IR_CODE = 0x27,
+ READ_I2C,
+ WRITE_I2C,
+};
+
+enum af9015_ir_mode {
+ AF9015_IR_MODE_DISABLED = 0,
+ AF9015_IR_MODE_HID,
+ AF9015_IR_MODE_RLC,
+ AF9015_IR_MODE_RC6,
+ AF9015_IR_MODE_POLLING, /* just guess */
+};
+
+struct af9015_state {
+ u8 ir_mode;
+ u8 rc_repeat;
+ u32 rc_keycode;
+ u8 rc_last[4];
+ bool rc_failed;
+ u8 dual_mode;
+ u8 seq; /* packet sequence number */
+ u16 mt2060_if1[2];
+ u16 firmware_size;
+ u16 firmware_checksum;
+ u32 eeprom_sum;
+ struct af9013_config af9013_config[2];
+
+ /* 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 mutex fe_mutex;
+};
+
+enum af9015_remote {
+ AF9015_REMOTE_NONE = 0,
+/* 1 */ AF9015_REMOTE_A_LINK_DTU_M,
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ AF9015_REMOTE_MYGICTV_U718,
+ AF9015_REMOTE_DIGITTRADE_DVB_T,
+/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
new file mode 100644
index 000000000000..b7004441ac2a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -0,0 +1,1087 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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 "af9035.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static u16 af9035_checksum(const u8 *buf, size_t len)
+{
+ size_t i;
+ u16 checksum = 0;
+
+ for (i = 1; i < len; i++) {
+ if (i % 2)
+ checksum += buf[i] << 8;
+ else
+ checksum += buf[i];
+ }
+ checksum = ~checksum;
+
+ return checksum;
+}
+
+static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
+{
+#define BUF_LEN 64
+#define REQ_HDR_LEN 4 /* send header size */
+#define ACK_HDR_LEN 3 /* rece header size */
+#define CHECKSUM_LEN 2
+#define USB_TIMEOUT 2000
+ struct state *state = d_to_priv(d);
+ int ret, wlen, rlen;
+ u8 buf[BUF_LEN];
+ u16 checksum, tmp_checksum;
+
+ /* buffer overflow check */
+ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
+ req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
+ pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
+ req->wlen, req->rlen);
+ return -EINVAL;
+ }
+
+ buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+ buf[1] = req->mbox;
+ buf[2] = req->cmd;
+ buf[3] = state->seq++;
+ memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+
+ wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
+ rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
+
+ /* calc and add checksum */
+ checksum = af9035_checksum(buf, buf[0] - 1);
+ buf[buf[0] - 1] = (checksum >> 8);
+ buf[buf[0] - 0] = (checksum & 0xff);
+
+ /* no ack for these packets */
+ if (req->cmd == CMD_FW_DL)
+ rlen = 0;
+
+ ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ if (ret)
+ goto err;
+
+ /* no ack for those packets */
+ if (req->cmd == CMD_FW_DL)
+ goto exit;
+
+ /* verify checksum */
+ checksum = af9035_checksum(buf, rlen - 2);
+ tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
+ if (tmp_checksum != checksum) {
+ pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n",
+ KBUILD_MODNAME, req->cmd, tmp_checksum,
+ checksum);
+ ret = -EIO;
+ goto err;
+ }
+
+ /* check status */
+ if (buf[2]) {
+ pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
+ req->cmd, buf[2]);
+ ret = -EIO;
+ goto err;
+ }
+
+ /* read request, copy returned data to return buf */
+ if (req->rlen)
+ memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
+
+exit:
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/* write multiple registers */
+static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+ u8 wbuf[6 + len];
+ u8 mbox = (reg >> 16) & 0xff;
+ struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
+
+ wbuf[0] = len;
+ wbuf[1] = 2;
+ wbuf[2] = 0;
+ wbuf[3] = 0;
+ wbuf[4] = (reg >> 8) & 0xff;
+ wbuf[5] = (reg >> 0) & 0xff;
+ memcpy(&wbuf[6], val, len);
+
+ return af9035_ctrl_msg(d, &req);
+}
+
+/* read multiple registers */
+static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+ u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
+ u8 mbox = (reg >> 16) & 0xff;
+ struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
+
+ return af9035_ctrl_msg(d, &req);
+}
+
+/* write single register */
+static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
+{
+ return af9035_wr_regs(d, reg, &val, 1);
+}
+
+/* read single register */
+static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
+{
+ return af9035_rd_regs(d, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = af9035_rd_regs(d, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return af9035_wr_regs(d, reg, &val, 1);
+}
+
+static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct state *state = d_to_priv(d);
+ int ret;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ /*
+ * I2C sub header is 5 bytes long. Meaning of those bytes are:
+ * 0: data len
+ * 1: I2C addr << 1
+ * 2: reg addr len
+ * byte 3 and 4 can be used as reg addr
+ * 3: reg addr MSB
+ * used when reg addr len is set to 2
+ * 4: reg addr LSB
+ * used when reg addr len is set to 1 or 2
+ *
+ * For the simplify we do not use register addr at all.
+ * NOTE: As a firmware knows tuner type there is very small possibility
+ * there could be some tuner I2C hacks done by firmware and this may
+ * lead problems if firmware expects those bytes are used.
+ */
+ if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+ (msg[1].flags & I2C_M_RD)) {
+ if (msg[0].len > 40 || msg[1].len > 40) {
+ /* TODO: correct limits > 40 */
+ ret = -EOPNOTSUPP;
+ } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+ /* integrated demod */
+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+ msg[0].buf[2];
+ ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
+ msg[1].len);
+ } else {
+ /* I2C */
+ u8 buf[5 + msg[0].len];
+ struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+ buf, msg[1].len, msg[1].buf };
+ buf[0] = msg[1].len;
+ buf[1] = msg[0].addr << 1;
+ buf[2] = 0x00; /* reg addr len */
+ buf[3] = 0x00; /* reg addr MSB */
+ buf[4] = 0x00; /* reg addr LSB */
+ memcpy(&buf[5], msg[0].buf, msg[0].len);
+ ret = af9035_ctrl_msg(d, &req);
+ }
+ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+ if (msg[0].len > 40) {
+ /* TODO: correct limits > 40 */
+ ret = -EOPNOTSUPP;
+ } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+ /* integrated demod */
+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+ msg[0].buf[2];
+ ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
+ msg[0].len - 3);
+ } else {
+ /* I2C */
+ u8 buf[5 + msg[0].len];
+ struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
+ 0, NULL };
+ buf[0] = msg[0].len;
+ buf[1] = msg[0].addr << 1;
+ buf[2] = 0x00; /* reg addr len */
+ buf[3] = 0x00; /* reg addr MSB */
+ buf[4] = 0x00; /* reg addr LSB */
+ memcpy(&buf[5], msg[0].buf, msg[0].len);
+ ret = af9035_ctrl_msg(d, &req);
+ }
+ } else {
+ /*
+ * We support only two kind of I2C transactions:
+ * 1) 1 x read + 1 x write
+ * 2) 1 x write
+ */
+ ret = -EOPNOTSUPP;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ if (ret < 0)
+ return ret;
+ else
+ return num;
+}
+
+static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9035_i2c_algo = {
+ .master_xfer = af9035_i2c_master_xfer,
+ .functionality = af9035_i2c_functionality,
+};
+
+static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ int ret;
+ u8 wbuf[1] = { 1 };
+ u8 rbuf[4];
+ struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
+ sizeof(rbuf), rbuf };
+
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: reply=%*ph\n", __func__, 4, rbuf);
+ if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
+ ret = WARM;
+ else
+ ret = COLD;
+
+ return ret;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ int ret, i, j, len;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ u8 hdr_core;
+ u16 hdr_addr, hdr_data_len, hdr_checksum;
+ #define MAX_DATA 58
+ #define HDR_SIZE 7
+
+ /*
+ * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
+ *
+ * byte 0: MCS 51 core
+ * There are two inside the AF9035 (1=Link and 2=OFDM) with separate
+ * address spaces
+ * byte 1-2: Big endian destination address
+ * byte 3-4: Big endian number of data bytes following the header
+ * byte 5-6: Big endian header checksum, apparently ignored by the chip
+ * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
+ */
+
+ for (i = fw->size; i > HDR_SIZE;) {
+ hdr_core = fw->data[fw->size - i + 0];
+ hdr_addr = fw->data[fw->size - i + 1] << 8;
+ hdr_addr |= fw->data[fw->size - i + 2] << 0;
+ hdr_data_len = fw->data[fw->size - i + 3] << 8;
+ hdr_data_len |= fw->data[fw->size - i + 4] << 0;
+ hdr_checksum = fw->data[fw->size - i + 5] << 8;
+ hdr_checksum |= fw->data[fw->size - i + 6] << 0;
+
+ pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+ __func__, hdr_core, hdr_addr, hdr_data_len,
+ hdr_checksum);
+
+ if (((hdr_core != 1) && (hdr_core != 2)) ||
+ (hdr_data_len > i)) {
+ pr_debug("%s: bad firmware\n", __func__);
+ break;
+ }
+
+ /* download begin packet */
+ req.cmd = CMD_FW_DL_BEGIN;
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ /* download firmware packet(s) */
+ for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
+ len = j;
+ if (len > MAX_DATA)
+ len = MAX_DATA;
+ req_fw_dl.wlen = len;
+ req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
+ HDR_SIZE + hdr_data_len - j];
+ ret = af9035_ctrl_msg(d, &req_fw_dl);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* download end packet */
+ req.cmd = CMD_FW_DL_END;
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ i -= hdr_data_len + HDR_SIZE;
+
+ pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
+ }
+
+ /* firmware loaded, request boot */
+ req.cmd = CMD_FW_BOOT;
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ /* ensure firmware starts */
+ wbuf[0] = 1;
+ ret = af9035_ctrl_msg(d, &req_fw_ver);
+ if (ret < 0)
+ goto err;
+
+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+ pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+ rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ int ret, i, i_prev;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ #define HDR_SIZE 7
+
+ /*
+ * There seems to be following firmware header. Meaning of bytes 0-3
+ * is unknown.
+ *
+ * 0: 3
+ * 1: 0, 1
+ * 2: 0
+ * 3: 1, 2, 3
+ * 4: addr MSB
+ * 5: addr LSB
+ * 6: count of data bytes ?
+ */
+
+ for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
+ if (i == fw->size ||
+ (fw->data[i + 0] == 0x03 &&
+ (fw->data[i + 1] == 0x00 ||
+ fw->data[i + 1] == 0x01) &&
+ fw->data[i + 2] == 0x00)) {
+ req_fw_dl.wlen = i - i_prev;
+ req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
+ i_prev = i;
+ ret = af9035_ctrl_msg(d, &req_fw_dl);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: data uploaded=%d\n", __func__, i);
+ }
+ }
+
+ /* firmware loaded, request boot */
+ req.cmd = CMD_FW_BOOT;
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ /* ensure firmware starts */
+ wbuf[0] = 1;
+ ret = af9035_ctrl_msg(d, &req_fw_ver);
+ if (ret < 0)
+ goto err;
+
+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+ pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+ rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_read_config(struct dvb_usb_device *d)
+{
+ struct state *state = d_to_priv(d);
+ int ret, i, eeprom_shift = 0;
+ u8 tmp;
+ u16 tmp16;
+
+ /* check if there is dual tuners */
+ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ state->dual_mode = tmp;
+ pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
+
+ for (i = 0; i < state->dual_mode + 1; i++) {
+ /* tuner */
+ ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ state->af9033_config[i].tuner = tmp;
+ pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
+
+ switch (tmp) {
+ case AF9033_TUNER_TUA9001:
+ case AF9033_TUNER_FC0011:
+ case AF9033_TUNER_MXL5007T:
+ case AF9033_TUNER_TDA18218:
+ state->af9033_config[i].spec_inv = 1;
+ break;
+ default:
+ pr_info("%s: tuner ID=%02x not supported, please " \
+ "report!", KBUILD_MODNAME, tmp);
+ };
+
+ /* tuner IF frequency */
+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp16 = tmp;
+
+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp16 |= tmp << 8;
+
+ pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
+
+ eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+ }
+
+ /* get demod clock */
+ ret = af9035_rd_reg(d, 0x00d800, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp = (tmp >> 0) & 0x0f;
+
+ for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
+ state->af9033_config[i].clock = clock_lut[tmp];
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_read_config_it9135(struct dvb_usb_device *d)
+{
+ struct state *state = d_to_priv(d);
+ int ret, i;
+ u8 tmp;
+
+ state->dual_mode = false;
+
+ /* get demod clock */
+ ret = af9035_rd_reg(d, 0x00d800, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp = (tmp >> 0) & 0x0f;
+
+ for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
+ state->af9033_config[i].clock = clock_lut_it9135[tmp];
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
+ int cmd, int arg)
+{
+ int ret;
+
+ switch (cmd) {
+ case FC0011_FE_CALLBACK_POWER:
+ /* Tuner enable */
+ ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ /* LED */
+ ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 50000);
+ break;
+ case FC0011_FE_CALLBACK_RESET:
+ ret = af9035_wr_reg(d, 0xd8e9, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0xd8e8, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0xd8e7, 1);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 20000);
+
+ ret = af9035_wr_reg(d, 0xd8e7, 0);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 20000);
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+ struct state *state = d_to_priv(d);
+
+ switch (state->af9033_config[0].tuner) {
+ case AF9033_TUNER_FC0011:
+ return af9035_fc0011_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -ENODEV;
+}
+
+static int af9035_frontend_callback(void *adapter_priv, int component,
+ int cmd, int arg)
+{
+ struct i2c_adapter *adap = adapter_priv;
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+ switch (component) {
+ case DVB_FRONTEND_COMPONENT_TUNER:
+ return af9035_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+
+ if (!state->af9033_config[adap->id].tuner) {
+ /* unsupported tuner */
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (adap->id == 0) {
+ state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+ state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+ ret = af9035_wr_reg(d, 0x00417f,
+ state->af9033_config[1].i2c_addr);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d81a,
+ state->dual_mode);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* attach demodulator */
+ adap->fe[0] = dvb_attach(af9033_attach,
+ &state->af9033_config[adap->id], &d->i2c_adap);
+ if (adap->fe[0] == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* disable I2C-gate */
+ adap->fe[0]->ops.i2c_gate_ctrl = NULL;
+ adap->fe[0]->callback = af9035_frontend_callback;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static struct tua9001_config af9035_tua9001_config = {
+ .i2c_addr = 0x60,
+};
+
+static const struct fc0011_config af9035_fc0011_config = {
+ .i2c_address = 0x60,
+};
+
+static struct mxl5007t_config af9035_mxl5007t_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+ .invert_if = 0,
+ .loop_thru_enable = 0,
+ .clk_out_enable = 0,
+ .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+};
+
+static struct tda18218_config af9035_tda18218_config = {
+ .i2c_address = 0x60,
+ .i2c_wr_max = 21,
+};
+
+static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ struct dvb_frontend *fe;
+
+ switch (state->af9033_config[adap->id].tuner) {
+ case AF9033_TUNER_TUA9001:
+ /* AF9035 gpiot3 = TUA9001 RESETN
+ AF9035 gpiot2 = TUA9001 RXEN */
+
+ /* configure gpiot2 and gpiot2 as output */
+ ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* reset tuner */
+ ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(2000, 20000);
+
+ ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* activate tuner RX */
+ /* TODO: use callback for TUA9001 RXEN */
+ ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* attach tuner */
+ fe = dvb_attach(tua9001_attach, adap->fe[0],
+ &d->i2c_adap, &af9035_tua9001_config);
+ break;
+ case AF9033_TUNER_FC0011:
+ fe = dvb_attach(fc0011_attach, adap->fe[0],
+ &d->i2c_adap, &af9035_fc0011_config);
+ break;
+ case AF9033_TUNER_MXL5007T:
+ ret = af9035_wr_reg(d, 0x00d8e0, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8e1, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8df, 0);
+ if (ret < 0)
+ goto err;
+
+ msleep(30);
+
+ ret = af9035_wr_reg(d, 0x00d8df, 1);
+ if (ret < 0)
+ goto err;
+
+ msleep(300);
+
+ ret = af9035_wr_reg(d, 0x00d8c0, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8c1, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8bf, 0);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8b4, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8b5, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(d, 0x00d8b3, 1);
+ if (ret < 0)
+ goto err;
+
+ /* attach tuner */
+ fe = dvb_attach(mxl5007t_attach, adap->fe[0],
+ &d->i2c_adap, 0x60, &af9035_mxl5007t_config);
+ break;
+ case AF9033_TUNER_TDA18218:
+ /* attach tuner */
+ fe = dvb_attach(tda18218_attach, adap->fe[0],
+ &d->i2c_adap, &af9035_tda18218_config);
+ break;
+ default:
+ fe = NULL;
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_init(struct dvb_usb_device *d)
+{
+ struct state *state = d_to_priv(d);
+ int ret, i;
+ u16 frame_size = 87 * 188 / 4;
+ u8 packet_size = 512 / 4;
+ struct reg_val_mask tab[] = {
+ { 0x80f99d, 0x01, 0x01 },
+ { 0x80f9a4, 0x01, 0x01 },
+ { 0x00dd11, 0x00, 0x20 },
+ { 0x00dd11, 0x00, 0x40 },
+ { 0x00dd13, 0x00, 0x20 },
+ { 0x00dd13, 0x00, 0x40 },
+ { 0x00dd11, 0x20, 0x20 },
+ { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+ { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+ { 0x00dd0c, packet_size, 0xff},
+ { 0x00dd11, state->dual_mode << 6, 0x40 },
+ { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+ { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+ { 0x00dd0d, packet_size, 0xff },
+ { 0x80f9a3, 0x00, 0x01 },
+ { 0x80f9cd, 0x00, 0x01 },
+ { 0x80f99d, 0x00, 0x01 },
+ { 0x80f9a4, 0x00, 0x01 },
+ };
+
+ pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+ __func__, d->udev->speed, frame_size, packet_size);
+
+ /* init endpoints */
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_rc_query(struct dvb_usb_device *d)
+{
+ unsigned int key;
+ unsigned char b[4];
+ int ret;
+ struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+
+ ret = af9035_ctrl_msg(d, &req);
+ if (ret < 0)
+ goto err;
+
+ if ((b[2] + b[3]) == 0xff) {
+ if ((b[0] + b[1]) == 0xff) {
+ /* NEC */
+ key = b[0] << 8 | b[2];
+ } else {
+ /* ext. NEC */
+ key = b[0] << 16 | b[1] << 8 | b[2];
+ }
+ } else {
+ key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+ }
+
+ rc_keydown(d->rc_dev, key, 0);
+
+err:
+ /* ignore errors */
+ return 0;
+}
+
+static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ int ret;
+ u8 tmp;
+
+ ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
+
+ /* don't activate rc if in HID mode or if not available */
+ if (tmp == 5) {
+ ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: ir_type=%02x\n", __func__, tmp);
+
+ switch (tmp) {
+ case 0: /* NEC */
+ default:
+ rc->allowed_protos = RC_TYPE_NEC;
+ break;
+ case 1: /* RC6 */
+ rc->allowed_protos = RC_TYPE_RC6;
+ break;
+ }
+
+ rc->query = af9035_rc_query;
+ rc->interval = 500;
+
+ /* load empty to enable rc */
+ if (!rc->map_name)
+ rc->map_name = RC_MAP_EMPTY;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/* interface 0 is used by DVB-T receiver and
+ interface 1 is for remote controller (HID) */
+static const struct dvb_usb_device_properties af9035_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .identify_state = af9035_identify_state,
+ .firmware = "dvb-usb-af9035-02.fw",
+ .download_firmware = af9035_download_firmware,
+
+ .i2c_algo = &af9035_i2c_algo,
+ .read_config = af9035_read_config,
+ .frontend_attach = af9035_frontend_attach,
+ .tuner_attach = af9035_tuner_attach,
+ .init = af9035_init,
+ .get_rc_config = af9035_get_rc_config,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+ }, {
+ .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+ },
+ },
+};
+
+static const struct dvb_usb_device_properties it9135_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .identify_state = af9035_identify_state,
+ .firmware = "dvb-usb-it9135-01.fw",
+ .download_firmware = af9035_download_firmware_it9135,
+
+ .i2c_algo = &af9035_i2c_algo,
+ .read_config = af9035_read_config_it9135,
+ .frontend_attach = af9035_frontend_attach,
+ .tuner_attach = af9035_tuner_attach,
+ .init = af9035_init,
+ .get_rc_config = af9035_get_rc_config,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+ }, {
+ .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+ },
+ },
+};
+
+static const struct usb_device_id af9035_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
+ &af9035_props, "Afatech AF9035 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
+ &af9035_props, "Afatech AF9035 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001,
+ &af9035_props, "Afatech AF9035 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002,
+ &af9035_props, "Afatech AF9035 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003,
+ &af9035_props, "Afatech AF9035 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK,
+ &af9035_props, "TerraTec Cinergy T Stick", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835,
+ &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835,
+ &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867,
+ &af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867,
+ &af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR,
+ &af9035_props, "AVerMedia Twinstar (A825)", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, af9035_id_table);
+
+static struct usb_driver af9035_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = af9035_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .reset_resume = dvb_usbv2_reset_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(af9035_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9035 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
new file mode 100644
index 000000000000..59ff69ede0f0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -0,0 +1,111 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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 AF9035_H
+#define AF9035_H
+
+#include "dvb_usb.h"
+#include "af9033.h"
+#include "tua9001.h"
+#include "fc0011.h"
+#include "mxl5007t.h"
+#include "tda18218.h"
+
+struct reg_val {
+ u32 reg;
+ u8 val;
+};
+
+struct reg_val_mask {
+ u32 reg;
+ u8 val;
+ u8 mask;
+};
+
+struct usb_req {
+ u8 cmd;
+ u8 mbox;
+ u8 wlen;
+ u8 *wbuf;
+ u8 rlen;
+ u8 *rbuf;
+};
+
+struct state {
+ u8 seq; /* packet sequence number */
+ bool dual_mode;
+
+ struct af9033_config af9033_config[2];
+};
+
+u32 clock_lut[] = {
+ 20480000, /* FPGA */
+ 16384000, /* 16.38 MHz */
+ 20480000, /* 20.48 MHz */
+ 36000000, /* 36.00 MHz */
+ 30000000, /* 30.00 MHz */
+ 26000000, /* 26.00 MHz */
+ 28000000, /* 28.00 MHz */
+ 32000000, /* 32.00 MHz */
+ 34000000, /* 34.00 MHz */
+ 24000000, /* 24.00 MHz */
+ 22000000, /* 22.00 MHz */
+ 12000000, /* 12.00 MHz */
+};
+
+u32 clock_lut_it9135[] = {
+ 12000000, /* 12.00 MHz */
+ 20480000, /* 20.48 MHz */
+ 36000000, /* 36.00 MHz */
+ 30000000, /* 30.00 MHz */
+ 26000000, /* 26.00 MHz */
+ 28000000, /* 28.00 MHz */
+ 32000000, /* 32.00 MHz */
+ 34000000, /* 34.00 MHz */
+ 24000000, /* 24.00 MHz */
+ 22000000, /* 22.00 MHz */
+};
+
+/* EEPROM locations */
+#define EEPROM_IR_MODE 0x430d
+#define EEPROM_DUAL_MODE 0x4326
+#define EEPROM_IR_TYPE 0x4329
+#define EEPROM_1_IFFREQ_L 0x432d
+#define EEPROM_1_IFFREQ_H 0x432e
+#define EEPROM_1_TUNER_ID 0x4331
+#define EEPROM_2_IFFREQ_L 0x433d
+#define EEPROM_2_IFFREQ_H 0x433e
+#define EEPROM_2_TUNER_ID 0x4341
+
+/* USB commands */
+#define CMD_MEM_RD 0x00
+#define CMD_MEM_WR 0x01
+#define CMD_I2C_RD 0x02
+#define CMD_I2C_WR 0x03
+#define CMD_IR_GET 0x18
+#define CMD_FW_DL 0x21
+#define CMD_FW_QUERYINFO 0x22
+#define CMD_FW_BOOT 0x23
+#define CMD_FW_DL_BEGIN 0x24
+#define CMD_FW_DL_END 0x25
+#define CMD_FW_SCATTER_WR 0x29
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
new file mode 100644
index 000000000000..b430bcace0b8
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -0,0 +1,1327 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#include "anysee.h"
+#include "dvb-pll.h"
+#include "tda1002x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+#include "tda18212.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "isl6423.h"
+#include "cxd2820r.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static DEFINE_MUTEX(anysee_usb_mutex);
+
+static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
+ u8 *rbuf, u8 rlen)
+{
+ struct anysee_state *state = d_to_priv(d);
+ int act_len, ret, i;
+ u8 buf[64];
+
+ memcpy(&buf[0], sbuf, slen);
+ buf[60] = state->seq++;
+
+ mutex_lock(&anysee_usb_mutex);
+
+ dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, buf);
+
+ /* 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_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf));
+ 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
+ */
+
+ /* 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) {
+ dev_dbg(&d->udev->dev, "%s: recv bulk message " \
+ "failed=%d\n", __func__, ret);
+ } else {
+ dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
+ rlen, buf);
+
+ if (buf[63] != 0x4f)
+ dev_dbg(&d->udev->dev, "%s: cmd failed\n",
+ __func__);
+
+ break;
+ }
+ }
+
+ if (ret) {
+ /* all retries failed, it is fatal */
+ dev_err(&d->udev->dev, "%s: recv bulk message failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto error_unlock;
+ }
+
+ /* read request, copy returned data to return buf */
+ if (rbuf && rlen)
+ memcpy(rbuf, buf, rlen);
+
+error_unlock:
+ mutex_unlock(&anysee_usb_mutex);
+
+ return ret;
+}
+
+static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+ u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
+ int ret;
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
+ dev_dbg(&d->udev->dev, "%s: reg=%04x val=%02x\n", __func__, reg, *val);
+ return ret;
+}
+
+static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+ u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
+ dev_dbg(&d->udev->dev, "%s: reg=%04x val=%02x\n", __func__, reg, val);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+/* write single register with mask */
+static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = anysee_read_reg(d, reg, &tmp);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ 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};
+ return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
+}
+
+static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
+ dev_dbg(&fe_to_d(fe)->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+ return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
+{
+ u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
+ dev_dbg(&d->udev->dev, "%s: state=%d interval=%d\n", __func__,
+ mode, interval);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+ u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+/* I2C */
+static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret = 0, inc, i = 0;
+ u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ while (i < num) {
+ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+ if (msg[i].len > 2 || msg[i+1].len > 60) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ buf[0] = CMD_I2C_READ;
+ buf[1] = (msg[i].addr << 1) | 0x01;
+ buf[2] = msg[i].buf[0];
+ buf[3] = msg[i].buf[1];
+ buf[4] = msg[i].len-1;
+ buf[5] = msg[i+1].len;
+ ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
+ msg[i+1].len);
+ inc = 2;
+ } else {
+ if (msg[i].len > 48) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ buf[0] = CMD_I2C_WRITE;
+ buf[1] = (msg[i].addr << 1);
+ buf[2] = msg[i].len;
+ buf[3] = 0x01;
+ memcpy(&buf[4], msg[i].buf, msg[i].len);
+ ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0);
+ inc = 1;
+ }
+ if (ret)
+ break;
+
+ i += inc;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret ? ret : i;
+}
+
+static u32 anysee_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm anysee_i2c_algo = {
+ .master_xfer = anysee_master_xfer,
+ .functionality = anysee_i2c_func,
+};
+
+static int anysee_mt352_demod_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 };
+ static u8 reset[] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 };
+ static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+/* Callbacks for DVB USB */
+static struct tda10023_config anysee_tda10023_config = {
+ .demod_address = (0x1a >> 1),
+ .invert = 0,
+ .xtal = 16000000,
+ .pll_m = 11,
+ .pll_p = 3,
+ .pll_n = 1,
+ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+ .deltaf = 0xfeeb,
+};
+
+static struct mt352_config anysee_mt352_config = {
+ .demod_address = (0x1e >> 1),
+ .demod_init = anysee_mt352_demod_init,
+};
+
+static struct zl10353_config anysee_zl10353_config = {
+ .demod_address = (0x1e >> 1),
+ .parallel_ts = 1,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config2 = {
+ .demod_address = (0x1e >> 1),
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+ .no_tuner = 1,
+ .if2 = 41500,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config = {
+ .demod_address = (0x18 >> 1),
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+ .no_tuner = 1,
+ .if2 = 41500,
+};
+
+static struct tda10023_config anysee_tda10023_tda18212_config = {
+ .demod_address = (0x1a >> 1),
+ .xtal = 16000000,
+ .pll_m = 12,
+ .pll_p = 3,
+ .pll_n = 1,
+ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
+ .deltaf = 0xba02,
+};
+
+static struct tda18212_config anysee_tda18212_config = {
+ .i2c_address = (0xc0 >> 1),
+ .if_dvbt_6 = 4150,
+ .if_dvbt_7 = 4150,
+ .if_dvbt_8 = 4150,
+ .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,
+ .i2c_wr_max = 48,
+};
+
+static struct stv0900_config anysee_stv0900_config = {
+ .demod_address = (0xd0 >> 1),
+ .demod_mode = 0,
+ .xtal = 8000000,
+ .clkmode = 3,
+ .diseqc_mode = 2,
+ .tun1_maddress = 0,
+ .tun1_adc = 1, /* 1 Vpp */
+ .path1_mode = 3,
+};
+
+static struct stv6110_config anysee_stv6110_config = {
+ .i2c_address = (0xc0 >> 1),
+ .mclk = 16000000,
+ .clk_div = 1,
+};
+
+static struct isl6423_config anysee_isl6423_config = {
+ .current_max = SEC_CURRENT_800m,
+ .curlim = SEC_CURRENT_LIM_OFF,
+ .mod_extern = 1,
+ .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
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH102A(MT352, DTT7579(?))
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
+ * PCB: PCB 507T (rev1.61)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
+ * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
+ *
+ * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
+ * PCB: 507CD (rev1.1)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
+ * IOD[0] ZL10353 1=enabled
+ * IOA[7] TS 0=enabled
+ * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
+ *
+ * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
+ * PCB: 507DC (rev0.2)
+ * parts: TDA10023, DTOS403IH102B TM, CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
+ * IOD[0] TDA10023 1=enabled
+ *
+ * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
+ * PCB: 507SI (rev2.1)
+ * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
+ * IOD[0] CX24116 1=enabled
+ *
+ * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev0.4)
+ * parts: TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ *
+ * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev1.1)
+ * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
+ * DVB-C:
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ * DVB-T:
+ * IOD[0] ZL10353 1=enabled
+ * IOE[0] tuner 0=enabled
+ * tuner is behind ZL10353 I2C-gate
+ *
+ * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
+ * PCB: 508TC (rev0.6)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * 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[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
+ * PCB: 508S2 (rev0.7)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * 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)
+ * 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[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * 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
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
+ */
+
+static int anysee_read_config(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d_to_priv(d);
+ int ret;
+ u8 hw_info[3];
+
+ /*
+ * Check which hardware we have.
+ * We must do this call two times to get reliable values (hw/fw bug).
+ */
+ ret = anysee_get_hw_info(d, hw_info);
+ if (ret)
+ goto error;
+
+ ret = anysee_get_hw_info(d, hw_info);
+ if (ret)
+ goto error;
+
+ /*
+ * Meaning of these info bytes are guessed.
+ */
+ dev_info(&d->udev->dev, "%s: firmware version %d.%d hardware id %d\n",
+ KBUILD_MODNAME, hw_info[1], hw_info[2], hw_info[0]);
+
+ state->hw = hw_info[0];
+error:
+ return ret;
+}
+
+/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */
+static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ /* enable / disable tuner access on IOE[4] */
+ return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10);
+}
+
+static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct anysee_state *state = fe_to_priv(fe);
+ struct dvb_usb_device *d = fe_to_d(fe);
+ int ret;
+ dev_dbg(&d->udev->dev, "%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+ /* no frontend sleep control */
+ if (onoff == 0)
+ return 0;
+
+ switch (state->hw) {
+ case ANYSEE_HW_507FA: /* 15 */
+ /* E30 Combo Plus */
+ /* E30 C Plus */
+
+ if (fe->id == 0) {
+ /* disable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C tuner on IOE[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+ } else {
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T tuner on IOE[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
+ if (ret)
+ goto error;
+ }
+
+ break;
+ case ANYSEE_HW_508TC: /* 18 */
+ case ANYSEE_HW_508PTC: /* 21 */
+ /* E7 TC */
+ /* E7 PTC */
+
+ if (fe->id == 0) {
+ /* disable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable IF route on IOE[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+ } else {
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
+ if (ret)
+ goto error;
+
+ /* enable IF route on IOE[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
+ if (ret)
+ goto error;
+ }
+
+ break;
+ default:
+ ret = 0;
+ }
+
+error:
+ return ret;
+}
+
+static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct anysee_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ u8 tmp;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = anysee_tda18212_config.i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x00",
+ }, {
+ .addr = anysee_tda18212_config.i2c_address,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &tmp,
+ }
+ };
+
+ switch (state->hw) {
+ case ANYSEE_HW_507T: /* 2 */
+ /* E30 */
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config,
+ &d->i2c_adap);
+ if (adap->fe[0])
+ break;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+ &d->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507CD: /* 6 */
+ /* E30 Plus */
+
+ /* enable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* enable transport stream on IOA[7] */
+ ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+ &d->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507DC: /* 10 */
+ /* E30 C Plus */
+
+ /* enable DVB-C demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(tda10023_attach,
+ &anysee_tda10023_config, &d->i2c_adap, 0x48);
+
+ break;
+ case ANYSEE_HW_507SI: /* 11 */
+ /* E30 S2 Plus */
+
+ /* enable DVB-S/S2 demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+ &d->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507FA: /* 15 */
+ /* E30 Combo Plus */
+ /* E30 C Plus */
+
+ /* enable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* probe TDA18212 */
+ tmp = 0;
+ ret = i2c_transfer(&d->i2c_adap, msg, 2);
+ if (ret == 2 && tmp == 0xc7)
+ dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
+ __func__);
+ else
+ tmp = 0;
+
+ /* disable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* disable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ if (tmp == 0xc7) {
+ /* TDA18212 config */
+ adap->fe[0] = dvb_attach(tda10023_attach,
+ &anysee_tda10023_tda18212_config,
+ &d->i2c_adap, 0x48);
+
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (adap->fe[0])
+ adap->fe[0]->ops.i2c_gate_ctrl =
+ anysee_i2c_gate_ctrl;
+ } else {
+ /* PLL config */
+ adap->fe[0] = dvb_attach(tda10023_attach,
+ &anysee_tda10023_config,
+ &d->i2c_adap, 0x48);
+ }
+
+ /* break out if first frontend attaching fails */
+ if (!adap->fe[0])
+ break;
+
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ if (tmp == 0xc7) {
+ /* TDA18212 config */
+ adap->fe[1] = dvb_attach(zl10353_attach,
+ &anysee_zl10353_tda18212_config2,
+ &d->i2c_adap);
+
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (adap->fe[1])
+ adap->fe[1]->ops.i2c_gate_ctrl =
+ anysee_i2c_gate_ctrl;
+ } else {
+ /* PLL config */
+ adap->fe[1] = dvb_attach(zl10353_attach,
+ &anysee_zl10353_config,
+ &d->i2c_adap);
+ }
+
+ break;
+ case ANYSEE_HW_508TC: /* 18 */
+ case ANYSEE_HW_508PTC: /* 21 */
+ /* E7 TC */
+ /* E7 PTC */
+
+ /* disable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(tda10023_attach,
+ &anysee_tda10023_tda18212_config,
+ &d->i2c_adap, 0x48);
+
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (adap->fe[0])
+ adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
+
+ /* break out if first frontend attaching fails */
+ if (!adap->fe[0])
+ break;
+
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[1] = dvb_attach(zl10353_attach,
+ &anysee_zl10353_tda18212_config,
+ &d->i2c_adap);
+
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (adap->fe[1])
+ adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
+
+ state->has_ci = true;
+
+ break;
+ case ANYSEE_HW_508S2: /* 19 */
+ case ANYSEE_HW_508PS2: /* 22 */
+ /* E7 S2 */
+ /* E7 PS2 */
+
+ /* enable DVB-S/S2 demod on IOE[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(stv0900_attach,
+ &anysee_stv0900_config, &d->i2c_adap, 0);
+
+ state->has_ci = true;
+
+ break;
+ case ANYSEE_HW_508T2C: /* 20 */
+ /* E7 T2C */
+
+ /* enable DVB-T/T2/C demod on IOE[5] */
+ ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(cxd2820r_attach,
+ &anysee_cxd2820r_config, &d->i2c_adap);
+
+ state->has_ci = true;
+
+ break;
+ }
+
+ if (!adap->fe[0]) {
+ /* we have no frontend :-( */
+ ret = -ENODEV;
+ dev_err(&d->udev->dev, "%s: Unsupported Anysee version. " \
+ "Please report the " \
+ "<linux-media@vger.kernel.org>.\n",
+ KBUILD_MODNAME);
+ }
+error:
+ return ret;
+}
+
+static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct anysee_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct dvb_frontend *fe;
+ int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ switch (state->hw) {
+ case ANYSEE_HW_507T: /* 2 */
+ /* E30 */
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe[0], (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[0], (0xc2 >> 1),
+ &d->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[0], (0xc0 >> 1),
+ &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+ break;
+ case ANYSEE_HW_507SI: /* 11 */
+ /* E30 S2 Plus */
+
+ /* attach LNB controller */
+ fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap,
+ &anysee_isl6423_config);
+
+ break;
+ case ANYSEE_HW_507FA: /* 15 */
+ /* E30 Combo Plus */
+ /* E30 C Plus */
+
+ /* Try first attach TDA18212 silicon tuner on IOE[4], if that
+ * fails attach old simple PLL. */
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+ &anysee_tda18212_config);
+
+ if (fe && adap->fe[1]) {
+ /* attach tuner for 2nd FE */
+ fe = dvb_attach(tda18212_attach, adap->fe[1],
+ &d->i2c_adap, &anysee_tda18212_config);
+ break;
+ } else if (fe) {
+ break;
+ }
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
+ &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+ if (fe && adap->fe[1]) {
+ /* attach tuner for 2nd FE */
+ fe = dvb_attach(dvb_pll_attach, adap->fe[0],
+ (0xc0 >> 1), &d->i2c_adap,
+ DVB_PLL_SAMSUNG_DTOS403IH102A);
+ }
+
+ break;
+ case ANYSEE_HW_508TC: /* 18 */
+ case ANYSEE_HW_508PTC: /* 21 */
+ /* E7 TC */
+ /* E7 PTC */
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+ &anysee_tda18212_config);
+
+ if (fe) {
+ /* attach tuner for 2nd FE */
+ fe = dvb_attach(tda18212_attach, adap->fe[1],
+ &d->i2c_adap, &anysee_tda18212_config);
+ }
+
+ break;
+ case ANYSEE_HW_508S2: /* 19 */
+ case ANYSEE_HW_508PS2: /* 22 */
+ /* E7 S2 */
+ /* E7 PS2 */
+
+ /* attach tuner */
+ fe = dvb_attach(stv6110_attach, adap->fe[0],
+ &anysee_stv6110_config, &d->i2c_adap);
+
+ if (fe) {
+ /* attach LNB controller */
+ fe = dvb_attach(isl6423_attach, adap->fe[0],
+ &d->i2c_adap, &anysee_isl6423_config);
+ }
+
+ break;
+
+ case ANYSEE_HW_508T2C: /* 20 */
+ /* E7 T2C */
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+ &anysee_tda18212_config2);
+
+ break;
+ default:
+ fe = NULL;
+ }
+
+ if (fe)
+ ret = 0;
+ else
+ ret = -ENODEV;
+
+ return ret;
+}
+
+static int anysee_rc_query(struct dvb_usb_device *d)
+{
+ u8 buf[] = {CMD_GET_IR_CODE};
+ u8 ircode[2];
+ int ret;
+
+ /* Remote controller is basic NEC using address byte 0x08.
+ Anysee device RC query returns only two bytes, status and code,
+ address byte is dropped. Also it does not return any value for
+ NEC RCs having address byte other than 0x08. Due to that, we
+ cannot use that device as standard NEC receiver.
+ It could be possible make hack which reads whole code directly
+ from device memory... */
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
+ if (ret)
+ return ret;
+
+ if (ircode[0]) {
+ dev_dbg(&d->udev->dev, "%s: key pressed %02x\n", __func__,
+ ircode[1]);
+ rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
+ }
+
+ return 0;
+}
+
+static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = anysee_rc_query;
+ rc->interval = 250; /* windows driver uses 500ms */
+
+ 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_to_priv(d);
+
+ 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_to_priv(d);
+ 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_to_priv(d);
+ 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_to_priv(d);
+
+ /* 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_to_priv(d);
+ int ret;
+
+ /* There is one interface with two alternate settings.
+ Alternate setting 0 is for bulk transfer.
+ Alternate setting 1 is for isochronous transfer.
+ We use bulk transfer (alternate setting 0). */
+ ret = usb_set_interface(d->udev, 0, 0);
+ if (ret)
+ return 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;
+}
+
+static void anysee_exit(struct dvb_usb_device *d)
+{
+ return anysee_ci_release(d);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct anysee_state),
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &anysee_i2c_algo,
+ .read_config = anysee_read_config,
+ .frontend_attach = anysee_frontend_attach,
+ .tuner_attach = anysee_tuner_attach,
+ .init = anysee_init,
+ .get_rc_config = anysee_get_rc_config,
+ .frontend_ctrl = anysee_frontend_ctrl,
+ .streaming_ctrl = anysee_streaming_ctrl,
+ .exit = anysee_exit,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512),
+ }
+ }
+};
+
+static const struct usb_device_id anysee_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE,
+ &anysee_props, "Anysee", RC_MAP_ANYSEE) },
+ { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE,
+ &anysee_props, "Anysee", RC_MAP_ANYSEE) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, anysee_id_table);
+
+static struct usb_driver anysee_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = anysee_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .reset_resume = dvb_usbv2_reset_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(anysee_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h
new file mode 100644
index 000000000000..4ab467679a43
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/anysee.h
@@ -0,0 +1,325 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#ifndef _DVB_USB_ANYSEE_H_
+#define _DVB_USB_ANYSEE_H_
+
+#define DVB_USB_LOG_PREFIX "anysee"
+#include "dvb_usb.h"
+#include "dvb_ca_en50221.h"
+
+enum cmd {
+ CMD_I2C_READ = 0x33,
+ CMD_I2C_WRITE = 0x31,
+ CMD_REG_READ = 0xb0,
+ CMD_REG_WRITE = 0xb1,
+ CMD_STREAMING_CTRL = 0x12,
+ CMD_LED_AND_IR_CTRL = 0x16,
+ 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 */
+#define ANYSEE_HW_507CD 6 /* E30 Plus */
+#define ANYSEE_HW_507DC 10 /* E30 C Plus */
+#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
+#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 */
+
+#define REG_IOA 0x80 /* Port A (bit addressable) */
+#define REG_IOB 0x90 /* Port B (bit addressable) */
+#define REG_IOC 0xa0 /* Port C (bit addressable) */
+#define REG_IOD 0xb0 /* Port D (bit addressable) */
+#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */
+#define REG_OEA 0xb2 /* Port A Output Enable */
+#define REG_OEB 0xb3 /* Port B Output Enable */
+#define REG_OEC 0xb4 /* Port C Output Enable */
+#define REG_OED 0xb5 /* Port D Output Enable */
+#define REG_OEE 0xb6 /* Port E Output Enable */
+
+#endif
+
+/***************************************************************************
+ * USB API description (reverse engineered)
+ ***************************************************************************
+
+Transaction flow:
+=================
+BULK[00001] >>> REQUEST PACKET 64 bytes
+BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
+BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
+
+General reply packet(s) are always used if not own reply defined.
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
+============================================================================
+| 00 | reply data (if any) from previous transaction
+| | Just same reply packet as returned during previous transaction.
+| | Needed only if reply is missed in previous transaction.
+| | Just skip normally.
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
+============================================================================
+| 00 | reply data (if any)
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C WRITE REQUEST PACKET
+============================================================================
+| 00 | 0x31 I2C write command
+----------------------------------------------------------------------------
+| 01 | i2c address
+----------------------------------------------------------------------------
+| 02 | data length
+| | 0x02 (for typical I2C reg / val pair)
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04- | data
+----------------------------------------------------------------------------
+| -59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C READ REQUEST PACKET
+============================================================================
+| 00 | 0x33 I2C read command
+----------------------------------------------------------------------------
+| 01 | i2c address + 1
+----------------------------------------------------------------------------
+| 02 | register
+----------------------------------------------------------------------------
+| 03 | 0x00
+----------------------------------------------------------------------------
+| 04 | 0x00
+----------------------------------------------------------------------------
+| 05 | data length
+----------------------------------------------------------------------------
+| 06-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
+============================================================================
+| 00 | 0xb1 register write command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04 | value
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
+============================================================================
+| 00 | 0xb0 register read command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | LED CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+| 01 | 0x01 (LED)
+----------------------------------------------------------------------------
+| 03 | 0x00 blink
+| | 0x01 lights continuously
+----------------------------------------------------------------------------
+| 04 | blink interval
+| | 0x00 fastest (looks like LED lights continuously)
+| | 0xff slowest
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | IR CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+| 01 | 0x02 (IR)
+----------------------------------------------------------------------------
+| 03 | 0x00 IR disabled
+| | 0x01 IR enabled
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | STREAMING CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x12 streaming control command
+----------------------------------------------------------------------------
+| 01 | 0x00 streaming disabled
+| | 0x01 streaming enabled
+----------------------------------------------------------------------------
+| 02 | 0x00
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x41 remote control command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REPLY PACKET
+============================================================================
+| 00 | 0x00 code not received
+| | 0x01 code received
+----------------------------------------------------------------------------
+| 01 | remote control code
+----------------------------------------------------------------------------
+| 02-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REQUEST PACKET
+============================================================================
+| 00 | 0x19 get hardware info command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REPLY PACKET
+============================================================================
+| 00 | hardware id
+----------------------------------------------------------------------------
+| 01-02 | firmware version
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | SMART CARD READER PACKET
+============================================================================
+| 00 | 0x34 smart card reader command
+----------------------------------------------------------------------------
+| xx |
+----------------------------------------------------------------------------
+| xx-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+*/
diff --git a/drivers/media/usb/dvb-usb-v2/au6610.c b/drivers/media/usb/dvb-usb-v2/au6610.c
new file mode 100644
index 000000000000..05f2a8628142
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/au6610.c
@@ -0,0 +1,206 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 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 "au6610.h"
+#include "zl10353.h"
+#include "qt1010.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ int ret;
+ u16 index;
+ u8 *usb_buf;
+
+ /*
+ * allocate enough for all known requests,
+ * read returns 5 and write 6 bytes
+ */
+ usb_buf = kmalloc(6, GFP_KERNEL);
+ if (!usb_buf)
+ return -ENOMEM;
+
+ switch (wlen) {
+ case 1:
+ index = wbuf[0] << 8;
+ break;
+ case 2:
+ index = wbuf[0] << 8;
+ index += wbuf[1];
+ break;
+ default:
+ pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
+ USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
+ usb_buf, 6, AU6610_USB_TIMEOUT);
+ if (ret < 0)
+ goto error;
+
+ switch (operation) {
+ case AU6610_REQ_I2C_READ:
+ case AU6610_REQ_USB_READ:
+ /* requested value is always 5th byte in buffer */
+ rbuf[0] = usb_buf[4];
+ }
+error:
+ kfree(usb_buf);
+ return ret;
+}
+
+static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u8 request;
+ u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+ if (wo) {
+ request = AU6610_REQ_I2C_WRITE;
+ } else { /* rw */
+ request = AU6610_REQ_I2C_READ;
+ }
+
+ return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
+}
+
+
+/* I2C */
+static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (num > 2)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf,
+ msg[i+1].len) < 0)
+ break;
+ i++;
+ } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+
+static u32 au6610_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au6610_i2c_algo = {
+ .master_xfer = au6610_i2c_xfer,
+ .functionality = au6610_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config au6610_zl10353_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+ &adap_to_d(adap)->i2c_adap);
+ if (adap->fe[0] == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct qt1010_config au6610_qt1010_config = {
+ .i2c_address = 0x62
+};
+
+static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &au6610_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+static int au6610_init(struct dvb_usb_device *d)
+{
+ /* TODO: this functionality belongs likely to the streaming control */
+ /* bInterfaceNumber 0, bAlternateSetting 5 */
+ return usb_set_interface(d->udev, 0, 5);
+}
+
+static struct dvb_usb_device_properties au6610_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+
+ .i2c_algo = &au6610_i2c_algo,
+ .frontend_attach = au6610_zl10353_frontend_attach,
+ .tuner_attach = au6610_qt1010_tuner_attach,
+ .init = au6610_init,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1),
+ },
+ },
+};
+
+static const struct usb_device_id au6610_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110,
+ &au6610_props, "Sigmatek DVB-110", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, au6610_id_table);
+
+static struct usb_driver au6610_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = au6610_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(au6610_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/au6610.h b/drivers/media/usb/dvb-usb-v2/au6610.h
new file mode 100644
index 000000000000..ea337bfc00b1
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/au6610.h
@@ -0,0 +1,32 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 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 AU6610_H
+#define AU6610_H
+#include "dvb_usb.h"
+
+#define AU6610_REQ_I2C_WRITE 0x14
+#define AU6610_REQ_I2C_READ 0x13
+#define AU6610_REQ_USB_WRITE 0x16
+#define AU6610_REQ_USB_READ 0x15
+
+#define AU6610_USB_TIMEOUT 1000
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
new file mode 100644
index 000000000000..54f1221d930d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -0,0 +1,919 @@
+/*
+ * 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-2012 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Driver modified by in order to work with upstream drxk driver, and
+ * tons of bugs got fixed, and converted to use dvb-usb-v2.
+ *
+ * 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"
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
+
+#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
+
+static int az6007_xfer_debug;
+module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);
+MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");
+
+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,
+ .qam_demod_parameter_count = 2,
+ .microcode_name = "dvb-usb-terratec-h7-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct az6007_device_state *st = fe_to_priv(fe);
+ struct dvb_usb_adapter *adap = fe->sec_priv;
+ int status = 0;
+
+ pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");
+
+ if (!adap || !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) {
+ pr_warn("usb read operation failed. (%d)\n", ret);
+ return -EIO;
+ }
+
+ if (az6007_xfer_debug) {
+ printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n",
+ req, value, index);
+ print_hex_dump_bytes("az6007: payload: ",
+ DUMP_PREFIX_NONE, b, blen);
+ }
+
+ 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;
+
+ if (az6007_xfer_debug) {
+ printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",
+ req, value, index);
+ print_hex_dump_bytes("az6007: payload: ",
+ DUMP_PREFIX_NONE, b, blen);
+ }
+
+ if (blen > 64) {
+ pr_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) {
+ pr_err("usb write operation failed. (%d)\n", 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_frontend *fe, int onoff)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+
+ pr_debug("%s: %s\n", __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_to_priv(d);
+ 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 = d_to_priv(d);
+
+ 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) {
+ pr_warn("usb in operation failed. (%d)\n", 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 = d_to_priv(d);
+
+ int ret;
+ u8 req;
+ u16 value1;
+ u16 index;
+ int blen;
+
+ pr_debug("%s(), slot %d\n", __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)
+ pr_warn("usb out operation failed. (%d)\n", 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 = d_to_priv(d);
+
+ 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) {
+ pr_warn("usb in operation failed. (%d)\n", ret);
+ ret = -EINVAL;
+ } else {
+ if (b[0] == 0)
+ pr_warn("Read CI IO error\n");
+
+ ret = b[1];
+ pr_debug("read cam data = %x from 0x%x\n", 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 = d_to_priv(d);
+
+ 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) {
+ pr_warn("usb out operation failed. (%d)\n", 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) {
+ pr_warn("usb in operation failed. (%d)\n", 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 = d_to_priv(d);
+
+ 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) {
+ pr_warn("usb out operation failed. (%d)\n", 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) {
+ pr_warn("usb out operation failed. (%d)\n", ret);
+ goto failed;
+ }
+
+ for (i = 0; i < 15; i++) {
+ msleep(100);
+
+ if (CI_CamReady(ca, slot)) {
+ pr_debug("CAM Ready\n");
+ 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 = d_to_priv(d);
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ pr_debug("%s()\n", __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) {
+ pr_warn("usb out operation failed. (%d)\n", 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 = d_to_priv(d);
+ 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) {
+ pr_warn("usb in operation failed. (%d)\n", 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;
+
+ pr_debug("%s()\n", __func__);
+
+ if (NULL == d)
+ return;
+
+ state = d_to_priv(d);
+ 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 *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct az6007_device_state *state = adap_to_priv(adap);
+ int ret;
+
+ pr_debug("%s()\n", __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(&adap->dvb_adap,
+ &state->ca,
+ 0, /* flags */
+ 1);/* n_slots */
+ if (ret != 0) {
+ pr_err("Cannot initialize CI: Error %d.\n", ret);
+ memset(&state->ca, 0, sizeof(state->ca));
+ return ret;
+ }
+
+ pr_debug("CI initialized.\n");
+
+ return 0;
+}
+
+static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct az6007_device_state *st = adap_to_priv(adap);
+ int ret;
+
+ ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
+ memcpy(mac, st->data, 6);
+
+ if (ret > 0)
+ pr_debug("%s: mac is %pM\n", __func__, mac);
+
+ return ret;
+}
+
+static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct az6007_device_state *st = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+
+ pr_debug("attaching demod drxk\n");
+
+ adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,
+ &d->i2c_adap);
+ if (!adap->fe[0])
+ return -EINVAL;
+
+ adap->fe[0]->sec_priv = adap;
+ st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
+ adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+ az6007_ci_init(adap);
+
+ return 0;
+}
+
+static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+
+ pr_debug("attaching tuner mt2063\n");
+
+ /* Attach mt2063 to DVB-C frontend */
+ if (adap->fe[0]->ops.i2c_gate_ctrl)
+ adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);
+ if (!dvb_attach(mt2063_attach, adap->fe[0],
+ &az6007_mt2063_config,
+ &d->i2c_adap))
+ return -EINVAL;
+
+ if (adap->fe[0]->ops.i2c_gate_ctrl)
+ adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);
+
+ return 0;
+}
+
+static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ struct az6007_device_state *state = d_to_priv(d);
+ int ret;
+
+ pr_debug("%s()\n", __func__);
+
+ if (!state->warm) {
+ mutex_init(&state->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;
+
+ state->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_to_priv(d);
+ 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) != 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 (az6007_xfer_debug)
+ printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",
+ 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];
+ } else
+ ret = -EIO;
+ i++;
+ } else if (!(msgs[i].flags & I2C_M_RD)) {
+ /* write bytes */
+ if (az6007_xfer_debug)
+ printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
+ 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;
+ for (j = 0; j < len; j++)
+ st->data[j] = msgs[i].buf[j + 1];
+ ret = __az6007_write(d->udev, req, value, index,
+ st->data, length);
+ } else {
+ /* read bytes */
+ if (az6007_xfer_debug)
+ printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
+ 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 (ret < 0)
+ goto err;
+ }
+err:
+ mutex_unlock(&st->mutex);
+
+ if (ret < 0) {
+ pr_info("%s ERROR: %i\n", __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,
+};
+
+static int az6007_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ int ret;
+ u8 *mac;
+
+ pr_debug("Identifying az6007 state\n");
+
+ mac = kmalloc(6, GFP_ATOMIC);
+ if (!mac)
+ return -ENOMEM;
+
+ /* Try to read the mac address */
+ ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+ if (ret == 6)
+ ret = WARM;
+ else
+ ret = COLD;
+
+ kfree(mac);
+
+ if (ret == COLD) {
+ __az6007_write(d->udev, 0x09, 1, 0, NULL, 0);
+ __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
+ __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
+ }
+
+ pr_debug("Device is on %s state\n",
+ ret == WARM ? "warm" : "cold");
+ return ret;
+}
+
+static void az6007_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ az6007_ci_uninit(d);
+ dvb_usbv2_disconnect(intf);
+}
+
+static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ pr_debug("Getting az6007 Remote Control properties\n");
+
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = az6007_rc_query;
+ rc->interval = 400;
+
+ return 0;
+}
+
+static int az6007_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ pr_debug("Loading az6007 firmware\n");
+
+ return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties az6007_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .firmware = AZ6007_FIRMWARE,
+
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct az6007_device_state),
+ .i2c_algo = &az6007_i2c_algo,
+ .tuner_attach = az6007_tuner_attach,
+ .frontend_attach = az6007_frontend_attach,
+ .streaming_ctrl = az6007_streaming_ctrl,
+ .get_rc_config = az6007_get_rc_config,
+ .read_mac_address = az6007_read_mac_addr,
+ .download_firmware = az6007_download_firmware,
+ .identify_state = az6007_identify_state,
+ .power_ctrl = az6007_power_ctrl,
+ .num_adapters = 1,
+ .adapter = {
+ { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
+ }
+};
+
+static struct usb_device_id az6007_usb_table[] = {
+ {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
+ &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
+ {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
+ &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+ {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
+ &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+
+static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+ az6007_ci_uninit(d);
+ return dvb_usbv2_suspend(intf, msg);
+}
+
+static int az6007_resume(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ struct dvb_usb_adapter *adap = &d->adapter[0];
+
+ az6007_ci_init(adap);
+ return dvb_usbv2_resume(intf);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = az6007_usb_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = az6007_usb_disconnect,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+ /*
+ * FIXME: need to implement reset_resume, likely with
+ * dvb-usb-v2 core support
+ */
+ .suspend = az6007_suspend,
+ .resume = az6007_resume,
+};
+
+module_usb_driver(az6007_usb_driver);
+
+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("2.0");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(AZ6007_FIRMWARE);
diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.c b/drivers/media/usb/dvb-usb-v2/ce6230.c
new file mode 100644
index 000000000000..819db9c01d5d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ce6230.c
@@ -0,0 +1,288 @@
+/*
+ * Intel CE6230 DVB USB driver
+ *
+ * Copyright (C) 2009 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 "ce6230.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
+{
+ int ret;
+ unsigned int pipe;
+ u8 request;
+ u8 requesttype;
+ u16 value;
+ u16 index;
+ u8 *buf;
+
+ request = req->cmd;
+ value = req->value;
+ index = req->index;
+
+ switch (req->cmd) {
+ case I2C_READ:
+ case DEMOD_READ:
+ case REG_READ:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ break;
+ case I2C_WRITE:
+ case DEMOD_WRITE:
+ case REG_WRITE:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ break;
+ default:
+ pr_debug("%s: unknown command=%02x\n", __func__, req->cmd);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ buf = kmalloc(req->data_len, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
+ /* write */
+ memcpy(buf, req->data, req->data_len);
+ pipe = usb_sndctrlpipe(d->udev, 0);
+ } else {
+ /* read */
+ pipe = usb_rcvctrlpipe(d->udev, 0);
+ }
+
+ msleep(1); /* avoid I2C errors */
+
+ ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
+ buf, req->data_len, CE6230_USB_TIMEOUT);
+
+ ce6230_debug_dump(request, requesttype, value, index, buf,
+ req->data_len);
+
+ if (ret < 0)
+ pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME,
+ ret);
+ else
+ ret = 0;
+
+ /* read request, copy returned data to return buf */
+ if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+ memcpy(req->data, buf, req->data_len);
+
+ kfree(buf);
+error:
+ return ret;
+}
+
+/* I2C */
+static struct zl10353_config ce6230_zl10353_config;
+
+static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret = 0, i = 0;
+ struct usb_req req;
+
+ if (num > 2)
+ return -EOPNOTSUPP;
+
+ memset(&req, 0, sizeof(req));
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ while (i < num) {
+ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+ if (msg[i].addr ==
+ ce6230_zl10353_config.demod_address) {
+ req.cmd = DEMOD_READ;
+ req.value = msg[i].addr >> 1;
+ req.index = msg[i].buf[0];
+ req.data_len = msg[i+1].len;
+ req.data = &msg[i+1].buf[0];
+ ret = ce6230_ctrl_msg(d, &req);
+ } else {
+ pr_err("%s: I2C read not implemented\n",
+ KBUILD_MODNAME);
+ ret = -EOPNOTSUPP;
+ }
+ i += 2;
+ } else {
+ if (msg[i].addr ==
+ ce6230_zl10353_config.demod_address) {
+ req.cmd = DEMOD_WRITE;
+ req.value = msg[i].addr >> 1;
+ req.index = msg[i].buf[0];
+ req.data_len = msg[i].len-1;
+ req.data = &msg[i].buf[1];
+ ret = ce6230_ctrl_msg(d, &req);
+ } else {
+ req.cmd = I2C_WRITE;
+ req.value = 0x2000 + (msg[i].addr >> 1);
+ req.index = 0x0000;
+ req.data_len = msg[i].len;
+ req.data = &msg[i].buf[0];
+ ret = ce6230_ctrl_msg(d, &req);
+ }
+ i += 1;
+ }
+ if (ret)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return ret ? ret : i;
+}
+
+static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ce6230_i2c_algorithm = {
+ .master_xfer = ce6230_i2c_master_xfer,
+ .functionality = ce6230_i2c_functionality,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config ce6230_zl10353_config = {
+ .demod_address = 0x1e,
+ .adc_clock = 450000,
+ .if2 = 45700,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .clock_ctl_1 = 0x34,
+ .pll_0 = 0x0e,
+};
+
+static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s:\n", __func__);
+
+ adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
+ &adap_to_d(adap)->i2c_adap);
+ if (adap->fe[0] == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct mxl5005s_config ce6230_mxl5003s_config = {
+ .i2c_address = 0xc6,
+ .if_freq = IF_FREQ_4570000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_DEFAULT,
+ .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 ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+
+ pr_debug("%s:\n", __func__);
+
+ ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
+ return ret;
+}
+
+static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+
+ pr_debug("%s: onoff=%d\n", __func__, onoff);
+
+ /* InterfaceNumber 1 / AlternateSetting 0 idle
+ InterfaceNumber 1 / AlternateSetting 1 streaming */
+ ret = usb_set_interface(d->udev, 1, onoff);
+ if (ret)
+ pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME,
+ ret);
+
+ return ret;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ce6230_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .bInterfaceNumber = 1,
+
+ .i2c_algo = &ce6230_i2c_algorithm,
+ .power_ctrl = ce6230_power_ctrl,
+ .frontend_attach = ce6230_zl10353_frontend_attach,
+ .tuner_attach = ce6230_mxl5003s_tuner_attach,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = (16 * 512),
+ }
+ }
+ },
+ }
+ },
+};
+
+static const struct usb_device_id ce6230_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
+ &ce6230_props, "Intel CE9500 reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
+ &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, ce6230_id_table);
+
+static struct usb_driver ce6230_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ce6230_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .reset_resume = dvb_usbv2_reset_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(ce6230_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Intel CE6230 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.h b/drivers/media/usb/dvb-usb-v2/ce6230.h
new file mode 100644
index 000000000000..42d754494a3a
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ce6230.h
@@ -0,0 +1,61 @@
+/*
+ * Intel CE6230 DVB USB driver
+ *
+ * Copyright (C) 2009 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 CE6230_H
+#define CE6230_H
+
+#include "dvb_usb.h"
+#include "zl10353.h"
+#include "mxl5005s.h"
+
+#define ce6230_debug_dump(r, t, v, i, b, l) { \
+ char *direction; \
+ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+ direction = ">>>"; \
+ else \
+ direction = "<<<"; \
+ pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \
+ __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+ l & 0xff, l >> 8, direction, l); \
+}
+
+#define CE6230_USB_TIMEOUT 1000
+
+struct usb_req {
+ u8 cmd; /* [1] */
+ u16 value; /* [2|3] */
+ u16 index; /* [4|5] */
+ u16 data_len; /* [6|7] */
+ u8 *data;
+};
+
+enum ce6230_cmd {
+ CONFIG_READ = 0xd0, /* rd 0 (unclear) */
+ UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */
+ I2C_READ = 0xd9, /* rd 9 (unclear) */
+ I2C_WRITE = 0xca, /* wr a */
+ DEMOD_READ = 0xdb, /* rd b */
+ DEMOD_WRITE = 0xcc, /* wr c */
+ REG_READ = 0xde, /* rd e */
+ REG_WRITE = 0xcf, /* wr f */
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
new file mode 100644
index 000000000000..9f7c970c6424
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
@@ -0,0 +1,125 @@
+/* cypress_firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
+
+struct usb_cypress_controller {
+ u8 id;
+ const char *name; /* name of the usb controller */
+ u16 cs_reg; /* needs to be restarted,
+ * when the firmware has been downloaded */
+};
+
+static const struct usb_cypress_controller cypress[] = {
+ { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 },
+ { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 },
+ { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
+ u8 len)
+{
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
+}
+
+int usbv2_cypress_load_firmware(struct usb_device *udev,
+ const struct firmware *fw, int type)
+{
+ struct hexline hx;
+ u8 reset;
+ int ret, pos = 0;
+
+ /* stop the CPU */
+ reset = 1;
+ ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1);
+ if (ret != 1)
+ pr_err("%s: could not stop the USB controller CPU",
+ KBUILD_MODNAME);
+
+ while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) {
+ pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n",
+ __func__, hx.addr, hx.len, hx.chk);
+
+ ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len);
+ if (ret != hx.len) {
+ pr_err("%s: error while transferring firmware " \
+ "(transferred size=%d, block size=%d)",
+ KBUILD_MODNAME, ret, hx.len);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret < 0) {
+ pr_err("%s: firmware download failed at %d with %d",
+ KBUILD_MODNAME, pos, ret);
+ return ret;
+ }
+
+ if (ret == 0) {
+ /* restart the CPU */
+ reset = 0;
+ if (ret || usb_cypress_writemem(
+ udev, cypress[type].cs_reg, &reset, 1) != 1) {
+ pr_err("%s: could not restart the USB controller CPU",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ }
+ } else
+ ret = -EIO;
+
+ return ret;
+}
+EXPORT_SYMBOL(usbv2_cypress_load_firmware);
+
+int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
+ int *pos)
+{
+ u8 *b = (u8 *) &fw->data[*pos];
+ int data_offs = 4;
+
+ if (*pos >= fw->size)
+ return 0;
+
+ memset(hx, 0, sizeof(struct hexline));
+
+ hx->len = b[0];
+
+ if ((*pos + hx->len + 4) >= fw->size)
+ return -EINVAL;
+
+ hx->addr = b[1] | (b[2] << 8);
+ hx->type = b[3];
+
+ if (hx->type == 0x04) {
+ /* b[4] and b[5] are the Extended linear address record data
+ * field */
+ hx->addr |= (b[4] << 24) | (b[5] << 16);
+ /*
+ hx->len -= 2;
+ data_offs += 2;
+ */
+ }
+ memcpy(hx->data, &b[data_offs], hx->len);
+ hx->chk = b[hx->len + data_offs];
+
+ *pos += hx->len + 5;
+
+ return *pos;
+}
+EXPORT_SYMBOL(dvb_usbv2_get_hexline);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Cypress firmware download");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
new file mode 100644
index 000000000000..80085fd4132c
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
@@ -0,0 +1,31 @@
+/* cypress_firmware.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#ifndef CYPRESS_FIRMWARE_H
+#define CYPRESS_FIRMWARE_H
+
+#define CYPRESS_AN2135 0
+#define CYPRESS_AN2235 1
+#define CYPRESS_FX2 2
+
+/* commonly used firmware download types and function */
+struct hexline {
+ u8 len;
+ u32 addr;
+ u8 type;
+ u8 data[255];
+ u8 chk;
+};
+extern int usbv2_cypress_load_firmware(struct usb_device *,
+ const struct firmware *, int);
+extern int dvb_usbv2_get_hexline(const struct firmware *,
+ struct hexline *, int *);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
new file mode 100644
index 000000000000..5a53c6231fc2
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -0,0 +1,392 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 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 DVB_USB_H
+#define DVB_USB_H
+
+#include <linux/usb/input.h>
+#include <linux/firmware.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "dvb-usb-ids.h"
+
+/*
+ * device file: /dev/dvb/adapter[0-1]/frontend[0-2]
+ *
+ * |-- device
+ * | |-- adapter0
+ * | | |-- frontend0
+ * | | |-- frontend1
+ * | | `-- frontend2
+ * | `-- adapter1
+ * | |-- frontend0
+ * | |-- frontend1
+ * | `-- frontend2
+ *
+ *
+ * Commonly used variable names:
+ * d = pointer to device (struct dvb_usb_device *)
+ * adap = pointer to adapter (struct dvb_usb_adapter *)
+ * fe = pointer to frontend (struct dvb_frontend *)
+ *
+ * Use macros defined in that file to resolve needed pointers.
+ */
+
+/* helper macros for every DVB USB driver use */
+#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \
+ adapter[adap->id]))
+#define adap_to_priv(adap) (adap_to_d(adap)->priv)
+#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv))
+#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe)))
+#define fe_to_priv(fe) (fe_to_d(fe)->priv)
+#define d_to_priv(d) (d->priv)
+
+#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \
+ .type = USB_BULK, \
+ .count = count_, \
+ .endpoint = endpoint_, \
+ .u = { \
+ .bulk = { \
+ .buffersize = size_, \
+ } \
+ } \
+}
+
+#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \
+ .type = USB_ISOC, \
+ .count = count_, \
+ .endpoint = endpoint_, \
+ .u = { \
+ .isoc = { \
+ .framesperurb = frames_, \
+ .framesize = size_,\
+ .interval = interval_, \
+ } \
+ } \
+}
+
+#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \
+ .props = (props_), \
+ .name = (name_), \
+ .rc_map = (rc), \
+ })
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+
+/**
+ * structure for carrying all needed data from the device driver to the general
+ * dvb usb routines
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @props: structure containing all device properties
+ */
+struct dvb_usb_driver_info {
+ const char *name;
+ const char *rc_map;
+ const struct dvb_usb_device_properties *props;
+};
+
+/**
+ * structure for remote controller configuration
+ * @map_name: name of rc codes table
+ * @allowed_protos: protocol(s) supported by the driver
+ * @change_protocol: callback to change protocol
+ * @query: called to query an event from the device
+ * @interval: time in ms between two queries
+ * @driver_type: used to point if a device supports raw mode
+ * @bulk_mode: device supports bulk mode for rc (disable polling mode)
+ */
+struct dvb_usb_rc {
+ const char *map_name;
+ u64 allowed_protos;
+ int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+ int (*query) (struct dvb_usb_device *d);
+ unsigned int interval;
+ const enum rc_driver_type driver_type;
+ bool bulk_mode;
+};
+
+/**
+ * usb streaming configration for adapter
+ * @type: urb type
+ * @count: count of used urbs
+ * @endpoint: stream usb endpoint number
+ */
+struct usb_data_stream_properties {
+#define USB_BULK 1
+#define USB_ISOC 2
+ u8 type;
+ u8 count;
+ u8 endpoint;
+
+ union {
+ struct {
+ unsigned int buffersize; /* per URB */
+ } bulk;
+ struct {
+ int framesperurb;
+ int framesize;
+ int interval;
+ } isoc;
+ } u;
+};
+
+/**
+ * properties of dvb usb device adapter
+ * @caps: adapter capabilities
+ * @pid_filter_count: pid count of adapter pid-filter
+ * @pid_filter_ctrl: called to enable/disable pid-filter
+ * @pid_filter: called to set/unset pid for filtering
+ * @stream: adapter usb stream configuration
+ */
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
+ u8 caps;
+
+ u8 pid_filter_count;
+ int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+ int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
+
+ struct usb_data_stream_properties stream;
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @driver_name: name of the owning driver module
+ * @owner: owner of the dvb_adapter
+ * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro
+ * @bInterfaceNumber: usb interface number driver binds
+ * @size_of_priv: bytes allocated for the driver private data
+ * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent
+ * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for
+ * receive
+ * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message
+ * @identify_state: called to determine the firmware state (cold or warm) and
+ * return possible firmware file name to be loaded
+ * @firmware: name of the firmware file to be loaded
+ * @download_firmware: called to download the firmware
+ * @i2c_algo: i2c_algorithm if the device has i2c-adapter
+ * @num_adapters: dvb usb device adapter count
+ * @get_adapter_count: called to resolve adapter count
+ * @adapter: array of all adapter properties of device
+ * @power_ctrl: called to enable/disable power of the device
+ * @read_config: called to resolve device configuration
+ * @read_mac_address: called to resolve adapter mac-address
+ * @frontend_attach: called to attach the possible frontends
+ * @tuner_attach: called to attach the possible tuners
+ * @frontend_ctrl: called to power on/off active frontend
+ * @streaming_ctrl: called to start/stop the usb streaming of adapter
+ * @init: called after adapters are created in order to finalize device
+ * configuration
+ * @exit: called when driver is unloaded
+ * @get_rc_config: called to resolve used remote controller configuration
+ * @get_stream_config: called to resolve input and output stream configuration
+ * of the adapter just before streaming is started. input stream is transport
+ * stream from the demodulator and output stream is usb stream to host.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+ const char *driver_name;
+ struct module *owner;
+ short *adapter_nr;
+
+ u8 bInterfaceNumber;
+ unsigned int size_of_priv;
+ u8 generic_bulk_ctrl_endpoint;
+ u8 generic_bulk_ctrl_endpoint_response;
+ unsigned int generic_bulk_ctrl_delay;
+
+#define WARM 0
+#define COLD 1
+ int (*identify_state) (struct dvb_usb_device *, const char **);
+ const char *firmware;
+#define RECONNECTS_USB 1
+ int (*download_firmware) (struct dvb_usb_device *,
+ const struct firmware *);
+
+ struct i2c_algorithm *i2c_algo;
+
+ unsigned int num_adapters;
+ int (*get_adapter_count) (struct dvb_usb_device *);
+ struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+ int (*power_ctrl) (struct dvb_usb_device *, int);
+ int (*read_config) (struct dvb_usb_device *d);
+ int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
+ int (*frontend_attach) (struct dvb_usb_adapter *);
+ int (*tuner_attach) (struct dvb_usb_adapter *);
+ int (*frontend_ctrl) (struct dvb_frontend *, int);
+ int (*streaming_ctrl) (struct dvb_frontend *, int);
+ int (*init) (struct dvb_usb_device *);
+ void (*exit) (struct dvb_usb_device *);
+ int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *);
+#define DVB_USB_FE_TS_TYPE_188 0
+#define DVB_USB_FE_TS_TYPE_204 1
+#define DVB_USB_FE_TS_TYPE_RAW 2
+ int (*get_stream_config) (struct dvb_frontend *, u8 *,
+ struct usb_data_stream_properties *);
+};
+
+/**
+ * generic object of an usb stream
+ * @buf_num: number of buffer allocated
+ * @buf_size: size of each buffer in buf_list
+ * @buf_list: array containing all allocate buffers for streaming
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list
+ *
+ * @urbs_initialized: number of URBs initialized
+ * @urbs_submitted: number of URBs submitted
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+ struct usb_device *udev;
+ struct usb_data_stream_properties props;
+
+#define USB_STATE_INIT 0x00
+#define USB_STATE_URB_BUF 0x01
+ u8 state;
+
+ void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+ struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ int buf_num;
+ unsigned long buf_size;
+ u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+ int urbs_initialized;
+ int urbs_submitted;
+
+ void *user_priv;
+};
+
+/**
+ * dvb adapter object on dvb usb device
+ * @props: pointer to adapter properties
+ * @stream: adapter the usb data stream
+ * @id: index of this adapter (starting with 0)
+ * @ts_type: transport stream, input stream, type
+ * @suspend_resume_active: set when there is ongoing suspend / resume
+ * @pid_filtering: is hardware pid_filtering used or not
+ * @feed_count: current feed count
+ * @max_feed_count: maimum feed count device can handle
+ * @dvb_adap: adapter dvb_adapter
+ * @dmxdev: adapter dmxdev
+ * @demux: adapter software demuxer
+ * @dvb_net: adapter dvb_net interfaces
+ * @sync_mutex: mutex used to sync control and streaming of the adapter
+ * @fe: adapter frontends
+ * @fe_init: rerouted frontend-init function
+ * @fe_sleep: rerouted frontend-sleep function
+ */
+struct dvb_usb_adapter {
+ const struct dvb_usb_adapter_properties *props;
+ struct usb_data_stream stream;
+ u8 id;
+ u8 ts_type;
+ bool suspend_resume_active;
+ bool pid_filtering;
+ u8 feed_count;
+ u8 max_feed_count;
+ s8 active_fe;
+
+ /* dvb */
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+ struct mutex sync_mutex;
+
+ struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
+ int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+ int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+};
+
+/**
+ * dvb usb device object
+ * @props: device properties
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @udev: pointer to the device's struct usb_device
+ * @intf: pointer to the device's usb interface
+ * @rc: remote controller configuration
+ * @probe_work: work to defer .probe()
+ * @powered: indicated whether the device is power or not
+ * @usb_mutex: mutex for usb control messages
+ * @i2c_mutex: mutex for i2c-transfers
+ * @i2c_adap: device's i2c-adapter
+ * @rc_dev: rc device for the remote control
+ * @rc_query_work: work for polling remote
+ * @priv: private data of the actual driver (allocate by dvb usb, size defined
+ * in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+ const struct dvb_usb_device_properties *props;
+ const char *name;
+ const char *rc_map;
+
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct dvb_usb_rc rc;
+ struct work_struct probe_work;
+ pid_t work_pid;
+ int powered;
+
+ /* locking */
+ struct mutex usb_mutex;
+
+ /* i2c */
+ struct mutex i2c_mutex;
+ struct i2c_adapter i2c_adap;
+
+ struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+ /* remote control */
+ struct rc_dev *rc_dev;
+ char rc_phys[64];
+ struct delayed_work rc_query_work;
+
+ void *priv;
+};
+
+extern int dvb_usbv2_probe(struct usb_interface *,
+ const struct usb_device_id *);
+extern void dvb_usbv2_disconnect(struct usb_interface *);
+extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t);
+extern int dvb_usbv2_resume(struct usb_interface *);
+extern int dvb_usbv2_reset_resume(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
+extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
new file mode 100644
index 000000000000..45f07090d431
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_common.h
@@ -0,0 +1,35 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 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 DVB_USB_COMMON_H
+#define DVB_USB_COMMON_H
+
+#include "dvb_usb.h"
+
+/* commonly used methods */
+extern int usb_urb_initv2(struct usb_data_stream *stream,
+ const struct usb_data_stream_properties *props);
+extern int usb_urb_exitv2(struct usb_data_stream *stream);
+extern int usb_urb_submitv2(struct usb_data_stream *stream,
+ struct usb_data_stream_properties *props);
+extern int usb_urb_killv2(struct usb_data_stream *stream);
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
new file mode 100644
index 000000000000..e2d73e1a7ae0
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -0,0 +1,1046 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 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 "dvb_usb_common.h"
+
+int dvb_usbv2_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling,
+ "disable remote control polling (default: 0)");
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
+ int, 0444);
+MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \
+ "PID filter, if any (default: 0)");
+
+static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name)
+{
+ int ret;
+ const struct firmware *fw;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ if (!d->props->download_firmware) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = request_firmware(&fw, name, &d->udev->dev);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: Did not find the firmware file "\
+ "'%s'. Please see linux/Documentation/dvb/ " \
+ "for more details on firmware-problems. " \
+ "Status %d\n", KBUILD_MODNAME, name, ret);
+ goto err;
+ }
+
+ dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n",
+ KBUILD_MODNAME, name);
+
+ ret = d->props->download_firmware(d, fw);
+ release_firmware(fw);
+ if (ret < 0)
+ goto err;
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
+{
+ int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ if (!d->props->i2c_algo)
+ return 0;
+
+ strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
+ d->i2c_adap.algo = d->props->i2c_algo;
+ d->i2c_adap.dev.parent = &d->udev->dev;
+ i2c_set_adapdata(&d->i2c_adap, d);
+
+ ret = i2c_add_adapter(&d->i2c_adap);
+ if (ret < 0) {
+ d->i2c_adap.algo = NULL;
+ dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err;
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
+{
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ if (d->i2c_adap.algo)
+ i2c_del_adapter(&d->i2c_adap);
+
+ return 0;
+}
+
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+ struct dvb_usb_device *d = container_of(work,
+ struct dvb_usb_device, rc_query_work.work);
+ int ret;
+
+ /*
+ * When the parameter has been set to 1 via sysfs while the
+ * driver was running, or when bulk mode is enabled after IR init.
+ */
+ if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+ return;
+
+ ret = d->rc.query(d);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ return; /* stop polling */
+ }
+
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->rc.interval));
+}
+
+static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+ int ret;
+ struct rc_dev *dev;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+ return 0;
+
+ d->rc.map_name = d->rc_map;
+ ret = d->props->get_rc_config(d, &d->rc);
+ if (ret < 0)
+ goto err;
+
+ /* disable rc when there is no keymap defined */
+ if (!d->rc.map_name)
+ return 0;
+
+ dev = rc_allocate_device();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->dev.parent = &d->udev->dev;
+ dev->input_name = d->name;
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+ dev->input_phys = d->rc_phys;
+ usb_to_input_id(d->udev, &dev->input_id);
+ /* TODO: likely RC-core should took const char * */
+ dev->driver_name = (char *) d->props->driver_name;
+ dev->map_name = d->rc.map_name;
+ dev->driver_type = d->rc.driver_type;
+ dev->allowed_protos = d->rc.allowed_protos;
+ dev->change_protocol = d->rc.change_protocol;
+ dev->priv = d;
+
+ ret = rc_register_device(dev);
+ if (ret < 0) {
+ rc_free_device(dev);
+ goto err;
+ }
+
+ d->rc_dev = dev;
+
+ /* start polling if needed */
+ if (d->rc.query && !d->rc.bulk_mode) {
+ /* initialize a work queue for handling polling */
+ INIT_DELAYED_WORK(&d->rc_query_work,
+ dvb_usb_read_remote_control);
+ dev_info(&d->udev->dev, "%s: schedule remote query interval " \
+ "to %d msecs\n", KBUILD_MODNAME,
+ d->rc.interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->rc.interval));
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ if (d->rc_dev) {
+ cancel_delayed_work_sync(&d->rc_query_work);
+ rc_unregister_device(d->rc_dev);
+ d->rc_dev = NULL;
+ }
+
+ return 0;
+}
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+ dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+ adap->id);
+
+ adap->stream.udev = adap_to_d(adap)->udev;
+ adap->stream.user_priv = adap;
+ adap->stream.complete = dvb_usb_data_complete;
+
+ return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+ dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+ adap->id);
+
+ return usb_urb_exitv2(&adap->stream);
+}
+
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
+ int count)
+{
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \
+ "setting pid [%s]: %04x (%04d) at index %d '%s'\n",
+ __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
+ adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+ dvbdmxfeed->pid, dvbdmxfeed->index,
+ (count == 1) ? "on" : "off");
+
+ if (adap->active_fe == -1)
+ return -EINVAL;
+
+ adap->feed_count += count;
+
+ /* stop feeding if it is last pid */
+ if (adap->feed_count == 0) {
+ dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
+ usb_urb_killv2(&adap->stream);
+
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(
+ adap->fe[adap->active_fe], 0);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+ "failed=%d\n", KBUILD_MODNAME,
+ ret);
+ goto err_mutex_unlock;
+ }
+ }
+ mutex_unlock(&adap->sync_mutex);
+ }
+
+ /* activate the pid on the device pid filter */
+ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->pid_filtering &&
+ adap->props->pid_filter)
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+ if (ret < 0)
+ dev_err(&d->udev->dev, "%s: pid_filter() " \
+ "failed=%d\n", KBUILD_MODNAME,
+ ret);
+
+ /* start feeding if it is first pid */
+ if (adap->feed_count == 1 && count == 1) {
+ struct usb_data_stream_properties stream_props;
+ mutex_lock(&adap->sync_mutex);
+ dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
+
+ /* resolve input and output streaming paramters */
+ if (d->props->get_stream_config) {
+ memcpy(&stream_props, &adap->props->stream,
+ sizeof(struct usb_data_stream_properties));
+ ret = d->props->get_stream_config(
+ adap->fe[adap->active_fe],
+ &adap->ts_type, &stream_props);
+ if (ret < 0)
+ goto err_mutex_unlock;
+ } else {
+ stream_props = adap->props->stream;
+ }
+
+ switch (adap->ts_type) {
+ case DVB_USB_FE_TS_TYPE_204:
+ adap->stream.complete = dvb_usb_data_complete_204;
+ break;
+ case DVB_USB_FE_TS_TYPE_RAW:
+ adap->stream.complete = dvb_usb_data_complete_raw;
+ break;
+ case DVB_USB_FE_TS_TYPE_188:
+ default:
+ adap->stream.complete = dvb_usb_data_complete;
+ break;
+ }
+
+ usb_urb_submitv2(&adap->stream, &stream_props);
+
+ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->props->caps &
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+ adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap,
+ adap->pid_filtering);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: " \
+ "pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_mutex_unlock;
+ }
+ }
+
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(
+ adap->fe[adap->active_fe], 1);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+ "failed=%d\n", KBUILD_MODNAME,
+ ret);
+ goto err_mutex_unlock;
+ }
+ }
+ }
+
+ return 0;
+err_mutex_unlock:
+ mutex_unlock(&adap->sync_mutex);
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+ ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+ &d->udev->dev, d->props->adapter_nr);
+ if (ret < 0) {
+ dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n",
+ __func__, ret);
+ goto err_dvb_register_adapter;
+ }
+
+ adap->dvb_adap.priv = adap;
+
+ if (d->props->read_mac_address) {
+ ret = d->props->read_mac_address(adap,
+ adap->dvb_adap.proposed_mac);
+ if (ret < 0)
+ goto err_dvb_dmx_init;
+
+ dev_info(&d->udev->dev, "%s: MAC address: %pM\n",
+ KBUILD_MODNAME, adap->dvb_adap.proposed_mac);
+ }
+
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ adap->demux.priv = adap;
+ adap->demux.filternum = 0;
+ adap->demux.filternum = adap->max_feed_count;
+ adap->demux.feednum = adap->demux.filternum;
+ adap->demux.start_feed = dvb_usb_start_feed;
+ adap->demux.stop_feed = dvb_usb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+ ret = dvb_dmx_init(&adap->demux);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_dvb_dmx_init;
+ }
+
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+ ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_dvb_dmxdev_init;
+ }
+
+ ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_dvb_net_init;
+ }
+
+ mutex_init(&adap->sync_mutex);
+
+ return 0;
+err_dvb_net_init:
+ dvb_dmxdev_release(&adap->dmxdev);
+err_dvb_dmxdev_init:
+ dvb_dmx_release(&adap->demux);
+err_dvb_dmx_init:
+ dvb_unregister_adapter(&adap->dvb_adap);
+err_dvb_register_adapter:
+ adap->dvb_adap.priv = NULL;
+ return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+ dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+ adap->id);
+
+ if (adap->dvb_adap.priv) {
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ }
+
+ return 0;
+}
+
+int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+
+ if (onoff)
+ d->powered++;
+ else
+ d->powered--;
+
+ if (d->powered == 0 || (onoff && d->powered == 1)) {
+ /* when switching from 1 to 0 or from 0 to 1 */
+ dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff);
+ if (d->props->power_ctrl) {
+ ret = d->props->power_ctrl(d, onoff);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usb_fe_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+ fe->id);
+
+ if (!adap->suspend_resume_active) {
+ adap->active_fe = fe->id;
+ mutex_lock(&adap->sync_mutex);
+ }
+
+ ret = dvb_usbv2_device_power_ctrl(d, 1);
+ if (ret < 0)
+ goto err;
+
+ if (d->props->frontend_ctrl) {
+ ret = d->props->frontend_ctrl(fe, 1);
+ if (ret < 0)
+ goto err;
+ }
+
+ if (adap->fe_init[fe->id]) {
+ ret = adap->fe_init[fe->id](fe);
+ if (ret < 0)
+ goto err;
+ }
+err:
+ if (!adap->suspend_resume_active)
+ mutex_unlock(&adap->sync_mutex);
+
+ dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+ fe->id);
+
+ if (!adap->suspend_resume_active)
+ mutex_lock(&adap->sync_mutex);
+
+ if (adap->fe_sleep[fe->id]) {
+ ret = adap->fe_sleep[fe->id](fe);
+ if (ret < 0)
+ goto err;
+ }
+
+ if (d->props->frontend_ctrl) {
+ ret = d->props->frontend_ctrl(fe, 0);
+ if (ret < 0)
+ goto err;
+ }
+
+ ret = dvb_usbv2_device_power_ctrl(d, 0);
+ if (ret < 0)
+ goto err;
+err:
+ if (!adap->suspend_resume_active) {
+ adap->active_fe = -1;
+ mutex_unlock(&adap->sync_mutex);
+ }
+
+ dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
+ return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+ int ret, i, count_registered = 0;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+ memset(adap->fe, 0, sizeof(adap->fe));
+ adap->active_fe = -1;
+
+ if (d->props->frontend_attach) {
+ ret = d->props->frontend_attach(adap);
+ if (ret < 0) {
+ dev_dbg(&d->udev->dev, "%s: frontend_attach() " \
+ "failed=%d\n", __func__, ret);
+ goto err_dvb_frontend_detach;
+ }
+ } else {
+ dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n",
+ __func__);
+ ret = 0;
+ goto err;
+ }
+
+ for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+ adap->fe[i]->id = i;
+ /* re-assign sleep and wakeup functions */
+ adap->fe_init[i] = adap->fe[i]->ops.init;
+ adap->fe[i]->ops.init = dvb_usb_fe_init;
+ adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+ adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+ ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: frontend%d registration " \
+ "failed\n", KBUILD_MODNAME, i);
+ goto err_dvb_unregister_frontend;
+ }
+
+ count_registered++;
+ }
+
+ if (d->props->tuner_attach) {
+ ret = d->props->tuner_attach(adap);
+ if (ret < 0) {
+ dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n",
+ __func__, ret);
+ goto err_dvb_unregister_frontend;
+ }
+ }
+
+ return 0;
+
+err_dvb_unregister_frontend:
+ for (i = count_registered - 1; i >= 0; i--)
+ dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+ for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+ if (adap->fe[i])
+ dvb_frontend_detach(adap->fe[i]);
+ }
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+ int i;
+ dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+ adap->id);
+
+ for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+ if (adap->fe[i]) {
+ dvb_unregister_frontend(adap->fe[i]);
+ dvb_frontend_detach(adap->fe[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int dvb_usbv2_adapter_init(struct dvb_usb_device *d)
+{
+ struct dvb_usb_adapter *adap;
+ int ret, i, adapter_count;
+
+ /* resolve adapter count */
+ adapter_count = d->props->num_adapters;
+ if (d->props->get_adapter_count) {
+ ret = d->props->get_adapter_count(d);
+ if (ret < 0)
+ goto err;
+
+ adapter_count = ret;
+ }
+
+ for (i = 0; i < adapter_count; i++) {
+ adap = &d->adapter[i];
+ adap->id = i;
+ adap->props = &d->props->adapter[i];
+
+ /* speed - when running at FULL speed we need a HW PID filter */
+ if (d->udev->speed == USB_SPEED_FULL &&
+ !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+ dev_err(&d->udev->dev, "%s: this USB2.0 device " \
+ "cannot be run on a USB1.1 port (it " \
+ "lacks a hardware PID filter)\n",
+ KBUILD_MODNAME);
+ ret = -ENODEV;
+ goto err;
+ } else if ((d->udev->speed == USB_SPEED_FULL &&
+ adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+ (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+ dev_info(&d->udev->dev, "%s: will use the device's " \
+ "hardware PID filter " \
+ "(table count: %d)\n", KBUILD_MODNAME,
+ adap->props->pid_filter_count);
+ adap->pid_filtering = 1;
+ adap->max_feed_count = adap->props->pid_filter_count;
+ } else {
+ dev_info(&d->udev->dev, "%s: will pass the complete " \
+ "MPEG2 transport stream to the " \
+ "software demuxer\n", KBUILD_MODNAME);
+ adap->pid_filtering = 0;
+ adap->max_feed_count = 255;
+ }
+
+ if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage &&
+ adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+ dev_info(&d->udev->dev, "%s: PID filter enabled by " \
+ "module option\n", KBUILD_MODNAME);
+ adap->pid_filtering = 1;
+ adap->max_feed_count = adap->props->pid_filter_count;
+ }
+
+ ret = dvb_usbv2_adapter_stream_init(adap);
+ if (ret)
+ goto err;
+
+ ret = dvb_usbv2_adapter_dvb_init(adap);
+ if (ret)
+ goto err;
+
+ ret = dvb_usbv2_adapter_frontend_init(adap);
+ if (ret)
+ goto err;
+
+ /* use exclusive FE lock if there is multiple shared FEs */
+ if (adap->fe[1])
+ adap->dvb_adap.mfe_shared = 1;
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
+{
+ int i;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+ if (d->adapter[i].props) {
+ dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
+ dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
+ dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+ }
+ }
+
+ return 0;
+}
+
+/* general initialization functions */
+static int dvb_usbv2_exit(struct dvb_usb_device *d)
+{
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ dvb_usbv2_remote_exit(d);
+ dvb_usbv2_adapter_exit(d);
+ dvb_usbv2_i2c_exit(d);
+ kfree(d->priv);
+ kfree(d);
+
+ return 0;
+}
+
+static int dvb_usbv2_init(struct dvb_usb_device *d)
+{
+ int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ dvb_usbv2_device_power_ctrl(d, 1);
+
+ if (d->props->read_config) {
+ ret = d->props->read_config(d);
+ if (ret < 0)
+ goto err;
+ }
+
+ ret = dvb_usbv2_i2c_init(d);
+ if (ret < 0)
+ goto err;
+
+ ret = dvb_usbv2_adapter_init(d);
+ if (ret < 0)
+ goto err;
+
+ if (d->props->init) {
+ ret = d->props->init(d);
+ if (ret < 0)
+ goto err;
+ }
+
+ ret = dvb_usbv2_remote_init(d);
+ if (ret < 0)
+ goto err;
+
+ dvb_usbv2_device_power_ctrl(d, 0);
+
+ return 0;
+err:
+ dvb_usbv2_device_power_ctrl(d, 0);
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+/*
+ * udev, which is used for the firmware downloading, requires we cannot
+ * block during module_init(). module_init() calls USB probe() which
+ * is this routine. Due to that we delay actual operation using workqueue
+ * and return always success here.
+ */
+static void dvb_usbv2_init_work(struct work_struct *work)
+{
+ int ret;
+ struct dvb_usb_device *d =
+ container_of(work, struct dvb_usb_device, probe_work);
+
+ d->work_pid = current->pid;
+ dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid);
+
+ if (d->props->size_of_priv) {
+ d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL);
+ if (!d->priv) {
+ dev_err(&d->udev->dev, "%s: kzalloc() failed\n",
+ KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto err_usb_driver_release_interface;
+ }
+ }
+
+ if (d->props->identify_state) {
+ const char *name = NULL;
+ ret = d->props->identify_state(d, &name);
+ if (ret == 0) {
+ ;
+ } else if (ret == COLD) {
+ dev_info(&d->udev->dev, "%s: found a '%s' in cold " \
+ "state\n", KBUILD_MODNAME, d->name);
+
+ if (!name)
+ name = d->props->firmware;
+
+ ret = dvb_usbv2_download_firmware(d, name);
+ if (ret == 0) {
+ /* device is warm, continue initialization */
+ ;
+ } else if (ret == RECONNECTS_USB) {
+ /*
+ * USB core will call disconnect() and then
+ * probe() as device reconnects itself from the
+ * USB bus. disconnect() will release all driver
+ * resources and probe() is called for 'new'
+ * device. As 'new' device is warm we should
+ * never go here again.
+ */
+ return;
+ } else {
+ /*
+ * Unexpected error. We must unregister driver
+ * manually from the device, because device is
+ * already register by returning from probe()
+ * with success. usb_driver_release_interface()
+ * finally calls disconnect() in order to free
+ * resources.
+ */
+ goto err_usb_driver_release_interface;
+ }
+ } else {
+ goto err_usb_driver_release_interface;
+ }
+ }
+
+ dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n",
+ KBUILD_MODNAME, d->name);
+
+ ret = dvb_usbv2_init(d);
+ if (ret < 0)
+ goto err_usb_driver_release_interface;
+
+ dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \
+ "connected\n", KBUILD_MODNAME, d->name);
+
+ return;
+err_usb_driver_release_interface:
+ dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n",
+ KBUILD_MODNAME, d->name, ret);
+ usb_driver_release_interface(to_usb_driver(d->intf->dev.driver),
+ d->intf);
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return;
+}
+
+int dvb_usbv2_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret;
+ struct dvb_usb_device *d;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct dvb_usb_driver_info *driver_info =
+ (struct dvb_usb_driver_info *) id->driver_info;
+
+ dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ if (!id->driver_info) {
+ dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
+ if (!d) {
+ dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ d->name = driver_info->name;
+ d->rc_map = driver_info->rc_map;
+ d->udev = udev;
+ d->intf = intf;
+ d->props = driver_info->props;
+
+ if (d->intf->cur_altsetting->desc.bInterfaceNumber !=
+ d->props->bInterfaceNumber) {
+ ret = -ENODEV;
+ goto err_kfree;
+ }
+
+ mutex_init(&d->usb_mutex);
+ mutex_init(&d->i2c_mutex);
+ INIT_WORK(&d->probe_work, dvb_usbv2_init_work);
+ usb_set_intfdata(intf, d);
+ ret = schedule_work(&d->probe_work);
+ if (ret < 0) {
+ dev_err(&d->udev->dev, "%s: schedule_work() failed\n",
+ KBUILD_MODNAME);
+ goto err_kfree;
+ }
+
+ return 0;
+err_kfree:
+ kfree(d);
+err:
+ dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_probe);
+
+void dvb_usbv2_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ const char *name = d->name;
+ struct device dev = d->udev->dev;
+ dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__,
+ current->pid, d->work_pid);
+
+ /* ensure initialization work is finished until release resources */
+ if (d->work_pid != current->pid)
+ cancel_work_sync(&d->probe_work);
+
+ if (d->props->exit)
+ d->props->exit(d);
+
+ dvb_usbv2_exit(d);
+
+ dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
+ KBUILD_MODNAME, name);
+}
+EXPORT_SYMBOL(dvb_usbv2_disconnect);
+
+int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ int ret = 0, i, active_fe;
+ struct dvb_frontend *fe;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /* stop remote controller poll */
+ if (d->rc.query && !d->rc.bulk_mode)
+ cancel_delayed_work_sync(&d->rc_query_work);
+
+ for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+ active_fe = d->adapter[i].active_fe;
+ if (d->adapter[i].dvb_adap.priv && active_fe != -1) {
+ fe = d->adapter[i].fe[active_fe];
+ d->adapter[i].suspend_resume_active = true;
+
+ if (d->props->streaming_ctrl)
+ d->props->streaming_ctrl(fe, 0);
+
+ /* stop usb streaming */
+ usb_urb_killv2(&d->adapter[i].stream);
+
+ ret = dvb_frontend_suspend(fe);
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_suspend);
+
+static int dvb_usbv2_resume_common(struct dvb_usb_device *d)
+{
+ int ret = 0, i, active_fe;
+ struct dvb_frontend *fe;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) {
+ active_fe = d->adapter[i].active_fe;
+ if (d->adapter[i].dvb_adap.priv && active_fe != -1) {
+ fe = d->adapter[i].fe[active_fe];
+
+ ret = dvb_frontend_resume(fe);
+
+ /* resume usb streaming */
+ usb_urb_submitv2(&d->adapter[i].stream, NULL);
+
+ if (d->props->streaming_ctrl)
+ d->props->streaming_ctrl(fe, 1);
+
+ d->adapter[i].suspend_resume_active = false;
+ }
+ }
+
+ /* start remote controller poll */
+ if (d->rc.query && !d->rc.bulk_mode)
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->rc.interval));
+
+ return ret;
+}
+
+int dvb_usbv2_resume(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ return dvb_usbv2_resume_common(d);
+}
+EXPORT_SYMBOL(dvb_usbv2_resume);
+
+int dvb_usbv2_reset_resume(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ dvb_usbv2_device_power_ctrl(d, 1);
+
+ if (d->props->init)
+ d->props->init(d);
+
+ ret = dvb_usbv2_resume_common(d);
+
+ dvb_usbv2_device_power_ctrl(d, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_reset_resume);
+
+MODULE_VERSION("2.0");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("DVB USB common");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
new file mode 100644
index 000000000000..0431beed0ef4
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -0,0 +1,77 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 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 "dvb_usb_common.h"
+
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+ u16 rlen)
+{
+ int ret, actual_length;
+
+ if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+ !d->props->generic_bulk_ctrl_endpoint_response) {
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&d->usb_mutex);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
+
+ ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+ d->props->generic_bulk_ctrl_endpoint), wbuf, wlen,
+ &actual_length, 2000);
+ if (ret < 0)
+ dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ else
+ ret = actual_length != wlen ? -EIO : 0;
+
+ /* an answer is expected, and no error before */
+ if (!ret && rbuf && rlen) {
+ if (d->props->generic_bulk_ctrl_delay)
+ usleep_range(d->props->generic_bulk_ctrl_delay,
+ d->props->generic_bulk_ctrl_delay
+ + 20000);
+
+ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+ d->props->generic_bulk_ctrl_endpoint_response),
+ rbuf, rlen, &actual_length, 2000);
+ if (ret)
+ dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \
+ "failed=%d\n", KBUILD_MODNAME, ret);
+
+ dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
+ actual_length, rbuf);
+ }
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw);
+
+int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+ return dvb_usbv2_generic_rw(d, buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write);
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c
new file mode 100644
index 000000000000..ab77622c383d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ec168.c
@@ -0,0 +1,376 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * Copyright (C) 2009 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 "ec168.h"
+#include "ec100.h"
+#include "mxl5005s.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
+{
+ int ret;
+ unsigned int pipe;
+ u8 request, requesttype;
+ u8 *buf;
+
+ switch (req->cmd) {
+ case DOWNLOAD_FIRMWARE:
+ case GPIO:
+ case WRITE_I2C:
+ case STREAMING_CTRL:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ request = req->cmd;
+ break;
+ case READ_I2C:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ request = req->cmd;
+ break;
+ case GET_CONFIG:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ request = CONFIG;
+ break;
+ case SET_CONFIG:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ request = CONFIG;
+ break;
+ case WRITE_DEMOD:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ request = DEMOD_RW;
+ break;
+ case READ_DEMOD:
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ request = DEMOD_RW;
+ break;
+ default:
+ pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ buf = kmalloc(req->size, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
+ /* write */
+ memcpy(buf, req->data, req->size);
+ pipe = usb_sndctrlpipe(d->udev, 0);
+ } else {
+ /* read */
+ pipe = usb_rcvctrlpipe(d->udev, 0);
+ }
+
+ msleep(1); /* avoid I2C errors */
+
+ ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value,
+ req->index, buf, req->size, EC168_USB_TIMEOUT);
+
+ ec168_debug_dump(request, requesttype, req->value, req->index, buf,
+ req->size);
+
+ if (ret < 0)
+ goto err_dealloc;
+ else
+ ret = 0;
+
+ /* 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);
+ return ret;
+
+err_dealloc:
+ kfree(buf);
+error:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+/* I2C */
+static struct ec100_config ec168_ec100_config;
+
+static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct ec168_req req;
+ int i = 0;
+ int ret;
+
+ if (num > 2)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ while (i < num) {
+ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+ if (msg[i].addr == ec168_ec100_config.demod_address) {
+ req.cmd = READ_DEMOD;
+ req.value = 0;
+ req.index = 0xff00 + msg[i].buf[0]; /* reg */
+ req.size = msg[i+1].len; /* bytes to read */
+ req.data = &msg[i+1].buf[0];
+ ret = ec168_ctrl_msg(d, &req);
+ i += 2;
+ } else {
+ pr_err("%s: I2C read not implemented\n",
+ KBUILD_MODNAME);
+ ret = -EOPNOTSUPP;
+ i += 2;
+ }
+ } else {
+ if (msg[i].addr == ec168_ec100_config.demod_address) {
+ req.cmd = WRITE_DEMOD;
+ req.value = msg[i].buf[1]; /* val */
+ req.index = 0xff00 + msg[i].buf[0]; /* reg */
+ req.size = 0;
+ req.data = NULL;
+ ret = ec168_ctrl_msg(d, &req);
+ i += 1;
+ } else {
+ req.cmd = WRITE_I2C;
+ req.value = msg[i].buf[0]; /* val */
+ req.index = 0x0100 + msg[i].addr; /* I2C addr */
+ req.size = msg[i].len-1;
+ req.data = &msg[i].buf[1];
+ ret = ec168_ctrl_msg(d, &req);
+ i += 1;
+ }
+ }
+ if (ret)
+ goto error;
+
+ }
+ ret = i;
+
+error:
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 ec168_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ec168_i2c_algo = {
+ .master_xfer = ec168_i2c_xfer,
+ .functionality = ec168_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int ec168_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ int ret;
+ u8 reply;
+ struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
+ pr_debug("%s:\n", __func__);
+
+ ret = ec168_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ pr_debug("%s: reply=%02x\n", __func__, reply);
+
+ if (reply == 0x01)
+ ret = WARM;
+ else
+ ret = COLD;
+
+ return ret;
+error:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int ec168_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ int ret, len, remaining;
+ struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
+ pr_debug("%s:\n", __func__);
+
+ #define LEN_MAX 2048 /* max packet size */
+ for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+ len = remaining;
+ if (len > LEN_MAX)
+ len = LEN_MAX;
+
+ req.size = len;
+ req.data = (u8 *) &fw->data[fw->size - remaining];
+ req.index = fw->size - remaining;
+
+ ret = ec168_ctrl_msg(d, &req);
+ if (ret) {
+ pr_err("%s: firmware download failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto error;
+ }
+ }
+
+ req.size = 0;
+
+ /* set "warm"? */
+ req.cmd = SET_CONFIG;
+ req.value = 0;
+ req.index = 0x0001;
+ ret = ec168_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ /* really needed - no idea what does */
+ req.cmd = GPIO;
+ req.value = 0;
+ req.index = 0x0206;
+ ret = ec168_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ /* activate tuner I2C? */
+ req.cmd = WRITE_I2C;
+ req.value = 0;
+ req.index = 0x00c6;
+ ret = ec168_ctrl_msg(d, &req);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct ec100_config ec168_ec100_config = {
+ .demod_address = 0xff, /* not real address, demod is integrated */
+};
+
+static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s:\n", __func__);
+ adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config,
+ &adap_to_d(adap)->i2c_adap);
+ if (adap->fe[0] == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct mxl5005s_config ec168_mxl5003s_config = {
+ .i2c_address = 0xc6,
+ .if_freq = IF_FREQ_4570000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_OFF,
+ .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 ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s:\n", __func__);
+ return dvb_attach(mxl5005s_attach, adap->fe[0],
+ &adap_to_d(adap)->i2c_adap,
+ &ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
+}
+
+static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
+ pr_debug("%s: onoff=%d\n", __func__, onoff);
+ if (onoff)
+ req.index = 0x0102;
+ return ec168_ctrl_msg(fe_to_d(fe), &req);
+}
+
+/* DVB USB Driver stuff */
+/* bInterfaceNumber 0 is HID
+ * bInterfaceNumber 1 is DVB-T */
+static struct dvb_usb_device_properties ec168_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .bInterfaceNumber = 1,
+
+ .identify_state = ec168_identify_state,
+ .firmware = "dvb-usb-ec168.fw",
+ .download_firmware = ec168_download_firmware,
+
+ .i2c_algo = &ec168_i2c_algo,
+ .frontend_attach = ec168_ec100_frontend_attach,
+ .tuner_attach = ec168_mxl5003s_tuner_attach,
+ .streaming_ctrl = ec168_streaming_ctrl,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512),
+ }
+ },
+};
+
+static const struct dvb_usb_driver_info ec168_driver_info = {
+ .name = "E3C EC168 reference design",
+ .props = &ec168_props,
+};
+
+static const struct usb_device_id ec168_id[] = {
+ { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168),
+ .driver_info = (kernel_ulong_t) &ec168_driver_info },
+ { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2),
+ .driver_info = (kernel_ulong_t) &ec168_driver_info },
+ { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3),
+ .driver_info = (kernel_ulong_t) &ec168_driver_info },
+ { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4),
+ .driver_info = (kernel_ulong_t) &ec168_driver_info },
+ { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5),
+ .driver_info = (kernel_ulong_t) &ec168_driver_info },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, ec168_id);
+
+static struct usb_driver ec168_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ec168_id,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(ec168_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("E3C EC168 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.h b/drivers/media/usb/dvb-usb-v2/ec168.h
new file mode 100644
index 000000000000..9181236f6ebc
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/ec168.h
@@ -0,0 +1,63 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * Copyright (C) 2009 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 EC168_H
+#define EC168_H
+
+#include "dvb_usb.h"
+
+#define ec168_debug_dump(r, t, v, i, b, l) { \
+ char *direction; \
+ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+ direction = ">>>"; \
+ else \
+ direction = "<<<"; \
+ pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \
+ __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+ l & 0xff, l >> 8, direction); \
+}
+
+#define EC168_USB_TIMEOUT 1000
+
+struct ec168_req {
+ u8 cmd; /* [1] */
+ u16 value; /* [2|3] */
+ u16 index; /* [4|5] */
+ u16 size; /* [6|7] */
+ u8 *data;
+};
+
+enum ec168_cmd {
+ DOWNLOAD_FIRMWARE = 0x00,
+ CONFIG = 0x01,
+ DEMOD_RW = 0x03,
+ GPIO = 0x04,
+ STREAMING_CTRL = 0x10,
+ READ_I2C = 0x20,
+ WRITE_I2C = 0x21,
+ HID_DOWNLOAD = 0x30,
+ GET_CONFIG,
+ SET_CONFIG,
+ READ_DEMOD,
+ WRITE_DEMOD,
+};
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c
new file mode 100644
index 000000000000..cf29f43e3598
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/gl861.c
@@ -0,0 +1,175 @@
+/* DVB USB compliant linux driver for GL861 USB2.0 devices.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gl861.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u16 index;
+ u16 value = addr << (8 + 1);
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 req, type;
+
+ if (wo) {
+ req = GL861_REQ_I2C_WRITE;
+ type = GL861_WRITE;
+ } else { /* rw */
+ req = GL861_REQ_I2C_READ;
+ type = GL861_READ;
+ }
+
+ switch (wlen) {
+ case 1:
+ index = wbuf[0];
+ break;
+ case 2:
+ index = wbuf[0];
+ value = value + wbuf[1];
+ break;
+ default:
+ pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen);
+ return -EINVAL;
+ }
+
+ msleep(1); /* avoid I2C errors */
+
+ return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
+ value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (num > 2)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+ break;
+ i++;
+ } else
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm gl861_i2c_algo = {
+ .master_xfer = gl861_i2c_xfer,
+ .functionality = gl861_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config gl861_zl10353_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
+{
+
+ adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+ &adap_to_d(adap)->i2c_adap);
+ if (adap->fe[0] == NULL)
+ return -EIO;
+
+ return 0;
+}
+
+static struct qt1010_config gl861_qt1010_config = {
+ .i2c_address = 0x62
+};
+
+static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach,
+ adap->fe[0], &adap_to_d(adap)->i2c_adap,
+ &gl861_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+static int gl861_init(struct dvb_usb_device *d)
+{
+ /*
+ * There is 2 interfaces. Interface 0 is for TV and interface 1 is
+ * for HID remote controller. Interface 0 has 2 alternate settings.
+ * For some reason we need to set interface explicitly, defaulted
+ * as alternate setting 1?
+ */
+ return usb_set_interface(d->udev, 0, 0);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+
+ .i2c_algo = &gl861_i2c_algo,
+ .frontend_attach = gl861_frontend_attach,
+ .tuner_attach = gl861_tuner_attach,
+ .init = gl861_init,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x81, 7, 512),
+ }
+ }
+};
+
+static const struct usb_device_id gl861_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801,
+ &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) },
+ { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU,
+ &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, gl861_id_table);
+
+static struct usb_driver gl861_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = gl861_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(gl861_usb_driver);
+
+MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.h b/drivers/media/usb/dvb-usb-v2/gl861.h
new file mode 100644
index 000000000000..b0b80d87bb7e
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/gl861.h
@@ -0,0 +1,12 @@
+#ifndef _DVB_USB_GL861_H_
+#define _DVB_USB_GL861_H_
+
+#include "dvb_usb.h"
+
+#define GL861_WRITE 0x40
+#define GL861_READ 0xc0
+
+#define GL861_REQ_I2C_WRITE 0x01
+#define GL861_REQ_I2C_READ 0x02
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
new file mode 100644
index 000000000000..695f9106bc54
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -0,0 +1,799 @@
+/*
+ * DVB USB compliant linux driver for ITE IT9135 and IT9137
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9135 (C) ITE Tech Inc.
+ * IT9137 (C) ITE Tech 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.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/dvb/it9137.txt for firmware information
+ *
+ */
+#define DVB_USB_LOG_PREFIX "it913x"
+
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb_usb.h"
+#include "it913x-fe.h"
+
+/* debug */
+static int dvb_usb_it913x_debug;
+#define it_debug(var, level, args...) \
+ do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \
+} while (0)
+#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args)
+#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args)
+
+module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+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=IT9135 V1 3=IT9135 V2");
+#define FW_IT9137 "dvb-usb-it9137-01.fw"
+#define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
+#define FW_IT9135_V2 "dvb-usb-it9135-02.fw"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct it913x_state {
+ struct ite_config it913x_config;
+ u8 pid_filter_onoff;
+ bool proprietary_ir;
+ int cmd_counter;
+};
+
+static u16 check_sum(u8 *p, u8 len)
+{
+ u16 sum = 0;
+ u8 i = 1;
+ while (i < len)
+ sum += (i++ & 1) ? (*p++) << 8 : *p++;
+ return ~sum;
+}
+
+static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro,
+ u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
+{
+ struct it913x_state *st = d->priv;
+ int ret = 0, i, buf_size = 1;
+ u8 *buff;
+ u8 rlen;
+ u16 chk_sum;
+
+ buff = kzalloc(256, GFP_KERNEL);
+ if (!buff) {
+ info("USB Buffer Failed");
+ return -ENOMEM;
+ }
+
+ buff[buf_size++] = pro;
+ buff[buf_size++] = cmd;
+ buff[buf_size++] = st->cmd_counter;
+
+ switch (mode) {
+ case READ_LONG:
+ case WRITE_LONG:
+ buff[buf_size++] = len;
+ buff[buf_size++] = 2;
+ buff[buf_size++] = (reg >> 24);
+ buff[buf_size++] = (reg >> 16) & 0xff;
+ buff[buf_size++] = (reg >> 8) & 0xff;
+ buff[buf_size++] = reg & 0xff;
+ break;
+ case READ_SHORT:
+ buff[buf_size++] = addr;
+ break;
+ case WRITE_SHORT:
+ buff[buf_size++] = len;
+ buff[buf_size++] = addr;
+ buff[buf_size++] = (reg >> 8) & 0xff;
+ buff[buf_size++] = reg & 0xff;
+ break;
+ case READ_DATA:
+ case WRITE_DATA:
+ break;
+ case WRITE_CMD:
+ mode = 7;
+ break;
+ default:
+ kfree(buff);
+ return -EINVAL;
+ }
+
+ if (mode & 1) {
+ for (i = 0; i < len ; i++)
+ buff[buf_size++] = data[i];
+ }
+ chk_sum = check_sum(&buff[1], buf_size);
+
+ buff[buf_size++] = chk_sum >> 8;
+ buff[0] = buf_size;
+ buff[buf_size++] = (chk_sum & 0xff);
+
+ ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ?
+ 5 : len + 5);
+ if (ret < 0)
+ goto error;
+
+ rlen = (mode & 0x1) ? 0x1 : len;
+
+ if (mode & 1)
+ ret = buff[2];
+ else
+ memcpy(data, &buff[3], rlen);
+
+ st->cmd_counter++;
+
+error: kfree(buff);
+
+ return ret;
+}
+
+static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data)
+{
+ int ret;
+ u8 b[1];
+ b[0] = data;
+ ret = it913x_io(d, WRITE_LONG, pro,
+ CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
+
+ return ret;
+}
+
+static int it913x_read_reg(struct dvb_usb_device *d, u32 reg)
+{
+ int ret;
+ u8 data[1];
+
+ ret = it913x_io(d, READ_LONG, DEV_0,
+ CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data));
+
+ return (ret < 0) ? ret : data[0];
+}
+
+static int it913x_query(struct dvb_usb_device *d, u8 pro)
+{
+ struct it913x_state *st = d->priv;
+ int ret, i;
+ u8 data[4];
+ u8 ver;
+
+ for (i = 0; i < 5; i++) {
+ ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ,
+ 0x1222, 0, &data[0], 3);
+ ver = data[0];
+ if (ver > 0 && ver < 3)
+ break;
+ msleep(100);
+ }
+
+ if (ver < 1 || ver > 2) {
+ info("Failed to identify chip version applying 1");
+ st->it913x_config.chip_ver = 0x1;
+ st->it913x_config.chip_type = 0x9135;
+ return 0;
+ }
+
+ st->it913x_config.chip_ver = ver;
+ st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
+
+ info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver,
+ st->it913x_config.chip_type);
+
+ ret = it913x_io(d, READ_SHORT, pro,
+ CMD_QUERYINFO, 0, 0x1, &data[0], 4);
+
+ st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) |
+ (data[2] << 8) | data[3];
+
+ return ret;
+}
+
+static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct it913x_state *st = adap_to_priv(adap);
+ int ret;
+ u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+ mutex_lock(&d->i2c_mutex);
+
+ deb_info(1, "PID_C (%02x)", onoff);
+
+ ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
+
+ mutex_unlock(&d->i2c_mutex);
+ return ret;
+}
+
+static int it913x_pid_filter(struct dvb_usb_adapter *adap,
+ int index, u16 pid, int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct it913x_state *st = adap_to_priv(adap);
+ int ret;
+ u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+ mutex_lock(&d->i2c_mutex);
+
+ deb_info(1, "PID_F (%02x)", onoff);
+
+ ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff));
+
+ ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8));
+
+ ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff);
+
+ ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f));
+
+ if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
+ ret |= it913x_wr_reg(d , pro, PID_EN, !onoff);
+ st->pid_filter_onoff = !onoff;
+ } else
+ st->pid_filter_onoff =
+ adap->pid_filtering;
+
+ mutex_unlock(&d->i2c_mutex);
+ return 0;
+}
+
+
+static int it913x_return_status(struct dvb_usb_device *d)
+{
+ struct it913x_state *st = d->priv;
+ int ret = it913x_query(d, DEV_0);
+ if (st->it913x_config.firmware > 0)
+ info("Firmware Version %d", st->it913x_config.firmware);
+
+ return ret;
+}
+
+static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ static u8 data[256];
+ int ret;
+ u32 reg;
+ u8 pro;
+
+ mutex_lock(&d->i2c_mutex);
+
+ deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
+
+ pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0;
+ pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
+ memcpy(data, msg[0].buf, msg[0].len);
+ reg = (data[0] << 24) + (data[1] << 16) +
+ (data[2] << 8) + data[3];
+ if (num == 2) {
+ ret = it913x_io(d, READ_LONG, pro,
+ CMD_DEMOD_READ, reg, 0, data, msg[1].len);
+ memcpy(msg[1].buf, data, msg[1].len);
+ } else
+ ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE,
+ reg, 0, &data[4], msg[0].len - 4);
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+static u32 it913x_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm it913x_i2c_algo = {
+ .master_xfer = it913x_i2c_xfer,
+ .functionality = it913x_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+#define IT913X_POLL 250
+static int it913x_rc_query(struct dvb_usb_device *d)
+{
+ u8 ibuf[4];
+ int ret;
+ u32 key;
+ /* Avoid conflict with frontends*/
+ mutex_lock(&d->i2c_mutex);
+
+ ret = it913x_io(d, 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] << 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 */
+static const char fw_it9135_v1[] = FW_IT9135_V1;
+static const char fw_it9135_v2[] = FW_IT9135_V2;
+static const char fw_it9137[] = FW_IT9137;
+
+static void ite_get_firmware_name(struct dvb_usb_device *d,
+ const char **name)
+{
+ struct it913x_state *st = d->priv;
+ int sw;
+ /* auto switch */
+ if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2)
+ sw = IT9137_FW;
+ else if (st->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:
+ st->it913x_config.firmware_ver = 1;
+ st->it913x_config.adc_x2 = 1;
+ st->it913x_config.read_slevel = false;
+ *name = fw_it9135_v1;
+ break;
+ case IT9135_V2_FW:
+ st->it913x_config.firmware_ver = 1;
+ st->it913x_config.adc_x2 = 1;
+ st->it913x_config.read_slevel = false;
+ *name = fw_it9135_v2;
+ switch (st->it913x_config.tuner_id_0) {
+ case IT9135_61:
+ case IT9135_62:
+ break;
+ default:
+ info("Unknown tuner ID applying default 0x60");
+ case IT9135_60:
+ st->it913x_config.tuner_id_0 = IT9135_60;
+ }
+ break;
+ case IT9137_FW:
+ default:
+ st->it913x_config.firmware_ver = 0;
+ st->it913x_config.adc_x2 = 0;
+ st->it913x_config.read_slevel = true;
+ *name = fw_it9137;
+ }
+
+ 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_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+ struct usb_data_stream_properties *stream)
+{
+ struct dvb_usb_adapter *adap = fe_to_adap(fe);
+ if (adap->pid_filtering)
+ stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID;
+ else
+ stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX;
+
+ return 0;
+}
+
+static int it913x_select_config(struct dvb_usb_device *d)
+{
+ struct it913x_state *st = d->priv;
+ int ret, reg;
+
+ ret = it913x_return_status(d);
+ if (ret < 0)
+ return ret;
+
+ if (st->it913x_config.chip_ver == 0x02
+ && st->it913x_config.chip_type == 0x9135)
+ reg = it913x_read_reg(d, 0x461d);
+ else
+ reg = it913x_read_reg(d, 0x461b);
+
+ if (reg < 0)
+ return reg;
+
+ if (reg == 0) {
+ st->it913x_config.dual_mode = 0;
+ st->it913x_config.tuner_id_0 = IT9135_38;
+ st->proprietary_ir = true;
+ } else {
+ /* TS mode */
+ reg = it913x_read_reg(d, 0x49c5);
+ if (reg < 0)
+ return reg;
+ st->it913x_config.dual_mode = reg;
+
+ /* IR mode type */
+ reg = it913x_read_reg(d, 0x49ac);
+ if (reg < 0)
+ return reg;
+ if (reg == 5) {
+ info("Remote propriety (raw) mode");
+ st->proprietary_ir = true;
+ } else if (reg == 1) {
+ info("Remote HID mode NOT SUPPORTED");
+ st->proprietary_ir = false;
+ }
+
+ /* Tuner_id */
+ reg = it913x_read_reg(d, 0x49d0);
+ if (reg < 0)
+ return reg;
+ st->it913x_config.tuner_id_0 = reg;
+ }
+
+ info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode,
+ st->it913x_config.tuner_id_0);
+
+ return ret;
+}
+
+static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct dvb_usb_adapter *adap = fe_to_adap(fe);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct it913x_state *st = fe_to_priv(fe);
+ int ret = 0;
+ u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
+
+ deb_info(1, "STM (%02x)", onoff);
+
+ if (!onoff) {
+ mutex_lock(&d->i2c_mutex);
+
+ ret = it913x_wr_reg(d, pro, PID_RST, 0x1);
+
+ mutex_unlock(&d->i2c_mutex);
+ st->pid_filter_onoff =
+ adap->pid_filtering;
+
+ }
+
+ return ret;
+}
+
+static int it913x_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ struct it913x_state *st = d->priv;
+ int ret;
+ u8 reg;
+
+ /* Read and select config */
+ ret = it913x_select_config(d);
+ if (ret < 0)
+ return ret;
+
+ ite_get_firmware_name(d, name);
+
+ if (st->it913x_config.firmware > 0)
+ return WARM;
+
+ if (st->it913x_config.dual_mode) {
+ st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0);
+ ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1);
+ ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1);
+ ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
+ msleep(50);
+ ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0);
+ msleep(50);
+ reg = it913x_read_reg(d, GPIOH1_O);
+ if (reg == 0) {
+ ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
+ ret |= it913x_return_status(d);
+ if (ret != 0)
+ ret = it913x_wr_reg(d, DEV_0,
+ GPIOH1_O, 0x0);
+ }
+ }
+
+ reg = it913x_read_reg(d, IO_MUX_POWER_CLK);
+
+ if (st->it913x_config.dual_mode) {
+ ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
+ if (st->it913x_config.firmware_ver == 1)
+ ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1);
+ else
+ ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1);
+ } else {
+ ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0);
+ if (st->it913x_config.firmware_ver == 1)
+ ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0);
+ else
+ ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0);
+ }
+
+ ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
+
+ return (ret < 0) ? ret : COLD;
+}
+
+static int it913x_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ struct it913x_state *st = d->priv;
+ int ret = 0, i = 0, pos = 0;
+ u8 packet_size, min_pkt;
+ u8 *fw_data;
+
+ ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
+
+ info("FRM Starting Firmware Download");
+
+ /* Multi firmware loader */
+ /* This uses scatter write firmware headers */
+ /* The firmware must start with 03 XX 00 */
+ /* and be the extact firmware length */
+
+ if (st->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(d, 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 (%d)" , ret);
+ else
+ info("FRM Firmware Download Completed - Resetting Device");
+
+ msleep(30);
+
+ ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
+ if (ret < 0)
+ info("FRM Device not responding to reboot");
+
+ ret = it913x_return_status(d);
+ if (st->it913x_config.firmware == 0) {
+ info("FRM Failed to reboot device");
+ return -ENODEV;
+ }
+
+ msleep(30);
+
+ ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400);
+
+ msleep(30);
+
+ /* Tuner function */
+ if (st->it913x_config.dual_mode)
+ ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0);
+ else
+ ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68);
+
+ if ((st->it913x_config.chip_ver == 1) &&
+ (st->it913x_config.chip_type == 0x9135)) {
+ ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0);
+ ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0);
+ if (st->it913x_config.dual_mode) {
+ ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0);
+ ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0);
+ }
+ }
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int it913x_name(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ const char *desc = d->name;
+ char *fe_name[] = {"_1", "_2", "_3", "_4"};
+ char *name = adap->fe[0]->ops.info.name;
+
+ strlcpy(name, desc, 128);
+ strlcat(name, fe_name[adap->id], 128);
+
+ return 0;
+}
+
+static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct it913x_state *st = d->priv;
+ int ret = 0;
+ u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
+ u16 ep_size = adap->stream.buf_size / 4;
+ u8 pkt_size = 0x80;
+
+ if (d->udev->speed != USB_SPEED_HIGH)
+ pkt_size = 0x10;
+
+ st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK);
+
+ adap->fe[0] = dvb_attach(it913x_fe_attach,
+ &d->i2c_adap, adap_addr, &st->it913x_config);
+
+ if (adap->id == 0 && adap->fe[0]) {
+ it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
+ it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f);
+ it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b);
+ it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f);
+ it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB,
+ ep_size & 0xff);
+ it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
+ ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size);
+ } else if (adap->id == 1 && adap->fe[0]) {
+ it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f);
+ it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB,
+ ep_size & 0xff);
+ it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
+ it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1);
+ it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
+ it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
+ it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
+ it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
+ it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
+ ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
+ } else
+ return -ENODEV;
+
+ ret |= it913x_name(adap);
+
+ return ret;
+}
+
+/* DVB USB Driver */
+static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ struct it913x_state *st = d->priv;
+
+ if (st->proprietary_ir == false) {
+ rc->map_name = NULL;
+ return 0;
+ }
+
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = it913x_rc_query;
+ rc->interval = 250;
+
+ return 0;
+}
+
+static int it913x_get_adapter_count(struct dvb_usb_device *d)
+{
+ struct it913x_state *st = d->priv;
+ if (st->it913x_config.dual_mode)
+ return 2;
+ return 1;
+}
+
+static struct dvb_usb_device_properties it913x_properties = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .bInterfaceNumber = 0,
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct it913x_state),
+
+ .identify_state = it913x_identify_state,
+ .i2c_algo = &it913x_i2c_algo,
+
+ .download_firmware = it913x_download_firmware,
+
+ .frontend_attach = it913x_frontend_attach,
+ .get_rc_config = it913x_get_rc_config,
+ .get_stream_config = it913x_get_stream_config,
+ .get_adapter_count = it913x_get_adapter_count,
+ .streaming_ctrl = it913x_streaming_ctrl,
+
+
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = it913x_pid_filter,
+ .pid_filter_ctrl = it913x_pid_filter_ctrl,
+ .stream =
+ DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX),
+ },
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = it913x_pid_filter,
+ .pid_filter_ctrl = it913x_pid_filter_ctrl,
+ .stream =
+ DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX),
+ }
+ }
+};
+
+static const struct usb_device_id it913x_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
+ &it913x_properties, "Kworld UB499-2T T09(IT9137)",
+ RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
+ &it913x_properties, "ITE 9135 Generic",
+ RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
+ &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)",
+ RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
+ &it913x_properties, "ITE 9135(9005) Generic",
+ RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
+ &it913x_properties, "ITE 9135(9006) Generic",
+ RC_MAP_IT913X_V1) },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, it913x_id_table);
+
+static struct usb_driver it913x_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .id_table = it913x_id_table,
+};
+
+module_usb_driver(it913x_driver);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("it913x USB 2 Driver");
+MODULE_VERSION("1.32");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FW_IT9135_V1);
+MODULE_FIRMWARE(FW_IT9135_V2);
+MODULE_FIRMWARE(FW_IT9137);
+
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
new file mode 100644
index 000000000000..c41d9d9ec7b5
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -0,0 +1,1369 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
+ * LME2510C + LG TDQY-P001F
+ * LME2510C + BS2F7HZ0194
+ * LME2510 + LG TDQY-P001F
+ * LME2510 + BS2F7HZ0194
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MV001F (LME2510+LGTDQY-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * MV0194 (LME2510+SHARP:BS2F7HZ0194)
+ * SHARP:BS2F7HZ0194 = (STV0299+IX2410)
+ *
+ * MVB0194 (LME2510C+SHARP0194)
+ *
+ * LME2510C + M88RS2000
+ *
+ * For firmware see Documentation/dvb/lmedm04.txt
+ *
+ * I2C addresses:
+ * 0xd0 - STV0288 - Demodulator
+ * 0xc0 - Sharp IX2505V - Tuner
+ * --
+ * 0x1c - TDA10086 - Demodulator
+ * 0xc0 - TDA8263 - Tuner
+ * --
+ * 0xd0 - STV0299 - Demodulator
+ * 0xc0 - IX2410 - Tuner
+ *
+ *
+ * VID = 3344 PID LME2510=1122 LME2510C=1120
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
+ *
+ * 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.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ * Known Issues :
+ * LME2510: Non Intel USB chipsets fail to maintain High Speed on
+ * Boot or Hot Plug.
+ *
+ * QQbox suffers from noise on LNB voltage.
+ *
+ * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
+ * with other tuners. After a cold reset streaming will not start.
+ *
+ * M88RS2000 suffers from loss of lock.
+ */
+#define DVB_USB_LOG_PREFIX "LME2510(C)"
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb_usb.h"
+#include "lmedm04.h"
+#include "tda826x.h"
+#include "tda10086.h"
+#include "stv0288.h"
+#include "ix2505v.h"
+#include "stv0299.h"
+#include "dvb-pll.h"
+#include "z0194a.h"
+#include "m88rs2000.h"
+
+
+#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw";
+#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw";
+#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw";
+#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw";
+#define LME2510_LG "dvb-usb-lme2510-lg.fw";
+#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw";
+
+/* debug */
+static int dvb_usb_lme2510_debug;
+#define lme_debug(var, level, args...) do { \
+ if ((var >= level)) \
+ pr_debug(DVB_USB_LOG_PREFIX": " args); \
+} while (0)
+#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+ deb_info(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(args...) pr_info(DVB_USB_LOG_PREFIX": "args)
+
+module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+static int dvb_usb_lme2510_firmware;
+module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
+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=default 1=off 2=on");
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define TUNER_DEFAULT 0x0
+#define TUNER_LG 0x1
+#define TUNER_S7395 0x2
+#define TUNER_S0194 0x3
+#define TUNER_RS2000 0x4
+
+struct lme2510_state {
+ u8 id;
+ u8 tuner_config;
+ u8 signal_lock;
+ 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;
+ u8 i2c_tuner_gate_r;
+ u8 i2c_tuner_addr;
+ u8 stream_on;
+ u8 pid_size;
+ u8 pid_off;
+ void *buffer;
+ struct urb *lme_urb;
+ void *usb_buffer;
+ int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t);
+ u8 dvb_usb_lme2510_firmware;
+};
+
+static int lme2510_bulk_write(struct usb_device *dev,
+ u8 *snd, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+ snd, len , &actual_l, 100);
+ return ret;
+}
+
+static int lme2510_bulk_read(struct usb_device *dev,
+ u8 *rev, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+ rev, len , &actual_l, 200);
+ return ret;
+}
+
+static int lme2510_usb_talk(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct lme2510_state *st = d->priv;
+ u8 *buff;
+ int ret = 0;
+
+ if (st->usb_buffer == NULL) {
+ st->usb_buffer = kmalloc(64, GFP_KERNEL);
+ if (st->usb_buffer == NULL) {
+ info("MEM Error no memory");
+ return -ENOMEM;
+ }
+ }
+ buff = st->usb_buffer;
+
+ ret = mutex_lock_interruptible(&d->usb_mutex);
+
+ if (ret < 0)
+ return -EAGAIN;
+
+ /* the read/write capped at 64 */
+ memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
+
+ ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+
+ ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
+ rlen : 64 , 0x01);
+
+ if (rlen > 0)
+ memcpy(rbuf, buff, rlen);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_stream_restart(struct dvb_usb_device *d)
+{
+ struct lme2510_state *st = d->priv;
+ u8 all_pids[] = LME_ALL_PIDS;
+ u8 stream_on[] = LME_ST_ON_W;
+ int ret;
+ 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));
+ return ret;
+}
+
+static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
+{
+ struct lme2510_state *st = d->priv;
+ static u8 pid_buff[] = LME_ZERO_PID;
+ static u8 rbuf[1];
+ u8 pid_no = index * 2;
+ u8 pid_len = pid_no + 2;
+ int ret = 0;
+ deb_info(1, "PID Setting Pid %04x", pid_out);
+
+ if (st->pid_size == 0)
+ ret |= lme2510_stream_restart(d);
+
+ pid_buff[2] = pid_no;
+ pid_buff[3] = (u8)pid_out & 0xff;
+ pid_buff[4] = pid_no + 1;
+ pid_buff[5] = (u8)(pid_out >> 8);
+
+ if (pid_len > st->pid_size)
+ st->pid_size = pid_len;
+ pid_buff[7] = 0x80 + st->pid_size;
+
+ ret |= lme2510_usb_talk(d, pid_buff ,
+ sizeof(pid_buff) , rbuf, sizeof(rbuf));
+
+ if (st->stream_on)
+ ret |= lme2510_stream_restart(d);
+
+ return ret;
+}
+
+static void lme2510_int_response(struct urb *lme_urb)
+{
+ struct dvb_usb_adapter *adap = lme_urb->context;
+ struct lme2510_state *st = adap_to_priv(adap);
+ static u8 *ibuf, *rbuf;
+ int i = 0, offset;
+ u32 key;
+
+ switch (lme_urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ info("Error %x", lme_urb->status);
+ break;
+ }
+
+ rbuf = (u8 *) lme_urb->transfer_buffer;
+
+ offset = ((lme_urb->actual_length/8) > 4)
+ ? 4 : (lme_urb->actual_length/8) ;
+
+ for (i = 0; i < offset; ++i) {
+ ibuf = (u8 *)&rbuf[i*8];
+ deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
+ offset, i, ibuf[0], ibuf[1]);
+
+ switch (ibuf[0]) {
+ case 0xaa:
+ debug_data_snipet(1, "INT Remote data snipet", ibuf);
+ if ((ibuf[4] + ibuf[5]) == 0xff) {
+ key = ibuf[5];
+ key += (ibuf[3] > 0)
+ ? (ibuf[3] ^ 0xff) << 8 : 0;
+ key += (ibuf[2] ^ 0xff) << 16;
+ deb_info(1, "INT Key =%08x", key);
+ if (adap_to_d(adap)->rc_dev != NULL)
+ rc_keydown(adap_to_d(adap)->rc_dev,
+ key, 0);
+ }
+ break;
+ case 0xbb:
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (ibuf[2] > 0)
+ st->signal_lock = ibuf[2];
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[3];
+ st->time_key = ibuf[7];
+ break;
+ case TUNER_S7395:
+ case TUNER_S0194:
+ /* Tweak for earlier firmware*/
+ if (ibuf[1] == 0x03) {
+ if (ibuf[2] > 1)
+ st->signal_lock = ibuf[2];
+ st->signal_level = ibuf[3];
+ st->signal_sn = ibuf[4];
+ } else {
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[5];
+ st->signal_lock =
+ (st->signal_lock & 0xf7) +
+ ((ibuf[2] & 0x01) << 0x03);
+ }
+ break;
+ case TUNER_RS2000:
+ if (ibuf[1] == 0x3 && ibuf[6] == 0xff)
+ st->signal_lock = 0xff;
+ else
+ st->signal_lock = 0x00;
+ st->signal_level = ibuf[5];
+ st->signal_sn = ibuf[4];
+ st->time_key = ibuf[7];
+ default:
+ break;
+ }
+ debug_data_snipet(5, "INT Remote data snipet in", ibuf);
+ break;
+ case 0xcc:
+ debug_data_snipet(1, "INT Control data snipet", ibuf);
+ break;
+ default:
+ debug_data_snipet(1, "INT Unknown data snipet", ibuf);
+ break;
+ }
+ }
+ usb_submit_urb(lme_urb, GFP_ATOMIC);
+}
+
+static int lme2510_int_read(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *lme_int = adap_to_priv(adap);
+
+ lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (lme_int->lme_urb == NULL)
+ return -ENOMEM;
+
+ lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC,
+ &lme_int->lme_urb->transfer_dma);
+
+ if (lme_int->buffer == NULL)
+ return -ENOMEM;
+
+ usb_fill_int_urb(lme_int->lme_urb,
+ d->udev,
+ usb_rcvintpipe(d->udev, 0xa),
+ lme_int->buffer,
+ 128,
+ lme2510_int_response,
+ adap,
+ 8);
+
+ lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
+ info("INT Interrupt Service Started");
+
+ return 0;
+}
+
+static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *st = adap_to_priv(adap);
+ static u8 clear_pid_reg[] = LME_ALL_PIDS;
+ static u8 rbuf[1];
+ int ret = 0;
+
+ deb_info(1, "PID Clearing Filter");
+
+ mutex_lock(&d->i2c_mutex);
+
+ if (!onoff) {
+ ret |= lme2510_usb_talk(d, clear_pid_reg,
+ sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+ st->pid_off = true;
+ } else
+ st->pid_off = false;
+
+ st->pid_size = 0;
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return 0;
+}
+
+static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+
+ deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
+ pid, index, onoff);
+
+ if (onoff) {
+ mutex_lock(&d->i2c_mutex);
+ ret |= lme2510_enable_pid(d, index, pid);
+ mutex_unlock(&d->i2c_mutex);
+ }
+
+
+ return ret;
+}
+
+
+static int lme2510_return_status(struct dvb_usb_device *d)
+{
+ int ret = 0;
+ u8 *data;
+
+ data = kzalloc(10, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+ info("Firmware Status: %x (%x)", ret , data[2]);
+
+ ret = (ret < 0) ? -ENODEV : data[2];
+ kfree(data);
+ return ret;
+}
+
+static int lme2510_msg(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int ret = 0;
+ struct lme2510_state *st = d->priv;
+
+ if (st->i2c_talk_onoff == 1) {
+
+ ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (wbuf[2] == 0x1c) {
+ if (wbuf[3] == 0x0e) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x10)) {
+ lme2510_stream_restart(d);
+ st->i2c_talk_onoff = 0;
+ }
+ msleep(80);
+ }
+ }
+ break;
+ case TUNER_S7395:
+ if (wbuf[2] == 0xd0) {
+ if (wbuf[3] == 0x24) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x8)) {
+ lme2510_stream_restart(d);
+ st->i2c_talk_onoff = 0;
+ }
+ }
+ }
+ break;
+ case TUNER_S0194:
+ if (wbuf[2] == 0xd0) {
+ if (wbuf[3] == 0x1b) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x8)) {
+ lme2510_stream_restart(d);
+ st->i2c_talk_onoff = 0;
+ }
+ }
+ }
+ break;
+ case TUNER_RS2000:
+ default:
+ break;
+ }
+ } else {
+ /* TODO rewrite this section */
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ switch (wbuf[3]) {
+ case 0x0e:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x43:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_level;
+ break;
+ case 0x1c:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
+ }
+ break;
+ case TUNER_S7395:
+ switch (wbuf[3]) {
+ case 0x10:
+ rbuf[0] = 0x55;
+ rbuf[1] = (st->signal_level & 0x80)
+ ? 0 : (st->signal_level * 2);
+ break;
+ case 0x2d:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x24:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x2e:
+ case 0x26:
+ case 0x27:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
+ }
+ break;
+ case TUNER_S0194:
+ switch (wbuf[3]) {
+ case 0x18:
+ rbuf[0] = 0x55;
+ rbuf[1] = (st->signal_level & 0x80)
+ ? 0 : (st->signal_level * 2);
+ break;
+ case 0x24:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x1b:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x19:
+ case 0x25:
+ case 0x1e:
+ case 0x1d:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ 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;
+ }
+
+ deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)",
+ wbuf[3], rbuf[1]);
+
+ }
+
+ return ret;
+}
+
+
+static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct lme2510_state *st = d->priv;
+ static u8 obuf[64], ibuf[64];
+ int i, read, read_o;
+ u16 len;
+ u8 gate = st->i2c_gate;
+
+ mutex_lock(&d->i2c_mutex);
+
+ if (gate == 0)
+ gate = 5;
+
+ for (i = 0; i < num; i++) {
+ read_o = 1 & (msg[i].flags & I2C_M_RD);
+ read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+ read |= read_o;
+ gate = (msg[i].addr == st->i2c_tuner_addr)
+ ? (read) ? st->i2c_tuner_gate_r
+ : st->i2c_tuner_gate_w
+ : st->i2c_gate;
+ obuf[0] = gate | (read << 7);
+
+ if (gate == 5)
+ obuf[1] = (read) ? 2 : msg[i].len + 1;
+ else
+ obuf[1] = msg[i].len + read + 1;
+
+ obuf[2] = msg[i].addr;
+ if (read) {
+ if (read_o)
+ len = 3;
+ else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ obuf[msg[i].len+3] = msg[i+1].len;
+ len = msg[i].len+4;
+ }
+ } else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ len = msg[i].len+3;
+ }
+
+ if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
+ deb_info(1, "i2c transfer failed.");
+ mutex_unlock(&d->i2c_mutex);
+ return -EAGAIN;
+ }
+
+ if (read) {
+ if (read_o)
+ memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+ else {
+ memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+ i++;
+ }
+ }
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm lme2510_i2c_algo = {
+ .master_xfer = lme2510_i2c_xfer,
+ .functionality = lme2510_i2c_func,
+};
+
+static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct dvb_usb_adapter *adap = fe_to_adap(fe);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *st = adap_to_priv(adap);
+ static u8 clear_reg_3[] = LME_ALL_PIDS;
+ static u8 rbuf[1];
+ int ret = 0, rlen = sizeof(rbuf);
+
+ deb_info(1, "STM (%02x)", onoff);
+
+ /* Streaming is started by FE_HAS_LOCK */
+ if (onoff == 1)
+ st->stream_on = 1;
+ else {
+ deb_info(1, "STM Steam Off");
+ /* mutex is here only to avoid collision with I2C */
+ mutex_lock(&d->i2c_mutex);
+
+ ret = lme2510_usb_talk(d, clear_reg_3,
+ sizeof(clear_reg_3), rbuf, rlen);
+ st->stream_on = 0;
+ st->i2c_talk_onoff = 1;
+
+ mutex_unlock(&d->i2c_mutex);
+ }
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static u8 check_sum(u8 *p, u8 len)
+{
+ u8 sum = 0;
+ while (len--)
+ sum += *p++;
+ return sum;
+}
+
+static int lme2510_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ int ret = 0;
+ u8 *data;
+ u16 j, wlen, len_in, start, end;
+ u8 packet_size, dlen, i;
+ u8 *fw_data;
+
+ packet_size = 0x31;
+ len_in = 1;
+
+ data = kzalloc(128, GFP_KERNEL);
+ if (!data) {
+ info("FRM Could not start Firmware Download"\
+ "(Buffer allocation failed)");
+ return -ENOMEM;
+ }
+
+ info("FRM Starting Firmware Download");
+
+ for (i = 1; i < 3; i++) {
+ start = (i == 1) ? 0 : 512;
+ end = (i == 1) ? 512 : fw->size;
+ for (j = start; j < end; j += (packet_size+1)) {
+ fw_data = (u8 *)(fw->data + j);
+ if ((end - j) > packet_size) {
+ data[0] = i;
+ dlen = packet_size;
+ } else {
+ data[0] = i | 0x80;
+ dlen = (u8)(end - j)-1;
+ }
+ data[1] = dlen;
+ memcpy(&data[2], fw_data, dlen+1);
+ wlen = (u8) dlen + 4;
+ data[wlen-1] = check_sum(fw_data, dlen+1);
+ deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+ data[dlen+2], data[dlen+3]);
+ lme2510_usb_talk(d, data, wlen, data, len_in);
+ ret |= (data[0] == 0x88) ? 0 : -1;
+ }
+ }
+
+ data[0] = 0x8a;
+ len_in = 1;
+ msleep(2000);
+ lme2510_usb_talk(d, data, len_in, data, len_in);
+ msleep(400);
+
+ if (ret < 0)
+ info("FRM Firmware Download Failed (%04x)" , ret);
+ else
+ info("FRM Firmware Download Completed - Resetting Device");
+
+ kfree(data);
+ return RECONNECTS_USB;
+}
+
+static void lme_coldreset(struct dvb_usb_device *d)
+{
+ u8 data[1] = {0};
+ data[0] = 0x0a;
+ info("FRM Firmware Cold Reset");
+
+ lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data));
+
+ return;
+}
+
+static const char fw_c_s7395[] = LME2510_C_S7395;
+static const char fw_c_lg[] = LME2510_C_LG;
+static const char fw_c_s0194[] = LME2510_C_S0194;
+static const char fw_c_rs2000[] = LME2510_C_RS2000;
+static const char fw_lg[] = LME2510_LG;
+static const char fw_s0194[] = LME2510_S0194;
+
+const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
+{
+ struct lme2510_state *st = d->priv;
+ struct usb_device *udev = d->udev;
+ const struct firmware *fw = NULL;
+ const char *fw_lme;
+ int ret = 0;
+
+ cold = (cold > 0) ? (cold & 1) : 0;
+
+ switch (le16_to_cpu(udev->descriptor.idProduct)) {
+ case 0x1122:
+ switch (st->dvb_usb_lme2510_firmware) {
+ default:
+ st->dvb_usb_lme2510_firmware = TUNER_S0194;
+ case TUNER_S0194:
+ fw_lme = fw_s0194;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ if (ret == 0) {
+ cold = 0;
+ break;
+ }
+ st->dvb_usb_lme2510_firmware = TUNER_LG;
+ case TUNER_LG:
+ fw_lme = fw_lg;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ if (ret == 0)
+ break;
+ st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+ break;
+ }
+ break;
+ case 0x1120:
+ switch (st->dvb_usb_lme2510_firmware) {
+ default:
+ st->dvb_usb_lme2510_firmware = TUNER_S7395;
+ case TUNER_S7395:
+ fw_lme = fw_c_s7395;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ if (ret == 0) {
+ cold = 0;
+ break;
+ }
+ st->dvb_usb_lme2510_firmware = TUNER_LG;
+ case TUNER_LG:
+ fw_lme = fw_c_lg;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ if (ret == 0)
+ break;
+ st->dvb_usb_lme2510_firmware = TUNER_S0194;
+ case TUNER_S0194:
+ fw_lme = fw_c_s0194;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ if (ret == 0)
+ break;
+ st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+ cold = 0;
+ break;
+ }
+ break;
+ case 0x22f0:
+ fw_lme = fw_c_rs2000;
+ st->dvb_usb_lme2510_firmware = TUNER_RS2000;
+ break;
+ default:
+ fw_lme = fw_c_s7395;
+ }
+
+ release_firmware(fw);
+
+ if (cold) {
+ dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware;
+ info("FRM Changing to %s firmware", fw_lme);
+ lme_coldreset(d);
+ return NULL;
+ }
+
+ return fw_lme;
+}
+
+static int lme2510_kill_urb(struct usb_data_stream *stream)
+{
+ int i;
+
+ for (i = 0; i < stream->urbs_submitted; i++) {
+ deb_info(3, "killing URB no. %d.", i);
+ /* stop the URB */
+ usb_kill_urb(stream->urb_list[i]);
+ }
+ stream->urbs_submitted = 0;
+
+ return 0;
+}
+
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x1c,
+ .invert = 0,
+ .diseqc_tone = 1,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0288_config lme_config = {
+ .demod_address = 0xd0,
+ .min_delay_ms = 15,
+ .inittab = s7395_inittab,
+};
+
+static struct ix2505v_config lme_tuner = {
+ .tuner_address = 0xc0,
+ .min_delay_ms = 100,
+ .tuner_gain = 0x0,
+ .tuner_chargepump = 0x3,
+};
+
+static struct stv0299_config sharp_z0194_config = {
+ .demod_address = 0xd0,
+ .inittab = sharp_z0194a_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .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_to_adap(fe);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ 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)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct lme2510_state *st = fe_to_priv(fe);
+ static u8 voltage_low[] = LME_VOLTAGE_L;
+ static u8 voltage_high[] = LME_VOLTAGE_H;
+ static u8 rbuf[1];
+ int ret = 0, len = 3, rlen = 1;
+
+ mutex_lock(&d->i2c_mutex);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_18:
+ ret |= lme2510_usb_talk(d,
+ voltage_high, len, rbuf, rlen);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ case SEC_VOLTAGE_13:
+ default:
+ ret |= lme2510_usb_talk(d,
+ voltage_low, len, rbuf, rlen);
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ if (st->tuner_config == TUNER_RS2000)
+ if (st->fe_set_voltage)
+ st->fe_set_voltage(fe, voltage);
+
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct lme2510_state *st = fe_to_priv(fe);
+
+ *strength = (u16)((u32)st->signal_level * 0xffff / 0xff);
+
+ return 0;
+}
+
+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lme2510_state *st = fe_to_priv(fe);
+
+ *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f);
+
+ return 0;
+}
+
+static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ *ber = 0;
+
+ return 0;
+}
+
+static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+
+ return 0;
+}
+
+static int lme_name(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *st = adap_to_priv(adap);
+ const char *desc = d->name;
+ char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
+ " SHARP:BS2F7HZ0194", " RS2000"};
+ char *name = adap->fe[0]->ops.info.name;
+
+ strlcpy(name, desc, 128);
+ strlcat(name, fe_name[st->tuner_config], 128);
+
+ return 0;
+}
+
+static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *st = d->priv;
+ int ret = 0;
+
+ st->i2c_talk_onoff = 1;
+ switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
+ case 0x1122:
+ case 0x1120:
+ st->i2c_gate = 4;
+ adap->fe[0] = dvb_attach(tda10086_attach,
+ &tda10086_config, &d->i2c_adap);
+ if (adap->fe[0]) {
+ 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 (st->dvb_usb_lme2510_firmware != TUNER_LG) {
+ st->dvb_usb_lme2510_firmware = TUNER_LG;
+ ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+ }
+ break;
+ }
+
+ st->i2c_gate = 4;
+ adap->fe[0] = dvb_attach(stv0299_attach,
+ &sharp_z0194_config, &d->i2c_adap);
+ if (adap->fe[0]) {
+ 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 (st->dvb_usb_lme2510_firmware != TUNER_S0194) {
+ st->dvb_usb_lme2510_firmware = TUNER_S0194;
+ ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+ }
+ break;
+ }
+
+ st->i2c_gate = 5;
+ adap->fe[0] = dvb_attach(stv0288_attach, &lme_config,
+ &d->i2c_adap);
+
+ if (adap->fe[0]) {
+ 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 (st->dvb_usb_lme2510_firmware != TUNER_S7395) {
+ st->dvb_usb_lme2510_firmware = TUNER_S7395;
+ ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
+ }
+ break;
+ }
+ case 0x22f0:
+ st->i2c_gate = 5;
+ adap->fe[0] = dvb_attach(m88rs2000_attach,
+ &m88rs2000_config, &d->i2c_adap);
+
+ if (adap->fe[0]) {
+ 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;
+ st->fe_set_voltage =
+ adap->fe[0]->ops.set_voltage;
+
+ adap->fe[0]->ops.read_signal_strength =
+ dm04_rs2000_read_signal_strength;
+ adap->fe[0]->ops.read_snr =
+ dm04_rs2000_read_snr;
+ adap->fe[0]->ops.read_ber =
+ dm04_read_ber;
+ adap->fe[0]->ops.read_ucblocks =
+ dm04_read_ucblocks;
+ }
+ break;
+ }
+
+ if (adap->fe[0] == NULL) {
+ info("DM04/QQBOX Not Powered up or not Supported");
+ return -ENODEV;
+ }
+
+ if (ret) {
+ if (adap->fe[0]) {
+ dvb_frontend_detach(adap->fe[0]);
+ adap->fe[0] = NULL;
+ }
+ d->rc_map = NULL;
+ return -ENODEV;
+ }
+
+ adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage;
+ ret = lme_name(adap);
+ return ret;
+}
+
+static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct lme2510_state *st = adap_to_priv(adap);
+ char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
+ int ret = 0;
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0,
+ &d->i2c_adap, 1))
+ ret = st->tuner_config;
+ break;
+ case TUNER_S7395:
+ if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner,
+ &d->i2c_adap))
+ ret = st->tuner_config;
+ break;
+ case TUNER_S0194:
+ if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0,
+ &d->i2c_adap, DVB_PLL_OPERA1))
+ ret = st->tuner_config;
+ break;
+ case TUNER_RS2000:
+ ret = st->tuner_config;
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ info("TUN Found %s tuner", tun_msg[ret]);
+ else {
+ info("TUN No tuner found --- resetting device");
+ lme_coldreset(d);
+ return -ENODEV;
+ }
+
+ /* Start the Interrupt*/
+ ret = lme2510_int_read(adap);
+ if (ret < 0) {
+ info("INT Unable to start Interrupt Service");
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
+{
+ struct lme2510_state *st = d->priv;
+ static u8 lnb_on[] = LNB_ON;
+ static u8 lnb_off[] = LNB_OFF;
+ static u8 rbuf[1];
+ int ret = 0, len = 3, rlen = 1;
+
+ mutex_lock(&d->i2c_mutex);
+
+ if (onoff)
+ ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+ else
+ ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+
+ st->i2c_talk_onoff = 1;
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+static int lme2510_get_adapter_count(struct dvb_usb_device *d)
+{
+ return 1;
+}
+
+static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ struct lme2510_state *st = d->priv;
+
+ usb_reset_configuration(d->udev);
+
+ usb_set_interface(d->udev,
+ d->intf->cur_altsetting->desc.bInterfaceNumber, 1);
+
+ st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
+
+ if (lme2510_return_status(d) == 0x44) {
+ *name = lme_firmware_switch(d, 0);
+ return COLD;
+ }
+
+ return 0;
+}
+
+static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+ struct usb_data_stream_properties *stream)
+{
+ struct dvb_usb_adapter *adap = fe_to_adap(fe);
+ struct dvb_usb_device *d = adap_to_d(adap);
+
+ if (adap == NULL)
+ return 0;
+ /* Turn PID filter on the fly by module option */
+ if (pid_filter == 2) {
+ adap->pid_filtering = 1;
+ adap->max_feed_count = 15;
+ }
+
+ if (!(le16_to_cpu(d->udev->descriptor.idProduct)
+ == 0x1122))
+ stream->endpoint = 0x8;
+
+ return 0;
+}
+
+static int lme2510_get_rc_config(struct dvb_usb_device *d,
+ struct dvb_usb_rc *rc)
+{
+ rc->allowed_protos = RC_TYPE_NEC;
+ return 0;
+}
+
+static void *lme2510_exit_int(struct dvb_usb_device *d)
+{
+ struct lme2510_state *st = d->priv;
+ struct dvb_usb_adapter *adap = &d->adapter[0];
+ void *buffer = NULL;
+
+ if (adap != NULL) {
+ lme2510_kill_urb(&adap->stream);
+ }
+
+ if (st->usb_buffer != NULL) {
+ st->i2c_talk_onoff = 1;
+ st->signal_lock = 0;
+ st->signal_level = 0;
+ st->signal_sn = 0;
+ buffer = st->usb_buffer;
+ }
+
+ if (st->lme_urb != NULL) {
+ usb_kill_urb(st->lme_urb);
+ usb_free_coherent(d->udev, 128, st->buffer,
+ st->lme_urb->transfer_dma);
+ info("Interrupt Service Stopped");
+ }
+
+ return buffer;
+}
+
+static void lme2510_exit(struct dvb_usb_device *d)
+{
+ void *usb_buffer;
+
+ if (d != NULL) {
+ usb_buffer = lme2510_exit_int(d);
+ if (usb_buffer != NULL)
+ kfree(usb_buffer);
+ }
+}
+
+static struct dvb_usb_device_properties lme2510_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .bInterfaceNumber = 0,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct lme2510_state),
+
+ .download_firmware = lme2510_download_firmware,
+
+ .power_ctrl = lme2510_powerup,
+ .identify_state = lme2510_identify_state,
+ .i2c_algo = &lme2510_i2c_algo,
+
+ .frontend_attach = dm04_lme2510_frontend_attach,
+ .tuner_attach = dm04_lme2510_tuner,
+ .get_stream_config = lme2510_get_stream_config,
+ .get_adapter_count = lme2510_get_adapter_count,
+ .streaming_ctrl = lme2510_streaming_ctrl,
+
+ .get_rc_config = lme2510_get_rc_config,
+
+ .exit = lme2510_exit,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 15,
+ .pid_filter = lme2510_pid_filter,
+ .pid_filter_ctrl = lme2510_pid_filter_ctrl,
+ .stream =
+ DVB_USB_STREAM_BULK(0x86, 10, 4096),
+ },
+ {
+ }
+ },
+};
+
+static const struct usb_device_id lme2510_id_table[] = {
+ { DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props,
+ "DM04_LME2510_DVB-S", RC_MAP_LME2510) },
+ { DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props,
+ "DM04_LME2510C_DVB-S", RC_MAP_LME2510) },
+ { DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props,
+ "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510) },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_id_table);
+
+static struct usb_driver lme2510_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .id_table = lme2510_id_table,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(lme2510_driver);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
+MODULE_VERSION("2.06");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(LME2510_C_S7395);
+MODULE_FIRMWARE(LME2510_C_LG);
+MODULE_FIRMWARE(LME2510_C_S0194);
+MODULE_FIRMWARE(LME2510_C_RS2000);
+MODULE_FIRMWARE(LME2510_LG);
+MODULE_FIRMWARE(LME2510_S0194);
+
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/usb/dvb-usb-v2/lmedm04.h
index e9c207205c2f..e9c207205c2f 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.h
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.h
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
index d83df4bb72d3..d83df4bb72d3 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 432706ae5274..432706ae5274 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
index e4121cb8f5ef..e4121cb8f5ef 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
index 0220f54299a5..0220f54299a5 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
index 34434557ef65..34434557ef65 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
index a57a45ffb9e4..a57a45ffb9e4 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
index b741b3a7a325..b741b3a7a325 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
index f0756071d347..f0756071d347 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
index 17831b0fb9db..17831b0fb9db 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
new file mode 100644
index 000000000000..ef4c65fcbb73
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -0,0 +1,527 @@
+/*
+ * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
+ *
+ * Copyright (C) 2010 Michael Krufky <mkrufky@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 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 "mxl111sf-tuner.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-reg.h"
+
+/* debug */
+static int mxl111sf_tuner_debug;
+module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define mxl_dbg(fmt, arg...) \
+ if (mxl111sf_tuner_debug) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define err pr_err
+
+/* ------------------------------------------------------------------------ */
+
+struct mxl111sf_tuner_state {
+ struct mxl111sf_state *mxl_state;
+
+ struct mxl111sf_tuner_config *cfg;
+
+ enum mxl_if_freq if_freq;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
+ u8 addr, u8 *data)
+{
+ return (state->cfg->read_reg) ?
+ state->cfg->read_reg(state->mxl_state, addr, data) :
+ -EINVAL;
+}
+
+static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
+ u8 addr, u8 data)
+{
+ return (state->cfg->write_reg) ?
+ state->cfg->write_reg(state->mxl_state, addr, data) :
+ -EINVAL;
+}
+
+static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
+ struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+ return (state->cfg->program_regs) ?
+ state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
+ -EINVAL;
+}
+
+static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
+ int onoff)
+{
+ return (state->cfg->top_master_ctrl) ?
+ state->cfg->top_master_ctrl(state->mxl_state, onoff) :
+ -EINVAL;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
+ {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
+ DIG_MODEINDEX, _A, _CSF, */
+ {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
+ {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
+ {0, 0, 0}
+};
+
+/* ------------------------------------------------------------------------ */
+
+static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
+ u8 bw)
+{
+ u8 filt_bw;
+
+ /* set channel bandwidth */
+ switch (bw) {
+ case 0: /* ATSC */
+ filt_bw = 25;
+ break;
+ case 1: /* QAM */
+ filt_bw = 69;
+ break;
+ case 6:
+ filt_bw = 21;
+ break;
+ case 7:
+ filt_bw = 42;
+ break;
+ case 8:
+ filt_bw = 63;
+ break;
+ default:
+ err("%s: invalid bandwidth setting!", __func__);
+ return NULL;
+ }
+
+ /* calculate RF channel */
+ freq /= 1000000;
+
+ freq *= 64;
+#if 0
+ /* do round */
+ freq += 0.5;
+#endif
+ /* set bandwidth */
+ mxl_phy_tune_rf[0].data = filt_bw;
+
+ /* set RF */
+ mxl_phy_tune_rf[1].data = (freq & 0xff);
+ mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
+
+ /* start tune */
+ return mxl_phy_tune_rf;
+}
+
+static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
+{
+ int ret;
+ u8 ctrl;
+#if 0
+ u16 iffcw;
+ u32 if_freq;
+#endif
+ mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
+ state->cfg->invert_spectrum, state->cfg->if_freq);
+
+ /* set IF polarity */
+ ctrl = state->cfg->invert_spectrum;
+
+ ctrl |= state->cfg->if_freq;
+
+ ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
+ if (mxl_fail(ret))
+ goto fail;
+
+#if 0
+ if_freq /= 1000000;
+
+ /* do round */
+ if_freq += 0.5;
+
+ if (MXL_IF_LO == state->cfg->if_freq) {
+ ctrl = 0x08;
+ iffcw = (u16)(if_freq / (108 * 4096));
+ } else if (MXL_IF_HI == state->cfg->if_freq) {
+ ctrl = 0x08;
+ iffcw = (u16)(if_freq / (216 * 4096));
+ } else {
+ ctrl = 0;
+ iffcw = 0;
+ }
+
+ ctrl |= (iffcw >> 8);
+#endif
+ ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ctrl &= 0xf0;
+ ctrl |= 0x90;
+
+ ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
+ if (mxl_fail(ret))
+ goto fail;
+
+#if 0
+ ctrl = iffcw & 0x00ff;
+#endif
+ ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
+ if (mxl_fail(ret))
+ goto fail;
+
+ state->if_freq = state->cfg->if_freq;
+fail:
+ return ret;
+}
+
+static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
+ int ret;
+ u8 mxl_mode;
+
+ mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
+
+ /* stop tune */
+ ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
+ if (mxl_fail(ret))
+ goto fail;
+
+ /* check device mode */
+ ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ /* Fill out registers for channel tune */
+ reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
+ if (!reg_ctrl_array)
+ return -EINVAL;
+
+ ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
+ if (mxl_fail(ret))
+ goto fail;
+
+ if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
+ /* IF tuner mode only */
+ mxl1x1sf_tuner_top_master_ctrl(state, 0);
+ mxl1x1sf_tuner_top_master_ctrl(state, 1);
+ mxl1x1sf_tuner_set_if_output_freq(state);
+ }
+
+ ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ if (state->cfg->ant_hunt)
+ state->cfg->ant_hunt(fe);
+fail:
+ return ret;
+}
+
+static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
+ int *rf_synth_lock,
+ int *ref_synth_lock)
+{
+ int ret;
+ u8 data;
+
+ *rf_synth_lock = 0;
+ *ref_synth_lock = 0;
+
+ ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
+ if (mxl_fail(ret))
+ goto fail;
+
+ *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
+ *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0;
+fail:
+ return ret;
+}
+
+#if 0
+static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
+ int onoff)
+{
+ return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
+ onoff ? 1 : 0);
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+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("()");
+
+ switch (delsys) {
+ case SYS_ATSC:
+ case SYS_ATSCMH:
+ 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 7000000:
+ bw = 7;
+ break;
+ case 8000000:
+ bw = 8;
+ break;
+ default:
+ err("%s: bandwidth not set!", __func__);
+ return -EINVAL;
+ }
+ break;
+ default:
+ err("%s: modulation type not supported!", __func__);
+ return -EINVAL;
+ }
+ ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
+ if (mxl_fail(ret))
+ goto fail;
+
+ state->frequency = c->frequency;
+ state->bandwidth = c->bandwidth_hz;
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int mxl111sf_tuner_init(struct dvb_frontend *fe)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ int ret;
+
+ /* wake from standby handled by usb driver */
+
+ return ret;
+}
+
+static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ int ret;
+
+ /* enter standby mode handled by usb driver */
+
+ return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ int rf_locked, ref_locked, ret;
+
+ *status = 0;
+
+ ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
+ if (mxl_fail(ret))
+ goto fail;
+ mxl_info("%s%s", rf_locked ? "rf locked " : "",
+ ref_locked ? "ref locked" : "");
+
+ if ((rf_locked) || (ref_locked))
+ *status |= TUNER_STATUS_LOCKED;
+fail:
+ return ret;
+}
+
+static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ u8 val1, val2;
+ int ret;
+
+ *strength = 0;
+
+ ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
+ if (mxl_fail(ret))
+ goto fail;
+
+ *strength = val1 | ((val2 & 0x07) << 8);
+fail:
+ ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
+ mxl_fail(ret);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ *frequency = state->frequency;
+ return 0;
+}
+
+static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+ *bandwidth = state->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;
+ mxl_dbg("()");
+ kfree(state);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
+ .info = {
+ .name = "MaxLinear MxL111SF",
+#if 0
+ .frequency_min = ,
+ .frequency_max = ,
+ .frequency_step = ,
+#endif
+ },
+#if 0
+ .init = mxl111sf_tuner_init,
+ .sleep = mxl111sf_tuner_sleep,
+#endif
+ .set_params = mxl111sf_tuner_set_params,
+ .get_status = mxl111sf_tuner_get_status,
+ .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,
+};
+
+struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
+ struct mxl111sf_state *mxl_state,
+ struct mxl111sf_tuner_config *cfg)
+{
+ struct mxl111sf_tuner_state *state = NULL;
+
+ mxl_dbg("()");
+
+ state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->mxl_state = mxl_state;
+ state->cfg = cfg;
+
+ memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+ return fe;
+}
+EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
+
+MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index ff333960b184..ff333960b184 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
new file mode 100644
index 000000000000..efdcb15358f1
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -0,0 +1,1431 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/i2c.h>
+
+#include "mxl111sf.h"
+#include "mxl111sf-reg.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf-gpio.h"
+
+#include "mxl111sf-demod.h"
+#include "mxl111sf-tuner.h"
+
+#include "lgdt3305.h"
+#include "lg2160.h"
+
+int dvb_usb_mxl111sf_debug;
+module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level "
+ "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
+
+int dvb_usb_mxl111sf_isoc;
+module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
+MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
+
+int dvb_usb_mxl111sf_spi;
+module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
+MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
+
+#define ANT_PATH_AUTO 0
+#define ANT_PATH_EXTERNAL 1
+#define ANT_PATH_INTERNAL 2
+
+int dvb_usb_mxl111sf_rfswitch =
+#if 0
+ ANT_PATH_AUTO;
+#else
+ ANT_PATH_EXTERNAL;
+#endif
+
+module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
+MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info pr_debug
+#define deb_reg pr_debug
+#define deb_adv pr_debug
+#define err pr_err
+#define info pr_info
+
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ int ret;
+ u8 sndbuf[1+wlen];
+
+ deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+
+ memset(sndbuf, 0, 1+wlen);
+
+ sndbuf[0] = cmd;
+ memcpy(&sndbuf[1], wbuf, wlen);
+
+ ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) :
+ dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen);
+ mxl_fail(ret);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define MXL_CMD_REG_READ 0xaa
+#define MXL_CMD_REG_WRITE 0x55
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
+{
+ u8 buf[2];
+ int ret;
+
+ ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
+ if (mxl_fail(ret)) {
+ mxl_debug("error reading reg: 0x%02x", addr);
+ goto fail;
+ }
+
+ if (buf[0] == addr)
+ *data = buf[1];
+ else {
+ err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+ addr, buf[0], buf[1]);
+ ret = -EINVAL;
+ }
+
+ deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+fail:
+ return ret;
+}
+
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
+{
+ u8 buf[] = { addr, data };
+ int ret;
+
+ deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+
+ ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
+ if (mxl_fail(ret))
+ err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+ u8 addr, u8 mask, u8 data)
+{
+ int ret;
+ u8 val;
+
+ if (mask != 0xff) {
+ ret = mxl111sf_read_reg(state, addr, &val);
+#if 1
+ /* dont know why this usually errors out on the first try */
+ if (mxl_fail(ret))
+ err("error writing addr: 0x%02x, mask: 0x%02x, "
+ "data: 0x%02x, retrying...", addr, mask, data);
+
+ ret = mxl111sf_read_reg(state, addr, &val);
+#endif
+ if (mxl_fail(ret))
+ goto fail;
+ }
+ val &= ~mask;
+ val |= data;
+
+ ret = mxl111sf_write_reg(state, addr, val);
+ mxl_fail(ret);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+ struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+ int i, ret = 0;
+
+ for (i = 0; ctrl_reg_info[i].addr |
+ ctrl_reg_info[i].mask |
+ ctrl_reg_info[i].data; i++) {
+
+ ret = mxl111sf_write_reg_mask(state,
+ ctrl_reg_info[i].addr,
+ ctrl_reg_info[i].mask,
+ ctrl_reg_info[i].data);
+ if (mxl_fail(ret)) {
+ err("failed on reg #%d (0x%02x)", i,
+ ctrl_reg_info[i].addr);
+ break;
+ }
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
+{
+ int ret;
+ u8 id, ver;
+ char *mxl_chip, *mxl_rev;
+
+ if ((state->chip_id) && (state->chip_ver))
+ return 0;
+
+ ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
+ if (mxl_fail(ret))
+ goto fail;
+ state->chip_id = id;
+
+ ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
+ if (mxl_fail(ret))
+ goto fail;
+ state->chip_ver = ver;
+
+ switch (id) {
+ case 0x61:
+ mxl_chip = "MxL101SF";
+ break;
+ case 0x63:
+ mxl_chip = "MxL111SF";
+ break;
+ default:
+ mxl_chip = "UNKNOWN MxL1X1";
+ break;
+ }
+ switch (ver) {
+ case 0x36:
+ state->chip_rev = MXL111SF_V6;
+ mxl_rev = "v6";
+ break;
+ case 0x08:
+ state->chip_rev = MXL111SF_V8_100;
+ mxl_rev = "v8_100";
+ break;
+ case 0x18:
+ state->chip_rev = MXL111SF_V8_200;
+ mxl_rev = "v8_200";
+ break;
+ default:
+ state->chip_rev = 0;
+ mxl_rev = "UNKNOWN REVISION";
+ break;
+ }
+ info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+fail:
+ return ret;
+}
+
+#define get_chip_info(state) \
+({ \
+ int ___ret; \
+ ___ret = mxl1x1sf_get_chip_info(state); \
+ if (mxl_fail(___ret)) { \
+ mxl_debug("failed to get chip info" \
+ " on first probe attempt"); \
+ ___ret = mxl1x1sf_get_chip_info(state); \
+ if (mxl_fail(___ret)) \
+ err("failed to get chip info during probe"); \
+ else \
+ mxl_debug("probe needed a retry " \
+ "in order to succeed."); \
+ } \
+ ___ret; \
+})
+
+/* ------------------------------------------------------------------------ */
+#if 0
+static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ /* power control depends on which adapter is being woken:
+ * save this for init, instead, via mxl111sf_adap_fe_init */
+ return 0;
+}
+#endif
+
+static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+ int err;
+
+ /* exit if we didnt initialize the driver yet */
+ if (!state->chip_id) {
+ mxl_debug("driver not yet initialized, exit.");
+ goto fail;
+ }
+
+ deb_info("%s()\n", __func__);
+
+ mutex_lock(&state->fe_lock);
+
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ err = mxl1x1sf_soft_reset(state);
+ mxl_fail(err);
+ err = mxl111sf_init_tuner_demod(state);
+ mxl_fail(err);
+ err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+
+ mxl_fail(err);
+ mxl111sf_enable_usb_output(state);
+ mxl_fail(err);
+ mxl1x1sf_top_master_ctrl(state, 1);
+ mxl_fail(err);
+
+ if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
+ (state->chip_rev > MXL111SF_V6)) {
+ mxl111sf_config_pin_mux_modes(state,
+ PIN_MUX_TS_SPI_IN_MODE_1);
+ mxl_fail(err);
+ }
+ err = mxl111sf_init_port_expander(state);
+ if (!mxl_fail(err)) {
+ state->gpio_mode = adap_state->gpio_mode;
+ err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ mxl_fail(err);
+#if 0
+ err = fe->ops.init(fe);
+#endif
+ msleep(100); /* add short delay after enabling
+ * the demod before touching it */
+ }
+
+ return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
+fail:
+ return -ENODEV;
+}
+
+static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
+{
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+ int err;
+
+ /* exit if we didnt initialize the driver yet */
+ if (!state->chip_id) {
+ mxl_debug("driver not yet initialized, exit.");
+ goto fail;
+ }
+
+ deb_info("%s()\n", __func__);
+
+ err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
+
+ mutex_unlock(&state->fe_lock);
+
+ return err;
+fail:
+ return -ENODEV;
+}
+
+
+static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+ int ret = 0;
+
+ deb_info("%s(%d)\n", __func__, onoff);
+
+ if (onoff) {
+ ret = mxl111sf_enable_usb_output(state);
+ mxl_fail(ret);
+ ret = mxl111sf_config_mpeg_in(state, 1, 1,
+ adap_state->ep6_clockphase,
+ 0, 0);
+ mxl_fail(ret);
+#if 0
+ } else {
+ ret = mxl111sf_disable_656_port(state);
+ mxl_fail(ret);
+#endif
+ }
+
+ return ret;
+}
+
+static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ int ret = 0;
+
+ deb_info("%s(%d)\n", __func__, onoff);
+
+ if (onoff) {
+ ret = mxl111sf_enable_usb_output(state);
+ mxl_fail(ret);
+
+ ret = mxl111sf_init_i2s_port(state, 200);
+ mxl_fail(ret);
+ ret = mxl111sf_config_i2s(state, 0, 15);
+ mxl_fail(ret);
+ } else {
+ ret = mxl111sf_disable_i2s_port(state);
+ mxl_fail(ret);
+ }
+ if (state->chip_rev > MXL111SF_V6)
+ ret = mxl111sf_config_spi(state, onoff);
+ mxl_fail(ret);
+
+ return ret;
+}
+
+static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ int ret = 0;
+
+ deb_info("%s(%d)\n", __func__, onoff);
+
+ if (onoff) {
+ ret = mxl111sf_enable_usb_output(state);
+ mxl_fail(ret);
+ }
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+ .i2c_addr = 0xb2 >> 1,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .qam_if_khz = 6000,
+ .vsb_if_khz = 6000,
+};
+
+static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct mxl111sf_state *state = d_to_priv(d);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe[fe_id] = dvb_attach(lgdt3305_attach,
+ &hauppauge_lgdt3305_config,
+ &d->i2c_adap);
+ if (adap->fe[fe_id]) {
+ state->num_frontends++;
+ adap_state->fe_init = adap->fe[fe_id]->ops.init;
+ adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+ adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct lg2160_config hauppauge_lg2160_config = {
+ .lg_chip = LG2160,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+};
+
+static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct mxl111sf_state *state = d_to_priv(d);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe[fe_id] = dvb_attach(lg2160_attach,
+ &hauppauge_lg2160_config,
+ &d->i2c_adap);
+ if (adap->fe[fe_id]) {
+ state->num_frontends++;
+ adap_state->fe_init = adap->fe[fe_id]->ops.init;
+ adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+ adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_config = {
+ .lg_chip = LG2161_1019,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 2, /* LG2161_OIF_SPI_MAS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_config = {
+ .lg_chip = LG2161_1040,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 4, /* LG2161_OIF_SPI_MAS */
+};
+
+static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct mxl111sf_state *state = d_to_priv(d);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe[fe_id] = dvb_attach(lg2160_attach,
+ (MXL111SF_V8_200 == state->chip_rev) ?
+ &hauppauge_lg2161_1040_config :
+ &hauppauge_lg2161_1019_config,
+ &d->i2c_adap);
+ if (adap->fe[fe_id]) {
+ state->num_frontends++;
+ adap_state->fe_init = adap->fe[fe_id]->ops.init;
+ adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+ adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
+ .lg_chip = LG2161_1019,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 1, /* LG2161_OIF_SERIAL_TS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
+ .lg_chip = LG2161_1040,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 7, /* LG2161_OIF_SERIAL_TS */
+};
+
+static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct mxl111sf_state *state = d_to_priv(d);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 0;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe[fe_id] = dvb_attach(lg2160_attach,
+ (MXL111SF_V8_200 == state->chip_rev) ?
+ &hauppauge_lg2161_1040_ep6_config :
+ &hauppauge_lg2161_1019_ep6_config,
+ &d->i2c_adap);
+ if (adap->fe[fe_id]) {
+ state->num_frontends++;
+ adap_state->fe_init = adap->fe[fe_id]->ops.init;
+ adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+ adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct mxl111sf_demod_config mxl_demod_config = {
+ .read_reg = mxl111sf_read_reg,
+ .write_reg = mxl111sf_write_reg,
+ .program_regs = mxl111sf_ctrl_program_regs,
+};
+
+static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct mxl111sf_state *state = d_to_priv(d);
+ struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_SOC_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ /* dont care if this fails */
+ mxl111sf_init_port_expander(state);
+
+ adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state,
+ &mxl_demod_config);
+ if (adap->fe[fe_id]) {
+ state->num_frontends++;
+ adap_state->fe_init = adap->fe[fe_id]->ops.init;
+ adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+ adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
+ int antpath)
+{
+ return mxl111sf_idac_config(state, 1, 1,
+ (antpath == ANT_PATH_INTERNAL) ?
+ 0x3f : 0x00, 0);
+}
+
+#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
+ err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+ __func__, __LINE__, \
+ (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
+ pwr0, pwr1, pwr2, pwr3)
+
+#define ANT_HUNT_SLEEP 90
+#define ANT_EXT_TWEAK 0
+
+static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
+{
+ struct mxl111sf_state *state = fe_to_priv(fe);
+ int antctrl = dvb_usb_mxl111sf_rfswitch;
+
+ u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
+
+ /* FIXME: must force EXTERNAL for QAM - done elsewhere */
+ mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
+ ANT_PATH_EXTERNAL : antctrl);
+
+ if (antctrl == ANT_PATH_AUTO) {
+#if 0
+ msleep(ANT_HUNT_SLEEP);
+#endif
+ fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
+
+ mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+ msleep(ANT_HUNT_SLEEP);
+ fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
+
+ mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+ msleep(ANT_HUNT_SLEEP);
+ fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
+
+ mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
+ msleep(ANT_HUNT_SLEEP);
+ fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
+
+ if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
+ /* return with EXTERNAL enabled */
+ mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+ DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
+ rxPwr0, rxPwr1, rxPwr2);
+ } else {
+ /* return with INTERNAL enabled */
+ DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
+ rxPwr0, rxPwr1, rxPwr2);
+ }
+ }
+ return 0;
+}
+
+static struct mxl111sf_tuner_config mxl_tuner_config = {
+ .if_freq = MXL_IF_6_0, /* applies to external IF output, only */
+ .invert_spectrum = 0,
+ .read_reg = mxl111sf_read_reg,
+ .write_reg = mxl111sf_write_reg,
+ .program_regs = mxl111sf_ctrl_program_regs,
+ .top_master_ctrl = mxl1x1sf_top_master_ctrl,
+ .ant_hunt = mxl111sf_ant_hunt,
+};
+
+static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
+{
+ struct mxl111sf_state *state = adap_to_priv(adap);
+ int i;
+
+ deb_adv("%s()\n", __func__);
+
+ for (i = 0; i < state->num_frontends; i++) {
+ if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state,
+ &mxl_tuner_config) == NULL)
+ return -EIO;
+ adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength;
+ }
+
+ return 0;
+}
+
+static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm mxl111sf_i2c_algo = {
+ .master_xfer = mxl111sf_i2c_xfer,
+ .functionality = mxl111sf_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
+};
+
+static int mxl111sf_init(struct dvb_usb_device *d)
+{
+ struct mxl111sf_state *state = d_to_priv(d);
+ int ret;
+ static u8 eeprom[256];
+ struct i2c_client c;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ err("failed to get chip info during probe");
+
+ mutex_init(&state->fe_lock);
+
+ if (state->chip_rev > MXL111SF_V6)
+ mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1);
+
+ c.adapter = &d->i2c_adap;
+ c.addr = 0xa0 >> 1;
+
+ ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
+ if (mxl_fail(ret))
+ return 0;
+ tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ?
+ eeprom + 0xa0 : eeprom + 0x80);
+#if 0
+ switch (state->tv.model) {
+ case 117001:
+ case 126001:
+ case 138001:
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n",
+ __func__, state->tv.model);
+ }
+#endif
+ return 0;
+}
+
+static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap)
+{
+ return mxl111sf_attach_demod(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap)
+{
+ return mxl111sf_lgdt3305_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap)
+{
+ return mxl111sf_lg2160_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ deb_info("%s\n", __func__);
+
+ ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = mxl111sf_attach_demod(adap, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mxl111sf_lg2160_frontend_attach(adap, 2);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ deb_info("%s\n", __func__);
+
+ ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = mxl111sf_attach_demod(adap, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ deb_info("%s\n", __func__);
+
+ ret = mxl111sf_attach_demod(adap, 0);
+ if (ret < 0)
+ return ret;
+
+ if (dvb_usb_mxl111sf_spi)
+ ret = mxl111sf_lg2161_frontend_attach(adap, 1);
+ else
+ ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1);
+
+ return ret;
+}
+
+static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint)
+{
+ deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint);
+ stream->type = USB_BULK;
+ stream->count = 5;
+ stream->endpoint = endpoint;
+ stream->u.bulk.buffersize = 8192;
+}
+
+static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream,
+ u8 endpoint, int framesperurb, int framesize)
+{
+ deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint,
+ framesperurb * framesize);
+ stream->type = USB_ISOC;
+ stream->count = 5;
+ stream->endpoint = endpoint;
+ stream->u.isoc.framesperurb = framesperurb;
+ stream->u.isoc.framesize = framesize;
+ stream->u.isoc.interval = 1;
+}
+
+/* DVB USB Driver stuff */
+
+/* dvbt mxl111sf
+ * bulk EP4/BULK/5/8192
+ * isoc EP4/ISOC/5/96/564
+ */
+static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+ else
+ mxl111sf_stream_config_bulk(stream, 4);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_dvbt,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_ep4_streaming_ctrl,
+ .get_stream_config = mxl111sf_get_stream_config_dvbt,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+/* atsc lgdt3305
+ * bulk EP6/BULK/5/8192
+ * isoc EP6/ISOC/5/24/3072
+ */
+static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+ else
+ mxl111sf_stream_config_bulk(stream, 6);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_atsc,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,
+ .get_stream_config = mxl111sf_get_stream_config_atsc,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+/* mh lg2160
+ * bulk EP5/BULK/5/8192/RAW
+ * isoc EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+ else
+ mxl111sf_stream_config_bulk(stream, 5);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mh = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_mh,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_ep5_streaming_ctrl,
+ .get_stream_config = mxl111sf_get_stream_config_mh,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+/* atsc mh lgdt3305 mxl111sf lg2160
+ * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW
+ * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ if (fe->id == 0) {
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+ else
+ mxl111sf_stream_config_bulk(stream, 6);
+ } else if (fe->id == 1) {
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+ else
+ mxl111sf_stream_config_bulk(stream, 4);
+ } else if (fe->id == 2) {
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+ else
+ mxl111sf_stream_config_bulk(stream, 5);
+ }
+ return 0;
+}
+
+static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff)
+{
+ deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+ if (fe->id == 0)
+ return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+ else if (fe->id == 1)
+ return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+ else if (fe->id == 2)
+ return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_atsc_mh,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh,
+ .get_stream_config = mxl111sf_get_stream_config_atsc_mh,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+/* mercury lgdt3305 mxl111sf lg2161
+ * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW
+ * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW
+ * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ if (fe->id == 0) {
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+ else
+ mxl111sf_stream_config_bulk(stream, 6);
+ } else if (fe->id == 1) {
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+ else
+ mxl111sf_stream_config_bulk(stream, 4);
+ } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) {
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+ else
+ mxl111sf_stream_config_bulk(stream, 5);
+ } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) {
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+ else
+ mxl111sf_stream_config_bulk(stream, 6);
+ }
+ return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff)
+{
+ deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+ if (fe->id == 0)
+ return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+ else if (fe->id == 1)
+ return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+ else if (fe->id == 2 && dvb_usb_mxl111sf_spi)
+ return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+ else if (fe->id == 2 && !dvb_usb_mxl111sf_spi)
+ return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_mercury,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_streaming_ctrl_mercury,
+ .get_stream_config = mxl111sf_get_stream_config_mercury,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+/* mercury mh mxl111sf lg2161
+ * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW
+ * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW
+ * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
+ u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+ deb_info("%s: fe=%d\n", __func__, fe->id);
+
+ if (fe->id == 0) {
+ *ts_type = DVB_USB_FE_TS_TYPE_188;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+ else
+ mxl111sf_stream_config_bulk(stream, 4);
+ } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) {
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+ else
+ mxl111sf_stream_config_bulk(stream, 5);
+ } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) {
+ *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+ if (dvb_usb_mxl111sf_isoc)
+ mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+ else
+ mxl111sf_stream_config_bulk(stream, 6);
+ }
+ return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff)
+{
+ deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+ if (fe->id == 0)
+ return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+ else if (fe->id == 1 && dvb_usb_mxl111sf_spi)
+ return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+ else if (fe->id == 1 && !dvb_usb_mxl111sf_spi)
+ return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+ return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct mxl111sf_state),
+
+ .generic_bulk_ctrl_endpoint = 0x02,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .i2c_algo = &mxl111sf_i2c_algo,
+ .frontend_attach = mxl111sf_frontend_attach_mercury_mh,
+ .tuner_attach = mxl111sf_attach_tuner,
+ .init = mxl111sf_init,
+ .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh,
+ .get_stream_config = mxl111sf_get_stream_config_mercury_mh,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+ }
+ }
+};
+
+static const struct usb_device_id mxl111sf_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, mxl111sf_id_table);
+
+static struct usb_driver mxl111sf_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mxl111sf_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(mxl111sf_usb_driver);
+
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
new file mode 100644
index 000000000000..9816de86e48c
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#ifndef _DVB_USB_MXL111SF_H_
+#define _DVB_USB_MXL111SF_H_
+
+#ifdef DVB_USB_LOG_PREFIX
+#undef DVB_USB_LOG_PREFIX
+#endif
+#define DVB_USB_LOG_PREFIX "mxl111sf"
+#include "dvb_usb.h"
+#include <media/tveeprom.h>
+
+#define MXL_EP1_REG_READ 1
+#define MXL_EP2_REG_WRITE 2
+#define MXL_EP3_INTERRUPT 3
+#define MXL_EP4_MPEG2 4
+#define MXL_EP5_I2S 5
+#define MXL_EP6_656 6
+#define MXL_EP6_MPEG2 6
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+enum mxl111sf_current_mode {
+ mxl_mode_dvbt = MXL_EP4_MPEG2,
+ mxl_mode_mh = MXL_EP5_I2S,
+ mxl_mode_atsc = MXL_EP6_MPEG2,
+};
+#endif
+
+enum mxl111sf_gpio_port_expander {
+ mxl111sf_gpio_hw,
+ mxl111sf_PCA9534,
+};
+
+struct mxl111sf_adap_state {
+ int alt_mode;
+ int gpio_mode;
+ int device_mode;
+ int ep6_clockphase;
+ int (*fe_init)(struct dvb_frontend *);
+ int (*fe_sleep)(struct dvb_frontend *);
+};
+
+struct mxl111sf_state {
+ struct dvb_usb_device *d;
+
+ enum mxl111sf_gpio_port_expander gpio_port_expander;
+ u8 port_expander_addr;
+
+ u8 chip_id;
+ u8 chip_ver;
+#define MXL111SF_V6 1
+#define MXL111SF_V8_100 2
+#define MXL111SF_V8_200 3
+ u8 chip_rev;
+
+#ifdef USING_ENUM_mxl111sf_current_mode
+ enum mxl111sf_current_mode current_mode;
+#endif
+
+#define MXL_TUNER_MODE 0
+#define MXL_SOC_MODE 1
+#define MXL_DEV_MODE_MASK 0x01
+#if 1
+ int device_mode;
+#endif
+ /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t),
+ EP5 BULK transfer (atsc-mh),
+ EP6 BULK transfer (atsc/qam),
+ use usb alt setting 2 for EP4 BULK transfer (dvb-t),
+ EP5 ISOC transfer (atsc-mh),
+ EP6 ISOC transfer (atsc/qam),
+ */
+ int alt_mode;
+ int gpio_mode;
+ struct tveeprom tv;
+
+ struct mutex fe_lock;
+ u8 num_frontends;
+ struct mxl111sf_adap_state adap_state[3];
+};
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data);
+
+struct mxl111sf_reg_ctrl_info {
+ u8 addr;
+ u8 mask;
+ u8 data;
+};
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+ u8 addr, u8 mask, u8 data);
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+ struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
+
+/* needed for hardware i2c functions in mxl111sf-i2c.c:
+ * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen);
+
+#define mxl_printk(kern, fmt, arg...) \
+ printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define mxl_info(fmt, arg...) \
+ mxl_printk(KERN_INFO, fmt, ##arg)
+
+extern int dvb_usb_mxl111sf_debug;
+#define mxl_debug(fmt, arg...) \
+ if (dvb_usb_mxl111sf_debug) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define MXL_I2C_DBG 0x04
+#define MXL_ADV_DBG 0x10
+#define mxl_debug_adv(fmt, arg...) \
+ if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c(fmt, arg...) \
+ if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+#define mxl_i2c_adv(fmt, arg...) \
+ if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \
+ (MXL_I2C_DBG | MXL_ADV_DBG)) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg)
+
+/* The following allows the mxl_fail() macro defined below to work
+ * in externel modules, such as mxl111sf-tuner.ko, even though
+ * dvb_usb_mxl111sf_debug is not defined within those modules */
+#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
+#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
+#else
+#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
+#endif
+
+#define mxl_fail(ret) \
+({ \
+ int __ret; \
+ __ret = (ret < 0); \
+ if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \
+ mxl_printk(KERN_ERR, "error %d on line %d", \
+ ret, __LINE__); \
+ __ret; \
+})
+
+#endif /* _DVB_USB_MXL111SF_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
new file mode 100644
index 000000000000..d2b1505b36f9
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -0,0 +1,1260 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl28xxu.h"
+
+#include "rtl2830.h"
+#include "rtl2832.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+#include "fc0012.h"
+#include "fc0013.h"
+
+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);
+
+ /* 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:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl28xx_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 rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+ return rtl28xx_wr_regs(d, reg, &val, 1);
+}
+
+static int rtl28xx_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 dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_priv *priv = d_to_priv(d);
+ 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 };
+
+ dev_dbg(&d->udev->dev, "%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 = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a);
+ if (ret)
+ goto err;
+
+ /* enable as output GPIO0, GPIO2, GPIO4 */
+ ret = rtl28xx_wr_reg(d, 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.
+ */
+
+ /* demod needs some time to wake up */
+ msleep(20);
+
+ /* open demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(d, &req_gate);
+ if (ret)
+ goto err;
+
+ /* check QT1010 ID(?) register; reg=0f val=2c */
+ ret = rtl28xxu_ctrl_msg(d, &req_qt1010);
+ if (ret == 0 && buf[0] == 0x2c) {
+ priv->tuner = TUNER_RTL2830_QT1010;
+ rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+ dev_dbg(&d->udev->dev, "%s: QT1010\n", __func__);
+ goto found;
+ } else {
+ dev_dbg(&d->udev->dev, "%s: QT1010 probe failed=%d - %02x\n",
+ __func__, ret, buf[0]);
+ }
+
+ /* open demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(d, &req_gate);
+ if (ret)
+ goto err;
+
+ /* check MT2060 ID register; reg=00 val=63 */
+ ret = rtl28xxu_ctrl_msg(d, &req_mt2060);
+ if (ret == 0 && buf[0] == 0x63) {
+ priv->tuner = TUNER_RTL2830_MT2060;
+ rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+ dev_dbg(&d->udev->dev, "%s: MT2060\n", __func__);
+ goto found;
+ } else {
+ dev_dbg(&d->udev->dev, "%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;
+ dev_dbg(&d->udev->dev, "%s: MXL5005S\n", __func__);
+ goto found;
+
+found:
+ /* attach demodulator */
+ adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config,
+ &d->i2c_adap);
+ if (adap->fe[0] == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+ .i2c_addr = 0x10, /* 0x20 */
+ .xtal = 28800000,
+ .if_dvbt = 0,
+ .tuner = TUNER_RTL2832_FC0012
+};
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+ .i2c_addr = 0x10, /* 0x20 */
+ .xtal = 28800000,
+ .if_dvbt = 0,
+ .tuner = TUNER_RTL2832_FC0013
+};
+
+static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
+ int cmd, int arg)
+{
+ int ret;
+ u8 val;
+
+ dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg);
+
+ switch (cmd) {
+ case FC_FE_CALLBACK_VHF_ENABLE:
+ /* set output values */
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+ if (ret)
+ goto err;
+
+ if (arg)
+ val &= 0xbf; /* set GPIO6 low */
+ else
+ val |= 0x40; /* set GPIO6 high */
+
+
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ if (ret)
+ goto err;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+
+static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d,
+ int cmd, int arg)
+{
+ /* TODO implement*/
+ return 0;
+}
+
+static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+ struct rtl28xxu_priv *priv = d->priv;
+
+ switch (priv->tuner) {
+ case TUNER_RTL2832_FC0012:
+ return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+
+ case TUNER_RTL2832_FC0013:
+ return rtl2832u_fc0013_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -ENODEV;
+}
+
+static int rtl2832u_frontend_callback(void *adapter_priv, int component,
+ int cmd, int arg)
+{
+ struct i2c_adapter *adap = adapter_priv;
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+ switch (component) {
+ case DVB_FRONTEND_COMPONENT_TUNER:
+ return rtl2832u_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct rtl2832_config *rtl2832_config;
+ u8 buf[2], val;
+ /* 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 FC0012 tuner probe */
+ struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
+ /* for FC0013 tuner probe */
+ struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
+ /* for MT2266 tuner probe */
+ struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
+ /* for FC2580 tuner probe */
+ struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+ /* for MT2063 tuner probe */
+ struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
+ /* for MAX3543 tuner probe */
+ struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
+ /* for TUA9001 tuner probe */
+ struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
+ /* for MXL5007T tuner probe */
+ struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
+ /* for E4000 tuner probe */
+ struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
+ /* for TDA18272 tuner probe */
+ struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_DIR, &val);
+ if (ret)
+ goto err;
+
+ val &= 0xbf;
+
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, val);
+ if (ret)
+ goto err;
+
+ /* enable as output GPIO3 and GPIO6*/
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x48;
+
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, val);
+ 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(d, &req_gate_open);
+ if (ret)
+ goto err;
+
+ priv->tuner = TUNER_NONE;
+
+ /* check FC0012 ID register; reg=00 val=a1 */
+ ret = rtl28xxu_ctrl_msg(d, &req_fc0012);
+ if (ret == 0 && buf[0] == 0xa1) {
+ priv->tuner = TUNER_RTL2832_FC0012;
+ rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+ dev_info(&d->udev->dev, "%s: FC0012 tuner found",
+ KBUILD_MODNAME);
+ goto found;
+ }
+
+ /* check FC0013 ID register; reg=00 val=a3 */
+ ret = rtl28xxu_ctrl_msg(d, &req_fc0013);
+ if (ret == 0 && buf[0] == 0xa3) {
+ priv->tuner = TUNER_RTL2832_FC0013;
+ rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
+ dev_info(&d->udev->dev, "%s: FC0013 tuner found",
+ KBUILD_MODNAME);
+ goto found;
+ }
+
+ /* check MT2266 ID register; reg=00 val=85 */
+ ret = rtl28xxu_ctrl_msg(d, &req_mt2266);
+ if (ret == 0 && buf[0] == 0x85) {
+ priv->tuner = TUNER_RTL2832_MT2266;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: MT2266 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check FC2580 ID register; reg=01 val=56 */
+ ret = rtl28xxu_ctrl_msg(d, &req_fc2580);
+ if (ret == 0 && buf[0] == 0x56) {
+ priv->tuner = TUNER_RTL2832_FC2580;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: FC2580 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check MT2063 ID register; reg=00 val=9e || 9c */
+ ret = rtl28xxu_ctrl_msg(d, &req_mt2063);
+ if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
+ priv->tuner = TUNER_RTL2832_MT2063;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: MT2063 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check MAX3543 ID register; reg=00 val=38 */
+ ret = rtl28xxu_ctrl_msg(d, &req_max3543);
+ if (ret == 0 && buf[0] == 0x38) {
+ priv->tuner = TUNER_RTL2832_MAX3543;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: MAX3534 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check TUA9001 ID register; reg=7e val=2328 */
+ ret = rtl28xxu_ctrl_msg(d, &req_tua9001);
+ if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
+ priv->tuner = TUNER_RTL2832_TUA9001;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: TUA9001 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check MXL5007R ID register; reg=d9 val=14 */
+ ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t);
+ if (ret == 0 && buf[0] == 0x14) {
+ priv->tuner = TUNER_RTL2832_MXL5007T;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: MXL5007T tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check E4000 ID register; reg=02 val=40 */
+ ret = rtl28xxu_ctrl_msg(d, &req_e4000);
+ if (ret == 0 && buf[0] == 0x40) {
+ priv->tuner = TUNER_RTL2832_E4000;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: E4000 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+ /* check TDA18272 ID register; reg=00 val=c760 */
+ ret = rtl28xxu_ctrl_msg(d, &req_tda18272);
+ if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
+ priv->tuner = TUNER_RTL2832_TDA18272;
+ /* TODO implement tuner */
+ dev_info(&d->udev->dev, "%s: TDA18272 tuner found",
+ KBUILD_MODNAME);
+ goto unsupported;
+ }
+
+unsupported:
+ /* close demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
+ if (ret)
+ goto err;
+
+ /* tuner not found */
+ dev_dbg(&d->udev->dev, "%s: No compatible tuner found\n", __func__);
+ ret = -ENODEV;
+ return ret;
+
+found:
+ /* close demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
+ if (ret)
+ goto err;
+
+ /* attach demodulator */
+ adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config,
+ &d->i2c_adap);
+ if (adap->fe[0] == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* set fe callbacks */
+ adap->fe[0]->callback = rtl2832u_frontend_callback;
+
+ return ret;
+
+err:
+ dev_dbg(&d->udev->dev, "%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 dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct i2c_adapter *rtl2830_tuner_i2c;
+ struct dvb_frontend *fe;
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
+ rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]);
+
+ switch (priv->tuner) {
+ case TUNER_RTL2830_QT1010:
+ fe = dvb_attach(qt1010_attach, adap->fe[0],
+ rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+ break;
+ case TUNER_RTL2830_MT2060:
+ fe = dvb_attach(mt2060_attach, adap->fe[0],
+ rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
+ 1220);
+ break;
+ case TUNER_RTL2830_MXL5005S:
+ fe = dvb_attach(mxl5005s_attach, adap->fe[0],
+ rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+ break;
+ default:
+ fe = NULL;
+ dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
+ priv->tuner);
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct dvb_frontend *fe;
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ switch (priv->tuner) {
+ case TUNER_RTL2832_FC0012:
+ fe = dvb_attach(fc0012_attach, adap->fe[0],
+ &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+ /* since fc0012 includs reading the signal strength delegate
+ * that to the tuner driver */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+ return 0;
+ break;
+ case TUNER_RTL2832_FC0013:
+ fe = dvb_attach(fc0013_attach, adap->fe[0],
+ &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+ /* fc0013 also supports signal strength reading */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+ return 0;
+ default:
+ fe = NULL;
+ dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
+ priv->tuner);
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl28xxu_init(struct dvb_usb_device *d)
+{
+ int ret;
+ u8 val;
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /* init USB endpoints */
+ ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
+ if (ret)
+ goto err;
+
+ /* enable DMA and Full Packet Mode*/
+ val |= 0x09;
+ ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
+ if (ret)
+ goto err;
+
+ /* set EPA maximum packet size to 0x0200 */
+ ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+ if (ret)
+ goto err;
+
+ /* change EPA FIFO length */
+ ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl28xxu_streaming_ctrl(struct dvb_frontend *fe , int onoff)
+{
+ int ret;
+ u8 buf[2];
+ struct dvb_usb_device *d = fe_to_d(fe);
+
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ if (onoff) {
+ buf[0] = 0x00;
+ buf[1] = 0x00;
+ } else {
+ buf[0] = 0x10; /* stall EPA */
+ buf[1] = 0x02; /* reset EPA */
+ }
+
+ ret = rtl28xx_wr_regs(d, USB_EPA_CTL, buf, 2);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+ u8 gpio, sys0;
+
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ /* demod adc */
+ ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
+ if (ret)
+ goto err;
+
+ /* tuner power, read GPIOs */
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+ if (ret)
+ goto err;
+
+ dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
+ sys0, gpio);
+
+ if (onoff) {
+ gpio |= 0x01; /* GPIO0 = 1 */
+ gpio &= (~0x10); /* GPIO4 = 0 */
+ gpio |= 0x04; /* GPIO2 = 1, LED on */
+ sys0 = sys0 & 0x0f;
+ sys0 |= 0xe0;
+ } else {
+ gpio &= (~0x01); /* GPIO0 = 0 */
+ gpio |= 0x10; /* GPIO4 = 1 */
+ gpio &= (~0x04); /* GPIO2 = 1, LED off */
+ sys0 = sys0 & (~0xc0);
+ }
+
+ dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
+ sys0, gpio);
+
+ /* demod adc */
+ ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
+ if (ret)
+ goto err;
+
+ /* tuner power, write GPIOs */
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+ u8 val;
+
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ if (onoff) {
+ /* set output values */
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x08;
+ val &= 0xef;
+
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ if (ret)
+ goto err;
+
+ /* demod_ctl_1 */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+ if (ret)
+ goto err;
+
+ val &= 0xef;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+ if (ret)
+ goto err;
+
+ /* demod control */
+ /* PLL enable */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ if (ret)
+ goto err;
+
+ /* bit 7 to 1 */
+ val |= 0x80;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ if (ret)
+ goto err;
+
+ /* demod HW reset */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ if (ret)
+ goto err;
+ /* bit 5 to 0 */
+ val &= 0xdf;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ if (ret)
+ goto err;
+
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x20;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ if (ret)
+ goto err;
+
+ mdelay(5);
+
+ /*enable ADC_Q and ADC_I */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x48;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ if (ret)
+ goto err;
+
+
+ } else {
+ /* demod_ctl_1 */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x0c;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+ if (ret)
+ goto err;
+
+ /* set output values */
+ ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+ if (ret)
+ goto err;
+
+ val |= 0x10;
+
+ ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ if (ret)
+ goto err;
+
+ /* demod control */
+ ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+ if (ret)
+ goto err;
+
+ val &= 0x37;
+
+ ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+ if (ret)
+ goto err;
+
+ }
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%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 = rtl28xx_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 = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+ if (ret)
+ goto err;
+
+ /* repeated intentionally to avoid extra keypress */
+ ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+ if (ret)
+ goto err;
+ }
+
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
+ struct dvb_usb_rc *rc)
+{
+ rc->map_name = RC_MAP_EMPTY;
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = rtl2831u_rc_query;
+ rc->interval = 400;
+
+ return 0;
+}
+
+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 = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
+ rc_nec_tab[i].val);
+ if (ret)
+ goto err;
+ }
+ priv->rc_active = true;
+ }
+
+ ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
+ if (ret)
+ goto err;
+
+ if (buf[0] != 0x83)
+ goto exit;
+
+ ret = rtl28xx_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 = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
+ ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
+ ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
+
+exit:
+ return ret;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
+ struct dvb_usb_rc *rc)
+{
+ rc->map_name = RC_MAP_EMPTY;
+ rc->allowed_protos = RC_TYPE_NEC;
+ rc->query = rtl2832u_rc_query;
+ rc->interval = 400;
+
+ return 0;
+}
+
+static const struct dvb_usb_device_properties rtl2831u_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+ .power_ctrl = rtl2831u_power_ctrl,
+ .i2c_algo = &rtl28xxu_i2c_algo,
+ .frontend_attach = rtl2831u_frontend_attach,
+ .tuner_attach = rtl2831u_tuner_attach,
+ .init = rtl28xxu_init,
+ .get_rc_config = rtl2831u_get_rc_config,
+ .streaming_ctrl = rtl28xxu_streaming_ctrl,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
+ },
+ },
+};
+
+static const struct dvb_usb_device_properties rtl2832u_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+ .power_ctrl = rtl2832u_power_ctrl,
+ .i2c_algo = &rtl28xxu_i2c_algo,
+ .frontend_attach = rtl2832u_frontend_attach,
+ .tuner_attach = rtl2832u_tuner_attach,
+ .init = rtl28xxu_init,
+ .get_rc_config = rtl2832u_get_rc_config,
+ .streaming_ctrl = rtl28xxu_streaming_ctrl,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
+ },
+ },
+};
+
+static const struct usb_device_id rtl28xxu_id_table[] = {
+ { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
+ &rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
+ { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
+ &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
+ &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
+ &rtl2832u_props, "Terratec Cinergy T Stick Black", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
+ &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
+ &rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
+
+static struct usb_driver rtl28xxu_usb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl28xxu_id_table,
+ .probe = dvb_usbv2_probe,
+ .disconnect = dvb_usbv2_disconnect,
+ .suspend = dvb_usbv2_suspend,
+ .resume = dvb_usbv2_resume,
+ .reset_resume = dvb_usbv2_reset_resume,
+ .no_dynamic_id = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(rtl28xxu_usb_driver);
+
+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
new file mode 100644
index 000000000000..575edbf13a92
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -0,0 +1,254 @@
+/*
+ * 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
+
+#include "dvb_usb.h"
+
+#define deb_dump(r, t, v, i, b, l) { \
+ char *direction; \
+ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+ direction = ">>>"; \
+ else \
+ direction = "<<<"; \
+ dev_dbg(&d->udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%s [%d bytes]\n", __func__, t, r, v & 0xff, v >> 8, \
+ i & 0xff, i >> 8, l & 0xff, l >> 8, direction, l); \
+}
+
+/*
+ * 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/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c
new file mode 100644
index 000000000000..eaf673a3978d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c
@@ -0,0 +1,357 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb_usb_common.h"
+
+/* URB stuff for streaming */
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+ struct usb_data_stream_properties *props);
+
+static void usb_urb_complete(struct urb *urb)
+{
+ struct usb_data_stream *stream = urb->context;
+ int ptype = usb_pipetype(urb->pipe);
+ int i;
+ u8 *b;
+
+ dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \
+ "length=%d/%d pack_num=%d errors=%d\n", __func__,
+ ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+ urb->status, urb->actual_length,
+ urb->transfer_buffer_length,
+ urb->number_of_packets, urb->error_count);
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n",
+ __func__, urb->status);
+ break;
+ }
+
+ b = (u8 *) urb->transfer_buffer;
+ switch (ptype) {
+ case PIPE_ISOCHRONOUS:
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status != 0)
+ dev_dbg(&stream->udev->dev, "%s: iso frame " \
+ "descriptor has an error=%d\n",
+ __func__,
+ urb->iso_frame_desc[i].status);
+ else if (urb->iso_frame_desc[i].actual_length > 0)
+ stream->complete(stream,
+ b + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ break;
+ case PIPE_BULK:
+ if (urb->actual_length > 0)
+ stream->complete(stream, b, urb->actual_length);
+ break;
+ default:
+ dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \
+ "completition handler\n", KBUILD_MODNAME);
+ return;
+ }
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+int usb_urb_killv2(struct usb_data_stream *stream)
+{
+ int i;
+ for (i = 0; i < stream->urbs_submitted; i++) {
+ dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
+ /* stop the URB */
+ usb_kill_urb(stream->urb_list[i]);
+ }
+ stream->urbs_submitted = 0;
+ return 0;
+}
+
+int usb_urb_submitv2(struct usb_data_stream *stream,
+ struct usb_data_stream_properties *props)
+{
+ int i, ret;
+
+ if (props) {
+ ret = usb_urb_reconfig(stream, props);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < stream->urbs_initialized; i++) {
+ dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
+ ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
+ if (ret) {
+ dev_err(&stream->udev->dev, "%s: could not submit " \
+ "urb no. %d - get them all back\n",
+ KBUILD_MODNAME, i);
+ usb_urb_killv2(stream);
+ return ret;
+ }
+ stream->urbs_submitted++;
+ }
+ return 0;
+}
+
+int usb_urb_free_urbs(struct usb_data_stream *stream)
+{
+ int i;
+
+ usb_urb_killv2(stream);
+
+ for (i = stream->urbs_initialized - 1; i >= 0; i--) {
+ if (stream->urb_list[i]) {
+ dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
+ __func__, i);
+ /* free the URBs */
+ usb_free_urb(stream->urb_list[i]);
+ }
+ }
+ stream->urbs_initialized = 0;
+
+ return 0;
+}
+
+static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
+{
+ int i, j;
+
+ /* allocate the URBs */
+ for (i = 0; i < stream->props.count; i++) {
+ dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+ stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!stream->urb_list[i]) {
+ dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+ for (j = 0; j < i; j++)
+ usb_free_urb(stream->urb_list[j]);
+ return -ENOMEM;
+ }
+ usb_fill_bulk_urb(stream->urb_list[i],
+ stream->udev,
+ usb_rcvbulkpipe(stream->udev,
+ stream->props.endpoint),
+ stream->buf_list[i],
+ stream->props.u.bulk.buffersize,
+ usb_urb_complete, stream);
+
+ stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
+ stream->urbs_initialized++;
+ }
+ return 0;
+}
+
+static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
+{
+ int i, j;
+
+ /* allocate the URBs */
+ for (i = 0; i < stream->props.count; i++) {
+ struct urb *urb;
+ int frame_offset = 0;
+ dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+ stream->urb_list[i] = usb_alloc_urb(
+ stream->props.u.isoc.framesperurb, GFP_ATOMIC);
+ if (!stream->urb_list[i]) {
+ dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+ for (j = 0; j < i; j++)
+ usb_free_urb(stream->urb_list[j]);
+ return -ENOMEM;
+ }
+
+ urb = stream->urb_list[i];
+
+ urb->dev = stream->udev;
+ urb->context = stream;
+ urb->complete = usb_urb_complete;
+ urb->pipe = usb_rcvisocpipe(stream->udev,
+ stream->props.endpoint);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = stream->props.u.isoc.interval;
+ urb->number_of_packets = stream->props.u.isoc.framesperurb;
+ urb->transfer_buffer_length = stream->props.u.isoc.framesize *
+ stream->props.u.isoc.framesperurb;
+ urb->transfer_buffer = stream->buf_list[i];
+ urb->transfer_dma = stream->dma_addr[i];
+
+ for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length =
+ stream->props.u.isoc.framesize;
+ frame_offset += stream->props.u.isoc.framesize;
+ }
+
+ stream->urbs_initialized++;
+ }
+ return 0;
+}
+
+int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+ if (stream->state & USB_STATE_URB_BUF) {
+ while (stream->buf_num) {
+ stream->buf_num--;
+ dev_dbg(&stream->udev->dev, "%s: free buf=%d\n",
+ __func__, stream->buf_num);
+ usb_free_coherent(stream->udev, stream->buf_size,
+ stream->buf_list[stream->buf_num],
+ stream->dma_addr[stream->buf_num]);
+ }
+ }
+
+ stream->state &= ~USB_STATE_URB_BUF;
+
+ return 0;
+}
+
+int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
+ unsigned long size)
+{
+ stream->buf_num = 0;
+ stream->buf_size = size;
+
+ dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \
+ "streaming\n", __func__, num * size);
+
+ for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+ stream->buf_list[stream->buf_num] = usb_alloc_coherent(
+ stream->udev, size, GFP_ATOMIC,
+ &stream->dma_addr[stream->buf_num]);
+ if (!stream->buf_list[stream->buf_num]) {
+ dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
+ __func__, stream->buf_num);
+ usb_free_stream_buffers(stream);
+ return -ENOMEM;
+ }
+
+ dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
+ __func__, stream->buf_num,
+ stream->buf_list[stream->buf_num],
+ (long long)stream->dma_addr[stream->buf_num]);
+ memset(stream->buf_list[stream->buf_num], 0, size);
+ stream->state |= USB_STATE_URB_BUF;
+ }
+
+ return 0;
+}
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+ struct usb_data_stream_properties *props)
+{
+ int buf_size;
+
+ if (!props)
+ return 0;
+
+ /* check allocated buffers are large enough for the request */
+ if (props->type == USB_BULK) {
+ buf_size = stream->props.u.bulk.buffersize;
+ } else if (props->type == USB_ISOC) {
+ buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
+ } else {
+ dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
+ KBUILD_MODNAME, props->type);
+ return -EINVAL;
+ }
+
+ if (stream->buf_num < props->count || stream->buf_size < buf_size) {
+ dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \
+ "allocated buffers are too small\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ /* check if all fields are same */
+ if (stream->props.type == props->type &&
+ stream->props.count == props->count &&
+ stream->props.endpoint == props->endpoint) {
+ if (props->type == USB_BULK &&
+ props->u.bulk.buffersize ==
+ stream->props.u.bulk.buffersize)
+ return 0;
+ else if (props->type == USB_ISOC &&
+ props->u.isoc.framesperurb ==
+ stream->props.u.isoc.framesperurb &&
+ props->u.isoc.framesize ==
+ stream->props.u.isoc.framesize &&
+ props->u.isoc.interval ==
+ stream->props.u.isoc.interval)
+ return 0;
+ }
+
+ dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
+
+ usb_urb_free_urbs(stream);
+ memcpy(&stream->props, props, sizeof(*props));
+ if (props->type == USB_BULK)
+ return usb_urb_alloc_bulk_urbs(stream);
+ else if (props->type == USB_ISOC)
+ return usb_urb_alloc_isoc_urbs(stream);
+
+ return 0;
+}
+
+int usb_urb_initv2(struct usb_data_stream *stream,
+ const struct usb_data_stream_properties *props)
+{
+ int ret;
+
+ if (!stream || !props)
+ return -EINVAL;
+
+ memcpy(&stream->props, props, sizeof(*props));
+
+ if (!stream->complete) {
+ dev_err(&stream->udev->dev, "%s: there is no data callback - " \
+ "this doesn't make sense\n", KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ switch (stream->props.type) {
+ case USB_BULK:
+ ret = usb_alloc_stream_buffers(stream, stream->props.count,
+ stream->props.u.bulk.buffersize);
+ if (ret < 0)
+ return ret;
+
+ return usb_urb_alloc_bulk_urbs(stream);
+ case USB_ISOC:
+ ret = usb_alloc_stream_buffers(stream, stream->props.count,
+ stream->props.u.isoc.framesize *
+ stream->props.u.isoc.framesperurb);
+ if (ret < 0)
+ return ret;
+
+ return usb_urb_alloc_isoc_urbs(stream);
+ default:
+ dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \
+ "transfer\n", KBUILD_MODNAME);
+ return -EINVAL;
+ }
+}
+
+int usb_urb_exitv2(struct usb_data_stream *stream)
+{
+ usb_urb_free_urbs(stream);
+ usb_free_stream_buffers(stream);
+
+ return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
new file mode 100644
index 000000000000..3c5fff89dbf1
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -0,0 +1,313 @@
+config DVB_USB
+ tristate "Support for various USB DVB devices"
+ depends on DVB_CORE && USB && I2C && RC_CORE
+ help
+ By enabling this you will be able to choose the various supported
+ USB1.1 and USB2.0 DVB devices.
+
+ Almost every USB device needs a firmware, please look into
+ <file:Documentation/dvb/README.dvb-usb>.
+
+ For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+ <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+ Say Y if you own a USB DVB device.
+
+config DVB_USB_DEBUG
+ bool "Enable extended debug support for all DVB-USB devices"
+ depends on DVB_USB
+ help
+ Say Y if you want to enable debugging. See modinfo dvb-usb (and the
+ appropriate drivers) for debug levels.
+
+config DVB_USB_A800
+ tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+config DVB_USB_DIBUSB_MB
+ tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
+ depends on DVB_USB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB3000MB
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
+
+ For an up-to-date list of devices supported by this driver, have a look
+ on the Linux-DVB Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_DIBUSB_MB_FAULTY
+ bool "Support faulty USB IDs"
+ depends on DVB_USB_DIBUSB_MB
+ help
+ Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
+config DVB_USB_DIBUSB_MC
+ tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for USB2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
+
+ For an up-to-date list of devices supported by this driver, have a look
+ on the Linux-DVB Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_DIB0700
+ tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
+ depends on DVB_USB
+ select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2266 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
+ USB bridge is also present in devices having the DiB7700 DVB-T-USB
+ silicon. This chip can be found in devices offered by Hauppauge,
+ Avermedia and other big and small companies.
+
+ For an up-to-date list of devices supported by this driver, have a look
+ on the LinuxTV Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_UMT_010
+ tristate "HanfTek UMT-010 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB3000MC
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+config DVB_USB_CXUSB
+ tristate "Conexant USB2.0 hybrid reference design support"
+ depends on DVB_USB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Conexant USB2.0 hybrid reference design.
+ Currently, only DVB and ATSC modes are supported, analog mode
+ shall be added in the future. Devices that require this module:
+
+ Medion MD95700 hybrid USB2.0 device.
+ DViCO FusionHDTV (Bluebird) USB2.0 devices
+
+config DVB_USB_M920X
+ tristate "Uli m920x DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+ Currently, only devices with a product id of
+ "DTV USB MINI" (in cold state) are supported.
+ Firmware required.
+
+config DVB_USB_DIGITV
+ tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
+
+config DVB_USB_VP7045
+ tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+
+ TwinhanDTV Alpha (stick) (VP-7045),
+ TwinhanDTV MagicBox II (VP-7046),
+ DigitalNow TinyUSB 2 DVB-t,
+ DigitalRise USB 2.0 Ter (Beetle) and
+ TYPHOON DVB-T USB DRIVE
+
+ DVB-T USB2.0 receivers.
+
+config DVB_USB_VP702X
+ tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+
+ TwinhanDTV StarBox,
+ DigitalRise USB Starbox and
+ TYPHOON DVB-S USB 2.0 BOX
+
+ DVB-S USB2.0 receivers.
+
+config DVB_USB_GP8PSK
+ tristate "GENPIX 8PSK->USB module support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+ GENPIX 8psk module
+
+ DVB-S USB2.0 receivers.
+
+config DVB_USB_NOVA_T_USB2
+ tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+config DVB_USB_TTUSB2
+ tristate "Pinnacle 400e DVB-S USB2.0 support"
+ depends on DVB_USB
+ select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
+ firmware protocol used by this module is similar to the one used by the
+ old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
+
+config DVB_USB_DTT200U
+ tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
+ depends on DVB_USB
+ help
+ Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+
+ The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
+
+ The WT-220U and its clones are pen-sized.
+
+config DVB_USB_OPERA1
+ tristate "Opera1 DVB-S USB2.0 receiver"
+ depends on DVB_USB
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+ tristate "Afatech AF9005 DVB-T USB1.1 support"
+ depends on DVB_USB && EXPERIMENTAL
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+ and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+ tristate "Afatech AF9005 default remote control support"
+ depends on DVB_USB_AF9005
+ help
+ Say Y here to support the default remote control decoding for the
+ Afatech AF9005 based receiver.
+
+config DVB_USB_PCTV452E
+ tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+ depends on DVB_USB
+ select TTPCI_EEPROM
+ select DVB_LNBP22 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for external USB adapter designed by Pinnacle,
+ shipped under the brand name 'PCTV HDTV Pro USB'.
+ Also supports TT Connect S2-3600/3650 cards.
+ Say Y if you own such a device and want to use it.
+
+config DVB_USB_DW2102
+ tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
+ depends on DVB_USB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
+ receivers.
+
+config DVB_USB_CINERGY_T2
+ tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
+ depends on DVB_USB
+ help
+ Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_USB_DTV5100
+ tristate "AME DTV-5100 USB2.0 DVB-T support"
+ depends on DVB_USB
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+config DVB_USB_FRIIO
+ tristate "Friio ISDB-T USB2.0 Receiver support"
+ depends on DVB_USB
+ help
+ Say Y here to support the Japanese DTV receiver Friio.
+
+config DVB_USB_AZ6027
+ tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
+ depends on DVB_USB
+ select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the AZ6027 device
+
+config DVB_USB_TECHNISAT_USB2
+ tristate "Technisat DVB-S/S2 USB2.0 support"
+ depends on DVB_USB
+ select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y here to support the Technisat USB2 DVB-S/S2 device
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile
new file mode 100644
index 000000000000..acdd1efd4e74
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/Makefile
@@ -0,0 +1,83 @@
+dvb-usb-objs += dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o
+dvb-usb-objs += dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
+obj-$(CONFIG_DVB_USB) += dvb-usb.o
+
+dvb-usb-vp7045-objs := vp7045.o vp7045-fe.o
+obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
+
+dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o
+obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
+
+dvb-usb-gp8psk-objs := gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
+dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o
+obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
+
+dvb-usb-dibusb-common-objs := dibusb-common.o
+
+dvb-usb-a800-objs := a800.o
+obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
+
+dvb-usb-dibusb-mb-objs := dibusb-mb.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
+
+dvb-usb-dibusb-mc-objs := dibusb-mc.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
+
+dvb-usb-nova-t-usb2-objs := nova-t-usb2.o
+obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
+
+dvb-usb-umt-010-objs := umt-010.o
+obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+
+dvb-usb-m920x-objs := m920x.o
+obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
+
+dvb-usb-digitv-objs := digitv.o
+obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
+
+dvb-usb-cxusb-objs := cxusb.o
+obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
+dvb-usb-ttusb2-objs := ttusb2.o
+obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
+
+dvb-usb-dib0700-objs := dib0700_core.o dib0700_devices.o
+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
+
+dvb-usb-af9005-remote-objs := af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+dvb-usb-pctv452e-objs := pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
+dvb-usb-dw2102-objs := dw2102.o
+obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
+
+dvb-usb-dtv5100-objs := dtv5100.o
+obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
+
+dvb-usb-cinergyT2-objs := cinergyT2-core.o cinergyT2-fe.o
+obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
+dvb-usb-friio-objs := friio.o friio-fe.o
+obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
+
+dvb-usb-az6027-objs := az6027.o
+obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+
+dvb-usb-technisat-usb2-objs := technisat-usb2.o
+obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
+# due to tuner-xc3028
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/pci/ttpci
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c
index 8d7fef84afd8..8d7fef84afd8 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/usb/dvb-usb/a800.c
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c
index 740f3f496f12..740f3f496f12 100644
--- a/drivers/media/dvb/dvb-usb/af9005-fe.c
+++ b/drivers/media/usb/dvb-usb/af9005-fe.c
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/usb/dvb-usb/af9005-remote.c
index 7e3961d0db6b..7e3961d0db6b 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/usb/dvb-usb/af9005-remote.c
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/usb/dvb-usb/af9005-script.h
index 4d69045426dd..4d69045426dd 100644
--- a/drivers/media/dvb/dvb-usb/af9005-script.h
+++ b/drivers/media/usb/dvb-usb/af9005-script.h
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
index af176b6ce738..af176b6ce738 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/usb/dvb-usb/af9005.c
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/usb/dvb-usb/af9005.h
index 6a2bf3de8456..6a2bf3de8456 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/usb/dvb-usb/af9005.h
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index 5e45ae605427..5e45ae605427 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
diff --git a/drivers/media/dvb/dvb-usb/az6027.h b/drivers/media/usb/dvb-usb/az6027.h
index f3afe17f3f3d..f3afe17f3f3d 100644
--- a/drivers/media/dvb/dvb-usb/az6027.h
+++ b/drivers/media/usb/dvb-usb/az6027.h
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c
index 0a98548ecd17..0a98548ecd17 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
index 1efc028a76c9..1efc028a76c9 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/usb/dvb-usb/cinergyT2.h
index 84efe03771eb..84efe03771eb 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2.h
+++ b/drivers/media/usb/dvb-usb/cinergyT2.h
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 3940bb0f9ef6..3940bb0f9ef6 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
index 1a51eafd31b9..1a51eafd31b9 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/usb/dvb-usb/cxusb.h
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
index 7de125c0b36f..7de125c0b36f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/usb/dvb-usb/dib0700.h
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
new file mode 100644
index 000000000000..ef87229de6af
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -0,0 +1,845 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ * 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.
+ *
+ * Copyright (C) 2005-6 DiBcom, SA
+ */
+#include "dib0700.h"
+
+/* debug */
+int dvb_usb_dib0700_debug;
+module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int nb_packet_buffer_size = 21;
+module_param(nb_packet_buffer_size, int, 0644);
+MODULE_PARM_DESC(nb_packet_buffer_size,
+ "Set the dib0700 driver data buffer size. This parameter "
+ "corresponds to the number of TS packets. The actual size of "
+ "the data buffer corresponds to this parameter "
+ "multiplied by 188 (default: 21)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+
+int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+ u32 *romversion, u32 *ramversion, u32 *fwtype)
+{
+ struct dib0700_state *st = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ REQUEST_GET_VERSION,
+ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+ st->buf, 16, USB_CTRL_GET_TIMEOUT);
+ if (hwversion != NULL)
+ *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) |
+ (st->buf[2] << 8) | st->buf[3];
+ if (romversion != NULL)
+ *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) |
+ (st->buf[6] << 8) | st->buf[7];
+ if (ramversion != NULL)
+ *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) |
+ (st->buf[10] << 8) | st->buf[11];
+ if (fwtype != NULL)
+ *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
+ (st->buf[14] << 8) | st->buf[15];
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+/* expecting rx buffer: request data[0] data[1] ... data[2] */
+static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
+{
+ int status;
+
+ deb_data(">>> ");
+ debug_dump(tx, txlen, deb_data);
+
+ status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
+ tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (status != txlen)
+ deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
+
+ return status < 0 ? status : 0;
+}
+
+/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+{
+ u16 index, value;
+ int status;
+
+ if (txlen < 2) {
+ err("tx buffer length is smaller than 2. Makes no sense.");
+ return -EINVAL;
+ }
+ if (txlen > 4) {
+ err("tx buffer length is larger than 4. Not supported.");
+ return -EINVAL;
+ }
+
+ deb_data(">>> ");
+ debug_dump(tx,txlen,deb_data);
+
+ value = ((txlen - 2) << 8) | tx[1];
+ index = 0;
+ if (txlen > 2)
+ index |= (tx[2] << 8);
+ if (txlen > 3)
+ index |= tx[3];
+
+ status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
+ USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (status < 0)
+ deb_info("ep 0 read error (status = %d)\n",status);
+
+ deb_data("<<< ");
+ debug_dump(rx, rxlen, deb_data);
+
+ return status; /* length in case of success */
+}
+
+int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+{
+ struct dib0700_state *st = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_SET_GPIO;
+ st->buf[1] = gpio;
+ st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+{
+ struct dib0700_state *st = d->priv;
+ int ret;
+
+ if (st->fw_version >= 0x10201) {
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+ st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+ st->buf[2] = nb_ts_packets & 0xff;
+
+ deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+ mutex_unlock(&d->usb_mutex);
+ } else {
+ deb_info("this firmware does not allow to change the USB xfer len\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/*
+ * I2C master xfer function (supported in 1.20 firmware)
+ */
+static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ /* The new i2c firmware messages are more reliable and in particular
+ properly support i2c read calls not preceded by a write */
+
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dib0700_state *st = d->priv;
+ uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
+ uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
+ uint8_t en_start = 0;
+ uint8_t en_stop = 0;
+ int result, i;
+
+ /* Ensure nobody else hits the i2c bus while we're sending our
+ sequence of messages, (such as the remote control thread) */
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EINTR;
+
+ for (i = 0; i < num; i++) {
+ if (i == 0) {
+ /* First message in the transaction */
+ en_start = 1;
+ } else if (!(msg[i].flags & I2C_M_NOSTART)) {
+ /* Device supports repeated-start */
+ en_start = 1;
+ } else {
+ /* Not the first packet and device doesn't support
+ repeated start */
+ en_start = 0;
+ }
+ if (i == (num - 1)) {
+ /* Last message in the transaction */
+ en_stop = 1;
+ }
+
+ if (msg[i].flags & I2C_M_RD) {
+ /* Read request */
+ u16 index, value;
+ uint8_t i2c_dest;
+
+ i2c_dest = (msg[i].addr << 1);
+ value = ((en_start << 7) | (en_stop << 6) |
+ (msg[i].len & 0x3F)) << 8 | i2c_dest;
+ /* I2C ctrl + FE bus; */
+ index = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
+
+ result = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev, 0),
+ REQUEST_NEW_I2C_READ,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value, index, msg[i].buf,
+ msg[i].len,
+ USB_CTRL_GET_TIMEOUT);
+ if (result < 0) {
+ deb_info("i2c read error (status = %d)\n", result);
+ break;
+ }
+
+ deb_data("<<< ");
+ debug_dump(msg[i].buf, msg[i].len, deb_data);
+
+ } else {
+ /* Write request */
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ mutex_unlock(&d->i2c_mutex);
+ return -EINTR;
+ }
+ st->buf[0] = REQUEST_NEW_I2C_WRITE;
+ st->buf[1] = msg[i].addr << 1;
+ st->buf[2] = (en_start << 7) | (en_stop << 6) |
+ (msg[i].len & 0x3F);
+ /* I2C ctrl + FE bus; */
+ st->buf[3] = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
+ /* The Actual i2c payload */
+ memcpy(&st->buf[4], msg[i].buf, msg[i].len);
+
+ deb_data(">>> ");
+ debug_dump(st->buf, msg[i].len + 4, deb_data);
+
+ result = usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev, 0),
+ REQUEST_NEW_I2C_WRITE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ 0, 0, st->buf, msg[i].len + 4,
+ USB_CTRL_GET_TIMEOUT);
+ mutex_unlock(&d->usb_mutex);
+ if (result < 0) {
+ deb_info("i2c write error (status = %d)\n", result);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+/*
+ * I2C master xfer function (pre-1.20 firmware)
+ */
+static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dib0700_state *st = d->priv;
+ int i,len;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EINTR;
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ mutex_unlock(&d->i2c_mutex);
+ return -EINTR;
+ }
+
+ for (i = 0; i < num; i++) {
+ /* fill in the address */
+ st->buf[1] = msg[i].addr << 1;
+ /* fill the buffer */
+ memcpy(&st->buf[2], msg[i].buf, msg[i].len);
+
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ st->buf[0] = REQUEST_I2C_READ;
+ st->buf[1] |= 1;
+
+ /* special thing in the current firmware: when length is zero the read-failed */
+ len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
+ msg[i+1].buf, msg[i+1].len);
+ if (len <= 0) {
+ deb_info("I2C read failed on address 0x%02x\n",
+ msg[i].addr);
+ break;
+ }
+
+ msg[i+1].len = len;
+
+ i++;
+ } else {
+ st->buf[0] = REQUEST_I2C_WRITE;
+ if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
+ break;
+ }
+ }
+ mutex_unlock(&d->usb_mutex);
+ mutex_unlock(&d->i2c_mutex);
+
+ return i;
+}
+
+static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dib0700_state *st = d->priv;
+
+ if (st->fw_use_new_i2c_api == 1) {
+ /* User running at least fw 1.20 */
+ return dib0700_i2c_xfer_new(adap, msg, num);
+ } else {
+ /* Use legacy calls */
+ return dib0700_i2c_xfer_legacy(adap, msg, num);
+ }
+}
+
+static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dib0700_i2c_algo = {
+ .master_xfer = dib0700_i2c_xfer,
+ .functionality = dib0700_i2c_func,
+};
+
+int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc, int *cold)
+{
+ s16 ret;
+ u8 *b;
+
+ b = kmalloc(16, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
+
+ deb_info("FW GET_VERSION length: %d\n",ret);
+
+ *cold = ret <= 0;
+ deb_info("cold: %d\n", *cold);
+
+ kfree(b);
+ return 0;
+}
+
+static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+ u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
+ u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+{
+ struct dib0700_state *st = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_SET_CLOCK;
+ st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+ (pll_range << 5) | (clock_gpio3 << 4);
+ st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */
+ st->buf[3] = pll_prediv & 0xff; /* LSB */
+ st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
+ st->buf[5] = pll_loopdiv & 0xff; /* LSB */
+ st->buf[6] = (free_div >> 8) & 0xff; /* MSB */
+ st->buf[7] = free_div & 0xff; /* LSB */
+ st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */
+ st->buf[9] = dsuScaler & 0xff; /* LSB */
+
+ ret = dib0700_ctrl_wr(d, st->buf, 10);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+{
+ struct dib0700_state *st = d->priv;
+ u16 divider;
+ int ret;
+
+ if (scl_kHz == 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_SET_I2C_PARAM;
+ divider = (u16) (30000 / scl_kHz);
+ st->buf[1] = 0;
+ st->buf[2] = (u8) (divider >> 8);
+ st->buf[3] = (u8) (divider & 0xff);
+ divider = (u16) (72000 / scl_kHz);
+ st->buf[4] = (u8) (divider >> 8);
+ st->buf[5] = (u8) (divider & 0xff);
+ divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
+ st->buf[6] = (u8) (divider >> 8);
+ st->buf[7] = (u8) (divider & 0xff);
+
+ deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+ (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+ st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+
+ ret = dib0700_ctrl_wr(d, st->buf, 8);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+
+int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
+{
+ switch (clk_MHz) {
+ case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
+ default: return -EINVAL;
+ }
+ return 0;
+}
+
+static int dib0700_jumpram(struct usb_device *udev, u32 address)
+{
+ int ret = 0, actlen;
+ u8 *buf;
+
+ buf = kmalloc(8, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = REQUEST_JUMPRAM;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ buf[4] = (address >> 24) & 0xff;
+ buf[5] = (address >> 16) & 0xff;
+ buf[6] = (address >> 8) & 0xff;
+ buf[7] = address & 0xff;
+
+ if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
+ deb_fw("jumpram to 0x%x failed\n",address);
+ goto out;
+ }
+ if (actlen != 8) {
+ deb_fw("jumpram to 0x%x failed\n",address);
+ ret = -EIO;
+ goto out;
+ }
+out:
+ kfree(buf);
+ return ret;
+}
+
+int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+ struct hexline hx;
+ int pos = 0, ret, act_len, i, adap_num;
+ u8 *buf;
+ u32 fw_version;
+
+ buf = kmalloc(260, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
+ deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+ hx.addr, hx.len, hx.chk);
+
+ buf[0] = hx.len;
+ buf[1] = (hx.addr >> 8) & 0xff;
+ buf[2] = hx.addr & 0xff;
+ buf[3] = hx.type;
+ memcpy(&buf[4],hx.data,hx.len);
+ buf[4+hx.len] = hx.chk;
+
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x01),
+ buf,
+ hx.len + 5,
+ &act_len,
+ 1000);
+
+ if (ret < 0) {
+ err("firmware download failed at %d with %d",pos,ret);
+ goto out;
+ }
+ }
+
+ if (ret == 0) {
+ /* start the firmware */
+ if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
+ info("firmware started successfully.");
+ msleep(500);
+ }
+ } else
+ ret = -EIO;
+
+ /* the number of ts packet has to be at least 1 */
+ if (nb_packet_buffer_size < 1)
+ nb_packet_buffer_size = 1;
+
+ /* get the fimware version */
+ usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ REQUEST_GET_VERSION,
+ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+ buf, 16, USB_CTRL_GET_TIMEOUT);
+ fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
+
+ /* set the buffer size - DVB-USB is allocating URB buffers
+ * only after the firwmare download was successful */
+ for (i = 0; i < dib0700_device_count; i++) {
+ for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
+ adap_num++) {
+ if (fw_version >= 0x10201) {
+ dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
+ } else {
+ /* for fw version older than 1.20.1,
+ * the buffersize has to be n times 512 */
+ dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
+ if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
+ dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
+ }
+ }
+ }
+out:
+ kfree(buf);
+ return ret;
+}
+
+int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dib0700_state *st = adap->dev->priv;
+ int ret;
+
+ if ((onoff != 0) && (st->fw_version >= 0x10201)) {
+ /* for firmware later than 1.20.1,
+ * the USB xfer length can be set */
+ ret = dib0700_set_usb_xfer_len(adap->dev,
+ st->nb_packet_buffer_size);
+ if (ret < 0) {
+ deb_info("can not set the USB xfer len\n");
+ return ret;
+ }
+ }
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_ENABLE_VIDEO;
+ /* this bit gives a kind of command,
+ * rather than enabling something or not */
+ st->buf[1] = (onoff << 4) | 0x00;
+
+ if (st->disable_streaming_master_mode == 1)
+ st->buf[2] = 0x00;
+ else
+ st->buf[2] = 0x01 << 4; /* Master mode */
+
+ st->buf[3] = 0x00;
+
+ deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
+
+ st->channel_state &= ~0x3;
+ if ((adap->fe_adap[0].stream.props.endpoint != 2)
+ && (adap->fe_adap[0].stream.props.endpoint != 3)) {
+ deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
+ if (onoff)
+ st->channel_state |= 1 << (adap->id);
+ else
+ st->channel_state |= 1 << ~(adap->id);
+ } else {
+ if (onoff)
+ st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2);
+ else
+ st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint);
+ }
+
+ st->buf[2] |= st->channel_state;
+
+ deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
+
+ ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+{
+ struct dvb_usb_device *d = rc->priv;
+ struct dib0700_state *st = d->priv;
+ int new_proto, ret;
+
+ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+ err("could not acquire lock");
+ return -EINTR;
+ }
+
+ st->buf[0] = REQUEST_SET_RC;
+ st->buf[1] = 0;
+ st->buf[2] = 0;
+
+ /* Set the IR mode */
+ if (rc_type == RC_TYPE_RC5)
+ new_proto = 1;
+ else if (rc_type == RC_TYPE_NEC)
+ new_proto = 0;
+ else if (rc_type == RC_TYPE_RC6) {
+ if (st->fw_version < 0x10200) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ new_proto = 2;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ st->buf[1] = new_proto;
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+ if (ret < 0) {
+ err("ir protocol setup failed");
+ goto out;
+ }
+
+ d->props.rc.core.protocol = rc_type;
+
+out:
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY_V1_20 10
+
+/* This is the structure of the RC response packet starting in firmware 1.20 */
+struct dib0700_rc_response {
+ u8 report_id;
+ u8 data_state;
+ union {
+ u16 system16;
+ struct {
+ u8 not_system;
+ u8 system;
+ };
+ };
+ u8 data;
+ u8 not_data;
+};
+#define RC_MSG_SIZE_V1_20 6
+
+static void dib0700_rc_urb_completion(struct urb *purb)
+{
+ struct dvb_usb_device *d = purb->context;
+ struct dib0700_rc_response *poll_reply;
+ u32 uninitialized_var(keycode);
+ u8 toggle;
+
+ deb_info("%s()\n", __func__);
+ if (d->rc_dev == NULL) {
+ /* This will occur if disable_rc_polling=1 */
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ return;
+ }
+
+ poll_reply = purb->transfer_buffer;
+
+ if (purb->status < 0) {
+ deb_info("discontinuing polling\n");
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ return;
+ }
+
+ if (purb->actual_length != RC_MSG_SIZE_V1_20) {
+ deb_info("malformed rc msg size=%d\n", purb->actual_length);
+ goto resubmit;
+ }
+
+ deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+ poll_reply->report_id, poll_reply->data_state,
+ poll_reply->system, poll_reply->not_system,
+ poll_reply->data, poll_reply->not_data,
+ purb->actual_length);
+
+ switch (d->props.rc.core.protocol) {
+ case RC_TYPE_NEC:
+ toggle = 0;
+
+ /* NEC protocol sends repeat code as 0 0 0 FF */
+ if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+ && (poll_reply->not_data == 0xff)) {
+ poll_reply->data_state = 2;
+ break;
+ }
+
+ if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+ deb_data("NEC extended protocol\n");
+ /* NEC extended code - 24 bits */
+ keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
+ } else {
+ deb_data("NEC normal protocol\n");
+ /* normal NEC code - 16 bits */
+ keycode = poll_reply->system << 8 | poll_reply->data;
+ }
+
+ break;
+ default:
+ deb_data("RC5 protocol\n");
+ /* RC5 Protocol */
+ toggle = poll_reply->report_id;
+ keycode = poll_reply->system << 8 | poll_reply->data;
+
+ break;
+ }
+
+ if ((poll_reply->data + poll_reply->not_data) != 0xff) {
+ /* Key failed integrity check */
+ err("key failed integrity check: %04x %02x %02x",
+ poll_reply->system,
+ poll_reply->data, poll_reply->not_data);
+ goto resubmit;
+ }
+
+ rc_keydown(d->rc_dev, keycode, toggle);
+
+resubmit:
+ /* Clean the buffer before we requeue */
+ memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
+
+ /* Requeue URB */
+ usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+ struct dib0700_state *st = d->priv;
+ struct urb *purb;
+ int ret;
+
+ /* Poll-based. Don't initialize bulk mode */
+ if (st->fw_version < 0x10200)
+ return 0;
+
+ /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+ purb = usb_alloc_urb(0, GFP_KERNEL);
+ if (purb == NULL) {
+ err("rc usb alloc urb failed");
+ return -ENOMEM;
+ }
+
+ purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
+ if (purb->transfer_buffer == NULL) {
+ err("rc kzalloc failed");
+ usb_free_urb(purb);
+ return -ENOMEM;
+ }
+
+ purb->status = -EINPROGRESS;
+ usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
+ purb->transfer_buffer, RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d);
+
+ ret = usb_submit_urb(purb, GFP_ATOMIC);
+ if (ret) {
+ err("rc submit urb failed");
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ }
+
+ return ret;
+}
+
+static int dib0700_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int i;
+ struct dvb_usb_device *dev;
+
+ for (i = 0; i < dib0700_device_count; i++)
+ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
+ &dev, adapter_nr) == 0) {
+ struct dib0700_state *st = dev->priv;
+ u32 hwversion, romversion, fw_version, fwtype;
+
+ dib0700_get_version(dev, &hwversion, &romversion,
+ &fw_version, &fwtype);
+
+ deb_info("Firmware version: %x, %d, 0x%x, %d\n",
+ hwversion, romversion, fw_version, fwtype);
+
+ st->fw_version = fw_version;
+ st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+
+ /* Disable polling mode on newer firmwares */
+ if (st->fw_version >= 0x10200)
+ dev->props.rc.core.bulk_mode = true;
+ else
+ dev->props.rc.core.bulk_mode = false;
+
+ dib0700_rc_setup(dev);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static struct usb_driver dib0700_driver = {
+ .name = "dvb_usb_dib0700",
+ .probe = dib0700_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dib0700_usb_id_table,
+};
+
+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");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 510001da6e83..510001da6e83 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/usb/dvb-usb/dib07x0.h
index 7e62c1018520..7e62c1018520 100644
--- a/drivers/media/dvb/dvb-usb/dib07x0.h
+++ b/drivers/media/usb/dvb-usb/dib07x0.h
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index a76bbb29ca36..a76bbb29ca36 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c
index a4ac37e0e98b..a4ac37e0e98b 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mb.c
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c
index 9d1a59d09c52..9d1a59d09c52 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc.c
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/usb/dvb-usb/dibusb.h
index e47c321b3ffc..e47c321b3ffc 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/usb/dvb-usb/dibusb.h
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c
index ff34419a4c88..ff34419a4c88 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/usb/dvb-usb/digitv.c
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/usb/dvb-usb/digitv.h
index 908c09f4966b..908c09f4966b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/usb/dvb-usb/digitv.h
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c
index 3d81daa49172..3d81daa49172 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c
index 66f205c112b2..66f205c112b2 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/usb/dvb-usb/dtt200u.c
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/usb/dvb-usb/dtt200u.h
index 005b0a7df358..005b0a7df358 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ b/drivers/media/usb/dvb-usb/dtt200u.h
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c
index 3d11df41cac0..3d11df41cac0 100644
--- a/drivers/media/dvb/dvb-usb/dtv5100.c
+++ b/drivers/media/usb/dvb-usb/dtv5100.c
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/usb/dvb-usb/dtv5100.h
index 93e96e04a82a..93e96e04a82a 100644
--- a/drivers/media/dvb/dvb-usb/dtv5100.h
+++ b/drivers/media/usb/dvb-usb/dtv5100.h
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/usb/dvb-usb/dvb-usb-common.h
index 6b7b2a89242e..6b7b2a89242e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb-common.h
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
new file mode 100644
index 000000000000..719413b15f20
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -0,0 +1,288 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb-usb-common.h"
+
+/* does the complete input transfer handling */
+static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ int newfeedcount, ret;
+
+ if (adap == NULL)
+ return -ENODEV;
+
+ if ((adap->active_fe < 0) ||
+ (adap->active_fe >= adap->num_frontends_initialized)) {
+ return -EINVAL;
+ }
+
+ newfeedcount = adap->feedcount + (onoff ? 1 : -1);
+
+ /* stop feed before setting a new pid if there will be no pid anymore */
+ if (newfeedcount == 0) {
+ deb_ts("stop feeding\n");
+ usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
+
+ if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+ ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
+ if (ret < 0) {
+ err("error while stopping stream.");
+ return ret;
+ }
+ }
+ }
+
+ adap->feedcount = newfeedcount;
+
+ /* activate the pid on the device specific pid_filter */
+ deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
+ adap->fe_adap[adap->active_fe].pid_filtering ?
+ "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
+ dvbdmxfeed->index, onoff ? "on" : "off");
+ if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->fe_adap[adap->active_fe].pid_filtering &&
+ adap->props.fe[adap->active_fe].pid_filter != NULL)
+ adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
+
+ /* start the feed if this was the first feed and there is still a feed
+ * for reception.
+ */
+ if (adap->feedcount == onoff && adap->feedcount > 0) {
+ deb_ts("submitting all URBs\n");
+ usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
+
+ deb_ts("controlling pid parser\n");
+ if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->props.fe[adap->active_fe].caps &
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+ adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
+ ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
+ adap->fe_adap[adap->active_fe].pid_filtering);
+ if (ret < 0) {
+ err("could not handle pid_parser");
+ return ret;
+ }
+ }
+ deb_ts("start feeding\n");
+ if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
+ ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
+ if (ret < 0) {
+ err("error while enabling fifo.");
+ return ret;
+ }
+ }
+
+ }
+ return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+ return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+ return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
+{
+ int i;
+ int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
+ adap->dev->owner, &adap->dev->udev->dev,
+ adapter_nums);
+
+ if (ret < 0) {
+ deb_info("dvb_register_adapter failed: error %d", ret);
+ goto err;
+ }
+ adap->dvb_adap.priv = adap;
+
+ if (adap->dev->props.read_mac_address) {
+ if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
+ info("MAC address: %pM",adap->dvb_adap.proposed_mac);
+ else
+ err("MAC address reading failed.");
+ }
+
+
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ adap->demux.priv = adap;
+
+ adap->demux.filternum = 0;
+ for (i = 0; i < adap->props.num_frontends; i++) {
+ if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
+ adap->demux.filternum = adap->fe_adap[i].max_feed_count;
+ }
+ adap->demux.feednum = adap->demux.filternum;
+ adap->demux.start_feed = dvb_usb_start_feed;
+ adap->demux.stop_feed = dvb_usb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+ if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
+ err("dvb_dmx_init failed: error %d",ret);
+ goto err_dmx;
+ }
+
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+ if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
+ err("dvb_dmxdev_init failed: error %d",ret);
+ goto err_dmx_dev;
+ }
+
+ 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:
+ dvb_unregister_adapter(&adap->dvb_adap);
+err:
+ return ret;
+}
+
+int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+ if (adap->state & DVB_USB_ADAP_STATE_DVB) {
+ deb_info("unregistering DVB part\n");
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ adap->state &= ~DVB_USB_ADAP_STATE_DVB;
+ }
+ return 0;
+}
+
+static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ int ret = (adap->props.frontend_ctrl) ?
+ adap->props.frontend_ctrl(fe, onoff) : 0;
+
+ if (ret < 0) {
+ err("frontend_ctrl request failed");
+ return ret;
+ }
+ if (onoff)
+ adap->active_fe = fe->id;
+
+ return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ dvb_usb_device_power_ctrl(adap->dev, 1);
+
+ dvb_usb_set_active_fe(fe, 1);
+
+ if (adap->fe_adap[fe->id].fe_init)
+ adap->fe_adap[fe->id].fe_init(fe);
+
+ return 0;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ if (adap->fe_adap[fe->id].fe_sleep)
+ adap->fe_adap[fe->id].fe_sleep(fe);
+
+ dvb_usb_set_active_fe(fe, 0);
+
+ return dvb_usb_device_power_ctrl(adap->dev, 0);
+}
+
+int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+ int ret, i;
+
+ /* register all given adapter frontends */
+ for (i = 0; i < adap->props.num_frontends; i++) {
+
+ if (adap->props.fe[i].frontend_attach == NULL) {
+ err("strange: '%s' #%d,%d "
+ "doesn't want to attach a frontend.",
+ adap->dev->desc->name, adap->id, i);
+
+ return 0;
+ }
+
+ ret = adap->props.fe[i].frontend_attach(adap);
+ if (ret || adap->fe_adap[i].fe == NULL) {
+ /* only print error when there is no FE at all */
+ if (i == 0)
+ err("no frontend was attached by '%s'",
+ adap->dev->desc->name);
+
+ return 0;
+ }
+
+ adap->fe_adap[i].fe->id = i;
+
+ /* re-assign sleep and wakeup functions */
+ adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
+ adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup;
+ adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
+ adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
+
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
+ err("Frontend %d registration failed.", i);
+ dvb_frontend_detach(adap->fe_adap[i].fe);
+ adap->fe_adap[i].fe = NULL;
+ /* In error case, do not try register more FEs,
+ * still leaving already registered FEs alive. */
+ if (i == 0)
+ return -ENODEV;
+ else
+ return 0;
+ }
+
+ /* only attach the tuner if the demod is there */
+ if (adap->props.fe[i].tuner_attach != NULL)
+ adap->props.fe[i].tuner_attach(adap);
+
+ adap->num_frontends_initialized++;
+ }
+
+ return 0;
+}
+
+int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+ int i = adap->num_frontends_initialized - 1;
+
+ /* unregister all given adapter frontends */
+ for (; i >= 0; i--) {
+ if (adap->fe_adap[i].fe != NULL) {
+ dvb_unregister_frontend(adap->fe_adap[i].fe);
+ dvb_frontend_detach(adap->fe_adap[i].fe);
+ }
+ }
+ adap->num_frontends_initialized = 0;
+
+ return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
index 733a7ff7b207..733a7ff7b207 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
index 88e4a62abc44..88e4a62abc44 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 169196ec2d4e..169196ec2d4e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 41bacff24960..41bacff24960 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
index 5c8f651344fc..5c8f651344fc 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
new file mode 100644
index 000000000000..aab0f99bc892
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -0,0 +1,483 @@
+/* dvb-usb.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
+ *
+ * TODO: clean-up the structures for unused fields and update the comments
+ */
+#ifndef __DVB_USB_H__
+#define __DVB_USB_H__
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
+#include "dvb-pll.h"
+
+#include "dvb-usb-ids.h"
+
+/* debug */
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var,level,args...) \
+ do { if ((var & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l,func) {\
+ int loop_; \
+ for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
+ func("\n");\
+}
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b,l,func)
+
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+
+#endif
+
+/* generic log methods - taken from usb.h */
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
+#endif
+
+#undef err
+#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/**
+ * struct dvb_usb_device_description - name and its according USB IDs
+ * @name: real name of the box, regardless which DVB USB device class is in use
+ * @cold_ids: array of struct usb_device_id which describe the device in
+ * pre-firmware state
+ * @warm_ids: array of struct usb_device_id which describe the device in
+ * post-firmware state
+ *
+ * Each DVB USB device class can have one or more actual devices, this struct
+ * assigns a name to it.
+ */
+struct dvb_usb_device_description {
+ const char *name;
+
+#define DVB_USB_ID_MAX_NUM 15
+ struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
+ struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
+};
+
+static inline u8 rc5_custom(struct rc_map_table *key)
+{
+ return (key->scancode >> 8) & 0xff;
+}
+
+static inline u8 rc5_data(struct rc_map_table *key)
+{
+ return key->scancode & 0xff;
+}
+
+static inline u16 rc5_scan(struct rc_map_table *key)
+{
+ return key->scancode & 0xffff;
+}
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+struct usb_data_stream;
+
+/**
+ * Properties of USB streaming - TODO this structure should be somewhere else
+ * describes the kind of USB transfer used for data-streaming.
+ * (BULK or ISOC)
+ */
+struct usb_data_stream_properties {
+#define USB_BULK 1
+#define USB_ISOC 2
+ int type;
+ int count;
+ int endpoint;
+
+ union {
+ struct {
+ int buffersize; /* per URB */
+ } bulk;
+ struct {
+ int framesperurb;
+ int framesize;
+ int interval;
+ } isoc;
+ } u;
+};
+
+/**
+ * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
+ * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
+ * @caps: capabilities of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ * PID-filter.
+ * @num_frontends: number of frontends of the DVB USB adapter.
+ * @frontend_ctrl: called to power on/off active frontend.
+ * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
+ * device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ * of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ * pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @stream: configuration of the USB streaming
+ */
+struct dvb_usb_adapter_fe_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
+#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
+#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10
+ int caps;
+ int pid_filter_count;
+
+ int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
+ int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+ int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
+
+ int (*frontend_attach) (struct dvb_usb_adapter *);
+ int (*tuner_attach) (struct dvb_usb_adapter *);
+
+ struct usb_data_stream_properties stream;
+
+ int size_of_priv;
+};
+
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+ int size_of_priv;
+
+ int (*frontend_ctrl) (struct dvb_frontend *, int);
+
+ int num_frontends;
+ struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
+};
+
+/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
+ * remote control handling).
+ * @rc_map_size: number of items in @rc_map_table.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED 0x00
+#define REMOTE_KEY_PRESSED 0x01
+#define REMOTE_KEY_REPEAT 0x02
+ struct rc_map_table *rc_map_table;
+ int rc_map_size;
+ int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+ int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @allowed_protos: protocol(s) supported by the driver
+ * @driver_type: Used to point if a device supports raw mode
+ * @change_protocol: callback to change protocol
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+ char *rc_codes;
+ u64 protocol;
+ u64 allowed_protos;
+ enum rc_driver_type driver_type;
+ int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+ char *module_name;
+ int (*rc_query) (struct dvb_usb_device *d);
+ int rc_interval;
+ bool bulk_mode; /* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ * based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+ DVB_RC_LEGACY,
+ DVB_RC_CORE,
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ * download.
+ * @firmware: name of the firmware file.
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ * DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+ * so do the warm initialization right after it
+ *
+ * @size_of_priv: how many bytes shall be allocated for the private field
+ * of struct dvb_usb_device.
+ *
+ * @power_ctrl: called to enable/disable power of the device.
+ * @read_mac_address: called to read the MAC address of the device.
+ * @identify_state: called to determine the state (cold or warm), when it
+ * is not distinguishable by the USB IDs.
+ *
+ * @rc: remote controller properties
+ *
+ * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
+ *
+ * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
+ * endpoint which received control messages with bulk transfers. When this
+ * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
+ * helper functions.
+ *
+ * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
+ * endpoint for responses to control messages sent with bulk transfers via
+ * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
+ * instead of the generic_bulk_ctrl_endpoint when reading usb responses in
+ * the dvb_usb_generic_rw helper function.
+ *
+ * @num_device_descs: number of struct dvb_usb_device_description in @devices
+ * @devices: array of struct dvb_usb_device_description compatibles with these
+ * properties.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+
+#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
+ int caps;
+
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135 1
+#define CYPRESS_AN2235 2
+#define CYPRESS_FX2 3
+ int usb_ctrl;
+ int (*download_firmware) (struct usb_device *, const struct firmware *);
+ const char *firmware;
+ int no_reconnect;
+
+ int size_of_priv;
+
+ int num_adapters;
+ struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+ int (*power_ctrl) (struct dvb_usb_device *, int);
+ int (*read_mac_address) (struct dvb_usb_device *, u8 []);
+ int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
+ struct dvb_usb_device_description **, int *);
+
+ struct {
+ enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
+ struct dvb_rc_legacy legacy;
+ struct dvb_rc core;
+ } rc;
+
+ struct i2c_algorithm *i2c_algo;
+
+ int generic_bulk_ctrl_endpoint;
+ int generic_bulk_ctrl_endpoint_response;
+
+ int num_device_descs;
+ struct dvb_usb_device_description devices[12];
+};
+
+/**
+ * struct usb_data_stream - generic object of an USB stream
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+ struct usb_device *udev;
+ struct usb_data_stream_properties props;
+
+#define USB_STATE_INIT 0x00
+#define USB_STATE_URB_BUF 0x01
+ int state;
+
+ void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+ struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ int buf_num;
+ unsigned long buf_size;
+ u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+ int urbs_initialized;
+ int urbs_submitted;
+
+ void *user_priv;
+};
+
+/**
+ * struct dvb_usb_adapter - a DVB adapter on a USB device
+ * @id: index of this adapter (starting with 0).
+ *
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ *
+ * @pll_addr: I2C address of the tuner for programming
+ * @pll_init: array containing the initialization buffer
+ * @pll_desc: pointer to the appropriate struct dvb_pll_desc
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
+ * @dvb_adap: device's dvb_adapter.
+ * @dmxdev: device's dmxdev.
+ * @demux: device's software demuxer.
+ * @dvb_net: device's dvb_net interfaces.
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ * device
+ *
+ * @fe_init: rerouted frontend-init (wakeup) function.
+ * @fe_sleep: rerouted frontend-sleep function.
+ *
+ * @stream: the usb data stream.
+ */
+struct dvb_usb_fe_adapter {
+ struct dvb_frontend *fe;
+
+ int (*fe_init) (struct dvb_frontend *);
+ int (*fe_sleep) (struct dvb_frontend *);
+
+ struct usb_data_stream stream;
+
+ int pid_filtering;
+ int max_feed_count;
+
+ void *priv;
+};
+
+struct dvb_usb_adapter {
+ struct dvb_usb_device *dev;
+ struct dvb_usb_adapter_properties props;
+
+#define DVB_USB_ADAP_STATE_INIT 0x000
+#define DVB_USB_ADAP_STATE_DVB 0x001
+ int state;
+
+ u8 id;
+
+ int feedcount;
+
+ /* dvb */
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+
+ struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
+ int active_fe;
+ int num_frontends_initialized;
+
+ void *priv;
+};
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @powered: indicated whether the device is power or not.
+ * Powered is in/decremented for each call to modify the state.
+ * @udev: pointer to the device's struct usb_device.
+ *
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
+ *
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ *
+ * @rc_dev: rc device for the remote control (rc-core mode)
+ * @input_dev: input device for the remote control (legacy mode)
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+ * @last_state: last state (no, pressed, repeat)
+ * @owner: owner of the dvb_adapter
+ * @priv: private data of the actual driver (allocate by dvb-usb, size defined
+ * in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+ struct dvb_usb_device_properties props;
+ struct dvb_usb_device_description *desc;
+
+ struct usb_device *udev;
+
+#define DVB_USB_STATE_INIT 0x000
+#define DVB_USB_STATE_I2C 0x001
+#define DVB_USB_STATE_DVB 0x002
+#define DVB_USB_STATE_REMOTE 0x004
+ int state;
+
+ int powered;
+
+ /* locking */
+ struct mutex usb_mutex;
+
+ /* i2c */
+ struct mutex i2c_mutex;
+ struct i2c_adapter i2c_adap;
+
+ int num_adapters_initialized;
+ struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+ /* remote control */
+ struct rc_dev *rc_dev;
+ struct input_dev *input_dev;
+ char rc_phys[64];
+ struct delayed_work rc_query_work;
+ u32 last_event;
+ int last_state;
+
+ struct module *owner;
+
+ void *priv;
+};
+
+extern int dvb_usb_device_init(struct usb_interface *,
+ struct dvb_usb_device_properties *,
+ struct module *, struct dvb_usb_device **,
+ short *adapter_nums);
+extern void dvb_usb_device_exit(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
+extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+/* commonly used remote control parsing */
+extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+
+/* commonly used firmware download types and function */
+struct hexline {
+ u8 len;
+ u32 addr;
+ u8 type;
+ u8 data[255];
+ u8 chk;
+};
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
+extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
+
+
+#endif
diff --git a/drivers/media/usb/dvb-usb/dvb_usb_dvb.c b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c
new file mode 100644
index 000000000000..384fe8eec21f
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb_usb_dvb.c
@@ -0,0 +1,403 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb_usb_common.h"
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+ size_t len)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+ adap->stream.udev = adap_to_d(adap)->udev;
+ adap->stream.user_priv = adap;
+ adap->stream.complete = dvb_usb_data_complete;
+
+ return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+ usb_urb_exitv2(&adap->stream);
+
+ return 0;
+}
+
+/* does the complete input transfer handling */
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count)
+{
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \
+ "%04x (%04d) at index %d '%s'\n", __func__, adap->id,
+ adap->active_fe, dvbdmxfeed->type,
+ adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+ dvbdmxfeed->pid, dvbdmxfeed->index,
+ (count == 1) ? "on" : "off");
+
+ if (adap->active_fe == -1)
+ return -EINVAL;
+
+ adap->feed_count += count;
+
+ /* stop feeding if it is last pid */
+ if (adap->feed_count == 0) {
+ pr_debug("%s: stop feeding\n", __func__);
+ usb_urb_killv2(&adap->stream);
+
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap, 0);
+ if (ret < 0) {
+ pr_err("%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_mutex_unlock;
+ }
+ }
+ mutex_unlock(&adap->sync_mutex);
+ }
+
+ /* activate the pid on the device pid filter */
+ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->pid_filtering &&
+ adap->props->pid_filter)
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+ if (ret < 0)
+ pr_err("%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+
+ /* start feeding if it is first pid */
+ if (adap->feed_count == 1 && count == 1) {
+ struct usb_data_stream_properties stream_props;
+ mutex_lock(&adap->sync_mutex);
+ pr_debug("%s: start feeding\n", __func__);
+
+ /* resolve input and output streaming paramters */
+ if (d->props->get_stream_config) {
+ memcpy(&stream_props, &adap->props->stream,
+ sizeof(struct usb_data_stream_properties));
+ ret = d->props->get_stream_config(
+ adap->fe[adap->active_fe],
+ &adap->ts_type, &stream_props);
+ if (ret < 0)
+ goto err_mutex_unlock;
+ } else {
+ stream_props = adap->props->stream;
+ }
+
+ switch (adap->ts_type) {
+ case DVB_USB_FE_TS_TYPE_204:
+ adap->stream.complete = dvb_usb_data_complete_204;
+ break;
+ case DVB_USB_FE_TS_TYPE_RAW:
+ adap->stream.complete = dvb_usb_data_complete_raw;
+ break;
+ case DVB_USB_FE_TS_TYPE_188:
+ default:
+ adap->stream.complete = dvb_usb_data_complete;
+ break;
+ }
+
+ usb_urb_submitv2(&adap->stream, &stream_props);
+
+ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->props->caps &
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+ adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap,
+ adap->pid_filtering);
+ if (ret < 0) {
+ pr_err("%s: pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_mutex_unlock;
+ }
+ }
+
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap, 1);
+ if (ret < 0) {
+ pr_err("%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err_mutex_unlock;
+ }
+ }
+ }
+
+ return 0;
+err_mutex_unlock:
+ mutex_unlock(&adap->sync_mutex);
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+ ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+ &d->udev->dev, d->props->adapter_nr);
+ if (ret < 0) {
+ pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__,
+ ret);
+ goto err;
+ }
+
+ adap->dvb_adap.priv = adap;
+
+ if (d->props->read_mac_address) {
+ ret = d->props->read_mac_address(adap,
+ adap->dvb_adap.proposed_mac);
+ if (ret < 0)
+ goto err_dmx;
+
+ pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME,
+ adap->dvb_adap.proposed_mac);
+ }
+
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ adap->demux.priv = adap;
+ adap->demux.filternum = 0;
+ if (adap->demux.filternum < adap->max_feed_count)
+ adap->demux.filternum = adap->max_feed_count;
+ adap->demux.feednum = adap->demux.filternum;
+ adap->demux.start_feed = dvb_usb_start_feed;
+ adap->demux.stop_feed = dvb_usb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+ ret = dvb_dmx_init(&adap->demux);
+ if (ret < 0) {
+ pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret);
+ goto err_dmx;
+ }
+
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+ ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+ if (ret < 0) {
+ pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME,
+ ret);
+ goto err_dmx_dev;
+ }
+
+ ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+ if (ret < 0) {
+ pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret);
+ goto err_net_init;
+ }
+
+ mutex_init(&adap->sync_mutex);
+
+ return 0;
+err_net_init:
+ dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_dev:
+ dvb_dmx_release(&adap->demux);
+err_dmx:
+ dvb_unregister_adapter(&adap->dvb_adap);
+err:
+ adap->dvb_adap.priv = NULL;
+ return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+ if (adap->dvb_adap.priv) {
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ }
+
+ return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ mutex_lock(&adap->sync_mutex);
+ pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+ ret = dvb_usbv2_device_power_ctrl(d, 1);
+ if (ret < 0)
+ goto err;
+
+ if (d->props->frontend_ctrl) {
+ ret = d->props->frontend_ctrl(fe, 1);
+ if (ret < 0)
+ goto err;
+ }
+
+ if (adap->fe_init[fe->id]) {
+ ret = adap->fe_init[fe->id](fe);
+ if (ret < 0)
+ goto err;
+ }
+
+ adap->active_fe = fe->id;
+ mutex_unlock(&adap->sync_mutex);
+
+ return 0;
+err:
+ mutex_unlock(&adap->sync_mutex);
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ mutex_lock(&adap->sync_mutex);
+ pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+ if (adap->fe_sleep[fe->id]) {
+ ret = adap->fe_sleep[fe->id](fe);
+ if (ret < 0)
+ goto err;
+ }
+
+ if (d->props->frontend_ctrl) {
+ ret = d->props->frontend_ctrl(fe, 0);
+ if (ret < 0)
+ goto err;
+ }
+
+ ret = dvb_usbv2_device_power_ctrl(d, 0);
+ if (ret < 0)
+ goto err;
+
+ adap->active_fe = -1;
+ mutex_unlock(&adap->sync_mutex);
+
+ return 0;
+err:
+ mutex_unlock(&adap->sync_mutex);
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+ int ret, i, count_registered = 0;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+ memset(adap->fe, 0, sizeof(adap->fe));
+ adap->active_fe = -1;
+
+ if (d->props->frontend_attach) {
+ ret = d->props->frontend_attach(adap);
+ if (ret < 0) {
+ pr_debug("%s: frontend_attach() failed=%d\n", __func__,
+ ret);
+ goto err_dvb_frontend_detach;
+ }
+ } else {
+ pr_debug("%s: frontend_attach() do not exists\n", __func__);
+ ret = 0;
+ goto err;
+ }
+
+ for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+ adap->fe[i]->id = i;
+
+ /* re-assign sleep and wakeup functions */
+ adap->fe_init[i] = adap->fe[i]->ops.init;
+ adap->fe[i]->ops.init = dvb_usb_fe_wakeup;
+ adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+ adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+ ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+ if (ret < 0) {
+ pr_err("%s: frontend%d registration failed\n",
+ KBUILD_MODNAME, i);
+ goto err_dvb_unregister_frontend;
+ }
+
+ count_registered++;
+ }
+
+ if (d->props->tuner_attach) {
+ ret = d->props->tuner_attach(adap);
+ if (ret < 0) {
+ pr_debug("%s: tuner_attach() failed=%d\n", __func__,
+ ret);
+ goto err_dvb_unregister_frontend;
+ }
+ }
+
+ return 0;
+
+err_dvb_unregister_frontend:
+ for (i = count_registered - 1; i >= 0; i--)
+ dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+ for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+ if (adap->fe[i])
+ dvb_frontend_detach(adap->fe[i]);
+ }
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+ int i;
+ pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+ for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+ if (adap->fe[i]) {
+ dvb_unregister_frontend(adap->fe[i]);
+ dvb_frontend_detach(adap->fe[i]);
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/usb/dvb-usb/dvb_usb_remote.c b/drivers/media/usb/dvb-usb/dvb_usb_remote.c
new file mode 100644
index 000000000000..f856ab6648c7
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/dvb_usb_remote.c
@@ -0,0 +1,117 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the input-device and for
+ * handling remote-control-queries.
+ */
+#include "dvb_usb_common.h"
+#include <linux/usb/input.h>
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+ struct dvb_usb_device *d = container_of(work,
+ struct dvb_usb_device, rc_query_work.work);
+ int ret;
+
+ /* TODO: need a lock here. We can simply skip checking for the remote
+ control if we're busy. */
+
+ /* when the parameter has been set to 1 via sysfs while the
+ * driver was running, or when bulk mode is enabled after IR init
+ */
+ if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+ return;
+
+ ret = d->rc.query(d);
+ if (ret < 0)
+ pr_err("%s: error %d while querying for an remote control " \
+ "event\n", KBUILD_MODNAME, ret);
+
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->rc.interval));
+}
+
+int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+ int ret;
+ struct rc_dev *dev;
+
+ if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+ return 0;
+
+ ret = d->props->get_rc_config(d, &d->rc);
+ if (ret < 0)
+ goto err;
+
+ dev = rc_allocate_device();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->dev.parent = &d->udev->dev;
+ dev->input_name = "IR-receiver inside an USB DVB receiver";
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+ dev->input_phys = d->rc_phys;
+ usb_to_input_id(d->udev, &dev->input_id);
+ /* TODO: likely RC-core should took const char * */
+ dev->driver_name = (char *) d->props->driver_name;
+ dev->driver_type = d->rc.driver_type;
+ dev->allowed_protos = d->rc.allowed_protos;
+ dev->change_protocol = d->rc.change_protocol;
+ dev->priv = d;
+ /* select used keymap */
+ if (d->rc.map_name)
+ dev->map_name = d->rc.map_name;
+ else if (d->rc_map)
+ dev->map_name = d->rc_map;
+ else
+ dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */
+
+ ret = rc_register_device(dev);
+ if (ret < 0) {
+ rc_free_device(dev);
+ goto err;
+ }
+
+ d->input_dev = NULL;
+ d->rc_dev = dev;
+
+ /* start polling if needed */
+ if (d->rc.query && !d->rc.bulk_mode) {
+ /* initialize a work queue for handling polling */
+ INIT_DELAYED_WORK(&d->rc_query_work,
+ dvb_usb_read_remote_control);
+ pr_info("%s: schedule remote query interval to %d msecs\n",
+ KBUILD_MODNAME, d->rc.interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->rc.interval));
+ }
+
+ d->state |= DVB_USB_STATE_REMOTE;
+
+ return 0;
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+ if (d->state & DVB_USB_STATE_REMOTE) {
+ cancel_delayed_work_sync(&d->rc_query_work);
+ rc_unregister_device(d->rc_dev);
+ }
+
+ d->state &= ~DVB_USB_STATE_REMOTE;
+
+ return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 9382895b1b88..9382895b1b88 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/usb/dvb-usb/dw2102.h
index 5cd0b0eb6ce1..5cd0b0eb6ce1 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.h
+++ b/drivers/media/usb/dvb-usb/dw2102.h
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c
index 90a70c66a96e..90a70c66a96e 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/usb/dvb-usb/friio-fe.c
diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c
index 474a17e4db0c..474a17e4db0c 100644
--- a/drivers/media/dvb/dvb-usb/friio.c
+++ b/drivers/media/usb/dvb-usb/friio.c
diff --git a/drivers/media/dvb/dvb-usb/friio.h b/drivers/media/usb/dvb-usb/friio.h
index 0f461ca10cb9..0f461ca10cb9 100644
--- a/drivers/media/dvb/dvb-usb/friio.h
+++ b/drivers/media/usb/dvb-usb/friio.h
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/usb/dvb-usb/gp8psk-fe.c
index 67957dd99ede..67957dd99ede 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/usb/dvb-usb/gp8psk-fe.c
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c
index 5d0384dd45b5..5d0384dd45b5 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/usb/dvb-usb/gp8psk.c
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/usb/dvb-usb/gp8psk.h
index ed32b9da4843..ed32b9da4843 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/usb/dvb-usb/gp8psk.h
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 288af29a8bb7..288af29a8bb7 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/usb/dvb-usb/m920x.h
index 3c061518ffc1..3c061518ffc1 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/usb/dvb-usb/m920x.h
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c
index 6c55384e2fca..6c55384e2fca 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index c8a95042dfbc..c8a95042dfbc 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
new file mode 100644
index 000000000000..02e878577c3d
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -0,0 +1,1063 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN 0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR 0x1b
+/* command to send I2C */
+#define PCTV_CMD_I2C 0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22 (0x10 >> 1)
+#define I2C_ADDR_24C16 (0xa0 >> 1)
+#define I2C_ADDR_24C64 (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO STB0899_GPIO01
+#define PCTV_LED_GREEN 0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...) \
+do { \
+ if (0) \
+ printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
+ ": " format "\n" , ## arg); \
+} while (0)
+
+enum {
+ TT3650_CMD_CI_TEST = 0x40,
+ TT3650_CMD_CI_RD_CTRL,
+ TT3650_CMD_CI_WR_CTRL,
+ TT3650_CMD_CI_RD_ATTR,
+ TT3650_CMD_CI_WR_ATTR,
+ TT3650_CMD_CI_RESET,
+ TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+ { PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+ { 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+ struct dvb_ca_en50221 ca;
+ struct mutex ca_mutex;
+
+ u8 c; /* transaction counter, wraps around... */
+ u8 initialized; /* set to 1 if 0x15 has been sent */
+ u16 last_rc_key;
+};
+
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
+ unsigned int write_len, unsigned int read_len)
+{
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 buf[64];
+ u8 id;
+ unsigned int rlen;
+ int ret;
+
+ BUG_ON(NULL == data && 0 != (write_len | read_len));
+ BUG_ON(write_len > 64 - 4);
+ BUG_ON(read_len > 64 - 4);
+
+ id = state->c++;
+
+ buf[0] = SYNC_BYTE_OUT;
+ buf[1] = id;
+ buf[2] = cmd;
+ buf[3] = write_len;
+
+ memcpy(buf + 4, data, write_len);
+
+ rlen = (read_len > 0) ? 64 : 0;
+ ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+ buf, rlen, /* delay_ms */ 0);
+ if (0 != ret)
+ goto failed;
+
+ ret = -EIO;
+ if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+ goto failed;
+
+ memcpy(data, buf + 4, read_len);
+
+ return 0;
+
+failed:
+ err("CI error %d; %02X %02X %02X -> %*ph.",
+ ret, SYNC_BYTE_OUT, id, cmd, 3, buf);
+
+ return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+ u8 cmd, u8 *data, unsigned int write_len,
+ unsigned int read_len)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ int ret;
+
+ mutex_lock(&state->ca_mutex);
+ ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+ mutex_unlock(&state->ca_mutex);
+
+ return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot, int address)
+{
+ u8 buf[3];
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ buf[0] = (address >> 8) & 0x0F;
+ buf[1] = address;
+
+ ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+ ci_dbg("%s %04x -> %d 0x%02x",
+ __func__, address, ret, buf[2]);
+
+ if (ret < 0)
+ return ret;
+
+ return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot, int address, u8 value)
+{
+ u8 buf[3];
+
+ ci_dbg("%s %d 0x%04x 0x%02x",
+ __func__, slot, address, value);
+
+ if (0 != slot)
+ return -EINVAL;
+
+ buf[0] = (address >> 8) & 0x0F;
+ buf[1] = address;
+ buf[2] = value;
+
+ return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address)
+{
+ u8 buf[2];
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ buf[0] = address & 3;
+
+ ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+ ci_dbg("%s 0x%02x -> %d 0x%02x",
+ __func__, address, ret, buf[1]);
+
+ if (ret < 0)
+ return ret;
+
+ return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address,
+ u8 value)
+{
+ u8 buf[2];
+
+ ci_dbg("%s %d 0x%02x 0x%02x",
+ __func__, slot, address, value);
+
+ if (0 != slot)
+ return -EINVAL;
+
+ buf[0] = address;
+ buf[1] = value;
+
+ return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+ int slot,
+ int enable)
+{
+ u8 buf[1];
+ int ret;
+
+ ci_dbg("%s %d %d", __func__, slot, enable);
+
+ if (0 != slot)
+ return -EINVAL;
+
+ enable = !!enable;
+ buf[0] = enable;
+
+ ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+ if (ret < 0)
+ return ret;
+
+ if (enable != buf[0]) {
+ err("CI not %sabled.", enable ? "en" : "dis");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+ return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+ return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 buf[1];
+ int ret;
+
+ ci_dbg("%s %d", __func__, slot);
+
+ if (0 != slot)
+ return -EINVAL;
+
+ buf[0] = 0;
+
+ mutex_lock(&state->ca_mutex);
+
+ ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+ if (0 != ret)
+ goto failed;
+
+ msleep(500);
+
+ buf[0] = 1;
+
+ ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+ if (0 != ret)
+ goto failed;
+
+ msleep(500);
+
+ buf[0] = 0; /* FTA */
+
+ ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+ mutex_unlock(&state->ca_mutex);
+
+ return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+ int slot,
+ int open)
+{
+ u8 buf[1];
+ int ret;
+
+ if (0 != slot)
+ return -EINVAL;
+
+ ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+ if (0 != ret)
+ return ret;
+
+ if (1 == buf[0])
+ return DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+
+ return 0;
+
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+ struct pctv452e_state *state;
+
+ ci_dbg("%s", __func__);
+
+ if (NULL == d)
+ return;
+
+ state = (struct pctv452e_state *)d->priv;
+ if (NULL == state)
+ return;
+
+ if (NULL == state->ca.data)
+ return;
+
+ /* Error ignored. */
+ tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+ dvb_ca_en50221_release(&state->ca);
+
+ memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+ struct dvb_usb_device *d = a->dev;
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ int ret;
+
+ ci_dbg("%s", __func__);
+
+ mutex_init(&state->ca_mutex);
+
+ state->ca.owner = THIS_MODULE;
+ state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+ state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+ state->ca.read_cam_control = tt3650_ci_read_cam_control;
+ state->ca.write_cam_control = tt3650_ci_write_cam_control;
+ state->ca.slot_reset = tt3650_ci_slot_reset;
+ state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+ state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+ state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+ state->ca.data = d;
+
+ ret = dvb_ca_en50221_init(&a->dvb_adap,
+ &state->ca,
+ /* flags */ 0,
+ /* n_slots */ 1);
+ if (0 != ret) {
+ err("Cannot initialize CI: Error %d.", ret);
+ memset(&state->ca, 0, sizeof(state->ca));
+ return ret;
+ }
+
+ info("CI initialized.");
+
+ return 0;
+}
+
+#define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ const u8 *snd_buf, u8 snd_len,
+ u8 *rcv_buf, u8 rcv_len)
+{
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 buf[64];
+ u8 id;
+ int ret;
+
+ id = state->c++;
+
+ ret = -EINVAL;
+ if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+ goto failed;
+
+ buf[0] = SYNC_BYTE_OUT;
+ buf[1] = id;
+ buf[2] = PCTV_CMD_I2C;
+ buf[3] = snd_len + 3;
+ buf[4] = addr << 1;
+ buf[5] = snd_len;
+ buf[6] = rcv_len;
+
+ memcpy(buf + 7, snd_buf, snd_len);
+
+ ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+ buf, /* rcv_len */ 64,
+ /* delay_ms */ 0);
+ if (ret < 0)
+ goto failed;
+
+ /* TT USB protocol error. */
+ ret = -EIO;
+ if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+ goto failed;
+
+ /* I2C device didn't respond as expected. */
+ ret = -EREMOTEIO;
+ if (buf[5] < snd_len || buf[6] < rcv_len)
+ goto failed;
+
+ memcpy(rcv_buf, buf + 7, rcv_len);
+
+ return rcv_len;
+
+failed:
+ err("I2C error %d; %02X %02X %02X %02X %02X -> "
+ "%02X %02X %02X %02X %02X.",
+ ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+ buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+ return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adapter);
+ int i;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+ int ret;
+
+ if (msg[i].flags & I2C_M_RD) {
+ addr = msg[i].addr;
+ snd_buf = NULL;
+ snd_len = 0;
+ rcv_buf = msg[i].buf;
+ rcv_len = msg[i].len;
+ } else {
+ addr = msg[i].addr;
+ snd_buf = msg[i].buf;
+ snd_len = msg[i].len;
+ rcv_buf = NULL;
+ rcv_len = 0;
+ }
+
+ ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
+ rcv_len);
+ if (ret < rcv_len)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
+{
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+ u8 rx[PCTV_ANSWER_LEN];
+ int ret;
+
+ info("%s: %d\n", __func__, i);
+
+ if (!i)
+ return 0;
+
+ if (state->initialized)
+ return 0;
+
+ /* hmm where shoud this should go? */
+ ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+ if (ret != 0)
+ info("%s: Warning set interface returned: %d\n",
+ __func__, ret);
+
+ /* this is a one-time initialization, dont know where to put */
+ b0[1] = state->c++;
+ /* reset board */
+ ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+ if (ret)
+ return ret;
+
+ b0[1] = state->c++;
+ b0[4] = 1;
+ /* reset board (again?) */
+ ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+ if (ret)
+ return ret;
+
+ state->initialized = 1;
+
+ return 0;
+}
+
+static int pctv452e_rc_query(struct dvb_usb_device *d)
+{
+ struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 b[CMD_BUFFER_SIZE];
+ u8 rx[PCTV_ANSWER_LEN];
+ int ret, i;
+ u8 id = state->c++;
+
+ /* prepare command header */
+ b[0] = SYNC_BYTE_OUT;
+ b[1] = id;
+ b[2] = PCTV_CMD_IR;
+ b[3] = 0;
+
+ /* send ir request */
+ ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+ if (ret != 0)
+ return ret;
+
+ if (debug > 3) {
+ info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx);
+ for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+ info(" %02x", rx[i+3]);
+
+ info("\n");
+ }
+
+ if ((rx[3] == 9) && (rx[12] & 0x01)) {
+ /* got a "press" event */
+ state->last_rc_key = (rx[7] << 8) | rx[6];
+ if (debug > 2)
+ info("%s: cmd=0x%02x sys=0x%02x\n",
+ __func__, rx[6], rx[7]);
+
+ rc_keydown(d->rc_dev, state->last_rc_key, 0);
+ } else if (state->last_rc_key) {
+ rc_keyup(d->rc_dev);
+ state->last_rc_key = 0;
+ }
+
+ return 0;
+}
+
+static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+ const u8 mem_addr[] = { 0x1f, 0xcc };
+ u8 encoded_mac[20];
+ int ret;
+
+ ret = -EAGAIN;
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ goto failed;
+
+ ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
+ mem_addr + 1, /* snd_len */ 1,
+ encoded_mac, /* rcv_len */ 20);
+ if (-EREMOTEIO == ret)
+ /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+ byte write if /WC is low. */
+ ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
+ mem_addr, 2,
+ encoded_mac, 20);
+
+ mutex_unlock(&d->i2c_mutex);
+
+ if (20 != ret)
+ goto failed;
+
+ ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
+ if (0 != ret)
+ goto failed;
+
+ return 0;
+
+failed:
+ memset(mac, 0, 6);
+
+ return ret;
+}
+
+static const struct stb0899_s1_reg pctv452e_init_dev[] = {
+ { STB0899_DISCNTRL1, 0x26 },
+ { STB0899_DISCNTRL2, 0x80 },
+ { STB0899_DISRX_ST0, 0x04 },
+ { STB0899_DISRX_ST1, 0x20 },
+ { STB0899_DISPARITY, 0x00 },
+ { STB0899_DISFIFO, 0x00 },
+ { STB0899_DISF22, 0x99 },
+ { STB0899_DISF22RX, 0x85 }, /* 0xa8 */
+ { STB0899_ACRPRESC, 0x11 },
+ { STB0899_ACRDIV1, 0x0a },
+ { STB0899_ACRDIV2, 0x05 },
+ { STB0899_DACR1 , 0x00 },
+ { STB0899_DACR2 , 0x00 },
+ { STB0899_OUTCFG, 0x00 },
+ { STB0899_MODECFG, 0x00 }, /* Inversion */
+ { STB0899_IRQMSK_3, 0xf3 },
+ { STB0899_IRQMSK_2, 0xfc },
+ { STB0899_IRQMSK_1, 0xff },
+ { STB0899_IRQMSK_0, 0xff },
+ { STB0899_I2CCFG, 0x88 },
+ { STB0899_I2CRPT, 0x58 },
+ { STB0899_GPIO00CFG, 0x82 },
+ { STB0899_GPIO01CFG, 0x82 }, /* LED: 0x02 green, 0x82 orange */
+ { STB0899_GPIO02CFG, 0x82 },
+ { STB0899_GPIO03CFG, 0x82 },
+ { STB0899_GPIO04CFG, 0x82 },
+ { STB0899_GPIO05CFG, 0x82 },
+ { STB0899_GPIO06CFG, 0x82 },
+ { STB0899_GPIO07CFG, 0x82 },
+ { STB0899_GPIO08CFG, 0x82 },
+ { STB0899_GPIO09CFG, 0x82 },
+ { STB0899_GPIO10CFG, 0x82 },
+ { STB0899_GPIO11CFG, 0x82 },
+ { STB0899_GPIO12CFG, 0x82 },
+ { STB0899_GPIO13CFG, 0x82 },
+ { STB0899_GPIO14CFG, 0x82 },
+ { STB0899_GPIO15CFG, 0x82 },
+ { STB0899_GPIO16CFG, 0x82 },
+ { STB0899_GPIO17CFG, 0x82 },
+ { STB0899_GPIO18CFG, 0x82 },
+ { STB0899_GPIO19CFG, 0x82 },
+ { STB0899_GPIO20CFG, 0x82 },
+ { STB0899_SDATCFG, 0xb8 },
+ { STB0899_SCLTCFG, 0xba },
+ { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
+ { STB0899_GPIO22, 0x82 },
+ { STB0899_GPIO21, 0x91 },
+ { STB0899_DIRCLKCFG, 0x82 },
+ { STB0899_CLKOUT27CFG, 0x7e },
+ { STB0899_STDBYCFG, 0x82 },
+ { STB0899_CS0CFG, 0x82 },
+ { STB0899_CS1CFG, 0x82 },
+ { STB0899_DISEQCOCFG, 0x20 },
+ { STB0899_NCOARSE, 0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
+ { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */
+ { STB0899_FILTCTRL, 0x00 },
+ { STB0899_SYSCTRL, 0x00 },
+ { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */
+ { STB0899_STOPCLK2, 0x00 },
+ { STB0899_INTBUFCTRL, 0x0a },
+ { STB0899_AGC2I1, 0x00 },
+ { STB0899_AGC2I2, 0x00 },
+ { STB0899_AGCIQIN, 0x00 },
+ { STB0899_TSTRES, 0x40 }, /* rjkm */
+ { 0xffff, 0xff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+ { STB0899_DEMOD, 0x00 },
+ { STB0899_RCOMPC, 0xc9 },
+ { STB0899_AGC1CN, 0x01 },
+ { STB0899_AGC1REF, 0x10 },
+ { STB0899_RTC, 0x23 },
+ { STB0899_TMGCFG, 0x4e },
+ { STB0899_AGC2REF, 0x34 },
+ { STB0899_TLSR, 0x84 },
+ { STB0899_CFD, 0xf7 },
+ { STB0899_ACLC, 0x87 },
+ { STB0899_BCLC, 0x94 },
+ { STB0899_EQON, 0x41 },
+ { STB0899_LDT, 0xf1 },
+ { STB0899_LDT2, 0xe3 },
+ { STB0899_EQUALREF, 0xb4 },
+ { STB0899_TMGRAMP, 0x10 },
+ { STB0899_TMGTHD, 0x30 },
+ { STB0899_IDCCOMP, 0xfd },
+ { STB0899_QDCCOMP, 0xff },
+ { STB0899_POWERI, 0x0c },
+ { STB0899_POWERQ, 0x0f },
+ { STB0899_RCOMP, 0x6c },
+ { STB0899_AGCIQIN, 0x80 },
+ { STB0899_AGC2I1, 0x06 },
+ { STB0899_AGC2I2, 0x00 },
+ { STB0899_TLIR, 0x30 },
+ { STB0899_RTF, 0x7f },
+ { STB0899_DSTATUS, 0x00 },
+ { STB0899_LDI, 0xbc },
+ { STB0899_CFRM, 0xea },
+ { STB0899_CFRL, 0x31 },
+ { STB0899_NIRM, 0x2b },
+ { STB0899_NIRL, 0x80 },
+ { STB0899_ISYMB, 0x1d },
+ { STB0899_QSYMB, 0xa6 },
+ { STB0899_SFRH, 0x2f },
+ { STB0899_SFRM, 0x68 },
+ { STB0899_SFRL, 0x40 },
+ { STB0899_SFRUPH, 0x2f },
+ { STB0899_SFRUPM, 0x68 },
+ { STB0899_SFRUPL, 0x40 },
+ { STB0899_EQUAI1, 0x02 },
+ { STB0899_EQUAQ1, 0xff },
+ { STB0899_EQUAI2, 0x04 },
+ { STB0899_EQUAQ2, 0x05 },
+ { STB0899_EQUAI3, 0x02 },
+ { STB0899_EQUAQ3, 0xfd },
+ { STB0899_EQUAI4, 0x03 },
+ { STB0899_EQUAQ4, 0x07 },
+ { STB0899_EQUAI5, 0x08 },
+ { STB0899_EQUAQ5, 0xf5 },
+ { STB0899_DSTATUS2, 0x00 },
+ { STB0899_VSTATUS, 0x00 },
+ { STB0899_VERROR, 0x86 },
+ { STB0899_IQSWAP, 0x2a },
+ { STB0899_ECNT1M, 0x00 },
+ { STB0899_ECNT1L, 0x00 },
+ { STB0899_ECNT2M, 0x00 },
+ { STB0899_ECNT2L, 0x00 },
+ { STB0899_ECNT3M, 0x0a },
+ { STB0899_ECNT3L, 0xad },
+ { STB0899_FECAUTO1, 0x06 },
+ { STB0899_FECM, 0x01 },
+ { STB0899_VTH12, 0xb0 },
+ { STB0899_VTH23, 0x7a },
+ { STB0899_VTH34, 0x58 },
+ { STB0899_VTH56, 0x38 },
+ { STB0899_VTH67, 0x34 },
+ { STB0899_VTH78, 0x24 },
+ { STB0899_PRVIT, 0xff },
+ { STB0899_VITSYNC, 0x19 },
+ { STB0899_RSULC, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+ { STB0899_TSULC, 0x42 },
+ { STB0899_RSLLC, 0x41 },
+ { STB0899_TSLPL, 0x12 },
+ { STB0899_TSCFGH, 0x0c },
+ { STB0899_TSCFGM, 0x00 },
+ { STB0899_TSCFGL, 0x00 },
+ { STB0899_TSOUT, 0x69 }, /* 0x0d for CAM */
+ { STB0899_RSSYNCDEL, 0x00 },
+ { STB0899_TSINHDELH, 0x02 },
+ { STB0899_TSINHDELM, 0x00 },
+ { STB0899_TSINHDELL, 0x00 },
+ { STB0899_TSLLSTKM, 0x1b },
+ { STB0899_TSLLSTKL, 0xb3 },
+ { STB0899_TSULSTKM, 0x00 },
+ { STB0899_TSULSTKL, 0x00 },
+ { STB0899_PCKLENUL, 0xbc },
+ { STB0899_PCKLENLL, 0xcc },
+ { STB0899_RSPCKLEN, 0xbd },
+ { STB0899_TSSTATUS, 0x90 },
+ { STB0899_ERRCTRL1, 0xb6 },
+ { STB0899_ERRCTRL2, 0x95 },
+ { STB0899_ERRCTRL3, 0x8d },
+ { STB0899_DMONMSK1, 0x27 },
+ { STB0899_DMONMSK0, 0x03 },
+ { STB0899_DEMAPVIT, 0x5c },
+ { STB0899_PLPARM, 0x19 },
+ { STB0899_PDELCTRL, 0x48 },
+ { STB0899_PDELCTRL2, 0x00 },
+ { STB0899_BBHCTRL1, 0x00 },
+ { STB0899_BBHCTRL2, 0x00 },
+ { STB0899_HYSTTHRESH, 0x77 },
+ { STB0899_MATCSTM, 0x00 },
+ { STB0899_MATCSTL, 0x00 },
+ { STB0899_UPLCSTM, 0x00 },
+ { STB0899_UPLCSTL, 0x00 },
+ { STB0899_DFLCSTM, 0x00 },
+ { STB0899_DFLCSTL, 0x00 },
+ { STB0899_SYNCCST, 0x00 },
+ { STB0899_SYNCDCSTM, 0x00 },
+ { STB0899_SYNCDCSTL, 0x00 },
+ { STB0899_ISI_ENTRY, 0x00 },
+ { STB0899_ISI_BIT_EN, 0x00 },
+ { STB0899_MATSTRM, 0xf0 },
+ { STB0899_MATSTRL, 0x02 },
+ { STB0899_UPLSTRM, 0x45 },
+ { STB0899_UPLSTRL, 0x60 },
+ { STB0899_DFLSTRM, 0xe3 },
+ { STB0899_DFLSTRL, 0x00 },
+ { STB0899_SYNCSTR, 0x47 },
+ { STB0899_SYNCDSTRM, 0x05 },
+ { STB0899_SYNCDSTRL, 0x18 },
+ { STB0899_CFGPDELSTATUS1, 0x19 },
+ { STB0899_CFGPDELSTATUS2, 0x2b },
+ { STB0899_BBFERRORM, 0x00 },
+ { STB0899_BBFERRORL, 0x01 },
+ { STB0899_UPKTERRORM, 0x00 },
+ { STB0899_UPKTERRORL, 0x00 },
+ { 0xffff, 0xff },
+};
+
+static struct stb0899_config stb0899_config = {
+ .init_dev = pctv452e_init_dev,
+ .init_s2_demod = stb0899_s2_init_2,
+ .init_s1_demod = pctv452e_init_s1_demod,
+ .init_s2_fec = stb0899_s2_init_4,
+ .init_tst = stb0899_s1_init_5,
+
+ .demod_address = I2C_ADDR_STB0899, /* I2C Address */
+ .block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+ .xtal_freq = 27000000, /* Assume Hz ? */
+ .inversion = IQ_SWAP_ON, /* ? */
+
+ .lo_clk = 76500000,
+ .hi_clk = 99000000,
+
+ .ts_output_mode = 0, /* Use parallel mode */
+ .clock_polarity = 0,
+ .data_clk_parity = 0,
+ .fec_mode = 0,
+
+ .esno_ave = STB0899_DVBS2_ESNO_AVE,
+ .esno_quant = STB0899_DVBS2_ESNO_QUANT,
+ .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
+ .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
+ .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
+ .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+ .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+ .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+ .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+ .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
+ .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+ .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
+ .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .tuner_set_rfsiggain = NULL,
+
+ /* helper for switching LED green/orange */
+ .postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+ .tuner_address = I2C_ADDR_STB6100,
+ .refclock = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+ .master_xfer = pctv452e_i2c_xfer,
+ .functionality = pctv452e_i2c_func
+};
+
+static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
+{
+ struct usb_device_id *id;
+
+ a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
+ &a->dev->i2c_adap);
+ if (!a->fe_adap[0].fe)
+ return -ENODEV;
+ if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
+ &a->dev->i2c_adap)) == 0)
+ err("Cannot attach lnbp22\n");
+
+ id = a->dev->desc->warm_ids[0];
+ if (USB_VID_TECHNOTREND == id->idVendor
+ && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+ /* Error ignored. */
+ tt3650_ci_init(a);
+
+ return 0;
+}
+
+static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
+{
+ if (!a->fe_adap[0].fe)
+ return -ENODEV;
+ if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
+ &a->dev->i2c_adap) == 0) {
+ err("%s failed\n", __func__);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct usb_device_id pctv452e_usb_table[] = {
+ {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+ {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+ {USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = sizeof(struct pctv452e_state),
+
+ .power_ctrl = pctv452e_power_ctrl,
+
+ .rc.core = {
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ .rc_query = pctv452e_rc_query,
+ .rc_interval = 100,
+ },
+
+ .num_adapters = 1,
+ .adapter = {{
+ .num_frontends = 1,
+ .fe = {{
+ .frontend_attach = pctv452e_frontend_attach,
+ .tuner_attach = pctv452e_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_ISOC,
+ .count = 4,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 4,
+ .framesize = 940,
+ .interval = 1
+ }
+ }
+ },
+ } },
+ } },
+
+ .i2c_algo = &pctv452e_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "PCTV HDTV USB",
+ .cold_ids = { NULL, NULL }, /* this is a warm only device */
+ .warm_ids = { &pctv452e_usb_table[0], NULL }
+ },
+ { 0 },
+ }
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = sizeof(struct pctv452e_state),
+
+ .power_ctrl = pctv452e_power_ctrl,
+ .read_mac_address = pctv452e_read_mac_address,
+
+ .rc.core = {
+ .rc_codes = RC_MAP_TT_1500,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ .rc_query = pctv452e_rc_query,
+ .rc_interval = 100,
+ },
+
+ .num_adapters = 1,
+ .adapter = {{
+ .num_frontends = 1,
+ .fe = {{
+ .frontend_attach = pctv452e_frontend_attach,
+ .tuner_attach = pctv452e_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_ISOC,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 4,
+ .framesize = 940,
+ .interval = 1
+ }
+ }
+ },
+
+ } },
+ } },
+
+ .i2c_algo = &pctv452e_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
+
+ .num_device_descs = 2,
+ .devices = {
+ { .name = "Technotrend TT Connect S2-3600",
+ .cold_ids = { NULL, NULL }, /* this is a warm only device */
+ .warm_ids = { &pctv452e_usb_table[1], NULL }
+ },
+ { .name = "Technotrend TT Connect S2-3650-CI",
+ .cold_ids = { NULL, NULL },
+ .warm_ids = { &pctv452e_usb_table[2], NULL }
+ },
+ { 0 },
+ }
+};
+
+static void pctv452e_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+ tt3650_ci_uninit(d);
+ dvb_usb_device_exit(intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
+ THIS_MODULE, NULL, adapter_nr))
+ return 0;
+
+ return -ENODEV;
+}
+
+static struct usb_driver pctv452e_usb_driver = {
+ .name = "pctv452e",
+ .probe = pctv452e_usb_probe,
+ .disconnect = pctv452e_usb_disconnect,
+ .id_table = pctv452e_usb_table,
+};
+
+module_usb_driver(pctv452e_usb_driver);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index acefaa89cc53..acefaa89cc53 100644
--- a/drivers/media/dvb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index e53a1061cb8e..e53a1061cb8e 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/usb/dvb-usb/ttusb2.h
index 52a63af40896..52a63af40896 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.h
+++ b/drivers/media/usb/dvb-usb/ttusb2.h
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c
index 9b042292e788..9b042292e788 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/usb/dvb-usb/umt-010.c
diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/usb/dvb-usb/usb-urb.c
index d62ee0f5a165..d62ee0f5a165 100644
--- a/drivers/media/dvb/dvb-usb/usb-urb.c
+++ b/drivers/media/usb/dvb-usb/usb-urb.c
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c
index 5eab468dd904..5eab468dd904 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/usb/dvb-usb/vp702x-fe.c
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c
index 07c673a6e764..07c673a6e764 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/usb/dvb-usb/vp702x.c
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/usb/dvb-usb/vp702x.h
index 20b90055e7ac..20b90055e7ac 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/usb/dvb-usb/vp702x.h
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c
index b8825b18c003..b8825b18c003 100644
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/usb/dvb-usb/vp7045-fe.c
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c
index d750724132ee..d750724132ee 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/usb/dvb-usb/vp7045.c
diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/usb/dvb-usb/vp7045.h
index cf5ec46f8bb1..cf5ec46f8bb1 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.h
+++ b/drivers/media/usb/dvb-usb/vp7045.h
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
new file mode 100644
index 000000000000..7a5bd61bd3bb
--- /dev/null
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -0,0 +1,58 @@
+config VIDEO_EM28XX
+ tristate "Empia EM28xx USB video capture support"
+ depends on VIDEO_DEV && I2C
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEOBUF_VMALLOC
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT
+
+ ---help---
+ This is a video4linux driver for Empia 28xx based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called em28xx
+
+config VIDEO_EM28XX_ALSA
+ depends on VIDEO_EM28XX && SND
+ select SND_PCM
+ tristate "Empia EM28xx ALSA audio module"
+ ---help---
+ This is an ALSA driver for some Empia 28xx based TV cards.
+
+ This is not required for em2800/em2820/em2821 boards. However,
+ newer em28xx devices uses Vendor Class for audio, instead of
+ implementing the USB Audio Class. For those chips, this module
+ will enable digital audio.
+
+ To compile this driver as a module, choose M here: the
+ module will be called em28xx-alsa
+
+config VIDEO_EM28XX_DVB
+ tristate "DVB/ATSC Support for em28xx based TV cards"
+ depends on VIDEO_EM28XX && DVB_CORE
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRXD if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEOBUF_DVB
+ ---help---
+ This adds support for DVB cards based on the
+ Empiatech em28xx chips.
+
+config VIDEO_EM28XX_RC
+ tristate "EM28XX Remote Controller support"
+ depends on RC_CORE
+ depends on VIDEO_EM28XX
+ depends on !(RC_CORE=m && VIDEO_EM28XX=y)
+ default VIDEO_EM28XX
+ ---help---
+ Enables Remote Controller support on em28xx driver.
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
new file mode 100644
index 000000000000..634fb920dd39
--- /dev/null
+++ b/drivers/media/usb/em28xx/Makefile
@@ -0,0 +1,15 @@
+em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o
+em28xx-y += em28xx-core.o em28xx-vbi.o
+
+em28xx-alsa-objs := em28xx-audio.o
+em28xx-rc-objs := em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
+obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
new file mode 100644
index 000000000000..2fdb66ee44ab
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -0,0 +1,751 @@
+/*
+ * Empiatech em28x1 audio extension
+ *
+ * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
+ *
+ * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * - Port to work with the in-kernel driver
+ * - Cleanups, fixes, alsa-controls, etc.
+ *
+ * This driver is based on my previous au600 usb pstn audio driver
+ * and inherits all the copyrights
+ *
+ * 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/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/ac97_codec.h>
+#include <media/v4l2-common.h>
+#include "em28xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do { \
+ if (debug) \
+ printk(KERN_INFO "em28xx-audio %s: " fmt, \
+ __func__, ##arg); \
+ } while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int em28xx_deinit_isoc_audio(struct em28xx *dev)
+{
+ int i;
+
+ dprintk("Stopping isoc\n");
+ for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ if (!irqs_disabled())
+ usb_kill_urb(dev->adev.urb[i]);
+ else
+ usb_unlink_urb(dev->adev.urb[i]);
+
+ usb_free_urb(dev->adev.urb[i]);
+ dev->adev.urb[i] = NULL;
+
+ kfree(dev->adev.transfer_buffer[i]);
+ dev->adev.transfer_buffer[i] = NULL;
+ }
+
+ return 0;
+}
+
+static void em28xx_audio_isocirq(struct urb *urb)
+{
+ struct em28xx *dev = urb->context;
+ int i;
+ unsigned int oldptr;
+ int period_elapsed = 0;
+ int status;
+ unsigned char *cp;
+ unsigned int stride;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dprintk("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ if (atomic_read(&dev->stream_started) == 0)
+ return;
+
+ if (dev->adev.capture_pcm_substream) {
+ substream = dev->adev.capture_pcm_substream;
+ runtime = substream->runtime;
+ stride = runtime->frame_bits >> 3;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int length =
+ urb->iso_frame_desc[i].actual_length / stride;
+ cp = (unsigned char *)urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+
+ if (!length)
+ continue;
+
+ oldptr = dev->adev.hwptr_done_capture;
+ if (oldptr + length >= runtime->buffer_size) {
+ unsigned int cnt =
+ runtime->buffer_size - oldptr;
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ cnt * stride);
+ memcpy(runtime->dma_area, cp + cnt * stride,
+ length * stride - cnt * stride);
+ } else {
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ length * stride);
+ }
+
+ snd_pcm_stream_lock(substream);
+
+ dev->adev.hwptr_done_capture += length;
+ if (dev->adev.hwptr_done_capture >=
+ runtime->buffer_size)
+ dev->adev.hwptr_done_capture -=
+ runtime->buffer_size;
+
+ dev->adev.capture_transfer_done += length;
+ if (dev->adev.capture_transfer_done >=
+ runtime->period_size) {
+ dev->adev.capture_transfer_done -=
+ runtime->period_size;
+ period_elapsed = 1;
+ }
+
+ snd_pcm_stream_unlock(substream);
+ }
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+ }
+ urb->status = 0;
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
+ status);
+ }
+ return;
+}
+
+static int em28xx_init_audio_isoc(struct em28xx *dev)
+{
+ int i, errCode;
+ const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+ EM28XX_AUDIO_MAX_PACKET_SIZE;
+
+ dprintk("Starting isoc transfers\n");
+
+ for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ struct urb *urb;
+ int j, k;
+
+ dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+ if (!dev->adev.transfer_buffer[i])
+ return -ENOMEM;
+
+ memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
+ urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+ if (!urb) {
+ em28xx_errdev("usb_alloc_urb failed!\n");
+ for (j = 0; j < i; j++) {
+ usb_free_urb(dev->adev.urb[j]);
+ kfree(dev->adev.transfer_buffer[j]);
+ }
+ return -ENOMEM;
+ }
+
+ urb->dev = dev->udev;
+ urb->context = dev;
+ 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;
+ urb->complete = em28xx_audio_isocirq;
+ urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+ urb->transfer_buffer_length = sb_size;
+
+ for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+ j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ EM28XX_AUDIO_MAX_PACKET_SIZE;
+ }
+ dev->adev.urb[i] = urb;
+ }
+
+ for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+ if (errCode) {
+ em28xx_errdev("submit of audio urb failed\n");
+ em28xx_deinit_isoc_audio(dev);
+ atomic_set(&dev->stream_started, 0);
+ return errCode;
+ }
+
+ }
+
+ return 0;
+}
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+static struct snd_pcm_hardware snd_em28xx_hw_capture = {
+ .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_MMAP_VALID,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
+ .period_bytes_min = 64, /* 12544/2, */
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 98, /* 12544, */
+};
+
+static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret = 0;
+
+ dprintk("opening device and trying to acquire exclusive lock\n");
+
+ if (!dev) {
+ em28xx_err("BUG: em28xx can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
+ runtime->hw = snd_em28xx_hw_capture;
+ if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
+ if (dev->audio_ifnum)
+ dev->alt = 1;
+ else
+ dev->alt = 7;
+
+ dprintk("changing alternate number on interface %d to %d\n",
+ dev->audio_ifnum, dev->alt);
+ usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
+
+ /* Sets volume, mute, etc */
+ dev->mute = 0;
+ mutex_lock(&dev->lock);
+ ret = em28xx_audio_analog_set(dev);
+ if (ret < 0)
+ goto err;
+
+ dev->adev.users++;
+ mutex_unlock(&dev->lock);
+ }
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ dev->adev.capture_pcm_substream = substream;
+
+ return 0;
+err:
+ mutex_unlock(&dev->lock);
+
+ em28xx_err("Error while configuring em28xx mixer\n");
+ return ret;
+}
+
+static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ dprintk("closing device\n");
+
+ dev->mute = 1;
+ mutex_lock(&dev->lock);
+ dev->adev.users--;
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
+
+ em28xx_audio_analog_set(dev);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int ret;
+
+ dprintk("Setting capture parameters\n");
+
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0)
+ return ret;
+#if 0
+ /* TODO: set up em28xx audio chip to deliver the correct audio format,
+ current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono */
+ unsigned int channels, rate, format;
+
+ format = params_format(hw_params);
+ rate = params_rate(hw_params);
+ channels = params_channels(hw_params);
+#endif
+
+ return 0;
+}
+
+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ dprintk("Stop capture, if needed\n");
+
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
+
+ return 0;
+}
+
+static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ dev->adev.hwptr_done_capture = 0;
+ dev->adev.capture_transfer_done = 0;
+
+ return 0;
+}
+
+static void audio_trigger(struct work_struct *work)
+{
+ struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+
+ if (atomic_read(&dev->stream_started)) {
+ dprintk("starting capture");
+ em28xx_init_audio_isoc(dev);
+ } else {
+ dprintk("stopping capture");
+ em28xx_deinit_isoc_audio(dev);
+ }
+}
+
+static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+ int retval = 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(&dev->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(&dev->stream_started, 0);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ schedule_work(&dev->wq_trigger);
+ return retval;
+}
+
+static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
+ *substream)
+{
+ unsigned long flags;
+ struct em28xx *dev;
+ snd_pcm_uframes_t hwptr_done;
+
+ dev = snd_pcm_substream_chip(substream);
+ spin_lock_irqsave(&dev->adev.slock, flags);
+ hwptr_done = dev->adev.hwptr_done_capture;
+ spin_unlock_irqrestore(&dev->adev.slock, flags);
+
+ return hwptr_done;
+}
+
+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);
+}
+
+/*
+ * AC97 volume control support
+ */
+static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 0;
+ info->value.integer.max = 0x1f;
+
+ return 0;
+}
+
+static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
+ (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+ int rc;
+
+ mutex_lock(&dev->lock);
+ rc = em28xx_read_ac97(dev, kcontrol->private_value);
+ if (rc < 0)
+ goto err;
+
+ val |= rc & 0x8000; /* Preserve the mute flag */
+
+ rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
+ if (rc < 0)
+ goto err;
+
+ dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+ (val & 0x8000) ? "muted " : "",
+ 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+ val, (int)kcontrol->private_value);
+
+err:
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ int val;
+
+ mutex_lock(&dev->lock);
+ val = em28xx_read_ac97(dev, kcontrol->private_value);
+ mutex_unlock(&dev->lock);
+ if (val < 0)
+ return val;
+
+ dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+ (val & 0x8000) ? "muted " : "",
+ 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+ val, (int)kcontrol->private_value);
+
+ value->value.integer.value[0] = 0x1f - (val & 0x1f);
+ value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
+
+ return 0;
+}
+
+static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ u16 val = value->value.integer.value[0];
+ int rc;
+
+ mutex_lock(&dev->lock);
+ rc = em28xx_read_ac97(dev, kcontrol->private_value);
+ if (rc < 0)
+ goto err;
+
+ if (val)
+ rc &= 0x1f1f;
+ else
+ rc |= 0x8000;
+
+ rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
+ if (rc < 0)
+ goto err;
+
+ dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+ (val & 0x8000) ? "muted " : "",
+ 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+ val, (int)kcontrol->private_value);
+
+err:
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ int val;
+
+ mutex_lock(&dev->lock);
+ val = em28xx_read_ac97(dev, kcontrol->private_value);
+ mutex_unlock(&dev->lock);
+ if (val < 0)
+ return val;
+
+ if (val & 0x8000)
+ value->value.integer.value[0] = 0;
+ else
+ value->value.integer.value[0] = 1;
+
+ dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+ (val & 0x8000) ? "muted " : "",
+ 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+ val, (int)kcontrol->private_value);
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
+
+static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
+ char *name, int id)
+{
+ int err;
+ char ctl_name[44];
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new tmp;
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ tmp.private_value = id,
+ tmp.name = ctl_name,
+
+ /* Add Mute Control */
+ sprintf(ctl_name, "%s Switch", name);
+ tmp.get = em28xx_vol_get_mute;
+ tmp.put = em28xx_vol_put_mute;
+ tmp.info = snd_ctl_boolean_mono_info;
+ kctl = snd_ctl_new1(&tmp, dev);
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+ dprintk("Added control %s for ac97 volume control 0x%04x\n",
+ ctl_name, id);
+
+ memset (&tmp, 0, sizeof(tmp));
+ tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ tmp.private_value = id,
+ tmp.name = ctl_name,
+
+ /* Add Volume Control */
+ sprintf(ctl_name, "%s Volume", name);
+ tmp.get = em28xx_vol_get;
+ tmp.put = em28xx_vol_put;
+ tmp.info = em28xx_vol_info;
+ tmp.tlv.p = em28xx_db_scale,
+ kctl = snd_ctl_new1(&tmp, dev);
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+ dprintk("Added control %s for ac97 volume control 0x%04x\n",
+ ctl_name, id);
+
+ return 0;
+}
+
+/*
+ * register/unregister code and data
+ */
+static struct snd_pcm_ops snd_em28xx_pcm_capture = {
+ .open = snd_em28xx_capture_open,
+ .close = snd_em28xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_em28xx_hw_capture_params,
+ .hw_free = snd_em28xx_hw_capture_free,
+ .prepare = snd_em28xx_prepare,
+ .trigger = snd_em28xx_capture_trigger,
+ .pointer = snd_em28xx_capture_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+static int em28xx_audio_init(struct em28xx *dev)
+{
+ struct em28xx_audio *adev = &dev->adev;
+ struct snd_pcm *pcm;
+ struct snd_card *card;
+ static int devnr;
+ int err;
+
+ if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
+ return 0;
+ }
+
+ printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+ printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
+ "Rechberger\n");
+ printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+
+ err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
+ &card);
+ if (err < 0)
+ return err;
+
+ spin_lock_init(&adev->slock);
+ err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
+ pcm->info_flags = 0;
+ pcm->private_data = dev;
+ strcpy(pcm->name, "Empia 28xx Capture");
+
+ snd_card_set_dev(card, &dev->udev->dev);
+ strcpy(card->driver, "Em28xx-Audio");
+ strcpy(card->shortname, "Em28xx Audio");
+ strcpy(card->longname, "Empia Em28xx Audio");
+
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
+
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
+ em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
+ em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
+ em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
+ em28xx_cvol_new(card, dev, "CD", AC97_CD);
+ em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
+ em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
+
+ em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
+ em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
+ em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
+ em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
+ em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
+ }
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ adev->sndcard = card;
+ adev->udev = dev->udev;
+
+ return 0;
+}
+
+static int em28xx_audio_fini(struct em28xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (dev->has_alsa_audio != 1) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
+ return 0;
+ }
+
+ if (dev->adev.sndcard) {
+ snd_card_free(dev->adev.sndcard);
+ dev->adev.sndcard = NULL;
+ }
+
+ return 0;
+}
+
+static struct em28xx_ops audio_ops = {
+ .id = EM28XX_AUDIO,
+ .name = "Em28xx Audio Extension",
+ .init = em28xx_audio_init,
+ .fini = em28xx_audio_fini,
+};
+
+static int __init em28xx_alsa_register(void)
+{
+ return em28xx_register_extension(&audio_ops);
+}
+
+static void __exit em28xx_alsa_unregister(void)
+{
+ em28xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Em28xx Audio driver");
+
+module_init(em28xx_alsa_register);
+module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index ca62b9981380..ca62b9981380 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
new file mode 100644
index 000000000000..bed07a6c33f8
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -0,0 +1,1260 @@
+/*
+ em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ 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/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <sound/ac97_codec.h>
+#include <media/v4l2-common.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int reg_debug;
+module_param(reg_debug, int, 0644);
+MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+ if (reg_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
+
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len)
+{
+ int ret;
+ int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ if (len > URB_MAX_CTRL_SIZE)
+ return -EINVAL;
+
+ if (reg_debug) {
+ printk(KERN_DEBUG "(pipe 0x%08x): "
+ "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8);
+ }
+
+ mutex_lock(&dev->ctrl_urb_lock);
+ ret = usb_control_msg(dev->udev, pipe, req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, dev->urb_buf, len, HZ);
+ if (ret < 0) {
+ if (reg_debug)
+ printk(" failed!\n");
+ mutex_unlock(&dev->ctrl_urb_lock);
+ return ret;
+ }
+
+ if (len)
+ memcpy(buf, dev->urb_buf, len);
+
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ if (reg_debug) {
+ int byte;
+
+ printk("<<<");
+ for (byte = 0; byte < len; byte++)
+ printk(" %02x", (unsigned char)buf[byte]);
+ printk("\n");
+ }
+
+ return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+ int ret;
+ u8 val;
+
+ ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+ return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+EXPORT_SYMBOL_GPL(em28xx_read_reg);
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int len)
+{
+ int ret;
+ int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
+ if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+ return -EINVAL;
+
+ if (reg_debug) {
+ int byte;
+
+ printk(KERN_DEBUG "(pipe 0x%08x): "
+ "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8);
+
+ for (byte = 0; byte < len; byte++)
+ printk(" %02x", (unsigned char)buf[byte]);
+ printk("\n");
+ }
+
+ mutex_lock(&dev->ctrl_urb_lock);
+ memcpy(dev->urb_buf, buf, len);
+ ret = usb_control_msg(dev->udev, pipe, req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, dev->urb_buf, len, HZ);
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ if (dev->wait_after_write)
+ msleep(dev->wait_after_write);
+
+ return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+ int rc;
+
+ rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+ /* Stores GPO/GPIO values at the cache, if changed
+ Only write values should be stored, since input on a GPIO
+ register will return the input bits.
+ Not sure what happens on reading GPO register.
+ */
+ if (rc >= 0) {
+ if (reg == dev->reg_gpo_num)
+ dev->reg_gpo = buf[0];
+ else if (reg == dev->reg_gpio_num)
+ dev->reg_gpio = buf[0];
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_write_regs);
+
+/* Write a single register */
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
+{
+ return em28xx_write_regs(dev, reg, &val, 1);
+}
+EXPORT_SYMBOL_GPL(em28xx_write_reg);
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ u8 bitmask)
+{
+ int oldval;
+ u8 newval;
+
+ /* Uses cache for gpo/gpio registers */
+ if (reg == dev->reg_gpo_num)
+ oldval = dev->reg_gpo;
+ else if (reg == dev->reg_gpio_num)
+ oldval = dev->reg_gpio;
+ else
+ oldval = em28xx_read_reg(dev, reg);
+
+ if (oldval < 0)
+ return oldval;
+
+ newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
+ return em28xx_write_regs(dev, reg, &newval, 1);
+}
+EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
+
+/*
+ * em28xx_is_ac97_ready()
+ * Checks if ac97 is ready
+ */
+static int em28xx_is_ac97_ready(struct em28xx *dev)
+{
+ int ret, i;
+
+ /* Wait up to 50 ms for AC97 command to complete */
+ for (i = 0; i < 10; i++, msleep(5)) {
+ ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & 0x01))
+ return 0;
+ }
+
+ em28xx_warn("AC97 command still being executed: not handled properly!\n");
+ return -EBUSY;
+}
+
+/*
+ * em28xx_read_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_read_ac97(struct em28xx *dev, u8 reg)
+{
+ int ret;
+ u8 addr = (reg & 0x7f) | 0x80;
+ u16 val;
+
+ ret = em28xx_is_ac97_ready(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
+ (u8 *)&val, sizeof(val));
+
+ if (ret < 0)
+ return ret;
+ return le16_to_cpu(val);
+}
+EXPORT_SYMBOL_GPL(em28xx_read_ac97);
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
+{
+ int ret;
+ u8 addr = reg & 0x7f;
+ __le16 value;
+
+ value = cpu_to_le16(val);
+
+ ret = em28xx_is_ac97_ready(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_write_ac97);
+
+struct em28xx_vol_itable {
+ enum em28xx_amux mux;
+ u8 reg;
+};
+
+static struct em28xx_vol_itable inputs[] = {
+ { EM28XX_AMUX_VIDEO, AC97_VIDEO },
+ { EM28XX_AMUX_LINE_IN, AC97_LINE },
+ { EM28XX_AMUX_PHONE, AC97_PHONE },
+ { EM28XX_AMUX_MIC, AC97_MIC },
+ { EM28XX_AMUX_CD, AC97_CD },
+ { EM28XX_AMUX_AUX, AC97_AUX },
+ { EM28XX_AMUX_PCM_OUT, AC97_PCM },
+};
+
+static int set_ac97_input(struct em28xx *dev)
+{
+ int ret, i;
+ enum em28xx_amux amux = dev->ctl_ainput;
+
+ /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+ em28xx should point to LINE IN, while AC97 should use VIDEO
+ */
+ if (amux == EM28XX_AMUX_VIDEO2)
+ amux = EM28XX_AMUX_VIDEO;
+
+ /* Mute all entres but the one that were selected */
+ for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+ if (amux == inputs[i].mux)
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+ else
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
+
+ if (ret < 0)
+ em28xx_warn("couldn't setup AC97 register %d\n",
+ inputs[i].reg);
+ }
+ return 0;
+}
+
+static int em28xx_set_audio_source(struct em28xx *dev)
+{
+ int ret;
+ u8 input;
+
+ if (dev->board.is_em2800) {
+ if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
+ input = EM2800_AUDIO_SRC_TUNER;
+ else
+ input = EM2800_AUDIO_SRC_LINE;
+
+ ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (dev->board.has_msp34xx)
+ input = EM28XX_AUDIO_SRC_TUNER;
+ else {
+ switch (dev->ctl_ainput) {
+ case EM28XX_AMUX_VIDEO:
+ input = EM28XX_AUDIO_SRC_TUNER;
+ break;
+ default:
+ input = EM28XX_AUDIO_SRC_LINE;
+ break;
+ }
+ }
+
+ if (dev->board.mute_gpio && dev->mute)
+ em28xx_gpio_set(dev, dev->board.mute_gpio);
+ else
+ em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
+ if (ret < 0)
+ return ret;
+ msleep(5);
+
+ switch (dev->audio_mode.ac97) {
+ case EM28XX_NO_AC97:
+ break;
+ default:
+ ret = set_ac97_input(dev);
+ }
+
+ return ret;
+}
+
+struct em28xx_vol_otable {
+ enum em28xx_aout mux;
+ u8 reg;
+};
+
+static const struct em28xx_vol_otable outputs[] = {
+ { EM28XX_AOUT_MASTER, AC97_MASTER },
+ { EM28XX_AOUT_LINE, AC97_HEADPHONE },
+ { EM28XX_AOUT_MONO, AC97_MASTER_MONO },
+ { EM28XX_AOUT_LFE, AC97_CENTER_LFE_MASTER },
+ { EM28XX_AOUT_SURR, AC97_SURROUND_MASTER },
+};
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+ int ret, i;
+ u8 xclk;
+
+ if (!dev->audio_mode.has_audio)
+ return 0;
+
+ /* It is assumed that all devices use master volume for output.
+ It would be possible to use also line output.
+ */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ /* Mute all outputs */
+ for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+ ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
+ if (ret < 0)
+ em28xx_warn("couldn't setup AC97 register %d\n",
+ outputs[i].reg);
+ }
+ }
+
+ xclk = dev->board.xclk & 0x7f;
+ if (!dev->mute)
+ xclk |= EM28XX_XCLK_AUDIO_UNMUTE;
+
+ ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
+ if (ret < 0)
+ return ret;
+ msleep(10);
+
+ /* Selects the proper audio input */
+ ret = em28xx_set_audio_source(dev);
+
+ /* Sets volume */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ int vol;
+
+ em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200);
+ em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031);
+ em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80);
+
+ /* LSB: left channel - both channels with the same level */
+ vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
+
+ /* Mute device, if needed */
+ if (dev->mute)
+ vol |= 0x8000;
+
+ /* Sets volume */
+ for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+ if (dev->ctl_aoutput & outputs[i].mux)
+ ret = em28xx_write_ac97(dev, outputs[i].reg,
+ vol);
+ if (ret < 0)
+ em28xx_warn("couldn't setup AC97 register %d\n",
+ outputs[i].reg);
+ }
+
+ if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
+ int sel = ac97_return_record_select(dev->ctl_aoutput);
+
+ /* Use the same input for both left and right
+ channels */
+ sel |= (sel << 8);
+
+ em28xx_write_ac97(dev, AC97_REC_SEL, sel);
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
+
+int em28xx_audio_setup(struct em28xx *dev)
+{
+ int vid1, vid2, feat, cfg;
+ u32 vid;
+
+ if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
+ || dev->chip_id == CHIP_ID_EM28174) {
+ /* Digital only device - don't load any alsa module */
+ dev->audio_mode.has_audio = false;
+ dev->has_audio_class = false;
+ dev->has_alsa_audio = false;
+ return 0;
+ }
+
+ dev->audio_mode.has_audio = true;
+
+ /* See how this device is configured */
+ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
+ em28xx_info("Config register raw data: 0x%02x\n", cfg);
+ if (cfg < 0) {
+ /* Register read error? */
+ cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
+ /* The device doesn't have vendor audio at all */
+ dev->has_alsa_audio = false;
+ dev->audio_mode.has_audio = false;
+ return 0;
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+ em28xx_info("I2S Audio (3 sample rates)\n");
+ dev->audio_mode.i2s_3rates = 1;
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+ em28xx_info("I2S Audio (5 sample rates)\n");
+ dev->audio_mode.i2s_5rates = 1;
+ }
+
+ if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ /* Skip the code that does AC97 vendor detection */
+ dev->audio_mode.ac97 = EM28XX_NO_AC97;
+ goto init_audio;
+ }
+
+ dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
+
+ vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
+ if (vid1 < 0) {
+ /*
+ * Device likely doesn't support AC97
+ * Note: (some) em2800 devices without eeprom reports 0x91 on
+ * CHIPCFG register, even not having an AC97 chip
+ */
+ em28xx_warn("AC97 chip type couldn't be determined\n");
+ dev->audio_mode.ac97 = EM28XX_NO_AC97;
+ dev->has_alsa_audio = false;
+ dev->audio_mode.has_audio = false;
+ goto init_audio;
+ }
+
+ vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
+ if (vid2 < 0)
+ goto init_audio;
+
+ vid = vid1 << 16 | vid2;
+
+ dev->audio_mode.ac97_vendor_id = vid;
+ em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
+
+ feat = em28xx_read_ac97(dev, AC97_RESET);
+ if (feat < 0)
+ goto init_audio;
+
+ dev->audio_mode.ac97_feat = feat;
+ em28xx_warn("AC97 features = 0x%04x\n", feat);
+
+ /* Try to identify what audio processor we have */
+ 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;
+
+init_audio:
+ /* Reports detected AC97 processor */
+ switch (dev->audio_mode.ac97) {
+ case EM28XX_NO_AC97:
+ em28xx_info("No AC97 audio processor\n");
+ break;
+ case EM28XX_AC97_EM202:
+ em28xx_info("Empia 202 AC97 audio processor detected\n");
+ break;
+ case EM28XX_AC97_SIGMATEL:
+ em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
+ dev->audio_mode.ac97_vendor_id & 0xff);
+ break;
+ case EM28XX_AC97_OTHER:
+ em28xx_warn("Unknown AC97 audio processor detected!\n");
+ break;
+ default:
+ break;
+ }
+
+ return em28xx_audio_analog_set(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_setup);
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+
+ em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+ em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+ return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+ int rc;
+
+ if (dev->chip_id == CHIP_ID_EM2874 ||
+ dev->chip_id == CHIP_ID_EM2884 ||
+ dev->chip_id == CHIP_ID_EM28174) {
+ /* The Transport Stream Enable Register moved in em2874 */
+ if (!start) {
+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+ 0x00,
+ EM2874_TS1_CAPTURE_ENABLE);
+ return rc;
+ }
+
+ /* Enable Transport Stream */
+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+ EM2874_TS1_CAPTURE_ENABLE,
+ EM2874_TS1_CAPTURE_ENABLE);
+ return rc;
+ }
+
+
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+ start ? 0x10 : 0x00, 0x10);
+ if (rc < 0)
+ return rc;
+
+ if (!start) {
+ /* disable video capture */
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+ return rc;
+ }
+
+ if (dev->board.is_webcam)
+ rc = em28xx_write_reg(dev, 0x13, 0x0c);
+
+ /* enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+ else
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+
+ msleep(6);
+
+ return rc;
+}
+
+int em28xx_vbi_supported(struct em28xx *dev)
+{
+ /* Modprobe option to manually disable */
+ if (disable_vbi == 1)
+ return 0;
+
+ if (dev->chip_id == CHIP_ID_EM2860 ||
+ dev->chip_id == CHIP_ID_EM2883)
+ return 1;
+
+ /* Version of em28xx that does not support VBI */
+ return 0;
+}
+
+int em28xx_set_outfmt(struct em28xx *dev)
+{
+ int ret;
+ u8 vinctrl;
+
+ ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+ dev->format->reg | 0x20, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+ if (ret < 0)
+ return ret;
+
+ vinctrl = dev->vinctl;
+ if (em28xx_vbi_supported(dev) == 1) {
+ vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+ em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+ }
+ }
+
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+ u8 ymin, u8 ymax)
+{
+ em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
+
+ em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+ em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+ em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+ return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height)
+{
+ u8 cwidth = width;
+ u8 cheight = height;
+ u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+ (width | (overflow & 2) << 7),
+ (height | (overflow & 1) << 8));
+
+ em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+ em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+ return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+ u8 mode;
+ /* the em2800 scaler only supports scaling down to 50% */
+
+ if (dev->board.is_em2800) {
+ mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+ } else {
+ u8 buf[2];
+
+ buf[0] = h;
+ buf[1] = h >> 8;
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+ buf[0] = v;
+ buf[1] = v >> 8;
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
+ mode = (h || v) ? 0x30 : 0x00;
+ }
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+ int width, height;
+ width = norm_maxw(dev);
+ height = norm_maxh(dev);
+
+ /* Properly setup VBI */
+ dev->vbi_width = 720;
+ if (dev->norm & V4L2_STD_525_60)
+ dev->vbi_height = 12;
+ else
+ dev->vbi_height = 18;
+
+ em28xx_set_outfmt(dev);
+
+ em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+ /* If we don't set the start position to 2 in VBI mode, we end up
+ with line 20/21 being YUYV encoded instead of being in 8-bit
+ greyscale. The core of the issue is that line 21 (and line 23 for
+ PAL WSS) are inside of active video region, and as a result they
+ get the pixelformatting associated with that area. So by cropping
+ it out, we end up with the same format as the rest of the VBI
+ region */
+ if (em28xx_vbi_supported(dev) == 1)
+ em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2);
+ else
+ em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+
+ return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+ int errCode, prev_alt = dev->alt;
+ int i;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
+
+ /*
+ * alt = 0 is used only for control messages, so, only values
+ * greater than 0 can be used for streaming.
+ */
+ if (alt && alt < dev->num_alt) {
+ em28xx_coredbg("alternate forced to %d\n", dev->alt);
+ dev->alt = alt;
+ goto set_alt;
+ }
+
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+ dev->alt = i;
+ break;
+ /* otherwise make sure that we end up with the maximum bandwidth
+ because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size[i] >
+ dev->alt_max_pkt_size[dev->alt])
+ dev->alt = i;
+ }
+
+set_alt:
+ if (dev->alt != prev_alt) {
+ em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
+ }
+ }
+ return 0;
+}
+
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+{
+ int rc = 0;
+
+ if (!gpio)
+ return rc;
+
+ if (dev->mode != EM28XX_SUSPEND) {
+ em28xx_write_reg(dev, 0x48, 0x00);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+ else
+ em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+ msleep(6);
+ }
+
+ /* Send GPIO reset sequences specified at board entry */
+ while (gpio->sleep >= 0) {
+ if (gpio->reg >= 0) {
+ rc = em28xx_write_reg_bits(dev,
+ gpio->reg,
+ gpio->val,
+ gpio->mask);
+ if (rc < 0)
+ return rc;
+ }
+ if (gpio->sleep > 0)
+ msleep(gpio->sleep);
+
+ gpio++;
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_gpio_set);
+
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
+{
+ if (dev->mode == set_mode)
+ return 0;
+
+ if (set_mode == EM28XX_SUSPEND) {
+ dev->mode = set_mode;
+
+ /* FIXME: add suspend support for ac97 */
+
+ return em28xx_gpio_set(dev, dev->board.suspend_gpio);
+ }
+
+ dev->mode = set_mode;
+
+ if (dev->mode == EM28XX_DIGITAL_MODE)
+ return em28xx_gpio_set(dev, dev->board.dvb_gpio);
+ else
+ return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
+}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void em28xx_irq_callback(struct urb *urb)
+{
+ struct em28xx *dev = urb->context;
+ int i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ em28xx_isocdbg("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->slock);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ urb->status = 0;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+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 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;
+
+ 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 (isoc_bufs->transfer_buffer[i]) {
+ usb_free_coherent(dev->udev,
+ urb->transfer_buffer_length,
+ isoc_bufs->transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ isoc_bufs->urb[i] = NULL;
+ }
+ isoc_bufs->transfer_buffer[i] = NULL;
+ }
+
+ kfree(isoc_bufs->urb);
+ kfree(isoc_bufs->transfer_buffer);
+
+ 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);
+
+/*
+ * Stop URBs
+ */
+void em28xx_stop_urbs(struct em28xx *dev)
+{
+ int i;
+ struct urb *urb;
+ struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
+
+ em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+
+ 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);
+ }
+ }
+
+ em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
+
+/*
+ * Allocate URBs
+ */
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+ int max_packets, int num_bufs, int max_pkt_size)
+{
+ struct em28xx_usb_isoc_bufs *isoc_bufs;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+
+ 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, mode);
+
+ isoc_bufs->num_bufs = num_bufs;
+
+ 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;
+ }
+
+ 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(isoc_bufs->urb);
+ return -ENOMEM;
+ }
+
+ 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 = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ 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, mode);
+ return -ENOMEM;
+ }
+ isoc_bufs->urb[i] = urb;
+
+ isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ 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, mode);
+ return -ENOMEM;
+ }
+ 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,
+ mode == EM28XX_ANALOG_MODE ?
+ EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
+
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ isoc_bufs->transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dev, 1);
+
+ 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 < isoc_bufs->num_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ 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 < 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, mode);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ INPUT(dev->ctl_input)->vmux, 0, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+/*
+ * Device control list
+ */
+
+static LIST_HEAD(em28xx_devlist);
+static DEFINE_MUTEX(em28xx_devlist_mutex);
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(em28xx_extension_devlist);
+
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+ struct em28xx *dev = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_add_tail(&ops->next, &em28xx_extension_devlist);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ ops->init(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+ return 0;
+}
+EXPORT_SYMBOL(em28xx_register_extension);
+
+void em28xx_unregister_extension(struct em28xx_ops *ops)
+{
+ struct em28xx *dev = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ ops->fini(dev);
+ }
+ list_del(&ops->next);
+ mutex_unlock(&em28xx_devlist_mutex);
+ printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
+
+void em28xx_init_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_add_tail(&dev->devlist, &em28xx_devlist);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+}
+
+void em28xx_close_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
+ }
+ list_del(&dev->devlist);
+ mutex_unlock(&em28xx_devlist_mutex);
+}
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a16531fa937a..a16531fa937a 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 1683bd9d51ee..1683bd9d51ee 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 97d36b4f19db..97d36b4f19db 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 6ff368297f6e..6ff368297f6e 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 2b4c9cba2d67..2b4c9cba2d67 100644
--- a/drivers/media/video/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
new file mode 100644
index 000000000000..78d6ebd712b9
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -0,0 +1,2624 @@
+/*
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
+ Sascha Sommer <saschasommer@freenet.de>
+
+ Some parts based on SN9C10x PC Camera Controllers GPL driver made
+ by Luca Risolia <luca.risolia@studio.unibo.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/msp3400.h>
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_DESC "Empia em28xx based USB video device driver"
+
+#define EM28XX_VERSION "0.1.3"
+
+#define em28xx_videodbg(fmt, arg...) do {\
+ if (video_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+ {
+ .name = "16 bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .reg = EM28XX_OUTFMT_YUV422_Y0UY1V,
+ }, {
+ .name = "16 bpp RGB 565, LE",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .reg = EM28XX_OUTFMT_RGB_16_656,
+ }, {
+ .name = "8 bpp Bayer BGBG..GRGR",
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .depth = 8,
+ .reg = EM28XX_OUTFMT_RGB_8_BGBG,
+ }, {
+ .name = "8 bpp Bayer GRGR..BGBG",
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = 8,
+ .reg = EM28XX_OUTFMT_RGB_8_GRGR,
+ }, {
+ .name = "8 bpp Bayer GBGB..RGRG",
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .depth = 8,
+ .reg = EM28XX_OUTFMT_RGB_8_GBGB,
+ }, {
+ .name = "12 bpp YUV411",
+ .fourcc = V4L2_PIX_FMT_YUV411P,
+ .depth = 12,
+ .reg = EM28XX_OUTFMT_YUV411,
+ },
+};
+
+/* supported controls */
+/* Common to all boards */
+static struct v4l2_queryctrl ac97_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x1f,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ }
+};
+
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vid_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vbi_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ remain = len;
+
+ if (dev->progressive)
+ fieldstart = outp;
+ else {
+ /* Interlaces two half frames */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+ }
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+
+ if (dev->progressive)
+ offset = linesdone * bytesperline + currlinedone;
+ else
+ offset = linesdone * bytesperline * 2 + currlinedone;
+
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ lencopy = remain;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp +
+ buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+ "(2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ dma_q->pos += len;
+}
+
+static void em28xx_copy_vbi(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *startwrite, *startread;
+ int offset;
+ int bytesperline;
+
+ if (dev == NULL) {
+ em28xx_isocdbg("dev is null\n");
+ return;
+ }
+ bytesperline = dev->vbi_width;
+
+ if (dma_q == NULL) {
+ em28xx_isocdbg("dma_q is null\n");
+ return;
+ }
+ if (buf == NULL) {
+ return;
+ }
+ if (p == NULL) {
+ em28xx_isocdbg("p is null\n");
+ return;
+ }
+ if (outp == NULL) {
+ em28xx_isocdbg("outp is null\n");
+ return;
+ }
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+
+ startwrite = outp + dma_q->pos;
+ offset = dma_q->pos;
+
+ /* Make sure the bottom field populates the second half of the frame */
+ if (buf->top_field == 0) {
+ startwrite += bytesperline * dev->vbi_height;
+ offset += bytesperline * dev->vbi_height;
+ }
+
+ memcpy(startwrite, startread, len);
+ dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vid_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ dev->isoc_ctl.vid_buf = *buf;
+
+ return;
+}
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vbi_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0x00, (*buf)->vb.size);
+
+ dev->isoc_ctl.vbi_buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf;
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ unsigned char *outp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.vid_buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* FIXME: incomplete buffer checks where removed to make
+ logic simpler. Impacts of those changes should be evaluated
+ */
+ if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+ em28xx_isocdbg("VBI HEADER!!!\n");
+ /* FIXME: Should add vbi copy */
+ continue;
+ }
+ if (p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+ len, (p[2] & 1) ? "odd" : "even");
+
+ if (dev->progressive || !(p[2] & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+
+ if (buf != NULL) {
+ if (p[2] & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL) {
+ if (p[0] != 0x88 && p[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ len += 4;
+ } else {
+ p += 4;
+ }
+ em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ }
+ return rc;
+}
+
+/* Version of isoc handler that takes into account a mixture of video and
+ VBI data */
+static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf, *vbi_buf;
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+ unsigned char *outp = NULL;
+ unsigned char *vbioutp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+ int vbi_size;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.vid_buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ vbi_buf = dev->isoc_ctl.vbi_buf;
+ if (vbi_buf != NULL)
+ vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length;
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* capture type 0 = vbi start
+ capture type 1 = video start
+ capture type 2 = video in progress */
+ if (p[0] == 0x33 && p[1] == 0x95) {
+ dev->capture_type = 0;
+ dev->vbi_read = 0;
+ em28xx_isocdbg("VBI START HEADER!!!\n");
+ dev->cur_field = p[2];
+ p += 4;
+ len -= 4;
+ } else if (p[0] == 0x88 && p[1] == 0x88 &&
+ p[2] == 0x88 && p[3] == 0x88) {
+ /* continuation */
+ p += 4;
+ len -= 4;
+ } else if (p[0] == 0x22 && p[1] == 0x5a) {
+ /* start video */
+ p += 4;
+ len -= 4;
+ }
+
+ vbi_size = dev->vbi_width * dev->vbi_height;
+
+ if (dev->capture_type == 0) {
+ if (dev->vbi_read >= vbi_size) {
+ /* We've already read all the VBI data, so
+ treat the rest as video */
+ em28xx_isocdbg("dev->vbi_read > vbi_size\n");
+ } else if ((dev->vbi_read + len) < vbi_size) {
+ /* This entire frame is VBI data */
+ if (dev->vbi_read == 0 &&
+ (!(dev->cur_field & 1))) {
+ /* Brand new frame */
+ if (vbi_buf != NULL)
+ vbi_buffer_filled(dev,
+ vbi_dma_q,
+ vbi_buf);
+ vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+ if (vbi_buf == NULL)
+ vbioutp = NULL;
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
+ }
+
+ if (dev->vbi_read == 0) {
+ vbi_dma_q->pos = 0;
+ if (vbi_buf != NULL) {
+ if (dev->cur_field & 1)
+ vbi_buf->top_field = 0;
+ else
+ vbi_buf->top_field = 1;
+ }
+ }
+
+ dev->vbi_read += len;
+ em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, len);
+ } else {
+ /* Some of this frame is VBI data and some is
+ video data */
+ int vbi_data_len = vbi_size - dev->vbi_read;
+ dev->vbi_read += vbi_data_len;
+ em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, vbi_data_len);
+ dev->capture_type = 1;
+ p += vbi_data_len;
+ len -= vbi_data_len;
+ }
+ }
+
+ if (dev->capture_type == 1) {
+ dev->capture_type = 2;
+ if (dev->progressive || !(dev->cur_field & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+ if (buf != NULL) {
+ if (dev->cur_field & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+
+ if (buf != NULL && dev->capture_type == 2) {
+ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
+ p[2] == 0x88 && p[3] == 0x88) {
+ p += 4;
+ len -= 4;
+ }
+ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, len=%i, %s\n",
+ p[2], len, (p[2] & 1) ?
+ "odd" : "even");
+ p += 4;
+ len -= 4;
+ }
+
+ if (len > 0)
+ em28xx_copy_video(dev, dma_q, buf, p, outp,
+ len);
+ }
+ }
+ return rc;
+}
+
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct v4l2_frequency f;
+
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
+ >> 3;
+
+ if (0 == *count)
+ *count = EM28XX_DEF_BUF;
+
+ if (*count < EM28XX_MIN_BUF)
+ *count = EM28XX_MIN_BUF;
+
+ /* Ask tuner to go to analog or radio mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+ f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.vid_buf == buf)
+ dev->isoc_ctl.vid_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+ + 7) >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ 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_ANALOG_MODE,
+ EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS,
+ dev->max_pkt_size,
+ em28xx_isoc_copy_vbi);
+ else
+ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+ EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS,
+ dev->max_pkt_size,
+ em28xx_isoc_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb,
+ struct em28xx_buffer,
+ vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb,
+ struct em28xx_buffer,
+ vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = (struct em28xx *)fh->dev;
+
+ em28xx_isocdbg("em28xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
+
+static void video_mux(struct em28xx *dev, int index)
+{
+ dev->ctl_input = index;
+ dev->ctl_ainput = INPUT(index)->amux;
+ dev->ctl_aoutput = INPUT(index)->aout;
+
+ if (!dev->ctl_aoutput)
+ dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ INPUT(index)->vmux, 0, 0);
+
+ if (dev->board.has_msp34xx) {
+ if (dev->i2s_speed) {
+ v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
+ s_i2s_clock_freq, dev->i2s_speed);
+ }
+ /* Note: this is msp3400 specific */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
+ }
+
+ if (dev->board.adecoder != EM28XX_NOADECODER) {
+ v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ dev->ctl_ainput, dev->ctl_aoutput, 0);
+ }
+
+ em28xx_audio_analog_set(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct em28xx_fh *fh, unsigned int bit)
+{
+ struct em28xx *dev = fh->dev;
+
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
+
+ /* is it free? */
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ em28xx_videodbg("res: get %d\n", bit);
+ return 1;
+}
+
+static int res_check(struct em28xx_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
+}
+
+static int res_locked(struct em28xx *dev, unsigned int bit)
+{
+ return dev->resources & bit;
+}
+
+static void res_free(struct em28xx_fh *fh, unsigned int bits)
+{
+ struct em28xx *dev = fh->dev;
+
+ BUG_ON((fh->resources & bits) != bits);
+
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ em28xx_videodbg("res: put %d\n", bits);
+}
+
+static int get_ressource(struct em28xx_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return EM28XX_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return EM28XX_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/*
+ * ac97_queryctrl()
+ * return the ac97 supported controls
+ */
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+
+ /* Control is not ac97 related */
+ return 1;
+}
+
+/*
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
+ */
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = dev->mute;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = dev->volume;
+ return 0;
+ default:
+ /* Control is not ac97 related */
+ return 1;
+ }
+}
+
+/*
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
+ */
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+ if (ctrl->id == ac97_qctrl[i].id)
+ goto handle;
+
+ /* Announce that hasn't handle it */
+ return 1;
+
+handle:
+ if (ctrl->value < ac97_qctrl[i].minimum ||
+ ctrl->value > ac97_qctrl[i].maximum)
+ return -ERANGE;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ dev->mute = ctrl->value;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ break;
+ }
+
+ return em28xx_audio_analog_set(dev);
+}
+
+static int check_dev(struct em28xx *dev)
+{
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_errdev("v4l2 ioctl: device not present\n");
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_errdev("v4l2 ioctl: device is misconfigured; "
+ "close and open it again\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static void get_scale(struct em28xx *dev,
+ unsigned int width, unsigned int height,
+ unsigned int *hscale, unsigned int *vscale)
+{
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+
+ *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
+ if (*hscale >= 0x4000)
+ *hscale = 0x3fff;
+
+ *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
+ if (*vscale >= 0x4000)
+ *vscale = 0x3fff;
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+ if (dev->progressive)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ else
+ f->fmt.pix.field = dev->interlaced ?
+ V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+ return 0;
+}
+
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return &format[i];
+
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ unsigned int width = f->fmt.pix.width;
+ unsigned int height = f->fmt.pix.height;
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+ unsigned int hscale, vscale;
+ struct em28xx_fmt *fmt;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (dev->board.is_em2800) {
+ /* 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 */
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
+ 1, 0);
+ }
+
+ get_scale(dev, width, height, &hscale, &vscale);
+
+ width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+ height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ f->fmt.pix.width = width;
+ f->fmt.pix.height = height;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ if (dev->progressive)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ else
+ f->fmt.pix.field = dev->interlaced ?
+ V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+
+ return 0;
+}
+
+static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
+ unsigned width, unsigned height)
+{
+ struct em28xx_fmt *fmt;
+
+ fmt = format_by_fourcc(fourcc);
+ if (!fmt)
+ return -EINVAL;
+
+ dev->format = fmt;
+ dev->width = width;
+ dev->height = height;
+
+ /* set new image size */
+ get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+ em28xx_set_alternate(dev);
+ em28xx_resolution_set(dev);
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ vidioc_try_fmt_vid_cap(file, priv, f);
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ em28xx_errdev("%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+ f->fmt.pix.width, f->fmt.pix.height);
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ *norm = dev->norm;
+
+ return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct v4l2_format f;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ dev->norm = *norm;
+
+ /* Adjusts width/height, if needed */
+ f.fmt.pix.width = dev->width;
+ f.fmt.pix.height = dev->height;
+ vidioc_try_fmt_vid_cap(file, priv, &f);
+
+ /* set new image size */
+ dev->width = f.fmt.pix.width;
+ dev->height = f.fmt.pix.height;
+ get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+ em28xx_resolution_set(dev);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *p)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc = 0;
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (dev->board.is_webcam)
+ rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+ video, g_parm, p);
+ else
+ v4l2_video_std_frame_period(dev->norm,
+ &p->parm.capture.timeperframe);
+
+ return rc;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *p)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ if (!dev->board.is_webcam)
+ return -EINVAL;
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
+}
+
+static const char *iname[] = {
+ [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+ [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+ [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+ [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+ [EM28XX_VMUX_SVIDEO] = "S-Video",
+ [EM28XX_VMUX_TELEVISION] = "Television",
+ [EM28XX_VMUX_CABLE] = "Cable TV",
+ [EM28XX_VMUX_DVB] = "DVB",
+ [EM28XX_VMUX_DEBUG] = "for debug only",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strcpy(i->name, iname[INPUT(n)->type]);
+
+ if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (EM28XX_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ i->std = dev->vdev->tvnorms;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ *i = dev->ctl_input;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (i >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(i)->type)
+ return -EINVAL;
+
+ video_mux(dev, i);
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ if (!dev->audio_mode.has_audio)
+ return -EINVAL;
+
+ switch (a->index) {
+ case EM28XX_AMUX_VIDEO:
+ strcpy(a->name, "Television");
+ break;
+ case EM28XX_AMUX_LINE_IN:
+ strcpy(a->name, "Line In");
+ break;
+ case EM28XX_AMUX_VIDEO2:
+ strcpy(a->name, "Television alt");
+ break;
+ case EM28XX_AMUX_PHONE:
+ strcpy(a->name, "Phone");
+ break;
+ case EM28XX_AMUX_MIC:
+ strcpy(a->name, "Mic");
+ break;
+ case EM28XX_AMUX_CD:
+ strcpy(a->name, "CD");
+ break;
+ case EM28XX_AMUX_AUX:
+ strcpy(a->name, "Aux");
+ break;
+ case EM28XX_AMUX_PCM_OUT:
+ strcpy(a->name, "PCM");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ a->index = dev->ctl_ainput;
+ a->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+
+ if (!dev->audio_mode.has_audio)
+ return -EINVAL;
+
+ if (a->index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(a->index)->type)
+ return -EINVAL;
+
+ dev->ctl_ainput = INPUT(a->index)->amux;
+ dev->ctl_aoutput = INPUT(a->index)->aout;
+
+ if (!dev->ctl_aoutput)
+ dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int id = qc->id;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ memset(qc, 0, sizeof(*qc));
+
+ qc->id = id;
+
+ /* enumerate AC97 controls */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ rc = ac97_queryctrl(qc);
+ if (!rc)
+ return 0;
+ }
+
+ /* enumerate V4L2 device controls */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
+
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+/*
+ * FIXME: This is an indirect way to check if a control exists at a
+ * subdev. Instead of that hack, maybe the better would be to change all
+ * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
+ */
+static int check_subdev_ctrl(struct em28xx *dev, int id)
+{
+ struct v4l2_queryctrl qc;
+
+ memset(&qc, 0, sizeof(qc));
+ qc.id = id;
+
+ /* enumerate V4L2 device controls */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
+
+ if (qc.type)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+ rc = 0;
+
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_get_ctrl(dev, ctrl);
+ else
+ rc = 1;
+
+ /* It were not an AC97 control. Sends it to the v4l2 dev interface */
+ if (rc == 1) {
+ if (check_subdev_ctrl(dev, ctrl->id))
+ return -EINVAL;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_set_ctrl(dev, ctrl);
+ else
+ rc = 1;
+
+ /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
+ if (rc == 1) {
+ rc = check_subdev_ctrl(dev, ctrl->id);
+ if (!rc)
+ v4l2_device_call_all(&dev->v4l2_dev, 0,
+ core, s_ctrl, ctrl);
+ /*
+ * In the case of non-AC97 volume controls, we still need
+ * to do some setups at em28xx, in order to mute/unmute
+ * and to adjust audio volume. However, the value ranges
+ * should be checked by the corresponding V4L subdriver.
+ */
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ dev->mute = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ }
+ }
+ return (rc < 0) ? rc : 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ 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;
+
+ dev->ctl_freq = f->frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int em28xx_reg_len(int reg)
+{
+ switch (reg) {
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+
+ return 0;
+}
+
+
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int ret;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ ret = em28xx_read_ac97(dev, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+ reg->size = 1;
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ /* Match host */
+ reg->size = em28xx_reg_len(reg->reg);
+ if (reg->size == 1) {
+ ret = em28xx_read_reg(dev, reg->reg);
+
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+ } else {
+ __le16 val = 0;
+ ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+ reg->reg, (char *)&val, 2);
+ if (ret < 0)
+ return ret;
+
+ reg->val = le16_to_cpu(val);
+ }
+
+ return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ __le16 buf;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ return em28xx_write_ac97(dev, reg->reg, reg->val);
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ /* Match host */
+ buf = cpu_to_le16(reg->val);
+
+ return em28xx_write_regs(dev, reg->reg, (char *)&buf,
+ em28xx_reg_len(reg->reg));
+}
+#endif
+
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc = -EINVAL;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (unlikely(type != fh->type))
+ return -EINVAL;
+
+ em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vidq);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vbiq);
+
+ return rc;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
+ return -EINVAL;
+
+ em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
+ }
+
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->capabilities =
+ V4L2_CAP_SLICED_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+ if (dev->vbi_dev)
+ cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+
+ if (dev->audio_mode.has_audio)
+ cap->capabilities |= V4L2_CAP_AUDIO;
+
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
+ return -EINVAL;
+
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+
+ return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_fmt *fmt;
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+
+ fmt = format_by_fourcc(fsize->pixel_format);
+ if (!fmt) {
+ em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ if (dev->board.is_em2800) {
+ if (fsize->index > 1)
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = maxw / (1 + fsize->index);
+ fsize->discrete.height = maxh / (1 + fsize->index);
+ return 0;
+ }
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ /* Report a continuous range */
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = 48;
+ fsize->stepwise.min_height = 32;
+ fsize->stepwise.max_width = maxw;
+ fsize->stepwise.max_height = maxh;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+ return 0;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ f->fmt.sliced.service_set = 0;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+ if (f->fmt.sliced.service_set == 0)
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
+
+ if (f->fmt.sliced.service_set == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
+
+ /* Varies by video standard (NTSC, PAL, etc.) */
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
+
+ /* Varies by video standard (NTSC, PAL, etc.) */
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
+
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+ else
+ return videobuf_reqbufs(&fh->vb_vbiq, rb);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_querybuf(&fh->vb_vidq, b);
+ else {
+ /* FIXME: I'm not sure yet whether this is a bug in zvbi or
+ the videobuf framework, but we probably shouldn't be
+ returning a buffer larger than that which was asked for.
+ At a minimum, it causes a crash in zvbi since it does
+ a memcpy based on the source buffer length */
+ int result = videobuf_querybuf(&fh->vb_vbiq, b);
+ b->length = dev->vbi_width * dev->vbi_height * 2;
+
+ return result;
+ }
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_qbuf(&fh->vb_vidq, b);
+ else
+ return videobuf_qbuf(&fh->vb_vbiq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
+ O_NONBLOCK);
+ else
+ return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
+ O_NONBLOCK);
+}
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+ if (unlikely(t->index > 0))
+ return -EINVAL;
+
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+ return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name, "Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
+
+ strcpy(a->name, "Radio");
+ return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+ return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ if (qc->id < V4L2_CID_BASE ||
+ qc->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct file *filp)
+{
+ int errCode = 0, radio = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct em28xx *dev = video_drvdata(filp);
+ enum v4l2_buf_type fh_type = 0;
+ struct em28xx_fh *fh;
+ enum v4l2_field field;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+ case VFL_TYPE_RADIO:
+ radio = 1;
+ break;
+ }
+
+ em28xx_videodbg("open dev=%s type=%s users=%d\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type],
+ dev->users);
+
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+ if (!fh) {
+ em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+ fh->dev = dev;
+ fh->radio = radio;
+ fh->type = fh_type;
+ filp->private_data = fh;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+ em28xx_set_alternate(dev);
+ em28xx_resolution_set(dev);
+
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_wake_i2c(dev);
+
+ }
+ if (fh->radio) {
+ em28xx_videodbg("video_open: setting radio device\n");
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+ }
+
+ dev->users++;
+
+ if (dev->progressive)
+ field = V4L2_FIELD_NONE;
+ else
+ field = V4L2_FIELD_INTERLACED;
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
+ sizeof(struct em28xx_buffer), fh, &dev->lock);
+
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct em28xx_buffer), fh, &dev->lock);
+ mutex_unlock(&dev->lock);
+
+ return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_release_analog_resources(struct em28xx *dev)
+{
+
+ /*FIXME: I2C IR should be disconnected */
+
+ if (dev->radio_dev) {
+ if (video_is_registered(dev->radio_dev))
+ video_unregister_device(dev->radio_dev);
+ else
+ video_device_release(dev->radio_dev);
+ dev->radio_dev = NULL;
+ }
+ if (dev->vbi_dev) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vbi_dev));
+ if (video_is_registered(dev->vbi_dev))
+ video_unregister_device(dev->vbi_dev);
+ else
+ video_device_release(dev->vbi_dev);
+ dev->vbi_dev = NULL;
+ }
+ if (dev->vdev) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vdev));
+ if (video_is_registered(dev->vdev))
+ video_unregister_device(dev->vdev);
+ else
+ video_device_release(dev->vdev);
+ dev->vdev = NULL;
+ }
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
+ */
+static int em28xx_v4l2_close(struct file *filp)
+{
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ int errCode;
+
+ em28xx_videodbg("users=%d\n", dev->users);
+
+ mutex_lock(&dev->lock);
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+ videobuf_stop(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
+
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
+
+ if (dev->users == 1) {
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_release_resources(dev);
+ kfree(dev->alt_max_pkt_size);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ kfree(fh);
+ return 0;
+ }
+
+ /* Save some power by putting tuner to sleep */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+ /* do this before setting alternate! */
+ em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
+ em28xx_set_mode(dev, EM28XX_SUSPEND);
+
+ /* set alternate 0 */
+ dev->alt = 0;
+ em28xx_videodbg("setting alternate 0\n");
+ errCode = usb_set_interface(dev->udev, 0, 0);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to "
+ "0 (error=%i)\n", errCode);
+ }
+ }
+
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
+ kfree(fh);
+ dev->users--;
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ /* FIXME: read() is not prepared to allow changing the video
+ resolution while streaming. Seems a bug at em28xx_set_fmt
+ */
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
+ rc = -EBUSY;
+ else
+ rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ rc = -EBUSY;
+ else
+ rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+/*
+ * em28xx_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
+{
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+ } else {
+ return POLLERR;
+ }
+}
+
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ unsigned int res;
+
+ mutex_lock(&dev->lock);
+ res = em28xx_poll(filp, wait);
+ mutex_unlock(&dev->lock);
+ return res;
+}
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
+ mutex_unlock(&dev->lock);
+
+ em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ rc);
+
+ return rc;
+}
+
+static const struct v4l2_file_operations em28xx_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = em28xx_v4l2_open,
+ .release = em28xx_v4l2_close,
+ .read = em28xx_v4l2_read,
+ .poll = em28xx_v4l2_poll,
+ .mmap = em28xx_v4l2_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
+ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+ .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_querystd = vidioc_querystd,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
+#endif
+};
+
+static const struct video_device em28xx_video_template = {
+ .fops = &em28xx_v4l_fops,
+ .release = video_device_release,
+ .ioctl_ops = &video_ioctl_ops,
+
+ .tvnorms = V4L2_STD_ALL,
+ .current_norm = V4L2_STD_PAL,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = em28xx_v4l2_open,
+ .release = em28xx_v4l2_close,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device em28xx_radio_template = {
+ .name = "em28xx-radio",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+};
+
+/******************************** usb interface ******************************/
+
+
+
+static struct video_device *em28xx_vdev_init(struct em28xx *dev,
+ const struct video_device *template,
+ const char *type_name)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = video_debug;
+ vfd->lock = &dev->lock;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s",
+ dev->name, type_name);
+
+ video_set_drvdata(vfd, dev);
+ return vfd;
+}
+
+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);
+
+ /* set default norm */
+ dev->norm = em28xx_video_template.current_norm;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+
+ /* 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,
+ maxw, norm_maxh(dev));
+
+ video_mux(dev, 0);
+
+ /* Audio defaults */
+ dev->mute = 1;
+ dev->volume = 0x1f;
+
+/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+ val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK,
+ (EM28XX_XCLK_AUDIO_UNMUTE | val));
+
+ em28xx_set_outfmt(dev);
+ em28xx_colorlevels_set_default(dev);
+ em28xx_compression_disable(dev);
+
+ /* allocate and fill video video_device struct */
+ dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
+ if (!dev->vdev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+
+ /* register v4l2 video video_device */
+ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ video_nr[dev->devno]);
+ if (ret) {
+ em28xx_errdev("unable to register video device (error=%i).\n",
+ ret);
+ return ret;
+ }
+
+ /* Allocate and fill vbi video_device struct */
+ if (em28xx_vbi_supported(dev) == 1) {
+ dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+ "vbi");
+
+ /* register v4l2 vbi video_device */
+ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]);
+ if (ret < 0) {
+ em28xx_errdev("unable to register vbi device\n");
+ return ret;
+ }
+ }
+
+ if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
+ dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+ "radio");
+ if (!dev->radio_dev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+ ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ radio_nr[dev->devno]);
+ if (ret < 0) {
+ em28xx_errdev("can't register radio device\n");
+ return ret;
+ }
+ em28xx_info("Registered radio device as %s\n",
+ video_device_node_name(dev->radio_dev));
+ }
+
+ em28xx_info("V4L2 video device registered as %s\n",
+ video_device_node_name(dev->vdev));
+
+ if (dev->vbi_dev)
+ em28xx_info("V4L2 VBI device registered as %s\n",
+ video_device_node_name(dev->vbi_dev));
+
+ return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 8757523e6863..8757523e6863 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
new file mode 100644
index 000000000000..6345f9331e7f
--- /dev/null
+++ b/drivers/media/usb/gspca/Kconfig
@@ -0,0 +1,425 @@
+menuconfig USB_GSPCA
+ tristate "GSPCA based webcams"
+ depends on VIDEO_V4L2
+ default m
+ ---help---
+ Say Y here if you want to enable selecting webcams based
+ on the GSPCA framework.
+
+ See <file:Documentation/video4linux/gspca.txt> for more info.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" to use this driver.
+
+ To compile this driver as modules, choose M here: the
+ module will be called gspca_main.
+
+
+if USB_GSPCA && VIDEO_V4L2
+
+source "drivers/media/usb/gspca/m5602/Kconfig"
+source "drivers/media/usb/gspca/stv06xx/Kconfig"
+source "drivers/media/usb/gspca/gl860/Kconfig"
+
+config USB_GSPCA_BENQ
+ tristate "Benq USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Benq DC E300 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_benq.
+
+config USB_GSPCA_CONEX
+ tristate "Conexant Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Conexant chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_conex.
+
+config USB_GSPCA_CPIA1
+ tristate "cpia CPiA (version 1) Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for USB cameras based on the cpia
+ CPiA chip. Note that you need atleast version 0.6.4 of libv4l for
+ applications to understand the videoformat generated by this driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_cpia1.
+
+config USB_GSPCA_ETOMS
+ tristate "Etoms USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Etoms chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_etoms.
+
+config USB_GSPCA_FINEPIX
+ tristate "Fujifilm FinePix USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the FinePix chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_finepix.
+
+config USB_GSPCA_JEILINJ
+ tristate "Jeilin JPEG USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on this Jeilin chip.
+
+ 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
+ help
+ Say Y here if you want support for the Microsoft Kinect sensor device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_kinect.
+
+config USB_GSPCA_KONICA
+ tristate "Konica USB Camera V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Konica chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_konica.
+
+config USB_GSPCA_MARS
+ tristate "Mars USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Mars chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_mars.
+
+config USB_GSPCA_MR97310A
+ tristate "Mars-Semi MR97310A USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the MR97310A chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_mr97310a.
+
+config USB_GSPCA_NW80X
+ tristate "Divio based (NW80x) USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the NW80x chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_nw80x.
+
+config USB_GSPCA_OV519
+ tristate "OV51x / OVFX2 / W996xCF USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on one of these:
+ OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_ov519.
+
+config USB_GSPCA_OV534
+ tristate "OV534 OV772x USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the OV534 chip
+ and sensor OV772x (e.g. Sony Playstation EYE)
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_ov534.
+
+config USB_GSPCA_OV534_9
+ tristate "OV534 OV965x USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the OV534 chip
+ and sensor OV965x (e.g. Hercules Dualpix)
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_ov534_9.
+
+config USB_GSPCA_PAC207
+ tristate "Pixart PAC207 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the PAC207 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_pac207.
+
+config USB_GSPCA_PAC7302
+ tristate "Pixart PAC7302 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the PAC7302 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_pac7302.
+
+config USB_GSPCA_PAC7311
+ tristate "Pixart PAC7311 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the PAC7311 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_pac7311.
+
+config USB_GSPCA_SE401
+ tristate "SE401 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the
+ Endpoints (formerly known as AOX) se401 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_se401.
+
+config USB_GSPCA_SN9C2028
+ tristate "SONIX Dual-Mode USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want streaming support for Sonix SN9C2028 cameras.
+ These are supported as stillcams in libgphoto2/camlibs/sonix.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sn9c2028.
+
+config USB_GSPCA_SN9C20X
+ tristate "SN9C20X USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the
+ sn9c20x chips (SN9C201 and SN9C202).
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sn9c20x.
+
+config USB_GSPCA_SONIXB
+ tristate "SONIX Bayer USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Sonix
+ chips with Bayer format (SN9C101, SN9C102 and SN9C103).
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sonixb.
+
+config USB_GSPCA_SONIXJ
+ tristate "SONIX JPEG USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Sonix
+ chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110).
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sonixj
+
+config USB_GSPCA_SPCA500
+ tristate "SPCA500 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA500 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca500.
+
+config USB_GSPCA_SPCA501
+ tristate "SPCA501 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA501 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca501.
+
+config USB_GSPCA_SPCA505
+ tristate "SPCA505 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA505 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca505.
+
+config USB_GSPCA_SPCA506
+ tristate "SPCA506 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA506 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca506.
+
+config USB_GSPCA_SPCA508
+ tristate "SPCA508 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA508 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca508.
+
+config USB_GSPCA_SPCA561
+ tristate "SPCA561 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA561 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca561.
+
+config USB_GSPCA_SPCA1528
+ tristate "SPCA1528 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca1528.
+
+config USB_GSPCA_SQ905
+ tristate "SQ Technologies SQ905 based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ905 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq905.
+
+config USB_GSPCA_SQ905C
+ tristate "SQ Technologies SQ905C based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ905C chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq905c.
+
+config USB_GSPCA_SQ930X
+ tristate "SQ Technologies SQ930X based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ930X chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq930x.
+
+config USB_GSPCA_STK014
+ tristate "Syntek DV4000 (STK014) USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the STK014 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_stk014.
+
+config USB_GSPCA_STV0680
+ tristate "STV0680 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the STV0680 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_stv0680.
+
+config USB_GSPCA_SUNPLUS
+ tristate "SUNPLUS USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Sunplus
+ SPCA504(abc) SPCA533 SPCA536 chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sunplus.
+
+config USB_GSPCA_T613
+ tristate "T613 (JPEG Compliance) USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the T613 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_t613.
+
+config USB_GSPCA_TOPRO
+ tristate "TOPRO USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the
+ TP6800 and TP6810 Topro chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_topro.
+
+config USB_GSPCA_TV8532
+ tristate "TV8532 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the TV8531 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_tv8532.
+
+config USB_GSPCA_VC032X
+ tristate "VC032X USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the VC032X chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_vc032x.
+
+config USB_GSPCA_VICAM
+ tristate "ViCam USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the 3com homeconnect camera
+ (vicam).
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_vicam.
+
+config USB_GSPCA_XIRLINK_CIT
+ tristate "Xirlink C-It USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for Xirlink C-It bases cameras.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_xirlink_cit.
+
+config USB_GSPCA_ZC3XX
+ tristate "ZC3XX USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the ZC3XX chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_zc3xx.
+
+endif
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index c901da0bd657..c901da0bd657 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
diff --git a/drivers/media/video/gspca/autogain_functions.c b/drivers/media/usb/gspca/autogain_functions.c
index 67db674bb044..67db674bb044 100644
--- a/drivers/media/video/gspca/autogain_functions.c
+++ b/drivers/media/usb/gspca/autogain_functions.c
diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h
index d625eafe63eb..d625eafe63eb 100644
--- a/drivers/media/video/gspca/autogain_functions.h
+++ b/drivers/media/usb/gspca/autogain_functions.h
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/usb/gspca/benq.c
index 352f32190e68..352f32190e68 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/usb/gspca/benq.c
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/usb/gspca/conex.c
index c9052f20435e..c9052f20435e 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/usb/gspca/conex.c
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index 2499a881d9a3..2499a881d9a3 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c
index 38f68e11c3a2..38f68e11c3a2 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/usb/gspca/etoms.c
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/usb/gspca/finepix.c
index c8f2201cc35a..c8f2201cc35a 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/usb/gspca/finepix.c
diff --git a/drivers/media/video/gspca/gl860/Kconfig b/drivers/media/usb/gspca/gl860/Kconfig
index 22772f53ec7b..22772f53ec7b 100644
--- a/drivers/media/video/gspca/gl860/Kconfig
+++ b/drivers/media/usb/gspca/gl860/Kconfig
diff --git a/drivers/media/usb/gspca/gl860/Makefile b/drivers/media/usb/gspca/gl860/Makefile
new file mode 100644
index 000000000000..cf6397415aad
--- /dev/null
+++ b/drivers/media/usb/gspca/gl860/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_USB_GL860) += gspca_gl860.o
+
+gspca_gl860-objs := gl860.o \
+ gl860-mi1320.o \
+ gl860-ov2640.o \
+ gl860-ov9655.o \
+ gl860-mi2020.o
+
+ccflags-y += -I$(srctree)/drivers/media/usb/gspca
+
diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/usb/gspca/gl860/gl860-mi1320.c
index b57160e04866..b57160e04866 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi1320.c
+++ b/drivers/media/usb/gspca/gl860/gl860-mi1320.c
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
index 2edda6b7d653..2edda6b7d653 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
diff --git a/drivers/media/video/gspca/gl860/gl860-ov2640.c b/drivers/media/usb/gspca/gl860/gl860-ov2640.c
index 768cac5cd72b..768cac5cd72b 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov2640.c
+++ b/drivers/media/usb/gspca/gl860/gl860-ov2640.c
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/usb/gspca/gl860/gl860-ov9655.c
index 5ae9619d72a5..5ae9619d72a5 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov9655.c
+++ b/drivers/media/usb/gspca/gl860/gl860-ov9655.c
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
index ced3b71f14e5..ced3b71f14e5 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/usb/gspca/gl860/gl860.c
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/usb/gspca/gl860/gl860.h
index 0330a0293b9c..0330a0293b9c 100644
--- a/drivers/media/video/gspca/gl860/gl860.h
+++ b/drivers/media/usb/gspca/gl860/gl860.h
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index d4e8343f5b10..d4e8343f5b10 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index dc688c7f5e48..dc688c7f5e48 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c
index 26b99310d628..26b99310d628 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/usb/gspca/jeilinj.c
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c
index 234777116e5f..234777116e5f 100644
--- a/drivers/media/video/gspca/jl2005bcd.c
+++ b/drivers/media/usb/gspca/jl2005bcd.c
diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/usb/gspca/jpeg.h
index ab54910418b4..ab54910418b4 100644
--- a/drivers/media/video/gspca/jpeg.h
+++ b/drivers/media/usb/gspca/jpeg.h
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c
index 40ad6687ee5d..40ad6687ee5d 100644
--- a/drivers/media/video/gspca/kinect.c
+++ b/drivers/media/usb/gspca/kinect.c
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/usb/gspca/konica.c
index bbf91e07e38b..bbf91e07e38b 100644
--- a/drivers/media/video/gspca/konica.c
+++ b/drivers/media/usb/gspca/konica.c
diff --git a/drivers/media/video/gspca/m5602/Kconfig b/drivers/media/usb/gspca/m5602/Kconfig
index 5a69016ed75f..5a69016ed75f 100644
--- a/drivers/media/video/gspca/m5602/Kconfig
+++ b/drivers/media/usb/gspca/m5602/Kconfig
diff --git a/drivers/media/usb/gspca/m5602/Makefile b/drivers/media/usb/gspca/m5602/Makefile
new file mode 100644
index 000000000000..8e1fb5a1d2a1
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_USB_M5602) += gspca_m5602.o
+
+gspca_m5602-objs := m5602_core.o \
+ m5602_ov9650.o \
+ m5602_ov7660.o \
+ m5602_mt9m111.o \
+ m5602_po1030.o \
+ m5602_s5k83a.o \
+ m5602_s5k4aa.o
+
+ccflags-y += -I$(srctree)/drivers/media/usb/gspca
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h
index 51af3ee3ab85..51af3ee3ab85 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/usb/gspca/m5602/m5602_bridge.h
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c
index ed22638978ce..ed22638978ce 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/usb/gspca/m5602/m5602_core.c
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
index 6268aa24ec5d..6268aa24ec5d 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
index 8c672b5c8c6a..8c672b5c8c6a 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
index 9a14835c128f..9a14835c128f 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
index 2b6a13b508f7..2b6a13b508f7 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
index 2114a8b90ec9..2114a8b90ec9 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
index f7aa5bf68983..f7aa5bf68983 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c
index b8771698cbcb..b8771698cbcb 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/usb/gspca/m5602/m5602_po1030.h
index 81a2bcb88fe3..81a2bcb88fe3 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.h
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
index cc8ec3f7e8dc..cc8ec3f7e8dc 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
index 8e0035e731c7..8e0035e731c7 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
index 1de743a02b02..1de743a02b02 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
index 79952247b534..79952247b534 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/usb/gspca/m5602/m5602_sensor.h
index edff4f1f586f..edff4f1f586f 100644
--- a/drivers/media/video/gspca/m5602/m5602_sensor.h
+++ b/drivers/media/usb/gspca/m5602/m5602_sensor.h
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/usb/gspca/mars.c
index ff2c5abf115b..ff2c5abf115b 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/usb/gspca/mars.c
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c
index 8f4714df5990..8f4714df5990 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/usb/gspca/mr97310a.c
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c
index 44c9964b1b3e..44c9964b1b3e 100644
--- a/drivers/media/video/gspca/nw80x.c
+++ b/drivers/media/usb/gspca/nw80x.c
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index bfc7cefa59f8..bfc7cefa59f8 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index bb09d7884b89..bb09d7884b89 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c
index c4cd028fe0b4..c4cd028fe0b4 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/usb/gspca/ov534_9.c
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c
index d236d1791f78..d236d1791f78 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/usb/gspca/pac207.c
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index 4877f7ab3d59..4877f7ab3d59 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c
index ba3558d3f017..ba3558d3f017 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/usb/gspca/pac7311.c
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/usb/gspca/pac_common.h
index 8462a7c1a338..8462a7c1a338 100644
--- a/drivers/media/video/gspca/pac_common.h
+++ b/drivers/media/usb/gspca/pac_common.h
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/usb/gspca/se401.c
index a33cb78a839c..a33cb78a839c 100644
--- a/drivers/media/video/gspca/se401.c
+++ b/drivers/media/usb/gspca/se401.c
diff --git a/drivers/media/video/gspca/se401.h b/drivers/media/usb/gspca/se401.h
index 96d8ebf3cf59..96d8ebf3cf59 100644
--- a/drivers/media/video/gspca/se401.h
+++ b/drivers/media/usb/gspca/se401.h
diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
index 03fa3fd940b4..03fa3fd940b4 100644
--- a/drivers/media/video/gspca/sn9c2028.c
+++ b/drivers/media/usb/gspca/sn9c2028.c
diff --git a/drivers/media/video/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h
index 8fd1d3e05665..8fd1d3e05665 100644
--- a/drivers/media/video/gspca/sn9c2028.h
+++ b/drivers/media/usb/gspca/sn9c2028.h
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index b9c6f17eabb2..b9c6f17eabb2 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index fd1f8d2d3b0b..fd1f8d2d3b0b 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index 150b2df40f7f..150b2df40f7f 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c
index 14d635277d71..14d635277d71 100644
--- a/drivers/media/video/gspca/spca1528.c
+++ b/drivers/media/usb/gspca/spca1528.c
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/usb/gspca/spca500.c
index 25cb68d0556d..25cb68d0556d 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/usb/gspca/spca500.c
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c
index 3b7f777785b4..3b7f777785b4 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/usb/gspca/spca501.c
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/usb/gspca/spca505.c
index bc7d67c3cb04..bc7d67c3cb04 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/usb/gspca/spca505.c
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/usb/gspca/spca506.c
index bab01c86c315..bab01c86c315 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/usb/gspca/spca506.c
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/usb/gspca/spca508.c
index 1286b4170b88..1286b4170b88 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/usb/gspca/spca508.c
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/usb/gspca/spca561.c
index cfe71dd6747d..cfe71dd6747d 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/usb/gspca/spca561.c
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c
index a8ac97931ad6..a8ac97931ad6 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/usb/gspca/sq905.c
diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c
new file mode 100644
index 000000000000..70fae6982e96
--- /dev/null
+++ b/drivers/media/usb/gspca/sq905c.c
@@ -0,0 +1,344 @@
+/*
+ * SQ905C subdriver
+ *
+ * Copyright (C) 2009 Theodore Kilgore
+ *
+ * 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
+ */
+
+/*
+ *
+ * This driver uses work done in
+ * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
+ *
+ * This driver has also used as a base the sq905c driver
+ * and may contain code fragments from it.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "sq905c"
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define SQ905C_CMD_TIMEOUT 500
+#define SQ905C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define SQ905C_MAX_TRANSFER 0x8000
+
+#define FRAME_HEADER_LEN 0x50
+
+/* Commands. These go in the "value" slot. */
+#define SQ905C_CLEAR 0xa0 /* clear everything */
+#define SQ905C_GET_ID 0x14f4 /* Read version number */
+#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
+#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
+#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
+
+/* For capture, this must go in the "index" slot. */
+#define SQ905C_CAPTURE_INDEX 0x110f
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+};
+
+/*
+ * Most of these cameras will do 640x480 and 320x240. 160x120 works
+ * in theory but gives very poor output. Therefore, not supported.
+ * The 0x2770:0x9050 cameras have max resolution of 320x240.
+ */
+static struct v4l2_pix_format sq905c_mode[] = {
+ { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0}
+};
+
+/* Send a command to the camera. */
+static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_SYNCH_FRAME, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ command, index, NULL, 0,
+ SQ905C_CMD_TIMEOUT);
+ if (ret < 0) {
+ pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
+ int size)
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_SYNCH_FRAME, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ command, index, gspca_dev->usb_buf, size,
+ SQ905C_CMD_TIMEOUT);
+ if (ret < 0) {
+ pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* 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 sq905c_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; /* bytes remaining in current frame. */
+ int data_len; /* size to use for the next read. */
+ int act_len;
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ pr_err("Couldn't allocate USB buffer\n");
+ goto quit_stream;
+ }
+
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
+ /* Request the header, which tells the size to download */
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, FRAME_HEADER_LEN, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for header",
+ act_len, FRAME_HEADER_LEN);
+ if (ret < 0 || act_len < FRAME_HEADER_LEN)
+ goto quit_stream;
+ /* size is read from 4 bytes starting 0x40, little endian */
+ bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
+ |(buffer[0x43]<<24);
+ PDEBUG(D_STREAM, "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, FRAME_HEADER_LEN);
+ while (bytes_left > 0 && gspca_dev->dev) {
+ data_len = bytes_left > SQ905C_MAX_TRANSFER ?
+ SQ905C_MAX_TRANSFER : bytes_left;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, data_len, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ if (ret < 0 || act_len < data_len)
+ goto quit_stream;
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for frame",
+ data_len, bytes_left);
+ bytes_left -= data_len;
+ if (bytes_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ buffer, data_len);
+ }
+ }
+quit_stream:
+ if (gspca_dev->dev) {
+ mutex_lock(&gspca_dev->usb_lock);
+ sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam = &gspca_dev->cam;
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ PDEBUG(D_PROBE,
+ "SQ9050 camera detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+ ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Get version command failed");
+ return ret;
+ }
+
+ ret = sq905c_read(gspca_dev, 0xf5, 0, 20);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Reading version command failed");
+ return ret;
+ }
+ /* Note we leave out the usb id and the manufacturing date */
+ PDEBUG(D_PROBE,
+ "SQ9050 ID string: %02x - %*ph",
+ gspca_dev->usb_buf[3], 6, gspca_dev->usb_buf + 14);
+
+ cam->cam_mode = sq905c_mode;
+ cam->nmodes = 2;
+ if (gspca_dev->usb_buf[15] == 0)
+ cam->nmodes = 1;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 32;
+ cam->bulk = 1;
+ INIT_WORK(&dev->work_struct, sq905c_dostream);
+ 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);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ /* connect to the camera and reset it. */
+ ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ return ret;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ dev->cap_mode = gspca_dev->cam.cam_mode;
+ /* "Open the shutter" and set size, to start capture */
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at high resolution");
+ dev->cap_mode++;
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
+ SQ905C_CAPTURE_INDEX);
+ break;
+ default: /* 320 */
+ PDEBUG(D_STREAM, "Start streaming at medium resolution");
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
+ SQ905C_CAPTURE_INDEX);
+ }
+
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return ret;
+ }
+ /* Start the workqueue function to do the streaming */
+ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(dev->work_thread, &dev->work_struct);
+
+ return 0;
+}
+
+/* Table of supported USB devices */
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x2770, 0x905c)},
+ {USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x9051)},
+ {USB_DEVICE(0x2770, 0x9052)},
+ {USB_DEVICE(0x2770, 0x913d)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- 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,
+ .reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c
new file mode 100644
index 000000000000..7e8748b31e85
--- /dev/null
+++ b/drivers/media/usb/gspca/sq930x.c
@@ -0,0 +1,1164 @@
+/*
+ * SQ930x subdriver
+ *
+ * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "sq930x"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
+ "Gerard Klaver <gerard at gkall dot hobby dot nl\n"
+ "Sam Revitch <samr7@cs.washington.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ struct { /* exposure/gain control cluster */
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ };
+
+ u8 do_ctrl;
+ u8 gpio[2];
+ u8 sensor;
+ u8 type;
+#define Generic 0
+#define Creative_live_motion 1
+};
+enum sensors {
+ SENSOR_ICX098BQ,
+ SENSOR_LZ24BP,
+ SENSOR_MI0360,
+ SENSOR_MT9V111, /* = MI360SOC */
+ SENSOR_OV7660,
+ SENSOR_OV9630,
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+};
+
+/* sq930x registers */
+#define SQ930_CTRL_UCBUS_IO 0x0001
+#define SQ930_CTRL_I2C_IO 0x0002
+#define SQ930_CTRL_GPIO 0x0005
+#define SQ930_CTRL_CAP_START 0x0010
+#define SQ930_CTRL_CAP_STOP 0x0011
+#define SQ930_CTRL_SET_EXPOSURE 0x001d
+#define SQ930_CTRL_RESET 0x001e
+#define SQ930_CTRL_GET_DEV_INFO 0x001f
+
+/* gpio 1 (8..15) */
+#define SQ930_GPIO_DFL_I2C_SDA 0x0001
+#define SQ930_GPIO_DFL_I2C_SCL 0x0002
+#define SQ930_GPIO_RSTBAR 0x0004
+#define SQ930_GPIO_EXTRA1 0x0040
+#define SQ930_GPIO_EXTRA2 0x0080
+/* gpio 3 (24..31) */
+#define SQ930_GPIO_POWER 0x0200
+#define SQ930_GPIO_DFL_LED 0x1000
+
+struct ucbus_write_cmd {
+ u16 bw_addr;
+ u8 bw_data;
+};
+struct i2c_write_cmd {
+ u8 reg;
+ u16 val;
+};
+
+static const struct ucbus_write_cmd icx098bq_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
+ {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
+ {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
+ {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
+ {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
+ {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
+ {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
+ {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
+ {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
+ {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
+ {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
+ {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
+ {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
+ {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
+ {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd icx098bq_start_1[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd icx098bq_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
+ {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
+ {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
+ {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
+ {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
+ {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
+ {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
+ {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
+ {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
+ {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
+ {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
+ {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
+ {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
+ {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
+ {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd mi0360_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
+ {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
+};
+static const struct i2c_write_cmd mi0360_init_23[] = {
+ {0x30, 0x0040}, /* reserved - def 0x0005 */
+ {0x31, 0x0000}, /* reserved - def 0x002a */
+ {0x34, 0x0100}, /* reserved - def 0x0100 */
+ {0x3d, 0x068f}, /* reserved - def 0x068f */
+};
+static const struct i2c_write_cmd mi0360_init_24[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mi0360_init_25[] = {
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x002a}, /* blue gain */
+ {0x2d, 0x0028}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mi0360_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+static const struct i2c_write_cmd mi0360_start_2[] = {
+ {0x62, 0x041d}, /* reserved - def 0x0418 */
+};
+static const struct i2c_write_cmd mi0360_start_3[] = {
+ {0x05, 0x007b}, /* horiz blanking */
+};
+static const struct i2c_write_cmd mi0360_start_4[] = {
+ {0x05, 0x03f5}, /* horiz blanking */
+};
+
+static const struct i2c_write_cmd mt9v111_init_0[] = {
+ {0x01, 0x0001}, /* select IFP/SOC registers */
+ {0x06, 0x300c}, /* operating mode control */
+ {0x08, 0xcc00}, /* output format control (RGB) */
+ {0x01, 0x0004}, /* select sensor core registers */
+};
+static const struct i2c_write_cmd mt9v111_init_1[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mt9v111_init_2[] = {
+ {0x30, 0x7800},
+ {0x31, 0x0000},
+ {0x07, 0x3002}, /* output control */
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x0020}, /* blue gain */
+ {0x2d, 0x0020}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mt9v111_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
+ {0xf5f9, 0x0a}
+};
+static const struct i2c_write_cmd mt9v111_init_3[] = {
+ {0x62, 0x0405},
+};
+static const struct i2c_write_cmd mt9v111_init_4[] = {
+/* {0x05, 0x00ce}, */
+ {0x05, 0x005d}, /* horizontal blanking */
+};
+
+static const struct ucbus_write_cmd ov7660_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
+ {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
+};
+
+static const struct ucbus_write_cmd ov9630_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
+ {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
+};
+
+/* start parameters indexed by [sensor][mode] */
+static const struct cap_s {
+ u8 cc_sizeid;
+ u8 cc_bytes[32];
+} capconfig[4][2] = {
+ [SENSOR_ICX098BQ] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_LZ24BP] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_MI0360] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_MT9V111] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+};
+
+struct sensor_s {
+ const char *name;
+ u8 i2c_addr;
+ u8 i2c_dum;
+ u8 gpio[5];
+ u8 cmd_len;
+ const struct ucbus_write_cmd *cmd;
+};
+
+static const struct sensor_s sensor_tb[] = {
+ [SENSOR_ICX098BQ] = {
+ "icx098bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, icx098bq_start_0
+ },
+ [SENSOR_LZ24BP] = {
+ "lz24bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, lz24bp_start_0
+ },
+ [SENSOR_MI0360] = {
+ "mi0360",
+ 0x5d, 0x80,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_MT9V111] = {
+ "mt9v111",
+ 0x5c, 0x7f,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_OV7660] = {
+ "ov7660",
+ 0x21, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov7660_start_0
+ },
+ [SENSOR_OV9630] = {
+ "ov9630",
+ 0x30, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov9630_start_0
+ },
+};
+
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 value, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x0c,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, 0, gspca_dev->usb_buf, len,
+ 500);
+ if (ret < 0) {
+ pr_err("reg_r %04x failed %d\n", value, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+ msleep(30);
+ if (ret < 0) {
+ pr_err("reg_w %04x %04x failed %d\n", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
+ const u8 *data, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
+ value, index, *data, data[len - 1]);
+ memcpy(gspca_dev->usb_buf, data, len);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, gspca_dev->usb_buf, len,
+ 1000);
+ msleep(30);
+ if (ret < 0) {
+ pr_err("reg_wb %04x %04x failed %d\n", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void i2c_write(struct sd *sd,
+ const struct i2c_write_cmd *cmd,
+ int ncmds)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ const struct sensor_s *sensor;
+ u16 val, idx;
+ u8 *buf;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ sensor = &sensor_tb[sd->sensor];
+
+ val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
+ idx = (cmd->val & 0xff00) | cmd->reg;
+
+ buf = gspca_dev->usb_buf;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+
+ while (--ncmds > 0) {
+ cmd++;
+ *buf++ = cmd->reg;
+ *buf++ = cmd->val >> 8;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+ }
+
+ PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
+ val, idx, gspca_dev->usb_buf[0], buf[-1]);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ pr_err("i2c_write failed %d\n", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void ucbus_write(struct gspca_dev *gspca_dev,
+ const struct ucbus_write_cmd *cmd,
+ int ncmds,
+ int batchsize)
+{
+ u8 *buf;
+ u16 val, idx;
+ int len, ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+#ifdef GSPCA_DEBUG
+ if ((batchsize - 1) * 3 > USB_BUF_SZ) {
+ pr_err("Bug: usb_buf overflow\n");
+ gspca_dev->usb_err = -ENOMEM;
+ return;
+ }
+#endif
+
+ for (;;) {
+ len = ncmds;
+ if (len > batchsize)
+ len = batchsize;
+ ncmds -= len;
+
+ val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
+ idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
+
+ buf = gspca_dev->usb_buf;
+ while (--len > 0) {
+ cmd++;
+ *buf++ = cmd->bw_addr;
+ *buf++ = cmd->bw_addr >> 8;
+ *buf++ = cmd->bw_data;
+ }
+ if (buf != gspca_dev->usb_buf)
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
+ val, idx,
+ gspca_dev->usb_buf[0], buf[-1]);
+ else
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
+ val, idx);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ pr_err("ucbus_write failed %d\n", ret);
+ gspca_dev->usb_err = ret;
+ return;
+ }
+ msleep(30);
+ if (ncmds <= 0)
+ break;
+ cmd++;
+ }
+}
+
+static void gpio_set(struct sd *sd, u16 val, u16 mask)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ if (mask & 0x00ff) {
+ sd->gpio[0] &= ~mask;
+ sd->gpio[0] |= val;
+ reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
+ ~sd->gpio[0] << 8);
+ }
+ mask >>= 8;
+ val >>= 8;
+ if (mask) {
+ sd->gpio[1] &= ~mask;
+ sd->gpio[1] |= val;
+ reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
+ ~sd->gpio[1] << 8);
+ }
+}
+
+static void gpio_init(struct sd *sd,
+ const u8 *gpio)
+{
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio, 0x000f);
+}
+
+static void bridge_init(struct sd *sd)
+{
+ static const struct ucbus_write_cmd clkfreq_cmd = {
+ 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */
+ };
+
+ ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
+
+ gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
+}
+
+static void cmos_probe(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const struct sensor_s *sensor;
+ static const u8 probe_order[] = {
+/* SENSOR_LZ24BP, (tested as ccd) */
+ SENSOR_OV9630,
+ SENSOR_MI0360,
+ SENSOR_OV7660,
+ SENSOR_MT9V111,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+ sensor = &sensor_tb[probe_order[i]];
+ ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
+ gpio_init(sd, sensor->gpio);
+ msleep(100);
+ reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
+ msleep(100);
+ if (gspca_dev->usb_buf[0] != 0)
+ break;
+ }
+ if (i >= ARRAY_SIZE(probe_order)) {
+ pr_err("Unknown sensor\n");
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+ sd->sensor = probe_order[i];
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV9630:
+ pr_err("Sensor %s not yet treated\n",
+ sensor_tb[sd->sensor].name);
+ gspca_dev->usb_err = -EINVAL;
+ break;
+ }
+}
+
+static void mt9v111_init(struct gspca_dev *gspca_dev)
+{
+ int i, nwait;
+ static const u8 cmd_001b[] = {
+ 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+ static const u8 cmd_011b[][7] = {
+ {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
+ {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
+ {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
+ {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
+ };
+
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
+ for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
+ ARRAY_SIZE(cmd_011b[0]));
+ msleep(400);
+ nwait = 20;
+ for (;;) {
+ reg_r(gspca_dev, 0x031b, 1);
+ if (gspca_dev->usb_buf[0] == 0
+ || gspca_dev->usb_err != 0)
+ break;
+ if (--nwait < 0) {
+ PDEBUG(D_PROBE, "mt9v111_init timeout");
+ gspca_dev->usb_err = -ETIME;
+ return;
+ }
+ msleep(50);
+ }
+ }
+}
+
+static void global_init(struct sd *sd, int first_time)
+{
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ icx098bq_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_LZ24BP:
+ if (sd->type != Creative_live_motion)
+ gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
+ else
+ gpio_set(sd, 0, 0x00ff);
+ msleep(50);
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ lz24bp_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_MI0360:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ if (first_time)
+ mt9v111_init(&sd->gspca_dev);
+ else
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ }
+}
+
+static void lz24bp_ppl(struct sd *sd, u16 ppl)
+{
+ struct ucbus_write_cmd cmds[2] = {
+ {0xf810, ppl >> 8},
+ {0xf811, ppl}
+ };
+
+ ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, integclks, intstartclk, frameclks, min_frclk;
+ const struct sensor_s *sensor;
+ u16 cmd;
+ u8 buf[15];
+
+ integclks = expo;
+ i = 0;
+ cmd = SQ930_CTRL_SET_EXPOSURE;
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ: /* ccd */
+ case SENSOR_LZ24BP:
+ min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
+ if (integclks >= min_frclk) {
+ intstartclk = 0;
+ frameclks = integclks;
+ } else {
+ intstartclk = min_frclk - integclks;
+ frameclks = min_frclk;
+ }
+ buf[i++] = intstartclk >> 8;
+ buf[i++] = intstartclk;
+ buf[i++] = frameclks >> 8;
+ buf[i++] = frameclks;
+ buf[i++] = gain;
+ break;
+ default: /* cmos */
+/* case SENSOR_MI0360: */
+/* case SENSOR_MT9V111: */
+ cmd |= 0x0100;
+ sensor = &sensor_tb[sd->sensor];
+ buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */
+ buf[i++] = 0x08; /* 2 * ni2c */
+ buf[i++] = 0x09; /* reg = shutter width */
+ buf[i++] = integclks >> 8; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = integclks; /* val L */
+ buf[i++] = 0x35; /* reg = global gain */
+ buf[i++] = 0x00; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = 0x80 + gain / 2; /* val L */
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x83;
+ break;
+ }
+ reg_wb(gspca_dev, cmd, 0, buf, i);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ sd->sensor = id->driver_info >> 8;
+ sd->type = id->driver_info;
+
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ cam->bulk = 1;
+
+ 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;
+
+ sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */
+
+/*fixme: is this needed for icx098bp and mi0360?
+ if (sd->sensor != SENSOR_LZ24BP)
+ reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
+ */
+
+ reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+ if (gspca_dev->usb_err < 0)
+ return gspca_dev->usb_err;
+
+/* it returns:
+ * 03 00 12 93 0b f6 c9 00 live! ultra
+ * 03 00 07 93 0b f6 ca 00 live! ultra for notebook
+ * 03 00 12 93 0b fe c8 00 Trust WB-3500T
+ * 02 00 06 93 0b fe c8 00 Joy-IT 318S
+ * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq
+ * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam
+ *
+ * byte
+ * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
+ * 1: 00
+ * 2: 06 / 07 / 12 = mode webcam? firmware??
+ * 3: 93 chip = 930b (930b or 930c)
+ * 4: 0b
+ * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
+ * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
+ * 7: 00
+ */
+ PDEBUG(D_PROBE, "info: %*ph", 8, gspca_dev->usb_buf);
+
+ bridge_init(sd);
+
+ if (sd->sensor == SENSOR_MI0360) {
+
+ /* no sensor probe for icam tracer */
+ if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */
+ sd->sensor = SENSOR_ICX098BQ;
+ else
+ cmos_probe(gspca_dev);
+ }
+ if (gspca_dev->usb_err >= 0) {
+ PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+ global_init(sd, 1);
+ }
+ return gspca_dev->usb_err;
+}
+
+/* send the start/stop commands to the webcam */
+static void send_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ const struct cap_s *cap;
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ cap = &capconfig[sd->sensor][mode];
+ reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START,
+ 0x0a00 | cap->cc_sizeid,
+ cap->cc_bytes, 32);
+}
+
+static void send_stop(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */
+ sd->do_ctrl = 0;
+ gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8;
+ return 0;
+}
+
+/* start the capture */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode;
+
+ bridge_init(sd);
+ global_init(sd, 0);
+ msleep(100);
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ ucbus_write(gspca_dev, icx098bq_start_0,
+ ARRAY_SIZE(icx098bq_start_0),
+ 8);
+ ucbus_write(gspca_dev, icx098bq_start_1,
+ ARRAY_SIZE(icx098bq_start_1),
+ 5);
+ ucbus_write(gspca_dev, icx098bq_start_2,
+ ARRAY_SIZE(icx098bq_start_2),
+ 6);
+ msleep(50);
+
+ /* 1st start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ msleep(70);
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+ gpio_set(sd, 0x7f, 0x00ff);
+
+ /* 2nd start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ goto out;
+ case SENSOR_LZ24BP:
+ ucbus_write(gspca_dev, lz24bp_start_0,
+ ARRAY_SIZE(lz24bp_start_0),
+ 8);
+ if (sd->type != Creative_live_motion)
+ ucbus_write(gspca_dev, lz24bp_start_1_gen,
+ ARRAY_SIZE(lz24bp_start_1_gen),
+ 5);
+ else
+ ucbus_write(gspca_dev, lz24bp_start_1_clm,
+ ARRAY_SIZE(lz24bp_start_1_clm),
+ 5);
+ ucbus_write(gspca_dev, lz24bp_start_2,
+ ARRAY_SIZE(lz24bp_start_2),
+ 6);
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310);
+ msleep(10);
+ break;
+ case SENSOR_MI0360:
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mi0360_init_23,
+ ARRAY_SIZE(mi0360_init_23));
+ i2c_write(sd, mi0360_init_24,
+ ARRAY_SIZE(mi0360_init_24));
+ i2c_write(sd, mi0360_init_25,
+ ARRAY_SIZE(mi0360_init_25));
+ ucbus_write(gspca_dev, mi0360_start_1,
+ ARRAY_SIZE(mi0360_start_1),
+ 5);
+ i2c_write(sd, mi0360_start_2,
+ ARRAY_SIZE(mi0360_start_2));
+ i2c_write(sd, mi0360_start_3,
+ ARRAY_SIZE(mi0360_start_3));
+
+ /* 1st start */
+ send_start(gspca_dev);
+ msleep(60);
+ send_stop(gspca_dev);
+
+ i2c_write(sd,
+ mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mt9v111_init_0,
+ ARRAY_SIZE(mt9v111_init_0));
+ i2c_write(sd, mt9v111_init_1,
+ ARRAY_SIZE(mt9v111_init_1));
+ i2c_write(sd, mt9v111_init_2,
+ ARRAY_SIZE(mt9v111_init_2));
+ ucbus_write(gspca_dev, mt9v111_start_1,
+ ARRAY_SIZE(mt9v111_start_1),
+ 5);
+ i2c_write(sd, mt9v111_init_3,
+ ARRAY_SIZE(mt9v111_init_3));
+ i2c_write(sd, mt9v111_init_4,
+ ARRAY_SIZE(mt9v111_init_4));
+ break;
+ }
+
+ send_start(gspca_dev);
+out:
+ msleep(1000);
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
+
+ sd->do_ctrl = 1; /* set the exposure */
+
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
+ send_stop(gspca_dev);
+}
+
+/* function called when the application gets a new frame */
+/* It sets the exposure if required and restart the bulk transfer. */
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
+ return;
+ sd->do_ctrl = 0;
+
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure),
+ v4l2_ctrl_g_ctrl(sd->gain));
+
+ gspca_dev->cam.bulk_nurbs = 1;
+ ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+ if (ret < 0)
+ pr_err("sd_dq_callback() err %d\n", ret);
+
+ /* wait a little time, otherwise the webcam crashes */
+ msleep(100);
+}
+
+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;
+
+ if (sd->do_ctrl)
+ gspca_dev->cam.bulk_nurbs = 0;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8);
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ setexposure(gspca_dev, ctrl->val, sd->gain->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 2);
+ sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356);
+ sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 1, 255, 1, 0x8d);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ v4l2_ctrl_cluster(2, &sd->exposure);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .init_controls = sd_init_controls,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .dq_callback = sd_dq_callback,
+};
+
+/* Table of supported USB devices */
+#define ST(sensor, type) \
+ .driver_info = (SENSOR_ ## sensor << 8) \
+ | (type)
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
+ {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
+ {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
+ {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
+ {}
+};
+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,
+ .reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/usb/gspca/stk014.c
index 8c0982607f25..8c0982607f25 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/usb/gspca/stk014.c
diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c
index 67605272aaa8..67605272aaa8 100644
--- a/drivers/media/video/gspca/stv0680.c
+++ b/drivers/media/usb/gspca/stv0680.c
diff --git a/drivers/media/video/gspca/stv06xx/Kconfig b/drivers/media/usb/gspca/stv06xx/Kconfig
index 634ad38d9fb8..634ad38d9fb8 100644
--- a/drivers/media/video/gspca/stv06xx/Kconfig
+++ b/drivers/media/usb/gspca/stv06xx/Kconfig
diff --git a/drivers/media/usb/gspca/stv06xx/Makefile b/drivers/media/usb/gspca/stv06xx/Makefile
new file mode 100644
index 000000000000..3a4b2f899049
--- /dev/null
+++ b/drivers/media/usb/gspca/stv06xx/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
+
+gspca_stv06xx-objs := stv06xx.o \
+ stv06xx_vv6410.o \
+ stv06xx_hdcs.o \
+ stv06xx_pb0100.o \
+ stv06xx_st6422.o
+
+ccflags-y += -I$(srctree)/drivers/media/usb/gspca
+
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c
index 999ec7764449..999ec7764449 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/usb/gspca/stv06xx/stv06xx.h
index 34957a4ec150..34957a4ec150 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.h
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
index 06fa54c5efb2..06fa54c5efb2 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.h
index 1ba9158d0102..1ba9158d0102 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.h
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
index cdfc3d05ab6b..cdfc3d05ab6b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.h
index 5071e5353fd3..5071e5353fd3 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.h
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/usb/gspca/stv06xx/stv06xx_sensor.h
index 3a498c2495c6..3a498c2495c6 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_sensor.h
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
index 8a57990dfe0f..8a57990dfe0f 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.h
index 8f20fbf30f33..8f20fbf30f33 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.h
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index 748e1421d6d8..748e1421d6d8 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.h
index 53e67b40ca05..53e67b40ca05 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.h
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index 9ccfcb1c6479..9ccfcb1c6479 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/usb/gspca/t613.c
index 8bc6c3ceec2c..8bc6c3ceec2c 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/usb/gspca/t613.c
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index a6055246cb9d..a6055246cb9d 100644
--- a/drivers/media/video/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/usb/gspca/tv8532.c
index 8591324a53e1..8591324a53e1 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/usb/gspca/tv8532.c
diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c
new file mode 100644
index 000000000000..e50079503d96
--- /dev/null
+++ b/drivers/media/usb/gspca/vc032x.c
@@ -0,0 +1,3850 @@
+/*
+ * Z-star vc0321 library
+ *
+ * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ * Copyright (C) 2006 Michel Xhaard
+ *
+ * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct { /* hvflip cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+
+ u8 image_offset;
+
+ u8 bridge;
+ u8 sensor;
+ u8 flags;
+#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
+#define FL_HFLIP 0x02 /* mirrored by default */
+#define FL_VFLIP 0x04 /* vertical flipped by default */
+};
+enum bridges {
+ BRIDGE_VC0321,
+ BRIDGE_VC0323,
+};
+enum sensors {
+ SENSOR_HV7131R,
+ SENSOR_MI0360,
+ SENSOR_MI1310_SOC,
+ SENSOR_MI1320,
+ SENSOR_MI1320_SOC,
+ SENSOR_OV7660,
+ SENSOR_OV7670,
+ SENSOR_PO1200,
+ SENSOR_PO3130NC,
+ SENSOR_POxxxx,
+ NSENSORS
+};
+
+
+static const struct v4l2_pix_format vc0321_mode[] = {
+ {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static const struct v4l2_pix_format vc0323_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+ {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 960 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+};
+static const struct v4l2_pix_format bi_mode[] = {
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static const struct v4l2_pix_format svga_mode[] = {
+ {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 800,
+ .sizeimage = 800 * 600 * 1 / 4 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* OV7660/7670 registers */
+#define OV7660_REG_MVFP 0x1e
+#define OV7660_MVFP_MIRROR 0x20
+#define OV7660_MVFP_VFLIP 0x10
+
+static const u8 mi0360_matrix[9] = {
+ 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
+};
+
+static const u8 mi0360_initVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xb8, 0x00, 0x13, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x14, 0x18, 0xcc},
+ {0xb8, 0xb2, 0x0a, 0xcc},
+ {0xb8, 0xb4, 0x0a, 0xcc},
+ {0xb8, 0xb5, 0x0a, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x31, 0x00, 0x00, 0xbb},
+ {0x09, 0x01, 0xc7, 0xbb},
+ {0x34, 0x01, 0x00, 0xbb},
+ {0x2b, 0x00, 0x28, 0xbb},
+ {0x2c, 0x00, 0x30, 0xbb},
+ {0x2d, 0x00, 0x30, 0xbb},
+ {0x2e, 0x00, 0x28, 0xbb},
+ {0x62, 0x04, 0x11, 0xbb},
+ {0x03, 0x01, 0xe0, 0xbb},
+ {0x2c, 0x00, 0x2c, 0xbb},
+ {0x20, 0xd0, 0x00, 0xbb},
+ {0x01, 0x00, 0x08, 0xbb},
+ {0x06, 0x00, 0x10, 0xbb},
+ {0x05, 0x00, 0x20, 0xbb},
+ {0x20, 0x00, 0x00, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0x35, 0x00, 0x60, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi0360_initQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x13, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc},
+ {0xb8, 0x14, 0x18, 0xcc},
+ {0xb8, 0xb2, 0x0a, 0xcc},
+ {0xb8, 0xb4, 0x0a, 0xcc},
+ {0xb8, 0xb5, 0x0a, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x31, 0x00, 0x00, 0xbb},
+ {0x09, 0x01, 0xc7, 0xbb},
+ {0x34, 0x01, 0x00, 0xbb},
+ {0x2b, 0x00, 0x28, 0xbb},
+ {0x2c, 0x00, 0x30, 0xbb},
+ {0x2d, 0x00, 0x30, 0xbb},
+ {0x2e, 0x00, 0x28, 0xbb},
+ {0x62, 0x04, 0x11, 0xbb},
+ {0x03, 0x01, 0xe0, 0xbb},
+ {0x2c, 0x00, 0x2c, 0xbb},
+ {0x20, 0xd0, 0x00, 0xbb},
+ {0x01, 0x00, 0x08, 0xbb},
+ {0x06, 0x00, 0x10, 0xbb},
+ {0x05, 0x00, 0x20, 0xbb},
+ {0x20, 0x00, 0x00, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc},
+ {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc},
+ {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc},
+ {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0x35, 0x00, 0xef, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+
+static const u8 mi1310_socinitVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const u8 mi1310_socinitQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x0d, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x70, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x60, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x37, 0x01, 0x40, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc},
+ {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x03, 0xcc},
+ {0xb6, 0x04, 0xc0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x09, 0xcc},
+ {0xb6, 0x17, 0x60, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0x06, 0x70, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5e, 0x6a, 0x53, 0xbb},
+ {0x5f, 0x40, 0x2c, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x58, 0x00, 0x00, 0xbb},
+ {0x53, 0x09, 0x03, 0xbb},
+ {0x54, 0x31, 0x18, 0xbb},
+ {0x55, 0x8b, 0x5f, 0xbb},
+ {0x56, 0xc0, 0xa9, 0xbb},
+ {0x57, 0xe0, 0xd2, 0xbb},
+ {0xe1, 0x00, 0x00, 0xbb},
+ {0xdc, 0x09, 0x03, 0xbb},
+ {0xdd, 0x31, 0x18, 0xbb},
+ {0xde, 0x8b, 0x5f, 0xbb},
+ {0xdf, 0xc0, 0xa9, 0xbb},
+ {0xe0, 0xe0, 0xd2, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {}
+};
+
+static const u8 mi1320_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const u8 mi1320_matrix[9] = {
+ 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static const u8 mi1320_initVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd},
+ {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb},
+ {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb},
+ {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb},
+ {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb},
+ {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb},
+ {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb},
+ {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb},
+ {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb},
+ {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb},
+ {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb},
+ {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb},
+ {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb},
+ {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb},
+ {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb},
+ {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb},
+ {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb},
+ {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb},
+ {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb},
+ {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb},
+ {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x00, 0xbb}, /* h/v flips - was 03 */
+ {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd},
+ {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const u8 mi1320_initQVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb},
+ {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb},
+ {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb},
+ {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb},
+ {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb},
+ {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb},
+ {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb},
+ {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb},
+ {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb},
+ {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb},
+ {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb},
+ {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb},
+ {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb},
+ {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb},
+ {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb},
+ {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb},
+ {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb},
+ {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb},
+ {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb},
+ {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb},
+ {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb},
+ {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const u8 mi1320_soc_InitVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitQVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+static const u8 mi1320_soc_InitSXGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb},
+ {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x64, 0x5e, 0x1c, 0xbb},
+ {}
+};
+static const u8 po3130_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const u8 po3130_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static const u8 po3130_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const u8 po3130_rundata[][4] = {
+ {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
+ {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
+ {0x00, 0x44, 0x40, 0xaa},
+/* {0x00, 0xd5, 0x7c, 0xaa}, */
+ {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa},
+ {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa},
+ {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa},
+ {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa},
+ {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa},
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {}
+};
+
+static const u8 po3130_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+ {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const u8 hv7131r_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const u8 hv7131r_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static const u8 hv7131r_initVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x02, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc}, /* i2c add: 11 */
+ {0xb3, 0x00, 0x27, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x58, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x03, 0xaa},
+ {0x00, 0x26, 0xa9, 0xaa},
+ {0x00, 0x27, 0x80, 0xaa},
+ {0x00, 0x30, 0x18, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+
+static const u8 hv7131r_initQVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x02, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc},
+ {0xbc, 0x00, 0xd3, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc},
+ {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc},
+ {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x58, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x03, 0xaa},
+ {0x00, 0x26, 0xa9, 0xaa},
+ {0x00, 0x27, 0x80, 0xaa},
+ {0x00, 0x30, 0x18, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc},
+ {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc},
+ {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc},
+ {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x10, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb9, 0x12, 0x00, 0xcc},
+ {0xb9, 0x13, 0x0a, 0xcc},
+ {0xb9, 0x14, 0x0a, 0xcc},
+ {0xb9, 0x15, 0x0a, 0xcc},
+ {0xb9, 0x16, 0x0a, 0xcc},
+ {0xb9, 0x18, 0x00, 0xcc},
+ {0xb9, 0x19, 0x0f, 0xcc},
+ {0xb8, 0x0c, 0x20, 0xcc},
+ {0xb8, 0x0d, 0x70, 0xcc},
+ {0xb9, 0x1a, 0x0f, 0xcc},
+ {0xb9, 0x1b, 0x0f, 0xcc},
+ {0xb9, 0x1c, 0x0f, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x13, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+
+static const u8 ov7660_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const u8 ov7660_matrix[9] = {
+ 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static const u8 ov7660_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
+ {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa},
+ {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa},
+ {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+
+ {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
+ {}
+};
+static const u8 ov7660_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+ {0xbc, 0x00, 0xd3, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+ {0xbc, 0x02, 0x08, 0xcc},
+ {0xbc, 0x03, 0x70, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xbc, 0x04, 0x08, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x3c, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x04, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+/* */
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+/* */
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+/* */
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+ {0x00, 0x29, 0x3c, 0xaa},
+ {0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+ {}
+};
+
+static const u8 ov7660_50HZ[][4] = {
+ {0x00, 0x3b, 0x08, 0xaa},
+ {0x00, 0x9d, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {}
+};
+
+static const u8 ov7660_60HZ[][4] = {
+ {0x00, 0x3b, 0x00, 0xaa},
+ {0x00, 0x9e, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {}
+};
+
+static const u8 ov7660_NoFliker[][4] = {
+ {0x00, 0x13, 0x87, 0xaa},
+ {}
+};
+
+static const u8 ov7670_InitVGA[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb0, 0x16, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xbc, 0x00, 0x41, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa},
+ {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa},
+ {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa},
+ {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa},
+ {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa},
+ {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa},
+ {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa},
+ {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa},
+ {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa},
+ {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa},
+ {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa},
+ {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa},
+ {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa},
+ {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa},
+ {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa},
+ {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa},
+ {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa},
+ {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa},
+ {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa},
+ {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
+ {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa},
+ {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa},
+ {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa},
+ {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa},
+ {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa},
+ {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa},
+ {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa},
+ {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa},
+ {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa},
+ {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa},
+ {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa},
+ {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa},
+ {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa},
+ {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa},
+ {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa},
+ {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa},
+ {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa},
+ {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa},
+ {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa},
+ {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa},
+ {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa},
+ {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa},
+ {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa},
+ {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa},
+ {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa},
+ {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa},
+ {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa},
+ {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa},
+ {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa},
+ {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa},
+ {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa},
+ {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa},
+ {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa},
+ {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa},
+ {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa},
+ {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa},
+ {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa},
+ {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa},
+ {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa},
+ {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa},
+ {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa},
+ {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa},
+ {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa},
+ {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa},
+ {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa},
+ {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa},
+ {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa},
+ {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa},
+ {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa},
+ {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa},
+ {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa},
+ {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa},
+ {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa},
+ {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa},
+ {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa},
+ {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa},
+ {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa},
+ {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
+ {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa},
+ {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa},
+ {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa},
+ {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa},
+ {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa},
+ {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa},
+ {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa},
+ {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa},
+ {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa},
+ {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa},
+ {},
+};
+
+static const u8 ov7670_InitQVGA[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb0, 0x16, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa},
+ {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa},
+ {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa},
+ {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa},
+ {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa},
+ {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa},
+ {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa},
+ {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa},
+ {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa},
+ {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa},
+ {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa},
+ {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa},
+ {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa},
+ {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa},
+ {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa},
+ {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa},
+ {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa},
+ {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa},
+ {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa},
+ {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
+ {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa},
+ {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa},
+ {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa},
+ {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa},
+ {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa},
+ {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa},
+ {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa},
+ {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa},
+ {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa},
+ {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa},
+ {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa},
+ {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa},
+ {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa},
+ {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa},
+ {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa},
+ {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa},
+ {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa},
+ {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa},
+ {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa},
+ {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa},
+ {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa},
+ {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa},
+ {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa},
+ {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa},
+ {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa},
+ {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa},
+ {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa},
+ {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa},
+ {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa},
+ {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa},
+ {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa},
+ {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa},
+ {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa},
+ {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa},
+ {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa},
+ {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa},
+ {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa},
+ {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa},
+ {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa},
+ {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa},
+ {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa},
+ {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa},
+ {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa},
+ {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa},
+ {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa},
+ {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa},
+ {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa},
+ {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa},
+ {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa},
+ {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa},
+ {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa},
+ {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa},
+ {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa},
+ {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa},
+ {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa},
+ {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa},
+ {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa},
+ {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
+ {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa},
+ {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa},
+ {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa},
+ {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa},
+ {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa},
+ {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa},
+ {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa},
+ {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa},
+ {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa},
+ {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa},
+ {},
+};
+
+/* PO1200 - values from usbvm326.inf and ms-win trace */
+static const u8 po1200_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const u8 po1200_matrix[9] = {
+ 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
+};
+static const u8 po1200_initVGA_data[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, /* reset? */
+ {0xb0, 0x03, 0x19, 0xcc},
+/* {0x00, 0x00, 0x33, 0xdd}, */
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb0, 0x02, 0x02, 0xcc},
+ {0xb3, 0x5d, 0x00, 0xcc},
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x02, 0xb2, 0xcc},
+ {0xb3, 0x03, 0x18, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x02, 0xcc},
+ {0xb3, 0x23, 0x58, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x03, 0xcc},
+ {0xb3, 0x17, 0x1f, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb0, 0x54, 0x13, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xdc, 0xcc}, /* i2c add: 5c */
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x13, 0x02, 0xaa},
+ {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */
+ {0x00, 0x21, 0x00, 0xaa},
+ {0x00, 0x25, 0x02, 0xaa},
+ {0x00, 0x3c, 0x4f, 0xaa},
+ {0x00, 0x3f, 0xe0, 0xaa},
+ {0x00, 0x42, 0xff, 0xaa},
+ {0x00, 0x45, 0x34, 0xaa},
+ {0x00, 0x55, 0xfe, 0xaa},
+ {0x00, 0x59, 0xd3, 0xaa},
+ {0x00, 0x5e, 0x04, 0xaa},
+ {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */
+ {0x00, 0x62, 0x02, 0xaa},
+ {0x00, 0xa7, 0x31, 0xaa},
+ {0x00, 0xa9, 0x66, 0xaa},
+ {0x00, 0xb0, 0x00, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb3, 0x11, 0xaa},
+ {0x00, 0xb6, 0x26, 0xaa},
+ {0x00, 0xb7, 0x20, 0xaa},
+ {0x00, 0xba, 0x04, 0xaa},
+ {0x00, 0x88, 0x42, 0xaa},
+ {0x00, 0x89, 0x9a, 0xaa},
+ {0x00, 0x8a, 0x88, 0xaa},
+ {0x00, 0x8b, 0x8e, 0xaa},
+ {0x00, 0x8c, 0x3e, 0xaa},
+ {0x00, 0x8d, 0x90, 0xaa},
+ {0x00, 0x8e, 0x87, 0xaa},
+ {0x00, 0x8f, 0x96, 0xaa},
+ {0x00, 0x90, 0x3d, 0xaa},
+ {0x00, 0x64, 0x00, 0xaa},
+ {0x00, 0x65, 0x10, 0xaa},
+ {0x00, 0x66, 0x20, 0xaa},
+ {0x00, 0x67, 0x2b, 0xaa},
+ {0x00, 0x68, 0x36, 0xaa},
+ {0x00, 0x69, 0x49, 0xaa},
+ {0x00, 0x6a, 0x5a, 0xaa},
+ {0x00, 0x6b, 0x7f, 0xaa},
+ {0x00, 0x6c, 0x9b, 0xaa},
+ {0x00, 0x6d, 0xba, 0xaa},
+ {0x00, 0x6e, 0xd4, 0xaa},
+ {0x00, 0x6f, 0xea, 0xaa},
+ {0x00, 0x70, 0x00, 0xaa},
+ {0x00, 0x71, 0x10, 0xaa},
+ {0x00, 0x72, 0x20, 0xaa},
+ {0x00, 0x73, 0x2b, 0xaa},
+ {0x00, 0x74, 0x36, 0xaa},
+ {0x00, 0x75, 0x49, 0xaa},
+ {0x00, 0x76, 0x5a, 0xaa},
+ {0x00, 0x77, 0x7f, 0xaa},
+ {0x00, 0x78, 0x9b, 0xaa},
+ {0x00, 0x79, 0xba, 0xaa},
+ {0x00, 0x7a, 0xd4, 0xaa},
+ {0x00, 0x7b, 0xea, 0xaa},
+ {0x00, 0x7c, 0x00, 0xaa},
+ {0x00, 0x7d, 0x10, 0xaa},
+ {0x00, 0x7e, 0x20, 0xaa},
+ {0x00, 0x7f, 0x2b, 0xaa},
+ {0x00, 0x80, 0x36, 0xaa},
+ {0x00, 0x81, 0x49, 0xaa},
+ {0x00, 0x82, 0x5a, 0xaa},
+ {0x00, 0x83, 0x7f, 0xaa},
+ {0x00, 0x84, 0x9b, 0xaa},
+ {0x00, 0x85, 0xba, 0xaa},
+ {0x00, 0x86, 0xd4, 0xaa},
+ {0x00, 0x87, 0xea, 0xaa},
+ {0x00, 0x57, 0x2a, 0xaa},
+ {0x00, 0x03, 0x01, 0xaa},
+ {0x00, 0x04, 0x10, 0xaa},
+ {0x00, 0x05, 0x10, 0xaa},
+ {0x00, 0x06, 0x10, 0xaa},
+ {0x00, 0x07, 0x10, 0xaa},
+ {0x00, 0x08, 0x13, 0xaa},
+ {0x00, 0x0a, 0x00, 0xaa},
+ {0x00, 0x0b, 0x10, 0xaa},
+ {0x00, 0x0c, 0x20, 0xaa},
+ {0x00, 0x0d, 0x18, 0xaa},
+ {0x00, 0x22, 0x01, 0xaa},
+ {0x00, 0x23, 0x60, 0xaa},
+ {0x00, 0x25, 0x08, 0xaa},
+ {0x00, 0x26, 0x82, 0xaa},
+ {0x00, 0x2e, 0x0f, 0xaa},
+ {0x00, 0x2f, 0x1e, 0xaa},
+ {0x00, 0x30, 0x2d, 0xaa},
+ {0x00, 0x31, 0x3c, 0xaa},
+ {0x00, 0x32, 0x4b, 0xaa},
+ {0x00, 0x33, 0x5a, 0xaa},
+ {0x00, 0x34, 0x69, 0xaa},
+ {0x00, 0x35, 0x78, 0xaa},
+ {0x00, 0x36, 0x87, 0xaa},
+ {0x00, 0x37, 0x96, 0xaa},
+ {0x00, 0x38, 0xa5, 0xaa},
+ {0x00, 0x39, 0xb4, 0xaa},
+ {0x00, 0x3a, 0xc3, 0xaa},
+ {0x00, 0x3b, 0xd2, 0xaa},
+ {0x00, 0x3c, 0xe1, 0xaa},
+ {0x00, 0x3e, 0xff, 0xaa},
+ {0x00, 0x3f, 0xff, 0xaa},
+ {0x00, 0x40, 0xff, 0xaa},
+ {0x00, 0x41, 0xff, 0xaa},
+ {0x00, 0x42, 0xff, 0xaa},
+ {0x00, 0x43, 0xff, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x20, 0xc4, 0xaa},
+ {0x00, 0x13, 0x03, 0xaa},
+ {0x00, 0x3c, 0x50, 0xaa},
+ {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */
+ {0x00, 0x51, 0x5b, 0xaa},
+ {0x00, 0x52, 0x91, 0xaa},
+ {0x00, 0x53, 0x4c, 0xaa},
+ {0x00, 0x54, 0x50, 0xaa},
+ {0x00, 0x56, 0x02, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x03, 0xcc},
+ {0xb6, 0x02, 0x20, 0xcc},
+ {0xb6, 0x05, 0x02, 0xcc},
+ {0xb6, 0x04, 0x58, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x21, 0xcc},
+ {0xb6, 0x18, 0x03, 0xcc},
+ {0xb6, 0x17, 0xa9, 0xcc},
+ {0xb6, 0x16, 0x80, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb8, 0x06, 0x20, 0xcc},
+ {0xb8, 0x07, 0x03, 0xcc},
+ {0xb8, 0x08, 0x58, 0xcc},
+ {0xb8, 0x09, 0x02, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xd9, 0x0f, 0xaa},
+ {0x00, 0xda, 0xaa, 0xaa},
+ {0x00, 0xd9, 0x10, 0xaa},
+ {0x00, 0xda, 0xaa, 0xaa},
+ {0x00, 0xd9, 0x11, 0xaa},
+ {0x00, 0xda, 0x00, 0xaa},
+ {0x00, 0xd9, 0x12, 0xaa},
+ {0x00, 0xda, 0xff, 0xaa},
+ {0x00, 0xd9, 0x13, 0xaa},
+ {0x00, 0xda, 0xff, 0xaa},
+ {0x00, 0xe8, 0x11, 0xaa},
+ {0x00, 0xe9, 0x12, 0xaa},
+ {0x00, 0xea, 0x5c, 0xaa},
+ {0x00, 0xeb, 0xff, 0xaa},
+ {0x00, 0xd8, 0x80, 0xaa},
+ {0x00, 0xe6, 0x02, 0xaa},
+ {0x00, 0xd6, 0x40, 0xaa},
+ {0x00, 0xe3, 0x05, 0xaa},
+ {0x00, 0xe0, 0x40, 0xaa},
+ {0x00, 0xde, 0x03, 0xaa},
+ {0x00, 0xdf, 0x03, 0xaa},
+ {0x00, 0xdb, 0x02, 0xaa},
+ {0x00, 0xdc, 0x00, 0xaa},
+ {0x00, 0xdd, 0x03, 0xaa},
+ {0x00, 0xe1, 0x08, 0xaa},
+ {0x00, 0xe2, 0x01, 0xaa},
+ {0x00, 0xd6, 0x40, 0xaa},
+ {0x00, 0xe4, 0x40, 0xaa},
+ {0x00, 0xa8, 0x8f, 0xaa},
+ {0x00, 0xb4, 0x16, 0xaa},
+ {0xb0, 0x02, 0x06, 0xcc},
+ {0xb0, 0x18, 0x06, 0xcc},
+ {0xb0, 0x19, 0x06, 0xcc},
+ {0xb3, 0x5d, 0x18, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0x00, 0xb4, 0x0e, 0xaa},
+ {0x00, 0xb5, 0x49, 0xaa},
+ {0x00, 0xb6, 0x1c, 0xaa},
+ {0x00, 0xb7, 0x96, 0xaa},
+/* end of usbvm326.inf - start of ms-win trace */
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x3d, 0xcc},
+/*read b306*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x1a, 0x09, 0xaa},
+ {0x00, 0x1b, 0x8a, 0xaa},
+/*read b827*/
+ {0xb8, 0x27, 0x00, 0xcc},
+ {0xb8, 0x26, 0x60, 0xcc},
+ {0xb8, 0x26, 0x60, 0xcc},
+/*gamma - to do?*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xae, 0x84, 0xaa},
+/*gamma again*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x96, 0xa0, 0xaa},
+/*matrix*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x91, 0x35, 0xaa},
+ {0x00, 0x92, 0x22, 0xaa},
+/*gamma*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x95, 0x85, 0xaa},
+/*matrix*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x4d, 0x20, 0xaa},
+ {0xb8, 0x22, 0x40, 0xcc},
+ {0xb8, 0x23, 0x40, 0xcc},
+ {0xb8, 0x24, 0x40, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0x00, 0x00, 0x64, 0xdd},
+ {0x00, 0x03, 0x01, 0xaa},
+/*read 46*/
+ {0x00, 0x46, 0x3c, 0xaa},
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0x16, 0x40, 0xaa},
+ {0x00, 0x17, 0x40, 0xaa},
+ {0x00, 0x18, 0x40, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa},
+ {0x00, 0x03, 0x01, 0xaa},
+ {0x00, 0x46, 0x3c, 0xaa},
+ {0x00, 0x00, 0x18, 0xdd},
+/*read bfff*/
+ {0x00, 0x03, 0x00, 0xaa},
+ {0x00, 0xb4, 0x1c, 0xaa},
+ {0x00, 0xb5, 0x92, 0xaa},
+ {0x00, 0xb6, 0x39, 0xaa},
+ {0x00, 0xb7, 0x24, 0xaa},
+/*write 89 0400 1415*/
+ {}
+};
+
+static const u8 poxxxx_init_common[][4] = {
+ {0xb3, 0x00, 0x04, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb0, 0x03, 0x09, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x03, 0x18, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x2c, 0x03, 0xcc},
+ {0xb3, 0x2d, 0x56, 0xcc},
+ {0xb3, 0x2e, 0x02, 0xcc},
+ {0xb3, 0x2f, 0x0a, 0xcc},
+ {0xb3, 0x40, 0x00, 0xcc},
+ {0xb3, 0x41, 0x34, 0xcc},
+ {0xb3, 0x42, 0x01, 0xcc},
+ {0xb3, 0x43, 0xe0, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb3, 0x4d, 0x00, 0xcc},
+ {0x00, 0x0b, 0x2a, 0xaa},
+ {0x00, 0x0e, 0x03, 0xaa},
+ {0x00, 0x0f, 0xea, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa},
+ {0x00, 0x31, 0x1f, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa},
+ {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa},
+ {0x00, 0x4d, 0x2e, 0xaa},
+ {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa},
+ {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x56, 0x0a, 0xaa},
+ {0x00, 0x57, 0x07, 0xaa},
+ {0x00, 0x58, 0x07, 0xaa},
+ {0x00, 0x59, 0x04, 0xaa},
+ {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x71, 0x04, 0xaa},
+ {0x00, 0x72, 0x10, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa},
+ {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa},
+ {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa},
+ {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x8b, 0x25, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x8d, 0x86, 0xaa},
+ {0x00, 0x8e, 0x82, 0xaa},
+ {0x00, 0x8f, 0x2d, 0xaa},
+ {0x00, 0x90, 0x8b, 0xaa},
+ {0x00, 0x91, 0x81, 0xaa},
+ {0x00, 0x92, 0x81, 0xaa},
+ {0x00, 0x93, 0x23, 0xaa},
+ {0x00, 0xa3, 0x2a, 0xaa},
+ {0x00, 0xa4, 0x03, 0xaa},
+ {0x00, 0xa5, 0xea, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa},
+ {0x00, 0xbe, 0x3b, 0xaa},
+ {0x00, 0x4e, 0x40, 0xaa},
+ {0x00, 0x06, 0x04, 0xaa},
+ {0x00, 0x07, 0x03, 0xaa},
+ {0x00, 0xcd, 0x18, 0xaa},
+ {0x00, 0x28, 0x03, 0xaa},
+ {0x00, 0x29, 0xef, 0xaa},
+/* reinit on alt 2 (qvga) or alt7 (vga) */
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb8, 0x00, 0x01, 0xcc},
+
+ {0x00, 0x1d, 0x85, 0xaa},
+ {0x00, 0x1e, 0xc6, 0xaa},
+ {0x00, 0x00, 0x40, 0xdd},
+ {0x00, 0x1d, 0x05, 0xaa},
+ {}
+};
+static const u8 poxxxx_gamma[][4] = {
+ {0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+
+ {0x00, 0xd6, 0x62, 0xaa}, /* gamma 1 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+
+ {0x00, 0xd6, 0xa2, 0xaa}, /* gamma 2 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+ {}
+};
+static const u8 poxxxx_init_start_3[][4] = {
+ {0x00, 0xb8, 0x28, 0xaa},
+ {0x00, 0xb9, 0x1e, 0xaa},
+ {0x00, 0xb6, 0x14, 0xaa},
+ {0x00, 0xb7, 0x0f, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa},
+ {0x00, 0x5d, 0x18, 0xaa},
+ {0x00, 0x5e, 0x24, 0xaa},
+ {0x00, 0x5f, 0x24, 0xaa},
+ {0x00, 0x86, 0x1a, 0xaa},
+ {0x00, 0x60, 0x00, 0xaa},
+ {0x00, 0x61, 0x1b, 0xaa},
+ {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x40, 0xaa},
+ {0x00, 0x87, 0x1a, 0xaa},
+ {0x00, 0x64, 0x00, 0xaa},
+ {0x00, 0x65, 0x08, 0xaa},
+ {0x00, 0x66, 0x10, 0xaa},
+ {0x00, 0x67, 0x20, 0xaa},
+ {0x00, 0x88, 0x10, 0xaa},
+ {0x00, 0x68, 0x00, 0xaa},
+ {0x00, 0x69, 0x08, 0xaa},
+ {0x00, 0x6a, 0x0f, 0xaa},
+ {0x00, 0x6b, 0x0f, 0xaa},
+ {0x00, 0x89, 0x07, 0xaa},
+ {0x00, 0xd5, 0x4c, 0xaa},
+ {0x00, 0x0a, 0x00, 0xaa},
+ {0x00, 0x0b, 0x2a, 0xaa},
+ {0x00, 0x0e, 0x03, 0xaa},
+ {0x00, 0x0f, 0xea, 0xaa},
+ {0x00, 0xa2, 0x00, 0xaa},
+ {0x00, 0xa3, 0x2a, 0xaa},
+ {0x00, 0xa4, 0x03, 0xaa},
+ {0x00, 0xa5, 0xea, 0xaa},
+ {}
+};
+static const u8 poxxxx_initVGA[][4] = {
+ {0x00, 0x20, 0x11, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0xbb, 0x0d, 0xaa},
+ {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0x00, 0x04, 0x06, 0xaa},
+ {0x00, 0x05, 0x3f, 0xaa},
+ {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
+ {}
+};
+static const u8 poxxxx_initQVGA[][4] = {
+ {0x00, 0x20, 0x33, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0xbb, 0x0d, 0xaa},
+ {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */
+ {0xb3, 0x23, 0xf0, 0xcc},
+ {0xb3, 0x16, 0x01, 0xcc},
+ {0xb3, 0x17, 0x3f, 0xcc},
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x00, 0xcc},
+ {0x00, 0x04, 0x06, 0xaa},
+ {0x00, 0x05, 0x3f, 0xaa},
+ {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
+ {}
+};
+static const u8 poxxxx_init_end_1[][4] = {
+ {0x00, 0x47, 0x25, 0xaa},
+ {0x00, 0x48, 0x80, 0xaa},
+ {0x00, 0x49, 0x1f, 0xaa},
+ {0x00, 0x4a, 0x40, 0xaa},
+ {0x00, 0x44, 0x40, 0xaa},
+ {0x00, 0xab, 0x4a, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb2, 0x04, 0xaa},
+ {0x00, 0xb3, 0x08, 0xaa},
+ {0x00, 0xb4, 0x0b, 0xaa},
+ {0x00, 0xb5, 0x0d, 0xaa},
+ {}
+};
+static const u8 poxxxx_init_end_2[][4] = {
+ {0x00, 0x1d, 0x85, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x1d, 0x05, 0xaa},
+ {}
+};
+
+struct sensor_info {
+ s8 sensorId;
+ u8 I2cAdd;
+ u8 IdAdd;
+ u16 VpId;
+ u8 m1;
+ u8 m2;
+ u8 op;
+};
+
+/* probe values */
+static const struct sensor_info vc0321_probe_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+/* 0 OV9640 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
+ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
+ {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 3 MI1310 */
+ {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 4 MI360 - tested in vc032x_probe_sensor */
+/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+/* 5 7131R */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+/* 6 OV7649 */
+ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+/* 7 PAS302BCW */
+ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+/* 8 OV7660 */
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
+/* 10 PO1030KC */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 11 MI1310_SOC */
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* 12 OV9650 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 13 S5K532 */
+ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+/* 14 MI360_SOC - ??? */
+/* 15 PO1200N */
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+/* 16 PO3030K */
+ {-1, 0x80 | 0x18, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 17 PO2030 */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* ?? */
+ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
+};
+static const struct sensor_info vc0323_probe_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+/* 0 OV9640 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
+ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
+ {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 3 MI1310 */
+ {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 4 MI360 - tested in vc032x_probe_sensor */
+/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+/* 5 7131R */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+/* 6 OV7649 */
+ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+/* 7 PAS302BCW */
+ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+/* 8 OV7660 */
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
+/* 10 PO1030KC */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 11 MI1310_SOC */
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* 12 OV9650 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 13 S5K532 */
+ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+/* 14 MI360_SOC - ??? */
+/* 15 PO1200N */
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+/* 16 ?? */
+ {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
+/* 17 PO2030 */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* ?? */
+ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+ {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
+/*fixme: not in the ms-win probe - may be found before? */
+ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+};
+
+/* read 'len' bytes in gspca_dev->usb_buf */
+static void reg_r_i(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 index,
+ u16 len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, /* value */
+ index, gspca_dev->usb_buf, len,
+ 500);
+ if (ret < 0) {
+ pr_err("reg_r err %d\n", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 index,
+ u16 len)
+{
+ reg_r_i(gspca_dev, req, index, len);
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (len == 1)
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
+ gspca_dev->usb_buf[0]);
+ else
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %*ph",
+ req, index, 3, gspca_dev->usb_buf);
+#endif
+}
+
+static void reg_w_i(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 value,
+ u16 index)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+ if (ret < 0) {
+ pr_err("reg_w err %d\n", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_w(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 value,
+ u16 index)
+{
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+#endif
+ reg_w_i(gspca_dev, req, value, index);
+}
+
+static u16 read_sensor_register(struct gspca_dev *gspca_dev,
+ u16 address)
+{
+ u8 ldata, mdata, hdata;
+ int retry = 50;
+
+ reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+ if (!(gspca_dev->usb_buf[0] & 0x02)) {
+ pr_err("I2c Bus Busy Wait %02x\n", gspca_dev->usb_buf[0]);
+ return 0;
+ }
+ reg_w(gspca_dev, 0xa0, address, 0xb33a);
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
+
+ do {
+ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+ if (gspca_dev->usb_buf[0] == 0x00)
+ break;
+ msleep(40);
+ } while (--retry >= 0);
+
+ reg_r(gspca_dev, 0xa1, 0xb33e, 1);
+ ldata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33d, 1);
+ mdata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33c, 1);
+ hdata = gspca_dev->usb_buf[0];
+ if (hdata != 0 && mdata != 0 && ldata != 0)
+ PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
+ hdata, mdata, ldata);
+ reg_r(gspca_dev, 0xa1, 0xb334, 1);
+ if (gspca_dev->usb_buf[0] == 0x02)
+ return (hdata << 8) + mdata;
+ return hdata;
+}
+
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, n;
+ u16 value;
+ const struct sensor_info *ptsensor_info;
+
+/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ /* select the back sensor */
+ }
+
+ reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
+ PDEBUG(D_PROBE, "vc032%d check sensor header %02x",
+ sd->bridge == BRIDGE_VC0321 ? 1 : 3, gspca_dev->usb_buf[0]);
+ if (sd->bridge == BRIDGE_VC0321) {
+ ptsensor_info = vc0321_probe_data;
+ n = ARRAY_SIZE(vc0321_probe_data);
+ } else {
+ ptsensor_info = vc0323_probe_data;
+ n = ARRAY_SIZE(vc0323_probe_data);
+ }
+ for (i = 0; i < n; i++) {
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
+ reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
+ value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
+ if (value == 0 && ptsensor_info->IdAdd == 0x82)
+ value = read_sensor_register(gspca_dev, 0x83);
+ if (value != 0) {
+ PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
+ value, i);
+ if (value == ptsensor_info->VpId)
+ return ptsensor_info->sensorId;
+
+ switch (value) {
+ case 0x3130:
+ return SENSOR_PO3130NC;
+ case 0x7673:
+ return SENSOR_OV7670;
+ case 0x8243:
+ return SENSOR_MI0360;
+ }
+ }
+ ptsensor_info++;
+ }
+ return -1;
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev,
+ u8 reg, const u8 *val,
+ u8 size) /* 1 or 2 */
+{
+ int retry;
+
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (size == 1)
+ PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
+ else
+ PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
+#endif
+ reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
+/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
+ reg_w_i(gspca_dev, 0xa0, size, 0xb334);
+ reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
+ reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
+ if (size > 1)
+ reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
+ reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
+ retry = 4;
+ do {
+ reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
+ if (gspca_dev->usb_buf[0] == 0)
+ break;
+ msleep(20);
+ } while (--retry > 0);
+ if (retry <= 0)
+ pr_err("i2c_write timeout\n");
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+ const u8 *tab, u8 tabsize, u16 addr)
+{
+ int j;
+ u16 ad = addr;
+
+ for (j = 0; j < tabsize; j++)
+ reg_w(gspca_dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+ const u8 data[][4])
+{
+ int i = 0;
+
+ for (;;) {
+ switch (data[i][3]) {
+ default:
+ return;
+ case 0xcc: /* normal write */
+ reg_w(gspca_dev, 0xa0, data[i][2],
+ (data[i][0]) << 8 | data[i][1]);
+ break;
+ case 0xaa: /* i2c op */
+ i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
+ break;
+ case 0xbb: /* i2c op */
+ i2c_write(gspca_dev, data[i][0], &data[i][1], 2);
+ break;
+ case 0xdd:
+ msleep(data[i][1] * 256 + data[i][2] + 10);
+ break;
+ }
+ i++;
+ }
+ /*not reached*/
+}
+
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->bridge = id->driver_info >> 8;
+ sd->flags = id->driver_info & 0xff;
+
+ if (id->idVendor == 0x046d &&
+ (id->idProduct == 0x0892 || id->idProduct == 0x0896))
+ sd->sensor = SENSOR_POxxxx; /* no probe */
+
+ 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;
+ struct cam *cam;
+ int sensor;
+ /* number of packets per ISOC message */
+ static u8 npkt[NSENSORS] = {
+ [SENSOR_HV7131R] = 64,
+ [SENSOR_MI0360] = 32,
+ [SENSOR_MI1310_SOC] = 32,
+ [SENSOR_MI1320] = 64,
+ [SENSOR_MI1320_SOC] = 128,
+ [SENSOR_OV7660] = 32,
+ [SENSOR_OV7670] = 64,
+ [SENSOR_PO1200] = 128,
+ [SENSOR_PO3130NC] = 128,
+ [SENSOR_POxxxx] = 128,
+ };
+
+ if (sd->sensor != SENSOR_POxxxx)
+ sensor = vc032x_probe_sensor(gspca_dev);
+ else
+ sensor = sd->sensor;
+
+ switch (sensor) {
+ case -1:
+ pr_err("Unknown sensor...\n");
+ return -EINVAL;
+ case SENSOR_HV7131R:
+ PDEBUG(D_PROBE, "Find Sensor HV7131R");
+ break;
+ case SENSOR_MI0360:
+ PDEBUG(D_PROBE, "Find Sensor MI0360");
+ sd->bridge = BRIDGE_VC0323;
+ break;
+ case SENSOR_MI1310_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+ break;
+ case SENSOR_MI1320:
+ PDEBUG(D_PROBE, "Find Sensor MI1320");
+ break;
+ case SENSOR_MI1320_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
+ break;
+ case SENSOR_OV7660:
+ PDEBUG(D_PROBE, "Find Sensor OV7660");
+ break;
+ case SENSOR_OV7670:
+ PDEBUG(D_PROBE, "Find Sensor OV7670");
+ break;
+ case SENSOR_PO1200:
+ PDEBUG(D_PROBE, "Find Sensor PO1200");
+ break;
+ case SENSOR_PO3130NC:
+ PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+ break;
+ case SENSOR_POxxxx:
+ PDEBUG(D_PROBE, "Sensor POxxxx");
+ break;
+ }
+ sd->sensor = sensor;
+
+ cam = &gspca_dev->cam;
+ if (sd->bridge == BRIDGE_VC0321) {
+ cam->cam_mode = vc0321_mode;
+ cam->nmodes = ARRAY_SIZE(vc0321_mode);
+ } else {
+ switch (sensor) {
+ case SENSOR_PO1200:
+ cam->cam_mode = svga_mode;
+ cam->nmodes = ARRAY_SIZE(svga_mode);
+ break;
+ case SENSOR_MI1310_SOC:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
+ break;
+ case SENSOR_MI1320_SOC:
+ cam->cam_mode = bi_mode;
+ cam->nmodes = ARRAY_SIZE(bi_mode);
+ break;
+ case SENSOR_OV7670:
+ cam->cam_mode = bi_mode;
+ cam->nmodes = ARRAY_SIZE(bi_mode) - 1;
+ break;
+ default:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
+ break;
+ }
+ }
+ cam->npkt = npkt[sd->sensor];
+
+ if (sd->sensor == SENSOR_OV7670)
+ sd->flags |= FL_HFLIP | FL_VFLIP;
+
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_r(gspca_dev, 0x8a, 0, 3);
+ reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
+ reg_r(gspca_dev, 0x8b, 0, 3);
+ reg_w(gspca_dev, 0x88, 0x00, 0x0202);
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_r(gspca_dev, 0xa1, 0xb300, 1);
+ if (gspca_dev->usb_buf[0] != 0) {
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ }
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
+ }
+ }
+ return gspca_dev->usb_err;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
+{
+ u8 data;
+
+ data = val;
+ if (data >= 0x80)
+ data &= 0x7f;
+ else
+ data = 0xff ^ data;
+ i2c_write(gspca_dev, 0x98, &data, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev, u8 val)
+{
+ i2c_write(gspca_dev, 0x99, &val, 1);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev, u8 val)
+{
+ u8 data;
+
+ data = val - (val >> 3) - 1;
+ i2c_write(gspca_dev, 0x94, &data, 1);
+ i2c_write(gspca_dev, 0x95, &val, 1);
+}
+
+static void sethvflip(struct gspca_dev *gspca_dev, bool hflip, bool vflip)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 data[2];
+
+ if (sd->flags & FL_HFLIP)
+ hflip = !hflip;
+ if (sd->flags & FL_VFLIP)
+ vflip = !vflip;
+ switch (sd->sensor) {
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320:
+ case SENSOR_MI1320_SOC:
+ data[0] = data[1] = 0; /* select page 0 */
+ i2c_write(gspca_dev, 0xf0, data, 2);
+ data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
+ data[1] = 0x02 * hflip
+ | 0x01 * vflip;
+ i2c_write(gspca_dev, 0x20, data, 2);
+ break;
+ case SENSOR_OV7660:
+ case SENSOR_OV7670:
+ data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
+ data[0] |= OV7660_MVFP_MIRROR * hflip
+ | OV7660_MVFP_VFLIP * vflip;
+ i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
+ break;
+ case SENSOR_PO1200:
+ data[0] = 0;
+ i2c_write(gspca_dev, 0x03, data, 1);
+ data[0] = 0x80 * hflip
+ | 0x40 * vflip
+ | 0x06;
+ i2c_write(gspca_dev, 0x1e, data, 1);
+ break;
+ }
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const u8 (*ov7660_freq_tb[3])[4] =
+ {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+ if (sd->sensor != SENSOR_OV7660)
+ return;
+ usb_exchange(gspca_dev, ov7660_freq_tb[val]);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 data;
+
+ switch (sd->sensor) {
+ case SENSOR_PO1200:
+ data = 0;
+ i2c_write(gspca_dev, 0x03, &data, 1);
+ if (val < 0)
+ data = 0x6a;
+ else
+ data = 0xb5 + val * 3;
+ i2c_write(gspca_dev, 0x61, &data, 1);
+ break;
+ case SENSOR_POxxxx:
+ if (val < 0)
+ data = 0x7e; /* def = max */
+ else
+ data = 0x60 + val * 0x0f;
+ i2c_write(gspca_dev, 0x59, &data, 1);
+ break;
+ }
+}
+static void setgain(struct gspca_dev *gspca_dev, u8 val)
+{
+ i2c_write(gspca_dev, 0x15, &val, 1);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+ u8 data;
+
+ data = val >> 8;
+ i2c_write(gspca_dev, 0x1a, &data, 1);
+ data = val;
+ i2c_write(gspca_dev, 0x1b, &data, 1);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev, s32 val)
+{
+ static const u8 data[2] = {0x28, 0x3c};
+
+ i2c_write(gspca_dev, 0xd1, &data[val], 1);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+/*fixme:to do */
+ usb_exchange(gspca_dev, poxxxx_gamma);
+}
+
+static void setbacklight(struct gspca_dev *gspca_dev, s32 val)
+{
+ u16 v;
+ u8 data;
+
+ data = (val << 4) | 0x0f;
+ i2c_write(gspca_dev, 0xaa, &data, 1);
+ v = 613 + 12 * val;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc4, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc5, &data, 1);
+ v = 1093 - 12 * val;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc6, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc7, &data, 1);
+ v = 342 + 9 * val;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc8, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc9, &data, 1);
+ v = 702 - 9 * val;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xca, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xcb, &data, 1);
+}
+
+static void setwb(struct gspca_dev *gspca_dev)
+{
+/*fixme:to do - valid when reg d1 = 0x1c - (reg16 + reg15 = 0xa3)*/
+ static const u8 data[2] = {0x00, 0x00};
+
+ i2c_write(gspca_dev, 0x16, &data[0], 1);
+ i2c_write(gspca_dev, 0x18, &data[1], 1);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ const u8 (*init)[4];
+ const u8 *GammaT = NULL;
+ const u8 *MatrixT = NULL;
+ int mode;
+ static const u8 (*mi1320_soc_init[])[4] = {
+ mi1320_soc_InitSXGA,
+ mi1320_soc_InitVGA,
+ mi1320_soc_InitQVGA,
+ };
+
+/*fixme: back sensor only*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
+ reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
+ }
+
+ /* Assume start use the good resolution from gspca_dev->mode */
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
+ sd->image_offset = 46;
+ } else {
+ if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
+ == V4L2_PIX_FMT_JPEG)
+ sd->image_offset = 0;
+ else
+ sd->image_offset = 32;
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ GammaT = hv7131r_gamma;
+ MatrixT = hv7131r_matrix;
+ if (mode)
+ init = hv7131r_initQVGA_data; /* 320x240 */
+ else
+ init = hv7131r_initVGA_data; /* 640x480 */
+ break;
+ case SENSOR_OV7660:
+ GammaT = ov7660_gamma;
+ MatrixT = ov7660_matrix;
+ if (mode)
+ init = ov7660_initQVGA_data; /* 320x240 */
+ else
+ init = ov7660_initVGA_data; /* 640x480 */
+ break;
+ case SENSOR_MI0360:
+ GammaT = mi1320_gamma;
+ MatrixT = mi0360_matrix;
+ if (mode)
+ init = mi0360_initQVGA_JPG; /* 320x240 */
+ else
+ init = mi0360_initVGA_JPG; /* 640x480 */
+ break;
+ case SENSOR_MI1310_SOC:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ switch (mode) {
+ case 1:
+ init = mi1310_socinitQVGA_JPG; /* 320x240 */
+ break;
+ case 0:
+ init = mi1310_socinitVGA_JPG; /* 640x480 */
+ break;
+ default:
+ init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
+ break;
+ }
+ break;
+ case SENSOR_MI1320:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ if (mode)
+ init = mi1320_initQVGA_data; /* 320x240 */
+ else
+ init = mi1320_initVGA_data; /* 640x480 */
+ break;
+ case SENSOR_MI1320_SOC:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ init = mi1320_soc_init[mode];
+ break;
+ case SENSOR_OV7670:
+ init = mode == 1 ? ov7670_InitVGA : ov7670_InitQVGA;
+ break;
+ case SENSOR_PO3130NC:
+ GammaT = po3130_gamma;
+ MatrixT = po3130_matrix;
+ if (mode)
+ init = po3130_initQVGA_data; /* 320x240 */
+ else
+ init = po3130_initVGA_data; /* 640x480 */
+ usb_exchange(gspca_dev, init);
+ init = po3130_rundata;
+ break;
+ case SENSOR_PO1200:
+ GammaT = po1200_gamma;
+ MatrixT = po1200_matrix;
+ init = po1200_initVGA_data;
+ break;
+ default:
+/* case SENSOR_POxxxx: */
+ usb_exchange(gspca_dev, poxxxx_init_common);
+ setgamma(gspca_dev);
+ usb_exchange(gspca_dev, poxxxx_init_start_3);
+ if (mode)
+ init = poxxxx_initQVGA;
+ else
+ init = poxxxx_initVGA;
+ usb_exchange(gspca_dev, init);
+ reg_r(gspca_dev, 0x8c, 0x0000, 3);
+ reg_w(gspca_dev, 0xa0,
+ gspca_dev->usb_buf[2] & 1 ? 0 : 1,
+ 0xb35c);
+ msleep(300);
+/*fixme: i2c read 04 and 05*/
+ init = poxxxx_init_end_1;
+ break;
+ }
+ usb_exchange(gspca_dev, init);
+ if (GammaT && MatrixT) {
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+ put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+ switch (sd->sensor) {
+ case SENSOR_PO1200:
+ case SENSOR_HV7131R:
+ reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
+ break;
+ case SENSOR_MI1310_SOC:
+ reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
+ break;
+ }
+ msleep(100);
+ }
+ switch (sd->sensor) {
+ case SENSOR_OV7670:
+ reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
+ reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
+ break;
+ case SENSOR_POxxxx:
+ usb_exchange(gspca_dev, poxxxx_init_end_2);
+ setwb(gspca_dev);
+ msleep(80); /* led on */
+ reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_MI1310_SOC:
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
+ break;
+ case SENSOR_POxxxx:
+ return;
+ default:
+ if (!(sd->flags & FL_SAMSUNG))
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
+ break;
+ }
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
+}
+
+/* called on streamoff with alt 0 and on disconnect */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (!gspca_dev->present)
+ return;
+/*fixme: is this useful?*/
+ if (sd->sensor == SENSOR_MI1310_SOC)
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
+ else if (!(sd->flags & FL_SAMSUNG))
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
+
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso pkt length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (data[0] == 0xff && data[1] == 0xd8) {
+ PDEBUG(D_PACK,
+ "vc032x header packet found len %d", len);
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+ data += sd->image_offset;
+ len -= sd->image_offset;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+ return;
+ }
+
+ /* The vc0321 sends some additional data after sending the complete
+ * frame, we ignore this. */
+ if (sd->bridge == BRIDGE_VC0321) {
+ int size, l;
+
+ l = gspca_dev->image_len;
+ size = gspca_dev->frsz;
+ if (len > size - l)
+ len = size - l;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *)gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ setbrightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ setcontrast(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ setcolors(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ sethvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ setsharpness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ setautogain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ setgain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ setexposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_BACKLIGHT_COMPENSATION:
+ setbacklight(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ setlightfreq(gspca_dev, ctrl->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *)gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+ bool has_brightness = false;
+ bool has_contrast = false;
+ bool has_sat = false;
+ bool has_hvflip = false;
+ bool has_freq = false;
+ bool has_backlight = false;
+ bool has_exposure = false;
+ bool has_autogain = false;
+ bool has_gain = false;
+ bool has_sharpness = false;
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_PO3130NC:
+ break;
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320:
+ case SENSOR_MI1320_SOC:
+ case SENSOR_OV7660:
+ has_hvflip = true;
+ break;
+ case SENSOR_OV7670:
+ has_hvflip = has_freq = true;
+ break;
+ case SENSOR_PO1200:
+ has_hvflip = has_sharpness = true;
+ break;
+ case SENSOR_POxxxx:
+ has_brightness = has_contrast = has_sat = has_backlight =
+ has_exposure = has_autogain = has_gain =
+ has_sharpness = true;
+ break;
+ }
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 8);
+ if (has_brightness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ if (has_contrast)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 127);
+ if (has_sat)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SATURATION, 1, 127, 1, 63);
+ if (has_hvflip) {
+ sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ }
+ if (has_sharpness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, -1, 2, 1, -1);
+ if (has_freq)
+ v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+ if (has_autogain)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ if (has_gain)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 78, 1, 0);
+ if (has_exposure)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 4095, 1, 450);
+ if (has_backlight)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BACKLIGHT_COMPENSATION, 0, 15, 1, 15);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ if (sd->hflip)
+ v4l2_ctrl_cluster(2, &sd->hflip);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .init_controls = sd_init_controls,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define BF(bridge, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 8) \
+ | (flags)
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
+ {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)},
+ {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
+ {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
+ {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
+ {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},
+ {}
+};
+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,
+ .reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c
index b1a64b912666..b1a64b912666 100644
--- a/drivers/media/video/gspca/vicam.c
+++ b/drivers/media/usb/gspca/vicam.c
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c
index 9e3a909e0a00..9e3a909e0a00 100644
--- a/drivers/media/video/gspca/w996Xcf.c
+++ b/drivers/media/usb/gspca/w996Xcf.c
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c
index 13b8d395d210..13b8d395d210 100644
--- a/drivers/media/video/gspca/xirlink_cit.c
+++ b/drivers/media/usb/gspca/xirlink_cit.c
diff --git a/drivers/media/video/gspca/zc3xx-reg.h b/drivers/media/usb/gspca/zc3xx-reg.h
index a1bd94e8ce52..a1bd94e8ce52 100644
--- a/drivers/media/video/gspca/zc3xx-reg.h
+++ b/drivers/media/usb/gspca/zc3xx-reg.h
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c
index f0bacee33ef9..f0bacee33ef9 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/usb/gspca/zc3xx.c
diff --git a/drivers/media/video/hdpvr/Kconfig b/drivers/media/usb/hdpvr/Kconfig
index de247f3c7d05..de247f3c7d05 100644
--- a/drivers/media/video/hdpvr/Kconfig
+++ b/drivers/media/usb/hdpvr/Kconfig
diff --git a/drivers/media/usb/hdpvr/Makefile b/drivers/media/usb/hdpvr/Makefile
new file mode 100644
index 000000000000..9b8d1463c526
--- /dev/null
+++ b/drivers/media/usb/hdpvr/Makefile
@@ -0,0 +1,7 @@
+hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
+
+obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
+
+ccflags-y += -Idrivers/media/i2c
+
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/usb/hdpvr/hdpvr-control.c
index ae8f229d1141..ae8f229d1141 100644
--- a/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/drivers/media/usb/hdpvr/hdpvr-control.c
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 304f43ef59eb..304f43ef59eb 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c
index 82e819fa91c0..82e819fa91c0 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 0e9e156bb2aa..0e9e156bb2aa 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index fea3c6926997..fea3c6926997 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig
new file mode 100644
index 000000000000..32b11c15bb1a
--- /dev/null
+++ b/drivers/media/usb/pvrusb2/Kconfig
@@ -0,0 +1,65 @@
+config VIDEO_PVRUSB2
+ tristate "Hauppauge WinTV-PVR USB2 support"
+ depends on VIDEO_V4L2 && I2C
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_SAA711X
+ select VIDEO_CX25840
+ select VIDEO_MSP3400
+ select VIDEO_WM8775
+ select VIDEO_CS53L32A
+ ---help---
+ This is a video4linux driver for Conexant 23416 based
+ usb2 personal video recorder devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pvrusb2
+
+config VIDEO_PVRUSB2_SYSFS
+ bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+ default y
+ depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+ ---help---
+ This option enables the operation of a sysfs based
+ interface for query and control of the pvrusb2 driver.
+
+ This is not generally needed for v4l applications,
+ although certain applications are optimized to take
+ advantage of this feature.
+
+ If you are in doubt, say Y.
+
+ Note: This feature is experimental and subject to change.
+
+config VIDEO_PVRUSB2_DVB
+ bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
+ default y
+ depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
+ select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+
+ This option enables a DVB interface for the pvrusb2 driver.
+ If your device does not support digital television, this
+ feature will have no affect on the driver's operation.
+
+ If you are in doubt, say Y.
+
+config VIDEO_PVRUSB2_DEBUGIFC
+ bool "pvrusb2 debug interface"
+ depends on VIDEO_PVRUSB2_SYSFS
+ ---help---
+ This option enables the inclusion of a debug interface
+ in the pvrusb2 driver, hosted through sysfs.
+
+ You do not need to select this option unless you plan
+ on debugging the driver or performing a manual firmware
+ extraction.
+
+ If you are in doubt, say N.
diff --git a/drivers/media/usb/pvrusb2/Makefile b/drivers/media/usb/pvrusb2/Makefile
new file mode 100644
index 000000000000..ad705547bdce
--- /dev/null
+++ b/drivers/media/usb/pvrusb2/Makefile
@@ -0,0 +1,22 @@
+obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
+
+pvrusb2-objs := pvrusb2-i2c-core.o \
+ pvrusb2-audio.o \
+ pvrusb2-encoder.o pvrusb2-video-v4l.o \
+ pvrusb2-eeprom.o \
+ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+ pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
+ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ pvrusb2-cs53l32a.o \
+ $(obj-pvrusb2-dvb-y) \
+ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
index cc06d5e4adcc..cc06d5e4adcc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
index e3e63d750891..e3e63d750891 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index 7c19ff72e6b3..7c19ff72e6b3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h
index d657e53bbfa3..d657e53bbfa3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
index 88320900dbd4..88320900dbd4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
index 53ba548b72a7..53ba548b72a7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
index 7d5a7139a45a..7d5a7139a45a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
index 794ff90121c7..794ff90121c7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
index c514d0b9ffdc..c514d0b9ffdc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
index e35c2322a08c..e35c2322a08c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
index be79249f8628..be79249f8628 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
index 4279ebb811a1..4279ebb811a1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
index 2f8d46761cd0..2f8d46761cd0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
new file mode 100644
index 000000000000..adc501d3c287
--- /dev/null
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
@@ -0,0 +1,576 @@
+/*
+ *
+ *
+ * Copyright (C) 2007 Mike Isely <isely@pobox.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
+ *
+ * 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
+ *
+ */
+
+/*
+
+This source file should encompass ALL per-device type information for the
+driver. To define a new device, add elements to the pvr2_device_table and
+pvr2_device_desc structures.
+
+*/
+
+#include "pvrusb2-devattr.h"
+#include <linux/usb.h>
+#include <linux/module.h>
+/* This is needed in order to pull in tuner type ids... */
+#include <linux/i2c.h>
+#include <media/tuner.h>
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-hdw-internal.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "s5h1411.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "tda8290.h"
+#include "tuner-simple.h"
+#endif
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 29xxx */
+
+static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_MSP3400 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
+};
+
+#define PVR2_FIRMWARE_29xxx "v4l-pvrusb2-29xxx-01.fw"
+static const char *pvr2_fw1_names_29xxx[] = {
+ PVR2_FIRMWARE_29xxx,
+};
+
+static const struct pvr2_device_desc pvr2_device_29xxx = {
+ .description = "WinTV PVR USB2 Model 29xxx",
+ .shortname = "29xxx",
+ .client_table.lst = pvr2_cli_29xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_29xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_29XXX,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 24xxx */
+
+static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_WM8775 },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
+};
+
+#define PVR2_FIRMWARE_24xxx "v4l-pvrusb2-24xxx-01.fw"
+static const char *pvr2_fw1_names_24xxx[] = {
+ PVR2_FIRMWARE_24xxx,
+};
+
+static const struct pvr2_device_desc pvr2_device_24xxx = {
+ .description = "WinTV PVR USB2 Model 24xxx",
+ .shortname = "24xxx",
+ .client_table.lst = pvr2_cli_24xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_24xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
+ .flag_has_cx25840 = !0,
+ .flag_has_wm8775 = !0,
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_24XXX,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD2 */
+
+static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
+};
+
+static const struct pvr2_device_desc pvr2_device_gotview_2 = {
+ .description = "Gotview USB 2.0 DVD 2",
+ .shortname = "gv2",
+ .client_table.lst = pvr2_cli_gotview_2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
+ .flag_has_cx25840 = !0,
+ .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD Deluxe */
+
+/* (same module list as gotview_2) */
+
+static const struct pvr2_device_desc pvr2_device_gotview_2d = {
+ .description = "Gotview USB 2.0 DVD Deluxe",
+ .shortname = "gv2d",
+ .client_table.lst = pvr2_cli_gotview_2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
+ .flag_has_cx25840 = !0,
+ .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Terratec Grabster AV400 */
+
+static const struct pvr2_device_client_desc pvr2_cli_av400[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+};
+
+static const struct pvr2_device_desc pvr2_device_av400 = {
+ .description = "Terratec Grabster AV400",
+ .shortname = "av400",
+ .flag_is_experimental = 1,
+ .client_table.lst = pvr2_cli_av400,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_av400),
+ .flag_has_cx25840 = !0,
+ .flag_has_analogtuner = 0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_AV400,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* OnAir Creator */
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3303_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .clock_polarity_flip = 1,
+};
+
+static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+
+ return 0;
+}
+
+static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+ .frontend_attach = pvr2_lgdt3303_attach,
+ .tuner_attach = pvr2_lgh06xf_attach,
+};
+#endif
+
+static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_CS53L32A },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_creator = {
+ .description = "OnAir Creator Hybrid USB tuner",
+ .shortname = "oac",
+ .client_table.lst = pvr2_cli_onair_creator,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator),
+ .default_tuner_type = TUNER_LG_TDVS_H06XF,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_creator_fe_props,
+#endif
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* OnAir USB 2.0 */
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3302_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3302,
+};
+
+static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_PHILIPS_FCV1236D);
+
+ return 0;
+}
+
+static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+ .frontend_attach = pvr2_lgdt3302_attach,
+ .tuner_attach = pvr2_fcv1236d_attach,
+};
+#endif
+
+static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = {
+ { .module_id = PVR2_CLIENT_ID_SAA7115 },
+ { .module_id = PVR2_CLIENT_ID_CS53L32A },
+ { .module_id = PVR2_CLIENT_ID_TUNER },
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
+ .description = "OnAir USB2 Hybrid USB tuner",
+ .shortname = "oa2",
+ .client_table.lst = pvr2_cli_onair_usb2,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2),
+ .default_tuner_type = TUNER_PHILIPS_FCV1236D,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_usb2_fe_props,
+#endif
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 73xxx */
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct tda10048_config hauppauge_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_50,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3800,
+ .dtv8_if_freq_khz = TDA10048_IF_4300,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+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,
+};
+
+static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_dvb_config);
+
+ return 0;
+}
+
+static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+ .frontend_attach = pvr2_tda10048_attach,
+ .tuner_attach = pvr2_73xxx_tda18271_8295_attach,
+};
+#endif
+
+static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+ { .module_id = PVR2_CLIENT_ID_TUNER,
+ .i2c_address_list = "\x42"},
+};
+
+#define PVR2_FIRMWARE_73xxx "v4l-pvrusb2-73xxx-01.fw"
+static const char *pvr2_fw1_names_73xxx[] = {
+ PVR2_FIRMWARE_73xxx,
+};
+
+static const struct pvr2_device_desc pvr2_device_73xxx = {
+ .description = "WinTV HVR-1900 Model 73xxx",
+ .shortname = "73xxx",
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_73xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
+ .flag_has_cx25840 = !0,
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_fx2_16kb = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_ZILOG,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_73xxx_dvb_props,
+#endif
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 75xxx */
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct s5h1409_config pvr2_s5h1409_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_PARALLEL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .qam_if = 4000,
+ .inversion = S5H1409_INVERSION_ON,
+ .status_mode = S5H1409_DEMODLOCKING,
+};
+
+static struct s5h1411_config pvr2_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_44000,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 5380, .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 hauppauge_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_config);
+
+ return 0;
+}
+
+static const struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1409_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
+
+static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1411_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
+#endif
+
+#define PVR2_FIRMWARE_75xxx "v4l-pvrusb2-73xxx-01.fw"
+static const char *pvr2_fw1_names_75xxx[] = {
+ PVR2_FIRMWARE_75xxx,
+};
+
+static const struct pvr2_device_desc pvr2_device_750xx = {
+ .description = "WinTV HVR-1950 Model 750xx",
+ .shortname = "750xx",
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+ .flag_has_cx25840 = !0,
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_fx2_16kb = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_ZILOG,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_750xx_dvb_props,
+#endif
+};
+
+static const struct pvr2_device_desc pvr2_device_751xx = {
+ .description = "WinTV HVR-1950 Model 751xx",
+ .shortname = "751xx",
+ .client_table.lst = pvr2_cli_73xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+ .flag_has_cx25840 = !0,
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_fx2_16kb = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_ZILOG,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_751xx_dvb_props,
+#endif
+};
+
+
+
+/*------------------------------------------------------------------------*/
+
+struct usb_device_id pvr2_device_table[] = {
+ { USB_DEVICE(0x2040, 0x2900),
+ .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+ { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */
+ .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+ { USB_DEVICE(0x2040, 0x2400),
+ .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
+ { USB_DEVICE(0x1164, 0x0622),
+ .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
+ { USB_DEVICE(0x1164, 0x0602),
+ .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
+ { USB_DEVICE(0x11ba, 0x1003),
+ .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
+ { USB_DEVICE(0x11ba, 0x1001),
+ .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
+ { USB_DEVICE(0x2040, 0x7300),
+ .driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
+ { USB_DEVICE(0x2040, 0x7500),
+ .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
+ { USB_DEVICE(0x2040, 0x7501),
+ .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
+ { USB_DEVICE(0x0ccd, 0x0039),
+ .driver_info = (kernel_ulong_t)&pvr2_device_av400},
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx);
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
index 273c8d4b3853..273c8d4b3853 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
index 8c95793433e7..8c95793433e7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h
index 884ff916a352..884ff916a352 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
index 9515f3a68f8f..9515f3a68f8f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
index cca3216f94cc..cca3216f94cc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
index e046fdaec5ae..e046fdaec5ae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
index 232fefbcd1ac..232fefbcd1ac 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
index 614755ea2ea3..614755ea2ea3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
index 036952f2a3cb..036952f2a3cb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index fb828ba1dbbe..fb828ba1dbbe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
index 8060fc666eeb..8060fc666eeb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index 885ce11f222d..885ce11f222d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
index 6a75769200bd..6a75769200bd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 20b6ae0bb40d..20b6ae0bb40d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h
index afb7e87c0394..afb7e87c0394 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
index bba6115c9ae8..bba6115c9ae8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
index 100e0780e1aa..100e0780e1aa 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c
index c1d9bb61cd77..c1d9bb61cd77 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c
index 453627b07833..453627b07833 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h
index a35c53d0b320..a35c53d0b320 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
index 6ef1335b2858..6ef1335b2858 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
index 6d875bfe7991..6d875bfe7991 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h
index 92b75544ee2e..92b75544ee2e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-util.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index f344aed32a93..f344aed32a93 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
index 34c011a7b107..34c011a7b107 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
index 2e205c99eb96..2e205c99eb96 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
index 3b0bd5db602b..3b0bd5db602b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
index 3ac8d751a5c0..3ac8d751a5c0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
index 0577bc7246fb..0577bc7246fb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h
index 240de9b35661..240de9b35661 100644
--- a/drivers/media/video/pvrusb2/pvrusb2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2.h
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/usb/pwc/Kconfig
index d63d0a850035..d63d0a850035 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/usb/pwc/Kconfig
diff --git a/drivers/media/usb/pwc/Makefile b/drivers/media/usb/pwc/Makefile
new file mode 100644
index 000000000000..d7fdbcb9edd3
--- /dev/null
+++ b/drivers/media/usb/pwc/Makefile
@@ -0,0 +1,4 @@
+pwc-objs += pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
+
+obj-$(CONFIG_USB_PWC) += pwc.o
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/usb/pwc/philips.txt
index d38dd791511e..d38dd791511e 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/usb/pwc/philips.txt
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c
index 1f506fde97d0..1f506fde97d0 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/usb/pwc/pwc-ctrl.c
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/usb/pwc/pwc-dec1.c
index e899036aadf4..e899036aadf4 100644
--- a/drivers/media/video/pwc/pwc-dec1.c
+++ b/drivers/media/usb/pwc/pwc-dec1.c
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/usb/pwc/pwc-dec1.h
index c565ef8f52fb..c565ef8f52fb 100644
--- a/drivers/media/video/pwc/pwc-dec1.h
+++ b/drivers/media/usb/pwc/pwc-dec1.h
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/usb/pwc/pwc-dec23.c
index 3792fedff951..3792fedff951 100644
--- a/drivers/media/video/pwc/pwc-dec23.c
+++ b/drivers/media/usb/pwc/pwc-dec23.c
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/usb/pwc/pwc-dec23.h
index c655b1c1e6a9..c655b1c1e6a9 100644
--- a/drivers/media/video/pwc/pwc-dec23.h
+++ b/drivers/media/usb/pwc/pwc-dec23.h
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index de7c7ba99ef4..de7c7ba99ef4 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/usb/pwc/pwc-kiara.c
index e5f4fd817125..e5f4fd817125 100644
--- a/drivers/media/video/pwc/pwc-kiara.c
+++ b/drivers/media/usb/pwc/pwc-kiara.c
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/usb/pwc/pwc-kiara.h
index 8e02b7ac2139..8e02b7ac2139 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/usb/pwc/pwc-kiara.h
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/usb/pwc/pwc-misc.c
index 9be5adffa874..9be5adffa874 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/usb/pwc/pwc-misc.c
diff --git a/drivers/media/video/pwc/pwc-nala.h b/drivers/media/usb/pwc/pwc-nala.h
index 168c73ef75d8..168c73ef75d8 100644
--- a/drivers/media/video/pwc/pwc-nala.h
+++ b/drivers/media/usb/pwc/pwc-nala.h
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/usb/pwc/pwc-timon.c
index c56c174b161c..c56c174b161c 100644
--- a/drivers/media/video/pwc/pwc-timon.c
+++ b/drivers/media/usb/pwc/pwc-timon.c
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/usb/pwc/pwc-timon.h
index 270c5b9010f6..270c5b9010f6 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/usb/pwc/pwc-timon.h
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/usb/pwc/pwc-uncompress.c
index b65903fbcf0d..b65903fbcf0d 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/usb/pwc/pwc-uncompress.c
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index 545e9bbdeede..545e9bbdeede 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h
index 7a6a0d39c2c6..7a6a0d39c2c6 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/usb/pwc/pwc.h
diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig
new file mode 100644
index 000000000000..7e8ee1f864ab
--- /dev/null
+++ b/drivers/media/usb/s2255/Kconfig
@@ -0,0 +1,9 @@
+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.
+
diff --git a/drivers/media/usb/s2255/Makefile b/drivers/media/usb/s2255/Makefile
new file mode 100644
index 000000000000..197d0bb2adfd
--- /dev/null
+++ b/drivers/media/usb/s2255/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_USB_S2255) += s2255drv.o
+
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
new file mode 100644
index 000000000000..a25513d484f7
--- /dev/null
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -0,0 +1,2690 @@
+/*
+ * s2255drv.c - a driver for the Sensoray 2255 USB video capture device
+ *
+ * Copyright (C) 2007-2010 by Sensoray Company Inc.
+ * Dean Anderson
+ *
+ * Some video buffer code based on vivi driver:
+ *
+ * Sensoray 2255 device supports 4 simultaneous channels.
+ * The channels are not "crossbar" inputs, they are physically
+ * attached to separate video decoders.
+ *
+ * Because of USB2.0 bandwidth limitations. There is only a
+ * certain amount of data which may be transferred at one time.
+ *
+ * Example maximum bandwidth utilization:
+ *
+ * -full size, color mode YUYV or YUV422P: 2 channels at once
+ * -full or half size Grey scale: all 4 channels at once
+ * -half size, color mode YUYV or YUV422P: all 4 channels at once
+ * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
+ * at once.
+ *
+ * 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/module.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#define S2255_VERSION "1.22.1"
+#define FIRMWARE_FILE_NAME "f2255usb.bin"
+
+/* default JPEG quality */
+#define S2255_DEF_JPEG_QUAL 50
+/* vendor request in */
+#define S2255_VR_IN 0
+/* vendor request out */
+#define S2255_VR_OUT 1
+/* firmware query */
+#define S2255_VR_FW 0x30
+/* USB endpoint number for configuring the device */
+#define S2255_CONFIG_EP 2
+/* maximum time for DSP to start responding after last FW word loaded(ms) */
+#define S2255_DSP_BOOTTIME 800
+/* maximum time to wait for firmware to load (ms) */
+#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME)
+#define S2255_DEF_BUFS 16
+#define S2255_SETMODE_TIMEOUT 500
+#define S2255_VIDSTATUS_TIMEOUT 350
+#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL)
+#define S2255_MARKER_RESPONSE cpu_to_le32(0x2255ACACL)
+#define S2255_RESPONSE_SETMODE cpu_to_le32(0x01)
+#define S2255_RESPONSE_FW cpu_to_le32(0x10)
+#define S2255_RESPONSE_STATUS cpu_to_le32(0x20)
+#define S2255_USB_XFER_SIZE (16 * 1024)
+#define MAX_CHANNELS 4
+#define SYS_FRAMES 4
+/* maximum size is PAL full size plus room for the marker header(s) */
+#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096)
+#define DEF_USB_BLOCK S2255_USB_XFER_SIZE
+#define LINE_SZ_4CIFS_NTSC 640
+#define LINE_SZ_2CIFS_NTSC 640
+#define LINE_SZ_1CIFS_NTSC 320
+#define LINE_SZ_4CIFS_PAL 704
+#define LINE_SZ_2CIFS_PAL 704
+#define LINE_SZ_1CIFS_PAL 352
+#define NUM_LINES_4CIFS_NTSC 240
+#define NUM_LINES_2CIFS_NTSC 240
+#define NUM_LINES_1CIFS_NTSC 240
+#define NUM_LINES_4CIFS_PAL 288
+#define NUM_LINES_2CIFS_PAL 288
+#define NUM_LINES_1CIFS_PAL 288
+#define LINE_SZ_DEF 640
+#define NUM_LINES_DEF 240
+
+
+/* predefined settings */
+#define FORMAT_NTSC 1
+#define FORMAT_PAL 2
+
+#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */
+#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */
+#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */
+/* SCALE_4CIFSI is the 2 fields interpolated into one */
+#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */
+
+#define COLOR_YUVPL 1 /* YUV planar */
+#define COLOR_YUVPK 2 /* YUV packed */
+#define COLOR_Y8 4 /* monochrome */
+#define COLOR_JPG 5 /* JPEG */
+
+#define MASK_COLOR 0x000000ff
+#define MASK_JPG_QUALITY 0x0000ff00
+#define MASK_INPUT_TYPE 0x000f0000
+/* frame decimation. */
+#define FDEC_1 1 /* capture every frame. default */
+#define FDEC_2 2 /* capture every 2nd frame */
+#define FDEC_3 3 /* capture every 3rd frame */
+#define FDEC_5 5 /* capture every 5th frame */
+
+/*-------------------------------------------------------
+ * Default mode parameters.
+ *-------------------------------------------------------*/
+#define DEF_SCALE SCALE_4CIFS
+#define DEF_COLOR COLOR_YUVPL
+#define DEF_FDEC FDEC_1
+#define DEF_BRIGHT 0
+#define DEF_CONTRAST 0x5c
+#define DEF_SATURATION 0x80
+#define DEF_HUE 0
+
+/* usb config commands */
+#define IN_DATA_TOKEN cpu_to_le32(0x2255c0de)
+#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))
+#define CMD_STATUS cpu_to_le32((CMD_2255 | 0x40))
+
+struct s2255_mode {
+ u32 format; /* input video format (NTSC, PAL) */
+ u32 scale; /* output video scale */
+ u32 color; /* output video color format */
+ u32 fdec; /* frame decimation */
+ u32 bright; /* brightness */
+ u32 contrast; /* contrast */
+ u32 saturation; /* saturation */
+ u32 hue; /* hue (NTSC only)*/
+ u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/
+ u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */
+ u32 restart; /* if DSP requires restart */
+};
+
+
+#define S2255_READ_IDLE 0
+#define S2255_READ_FRAME 1
+
+/* frame structure */
+struct s2255_framei {
+ unsigned long size;
+ unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct s2255_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */
+};
+
+#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \
+ DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
+ DEF_HUE, 0, DEF_USB_BLOCK, 0}
+
+struct s2255_dmaqueue {
+ struct list_head active;
+ struct s2255_dev *dev;
+};
+
+/* for firmware loading, fw_state */
+#define S2255_FW_NOTLOADED 0
+#define S2255_FW_LOADED_DSPWAIT 1
+#define S2255_FW_SUCCESS 2
+#define S2255_FW_FAILED 3
+#define S2255_FW_DISCONNECTING 4
+#define S2255_FW_MARKER cpu_to_le32(0x22552f2f)
+/* 2255 read states */
+#define S2255_READ_IDLE 0
+#define S2255_READ_FRAME 1
+struct s2255_fw {
+ int fw_loaded;
+ int fw_size;
+ struct urb *fw_urb;
+ atomic_t fw_state;
+ void *pfw_data;
+ wait_queue_head_t wait_fw;
+ const struct firmware *fw;
+};
+
+struct s2255_pipeinfo {
+ u32 max_transfer_size;
+ u32 cur_transfer_size;
+ u8 *transfer_buffer;
+ u32 state;
+ void *stream_urb;
+ void *dev; /* back pointer to s2255_dev struct*/
+ u32 err_count;
+ u32 idx;
+};
+
+struct s2255_fmt; /*forward declaration */
+struct s2255_dev;
+
+struct s2255_channel {
+ struct video_device vdev;
+ int resources;
+ struct s2255_dmaqueue vidq;
+ struct s2255_bufferi buffer;
+ struct s2255_mode mode;
+ /* jpeg compression */
+ struct v4l2_jpegcompression jc;
+ /* capture parameters (for high quality mode full size) */
+ struct v4l2_captureparm cap_parm;
+ int cur_frame;
+ int last_frame;
+
+ int b_acquire;
+ /* allocated image size */
+ unsigned long req_image_size;
+ /* received packet size */
+ unsigned long pkt_size;
+ int bad_payload;
+ unsigned long frame_count;
+ /* if JPEG image */
+ int jpg_size;
+ /* if channel configured to default state */
+ int configured;
+ wait_queue_head_t wait_setmode;
+ int setmode_ready;
+ /* video status items */
+ int vidstatus;
+ wait_queue_head_t wait_vidstatus;
+ int vidstatus_ready;
+ unsigned int width;
+ unsigned int height;
+ const struct s2255_fmt *fmt;
+ int idx; /* channel number on device, 0-3 */
+};
+
+
+struct s2255_dev {
+ struct s2255_channel channel[MAX_CHANNELS];
+ struct v4l2_device v4l2_dev;
+ atomic_t num_channels;
+ int frames;
+ struct mutex lock; /* channels[].vdev.lock */
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ u8 read_endpoint;
+ struct timer_list timer;
+ struct s2255_fw *fw_data;
+ struct s2255_pipeinfo pipe;
+ u32 cc; /* current channel */
+ int frame_ready;
+ int chn_ready;
+ spinlock_t slock;
+ /* dsp firmware version (f2255usb.bin) */
+ int dsp_fw_ver;
+ u16 pid; /* product id */
+};
+
+static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct s2255_dev, v4l2_dev);
+}
+
+struct s2255_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* buffer for one video frame */
+struct s2255_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct s2255_fmt *fmt;
+};
+
+struct s2255_fh {
+ struct s2255_dev *dev;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct s2255_channel *channel;
+ int resources;
+};
+
+/* current cypress EEPROM firmware version */
+#define S2255_CUR_USB_FWVER ((3 << 8) | 12)
+/* current DSP FW version */
+#define S2255_CUR_DSP_FWVER 10104
+/* Need DSP version 5+ for video status feature */
+#define S2255_MIN_DSP_STATUS 5
+#define S2255_MIN_DSP_COLORFILTER 8
+#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC)
+
+/* private V4L2 controls */
+
+/*
+ * The following chart displays how COLORFILTER should be set
+ * =========================================================
+ * = fourcc = COLORFILTER =
+ * = ===============================
+ * = = 0 = 1 =
+ * =========================================================
+ * = V4L2_PIX_FMT_GREY(Y8) = monochrome from = monochrome=
+ * = = s-video or = composite =
+ * = = B/W camera = input =
+ * =========================================================
+ * = other = color, svideo = color, =
+ * = = = composite =
+ * =========================================================
+ *
+ * Notes:
+ * channels 0-3 on 2255 are composite
+ * channels 0-1 on 2257 are composite, 2-3 are s-video
+ * If COLORFILTER is 0 with a composite color camera connected,
+ * the output will appear monochrome but hatching
+ * will occur.
+ * COLORFILTER is different from "color killer" and "color effects"
+ * for reasons above.
+ */
+#define S2255_V4L2_YC_ON 1
+#define S2255_V4L2_YC_OFF 0
+#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0)
+
+/* frame prefix size (sent once every frame) */
+#define PREFIX_SIZE 512
+
+/* Channels on box are in reverse order */
+static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
+
+static int debug;
+static int *s2255_debug = &debug;
+
+static int s2255_start_readpipe(struct s2255_dev *dev);
+static void s2255_stop_readpipe(struct s2255_dev *dev);
+static int s2255_start_acquire(struct s2255_channel *channel);
+static int s2255_stop_acquire(struct s2255_channel *channel);
+static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+ int jpgsize);
+static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
+static int s2255_board_shutdown(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev, int reset);
+static void s2255_destroy(struct s2255_dev *dev);
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+ u16 index, u16 value, void *buf,
+ s32 buf_len, int bOut);
+
+/* dev_err macro with driver name */
+#define S2255_DRIVER_NAME "s2255"
+#define s2255_dev_err(dev, fmt, arg...) \
+ dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (*s2255_debug >= (level)) { \
+ printk(KERN_DEBUG S2255_DRIVER_NAME \
+ ": " fmt, ##arg); \
+ } \
+ } while (0)
+
+static struct usb_driver s2255_driver;
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+
+/* start video number */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+
+/* Enable jpeg capture. */
+static int jpeg_enable = 1;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
+module_param(video_nr, int, 0644);
+MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+module_param(jpeg_enable, int, 0644);
+MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
+
+/* USB device table */
+#define USB_SENSORAY_VID 0x1943
+static struct usb_device_id s2255_table[] = {
+ {USB_DEVICE(USB_SENSORAY_VID, 0x2255)},
+ {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, s2255_table);
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(400)
+
+/* image formats. */
+/* JPEG formats must be defined last to support jpeg_enable parameter */
+static const struct s2255_fmt formats[] = {
+ {
+ .name = "4:2:2, planar, YUV422P",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16
+
+ }, {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16
+
+ }, {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16
+ }, {
+ .name = "8bpp GREY",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8
+ }, {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }, {
+ .name = "MJPG",
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .depth = 24
+ }
+};
+
+static int norm_maxw(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
+}
+
+static int norm_maxh(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
+}
+
+static int norm_minw(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
+}
+
+static int norm_minh(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
+}
+
+
+/*
+ * TODO: fixme: move YUV reordering to hardware
+ * converts 2255 planar format to yuyv or uyvy
+ */
+static void planar422p_to_yuv_packed(const unsigned char *in,
+ unsigned char *out,
+ int width, int height,
+ int fmt)
+{
+ unsigned char *pY;
+ unsigned char *pCb;
+ unsigned char *pCr;
+ unsigned long size = height * width;
+ unsigned int i;
+ pY = (unsigned char *)in;
+ pCr = (unsigned char *)in + height * width;
+ pCb = (unsigned char *)in + height * width + (height * width / 2);
+ for (i = 0; i < size * 2; i += 4) {
+ out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;
+ out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;
+ out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;
+ out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;
+ }
+ return;
+}
+
+static void s2255_reset_dsppower(struct s2255_dev *dev)
+{
+ s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
+ msleep(10);
+ s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+ msleep(600);
+ s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
+ return;
+}
+
+/* kickstarts the firmware loading. from probe
+ */
+static void s2255_timer(unsigned long user_data)
+{
+ struct s2255_fw *data = (struct s2255_fw *)user_data;
+ dprintk(100, "%s\n", __func__);
+ if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+ printk(KERN_ERR "s2255: can't submit urb\n");
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+}
+
+
+/* this loads the firmware asynchronously.
+ Originally this was done synchroously in probe.
+ But it is better to load it asynchronously here than block
+ inside the probe function. Blocking inside probe affects boot time.
+ FW loading is triggered by the timer in the probe function
+*/
+static void s2255_fwchunk_complete(struct urb *urb)
+{
+ struct s2255_fw *data = urb->context;
+ struct usb_device *udev = urb->dev;
+ int len;
+ dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
+ if (urb->status) {
+ dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+ if (data->fw_urb == NULL) {
+ s2255_dev_err(&udev->dev, "disconnected\n");
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+#define CHUNK_SIZE 512
+ /* all USB transfers must be done with continuous kernel memory.
+ can't allocate more than 128k in current linux kernel, so
+ upload the firmware in chunks
+ */
+ if (data->fw_loaded < data->fw_size) {
+ len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ?
+ data->fw_size % CHUNK_SIZE : CHUNK_SIZE;
+
+ if (len < CHUNK_SIZE)
+ memset(data->pfw_data, 0, CHUNK_SIZE);
+
+ dprintk(100, "completed len %d, loaded %d \n", len,
+ data->fw_loaded);
+
+ memcpy(data->pfw_data,
+ (char *) data->fw->data + data->fw_loaded, len);
+
+ usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2),
+ data->pfw_data, CHUNK_SIZE,
+ s2255_fwchunk_complete, data);
+ if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+ dev_err(&udev->dev, "failed submit URB\n");
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+ data->fw_loaded += len;
+ } else {
+ atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
+ dprintk(100, "%s: firmware upload complete\n", __func__);
+ }
+ return;
+
+}
+
+static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
+{
+ struct s2255_dmaqueue *dma_q = &channel->vidq;
+ struct s2255_buffer *buf;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ unsigned long flags = 0;
+ int rc = 0;
+ spin_lock_irqsave(&dev->slock, flags);
+ if (list_empty(&dma_q->active)) {
+ dprintk(1, "No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct s2255_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ s2255_fillbuff(channel, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return rc;
+}
+
+static const struct s2255_fmt *format_by_fourcc(int fourcc)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (-1 == formats[i].fourcc)
+ continue;
+ if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+ continue;
+ if (formats[i].fourcc == fourcc)
+ return formats + i;
+ }
+ return NULL;
+}
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void s2255_fillbuff(struct s2255_channel *channel,
+ struct s2255_buffer *buf, int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+
+ if (!vbuf)
+ return;
+ last_frame = channel->last_frame;
+ if (last_frame != -1) {
+ tmpbuf =
+ (const char *)channel->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
+ vbuf, buf->vb.width,
+ buf->vb.height,
+ buf->fmt->fourcc);
+ break;
+ case V4L2_PIX_FMT_GREY:
+ memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ memcpy(vbuf, tmpbuf,
+ buf->vb.width * buf->vb.height * 2);
+ break;
+ default:
+ printk(KERN_DEBUG "s2255: unknown format?\n");
+ }
+ channel->last_frame = -1;
+ } else {
+ printk(KERN_ERR "s2255: =======no frame\n");
+ return;
+
+ }
+ dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = channel->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct s2255_fh *fh = vq->priv_data;
+ struct s2255_channel *channel = fh->channel;
+ *size = channel->width * channel->height * (channel->fmt->depth >> 3);
+
+ if (0 == *count)
+ *count = S2255_DEF_BUFS;
+
+ if (*size * *count > vid_limit * 1024 * 1024)
+ *count = (vid_limit * 1024 * 1024) / *size;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
+{
+ dprintk(4, "%s\n", __func__);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct s2255_fh *fh = vq->priv_data;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+ int rc;
+ int w = channel->width;
+ int h = channel->height;
+ dprintk(4, "%s, field=%d\n", __func__, field);
+ if (channel->fmt == NULL)
+ return -EINVAL;
+
+ if ((w < norm_minw(&channel->vdev)) ||
+ (w > norm_maxw(&channel->vdev)) ||
+ (h < norm_minh(&channel->vdev)) ||
+ (h > norm_maxh(&channel->vdev))) {
+ dprintk(4, "invalid buffer prepare\n");
+ return -EINVAL;
+ }
+ buf->vb.size = w * h * (channel->fmt->depth >> 3);
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
+ dprintk(4, "invalid buffer prepare\n");
+ return -EINVAL;
+ }
+
+ buf->fmt = channel->fmt;
+ buf->vb.width = w;
+ buf->vb.height = h;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+ struct s2255_fh *fh = vq->priv_data;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dmaqueue *vidq = &channel->vidq;
+ dprintk(1, "%s\n", __func__);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+ struct s2255_fh *fh = vq->priv_data;
+ dprintk(4, "%s %d\n", __func__, fh->channel->idx);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops s2255_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+
+static int res_get(struct s2255_fh *fh)
+{
+ struct s2255_channel *channel = fh->channel;
+ /* is it free? */
+ if (channel->resources)
+ return 0; /* no, someone else uses it */
+ /* it's free, grab it */
+ channel->resources = 1;
+ fh->resources = 1;
+ dprintk(1, "s2255: res: get\n");
+ return 1;
+}
+
+static int res_locked(struct s2255_fh *fh)
+{
+ return fh->channel->resources;
+}
+
+static int res_check(struct s2255_fh *fh)
+{
+ return fh->resources;
+}
+
+
+static void res_free(struct s2255_fh *fh)
+{
+ struct s2255_channel *channel = fh->channel;
+ channel->resources = 0;
+ fh->resources = 0;
+ dprintk(1, "res: put\n");
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
+{
+ static const char *colorfilter[] = {
+ "Off",
+ "On",
+ NULL
+ };
+ if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) {
+ int i;
+ const char **menu_items = colorfilter;
+ for (i = 0; i < qmenu->index && menu_items[i]; i++)
+ ; /* do nothing (from v4l2-common.c) */
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+ strlcpy(qmenu->name, menu_items[qmenu->index],
+ sizeof(qmenu->name));
+ return 0;
+ }
+ return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s2255_fh *fh = file->private_data;
+ struct s2255_dev *dev = fh->dev;
+ strlcpy(cap->driver, "s2255", sizeof(cap->driver));
+ strlcpy(cap->card, "s2255", sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ 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;
+ dprintk(4, "name %s\n", formats[index].name);
+ strlcpy(f->description, formats[index].name, sizeof(f->description));
+ f->pixelformat = formats[index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+
+ f->fmt.pix.width = channel->width;
+ f->fmt.pix.height = channel->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = channel->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
+ 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)
+{
+ const struct s2255_fmt *fmt;
+ enum v4l2_field field;
+ int b_any_field = 0;
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ int is_ntsc;
+ is_ntsc =
+ (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ if (field == V4L2_FIELD_ANY)
+ b_any_field = 1;
+
+ dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
+ __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
+ if (is_ntsc) {
+ /* NTSC */
+ if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
+ f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
+ if (b_any_field) {
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (!((field == V4L2_FIELD_INTERLACED) ||
+ (field == V4L2_FIELD_SEQ_TB) ||
+ (field == V4L2_FIELD_INTERLACED_TB))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ } else {
+ f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
+ if (b_any_field) {
+ field = V4L2_FIELD_TOP;
+ } else if (!((field == V4L2_FIELD_TOP) ||
+ (field == V4L2_FIELD_BOTTOM))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+
+ }
+ if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
+ else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
+ else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+ else
+ f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+ } else {
+ /* PAL */
+ if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
+ f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
+ if (b_any_field) {
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (!((field == V4L2_FIELD_INTERLACED) ||
+ (field == V4L2_FIELD_SEQ_TB) ||
+ (field == V4L2_FIELD_INTERLACED_TB))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ } else {
+ f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
+ if (b_any_field) {
+ field = V4L2_FIELD_TOP;
+ } else if (!((field == V4L2_FIELD_TOP) ||
+ (field == V4L2_FIELD_BOTTOM))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ }
+ if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
+ f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
+ f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
+ f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ } else {
+ f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ }
+ }
+ f->fmt.pix.field = field;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ dprintk(50, "%s: set width %d height %d field %d\n", __func__,
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ const struct s2255_fmt *fmt;
+ struct videobuf_queue *q = &fh->vb_vidq;
+ struct s2255_mode mode;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, fh, f);
+
+ if (ret < 0)
+ return ret;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ dprintk(1, "queue busy\n");
+ ret = -EBUSY;
+ goto out_s_fmt;
+ }
+
+ if (res_locked(fh)) {
+ dprintk(1, "%s: channel busy\n", __func__);
+ ret = -EBUSY;
+ goto out_s_fmt;
+ }
+ mode = channel->mode;
+ channel->fmt = fmt;
+ channel->width = f->fmt.pix.width;
+ channel->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+ if (channel->width > norm_minw(&channel->vdev)) {
+ if (channel->height > norm_minh(&channel->vdev)) {
+ if (channel->cap_parm.capturemode &
+ V4L2_MODE_HIGHQUALITY)
+ mode.scale = SCALE_4CIFSI;
+ else
+ mode.scale = SCALE_4CIFS;
+ } else
+ mode.scale = SCALE_2CIFS;
+
+ } else {
+ mode.scale = SCALE_1CIFS;
+ }
+ /* color mode */
+ switch (channel->fmt->fourcc) {
+ case V4L2_PIX_FMT_GREY:
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_Y8;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_JPG;
+ mode.color |= (channel->jc.quality << 8);
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPL;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPK;
+ break;
+ }
+ if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+ mode.restart = 1;
+ else if (mode.scale != channel->mode.scale)
+ mode.restart = 1;
+ else if (mode.format != channel->mode.format)
+ mode.restart = 1;
+ channel->mode = mode;
+ (void) s2255_set_mode(channel, &mode);
+ ret = 0;
+out_s_fmt:
+ mutex_unlock(&q->vb_lock);
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct s2255_fh *fh = priv;
+ rc = videobuf_reqbufs(&fh->vb_vidq, p);
+ return rc;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct s2255_fh *fh = priv;
+ rc = videobuf_querybuf(&fh->vb_vidq, p);
+ return rc;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct s2255_fh *fh = priv;
+ rc = videobuf_qbuf(&fh->vb_vidq, p);
+ return rc;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct s2255_fh *fh = priv;
+ rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+/* write to the configuration pipe, synchronously */
+static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
+ int size)
+{
+ int pipe;
+ int done;
+ long retval = -1;
+ if (udev) {
+ pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP);
+ retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500);
+ }
+ return retval;
+}
+
+static u32 get_transfer_size(struct s2255_mode *mode)
+{
+ int linesPerFrame = LINE_SZ_DEF;
+ int pixelsPerLine = NUM_LINES_DEF;
+ u32 outImageSize;
+ u32 usbInSize;
+ unsigned int mask_mult;
+
+ if (mode == NULL)
+ return 0;
+
+ if (mode->format == FORMAT_NTSC) {
+ switch (mode->scale) {
+ case SCALE_4CIFS:
+ case SCALE_4CIFSI:
+ linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
+ pixelsPerLine = LINE_SZ_4CIFS_NTSC;
+ break;
+ case SCALE_2CIFS:
+ linesPerFrame = NUM_LINES_2CIFS_NTSC;
+ pixelsPerLine = LINE_SZ_2CIFS_NTSC;
+ break;
+ case SCALE_1CIFS:
+ linesPerFrame = NUM_LINES_1CIFS_NTSC;
+ pixelsPerLine = LINE_SZ_1CIFS_NTSC;
+ break;
+ default:
+ break;
+ }
+ } else if (mode->format == FORMAT_PAL) {
+ switch (mode->scale) {
+ case SCALE_4CIFS:
+ case SCALE_4CIFSI:
+ linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
+ pixelsPerLine = LINE_SZ_4CIFS_PAL;
+ break;
+ case SCALE_2CIFS:
+ linesPerFrame = NUM_LINES_2CIFS_PAL;
+ pixelsPerLine = LINE_SZ_2CIFS_PAL;
+ break;
+ case SCALE_1CIFS:
+ linesPerFrame = NUM_LINES_1CIFS_PAL;
+ pixelsPerLine = LINE_SZ_1CIFS_PAL;
+ break;
+ default:
+ break;
+ }
+ }
+ outImageSize = linesPerFrame * pixelsPerLine;
+ if ((mode->color & MASK_COLOR) != COLOR_Y8) {
+ /* 2 bytes/pixel if not monochrome */
+ outImageSize *= 2;
+ }
+
+ /* total bytes to send including prefix and 4K padding;
+ must be a multiple of USB_READ_SIZE */
+ usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */
+ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1;
+ /* if size not a multiple of USB_READ_SIZE */
+ if (usbInSize & ~mask_mult)
+ usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK);
+ return usbInSize;
+}
+
+static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
+{
+ struct device *dev = &sdev->udev->dev;
+ dev_info(dev, "------------------------------------------------\n");
+ dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
+ dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
+ dev_info(dev, "bright: 0x%x\n", mode->bright);
+ dev_info(dev, "------------------------------------------------\n");
+}
+
+/*
+ * set mode is the function which controls the DSP.
+ * the restart parameter in struct s2255_mode should be set whenever
+ * the image size could change via color format, video system or image
+ * size.
+ * When the restart parameter is set, we sleep for ONE frame to allow the
+ * DSP time to get the new frame
+ */
+static int s2255_set_mode(struct s2255_channel *channel,
+ struct s2255_mode *mode)
+{
+ int res;
+ __le32 *buffer;
+ unsigned long chn_rev;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(3, "%s channel: %d\n", __func__, channel->idx);
+ /* if JPEG, set the quality */
+ if ((mode->color & MASK_COLOR) == COLOR_JPG) {
+ mode->color &= ~MASK_COLOR;
+ mode->color |= COLOR_JPG;
+ mode->color &= ~MASK_JPG_QUALITY;
+ mode->color |= (channel->jc.quality << 8);
+ }
+ /* save the mode */
+ channel->mode = *mode;
+ channel->req_image_size = get_transfer_size(mode);
+ dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+ /* set the mode */
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_SET_MODE;
+ memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+ channel->setmode_ready = 0;
+ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+ if (debug)
+ s2255_print_cfg(dev, mode);
+ kfree(buffer);
+ /* wait at least 3 frames before continuing */
+ if (mode->restart) {
+ wait_event_timeout(channel->wait_setmode,
+ (channel->setmode_ready != 0),
+ msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
+ if (channel->setmode_ready != 1) {
+ printk(KERN_DEBUG "s2255: no set mode response\n");
+ res = -EFAULT;
+ }
+ }
+ /* clear the restart flag */
+ channel->mode.restart = 0;
+ dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
+ return res;
+}
+
+static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
+{
+ int res;
+ __le32 *buffer;
+ u32 chn_rev;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(4, "%s chan %d\n", __func__, channel->idx);
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+ /* form the get vid status command */
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_STATUS;
+ *pstatus = 0;
+ channel->vidstatus_ready = 0;
+ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+ kfree(buffer);
+ wait_event_timeout(channel->wait_vidstatus,
+ (channel->vidstatus_ready != 0),
+ msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
+ if (channel->vidstatus_ready != 1) {
+ printk(KERN_DEBUG "s2255: no vidstatus response\n");
+ res = -EFAULT;
+ }
+ *pstatus = channel->vidstatus;
+ dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
+ return res;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ int res;
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
+ int j;
+ dprintk(4, "%s\n", __func__);
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&dev->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (i != fh->type) {
+ dev_err(&dev->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(fh)) {
+ s2255_dev_err(&dev->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
+ channel->frame_count = 0;
+ for (j = 0; j < SYS_FRAMES; j++) {
+ channel->buffer.frame[j].ulState = S2255_READ_IDLE;
+ channel->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&fh->vb_vidq);
+ if (res == 0) {
+ s2255_start_acquire(channel);
+ channel->b_acquire = 1;
+ } else
+ res_free(fh);
+
+ return res;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct s2255_fh *fh = priv;
+ dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ printk(KERN_ERR "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (i != fh->type) {
+ printk(KERN_ERR "invalid type i\n");
+ return -EINVAL;
+ }
+ s2255_stop_acquire(fh->channel);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_mode mode;
+ struct videobuf_queue *q = &fh->vb_vidq;
+ int ret = 0;
+ mutex_lock(&q->vb_lock);
+ if (videobuf_queue_is_busy(q)) {
+ dprintk(1, "queue busy\n");
+ ret = -EBUSY;
+ goto out_s_std;
+ }
+ if (res_locked(fh)) {
+ dprintk(1, "can't change standard after started\n");
+ ret = -EBUSY;
+ goto out_s_std;
+ }
+ mode = fh->channel->mode;
+ if (*i & V4L2_STD_NTSC) {
+ dprintk(4, "%s NTSC\n", __func__);
+ /* if changing format, reset frame decimation/intervals */
+ if (mode.format != FORMAT_NTSC) {
+ mode.restart = 1;
+ mode.format = FORMAT_NTSC;
+ mode.fdec = FDEC_1;
+ }
+ } else if (*i & V4L2_STD_PAL) {
+ dprintk(4, "%s PAL\n", __func__);
+ if (mode.format != FORMAT_PAL) {
+ mode.restart = 1;
+ mode.format = FORMAT_PAL;
+ mode.fdec = FDEC_1;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ if (mode.restart)
+ s2255_set_mode(fh->channel, &mode);
+out_s_std:
+ mutex_unlock(&q->vb_lock);
+ return ret;
+}
+
+/* Sensoray 2255 is a multiple channel capture device.
+ It does not have a "crossbar" of inputs.
+ We use one V4L device per channel. The user must
+ be aware that certain combinations are not allowed.
+ For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
+ at once in color(you can do full fps on 4 channels with greyscale.
+*/
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
+ u32 status = 0;
+ if (inp->index != 0)
+ return -EINVAL;
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = S2255_NORMS;
+ inp->status = 0;
+ if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
+ int rc;
+ rc = s2255_cmd_status(fh->channel, &status);
+ dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
+ if (rc == 0)
+ inp->status = (status & 0x01) ? 0
+ : V4L2_IN_ST_NO_SIGNAL;
+ }
+ switch (dev->pid) {
+ case 0x2255:
+ default:
+ strlcpy(inp->name, "Composite", sizeof(inp->name));
+ break;
+ case 0x2257:
+ strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
+ sizeof(inp->name));
+ break;
+ }
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dev *dev = fh->dev;
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT);
+ break;
+ case V4L2_CID_CONTRAST:
+ v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST);
+ break;
+ case V4L2_CID_SATURATION:
+ v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION);
+ break;
+ case V4L2_CID_HUE:
+ v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE);
+ break;
+ case V4L2_CID_PRIVATE_COLORFILTER:
+ if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+ return -EINVAL;
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
+ return -EINVAL;
+ strlcpy(qc->name, "Color Filter", sizeof(qc->name));
+ qc->type = V4L2_CTRL_TYPE_MENU;
+ qc->minimum = 0;
+ qc->maximum = 1;
+ qc->step = 1;
+ qc->default_value = 1;
+ qc->flags = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dprintk(4, "%s, id %d\n", __func__, qc->id);
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = channel->mode.bright;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = channel->mode.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = channel->mode.saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = channel->mode.hue;
+ break;
+ case V4L2_CID_PRIVATE_COLORFILTER:
+ if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+ return -EINVAL;
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
+ return -EINVAL;
+ ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
+ break;
+ default:
+ return -EINVAL;
+ }
+ dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value);
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_mode mode;
+ mode = channel->mode;
+ dprintk(4, "%s\n", __func__);
+ /* update the mode to the corresponding value */
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ mode.bright = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ mode.contrast = ctrl->value;
+ break;
+ case V4L2_CID_HUE:
+ mode.hue = ctrl->value;
+ break;
+ case V4L2_CID_SATURATION:
+ mode.saturation = ctrl->value;
+ break;
+ case V4L2_CID_PRIVATE_COLORFILTER:
+ if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+ return -EINVAL;
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
+ return -EINVAL;
+ mode.color &= ~MASK_INPUT_TYPE;
+ mode.color |= ((ctrl->value ? 0 : 1) << 16);
+ break;
+ default:
+ return -EINVAL;
+ }
+ mode.restart = 0;
+ /* set mode here. Note: stream does not need restarted.
+ some V4L programs restart stream unnecessarily
+ after a s_crtl.
+ */
+ s2255_set_mode(fh->channel, &mode);
+ return 0;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jc)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ *jc = channel->jc;
+ dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jc)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ if (jc->quality < 0 || jc->quality > 100)
+ return -EINVAL;
+ channel->jc.quality = jc->quality;
+ dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct s2255_fh *fh = priv;
+ __u32 def_num, def_dem;
+ struct s2255_channel *channel = fh->channel;
+ if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ memset(sp, 0, sizeof(struct v4l2_streamparm));
+ sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ sp->parm.capture.capturemode = channel->cap_parm.capturemode;
+ def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ sp->parm.capture.timeperframe.denominator = def_dem;
+ switch (channel->mode.fdec) {
+ default:
+ case FDEC_1:
+ sp->parm.capture.timeperframe.numerator = def_num;
+ break;
+ case FDEC_2:
+ sp->parm.capture.timeperframe.numerator = def_num * 2;
+ break;
+ case FDEC_3:
+ sp->parm.capture.timeperframe.numerator = def_num * 3;
+ break;
+ case FDEC_5:
+ sp->parm.capture.timeperframe.numerator = def_num * 5;
+ break;
+ }
+ dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
+ sp->parm.capture.capturemode,
+ sp->parm.capture.timeperframe.numerator,
+ sp->parm.capture.timeperframe.denominator);
+ return 0;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_mode mode;
+ int fdec = FDEC_1;
+ __u32 def_num, def_dem;
+ if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ mode = channel->mode;
+ /* high quality capture mode requires a stream restart */
+ if (channel->cap_parm.capturemode
+ != sp->parm.capture.capturemode && res_locked(fh))
+ return -EBUSY;
+ def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ if (def_dem != sp->parm.capture.timeperframe.denominator)
+ sp->parm.capture.timeperframe.numerator = def_num;
+ else if (sp->parm.capture.timeperframe.numerator <= def_num)
+ sp->parm.capture.timeperframe.numerator = def_num;
+ else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) {
+ sp->parm.capture.timeperframe.numerator = def_num * 2;
+ fdec = FDEC_2;
+ } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) {
+ sp->parm.capture.timeperframe.numerator = def_num * 3;
+ fdec = FDEC_3;
+ } else {
+ sp->parm.capture.timeperframe.numerator = def_num * 5;
+ fdec = FDEC_5;
+ }
+ mode.fdec = fdec;
+ sp->parm.capture.timeperframe.denominator = def_dem;
+ s2255_set_mode(channel, &mode);
+ dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+ __func__,
+ sp->parm.capture.capturemode,
+ sp->parm.capture.timeperframe.numerator,
+ sp->parm.capture.timeperframe.denominator, fdec);
+ return 0;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fe)
+{
+ int is_ntsc = 0;
+#define NUM_FRAME_ENUMS 4
+ int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
+ if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS)
+ return -EINVAL;
+ switch (fe->width) {
+ case 640:
+ if (fe->height != 240 && fe->height != 480)
+ return -EINVAL;
+ is_ntsc = 1;
+ break;
+ case 320:
+ if (fe->height != 240)
+ return -EINVAL;
+ is_ntsc = 1;
+ break;
+ case 704:
+ if (fe->height != 288 && fe->height != 576)
+ return -EINVAL;
+ break;
+ case 352:
+ if (fe->height != 288)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fe->discrete.denominator = is_ntsc ? 30000 : 25000;
+ fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
+ dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
+ fe->discrete.denominator);
+ return 0;
+}
+
+static int __s2255_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct s2255_channel *channel = video_drvdata(file);
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+ struct s2255_fh *fh;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int state;
+ dprintk(1, "s2255: open called (dev=%s)\n",
+ video_device_node_name(vdev));
+ state = atomic_read(&dev->fw_data->fw_state);
+ switch (state) {
+ case S2255_FW_DISCONNECTING:
+ return -ENODEV;
+ case S2255_FW_FAILED:
+ s2255_dev_err(&dev->udev->dev,
+ "firmware load failed. retrying.\n");
+ s2255_fwload_start(dev, 1);
+ wait_event_timeout(dev->fw_data->wait_fw,
+ ((atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_SUCCESS) ||
+ (atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_DISCONNECTING)),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ /* state may have changed, re-read */
+ state = atomic_read(&dev->fw_data->fw_state);
+ break;
+ case S2255_FW_NOTLOADED:
+ case S2255_FW_LOADED_DSPWAIT:
+ /* give S2255_LOAD_TIMEOUT time for firmware to load in case
+ driver loaded and then device immediately opened */
+ printk(KERN_INFO "%s waiting for firmware load\n", __func__);
+ wait_event_timeout(dev->fw_data->wait_fw,
+ ((atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_SUCCESS) ||
+ (atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_DISCONNECTING)),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ /* state may have changed, re-read */
+ state = atomic_read(&dev->fw_data->fw_state);
+ break;
+ case S2255_FW_SUCCESS:
+ default:
+ break;
+ }
+ /* state may have changed in above switch statement */
+ switch (state) {
+ case S2255_FW_SUCCESS:
+ break;
+ case S2255_FW_FAILED:
+ printk(KERN_INFO "2255 firmware load failed.\n");
+ return -ENODEV;
+ case S2255_FW_DISCONNECTING:
+ printk(KERN_INFO "%s: disconnecting\n", __func__);
+ return -ENODEV;
+ case S2255_FW_LOADED_DSPWAIT:
+ case S2255_FW_NOTLOADED:
+ printk(KERN_INFO "%s: firmware not loaded yet"
+ "please try again later\n",
+ __func__);
+ /*
+ * Timeout on firmware load means device unusable.
+ * Set firmware failure state.
+ * On next s2255_open the firmware will be reloaded.
+ */
+ atomic_set(&dev->fw_data->fw_state,
+ S2255_FW_FAILED);
+ return -EAGAIN;
+ default:
+ printk(KERN_INFO "%s: unknown state\n", __func__);
+ return -EFAULT;
+ }
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+ file->private_data = fh;
+ fh->dev = dev;
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh->channel = channel;
+ if (!channel->configured) {
+ /* configure channel to default state */
+ channel->fmt = &formats[0];
+ s2255_set_mode(channel, &channel->mode);
+ channel->configured = 1;
+ }
+ dprintk(1, "%s: dev=%s type=%s\n", __func__,
+ video_device_node_name(vdev), v4l2_type_names[type]);
+ dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&channel->vidq);
+ dprintk(4, "%s: list_empty active=%d\n", __func__,
+ list_empty(&channel->vidq.active));
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
+ NULL, &dev->slock,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct s2255_buffer),
+ fh, vdev->lock);
+ return 0;
+}
+
+static int s2255_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ int ret;
+
+ if (mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ ret = __s2255_open(file);
+ mutex_unlock(vdev->lock);
+ return ret;
+}
+
+static unsigned int s2255_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s2255_fh *fh = file->private_data;
+ struct s2255_dev *dev = fh->dev;
+ int rc;
+ dprintk(100, "%s\n", __func__);
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+ mutex_lock(&dev->lock);
+ rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+static void s2255_destroy(struct s2255_dev *dev)
+{
+ /* board shutdown stops the read pipe if it is running */
+ s2255_board_shutdown(dev);
+ /* make sure firmware still not trying to load */
+ del_timer(&dev->timer); /* only started in .probe and .open */
+ if (dev->fw_data->fw_urb) {
+ usb_kill_urb(dev->fw_data->fw_urb);
+ usb_free_urb(dev->fw_data->fw_urb);
+ dev->fw_data->fw_urb = NULL;
+ }
+ release_firmware(dev->fw_data->fw);
+ kfree(dev->fw_data->pfw_data);
+ kfree(dev->fw_data);
+ /* reset the DSP so firmware can be reloaded next time */
+ s2255_reset_dsppower(dev);
+ mutex_destroy(&dev->lock);
+ usb_put_dev(dev->udev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ dprintk(1, "%s", __func__);
+ kfree(dev);
+}
+
+static int s2255_release(struct file *file)
+{
+ struct s2255_fh *fh = file->private_data;
+ struct s2255_dev *dev = fh->dev;
+ struct video_device *vdev = video_devdata(file);
+ struct s2255_channel *channel = fh->channel;
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&dev->lock);
+ /* turn off stream */
+ if (res_check(fh)) {
+ if (channel->b_acquire)
+ s2255_stop_acquire(fh->channel);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
+ }
+ videobuf_mmap_free(&fh->vb_vidq);
+ mutex_unlock(&dev->lock);
+ dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
+ kfree(fh);
+ return 0;
+}
+
+static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
+{
+ struct s2255_fh *fh = file->private_data;
+ struct s2255_dev *dev;
+ int ret;
+
+ if (!fh)
+ return -ENODEV;
+ dev = fh->dev;
+ dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ mutex_unlock(&dev->lock);
+ dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
+}
+
+static const struct v4l2_file_operations s2255_fops_v4l = {
+ .owner = THIS_MODULE,
+ .open = s2255_open,
+ .release = s2255_release,
+ .poll = s2255_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = s2255_mmap_v4l,
+};
+
+static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
+ .vidioc_querymenu = vidioc_querymenu,
+ .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_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+ .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+};
+
+static void s2255_video_device_release(struct video_device *vdev)
+{
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+ dprintk(4, "%s, chnls: %d \n", __func__,
+ atomic_read(&dev->num_channels));
+ if (atomic_dec_and_test(&dev->num_channels))
+ s2255_destroy(dev);
+ return;
+}
+
+static struct video_device template = {
+ .name = "s2255v",
+ .fops = &s2255_fops_v4l,
+ .ioctl_ops = &s2255_ioctl_ops,
+ .release = s2255_video_device_release,
+ .tvnorms = S2255_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int s2255_probe_v4l(struct s2255_dev *dev)
+{
+ int ret;
+ int i;
+ int cur_nr = video_nr;
+ struct s2255_channel *channel;
+ ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
+ if (ret)
+ return ret;
+ /* initialize all video 4 linux */
+ /* register 4 video devices */
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ channel = &dev->channel[i];
+ INIT_LIST_HEAD(&channel->vidq.active);
+ channel->vidq.dev = dev;
+ /* register 4 video devices */
+ channel->vdev = template;
+ channel->vdev.lock = &dev->lock;
+ channel->vdev.v4l2_dev = &dev->v4l2_dev;
+ video_set_drvdata(&channel->vdev, channel);
+ if (video_nr == -1)
+ ret = video_register_device(&channel->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr);
+ else
+ ret = video_register_device(&channel->vdev,
+ VFL_TYPE_GRABBER,
+ cur_nr + i);
+
+ if (ret) {
+ dev_err(&dev->udev->dev,
+ "failed to register video device!\n");
+ break;
+ }
+ atomic_inc(&dev->num_channels);
+ v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+ video_device_node_name(&channel->vdev));
+
+ }
+ printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
+ S2255_VERSION);
+ /* if no channels registered, return error and probe will fail*/
+ if (atomic_read(&dev->num_channels) == 0) {
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return ret;
+ }
+ if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
+ printk(KERN_WARNING "s2255: Not all channels available.\n");
+ return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process( call this
+ * function again).
+ *
+ * Received frame structure:
+ * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME)
+ * bytes 4-7: channel: 0-3
+ * bytes 8-11: payload size: size of the frame
+ * bytes 12-payloadsize+12: frame data
+ */
+static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
+{
+ char *pdest;
+ u32 offset = 0;
+ int bframe = 0;
+ char *psrc;
+ unsigned long copy_size;
+ unsigned long size;
+ s32 idx = -1;
+ struct s2255_framei *frm;
+ unsigned char *pdata;
+ struct s2255_channel *channel;
+ dprintk(100, "buffer to user\n");
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
+ if (frm->ulState == S2255_READ_IDLE) {
+ int jj;
+ unsigned int cc;
+ __le32 *pdword; /*data from dsp is little endian */
+ int payload;
+ /* search for marker codes */
+ pdata = (unsigned char *)pipe_info->transfer_buffer;
+ pdword = (__le32 *)pdata;
+ for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
+ switch (*pdword) {
+ case S2255_MARKER_FRAME:
+ dprintk(4, "found frame marker at offset:"
+ " %d [%x %x]\n", jj, pdata[0],
+ pdata[1]);
+ offset = jj + PREFIX_SIZE;
+ bframe = 1;
+ cc = le32_to_cpu(pdword[1]);
+ if (cc >= MAX_CHANNELS) {
+ printk(KERN_ERR
+ "bad channel\n");
+ return -EINVAL;
+ }
+ /* reverse it */
+ dev->cc = G_chnmap[cc];
+ channel = &dev->channel[dev->cc];
+ 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 = le32_to_cpu(pdword[4]);
+ break;
+ case S2255_MARKER_RESPONSE:
+
+ pdata += DEF_USB_BLOCK;
+ jj += DEF_USB_BLOCK;
+ if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
+ break;
+ cc = G_chnmap[le32_to_cpu(pdword[1])];
+ if (cc >= MAX_CHANNELS)
+ break;
+ channel = &dev->channel[cc];
+ switch (pdword[2]) {
+ case S2255_RESPONSE_SETMODE:
+ /* check if channel valid */
+ /* set mode ready */
+ channel->setmode_ready = 1;
+ wake_up(&channel->wait_setmode);
+ dprintk(5, "setmode ready %d\n", cc);
+ break;
+ case S2255_RESPONSE_FW:
+ dev->chn_ready |= (1 << cc);
+ if ((dev->chn_ready & 0x0f) != 0x0f)
+ break;
+ /* all channels ready */
+ printk(KERN_INFO "s2255: fw loaded\n");
+ atomic_set(&dev->fw_data->fw_state,
+ S2255_FW_SUCCESS);
+ wake_up(&dev->fw_data->wait_fw);
+ break;
+ case S2255_RESPONSE_STATUS:
+ channel->vidstatus = le32_to_cpu(pdword[3]);
+ channel->vidstatus_ready = 1;
+ wake_up(&channel->wait_vidstatus);
+ dprintk(5, "got vidstatus %x chan %d\n",
+ le32_to_cpu(pdword[3]), cc);
+ break;
+ default:
+ printk(KERN_INFO "s2255 unknown resp\n");
+ }
+ default:
+ pdata++;
+ break;
+ }
+ if (bframe)
+ break;
+ } /* for */
+ if (!bframe)
+ return -EINVAL;
+ }
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
+ /* search done. now find out if should be acquiring on this channel */
+ if (!channel->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = S2255_READ_IDLE;
+ return -EINVAL;
+ }
+
+ if (frm->ulState == S2255_READ_IDLE) {
+ frm->ulState = S2255_READ_FRAME;
+ frm->cur_size = 0;
+ }
+
+ /* skip the marker 512 bytes (and offset if out of sync) */
+ psrc = (u8 *)pipe_info->transfer_buffer + offset;
+
+
+ if (frm->lpvbits == NULL) {
+ dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
+ frm, dev, dev->cc, idx);
+ return -ENOMEM;
+ }
+
+ pdest = frm->lpvbits + frm->cur_size;
+
+ copy_size = (pipe_info->cur_transfer_size - offset);
+
+ size = channel->pkt_size - PREFIX_SIZE;
+
+ /* sanity check on pdest */
+ if ((copy_size + frm->cur_size) < channel->req_image_size)
+ memcpy(pdest, psrc, copy_size);
+
+ frm->cur_size += copy_size;
+ dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+
+ if (frm->cur_size >= size) {
+ dprintk(2, "****************[%d]Buffer[%d]full*************\n",
+ dev->cc, idx);
+ channel->last_frame = channel->cur_frame;
+ channel->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if ((channel->cur_frame == SYS_FRAMES) ||
+ (channel->cur_frame == channel->buffer.dwFrames))
+ channel->cur_frame = 0;
+ /* frame ready */
+ if (channel->b_acquire)
+ s2255_got_frame(channel, channel->jpg_size);
+ channel->frame_count++;
+ frm->ulState = S2255_READ_IDLE;
+ frm->cur_size = 0;
+
+ }
+ /* done successfully */
+ return 0;
+}
+
+static void s2255_read_video_callback(struct s2255_dev *dev,
+ struct s2255_pipeinfo *pipe_info)
+{
+ int res;
+ dprintk(50, "callback read video \n");
+
+ if (dev->cc >= MAX_CHANNELS) {
+ dev->cc = 0;
+ dev_err(&dev->udev->dev, "invalid channel\n");
+ return;
+ }
+ /* otherwise copy to the system buffers */
+ res = save_frame(dev, pipe_info);
+ if (res != 0)
+ dprintk(4, "s2255: read callback failed\n");
+
+ dprintk(50, "callback read video done\n");
+ return;
+}
+
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
+ u16 Index, u16 Value, void *TransferBuffer,
+ s32 TransferBufferLength, int bOut)
+{
+ int r;
+ if (!bOut) {
+ r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+ Request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ Value, Index, TransferBuffer,
+ TransferBufferLength, HZ * 5);
+ } else {
+ r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ Value, Index, TransferBuffer,
+ TransferBufferLength, HZ * 5);
+ }
+ return r;
+}
+
+/*
+ * retrieve FX2 firmware version. future use.
+ * @param dev pointer to device extension
+ * @return -1 for fail, else returns firmware version as an int(16 bits)
+ */
+static int s2255_get_fx2fw(struct s2255_dev *dev)
+{
+ int fw;
+ int ret;
+ unsigned char transBuffer[64];
+ ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
+ S2255_VR_IN);
+ if (ret < 0)
+ dprintk(2, "get fw error: %x\n", ret);
+ fw = transBuffer[0] + (transBuffer[1] << 8);
+ dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
+ return fw;
+}
+
+/*
+ * Create the system ring buffer to copy frames into from the
+ * usb read pipe.
+ */
+static int s2255_create_sys_buffers(struct s2255_channel *channel)
+{
+ unsigned long i;
+ unsigned long reqsize;
+ dprintk(1, "create sys buffers\n");
+ channel->buffer.dwFrames = SYS_FRAMES;
+ /* always allocate maximum size(PAL) for system buffers */
+ reqsize = SYS_FRAMES_MAXSIZE;
+
+ if (reqsize > SYS_FRAMES_MAXSIZE)
+ reqsize = SYS_FRAMES_MAXSIZE;
+
+ for (i = 0; i < SYS_FRAMES; i++) {
+ /* allocate the frames */
+ channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
+ dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
+ &channel->buffer.frame[i], channel->idx, i,
+ channel->buffer.frame[i].lpvbits);
+ channel->buffer.frame[i].size = reqsize;
+ if (channel->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO "out of memory. using less frames\n");
+ channel->buffer.dwFrames = i;
+ break;
+ }
+ }
+
+ /* make sure internal states are set */
+ for (i = 0; i < SYS_FRAMES; i++) {
+ channel->buffer.frame[i].ulState = 0;
+ channel->buffer.frame[i].cur_size = 0;
+ }
+
+ channel->cur_frame = 0;
+ channel->last_frame = -1;
+ return 0;
+}
+
+static int s2255_release_sys_buffers(struct s2255_channel *channel)
+{
+ unsigned long i;
+ dprintk(1, "release sys buffers\n");
+ for (i = 0; i < SYS_FRAMES; i++) {
+ if (channel->buffer.frame[i].lpvbits) {
+ dprintk(1, "vfree %p\n",
+ channel->buffer.frame[i].lpvbits);
+ vfree(channel->buffer.frame[i].lpvbits);
+ }
+ channel->buffer.frame[i].lpvbits = NULL;
+ }
+ return 0;
+}
+
+static int s2255_board_init(struct s2255_dev *dev)
+{
+ struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
+ int fw_ver;
+ int j;
+ struct s2255_pipeinfo *pipe = &dev->pipe;
+ dprintk(4, "board init: %p", dev);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->dev = dev;
+ pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+ pipe->max_transfer_size = S2255_USB_XFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ dprintk(1, "out of memory!\n");
+ return -ENOMEM;
+ }
+ /* query the firmware */
+ fw_ver = s2255_get_fx2fw(dev);
+
+ printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
+ (fw_ver >> 8) & 0xff,
+ fw_ver & 0xff);
+
+ if (fw_ver < S2255_CUR_USB_FWVER)
+ printk(KERN_INFO "s2255: newer USB firmware available\n");
+
+ for (j = 0; j < MAX_CHANNELS; j++) {
+ struct s2255_channel *channel = &dev->channel[j];
+ channel->b_acquire = 0;
+ channel->mode = mode_def;
+ if (dev->pid == 0x2257 && j > 1)
+ channel->mode.color |= (1 << 16);
+ channel->jc.quality = S2255_DEF_JPEG_QUAL;
+ channel->width = LINE_SZ_4CIFS_NTSC;
+ channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ channel->fmt = &formats[0];
+ channel->mode.restart = 1;
+ channel->req_image_size = get_transfer_size(&mode_def);
+ channel->frame_count = 0;
+ /* create the system buffers */
+ s2255_create_sys_buffers(channel);
+ }
+ /* start read pipe */
+ s2255_start_readpipe(dev);
+ dprintk(1, "%s: success\n", __func__);
+ return 0;
+}
+
+static int s2255_board_shutdown(struct s2255_dev *dev)
+{
+ u32 i;
+ dprintk(1, "%s: dev: %p", __func__, dev);
+
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (dev->channel[i].b_acquire)
+ s2255_stop_acquire(&dev->channel[i]);
+ }
+ s2255_stop_readpipe(dev);
+ for (i = 0; i < MAX_CHANNELS; i++)
+ s2255_release_sys_buffers(&dev->channel[i]);
+ /* release transfer buffer */
+ kfree(dev->pipe.transfer_buffer);
+ return 0;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct s2255_pipeinfo *pipe_info;
+ struct s2255_dev *dev;
+ int status;
+ int pipe;
+ pipe_info = purb->context;
+ dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
+ purb->status);
+ if (pipe_info == NULL) {
+ dev_err(&purb->dev->dev, "no context!\n");
+ return;
+ }
+
+ dev = pipe_info->dev;
+ if (dev == NULL) {
+ dev_err(&purb->dev->dev, "no context!\n");
+ return;
+ }
+ status = purb->status;
+ /* if shutting down, do not resubmit, exit immediately */
+ if (status == -ESHUTDOWN) {
+ dprintk(2, "%s: err shutdown\n", __func__);
+ pipe_info->err_count++;
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ dprintk(2, "%s: exiting USB pipe", __func__);
+ return;
+ }
+
+ if (status == 0)
+ s2255_read_video_callback(dev, pipe_info);
+ else {
+ pipe_info->err_count++;
+ dprintk(1, "%s: failed URB %d\n", __func__, status);
+ }
+
+ pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->cur_transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
+ dev_err(&dev->udev->dev, "error submitting urb\n");
+ }
+ } else {
+ dprintk(2, "%s :complete state 0\n", __func__);
+ }
+ return;
+}
+
+static int s2255_start_readpipe(struct s2255_dev *dev)
+{
+ int pipe;
+ int retval;
+ struct s2255_pipeinfo *pipe_info = &dev->pipe;
+ pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+ dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
+ pipe_info->state = 1;
+ pipe_info->err_count = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&dev->udev->dev,
+ "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->cur_transfer_size,
+ read_pipe_completion, pipe_info);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR "s2255: start read pipe failed\n");
+ return retval;
+ }
+ return 0;
+}
+
+/* starts acquisition process */
+static int s2255_start_acquire(struct s2255_channel *channel)
+{
+ unsigned char *buffer;
+ int res;
+ unsigned long chn_rev;
+ int j;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
+ for (j = 0; j < SYS_FRAMES; j++) {
+ channel->buffer.frame[j].ulState = 0;
+ channel->buffer.frame[j].cur_size = 0;
+ }
+
+ /* send the start command */
+ *(__le32 *) buffer = IN_DATA_TOKEN;
+ *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
+ *((__le32 *) buffer + 2) = CMD_START;
+ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+ if (res != 0)
+ dev_err(&dev->udev->dev, "CMD_START error\n");
+
+ dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
+ kfree(buffer);
+ return 0;
+}
+
+static int s2255_stop_acquire(struct s2255_channel *channel)
+{
+ unsigned char *buffer;
+ int res;
+ unsigned long chn_rev;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+ /* send the stop command */
+ *(__le32 *) buffer = IN_DATA_TOKEN;
+ *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
+ *((__le32 *) buffer + 2) = CMD_STOP;
+ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+ if (res != 0)
+ dev_err(&dev->udev->dev, "CMD_STOP error\n");
+ kfree(buffer);
+ channel->b_acquire = 0;
+ dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
+ return res;
+}
+
+static void s2255_stop_readpipe(struct s2255_dev *dev)
+{
+ struct s2255_pipeinfo *pipe = &dev->pipe;
+
+ pipe->state = 0;
+ if (pipe->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe->stream_urb);
+ usb_free_urb(pipe->stream_urb);
+ pipe->stream_urb = NULL;
+ }
+ dprintk(4, "%s", __func__);
+ return;
+}
+
+static void s2255_fwload_start(struct s2255_dev *dev, int reset)
+{
+ if (reset)
+ s2255_reset_dsppower(dev);
+ dev->fw_data->fw_size = dev->fw_data->fw->size;
+ atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
+ memcpy(dev->fw_data->pfw_data,
+ dev->fw_data->fw->data, CHUNK_SIZE);
+ dev->fw_data->fw_loaded = CHUNK_SIZE;
+ usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, 2),
+ dev->fw_data->pfw_data,
+ CHUNK_SIZE, s2255_fwchunk_complete,
+ dev->fw_data);
+ mod_timer(&dev->timer, jiffies + HZ);
+}
+
+/* standard usb probe function */
+static int s2255_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct s2255_dev *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int retval = -ENOMEM;
+ __le32 *pdata;
+ int fw_size;
+ dprintk(2, "%s\n", __func__);
+ /* allocate memory for our device state and initialize it to zero */
+ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
+ if (dev == NULL) {
+ s2255_dev_err(&interface->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+ atomic_set(&dev->num_channels, 0);
+ dev->pid = id->idProduct;
+ dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
+ if (!dev->fw_data)
+ goto errorFWDATA1;
+ mutex_init(&dev->lock);
+ /* grab usb_device and save it */
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+ if (dev->udev == NULL) {
+ dev_err(&interface->dev, "null usb device\n");
+ retval = -ENODEV;
+ goto errorUDEV;
+ }
+ dprintk(1, "dev: %p, udev %p interface %p\n", dev,
+ dev->udev, interface);
+ dev->interface = interface;
+ /* set up the endpoint information */
+ iface_desc = interface->cur_altsetting;
+ dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ dev->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!dev->read_endpoint) {
+ dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
+ goto errorEP;
+ }
+ init_timer(&dev->timer);
+ dev->timer.function = s2255_timer;
+ dev->timer.data = (unsigned long)dev->fw_data;
+ init_waitqueue_head(&dev->fw_data->wait_fw);
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ struct s2255_channel *channel = &dev->channel[i];
+ dev->channel[i].idx = i;
+ init_waitqueue_head(&channel->wait_setmode);
+ init_waitqueue_head(&channel->wait_vidstatus);
+ }
+
+ dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->fw_data->fw_urb) {
+ dev_err(&interface->dev, "out of memory!\n");
+ goto errorFWURB;
+ }
+
+ dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
+ if (!dev->fw_data->pfw_data) {
+ dev_err(&interface->dev, "out of memory!\n");
+ goto errorFWDATA2;
+ }
+ /* load the first chunk */
+ if (request_firmware(&dev->fw_data->fw,
+ FIRMWARE_FILE_NAME, &dev->udev->dev)) {
+ printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
+ goto errorREQFW;
+ }
+ /* check the firmware is valid */
+ fw_size = dev->fw_data->fw->size;
+ pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
+
+ if (*pdata != S2255_FW_MARKER) {
+ printk(KERN_INFO "Firmware invalid.\n");
+ retval = -ENODEV;
+ goto errorFWMARKER;
+ } else {
+ /* make sure firmware is the latest */
+ __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 = 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 &&
+ dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
+ printk(KERN_WARNING "s2255: 2257 requires firmware %d"
+ " or above.\n", S2255_MIN_DSP_COLORFILTER);
+ }
+ usb_reset_device(dev->udev);
+ /* load 2255 board specific */
+ retval = s2255_board_init(dev);
+ if (retval)
+ goto errorBOARDINIT;
+ spin_lock_init(&dev->slock);
+ s2255_fwload_start(dev, 0);
+ /* loads v4l specific */
+ retval = s2255_probe_v4l(dev);
+ if (retval)
+ goto errorBOARDINIT;
+ dev_info(&interface->dev, "Sensoray 2255 detected\n");
+ return 0;
+errorBOARDINIT:
+ s2255_board_shutdown(dev);
+errorFWMARKER:
+ release_firmware(dev->fw_data->fw);
+errorREQFW:
+ kfree(dev->fw_data->pfw_data);
+errorFWDATA2:
+ usb_free_urb(dev->fw_data->fw_urb);
+errorFWURB:
+ del_timer(&dev->timer);
+errorEP:
+ usb_put_dev(dev->udev);
+errorUDEV:
+ kfree(dev->fw_data);
+ mutex_destroy(&dev->lock);
+errorFWDATA1:
+ kfree(dev);
+ printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
+ return retval;
+}
+
+/* disconnect routine. when board is removed physically or with rmmod */
+static void s2255_disconnect(struct usb_interface *interface)
+{
+ struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
+ int i;
+ int channels = atomic_read(&dev->num_channels);
+ mutex_lock(&dev->lock);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ mutex_unlock(&dev->lock);
+ /*see comments in the uvc_driver.c usb disconnect function */
+ atomic_inc(&dev->num_channels);
+ /* unregister each video device. */
+ for (i = 0; i < channels; i++)
+ video_unregister_device(&dev->channel[i].vdev);
+ /* wake up any of our timers */
+ atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
+ wake_up(&dev->fw_data->wait_fw);
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ dev->channel[i].setmode_ready = 1;
+ wake_up(&dev->channel[i].wait_setmode);
+ dev->channel[i].vidstatus_ready = 1;
+ wake_up(&dev->channel[i].wait_vidstatus);
+ }
+ if (atomic_dec_and_test(&dev->num_channels))
+ s2255_destroy(dev);
+ dev_info(&interface->dev, "%s\n", __func__);
+}
+
+static struct usb_driver s2255_driver = {
+ .name = S2255_DRIVER_NAME,
+ .probe = s2255_probe,
+ .disconnect = s2255_disconnect,
+ .id_table = s2255_table,
+};
+
+module_usb_driver(s2255_driver);
+
+MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
+MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(S2255_VERSION);
+MODULE_FIRMWARE(FIRMWARE_FILE_NAME);
diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig
new file mode 100644
index 000000000000..3c76e62d820d
--- /dev/null
+++ b/drivers/media/usb/siano/Kconfig
@@ -0,0 +1,10 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_USB_DRV
+ tristate "Siano SMS1xxx based MDTV receiver"
+ depends on DVB_CORE && RC_CORE && HAS_DMA
+ ---help---
+ Choose if you would like to have Siano's support for USB interface
+
diff --git a/drivers/media/usb/siano/Makefile b/drivers/media/usb/siano/Makefile
new file mode 100644
index 000000000000..758b6a090c59
--- /dev/null
+++ b/drivers/media/usb/siano/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/common/siano
+ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index aac622200e99..aac622200e99 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/usb/sn9c102/Kconfig
index 6ebaf2940d06..6ebaf2940d06 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/usb/sn9c102/Kconfig
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/usb/sn9c102/Makefile
index 7ecd5a90c7c9..7ecd5a90c7c9 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/usb/sn9c102/Makefile
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/usb/sn9c102/sn9c102.h
index 2bc153e869be..2bc153e869be 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/usb/sn9c102/sn9c102.h
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/usb/sn9c102/sn9c102_config.h
index 0f4e0378b071..0f4e0378b071 100644
--- a/drivers/media/video/sn9c102/sn9c102_config.h
+++ b/drivers/media/usb/sn9c102/sn9c102_config.h
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c
index 19ea780b16ff..19ea780b16ff 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/usb/sn9c102/sn9c102_core.c
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/usb/sn9c102/sn9c102_devtable.h
index b3d2cc729657..b3d2cc729657 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/usb/sn9c102/sn9c102_devtable.h
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/usb/sn9c102/sn9c102_hv7131d.c
index 2dce5c908c8e..2dce5c908c8e 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/usb/sn9c102/sn9c102_hv7131d.c
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/usb/sn9c102/sn9c102_hv7131r.c
index 4295887ff609..4295887ff609 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131r.c
+++ b/drivers/media/usb/sn9c102/sn9c102_hv7131r.c
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/usb/sn9c102/sn9c102_mi0343.c
index 1f5b09bec89c..1f5b09bec89c 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0343.c
+++ b/drivers/media/usb/sn9c102/sn9c102_mi0343.c
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/usb/sn9c102/sn9c102_mi0360.c
index d973fc1973d9..d973fc1973d9 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0360.c
+++ b/drivers/media/usb/sn9c102/sn9c102_mi0360.c
diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/usb/sn9c102/sn9c102_mt9v111.c
index 95986eb492e4..95986eb492e4 100644
--- a/drivers/media/video/sn9c102/sn9c102_mt9v111.c
+++ b/drivers/media/usb/sn9c102/sn9c102_mt9v111.c
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/usb/sn9c102/sn9c102_ov7630.c
index 803712c29f02..803712c29f02 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/usb/sn9c102/sn9c102_ov7630.c
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/usb/sn9c102/sn9c102_ov7660.c
index 7977795d342b..7977795d342b 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/usb/sn9c102/sn9c102_ov7660.c
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/usb/sn9c102/sn9c102_pas106b.c
index 81cd969c1b7b..81cd969c1b7b 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas106b.c
+++ b/drivers/media/usb/sn9c102/sn9c102_pas106b.c
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c
index 2e86fdc86989..2e86fdc86989 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/usb/sn9c102/sn9c102_sensor.h
index 3679970dba2c..3679970dba2c 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/usb/sn9c102/sn9c102_sensor.h
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c
index 04cdfdde8564..04cdfdde8564 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/usb/sn9c102/sn9c102_tas5110d.c
index 9372e6f9fcff..9372e6f9fcff 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110d.c
+++ b/drivers/media/usb/sn9c102/sn9c102_tas5110d.c
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c
index a30bbc4389f5..a30bbc4389f5 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c
diff --git a/drivers/media/usb/stk1160/Kconfig b/drivers/media/usb/stk1160/Kconfig
new file mode 100644
index 000000000000..1c3a1ec00237
--- /dev/null
+++ b/drivers/media/usb/stk1160/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_STK1160
+ tristate "STK1160 USB video capture support"
+ depends on VIDEO_DEV && I2C
+ select VIDEOBUF2_VMALLOC
+ select VIDEO_SAA711X
+
+ ---help---
+ This is a video4linux driver for STK1160 based video capture devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stk1160
+
+config VIDEO_STK1160_AC97
+ bool "STK1160 AC97 codec support"
+ depends on VIDEO_STK1160 && SND
+ select SND_AC97_CODEC
+
+ ---help---
+ Enables AC97 codec support for stk1160 driver.
+.
diff --git a/drivers/media/usb/stk1160/Makefile b/drivers/media/usb/stk1160/Makefile
new file mode 100644
index 000000000000..dfe3e90ff392
--- /dev/null
+++ b/drivers/media/usb/stk1160/Makefile
@@ -0,0 +1,11 @@
+obj-stk1160-ac97-$(CONFIG_VIDEO_STK1160_AC97) := stk1160-ac97.o
+
+stk1160-y := stk1160-core.o \
+ stk1160-v4l.o \
+ stk1160-video.o \
+ stk1160-i2c.o \
+ $(obj-stk1160-ac97-y)
+
+obj-$(CONFIG_VIDEO_STK1160) += stk1160.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/usb/stk1160/stk1160-ac97.c b/drivers/media/usb/stk1160/stk1160-ac97.c
new file mode 100644
index 000000000000..c8583c262c3d
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-ac97.c
@@ -0,0 +1,152 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static struct snd_ac97 *stk1160_ac97;
+
+static void stk1160_write_ac97(struct snd_ac97 *ac97, u16 reg, u16 value)
+{
+ struct stk1160 *dev = ac97->private_data;
+
+ /* Set codec register address */
+ stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
+
+ /* Set codec command */
+ stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff);
+ stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8);
+
+ /*
+ * Set command write bit to initiate write operation.
+ * The bit will be cleared when transfer is done.
+ */
+ stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
+}
+
+static u16 stk1160_read_ac97(struct snd_ac97 *ac97, u16 reg)
+{
+ struct stk1160 *dev = ac97->private_data;
+ u8 vall = 0;
+ u8 valh = 0;
+
+ /* Set codec register address */
+ stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
+
+ /*
+ * Set command read bit to initiate read operation.
+ * The bit will be cleared when transfer is done.
+ */
+ stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b);
+
+ /* Retrieve register value */
+ stk1160_read_reg(dev, STK1160_AC97_CMD, &vall);
+ stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh);
+
+ return (valh << 8) | vall;
+}
+
+static void stk1160_reset_ac97(struct snd_ac97 *ac97)
+{
+ struct stk1160 *dev = ac97->private_data;
+ /* Two-step reset AC97 interface and hardware codec */
+ stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94);
+ stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x88);
+
+ /* Set 16-bit audio data and choose L&R channel*/
+ stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01);
+}
+
+static struct snd_ac97_bus_ops stk1160_ac97_ops = {
+ .read = stk1160_read_ac97,
+ .write = stk1160_write_ac97,
+ .reset = stk1160_reset_ac97,
+};
+
+int stk1160_ac97_register(struct stk1160 *dev)
+{
+ struct snd_card *card = NULL;
+ struct snd_ac97_bus *ac97_bus;
+ struct snd_ac97_template ac97_template;
+ int rc;
+
+ /*
+ * Just want a card to access ac96 controls,
+ * the actual capture interface will be handled by snd-usb-audio
+ */
+ rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (rc < 0)
+ return rc;
+
+ snd_card_set_dev(card, dev->dev);
+
+ /* TODO: I'm not sure where should I get these names :-( */
+ snprintf(card->shortname, sizeof(card->shortname),
+ "stk1160-mixer");
+ snprintf(card->longname, sizeof(card->longname),
+ "stk1160 ac97 codec mixer control");
+ strncpy(card->driver, dev->dev->driver->name, sizeof(card->driver));
+
+ rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus);
+ if (rc)
+ goto err;
+
+ /* We must set private_data before calling snd_ac97_mixer */
+ memset(&ac97_template, 0, sizeof(ac97_template));
+ ac97_template.private_data = dev;
+ ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
+ rc = snd_ac97_mixer(ac97_bus, &ac97_template, &stk1160_ac97);
+ if (rc)
+ goto err;
+
+ dev->snd_card = card;
+ rc = snd_card_register(card);
+ if (rc)
+ goto err;
+
+ return 0;
+
+err:
+ dev->snd_card = NULL;
+ snd_card_free(card);
+ return rc;
+}
+
+int stk1160_ac97_unregister(struct stk1160 *dev)
+{
+ struct snd_card *card = dev->snd_card;
+
+ /*
+ * We need to check usb_device,
+ * because ac97 release attempts to communicate with codec
+ */
+ if (card && dev->udev)
+ snd_card_free(card);
+
+ return 0;
+}
diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c
new file mode 100644
index 000000000000..74236fd3b7ec
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-core.c
@@ -0,0 +1,432 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ * 1. (Try to) detect if we must register ac97 mixer
+ * 2. Support stream at lower speed: lower frame rate or lower frame size.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/usb.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <media/saa7115.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int input;
+module_param(input, int, 0644);
+MODULE_PARM_DESC(input, "Set default input");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ezequiel Garcia");
+MODULE_DESCRIPTION("STK1160 driver");
+
+/* Devices supported by this driver */
+static struct usb_device_id stk1160_id_table[] = {
+ { USB_DEVICE(0x05e1, 0x0408) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, stk1160_id_table);
+
+/* saa7113 I2C address */
+static unsigned short saa7113_addrs[] = {
+ 0x4a >> 1,
+ I2C_CLIENT_END
+};
+
+/*
+ * Read/Write stk registers
+ */
+int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value)
+{
+ int ret;
+ int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+ *value = 0;
+ ret = usb_control_msg(dev->udev, pipe, 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, value, sizeof(u8), HZ);
+ if (ret < 0) {
+ stk1160_err("read failed on reg 0x%x (%d)\n",
+ reg, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value)
+{
+ int ret;
+ int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+ ret = usb_control_msg(dev->udev, pipe, 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, reg, NULL, 0, HZ);
+ if (ret < 0) {
+ stk1160_err("write failed on reg 0x%x (%d)\n",
+ reg, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void stk1160_select_input(struct stk1160 *dev)
+{
+ static const u8 gctrl[] = {
+ 0x98, 0x90, 0x88, 0x80
+ };
+
+ if (dev->ctl_input < ARRAY_SIZE(gctrl))
+ stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]);
+}
+
+/* TODO: We should break this into pieces */
+static void stk1160_reg_reset(struct stk1160 *dev)
+{
+ int i;
+
+ static const struct regval ctl[] = {
+ {STK1160_GCTRL+2, 0x0078},
+
+ {STK1160_RMCTL+1, 0x0000},
+ {STK1160_RMCTL+3, 0x0002},
+
+ {STK1160_PLLSO, 0x0010},
+ {STK1160_PLLSO+1, 0x0000},
+ {STK1160_PLLSO+2, 0x0014},
+ {STK1160_PLLSO+3, 0x000E},
+
+ {STK1160_PLLFD, 0x0046},
+
+ /* Timing generator setup */
+ {STK1160_TIGEN, 0x0012},
+ {STK1160_TICTL, 0x002D},
+ {STK1160_TICTL+1, 0x0001},
+ {STK1160_TICTL+2, 0x0000},
+ {STK1160_TICTL+3, 0x0000},
+ {STK1160_TIGEN, 0x0080},
+
+ {0xffff, 0xffff}
+ };
+
+ for (i = 0; ctl[i].reg != 0xffff; i++)
+ stk1160_write_reg(dev, ctl[i].reg, ctl[i].val);
+}
+
+static void stk1160_release(struct v4l2_device *v4l2_dev)
+{
+ struct stk1160 *dev = container_of(v4l2_dev, struct stk1160, v4l2_dev);
+
+ stk1160_info("releasing all resources\n");
+
+ stk1160_i2c_unregister(dev);
+
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev->alt_max_pkt_size);
+ kfree(dev);
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+/*
+ * Scan usb interface and populate max_pkt_size array
+ * with information on each alternate setting.
+ * The array should be allocated by the caller.
+ */
+static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev,
+ unsigned int *max_pkt_size)
+{
+ int i, e, sizedescr, size, ifnum;
+ const struct usb_endpoint_descriptor *desc;
+
+ bool has_video = false, has_audio = false;
+ const char *speed;
+
+ ifnum = intf->altsetting[0].desc.bInterfaceNumber;
+
+ /* Get endpoints */
+ for (i = 0; i < intf->num_altsetting; i++) {
+
+ for (e = 0; e < intf->altsetting[i].desc.bNumEndpoints; e++) {
+
+ /* This isn't clear enough, at least to me */
+ desc = &intf->altsetting[i].endpoint[e].desc;
+ sizedescr = le16_to_cpu(desc->wMaxPacketSize);
+ size = sizedescr & 0x7ff;
+
+ if (udev->speed == USB_SPEED_HIGH)
+ size = size * hb_mult(sizedescr);
+
+ if (usb_endpoint_xfer_isoc(desc) &&
+ usb_endpoint_dir_in(desc)) {
+ switch (desc->bEndpointAddress) {
+ case STK1160_EP_AUDIO:
+ has_audio = true;
+ break;
+ case STK1160_EP_VIDEO:
+ has_video = true;
+ max_pkt_size[i] = size;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Is this even possible? */
+ if (!(has_audio || has_video)) {
+ dev_err(&udev->dev, "no audio or video endpoints found\n");
+ return -ENODEV;
+ }
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5";
+ break;
+ case USB_SPEED_FULL:
+ speed = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "480";
+ break;
+ default:
+ speed = "unknown";
+ }
+
+ dev_info(&udev->dev, "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),
+ ifnum,
+ intf->altsetting->desc.bInterfaceNumber);
+
+ /* This should never happen, since we rejected audio interfaces */
+ if (has_audio)
+ dev_warn(&udev->dev, "audio interface %d found.\n\
+ This is not implemented by this driver,\
+ you should use snd-usb-audio instead\n", ifnum);
+
+ if (has_video)
+ dev_info(&udev->dev, "video interface %d found\n",
+ ifnum);
+
+ /*
+ * Make sure we have 480 Mbps of bandwidth, otherwise things like
+ * video stream wouldn't likely work, since 12 Mbps is generally
+ * not enough even for most streams.
+ */
+ if (udev->speed != USB_SPEED_HIGH)
+ dev_warn(&udev->dev, "must be connected to a high-speed USB 2.0 port\n\
+ You may not be able to stream video smoothly\n");
+
+ return 0;
+}
+
+static int stk1160_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ifnum;
+ int rc = 0;
+
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ struct usb_device *udev;
+ struct stk1160 *dev;
+
+ ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+ udev = interface_to_usbdev(interface);
+
+ /*
+ * Since usb audio class is supported by snd-usb-audio,
+ * we reject audio interface.
+ */
+ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO)
+ return -ENODEV;
+
+ /* Alloc an array for all possible max_pkt_size */
+ alt_max_pkt_size = kmalloc(sizeof(alt_max_pkt_size[0]) *
+ interface->num_altsetting, GFP_KERNEL);
+ if (alt_max_pkt_size == NULL)
+ return -ENOMEM;
+
+ /*
+ * Scan usb posibilities and populate alt_max_pkt_size array.
+ * Also, check if device speed is fast enough.
+ */
+ rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size);
+ if (rc < 0) {
+ kfree(alt_max_pkt_size);
+ return rc;
+ }
+
+ dev = kzalloc(sizeof(struct stk1160), GFP_KERNEL);
+ if (dev == NULL) {
+ kfree(alt_max_pkt_size);
+ return -ENOMEM;
+ }
+
+ dev->alt_max_pkt_size = alt_max_pkt_size;
+ dev->udev = udev;
+ dev->num_alt = interface->num_altsetting;
+ dev->ctl_input = input;
+
+ /* We save struct device for debug purposes only */
+ dev->dev = &interface->dev;
+
+ usb_set_intfdata(interface, dev);
+
+ /* initialize videobuf2 stuff */
+ rc = stk1160_vb2_setup(dev);
+ if (rc < 0)
+ goto free_err;
+
+ /*
+ * There is no need to take any locks here in probe
+ * because we register the device node as the *last* thing.
+ */
+ spin_lock_init(&dev->buf_lock);
+ mutex_init(&dev->v4l_lock);
+ mutex_init(&dev->vb_queue_lock);
+
+ rc = v4l2_ctrl_handler_init(&dev->ctrl_handler, 0);
+ if (rc) {
+ stk1160_err("v4l2_ctrl_handler_init failed (%d)\n", rc);
+ goto free_err;
+ }
+
+ /*
+ * We obtain a v4l2_dev but defer
+ * registration of video device node as the last thing.
+ * There is no need to set the name if we give a device struct
+ */
+ dev->v4l2_dev.release = stk1160_release;
+ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+ rc = v4l2_device_register(dev->dev, &dev->v4l2_dev);
+ if (rc) {
+ stk1160_err("v4l2_device_register failed (%d)\n", rc);
+ goto free_ctrl;
+ }
+
+ rc = stk1160_i2c_register(dev);
+ if (rc < 0)
+ goto unreg_v4l2;
+
+ /*
+ * To the best of my knowledge stk1160 boards only have
+ * saa7113, but it doesn't hurt to support them all.
+ */
+ dev->sd_saa7115 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "saa7115_auto", 0, saa7113_addrs);
+
+ stk1160_info("driver ver %s successfully loaded\n",
+ STK1160_VERSION);
+
+ /* i2c reset saa711x */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ 0, 0, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+
+ /* reset stk1160 to default values */
+ stk1160_reg_reset(dev);
+
+ /* select default input */
+ stk1160_select_input(dev);
+
+ stk1160_ac97_register(dev);
+
+ rc = stk1160_video_register(dev);
+ if (rc < 0)
+ goto unreg_i2c;
+
+ return 0;
+
+unreg_i2c:
+ stk1160_i2c_unregister(dev);
+unreg_v4l2:
+ v4l2_device_unregister(&dev->v4l2_dev);
+free_ctrl:
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+free_err:
+ kfree(alt_max_pkt_size);
+ kfree(dev);
+
+ return rc;
+}
+
+static void stk1160_disconnect(struct usb_interface *interface)
+{
+ struct stk1160 *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /*
+ * Wait until all current v4l2 operation are finished
+ * then deallocate resources
+ */
+ mutex_lock(&dev->vb_queue_lock);
+ mutex_lock(&dev->v4l_lock);
+
+ /* Here is the only place where isoc get released */
+ stk1160_uninit_isoc(dev);
+
+ /* ac97 unregister needs to be done before usb_device is cleared */
+ stk1160_ac97_unregister(dev);
+
+ stk1160_clear_queue(dev);
+
+ video_unregister_device(&dev->vdev);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+
+ /* This way current users can detect device is gone */
+ dev->udev = NULL;
+
+ mutex_unlock(&dev->v4l_lock);
+ mutex_unlock(&dev->vb_queue_lock);
+
+ /*
+ * This calls stk1160_release if it's the last reference.
+ * therwise, release is posponed until there are no users left.
+ */
+ v4l2_device_put(&dev->v4l2_dev);
+}
+
+static struct usb_driver stk1160_usb_driver = {
+ .name = "stk1160",
+ .id_table = stk1160_id_table,
+ .probe = stk1160_probe,
+ .disconnect = stk1160_disconnect,
+};
+
+module_usb_driver(stk1160_usb_driver);
diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c
new file mode 100644
index 000000000000..176ac937306b
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-i2c.c
@@ -0,0 +1,294 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk_i2c(fmt, args...) \
+do { \
+ if (i2c_debug) \
+ printk(KERN_DEBUG fmt, ##args); \
+} while (0)
+
+static int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask)
+{
+ unsigned long end;
+ u8 flag;
+
+ /* Wait until read/write finish bit is set */
+ end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT);
+ while (time_is_after_jiffies(end)) {
+
+ stk1160_read_reg(dev, STK1160_SICTL+1, &flag);
+ /* read/write done? */
+ if (flag & wait_bit_mask)
+ goto done;
+
+ usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC);
+ }
+
+ return -ETIMEDOUT;
+
+done:
+ return 0;
+}
+
+static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr,
+ u8 reg, u8 value)
+{
+ int rc;
+
+ /* Set serial device address */
+ rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+ if (rc < 0)
+ return rc;
+
+ /* Set i2c device register sub-address */
+ rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Set i2c device register value */
+ rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value);
+ if (rc < 0)
+ return rc;
+
+ /* Start write now */
+ rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01);
+ if (rc < 0)
+ return rc;
+
+ rc = stk1160_i2c_busy_wait(dev, 0x04);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr,
+ u8 reg, u8 *value)
+{
+ int rc;
+
+ /* Set serial device address */
+ rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+ if (rc < 0)
+ return rc;
+
+ /* Set i2c device register sub-address */
+ rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Start read now */
+ rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
+ if (rc < 0)
+ return rc;
+
+ rc = stk1160_i2c_busy_wait(dev, 0x01);
+ if (rc < 0)
+ return rc;
+
+ stk1160_read_reg(dev, STK1160_SBUSR_RD, value);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+/*
+ * stk1160_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int stk1160_i2c_check_for_device(struct stk1160 *dev,
+ unsigned char addr)
+{
+ int rc;
+
+ /* Set serial device address */
+ rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+ if (rc < 0)
+ return rc;
+
+ /* Set device sub-address, we'll chip version reg */
+ rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00);
+ if (rc < 0)
+ return rc;
+
+ /* Start read now */
+ rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
+ if (rc < 0)
+ return rc;
+
+ rc = stk1160_i2c_busy_wait(dev, 0x01);
+ if (rc < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ * stk1160_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct stk1160 *dev = i2c_adap->algo_data;
+ int addr, rc, i;
+
+ for (i = 0; i < num; i++) {
+ addr = msgs[i].addr << 1;
+ dprintk_i2c("%s: addr=%x", __func__, addr);
+
+ if (!msgs[i].len) {
+ /* no len: check only for device presence */
+ rc = stk1160_i2c_check_for_device(dev, addr);
+ if (rc < 0) {
+ dprintk_i2c(" no device\n");
+ return rc;
+ }
+
+ } else if (msgs[i].flags & I2C_M_RD) {
+ /* read request without preceding register selection */
+ dprintk_i2c(" subaddr not selected");
+ rc = -EOPNOTSUPP;
+ goto err;
+
+ } else if (i + 1 < num && msgs[i].len <= 2 &&
+ (msgs[i + 1].flags & I2C_M_RD) &&
+ msgs[i].addr == msgs[i + 1].addr) {
+
+ if (msgs[i].len != 1 || msgs[i + 1].len != 1) {
+ dprintk_i2c(" len not supported");
+ rc = -EOPNOTSUPP;
+ goto err;
+ }
+
+ dprintk_i2c(" subaddr=%x", msgs[i].buf[0]);
+
+ rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0],
+ msgs[i + 1].buf);
+
+ dprintk_i2c(" read=%x", *msgs[i + 1].buf);
+
+ /* consumed two msgs, so we skip one of them */
+ i++;
+
+ } else {
+ if (msgs[i].len != 2) {
+ dprintk_i2c(" len not supported");
+ rc = -EOPNOTSUPP;
+ goto err;
+ }
+
+ dprintk_i2c(" subaddr=%x write=%x",
+ msgs[i].buf[0], msgs[i].buf[1]);
+
+ rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0],
+ msgs[i].buf[1]);
+ }
+
+ if (rc < 0)
+ goto err;
+ dprintk_i2c(" OK\n");
+ }
+
+ return num;
+err:
+ dprintk_i2c(" ERROR: %d\n", rc);
+ return num;
+}
+
+/*
+ * functionality(), what da heck is this?
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm algo = {
+ .master_xfer = stk1160_i2c_xfer,
+ .functionality = functionality,
+};
+
+static struct i2c_adapter adap_template = {
+ .owner = THIS_MODULE,
+ .name = "stk1160",
+ .algo = &algo,
+};
+
+static struct i2c_client client_template = {
+ .name = "stk1160 internal",
+};
+
+/*
+ * stk1160_i2c_register()
+ * register i2c bus
+ */
+int stk1160_i2c_register(struct stk1160 *dev)
+{
+ int rc;
+
+ dev->i2c_adap = adap_template;
+ dev->i2c_adap.dev.parent = dev->dev;
+ strcpy(dev->i2c_adap.name, "stk1160");
+ dev->i2c_adap.algo_data = dev;
+
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+
+ rc = i2c_add_adapter(&dev->i2c_adap);
+ if (rc < 0) {
+ stk1160_err("cannot add i2c adapter (%d)\n", rc);
+ return rc;
+ }
+
+ dev->i2c_client = client_template;
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ /* Set i2c clock divider device address */
+ stk1160_write_reg(dev, STK1160_SICTL_CD, 0x0f);
+
+ /* ??? */
+ stk1160_write_reg(dev, STK1160_ASIC + 3, 0x00);
+
+ return 0;
+}
+
+/*
+ * stk1160_i2c_unregister()
+ * unregister i2c_bus
+ */
+int stk1160_i2c_unregister(struct stk1160 *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
diff --git a/drivers/media/usb/stk1160/stk1160-reg.h b/drivers/media/usb/stk1160/stk1160-reg.h
new file mode 100644
index 000000000000..3e49da6e7edd
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-reg.h
@@ -0,0 +1,93 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+/* GPIO Control */
+#define STK1160_GCTRL 0x000
+
+/* Remote Wakup Control */
+#define STK1160_RMCTL 0x00c
+
+/*
+ * Decoder Control Register:
+ * This byte controls capture start/stop
+ * with bit #7 (0x?? OR 0x80 to activate).
+ */
+#define STK1160_DCTRL 0x100
+
+/* Capture Frame Start Position */
+#define STK116_CFSPO 0x110
+#define STK116_CFSPO_STX_L 0x110
+#define STK116_CFSPO_STX_H 0x111
+#define STK116_CFSPO_STY_L 0x112
+#define STK116_CFSPO_STY_H 0x113
+
+/* Capture Frame End Position */
+#define STK116_CFEPO 0x114
+#define STK116_CFEPO_ENX_L 0x114
+#define STK116_CFEPO_ENX_H 0x115
+#define STK116_CFEPO_ENY_L 0x116
+#define STK116_CFEPO_ENY_H 0x117
+
+/* Serial Interface Control */
+#define STK1160_SICTL 0x200
+#define STK1160_SICTL_CD 0x202
+#define STK1160_SICTL_SDA 0x203
+
+/* Serial Bus Write */
+#define STK1160_SBUSW 0x204
+#define STK1160_SBUSW_WA 0x204
+#define STK1160_SBUSW_WD 0x205
+
+/* Serial Bus Read */
+#define STK1160_SBUSR 0x208
+#define STK1160_SBUSR_RA 0x208
+#define STK1160_SBUSR_RD 0x209
+
+/* Alternate Serial Inteface Control */
+#define STK1160_ASIC 0x2fc
+
+/* PLL Select Options */
+#define STK1160_PLLSO 0x018
+
+/* PLL Frequency Divider */
+#define STK1160_PLLFD 0x01c
+
+/* Timing Generator */
+#define STK1160_TIGEN 0x300
+
+/* Timing Control Parameter */
+#define STK1160_TICTL 0x350
+
+/* AC97 Audio Control */
+#define STK1160_AC97CTL_0 0x500
+#define STK1160_AC97CTL_1 0x504
+
+/* Use [0:6] bits of register 0x504 to set codec command address */
+#define STK1160_AC97_ADDR 0x504
+/* Use [16:31] bits of register 0x500 to set codec command data */
+#define STK1160_AC97_CMD 0x502
+
+/* Audio I2S Interface */
+#define STK1160_I2SCTL 0x50c
+
+/* EEPROM Interface */
+#define STK1160_EEPROM_SZ 0x5f0
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
new file mode 100644
index 000000000000..1ad4ac187727
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -0,0 +1,740 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include <media/saa7115.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int vidioc_debug;
+module_param(vidioc_debug, int, 0644);
+MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]");
+
+static bool keep_buffers;
+module_param(keep_buffers, bool, 0644);
+MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming");
+
+/* supported video standards */
+static struct stk1160_fmt format[] = {
+ {
+ .name = "16 bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ }
+};
+
+static void stk1160_set_std(struct stk1160 *dev)
+{
+ int i;
+
+ static struct regval std525[] = {
+
+ /* 720x480 */
+
+ /* Frame start */
+ {STK116_CFSPO_STX_L, 0x0000},
+ {STK116_CFSPO_STX_H, 0x0000},
+ {STK116_CFSPO_STY_L, 0x0003},
+ {STK116_CFSPO_STY_H, 0x0000},
+
+ /* Frame end */
+ {STK116_CFEPO_ENX_L, 0x05a0},
+ {STK116_CFEPO_ENX_H, 0x0005},
+ {STK116_CFEPO_ENY_L, 0x00f3},
+ {STK116_CFEPO_ENY_H, 0x0000},
+
+ {0xffff, 0xffff}
+ };
+
+ static struct regval std625[] = {
+
+ /* 720x576 */
+
+ /* TODO: Each line of frame has some junk at the end */
+ /* Frame start */
+ {STK116_CFSPO, 0x0000},
+ {STK116_CFSPO+1, 0x0000},
+ {STK116_CFSPO+2, 0x0001},
+ {STK116_CFSPO+3, 0x0000},
+
+ /* Frame end */
+ {STK116_CFEPO, 0x05a0},
+ {STK116_CFEPO+1, 0x0005},
+ {STK116_CFEPO+2, 0x0121},
+ {STK116_CFEPO+3, 0x0001},
+
+ {0xffff, 0xffff}
+ };
+
+ if (dev->norm & V4L2_STD_525_60) {
+ stk1160_dbg("registers to NTSC like standard\n");
+ for (i = 0; std525[i].reg != 0xffff; i++)
+ stk1160_write_reg(dev, std525[i].reg, std525[i].val);
+ } else {
+ stk1160_dbg("registers to PAL like standard\n");
+ for (i = 0; std625[i].reg != 0xffff; i++)
+ stk1160_write_reg(dev, std625[i].reg, std625[i].val);
+ }
+
+}
+
+/*
+ * Set a new alternate setting.
+ * Returns true is dev->max_pkt_size has changed, false otherwise.
+ */
+static bool stk1160_set_alternate(struct stk1160 *dev)
+{
+ int i, prev_alt = dev->alt;
+ unsigned int min_pkt_size;
+ bool new_pkt_size;
+
+ /*
+ * If we don't set right alternate,
+ * then we will get a green screen with junk.
+ */
+ min_pkt_size = STK1160_MIN_PKT_SIZE;
+
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+ dev->alt = i;
+ break;
+ /*
+ * otherwise make sure that we end up with the maximum bandwidth
+ * because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size[i] >
+ dev->alt_max_pkt_size[dev->alt])
+ dev->alt = i;
+ }
+
+ stk1160_info("setting alternate %d\n", dev->alt);
+
+ if (dev->alt != prev_alt) {
+ stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ stk1160_dbg("setting alt %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->alt_max_pkt_size[dev->alt]);
+ usb_set_interface(dev->udev, 0, dev->alt);
+ }
+
+ new_pkt_size = dev->max_pkt_size != dev->alt_max_pkt_size[dev->alt];
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+
+ return new_pkt_size;
+}
+
+static int stk1160_start_streaming(struct stk1160 *dev)
+{
+ bool new_pkt_size;
+ int rc = 0;
+ int i;
+
+ /* Check device presence */
+ if (!dev->udev)
+ return -ENODEV;
+
+ if (mutex_lock_interruptible(&dev->v4l_lock))
+ return -ERESTARTSYS;
+ /*
+ * For some reason it is mandatory to set alternate *first*
+ * and only *then* initialize isoc urbs.
+ * Someone please explain me why ;)
+ */
+ new_pkt_size = stk1160_set_alternate(dev);
+
+ /*
+ * We (re)allocate isoc urbs if:
+ * there is no allocated isoc urbs, OR
+ * a new dev->max_pkt_size is detected
+ */
+ if (!dev->isoc_ctl.num_bufs || new_pkt_size) {
+ rc = stk1160_alloc_isoc(dev);
+ if (rc < 0)
+ goto out_unlock;
+ }
+
+ /* 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_KERNEL);
+ if (rc) {
+ stk1160_err("cannot submit urb[%d] (%d)\n", i, rc);
+ stk1160_uninit_isoc(dev);
+ goto out_unlock;
+ }
+ }
+
+ /* Start saa711x */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+
+ /* Start stk1160 */
+ stk1160_write_reg(dev, STK1160_DCTRL, 0xb3);
+ stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00);
+
+ stk1160_dbg("streaming started\n");
+
+out_unlock:
+ mutex_unlock(&dev->v4l_lock);
+
+ return rc;
+}
+
+/* Must be called with v4l_lock hold */
+static void stk1160_stop_hw(struct stk1160 *dev)
+{
+ /* If the device is not physically present, there is nothing to do */
+ if (!dev->udev)
+ return;
+
+ /* set alternate 0 */
+ dev->alt = 0;
+ stk1160_info("setting alternate %d\n", dev->alt);
+ usb_set_interface(dev->udev, 0, 0);
+
+ /* Stop stk1160 */
+ stk1160_write_reg(dev, STK1160_DCTRL, 0x00);
+ stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00);
+
+ /* Stop saa711x */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+static int stk1160_stop_streaming(struct stk1160 *dev)
+{
+ if (mutex_lock_interruptible(&dev->v4l_lock))
+ return -ERESTARTSYS;
+
+ stk1160_cancel_isoc(dev);
+
+ /*
+ * It is possible to keep buffers around using a module parameter.
+ * This is intended to avoid memory fragmentation.
+ */
+ if (!keep_buffers)
+ stk1160_free_isoc(dev);
+
+ stk1160_stop_hw(dev);
+
+ stk1160_clear_queue(dev);
+
+ stk1160_dbg("streaming stopped\n");
+
+ mutex_unlock(&dev->v4l_lock);
+
+ return 0;
+}
+
+static struct v4l2_file_operations stk1160_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+/*
+ * vidioc ioctls
+ */
+static int vidioc_querycap(struct file *file,
+ void *priv, struct v4l2_capability *cap)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ strcpy(cap->driver, "stk1160");
+ strcpy(cap->card, "stk1160");
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->device_caps =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
+ f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ if (f->fmt.pix.pixelformat != format[0].fourcc) {
+ stk1160_err("fourcc format 0x%08x invalid\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ /*
+ * User can't choose size at his own will,
+ * so we just return him the current size chosen
+ * at standard selection.
+ * TODO: Implement frame scaling?
+ */
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct stk1160 *dev = video_drvdata(file);
+ struct vb2_queue *q = &dev->vb_vidq;
+ int rc;
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ rc = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (rc < 0)
+ return rc;
+
+ /* We don't support any format changes */
+
+ return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct stk1160 *dev = video_drvdata(file);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ *norm = dev->norm;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct stk1160 *dev = video_drvdata(file);
+ struct vb2_queue *q = &dev->vb_vidq;
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ /* Check device presence */
+ if (!dev->udev)
+ return -ENODEV;
+
+ /* We need to set this now, before we call stk1160_set_std */
+ dev->norm = *norm;
+
+ /* This is taken from saa7115 video decoder */
+ if (dev->norm & V4L2_STD_525_60) {
+ dev->width = 720;
+ dev->height = 480;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ dev->width = 720;
+ dev->height = 576;
+ } else {
+ stk1160_err("invalid standard\n");
+ return -EINVAL;
+ }
+
+ stk1160_set_std(dev);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ dev->norm);
+
+ return 0;
+}
+
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ if (i->index > STK1160_MAX_INPUT)
+ return -EINVAL;
+
+ sprintf(i->name, "Composite%d", i->index);
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->std = dev->vdev.tvnorms;
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct stk1160 *dev = video_drvdata(file);
+ *i = dev->ctl_input;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ if (vb2_is_busy(&dev->vb_vidq))
+ return -EBUSY;
+
+ if (i > STK1160_MAX_INPUT)
+ return -EINVAL;
+
+ dev->ctl_input = i;
+
+ stk1160_select_input(dev);
+
+ return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ switch (chip->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct stk1160 *dev = video_drvdata(file);
+ int rc;
+ u8 val;
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ /* TODO: Support me please :-( */
+ return -EINVAL;
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ /* Match host */
+ rc = stk1160_read_reg(dev, reg->reg, &val);
+ reg->val = val;
+ reg->size = 1;
+
+ return rc;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct stk1160 *dev = video_drvdata(file);
+
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_AC97:
+ return -EINVAL;
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ /* TODO: is this correct? */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+ return 0;
+ default:
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ }
+
+ /* Match host */
+ return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val));
+}
+#endif
+
+static const struct v4l2_ioctl_ops stk1160_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_querystd = vidioc_querystd,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+
+ /* vb2 takes care of these */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+/********************************************************************/
+
+/*
+ * Videobuf2 operations
+ */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct stk1160 *dev = vb2_get_drv_priv(vq);
+ unsigned long size;
+
+ size = dev->width * dev->height * 2;
+
+ /*
+ * Here we can change the number of buffers being requested.
+ * So, we set a minimum and a maximum like this:
+ */
+ *nbuffers = clamp_t(unsigned int, *nbuffers,
+ STK1160_MIN_VIDEO_BUFFERS, STK1160_MAX_VIDEO_BUFFERS);
+
+ /* This means a packed colorformat */
+ *nplanes = 1;
+
+ sizes[0] = size;
+
+ stk1160_info("%s: buffer count %d, each %ld bytes\n",
+ __func__, *nbuffers, size);
+
+ return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ unsigned long flags;
+ struct stk1160 *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct stk1160_buffer *buf =
+ container_of(vb, struct stk1160_buffer, vb);
+
+ spin_lock_irqsave(&dev->buf_lock, flags);
+ if (!dev->udev) {
+ /*
+ * If the device is disconnected return the buffer to userspace
+ * directly. The next QBUF call will fail with -ENODEV.
+ */
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ } else {
+
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+ buf->bytesused = 0;
+ buf->pos = 0;
+
+ /*
+ * If buffer length is less from expected then we return
+ * the buffer to userspace directly.
+ */
+ if (buf->length < dev->width * dev->height * 2)
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ else
+ list_add_tail(&buf->list, &dev->avail_bufs);
+
+ }
+ spin_unlock_irqrestore(&dev->buf_lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct stk1160 *dev = vb2_get_drv_priv(vq);
+ return stk1160_start_streaming(dev);
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct stk1160 *dev = vb2_get_drv_priv(vq);
+ return stk1160_stop_streaming(dev);
+}
+
+static struct vb2_ops stk1160_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static struct video_device v4l_template = {
+ .name = "stk1160",
+ .tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50,
+ .fops = &stk1160_fops,
+ .ioctl_ops = &stk1160_ioctl_ops,
+ .release = video_device_release_empty,
+};
+
+/********************************************************************/
+
+/* Must be called with both v4l_lock and vb_queue_lock hold */
+void stk1160_clear_queue(struct stk1160 *dev)
+{
+ struct stk1160_buffer *buf;
+ unsigned long flags;
+
+ /* Release all active buffers */
+ spin_lock_irqsave(&dev->buf_lock, flags);
+ while (!list_empty(&dev->avail_bufs)) {
+ buf = list_first_entry(&dev->avail_bufs,
+ struct stk1160_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ stk1160_info("buffer [%p/%d] aborted\n",
+ buf, buf->vb.v4l2_buf.index);
+ }
+ /* It's important to clear current buffer */
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->buf_lock, flags);
+}
+
+int stk1160_vb2_setup(struct stk1160 *dev)
+{
+ int rc;
+ struct vb2_queue *q;
+
+ q = &dev->vb_vidq;
+ memset(q, 0, sizeof(dev->vb_vidq));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct stk1160_buffer);
+ q->ops = &stk1160_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ rc = vb2_queue_init(q);
+ if (rc < 0)
+ return rc;
+
+ /* initialize video dma queue */
+ INIT_LIST_HEAD(&dev->avail_bufs);
+
+ return 0;
+}
+
+int stk1160_video_register(struct stk1160 *dev)
+{
+ int rc;
+
+ /* Initialize video_device with a template structure */
+ dev->vdev = v4l_template;
+ dev->vdev.debug = vidioc_debug;
+ dev->vdev.queue = &dev->vb_vidq;
+
+ /*
+ * Provide mutexes for v4l2 core and for videobuf2 queue.
+ * It will be used to protect *only* v4l2 ioctls.
+ */
+ dev->vdev.lock = &dev->v4l_lock;
+ dev->vdev.queue->lock = &dev->vb_queue_lock;
+
+ /* This will be used to set video_device parent */
+ dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
+
+ /* NTSC is default */
+ dev->norm = V4L2_STD_NTSC_M;
+ dev->width = 720;
+ dev->height = 480;
+
+ /* set default format */
+ dev->fmt = &format[0];
+ stk1160_set_std(dev);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ dev->norm);
+
+ video_set_drvdata(&dev->vdev, dev);
+ rc = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (rc < 0) {
+ stk1160_err("video_register_device failed (%d)\n", rc);
+ return rc;
+ }
+
+ v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+ video_device_node_name(&dev->vdev));
+
+ return 0;
+}
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
new file mode 100644
index 000000000000..378526981146
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -0,0 +1,518 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/ratelimit.h>
+
+#include "stk1160.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static inline void print_err_status(struct stk1160 *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+
+ if (packet < 0)
+ printk_ratelimited(KERN_WARNING "URB status %d [%s].\n",
+ status, errmsg);
+ else
+ printk_ratelimited(KERN_INFO "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+}
+
+static inline
+struct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev)
+{
+ struct stk1160_buffer *buf = NULL;
+ unsigned long flags = 0;
+
+ /* Current buffer must be NULL when this functions gets called */
+ BUG_ON(dev->isoc_ctl.buf);
+
+ spin_lock_irqsave(&dev->buf_lock, flags);
+ if (!list_empty(&dev->avail_bufs)) {
+ buf = list_first_entry(&dev->avail_bufs,
+ struct stk1160_buffer, list);
+ list_del(&buf->list);
+ }
+ spin_unlock_irqrestore(&dev->buf_lock, flags);
+
+ return buf;
+}
+
+static inline
+void stk1160_buffer_done(struct stk1160 *dev)
+{
+ struct stk1160_buffer *buf = dev->isoc_ctl.buf;
+
+ dev->field_count++;
+
+ buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ buf->vb.v4l2_buf.bytesused = buf->bytesused;
+ do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+
+ vb2_set_plane_payload(&buf->vb, 0, buf->bytesused);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+
+ dev->isoc_ctl.buf = NULL;
+}
+
+static inline
+void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
+{
+ int linesdone, lineoff, lencopy;
+ int bytesperline = dev->width * 2;
+ struct stk1160_buffer *buf = dev->isoc_ctl.buf;
+ u8 *dst = buf->mem;
+ int remain;
+
+ /*
+ * TODO: These stk1160_dbg are very spammy!
+ * We should 1) check why we are getting them
+ * and 2) add ratelimit.
+ *
+ * UPDATE: One of the reasons (the only one?) for getting these
+ * is incorrect standard (mismatch between expected and configured).
+ * So perhaps, we could add a counter for errors. When the counter
+ * reaches some value, we simply stop streaming.
+ */
+
+ len -= 4;
+ src += 4;
+
+ remain = len;
+
+ linesdone = buf->pos / bytesperline;
+ lineoff = buf->pos % bytesperline; /* offset in current line */
+
+ if (!buf->odd)
+ dst += bytesperline;
+
+ /* Multiply linesdone by two, to take account of the other field */
+ dst += linesdone * bytesperline * 2 + lineoff;
+
+ /* Copy the remaining of current line */
+ if (remain < (bytesperline - lineoff))
+ lencopy = remain;
+ else
+ lencopy = bytesperline - lineoff;
+
+ /*
+ * Check if we have enough space left in the buffer.
+ * In that case, we force loop exit after copy.
+ */
+ if (lencopy > buf->bytesused - buf->length) {
+ lencopy = buf->bytesused - buf->length;
+ remain = lencopy;
+ }
+
+ /* Check if the copy is done */
+ if (lencopy == 0 || remain == 0)
+ return;
+
+ /* Let the bug hunt begin! sanity checks! */
+ if (lencopy < 0) {
+ stk1160_dbg("copy skipped: negative lencopy\n");
+ return;
+ }
+
+ if ((unsigned long)dst + lencopy >
+ (unsigned long)buf->mem + buf->length) {
+ printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
+ return;
+ }
+
+ memcpy(dst, src, lencopy);
+
+ buf->bytesused += lencopy;
+ buf->pos += lencopy;
+ remain -= lencopy;
+
+ /* Copy current field line by line, interlacing with the other field */
+ while (remain > 0) {
+
+ dst += lencopy + bytesperline;
+ src += lencopy;
+
+ /* Copy one line at a time */
+ if (remain < bytesperline)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ /*
+ * Check if we have enough space left in the buffer.
+ * In that case, we force loop exit after copy.
+ */
+ if (lencopy > buf->bytesused - buf->length) {
+ lencopy = buf->bytesused - buf->length;
+ remain = lencopy;
+ }
+
+ /* Check if the copy is done */
+ if (lencopy == 0 || remain == 0)
+ return;
+
+ if (lencopy < 0) {
+ printk_ratelimited(KERN_WARNING "stk1160: negative lencopy detected\n");
+ return;
+ }
+
+ if ((unsigned long)dst + lencopy >
+ (unsigned long)buf->mem + buf->length) {
+ printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
+ return;
+ }
+
+ memcpy(dst, src, lencopy);
+ remain -= lencopy;
+
+ buf->bytesused += lencopy;
+ buf->pos += lencopy;
+ }
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb)
+{
+ int i, len, status;
+ u8 *p;
+
+ if (!dev) {
+ stk1160_warn("%s called with null device\n", __func__);
+ return;
+ }
+
+ if (urb->status < 0) {
+ /* Print status and drop current packet (or field?) */
+ print_err_status(dev, -1, urb->status);
+ return;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ status = urb->iso_frame_desc[i].status;
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ continue;
+ }
+
+ /* Get packet actual length and pointer to data */
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ len = urb->iso_frame_desc[i].actual_length;
+
+ /* Empty packet */
+ if (len <= 4)
+ continue;
+
+ /*
+ * An 8-byte packet sequence means end of field.
+ * So if we don't have any packet, we start receiving one now
+ * and if we do have a packet, then we are done with it.
+ *
+ * These end of field packets are always 0xc0 or 0x80,
+ * but not always 8-byte long so we don't check packet length.
+ */
+ if (p[0] == 0xc0) {
+
+ /*
+ * If first byte is 0xc0 then we received
+ * second field, and frame has ended.
+ */
+ if (dev->isoc_ctl.buf != NULL)
+ stk1160_buffer_done(dev);
+
+ dev->isoc_ctl.buf = stk1160_next_buffer(dev);
+ if (dev->isoc_ctl.buf == NULL)
+ return;
+ }
+
+ /*
+ * If we don't have a buffer here, then it means we
+ * haven't found the start mark sequence.
+ */
+ if (dev->isoc_ctl.buf == NULL)
+ continue;
+
+ if (p[0] == 0xc0 || p[0] == 0x80) {
+
+ /* We set next packet parity and
+ * continue to get next one
+ */
+ dev->isoc_ctl.buf->odd = *p & 0x40;
+ dev->isoc_ctl.buf->pos = 0;
+ continue;
+ }
+
+ stk1160_copy_video(dev, p, len);
+ }
+}
+
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void stk1160_isoc_irq(struct urb *urb)
+{
+ int i, rc;
+ struct stk1160 *dev = urb->context;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* TODO: check uvc driver: he frees the queue here */
+ return;
+ default:
+ stk1160_err("urb error! status %d\n", urb->status);
+ return;
+ }
+
+ stk1160_process_isoc(dev, urb);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc)
+ stk1160_err("urb re-submit failed (%d)\n", rc);
+}
+
+/*
+ * Cancel urbs
+ * This function can't be called in atomic context
+ */
+void stk1160_cancel_isoc(struct stk1160 *dev)
+{
+ int i;
+
+ /*
+ * This check is not necessary, but we add it
+ * to avoid a spurious debug message
+ */
+ if (!dev->isoc_ctl.num_bufs)
+ return;
+
+ stk1160_dbg("killing urbs...\n");
+
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+
+ /*
+ * To kill urbs we can't be in atomic context.
+ * We don't care for NULL pointer since
+ * usb_kill_urb allows it.
+ */
+ usb_kill_urb(dev->isoc_ctl.urb[i]);
+ }
+
+ stk1160_dbg("all urbs killed\n");
+}
+
+/*
+ * Releases urb and transfer buffers
+ * Obviusly, associated urb must be killed before releasing it.
+ */
+void stk1160_free_isoc(struct stk1160 *dev)
+{
+ struct urb *urb;
+ int i;
+
+ stk1160_dbg("freeing urb buffers...\n");
+
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+
+ if (dev->isoc_ctl.transfer_buffer[i]) {
+#ifndef CONFIG_DMA_NONCOHERENT
+ usb_free_coherent(dev->udev,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+#else
+ kfree(dev->isoc_ctl.transfer_buffer[i]);
+#endif
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
+ }
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+
+ stk1160_dbg("all urb buffers freed\n");
+}
+
+/*
+ * Helper for cancelling and freeing urbs
+ * This function can't be called in atomic context
+ */
+void stk1160_uninit_isoc(struct stk1160 *dev)
+{
+ stk1160_cancel_isoc(dev);
+ stk1160_free_isoc(dev);
+}
+
+/*
+ * Allocate URBs
+ */
+int stk1160_alloc_isoc(struct stk1160 *dev)
+{
+ struct urb *urb;
+ int i, j, k, sb_size, max_packets, num_bufs;
+
+ /*
+ * It may be necessary to release isoc here,
+ * since isoc are only released on disconnection.
+ * (see new_pkt_size flag)
+ */
+ if (dev->isoc_ctl.num_bufs)
+ stk1160_uninit_isoc(dev);
+
+ stk1160_dbg("allocating urbs...\n");
+
+ num_bufs = STK1160_NUM_BUFS;
+ max_packets = STK1160_NUM_PACKETS;
+ sb_size = max_packets * dev->max_pkt_size;
+
+ dev->isoc_ctl.buf = NULL;
+ dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ stk1160_err("out of memory for urb array\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.transfer_buffer) {
+ stk1160_err("out of memory for usb transfers\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < num_bufs; i++) {
+
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ stk1160_err("cannot alloc urb[%d]\n", i);
+ stk1160_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->isoc_ctl.urb[i] = urb;
+
+#ifndef CONFIG_DMA_NONCOHERENT
+ dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+#else
+ dev->isoc_ctl.transfer_buffer[i] = kmalloc(sb_size, GFP_KERNEL);
+#endif
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ stk1160_err("cannot alloc %d bytes for tx buffer\n",
+ sb_size);
+ stk1160_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ /*
+ * FIXME: Where can I get the endpoint?
+ */
+ urb->dev = dev->udev;
+ urb->pipe = usb_rcvisocpipe(dev->udev, STK1160_EP_VIDEO);
+ urb->transfer_buffer = dev->isoc_ctl.transfer_buffer[i];
+ urb->transfer_buffer_length = sb_size;
+ urb->complete = stk1160_isoc_irq;
+ urb->context = dev;
+ urb->interval = 1;
+ urb->start_frame = 0;
+ urb->number_of_packets = max_packets;
+#ifndef CONFIG_DMA_NONCOHERENT
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+#else
+ urb->transfer_flags = URB_ISO_ASAP;
+#endif
+
+ k = 0;
+ for (j = 0; j < max_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;
+ }
+ }
+
+ stk1160_dbg("urbs allocated\n");
+
+ /* At last we can say we have some buffers */
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ return 0;
+}
+
diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h
new file mode 100644
index 000000000000..3feba0033f98
--- /dev/null
+++ b/drivers/media/usb/stk1160/stk1160.h
@@ -0,0 +1,208 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ * Copyright (C) 2010 R.M. Thomas
+ * <rmthomas--a.t--sciolus.org>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define STK1160_VERSION "0.9.5"
+#define STK1160_VERSION_NUM 0x000905
+
+/* TODO: Decide on number of packets for each buffer */
+#define STK1160_NUM_PACKETS 64
+
+/* Number of buffers for isoc transfers */
+#define STK1160_NUM_BUFS 16 /* TODO */
+
+/* TODO: This endpoint address should be retrieved */
+#define STK1160_EP_VIDEO 0x82
+#define STK1160_EP_AUDIO 0x81
+
+/* Max and min video buffers */
+#define STK1160_MIN_VIDEO_BUFFERS 8
+#define STK1160_MAX_VIDEO_BUFFERS 32
+
+#define STK1160_MIN_PKT_SIZE 3072
+
+#define STK1160_MAX_INPUT 3
+
+#define STK1160_I2C_TIMEOUT 100
+
+/* TODO: Print helpers
+ * I could use dev_xxx, pr_xxx, v4l2_xxx or printk.
+ * However, there isn't a solid consensus on which
+ * new drivers should use.
+ *
+ */
+#define DEBUG
+#ifdef DEBUG
+#define stk1160_dbg(fmt, args...) \
+ printk(KERN_DEBUG "stk1160: " fmt, ## args)
+#else
+#define stk1160_dbg(fmt, args...)
+#endif
+
+#define stk1160_info(fmt, args...) \
+ pr_info("stk1160: " fmt, ## args)
+
+#define stk1160_warn(fmt, args...) \
+ pr_warn("stk1160: " fmt, ## args)
+
+#define stk1160_err(fmt, args...) \
+ pr_err("stk1160: " fmt, ## args)
+
+/* Buffer for one video frame */
+struct stk1160_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ struct list_head list;
+
+ void *mem;
+ unsigned int length; /* buffer length */
+ unsigned int bytesused; /* bytes written */
+ int odd; /* current oddity */
+
+ /*
+ * Since we interlace two fields per frame,
+ * this is different from bytesused.
+ */
+ unsigned int pos; /* current pos inside buffer */
+};
+
+struct stk1160_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* current buffer */
+ struct stk1160_buffer *buf;
+};
+
+struct stk1160_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+};
+
+struct stk1160 {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct device *dev;
+ struct usb_device *udev;
+
+ /* saa7115 subdev */
+ struct v4l2_subdev *sd_saa7115;
+
+ /* isoc control struct */
+ struct list_head avail_bufs;
+
+ /* video capture */
+ struct vb2_queue vb_vidq;
+
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+ /* array of wMaxPacketSize */
+ unsigned int *alt_max_pkt_size;
+ /* alternate */
+ int alt;
+ /* Number of alternative settings */
+ int num_alt;
+
+ struct stk1160_isoc_ctl isoc_ctl;
+ char urb_buf[255]; /* urb control msg buffer */
+
+ /* frame properties */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ unsigned int ctl_input; /* selected input */
+ v4l2_std_id norm; /* current norm */
+ struct stk1160_fmt *fmt; /* selected format */
+
+ unsigned int field_count; /* not sure ??? */
+ enum v4l2_field field; /* also not sure :/ */
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+
+ struct mutex v4l_lock;
+ struct mutex vb_queue_lock;
+ spinlock_t buf_lock;
+
+ struct file *fh_owner; /* filehandle ownership */
+
+ /* EXPERIMENTAL */
+ struct snd_card *snd_card;
+};
+
+struct regval {
+ u16 reg;
+ u16 val;
+};
+
+/* Provided by stk1160-v4l.c */
+int stk1160_vb2_setup(struct stk1160 *dev);
+int stk1160_video_register(struct stk1160 *dev);
+void stk1160_video_unregister(struct stk1160 *dev);
+void stk1160_clear_queue(struct stk1160 *dev);
+
+/* Provided by stk1160-video.c */
+int stk1160_alloc_isoc(struct stk1160 *dev);
+void stk1160_free_isoc(struct stk1160 *dev);
+void stk1160_cancel_isoc(struct stk1160 *dev);
+void stk1160_uninit_isoc(struct stk1160 *dev);
+
+/* Provided by stk1160-i2c.c */
+int stk1160_i2c_register(struct stk1160 *dev);
+int stk1160_i2c_unregister(struct stk1160 *dev);
+
+/* Provided by stk1160-core.c */
+int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value);
+int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value);
+int stk1160_write_regs_req(struct stk1160 *dev, u8 req, u16 reg,
+ char *buf, int len);
+int stk1160_read_reg_req_len(struct stk1160 *dev, u8 req, u16 reg,
+ char *buf, int len);
+void stk1160_select_input(struct stk1160 *dev);
+
+/* Provided by stk1160-ac97.c */
+#ifdef CONFIG_VIDEO_STK1160_AC97
+int stk1160_ac97_register(struct stk1160 *dev);
+int stk1160_ac97_unregister(struct stk1160 *dev);
+#else
+static inline int stk1160_ac97_register(struct stk1160 *dev) { return 0; }
+static inline int stk1160_ac97_unregister(struct stk1160 *dev) { return 0; }
+#endif
+
diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/media/usb/stkwebcam/Kconfig
new file mode 100644
index 000000000000..2fb0c2b687f4
--- /dev/null
+++ b/drivers/media/usb/stkwebcam/Kconfig
@@ -0,0 +1,13 @@
+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.
+
diff --git a/drivers/media/usb/stkwebcam/Makefile b/drivers/media/usb/stkwebcam/Makefile
new file mode 100644
index 000000000000..20ef8a4b990c
--- /dev/null
+++ b/drivers/media/usb/stkwebcam/Makefile
@@ -0,0 +1,4 @@
+stkwebcam-objs := stk-webcam.o stk-sensor.o
+
+obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
+
diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/usb/stkwebcam/stk-sensor.c
index e546b014d7ad..e546b014d7ad 100644
--- a/drivers/media/video/stk-sensor.c
+++ b/drivers/media/usb/stkwebcam/stk-sensor.c
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index 86a0fc56c330..86a0fc56c330 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h
index 9f6736637571..9f6736637571 100644
--- a/drivers/media/video/stk-webcam.h
+++ b/drivers/media/usb/stkwebcam/stk-webcam.h
diff --git a/drivers/media/video/tlg2300/Kconfig b/drivers/media/usb/tlg2300/Kconfig
index 645d915267e6..645d915267e6 100644
--- a/drivers/media/video/tlg2300/Kconfig
+++ b/drivers/media/usb/tlg2300/Kconfig
diff --git a/drivers/media/usb/tlg2300/Makefile b/drivers/media/usb/tlg2300/Makefile
new file mode 100644
index 000000000000..137f8e38cdec
--- /dev/null
+++ b/drivers/media/usb/tlg2300/Makefile
@@ -0,0 +1,9 @@
+poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
+
+obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
diff --git a/drivers/media/video/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
index 9f8b7da56b67..9f8b7da56b67 100644
--- a/drivers/media/video/tlg2300/pd-alsa.c
+++ b/drivers/media/usb/tlg2300/pd-alsa.c
diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h
index 5dd73b7857d1..5dd73b7857d1 100644
--- a/drivers/media/video/tlg2300/pd-common.h
+++ b/drivers/media/usb/tlg2300/pd-common.h
diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/usb/tlg2300/pd-dvb.c
index 30fcb117e898..30fcb117e898 100644
--- a/drivers/media/video/tlg2300/pd-dvb.c
+++ b/drivers/media/usb/tlg2300/pd-dvb.c
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c
index 7b1f6ebd0e2c..7b1f6ebd0e2c 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/usb/tlg2300/pd-main.c
diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c
index 4fad1dfb92cf..4fad1dfb92cf 100644
--- a/drivers/media/video/tlg2300/pd-radio.c
+++ b/drivers/media/usb/tlg2300/pd-radio.c
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c
index bfbf9e56b0a4..bfbf9e56b0a4 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/usb/tlg2300/pd-video.c
diff --git a/drivers/media/video/tlg2300/vendorcmds.h b/drivers/media/usb/tlg2300/vendorcmds.h
index ba6f4ae3b2c2..ba6f4ae3b2c2 100644
--- a/drivers/media/video/tlg2300/vendorcmds.h
+++ b/drivers/media/usb/tlg2300/vendorcmds.h
diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/usb/tm6000/Kconfig
index a43b77abd931..a43b77abd931 100644
--- a/drivers/media/video/tm6000/Kconfig
+++ b/drivers/media/usb/tm6000/Kconfig
diff --git a/drivers/media/usb/tm6000/Makefile b/drivers/media/usb/tm6000/Makefile
new file mode 100644
index 000000000000..f2644933b8d1
--- /dev/null
+++ b/drivers/media/usb/tm6000/Makefile
@@ -0,0 +1,15 @@
+tm6000-y := tm6000-cards.o \
+ tm6000-core.o \
+ tm6000-i2c.o \
+ tm6000-video.o \
+ tm6000-stds.o \
+ tm6000-input.o
+
+obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
+obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
new file mode 100644
index 000000000000..813c1ec53608
--- /dev/null
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -0,0 +1,529 @@
+/*
+ *
+ * Support for audio capture for tm5600/6000/6010
+ * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on cx88-alsa.c
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#undef dprintk
+
+#define dprintk(level, fmt, arg...) do { \
+ if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
+ } while (0)
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+
+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.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
+
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
+ "{{Trident,tm6000},"
+ "{{Trident,tm6010}");
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+ Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+
+ dprintk(1, "Starting audio DMA\n");
+
+ /* Enables audio */
+ tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
+
+ tm6000_set_audio_bitrate(core, 48000);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* Disables audio */
+ tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
+
+ return 0;
+}
+
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ dprintk(2, "Freeing buffer\n");
+
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ substream->runtime->dma_bytes = 0;
+}
+
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ dprintk(2, "Allocating buffer\n");
+
+ if (substream->runtime->dma_area) {
+ if (substream->runtime->dma_bytes > size)
+ return 0;
+
+ dsp_buffer_free(substream);
+ }
+
+ substream->runtime->dma_area = vmalloc(size);
+ if (!substream->runtime->dma_area)
+ return -ENOMEM;
+
+ substream->runtime->dma_bytes = size;
+
+ return 0;
+}
+
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE 4096
+
+static struct snd_pcm_hardware snd_tm6000_digital_hw = {
+ .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 | 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 = 2,
+ .periods_max = 98,
+ .buffer_bytes_max = 62720 * 8,
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ err = snd_pcm_hw_constraint_pow2(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+
+ runtime->hw = snd_tm6000_digital_hw;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ return 0;
+_error:
+ dprintk(1, "Error opening PCM!\n");
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_tm6000_close(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
+
+ return 0;
+}
+
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+ struct snd_tm6000_card *chip = core->adev;
+ struct snd_pcm_substream *substream = chip->substream;
+ struct snd_pcm_runtime *runtime;
+ int period_elapsed = 0;
+ unsigned int stride, buf_pos;
+ int length;
+
+ if (atomic_read(&core->stream_started) == 0)
+ return 0;
+
+ if (!size || !substream) {
+ dprintk(1, "substream was NULL\n");
+ return -EINVAL;
+ }
+
+ runtime = substream->runtime;
+ if (!runtime || !runtime->dma_area) {
+ dprintk(1, "runtime was NULL\n");
+ return -EINVAL;
+ }
+
+ buf_pos = chip->buf_pos;
+ stride = runtime->frame_bits >> 3;
+
+ if (stride == 0) {
+ dprintk(1, "stride is zero\n");
+ return -EINVAL;
+ }
+
+ length = size / stride;
+ if (length == 0) {
+ dprintk(1, "%s: length was zero\n", __func__);
+ return -EINVAL;
+ }
+
+ dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+ runtime->dma_area, buf_pos,
+ (unsigned int)runtime->buffer_size, stride);
+
+ if (buf_pos + length >= runtime->buffer_size) {
+ unsigned int cnt = runtime->buffer_size - buf_pos;
+ memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
+ memcpy(runtime->dma_area, buf + cnt * stride,
+ length * stride - cnt * stride);
+ } else
+ memcpy(runtime->dma_area + buf_pos * stride, buf,
+ length * stride);
+
+ snd_pcm_stream_lock(substream);
+
+ chip->buf_pos += length;
+ if (chip->buf_pos >= runtime->buffer_size)
+ chip->buf_pos -= runtime->buffer_size;
+
+ chip->period_pos += length;
+ if (chip->period_pos >= runtime->period_size) {
+ chip->period_pos -= runtime->period_size;
+ period_elapsed = 1;
+ }
+
+ snd_pcm_stream_unlock(substream);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int size, rc;
+
+ size = params_period_bytes(hw_params) * params_periods(hw_params);
+
+ rc = dsp_buffer_alloc(substream, size);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
+
+ dsp_buffer_free(substream);
+ return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ chip->buf_pos = 0;
+ chip->period_pos = 0;
+
+ return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static void audio_trigger(struct work_struct *work)
+{
+ struct tm6000_core *core = container_of(work, struct tm6000_core,
+ wq_trigger);
+ struct snd_tm6000_card *chip = core->adev;
+
+ if (atomic_read(&core->stream_started)) {
+ dprintk(1, "starting capture");
+ _tm6000_start_audio_dma(chip);
+ } else {
+ dprintk(1, "stopping capture");
+ _tm6000_stop_audio_dma(chip);
+ }
+}
+
+static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+ 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;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ schedule_work(&core->wq_trigger);
+
+ return err;
+}
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(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
+ */
+static struct snd_pcm_ops snd_tm6000_pcm_ops = {
+ .open = snd_tm6000_pcm_open,
+ .close = snd_tm6000_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_tm6000_hw_params,
+ .hw_free = snd_tm6000_hw_free,
+ .prepare = snd_tm6000_prepare,
+ .trigger = snd_tm6000_card_trigger,
+ .pointer = snd_tm6000_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+/*
+ * create a PCM device
+ */
+
+/* FIXME: Control interface - How to control volume/mute? */
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+static int tm6000_audio_init(struct tm6000_core *dev)
+{
+ struct snd_card *card;
+ struct snd_tm6000_card *chip;
+ int rc;
+ static int devnr;
+ char component[14];
+ struct snd_pcm *pcm;
+
+ if (!dev)
+ return 0;
+
+ if (devnr >= SNDRV_CARDS)
+ return -ENODEV;
+
+ if (!enable[devnr])
+ return -ENOENT;
+
+ rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+ if (rc < 0) {
+ snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
+ return rc;
+ }
+ strcpy(card->driver, "tm6000-alsa");
+ strcpy(card->shortname, "TM5600/60x0");
+ sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+ dev->udev->bus->busnum, dev->udev->devnum);
+
+ sprintf(component, "USB%04x:%04x",
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct));
+ snd_component_add(card, component);
+ snd_card_set_dev(card, &dev->udev->dev);
+
+ chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
+ if (!chip) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ chip->core = dev;
+ chip->card = card;
+ dev->adev = chip;
+ spin_lock_init(&chip->reg_lock);
+
+ rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
+ if (rc < 0)
+ goto error_chip;
+
+ pcm->info_flags = 0;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Trident TM5600/60x0");
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
+ rc = snd_card_register(card);
+ if (rc < 0)
+ goto error_chip;
+
+ dprintk(1, "Registered audio driver for %s\n", card->longname);
+
+ return 0;
+
+error_chip:
+ kfree(chip);
+ dev->adev = NULL;
+error:
+ snd_card_free(card);
+ return rc;
+}
+
+static int tm6000_audio_fini(struct tm6000_core *dev)
+{
+ struct snd_tm6000_card *chip;
+
+ if (!dev)
+ return 0;
+ chip = dev->adev;
+
+ if (!chip)
+ return 0;
+
+ if (!chip->card)
+ return 0;
+
+ snd_card_free(chip->card);
+ chip->card = NULL;
+ kfree(chip);
+ dev->adev = NULL;
+
+ return 0;
+}
+
+static struct tm6000_ops audio_ops = {
+ .type = TM6000_AUDIO,
+ .name = "TM6000 Audio Extension",
+ .init = tm6000_audio_init,
+ .fini = tm6000_audio_fini,
+ .fillbuf = tm6000_fillbuf,
+};
+
+static int __init tm6000_alsa_register(void)
+{
+ return tm6000_register_extension(&audio_ops);
+}
+
+static void __exit tm6000_alsa_unregister(void)
+{
+ tm6000_unregister_extension(&audio_ops);
+}
+
+module_init(tm6000_alsa_register);
+module_exit(tm6000_alsa_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 034659b13174..034659b13174 100644
--- a/drivers/media/video/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/usb/tm6000/tm6000-core.c
index 22cc0116deb6..22cc0116deb6 100644
--- a/drivers/media/video/tm6000/tm6000-core.c
+++ b/drivers/media/usb/tm6000/tm6000-core.c
diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c
index e1f3f66e1e63..e1f3f66e1e63 100644
--- a/drivers/media/video/tm6000/tm6000-dvb.c
+++ b/drivers/media/usb/tm6000/tm6000-dvb.c
diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/usb/tm6000/tm6000-i2c.c
index c7e23e3dd75e..c7e23e3dd75e 100644
--- a/drivers/media/video/tm6000/tm6000-i2c.c
+++ b/drivers/media/usb/tm6000/tm6000-i2c.c
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
new file mode 100644
index 000000000000..dffbd4bd47b1
--- /dev/null
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -0,0 +1,499 @@
+/*
+ * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2
+ *
+ * This program is distributed 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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <media/rc-core.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+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)");
+
+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(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;
+};
+
+struct tm6000_IR {
+ struct tm6000_core *dev;
+ struct rc_dev *rc;
+ char name[32];
+ char phys[32];
+
+ /* poll expernal decoder */
+ int polling;
+ struct delayed_work work;
+ u8 wait:1;
+ u8 pwled:2;
+ u8 submit_urb:1;
+ u16 key_addr;
+ struct urb *int_urb;
+
+ /* IR device properties */
+ u64 rc_type;
+};
+
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ 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;
+ 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:
+ leader = 900; /* ms */
+ pulse = 700; /* ms - the actual value would be 562 */
+ break;
+ default:
+ 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;
+}
+
+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;
+
+ 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;
+
+ if (ir_debug)
+ print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
+ DUMP_PREFIX_OFFSET,16, 1,
+ buf, urb->actual_length, false);
+
+ 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);
+
+ 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 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)
+ return;
+
+ dprintk(3, "%s\n",__func__);
+
+ 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;
+
+ if (rc > 1)
+ poll_result.rc_data = buf[0] | buf[1] << 8;
+ else
+ poll_result.rc_data = buf[0];
+
+ /* Check if something was read */
+ if ((poll_result.rc_data & 0xff) == 0xff) {
+ if (!ir->pwled) {
+ tm6000_flash_led(dev, 1);
+ ir->pwled = 1;
+ }
+ return;
+ }
+
+ 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_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 rc;
+
+ dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb,
+ ir->pwled);
+
+ if (ir->submit_urb) {
+ dprintk(3, "Resubmit urb\n");
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+
+ 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;
+ }
+
+ /* 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;
+ }
+}
+
+static int tm6000_ir_start(struct rc_dev *rc)
+{
+ struct tm6000_IR *ir = rc->priv;
+
+ dprintk(2, "%s\n",__func__);
+
+ schedule_delayed_work(&ir->work, 0);
+
+ return 0;
+}
+
+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);
+}
+
+static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
+{
+ struct tm6000_IR *ir = rc->priv;
+
+ 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->rc_type = rc_type;
+
+ tm6000_ir_config(ir);
+ /* TODO */
+ return 0;
+}
+
+static int __tm6000_ir_int_start(struct rc_dev *rc)
+{
+ struct tm6000_IR *ir = rc->priv;
+ struct tm6000_core *dev;
+ int pipe, size;
+ int err = -ENOMEM;
+
+ if (!ir)
+ return -ENODEV;
+ dev = ir->dev;
+
+ dprintk(2, "%s\n",__func__);
+
+ ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!ir->int_urb)
+ return -ENOMEM;
+
+ pipe = usb_rcvintpipe(dev->udev,
+ dev->int_in.endp->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+
+ size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+ dprintk(1, "IR max size: %d\n", size);
+
+ 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(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);
+
+ ir->submit_urb = 1;
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
+
+ return 0;
+}
+
+static void __tm6000_ir_int_stop(struct rc_dev *rc)
+{
+ struct tm6000_IR *ir = rc->priv;
+
+ 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;
+}
+
+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)
+{
+ struct tm6000_IR *ir;
+ struct rc_dev *rc;
+ int err = -ENOMEM;
+
+ if (!enable_ir)
+ return -ENODEV;
+
+ if (!dev->caps.has_remote)
+ return 0;
+
+ if (!dev->ir_codes)
+ return 0;
+
+ 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 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;
+ 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;
+
+ snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+ dev->name);
+
+ usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+ tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
+
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_USB;
+ rc->input_id.version = 1;
+ rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ rc->map_name = dev->ir_codes;
+ rc->driver_name = "tm6000";
+ rc->dev.parent = &dev->udev->dev;
+
+ /* ir register */
+ err = rc_register_device(rc);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ dev->ir = NULL;
+ rc_free_device(rc);
+ kfree(ir);
+ return err;
+}
+
+int tm6000_ir_fini(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ /* skip detach on non attached board */
+
+ if (!ir)
+ return 0;
+
+ dprintk(2, "%s\n",__func__);
+
+ if (!ir->polling)
+ __tm6000_ir_int_stop(ir->rc);
+
+ tm6000_ir_stop(ir->rc);
+
+ /* Turn off the led */
+ tm6000_flash_led(dev, 0);
+ ir->pwled = 0;
+
+ rc_unregister_device(ir->rc);
+
+ kfree(ir);
+ dev->ir = NULL;
+
+ return 0;
+}
diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/usb/tm6000/tm6000-regs.h
index a38c251ed57b..a38c251ed57b 100644
--- a/drivers/media/video/tm6000/tm6000-regs.h
+++ b/drivers/media/usb/tm6000/tm6000-regs.h
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c
index 5e28d6a2412f..5e28d6a2412f 100644
--- a/drivers/media/video/tm6000/tm6000-stds.c
+++ b/drivers/media/usb/tm6000/tm6000-stds.c
diff --git a/drivers/media/video/tm6000/tm6000-usb-isoc.h b/drivers/media/usb/tm6000/tm6000-usb-isoc.h
index 99d15a55aa03..99d15a55aa03 100644
--- a/drivers/media/video/tm6000/tm6000-usb-isoc.h
+++ b/drivers/media/usb/tm6000/tm6000-usb-isoc.h
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
new file mode 100644
index 000000000000..45ed59cb2d04
--- /dev/null
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -0,0 +1,1852 @@
+/*
+ * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ * - Fixed module load/unload
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2
+ *
+ * This program is distributed 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/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include <media/tuner.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+
+#include "tm6000-regs.h"
+#include "tm6000.h"
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
+
+/* Limits minimum and default number of buffers */
+#define TM6000_MIN_BUF 4
+#define TM6000_DEF_BUF 8
+
+#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
+
+/* Debug level */
+int tm6000_debug;
+EXPORT_SYMBOL_GPL(tm6000_debug);
+
+static const struct v4l2_queryctrl no_ctrl = {
+ .name = "42",
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+/* supported controls */
+static struct v4l2_queryctrl tm6000_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 54,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 119,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 112,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ /* --- audio --- */
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = -15,
+ .maximum = 15,
+ .step = 1,
+ .default_value = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
+static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
+static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
+
+static struct tm6000_fmt format[] = {
+ {
+ .name = "4:2:2, packed, YVY2",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ }, {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ }, {
+ .name = "A/V + VBI mux packet",
+ .fourcc = V4L2_PIX_FMT_TM6000,
+ .depth = 16,
+ }
+};
+
+static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
+{
+ unsigned int i;
+
+ for (i = 0; i < CTRLS; i++)
+ if (tm6000_qctrl[i].id == id)
+ return tm6000_qctrl+i;
+ return NULL;
+}
+
+/* ------------------------------------------------------------------
+ * DMA and thread functions
+ * ------------------------------------------------------------------
+ */
+
+#define norm_maxw(a) 720
+#define norm_maxh(a) 576
+
+#define norm_minw(a) norm_maxw(a)
+#define norm_minh(a) norm_maxh(a)
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
+ struct tm6000_buffer **buf)
+{
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+
+ if (list_empty(&dma_q->active)) {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
+ *buf = NULL;
+ return;
+ }
+
+ *buf = list_entry(dma_q->active.next,
+ struct tm6000_buffer, vb.queue);
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct tm6000_core *dev,
+ struct tm6000_dmaqueue *dma_q,
+ struct tm6000_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_streams(u8 *data, unsigned long len,
+ struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ u8 *ptr = data, *endp = data+len;
+ unsigned long header = 0;
+ int rc = 0;
+ unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+ struct tm6000_buffer *vbuf = NULL;
+ char *voutp = NULL;
+ unsigned int linewidth;
+
+ if (!dev->radio) {
+ /* get video buffer */
+ get_next_buf(dma_q, &vbuf);
+
+ if (!vbuf)
+ return rc;
+ voutp = videobuf_to_vmalloc(&vbuf->vb);
+
+ if (!voutp)
+ return 0;
+ }
+
+ for (ptr = data; ptr < endp;) {
+ if (!dev->isoc_ctl.cmd) {
+ /* Header */
+ if (dev->isoc_ctl.tmp_buf_len > 0) {
+ /* from last urb or packet */
+ header = dev->isoc_ctl.tmp_buf;
+ if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
+ memcpy((u8 *)&header +
+ dev->isoc_ctl.tmp_buf_len,
+ ptr,
+ 4 - dev->isoc_ctl.tmp_buf_len);
+ ptr += 4 - dev->isoc_ctl.tmp_buf_len;
+ }
+ dev->isoc_ctl.tmp_buf_len = 0;
+ } else {
+ if (ptr + 3 >= endp) {
+ /* have incomplete header */
+ dev->isoc_ctl.tmp_buf_len = endp - ptr;
+ memcpy(&dev->isoc_ctl.tmp_buf, ptr,
+ dev->isoc_ctl.tmp_buf_len);
+ return rc;
+ }
+ /* Seek for sync */
+ for (; ptr < endp - 3; ptr++) {
+ if (*(ptr + 3) == 0x47)
+ break;
+ }
+ /* Get message header */
+ header = *(unsigned long *)ptr;
+ ptr += 4;
+ }
+
+ /* split the header fields */
+ size = ((header & 0x7e) << 1);
+ if (size > 0)
+ size -= 4;
+ block = (header >> 7) & 0xf;
+ field = (header >> 11) & 0x1;
+ line = (header >> 12) & 0x1ff;
+ cmd = (header >> 21) & 0x7;
+ /* Validates haeder fields */
+ if (size > TM6000_URB_MSG_LEN)
+ size = TM6000_URB_MSG_LEN;
+ pktsize = TM6000_URB_MSG_LEN;
+ /*
+ * calculate position in buffer and change the buffer
+ */
+ switch (cmd) {
+ case TM6000_URB_MSG_VIDEO:
+ if (!dev->radio) {
+ if ((dev->isoc_ctl.vfield != field) &&
+ (field == 1)) {
+ /*
+ * Announces that a new buffer
+ * were filled
+ */
+ buffer_filled(dev, dma_q, vbuf);
+ dprintk(dev, V4L2_DEBUG_ISOC,
+ "new buffer filled\n");
+ get_next_buf(dma_q, &vbuf);
+ if (!vbuf)
+ return rc;
+ voutp = videobuf_to_vmalloc(&vbuf->vb);
+ if (!voutp)
+ return rc;
+ memset(voutp, 0, vbuf->vb.size);
+ }
+ linewidth = vbuf->vb.width << 1;
+ pos = ((line << 1) - field - 1) *
+ linewidth + block * TM6000_URB_MSG_LEN;
+ /* Don't allow to write out of the buffer */
+ if (pos + size > vbuf->vb.size)
+ cmd = TM6000_URB_MSG_ERR;
+ dev->isoc_ctl.vfield = field;
+ }
+ break;
+ case TM6000_URB_MSG_VBI:
+ break;
+ case TM6000_URB_MSG_AUDIO:
+ case TM6000_URB_MSG_PTS:
+ size = pktsize; /* Size is always 180 bytes */
+ break;
+ }
+ } else {
+ /* Continue the last copy */
+ cmd = dev->isoc_ctl.cmd;
+ size = dev->isoc_ctl.size;
+ pos = dev->isoc_ctl.pos;
+ pktsize = dev->isoc_ctl.pktsize;
+ field = dev->isoc_ctl.field;
+ }
+ cpysize = (endp - ptr > size) ? size : endp - ptr;
+ if (cpysize) {
+ /* copy data in different buffers */
+ switch (cmd) {
+ case TM6000_URB_MSG_VIDEO:
+ /* Fills video buffer */
+ if (vbuf)
+ memcpy(&voutp[pos], ptr, cpysize);
+ break;
+ case TM6000_URB_MSG_AUDIO: {
+ int i;
+ for (i = 0; i < cpysize; i += 2)
+ swab16s((u16 *)(ptr + i));
+
+ tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
+ break;
+ }
+ case TM6000_URB_MSG_VBI:
+ /* Need some code to copy vbi buffer */
+ break;
+ case TM6000_URB_MSG_PTS: {
+ /* Need some code to copy pts */
+ u32 pts;
+ pts = *(u32 *)ptr;
+ dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
+ field, pts);
+ break;
+ }
+ }
+ }
+ if (ptr + pktsize > endp) {
+ /*
+ * End of URB packet, but cmd processing is not
+ * complete. Preserve the state for a next packet
+ */
+ dev->isoc_ctl.pos = pos + cpysize;
+ dev->isoc_ctl.size = size - cpysize;
+ dev->isoc_ctl.cmd = cmd;
+ dev->isoc_ctl.field = field;
+ dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
+ ptr += endp - ptr;
+ } else {
+ dev->isoc_ctl.cmd = 0;
+ ptr += pktsize;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_multiplexed(u8 *ptr, unsigned long len,
+ struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ unsigned int pos = dev->isoc_ctl.pos, cpysize;
+ int rc = 1;
+ struct tm6000_buffer *buf;
+ char *outp = NULL;
+
+ get_next_buf(dma_q, &buf);
+ if (buf)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ if (!outp)
+ return 0;
+
+ while (len > 0) {
+ cpysize = min(len, buf->vb.size-pos);
+ memcpy(&outp[pos], ptr, cpysize);
+ pos += cpysize;
+ ptr += cpysize;
+ len -= cpysize;
+ if (pos >= buf->vb.size) {
+ pos = 0;
+ /* Announces that a new buffer were filled */
+ buffer_filled(dev, dma_q, buf);
+ dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
+ get_next_buf(dma_q, &buf);
+ if (!buf)
+ break;
+ outp = videobuf_to_vmalloc(&(buf->vb));
+ if (!outp)
+ return rc;
+ pos = 0;
+ }
+ }
+
+ dev->isoc_ctl.pos = pos;
+ return rc;
+}
+
+static inline void print_err_status(struct tm6000_core *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
+ status, errmsg);
+ } else {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int tm6000_isoc_copy(struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ int i, len = 0, rc = 1, status;
+ char *p;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length;
+
+ if (len > 0) {
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (!urb->iso_frame_desc[i].status) {
+ if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
+ rc = copy_multiplexed(p, len, urb);
+ if (rc <= 0)
+ return rc;
+ } else {
+ copy_streams(p, len, urb);
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ * URB control
+ * ------------------------------------------------------------------
+ */
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void tm6000_irq_callback(struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ int i;
+
+ switch (urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ tm6000_err("urb completion error %d.\n", urb->status);
+ break;
+ }
+
+ spin_lock(&dev->slock);
+ tm6000_isoc_copy(urb);
+ spin_unlock(&dev->slock);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status)
+ tm6000_err("urb resubmit failed (error=%i)\n",
+ urb->status);
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+static void tm6000_uninit_isoc(struct tm6000_core *dev)
+{
+ struct urb *urb;
+ int i;
+
+ dev->isoc_ctl.buf = NULL;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ usb_kill_urb(urb);
+ usb_unlink_urb(urb);
+ if (dev->isoc_ctl.transfer_buffer[i]) {
+ usb_free_coherent(dev->udev,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
+ }
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+static int tm6000_prepare_isoc(struct tm6000_core *dev)
+{
+ struct tm6000_dmaqueue *dma_q = &dev->vidq;
+ int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
+ struct urb *urb;
+
+ /* De-allocates all pending stuff */
+ tm6000_uninit_isoc(dev);
+ /* Stop interrupt USB pipe */
+ tm6000_ir_int_stop(dev);
+
+ usb_set_interface(dev->udev,
+ dev->isoc_in.bInterfaceNumber,
+ dev->isoc_in.bAlternateSetting);
+
+ /* Start interrupt USB pipe */
+ tm6000_ir_int_start(dev);
+
+ pipe = usb_rcvisocpipe(dev->udev,
+ dev->isoc_in.endp->desc.bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+
+ size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+
+ if (size > dev->isoc_in.maxsize)
+ size = dev->isoc_in.maxsize;
+
+ dev->isoc_ctl.max_pkt_size = size;
+
+ max_packets = TM6000_MAX_ISO_PACKETS;
+ sb_size = max_packets * size;
+
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ tm6000_err("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.transfer_buffer) {
+ tm6000_err("cannot allocate memory for usbtransfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
+ " (%d bytes) of %d bytes each to handle %u size\n",
+ max_packets, num_bufs, sb_size,
+ dev->isoc_in.maxsize, size);
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
+ tm6000_uninit_isoc(dev);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ tm6000_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ tm6000_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ usb_fill_bulk_urb(urb, dev->udev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ tm6000_irq_callback, dma_q);
+ urb->interval = dev->isoc_in.endp->desc.bInterval;
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = size * j;
+ urb->iso_frame_desc[j].length = size;
+ }
+ }
+
+ return 0;
+}
+
+static int tm6000_start_thread(struct tm6000_core *dev)
+{
+ struct tm6000_dmaqueue *dma_q = &dev->vidq;
+ int i;
+
+ dma_q->frame = 0;
+ dma_q->ini_jiffies = jiffies;
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ tm6000_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ tm6000_uninit_isoc(dev);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ * Videobuf operations
+ * ------------------------------------------------------------------
+ */
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+
+ *size = fh->fmt->depth * fh->width * fh->height >> 3;
+ if (0 == *count)
+ *count = TM6000_DEF_BUF;
+
+ if (*count < TM6000_MIN_BUF)
+ *count = TM6000_MIN_BUF;
+
+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_core *dev = fh->dev;
+ unsigned long flags;
+
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
+ struct tm6000_core *dev = fh->dev;
+ int rc = 0;
+
+ BUG_ON(NULL == fh->fmt);
+
+
+ /* FIXME: It assumes depth=2 */
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ if (buf->fmt != fh->fmt ||
+ buf->vb.width != fh->width ||
+ buf->vb.height != fh->height ||
+ buf->vb.field != field) {
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+ }
+
+ if (!dev->isoc_ctl.num_bufs) {
+ rc = tm6000_prepare_isoc(dev);
+ if (rc < 0)
+ goto fail;
+
+ rc = tm6000_start_thread(dev);
+ if (rc < 0)
+ goto fail;
+
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_core *dev = fh->dev;
+ struct tm6000_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops tm6000_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ * IOCTL handling
+ * ------------------------------------------------------------------
+ */
+
+static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh && dev->is_res_read)
+ return true;
+
+ return false;
+}
+
+static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh)
+ return true;
+
+ return false;
+}
+
+static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
+ bool is_res_read)
+{
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources == fh && dev->is_res_read == is_res_read)
+ return true;
+
+ /* is it free? */
+ if (dev->resources)
+ return false;
+
+ /* grab it */
+ dev->resources = fh;
+ dev->is_res_read = is_res_read;
+ dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+ return true;
+}
+
+static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ /* Is the current fh handling it? if so, that's OK */
+ if (dev->resources != fh)
+ return;
+
+ dev->resources = NULL;
+ dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
+}
+
+/* ------------------------------------------------------------------
+ * IOCTL vidioc handling
+ * ------------------------------------------------------------------
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+
+ strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
+ strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE;
+
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
+ return -EINVAL;
+
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
+}
+
+static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return format+i;
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+ struct tm6000_fmt *fmt;
+ enum v4l2_field field;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt) {
+ dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
+ " invalid.\n", f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_SEQ_TB;
+ else if (V4L2_FIELD_INTERLACED != field) {
+ dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ tm6000_get_std_res(dev);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+
+ f->fmt.pix.width &= ~0x01;
+
+ f->fmt.pix.field = field;
+
+ 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;
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+ int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+ if (ret < 0)
+ return ret;
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+
+ dev->fourcc = f->fmt.pix.pixelformat;
+
+ tm6000_set_fourcc_format(dev);
+
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct tm6000_fh *fh = priv;
+
+ return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh = priv;
+
+ return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh = priv;
+
+ return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
+
+ if (!res_get(dev, fh, false))
+ return -EBUSY;
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (i != fh->type)
+ return -EINVAL;
+
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev, fh);
+
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ int rc = 0;
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ dev->norm = *norm;
+ rc = tm6000_init_analog_mode(dev);
+
+ fh->width = dev->width;
+ fh->height = dev->height;
+
+ if (rc < 0)
+ return rc;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+ return 0;
+}
+
+static const char *iname[] = {
+ [TM6000_INPUT_TV] = "Television",
+ [TM6000_INPUT_COMPOSITE1] = "Composite 1",
+ [TM6000_INPUT_COMPOSITE2] = "Composite 2",
+ [TM6000_INPUT_SVIDEO] = "S-Video",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= 3)
+ return -EINVAL;
+
+ if (!dev->vinput[n].type)
+ return -EINVAL;
+
+ i->index = n;
+
+ if (dev->vinput[n].type == TM6000_INPUT_TV)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strcpy(i->name, iname[dev->vinput[n].type]);
+
+ i->std = TM6000_STD;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ *i = dev->input;
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+ int rc = 0;
+
+ if (i >= 3)
+ return -EINVAL;
+ if (!dev->vinput[i].type)
+ return -EINVAL;
+
+ dev->input = i;
+
+ rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
+
+ return rc;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+ if (qc->id && qc->id == tm6000_qctrl[i].id) {
+ memcpy(qc, &(tm6000_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+ int val;
+
+ /* FIXME: Probably, those won't work! Maybe we need shadow regs */
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
+ return 0;
+ case V4L2_CID_SATURATION:
+ val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
+ return 0;
+ case V4L2_CID_HUE:
+ val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
+ return 0;
+ case V4L2_CID_AUDIO_MUTE:
+ val = dev->ctl_mute;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ val = dev->ctl_volume;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ if (val < 0)
+ return val;
+
+ ctrl->value = val;
+
+ return 0;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+ u8 val = ctrl->value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+ return 0;
+ case V4L2_CID_BRIGHTNESS:
+ tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
+ return 0;
+ case V4L2_CID_SATURATION:
+ tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
+ return 0;
+ case V4L2_CID_HUE:
+ tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
+ return 0;
+ case V4L2_CID_AUDIO_MUTE:
+ dev->ctl_mute = val;
+ tm6000_tvaudio_set_mute(dev, val);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->ctl_volume = val;
+ tm6000_set_volume(dev, val);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+ t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+ t->audmode = dev->amode;
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ dev->amode = t->audmode;
+ dprintk(dev, 3, "audio mode: %x\n", t->audmode);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+ if (unlikely(f->tuner != 0))
+ return -EINVAL;
+ if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+ return -EINVAL;
+ if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+ return -EINVAL;
+
+ dev->freq = f->frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+
+ return 0;
+}
+
+static int radio_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+
+ strcpy(cap->driver, "tm6000");
+ strlcpy(cap->card, dev->name, sizeof(dev->name));
+ sprintf(cap->bus_info, "USB%04x:%04x",
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct));
+ cap->version = dev->dev_type;
+ cap->capabilities = V4L2_CAP_TUNER |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+ t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+ return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+ return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (i->index != 0)
+ return -EINVAL;
+
+ if (!dev->rinput.type)
+ return -EINVAL;
+
+ strcpy(i->name, "Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
+
+ return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (dev->input != 5)
+ return -EINVAL;
+
+ *i = dev->input - 5;
+
+ return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ memset(a, 0, sizeof(*a));
+ strcpy(a->name, "Radio");
+ return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ struct tm6000_fh *fh = priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (i)
+ return -EINVAL;
+
+ if (!dev->rinput.type)
+ return -EINVAL;
+
+ dev->input = i + 5;
+
+ return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ const struct v4l2_queryctrl *ctrl;
+
+ if (c->id < V4L2_CID_BASE ||
+ c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ ctrl = ctrl_by_id(c->id);
+ *c = *ctrl;
+ } else
+ *c = no_ctrl;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ File operations for the device
+ ------------------------------------------------------------------*/
+
+static int __tm6000_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct tm6000_core *dev = video_drvdata(file);
+ struct tm6000_fh *fh;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int i, rc;
+ int radio = 0;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
+ video_device_node_name(vdev));
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
+ type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+ case VFL_TYPE_RADIO:
+ radio = 1;
+ break;
+ }
+
+ /* If more than one user, mutex should be added */
+ dev->users++;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
+ video_device_node_name(vdev), v4l2_type_names[type],
+ dev->users);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh) {
+ dev->users--;
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+ fh->radio = radio;
+ dev->radio = radio;
+ fh->type = type;
+ dev->fourcc = format[0].fourcc;
+
+ fh->fmt = format_by_fourcc(dev->fourcc);
+
+ tm6000_get_std_res(dev);
+
+ fh->width = dev->width;
+ fh->height = dev->height;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
+ "dev->vidq=0x%08lx\n",
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&dev->vidq);
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+ "queued=%d\n", list_empty(&dev->vidq.queued));
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+ "active=%d\n", list_empty(&dev->vidq.active));
+
+ /* initialize hardware on analog mode */
+ rc = tm6000_init_analog_mode(dev);
+ if (rc < 0)
+ return rc;
+
+ if (dev->mode != TM6000_MODE_ANALOG) {
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+ qctl_regs[i] = tm6000_qctrl[i].default_value;
+
+ dev->mode = TM6000_MODE_ANALOG;
+ }
+
+ if (!fh->radio) {
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
+ NULL, &dev->slock,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct tm6000_buffer), fh, &dev->lock);
+ } else {
+ dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
+ dev->input = 5;
+ tm6000_set_audio_rinput(dev);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+ tm6000_prepare_isoc(dev);
+ tm6000_start_thread(dev);
+ }
+
+ return 0;
+}
+
+static int tm6000_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ int res;
+
+ mutex_lock(vdev->lock);
+ res = __tm6000_open(file);
+ mutex_unlock(vdev->lock);
+ return res;
+}
+
+static ssize_t
+tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ int res;
+
+ if (!res_get(fh->dev, fh, true))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ res = videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
+ file->f_flags & O_NONBLOCK);
+ mutex_unlock(&dev->lock);
+ return res;
+ }
+ return 0;
+}
+
+static unsigned int
+__tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_buffer *buf;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ if (!!is_res_streaming(fh->dev, fh))
+ return POLLERR;
+
+ if (!is_res_read(fh->dev, fh)) {
+ /* streaming capture */
+ if (list_empty(&fh->vb_vidq.stream))
+ return POLLERR;
+ buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
+ } else {
+ /* read() capture */
+ return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+ }
+ poll_wait(file, &buf->vb.done, wait);
+ if (buf->vb.state == VIDEOBUF_DONE ||
+ buf->vb.state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static unsigned int tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+ unsigned int res;
+
+ mutex_lock(&dev->lock);
+ res = __tm6000_poll(file, wait);
+ mutex_unlock(&dev->lock);
+ return res;
+}
+
+static int tm6000_release(struct file *file)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+ struct video_device *vdev = video_devdata(file);
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
+ video_device_node_name(vdev), dev->users);
+
+ mutex_lock(&dev->lock);
+ dev->users--;
+
+ res_free(dev, fh);
+
+ if (!dev->users) {
+ 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);
+ }
+
+ kfree(fh);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+ int res;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ res = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ mutex_unlock(&dev->lock);
+ return res;
+}
+
+static struct v4l2_file_operations tm6000_fops = {
+ .owner = THIS_MODULE,
+ .open = tm6000_open,
+ .release = tm6000_release,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .read = tm6000_read,
+ .poll = tm6000_poll,
+ .mmap = tm6000_mmap,
+};
+
+static const struct v4l2_ioctl_ops video_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_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .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_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+};
+
+static struct video_device tm6000_template = {
+ .name = "tm6000",
+ .fops = &tm6000_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .release = video_device_release,
+ .tvnorms = TM6000_STD,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = tm6000_open,
+ .release = tm6000_release,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_s_std = radio_s_std,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_input = radio_g_input,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+};
+
+static struct video_device tm6000_radio_template = {
+ .name = "tm6000",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+};
+
+/* -----------------------------------------------------------------
+ * Initialization and module stuff
+ * ------------------------------------------------------------------
+ */
+
+static struct video_device *vdev_init(struct tm6000_core *dev,
+ const struct video_device
+ *template, const char *type_name)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = tm6000_debug;
+ vfd->lock = &dev->lock;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+ video_set_drvdata(vfd, dev);
+ return vfd;
+}
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+ int ret = -1;
+
+ dev->vfd = vdev_init(dev, &tm6000_template, "video");
+
+ if (!dev->vfd) {
+ printk(KERN_INFO "%s: can't register video device\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
+ ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
+
+ if (ret < 0) {
+ printk(KERN_INFO "%s: can't register video device\n",
+ dev->name);
+ return ret;
+ }
+
+ printk(KERN_INFO "%s: registered device %s\n",
+ dev->name, video_device_node_name(dev->vfd));
+
+ if (dev->caps.has_radio) {
+ dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
+ "radio");
+ if (!dev->radio_dev) {
+ printk(KERN_INFO "%s: can't register radio device\n",
+ dev->name);
+ return ret; /* FIXME release resource */
+ }
+
+ ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ radio_nr);
+ if (ret < 0) {
+ printk(KERN_INFO "%s: can't register radio device\n",
+ dev->name);
+ return ret; /* FIXME release resource */
+ }
+
+ printk(KERN_INFO "%s: registered device %s\n",
+ dev->name, video_device_node_name(dev->radio_dev));
+ }
+
+ printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
+ return ret;
+}
+
+int tm6000_v4l2_unregister(struct tm6000_core *dev)
+{
+ video_unregister_device(dev->vfd);
+
+ if (dev->radio_dev) {
+ if (video_is_registered(dev->radio_dev))
+ video_unregister_device(dev->radio_dev);
+ else
+ video_device_release(dev->radio_dev);
+ dev->radio_dev = NULL;
+ }
+
+ return 0;
+}
+
+int tm6000_v4l2_exit(void)
+{
+ return 0;
+}
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "Allow changing video device number");
+
+module_param_named(debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h
index 6df418658c9c..6df418658c9c 100644
--- a/drivers/media/video/tm6000/tm6000.h
+++ b/drivers/media/usb/tm6000/tm6000.h
diff --git a/drivers/media/usb/ttusb-budget/Kconfig b/drivers/media/usb/ttusb-budget/Kconfig
new file mode 100644
index 000000000000..97bad7da689c
--- /dev/null
+++ b/drivers/media/usb/ttusb-budget/Kconfig
@@ -0,0 +1,18 @@
+config DVB_TTUSB_BUDGET
+ tristate "Technotrend/Hauppauge Nova-USB devices"
+ depends on DVB_CORE && USB && I2C && PCI
+ select DVB_CX22700 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for external USB adapters designed by Technotrend and
+ produced by Hauppauge, shipped under the brand name 'Nova-USB'.
+
+ These devices don't have a MPEG decoder built in, so you need
+ an external software decoder to watch TV.
+
+ Say Y if you own such a device and want to use it.
diff --git a/drivers/media/usb/ttusb-budget/Makefile b/drivers/media/usb/ttusb-budget/Makefile
new file mode 100644
index 000000000000..f47bbf62dcde
--- /dev/null
+++ b/drivers/media/usb/ttusb-budget/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
+
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index 5b682cc4c814..5b682cc4c814 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/usb/ttusb-dec/Kconfig
index 290254ab06db..290254ab06db 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/usb/ttusb-dec/Kconfig
diff --git a/drivers/media/usb/ttusb-dec/Makefile b/drivers/media/usb/ttusb-dec/Makefile
new file mode 100644
index 000000000000..5352740d2353
--- /dev/null
+++ b/drivers/media/usb/ttusb-dec/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
+
+ccflags-y += -Idrivers/media/dvb-core/
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index 504c81230339..504c81230339 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c
index 5c45c9d0712d..5c45c9d0712d 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/drivers/media/usb/ttusb-dec/ttusbdecfe.h
index 15ccc3d1a20e..15ccc3d1a20e 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
+++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.h
diff --git a/drivers/media/usb/usbvision/Kconfig b/drivers/media/usb/usbvision/Kconfig
new file mode 100644
index 000000000000..6b6afc5d8f7e
--- /dev/null
+++ b/drivers/media/usb/usbvision/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_USBVISION
+ tristate "USB video devices based on Nogatech NT1003/1004/1005"
+ depends on I2C && VIDEO_V4L2
+ select VIDEO_TUNER
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ ---help---
+ There are more than 50 different USB video devices based on
+ NT1003/1004/1005 USB Bridges. This driver enables using those
+ devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbvision.
diff --git a/drivers/media/usb/usbvision/Makefile b/drivers/media/usb/usbvision/Makefile
new file mode 100644
index 000000000000..9b3a5581df42
--- /dev/null
+++ b/drivers/media/usb/usbvision/Makefile
@@ -0,0 +1,6 @@
+usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o
+
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
+
+ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/usb/usbvision/usbvision-cards.c
index 3103d0d020e8..3103d0d020e8 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/usb/usbvision/usbvision-cards.c
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/usb/usbvision/usbvision-cards.h
index a51cc1185cce..a51cc1185cce 100644
--- a/drivers/media/video/usbvision/usbvision-cards.h
+++ b/drivers/media/usb/usbvision/usbvision-cards.h
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c
index c9b2042f8bdf..c9b2042f8bdf 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/usb/usbvision/usbvision-core.c
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c
index 89fec029e924..89fec029e924 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/usb/usbvision/usbvision-i2c.c
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
new file mode 100644
index 000000000000..8a4317979a43
--- /dev/null
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -0,0 +1,1720 @@
+/*
+ * USB USBVISION Video device driver 0.9.10
+ *
+ *
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *
+ * This module is part of usbvision driver project.
+ *
+ * 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.
+ *
+ * Let's call the version 0.... until compression decoding is completely
+ * implemented.
+ *
+ * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach.
+ * It was based on USB CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt
+ * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler &
+ * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ *
+ * TODO:
+ * - use submit_urb for all setup packets
+ * - Fix memory settings for nt1004. It is 4 times as big as the
+ * nt1003 memory.
+ * - Add audio on endpoint 3 for nt1004 chip.
+ * Seems impossible, needs a codec interface. Which one?
+ * - Clean up the driver.
+ * - optimization for performance.
+ * - Add Videotext capability (VBI). Working on it.....
+ * - Check audio for other devices
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/saa7115.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/tuner.h>
+
+#include <linux/workqueue.h>
+
+#include "usbvision.h"
+#include "usbvision-cards.h"
+
+#define DRIVER_AUTHOR \
+ "Joerg Heckenbach <joerg@heckenbach-aw.de>, " \
+ "Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_NAME "usbvision"
+#define DRIVER_ALIAS "USBVision"
+#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
+#define DRIVER_LICENSE "GPL"
+#define USBVISION_VERSION_STRING "0.9.11"
+
+#define ENABLE_HEXDUMP 0 /* Enable if you need it */
+
+
+#ifdef USBVISION_DEBUG
+ #define PDEBUG(level, fmt, args...) { \
+ if (video_debug & (level)) \
+ printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+ __func__, __LINE__ , ## args); \
+ }
+#else
+ #define PDEBUG(level, fmt, args...) do {} while (0)
+#endif
+
+#define DBG_IO (1 << 1)
+#define DBG_PROBE (1 << 2)
+#define DBG_MMAP (1 << 3)
+
+/* String operations */
+#define rmspace(str) while (*str == ' ') str++;
+#define goto2next(str) while (*str != ' ') str++; while (*str == ' ') str++;
+
+
+/* sequential number of usbvision device */
+static int usbvision_nr;
+
+static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
+ { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
+ { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" },
+ { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" },
+ { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" },
+ { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" },
+ { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" },
+ { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */
+ { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
+};
+
+/* Function prototypes */
+static void usbvision_release(struct usb_usbvision *usbvision);
+
+/* Default initialization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isoc_mode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug;
+/* Set the default device to power on at startup */
+static int power_on_at_open = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+
+/* Grab parameters for the device driver */
+
+/* Showing parameters under SYSFS */
+module_param(isoc_mode, int, 0444);
+module_param(video_debug, int, 0444);
+module_param(power_on_at_open, int, 0444);
+module_param(video_nr, int, 0444);
+module_param(radio_nr, int, 0444);
+
+MODULE_PARM_DESC(isoc_mode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
+MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
+MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)");
+MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");
+MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
+
+
+/* Misc stuff */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(USBVISION_VERSION_STRING);
+MODULE_ALIAS(DRIVER_ALIAS);
+
+
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module. */
+/* Device information is located at /sys/class/video4linux/video0 */
+/* Device parameters information is located at /sys/module/usbvision */
+/* Device USB Information is located at */
+/* /sys/bus/usb/drivers/USBVision Video Grabber */
+/*****************************************************************************/
+
+#define YES_NO(x) ((x) ? "Yes" : "No")
+
+static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ return video_get_drvdata(vdev);
+}
+
+static ssize_t show_version(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n",
+ usbvision_device_data[usbvision->dev_model].model_string);
+}
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+static ssize_t show_hue(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_HUE;
+ ctrl.value = 0;
+ if (usbvision->user)
+ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+}
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+
+static ssize_t show_contrast(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_CONTRAST;
+ ctrl.value = 0;
+ if (usbvision->user)
+ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+}
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+
+static ssize_t show_brightness(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_BRIGHTNESS;
+ ctrl.value = 0;
+ if (usbvision->user)
+ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+}
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+
+static ssize_t show_saturation(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_SATURATION;
+ ctrl.value = 0;
+ if (usbvision->user)
+ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+}
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+
+static ssize_t show_streaming(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->streaming == stream_on ? 1 : 0));
+}
+static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_compression(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS));
+}
+static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+
+static ssize_t show_device_bridge(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev =
+ container_of(cd, struct video_device, dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%d\n", usbvision->bridge_type);
+}
+static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+
+static void usbvision_create_sysfs(struct video_device *vdev)
+{
+ int res;
+
+ if (!vdev)
+ return;
+ do {
+ res = device_create_file(&vdev->dev, &dev_attr_version);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_model);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_hue);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_contrast);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_brightness);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_saturation);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_streaming);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_compression);
+ if (res < 0)
+ break;
+ res = device_create_file(&vdev->dev, &dev_attr_bridge);
+ if (res >= 0)
+ return;
+ } while (0);
+
+ dev_err(&vdev->dev, "%s error: %d\n", __func__, res);
+}
+
+static void usbvision_remove_sysfs(struct video_device *vdev)
+{
+ if (vdev) {
+ device_remove_file(&vdev->dev, &dev_attr_version);
+ device_remove_file(&vdev->dev, &dev_attr_model);
+ device_remove_file(&vdev->dev, &dev_attr_hue);
+ device_remove_file(&vdev->dev, &dev_attr_contrast);
+ device_remove_file(&vdev->dev, &dev_attr_brightness);
+ device_remove_file(&vdev->dev, &dev_attr_saturation);
+ device_remove_file(&vdev->dev, &dev_attr_streaming);
+ device_remove_file(&vdev->dev, &dev_attr_compression);
+ device_remove_file(&vdev->dev, &dev_attr_bridge);
+ }
+}
+
+/*
+ * usbvision_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'usbvision->user'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ */
+static int usbvision_v4l2_open(struct file *file)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int err_code = 0;
+
+ PDEBUG(DBG_IO, "open");
+
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+ return -ERESTARTSYS;
+ usbvision_reset_power_off_timer(usbvision);
+
+ if (usbvision->user)
+ err_code = -EBUSY;
+ else {
+ /* Allocate memory for the scratch ring buffer */
+ err_code = usbvision_scratch_alloc(usbvision);
+ if (isoc_mode == ISOC_MODE_COMPRESS) {
+ /* Allocate intermediate decompression buffers
+ only if needed */
+ err_code = usbvision_decompress_alloc(usbvision);
+ }
+ if (err_code) {
+ /* Deallocate all buffers if trouble */
+ usbvision_scratch_free(usbvision);
+ usbvision_decompress_free(usbvision);
+ }
+ }
+
+ /* If so far no errors then we shall start the camera */
+ if (!err_code) {
+ if (usbvision->power == 0) {
+ usbvision_power_on(usbvision);
+ usbvision_i2c_register(usbvision);
+ }
+
+ /* Send init sequence only once, it's large! */
+ if (!usbvision->initialized) {
+ int setup_ok = 0;
+ setup_ok = usbvision_setup(usbvision, isoc_mode);
+ if (setup_ok)
+ usbvision->initialized = 1;
+ else
+ err_code = -EBUSY;
+ }
+
+ if (!err_code) {
+ usbvision_begin_streaming(usbvision);
+ err_code = usbvision_init_isoc(usbvision);
+ /* device must be initialized before isoc transfer */
+ usbvision_muxsel(usbvision, 0);
+ usbvision->user++;
+ } else {
+ if (power_on_at_open) {
+ usbvision_i2c_unregister(usbvision);
+ usbvision_power_off(usbvision);
+ usbvision->initialized = 0;
+ }
+ }
+ }
+
+ /* prepare queues */
+ usbvision_empty_framequeues(usbvision);
+ mutex_unlock(&usbvision->v4l2_lock);
+
+ PDEBUG(DBG_IO, "success");
+ return err_code;
+}
+
+/*
+ * usbvision_v4l2_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in usbvision_v4l2_open().
+ *
+ */
+static int usbvision_v4l2_close(struct file *file)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ PDEBUG(DBG_IO, "close");
+
+ mutex_lock(&usbvision->v4l2_lock);
+ usbvision_audio_off(usbvision);
+ usbvision_restart_isoc(usbvision);
+ usbvision_stop_isoc(usbvision);
+
+ usbvision_decompress_free(usbvision);
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ usbvision_scratch_free(usbvision);
+
+ usbvision->user--;
+
+ if (power_on_at_open) {
+ /* power off in a little while
+ to avoid off/on every close/open short sequences */
+ usbvision_set_power_off_timer(usbvision);
+ usbvision->initialized = 0;
+ }
+
+ if (usbvision->remove_pending) {
+ printk(KERN_INFO "%s: Final disconnect\n", __func__);
+ usbvision_release(usbvision);
+ }
+ mutex_unlock(&usbvision->v4l2_lock);
+
+ PDEBUG(DBG_IO, "success");
+ return 0;
+}
+
+
+/*
+ * usbvision_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int err_code;
+
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (err_code < 0) {
+ dev_err(&usbvision->vdev->dev,
+ "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
+ __func__, err_code);
+ return err_code;
+ }
+ reg->val = err_code;
+ reg->size = 1;
+ return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int err_code;
+
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
+ if (err_code < 0) {
+ dev_err(&usbvision->vdev->dev,
+ "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
+ __func__, err_code);
+ return err_code;
+ }
+ return 0;
+}
+#endif
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *vc)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card,
+ usbvision_device_data[usbvision->dev_model].model_string,
+ sizeof(vc->card));
+ usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *vi)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int chan;
+
+ if (vi->index >= usbvision->video_inputs)
+ return -EINVAL;
+ if (usbvision->have_tuner)
+ chan = vi->index;
+ else
+ chan = vi->index + 1; /* skip Television string*/
+
+ /* Determine the requested input characteristics
+ specific for each usbvision card model */
+ switch (chan) {
+ case 0:
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4) {
+ strcpy(vi->name, "White Video Input");
+ } else {
+ strcpy(vi->name, "Television");
+ vi->type = V4L2_INPUT_TYPE_TUNER;
+ vi->audioset = 1;
+ vi->tuner = chan;
+ vi->std = USBVISION_NORMS;
+ }
+ break;
+ case 1:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
+ strcpy(vi->name, "Green Video Input");
+ else
+ strcpy(vi->name, "Composite Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 2:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
+ strcpy(vi->name, "Yellow Video Input");
+ else
+ strcpy(vi->name, "S-Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 3:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(vi->name, "Red Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ }
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ *input = usbvision->ctl_input;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ if (input >= usbvision->video_inputs)
+ return -EINVAL;
+
+ usbvision_muxsel(usbvision, input);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision,
+ usbvision->curwidth,
+ usbvision->curheight);
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ usbvision->tvnorm_id = *id;
+
+ call_all(usbvision, core, s_std, usbvision->tvnorm_id);
+ /* propagate the change to the decoder */
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
+
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */
+ return -EINVAL;
+ if (usbvision->radio) {
+ strcpy(vt->name, "Radio");
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strcpy(vt->name, "Television");
+ }
+ /* Let clients fill in the remainder of this struct */
+ call_all(usbvision, tuner, g_tuner, vt);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ /* Only no or one tuner for now */
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_all(usbvision, tuner, s_tuner, vt);
+
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ freq->tuner = 0; /* Only one tuner */
+ if (usbvision->radio)
+ freq->type = V4L2_TUNER_RADIO;
+ else
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ freq->frequency = usbvision->freq;
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ /* Only no or one tuner for now */
+ if (!usbvision->have_tuner || freq->tuner)
+ return -EINVAL;
+
+ usbvision->freq = freq->frequency;
+ call_all(usbvision, tuner, s_frequency, freq);
+
+ return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ if (usbvision->radio)
+ strcpy(a->name, "Radio");
+ else
+ strcpy(a->name, "TV");
+
+ return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ if (a->index)
+ return -EINVAL;
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ call_all(usbvision, core, queryctrl, ctrl);
+
+ if (!ctrl->type)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ call_all(usbvision, core, g_ctrl, ctrl);
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ call_all(usbvision, core, s_ctrl, ctrl);
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file,
+ void *priv, struct v4l2_requestbuffers *vr)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int ret;
+
+ RESTRICT_TO_RANGE(vr->count, 1, USBVISION_NUMFRAMES);
+
+ /* Check input validity:
+ the user must do a VIDEO CAPTURE and MMAP method. */
+ if (vr->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
+ return ret;
+ }
+
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision, vr->count);
+
+ usbvision->cur_frame = NULL;
+
+ return 0;
+}
+
+static int vidioc_querybuf(struct file *file,
+ void *priv, struct v4l2_buffer *vb)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ struct usbvision_frame *frame;
+
+ /* FIXME : must control
+ that buffers are mapped (VIDIOC_REQBUFS has been called) */
+ if (vb->index >= usbvision->num_frames)
+ return -EINVAL;
+ /* Updating the corresponding frame state */
+ vb->flags = 0;
+ frame = &usbvision->frame[vb->index];
+ if (frame->grabstate >= frame_state_ready)
+ vb->flags |= V4L2_BUF_FLAG_QUEUED;
+ if (frame->grabstate >= frame_state_done)
+ vb->flags |= V4L2_BUF_FLAG_DONE;
+ if (frame->grabstate == frame_state_unused)
+ vb->flags |= V4L2_BUF_FLAG_MAPPED;
+ vb->memory = V4L2_MEMORY_MMAP;
+
+ vb->m.offset = vb->index * PAGE_ALIGN(usbvision->max_frame_size);
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->field = V4L2_FIELD_NONE;
+ vb->length = usbvision->curwidth *
+ usbvision->curheight *
+ usbvision->palette.bytes_per_pixel;
+ vb->timestamp = usbvision->frame[vb->index].timestamp;
+ vb->sequence = usbvision->frame[vb->index].sequence;
+ return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ struct usbvision_frame *frame;
+ unsigned long lock_flags;
+
+ /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+ if (vb->index >= usbvision->num_frames)
+ return -EINVAL;
+
+ frame = &usbvision->frame[vb->index];
+
+ if (frame->grabstate != frame_state_unused)
+ return -EAGAIN;
+
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int ret;
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == stream_idle)
+ return -EINVAL;
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ f = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ f->grabstate = frame_state_unused;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->flags = V4L2_BUF_FLAG_MAPPED |
+ V4L2_BUF_FLAG_QUEUED |
+ V4L2_BUF_FLAG_DONE;
+ vb->index = f->index;
+ vb->sequence = f->sequence;
+ vb->timestamp = f->timestamp;
+ vb->field = V4L2_FIELD_NONE;
+ vb->bytesused = f->scanlength;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ usbvision->streaming = stream_on;
+ call_all(usbvision, video, s_stream, 1);
+
+ return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+ void *priv, enum v4l2_buf_type type)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (usbvision->streaming == stream_on) {
+ usbvision_stream_interrupt(usbvision);
+ /* Stop all video streamings */
+ call_all(usbvision, video, s_stream, 0);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *vfd)
+{
+ if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1)
+ return -EINVAL;
+ strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ vf->fmt.pix.width = usbvision->curwidth;
+ vf->fmt.pix.height = usbvision->curheight;
+ vf->fmt.pix.pixelformat = usbvision->palette.format;
+ vf->fmt.pix.bytesperline =
+ usbvision->curwidth * usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline * usbvision->curheight;
+ vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int format_idx;
+
+ /* Find requested format in available ones */
+ for (format_idx = 0; format_idx < USBVISION_SUPPORTED_PALETTES; format_idx++) {
+ if (vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[format_idx].format) {
+ usbvision->palette = usbvision_v4l2_format[format_idx];
+ break;
+ }
+ }
+ /* robustness */
+ if (format_idx == USBVISION_SUPPORTED_PALETTES)
+ return -EINVAL;
+ RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+ RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+ vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+ usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, vf);
+ if (ret)
+ return ret;
+
+ /* stop io in case it is already in progress */
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
+ return ret;
+ }
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->cur_frame = NULL;
+
+ /* by now we are committed to the new data... */
+ usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+
+ return 0;
+}
+
+static ssize_t usbvision_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int noblock = file->f_flags & O_NONBLOCK;
+ unsigned long lock_flags;
+ int ret, i;
+ struct usbvision_frame *frame;
+
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
+ (unsigned long)count, noblock);
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
+ return -EFAULT;
+
+ /* This entry point is compatible with the mmap routines
+ so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+ to get frames or call read on the device. */
+ if (!usbvision->num_frames) {
+ /* First, allocate some frames to work with
+ if this has not been done with VIDIOC_REQBUF */
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ usbvision_frames_alloc(usbvision, USBVISION_NUMFRAMES);
+ }
+
+ if (usbvision->streaming != stream_on) {
+ /* no stream is running, make it running ! */
+ usbvision->streaming = stream_on;
+ call_all(usbvision, video, s_stream, 1);
+ }
+
+ /* Then, enqueue as many frames as possible
+ (like a user of VIDIOC_QBUF would do) */
+ for (i = 0; i < usbvision->num_frames; i++) {
+ frame = &usbvision->frame[i];
+ if (frame->grabstate == frame_state_unused) {
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
+ /* Accumulated in usbvision_parse_data() */
+ frame->scanlength = 0;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&frame->frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock,
+ lock_flags);
+ }
+ }
+
+ /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
+ if (list_empty(&(usbvision->outqueue))) {
+ if (noblock)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ frame = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ /* An error returns an empty frame */
+ if (frame->grabstate == frame_state_error) {
+ frame->bytes_read = 0;
+ return 0;
+ }
+
+ PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+ __func__,
+ frame->index, frame->bytes_read, frame->scanlength);
+
+ /* copy bytes to user space; we allow for partials reads */
+ if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
+ count = frame->scanlength - frame->bytes_read;
+
+ if (copy_to_user(buf, frame->data + frame->bytes_read, count))
+ return -EFAULT;
+
+ frame->bytes_read += count;
+ PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+ __func__,
+ (unsigned long)count, frame->bytes_read);
+
+ /* For now, forget the frame if it has not been read in one shot. */
+/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */
+ frame->bytes_read = 0;
+
+ /* Mark it as available to be used again. */
+ frame->grabstate = frame_state_unused;
+/* } */
+
+ return count;
+}
+
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int res;
+
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+ return -ERESTARTSYS;
+ res = usbvision_read(file, buf, count, ppos);
+ mutex_unlock(&usbvision->v4l2_lock);
+ return res;
+}
+
+static int usbvision_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long size = vma->vm_end - vma->vm_start,
+ start = vma->vm_start;
+ void *pos;
+ u32 i;
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+ PDEBUG(DBG_MMAP, "mmap");
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return -EFAULT;
+
+ if (!(vma->vm_flags & VM_WRITE) ||
+ size != PAGE_ALIGN(usbvision->max_frame_size)) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < usbvision->num_frames; i++) {
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+ vma->vm_pgoff)
+ break;
+ }
+ if (i == usbvision->num_frames) {
+ PDEBUG(DBG_MMAP,
+ "mmap: user supplied mapping address is out of range");
+ return -EINVAL;
+ }
+
+ /* VM_IO is eventually going to replace PageReserved altogether */
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
+ pos = usbvision->frame[i].data;
+ while (size > 0) {
+ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+ PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int res;
+
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+ return -ERESTARTSYS;
+ res = usbvision_mmap(file, vma);
+ mutex_unlock(&usbvision->v4l2_lock);
+ return res;
+}
+
+/*
+ * Here comes the stuff for radio on usbvision based devices
+ *
+ */
+static int usbvision_radio_open(struct file *file)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int err_code = 0;
+
+ PDEBUG(DBG_IO, "%s:", __func__);
+
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+ return -ERESTARTSYS;
+ if (usbvision->user) {
+ dev_err(&usbvision->rdev->dev,
+ "%s: Someone tried to open an already opened USBVision Radio!\n",
+ __func__);
+ err_code = -EBUSY;
+ } else {
+ if (power_on_at_open) {
+ usbvision_reset_power_off_timer(usbvision);
+ if (usbvision->power == 0) {
+ usbvision_power_on(usbvision);
+ usbvision_i2c_register(usbvision);
+ }
+ }
+
+ /* Alternate interface 1 is is the biggest frame size */
+ err_code = usbvision_set_alternate(usbvision);
+ if (err_code < 0) {
+ usbvision->last_error = err_code;
+ err_code = -EBUSY;
+ goto out;
+ }
+
+ /* If so far no errors then we shall start the radio */
+ usbvision->radio = 1;
+ call_all(usbvision, tuner, s_radio);
+ usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
+ usbvision->user++;
+ }
+
+ if (err_code) {
+ if (power_on_at_open) {
+ usbvision_i2c_unregister(usbvision);
+ usbvision_power_off(usbvision);
+ usbvision->initialized = 0;
+ }
+ }
+out:
+ mutex_unlock(&usbvision->v4l2_lock);
+ return err_code;
+}
+
+
+static int usbvision_radio_close(struct file *file)
+{
+ struct usb_usbvision *usbvision = video_drvdata(file);
+ int err_code = 0;
+
+ PDEBUG(DBG_IO, "");
+
+ mutex_lock(&usbvision->v4l2_lock);
+ /* Set packet size to 0 */
+ usbvision->iface_alt = 0;
+ err_code = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->iface_alt);
+
+ usbvision_audio_off(usbvision);
+ usbvision->radio = 0;
+ usbvision->user--;
+
+ if (power_on_at_open) {
+ usbvision_set_power_off_timer(usbvision);
+ usbvision->initialized = 0;
+ }
+
+ if (usbvision->remove_pending) {
+ printk(KERN_INFO "%s: Final disconnect\n", __func__);
+ usbvision_release(usbvision);
+ }
+
+ mutex_unlock(&usbvision->v4l2_lock);
+ PDEBUG(DBG_IO, "success");
+ return err_code;
+}
+
+/* Video registration stuff */
+
+/* Video template */
+static const struct v4l2_file_operations usbvision_fops = {
+ .owner = THIS_MODULE,
+ .open = usbvision_v4l2_open,
+ .release = usbvision_v4l2_close,
+ .read = usbvision_v4l2_read,
+ .mmap = usbvision_v4l2_mmap,
+ .unlocked_ioctl = video_ioctl2,
+/* .poll = video_poll, */
+};
+
+static const struct v4l2_ioctl_ops usbvision_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_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device usbvision_video_template = {
+ .fops = &usbvision_fops,
+ .ioctl_ops = &usbvision_ioctl_ops,
+ .name = "usbvision-video",
+ .release = video_device_release,
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
+};
+
+
+/* Radio template */
+static const struct v4l2_file_operations usbvision_radio_fops = {
+ .owner = THIS_MODULE,
+ .open = usbvision_radio_open,
+ .release = usbvision_radio_close,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+};
+
+static struct video_device usbvision_radio_template = {
+ .fops = &usbvision_radio_fops,
+ .name = "usbvision-radio",
+ .release = video_device_release,
+ .ioctl_ops = &usbvision_radio_ioctl_ops,
+
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
+};
+
+
+static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
+ struct video_device *vdev_template,
+ char *name)
+{
+ struct usb_device *usb_dev = usbvision->dev;
+ struct video_device *vdev;
+
+ if (usb_dev == NULL) {
+ dev_err(&usbvision->dev->dev,
+ "%s: usbvision->dev is not set\n", __func__);
+ return NULL;
+ }
+
+ vdev = video_device_alloc();
+ if (NULL == vdev)
+ return NULL;
+ *vdev = *vdev_template;
+ vdev->lock = &usbvision->v4l2_lock;
+ vdev->v4l2_dev = &usbvision->v4l2_dev;
+ snprintf(vdev->name, sizeof(vdev->name), "%s", name);
+ video_set_drvdata(vdev, usbvision);
+ return vdev;
+}
+
+/* unregister video4linux devices */
+static void usbvision_unregister_video(struct usb_usbvision *usbvision)
+{
+ /* Radio Device: */
+ if (usbvision->rdev) {
+ PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
+ video_device_node_name(usbvision->rdev));
+ if (video_is_registered(usbvision->rdev))
+ video_unregister_device(usbvision->rdev);
+ else
+ video_device_release(usbvision->rdev);
+ usbvision->rdev = NULL;
+ }
+
+ /* Video Device: */
+ if (usbvision->vdev) {
+ PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
+ video_device_node_name(usbvision->vdev));
+ if (video_is_registered(usbvision->vdev))
+ video_unregister_device(usbvision->vdev);
+ else
+ video_device_release(usbvision->vdev);
+ usbvision->vdev = NULL;
+ }
+}
+
+/* register video4linux devices */
+static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
+{
+ /* Video Device: */
+ usbvision->vdev = usbvision_vdev_init(usbvision,
+ &usbvision_video_template,
+ "USBVision Video");
+ if (usbvision->vdev == NULL)
+ goto err_exit;
+ if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
+ goto err_exit;
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
+ usbvision->nr, video_device_node_name(usbvision->vdev));
+
+ /* Radio Device: */
+ if (usbvision_device_data[usbvision->dev_model].radio) {
+ /* usbvision has radio */
+ usbvision->rdev = usbvision_vdev_init(usbvision,
+ &usbvision_radio_template,
+ "USBVision Radio");
+ if (usbvision->rdev == NULL)
+ goto err_exit;
+ if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
+ goto err_exit;
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
+ usbvision->nr, video_device_node_name(usbvision->rdev));
+ }
+ /* all done */
+ return 0;
+
+ err_exit:
+ dev_err(&usbvision->dev->dev,
+ "USBVision[%d]: video_register_device() failed\n",
+ usbvision->nr);
+ usbvision_unregister_video(usbvision);
+ return -1;
+}
+
+/*
+ * usbvision_alloc()
+ *
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
+ *
+ * Returns NULL on error, a pointer to usb_usbvision else.
+ *
+ */
+static struct usb_usbvision *usbvision_alloc(struct usb_device *dev,
+ struct usb_interface *intf)
+{
+ struct usb_usbvision *usbvision;
+
+ usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
+ if (usbvision == NULL)
+ return NULL;
+
+ usbvision->dev = dev;
+ if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev))
+ goto err_free;
+
+ mutex_init(&usbvision->v4l2_lock);
+
+ /* prepare control urb for control messages during interrupts */
+ usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (usbvision->ctrl_urb == NULL)
+ goto err_unreg;
+ init_waitqueue_head(&usbvision->ctrl_urb_wq);
+
+ usbvision_init_power_off_timer(usbvision);
+
+ return usbvision;
+
+err_unreg:
+ v4l2_device_unregister(&usbvision->v4l2_dev);
+err_free:
+ kfree(usbvision);
+ return NULL;
+}
+
+/*
+ * usbvision_release()
+ *
+ * This code does final release of struct usb_usbvision. This happens
+ * after the device is disconnected -and- all clients closed their files.
+ *
+ */
+static void usbvision_release(struct usb_usbvision *usbvision)
+{
+ PDEBUG(DBG_PROBE, "");
+
+ usbvision_reset_power_off_timer(usbvision);
+
+ usbvision->initialized = 0;
+
+ usbvision_remove_sysfs(usbvision->vdev);
+ usbvision_unregister_video(usbvision);
+
+ usb_free_urb(usbvision->ctrl_urb);
+
+ v4l2_device_unregister(&usbvision->v4l2_dev);
+ kfree(usbvision);
+
+ PDEBUG(DBG_PROBE, "success");
+}
+
+
+/*********************** usb interface **********************************/
+
+static void usbvision_configure_video(struct usb_usbvision *usbvision)
+{
+ int model;
+
+ if (usbvision == NULL)
+ return;
+
+ model = usbvision->dev_model;
+ usbvision->palette = usbvision_v4l2_format[2]; /* V4L2_PIX_FMT_RGB24; */
+
+ if (usbvision_device_data[usbvision->dev_model].vin_reg2_override) {
+ usbvision->vin_reg2_preset =
+ usbvision_device_data[usbvision->dev_model].vin_reg2;
+ } else {
+ usbvision->vin_reg2_preset = 0;
+ }
+
+ usbvision->tvnorm_id = usbvision_device_data[model].video_norm;
+
+ usbvision->video_inputs = usbvision_device_data[model].video_channels;
+ usbvision->ctl_input = 0;
+
+ /* This should be here to make i2c clients to be able to register */
+ /* first switch off audio */
+ if (usbvision_device_data[model].audio_channels > 0)
+ usbvision_audio_off(usbvision);
+ if (!power_on_at_open) {
+ /* and then power up the noisy tuner */
+ usbvision_power_on(usbvision);
+ usbvision_i2c_register(usbvision);
+ }
+}
+
+/*
+ * usbvision_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like USBVISION video device
+ *
+ */
+static int __devinit usbvision_probe(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
+ struct usb_interface *uif;
+ __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+ const struct usb_host_interface *interface;
+ struct usb_usbvision *usbvision = NULL;
+ const struct usb_endpoint_descriptor *endpoint;
+ int model, i;
+
+ PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
+ dev->descriptor.idVendor,
+ dev->descriptor.idProduct, ifnum);
+
+ model = devid->driver_info;
+ if (model < 0 || model >= usbvision_device_data_size) {
+ PDEBUG(DBG_PROBE, "model out of bounds %d", model);
+ return -ENODEV;
+ }
+ printk(KERN_INFO "%s: %s found\n", __func__,
+ usbvision_device_data[model].model_string);
+
+ if (usbvision_device_data[model].interface >= 0)
+ interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
+ else
+ interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+ endpoint = &interface->endpoint[1].desc;
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
+ dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
+ __func__, ifnum);
+ dev_err(&intf->dev, "%s: Endpoint attributes %d",
+ __func__, endpoint->bmAttributes);
+ return -ENODEV;
+ }
+ if (usb_endpoint_dir_out(endpoint)) {
+ dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n",
+ __func__, ifnum);
+ return -ENODEV;
+ }
+
+ usbvision = usbvision_alloc(dev, intf);
+ if (usbvision == NULL) {
+ dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (dev->descriptor.bNumConfigurations > 1)
+ usbvision->bridge_type = BRIDGE_NT1004;
+ else if (model == DAZZLE_DVC_90_REV_1_SECAM)
+ usbvision->bridge_type = BRIDGE_NT1005;
+ else
+ usbvision->bridge_type = BRIDGE_NT1003;
+ PDEBUG(DBG_PROBE, "bridge_type %d", usbvision->bridge_type);
+
+ /* compute alternate max packet sizes */
+ uif = dev->actconfig->interface[0];
+
+ usbvision->num_alt = uif->num_altsetting;
+ PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt);
+ usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
+ if (usbvision->alt_max_pkt_size == NULL) {
+ dev_err(&intf->dev, "usbvision: out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < usbvision->num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ wMaxPacketSize);
+ usbvision->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i", i,
+ usbvision->alt_max_pkt_size[i]);
+ }
+
+
+ usbvision->nr = usbvision_nr++;
+
+ usbvision->have_tuner = usbvision_device_data[model].tuner;
+ if (usbvision->have_tuner)
+ usbvision->tuner_type = usbvision_device_data[model].tuner_type;
+
+ usbvision->dev_model = model;
+ usbvision->remove_pending = 0;
+ usbvision->iface = ifnum;
+ usbvision->iface_alt = 0;
+ usbvision->video_endp = endpoint->bEndpointAddress;
+ usbvision->isoc_packet_size = 0;
+ usbvision->usb_bandwidth = 0;
+ usbvision->user = 0;
+ usbvision->streaming = stream_off;
+ usbvision_configure_video(usbvision);
+ usbvision_register_video(usbvision);
+
+ usbvision_create_sysfs(usbvision->vdev);
+
+ PDEBUG(DBG_PROBE, "success");
+ return 0;
+}
+
+
+/*
+ * usbvision_disconnect()
+ *
+ * This procedure stops all driver activity, deallocates interface-private
+ * structure (pointed by 'ptr') and after that driver should be removable
+ * with no ill consequences.
+ *
+ */
+static void __devexit usbvision_disconnect(struct usb_interface *intf)
+{
+ struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
+
+ PDEBUG(DBG_PROBE, "");
+
+ if (usbvision == NULL) {
+ pr_err("%s: usb_get_intfdata() failed\n", __func__);
+ return;
+ }
+
+ mutex_lock(&usbvision->v4l2_lock);
+
+ /* At this time we ask to cancel outstanding URBs */
+ usbvision_stop_isoc(usbvision);
+
+ v4l2_device_disconnect(&usbvision->v4l2_dev);
+
+ if (usbvision->power) {
+ usbvision_i2c_unregister(usbvision);
+ usbvision_power_off(usbvision);
+ }
+ usbvision->remove_pending = 1; /* Now all ISO data will be ignored */
+
+ usb_put_dev(usbvision->dev);
+ usbvision->dev = NULL; /* USB device is no more */
+
+ mutex_unlock(&usbvision->v4l2_lock);
+
+ if (usbvision->user) {
+ printk(KERN_INFO "%s: In use, disconnect pending\n",
+ __func__);
+ wake_up_interruptible(&usbvision->wait_frame);
+ wake_up_interruptible(&usbvision->wait_stream);
+ } else {
+ usbvision_release(usbvision);
+ }
+
+ PDEBUG(DBG_PROBE, "success");
+}
+
+static struct usb_driver usbvision_driver = {
+ .name = "usbvision",
+ .id_table = usbvision_table,
+ .probe = usbvision_probe,
+ .disconnect = __devexit_p(usbvision_disconnect),
+};
+
+/*
+ * usbvision_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ */
+static int __init usbvision_init(void)
+{
+ int err_code;
+
+ PDEBUG(DBG_PROBE, "");
+
+ PDEBUG(DBG_IO, "IO debugging is enabled [video]");
+ PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
+ PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
+
+ /* disable planar mode support unless compression enabled */
+ if (isoc_mode != ISOC_MODE_COMPRESS) {
+ /* FIXME : not the right way to set supported flag */
+ usbvision_v4l2_format[6].supported = 0; /* V4L2_PIX_FMT_YVU420 */
+ usbvision_v4l2_format[7].supported = 0; /* V4L2_PIX_FMT_YUV422P */
+ }
+
+ err_code = usb_register(&usbvision_driver);
+
+ if (err_code == 0) {
+ printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
+ PDEBUG(DBG_PROBE, "success");
+ }
+ return err_code;
+}
+
+static void __exit usbvision_exit(void)
+{
+ PDEBUG(DBG_PROBE, "");
+
+ usb_deregister(&usbvision_driver);
+ PDEBUG(DBG_PROBE, "success");
+}
+
+module_init(usbvision_init);
+module_exit(usbvision_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index 43cf61fe4943..43cf61fe4943 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig
index 541c9f1e4c6a..541c9f1e4c6a 100644
--- a/drivers/media/video/uvc/Kconfig
+++ b/drivers/media/usb/uvc/Kconfig
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/usb/uvc/Makefile
index c26d12fdb8f4..c26d12fdb8f4 100644
--- a/drivers/media/video/uvc/Makefile
+++ b/drivers/media/usb/uvc/Makefile
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index f7061a5ef1d2..f7061a5ef1d2 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c
index 14561a5abb79..14561a5abb79 100644
--- a/drivers/media/video/uvc/uvc_debugfs.c
+++ b/drivers/media/usb/uvc/uvc_debugfs.c
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
new file mode 100644
index 000000000000..45d7aa162d9d
--- /dev/null
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -0,0 +1,2472 @@
+/*
+ * uvc_driver.c -- USB Video Class driver
+ *
+ * Copyright (C) 2005-2010
+ * 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.
+ *
+ */
+
+/*
+ * This driver aims to support video input and ouput devices compliant with the
+ * 'USB Video Class' specification.
+ *
+ * The driver doesn't support the deprecated v4l1 interface. It implements the
+ * mmap capture method only, and doesn't do any image format conversion in
+ * software. If your user-space application doesn't support YUYV or MJPEG, fix
+ * it :-). Please note that the MJPEG data have been stripped from their
+ * Huffman tables (DHT marker), you will need to add it back if your JPEG
+ * codec can't handle MJPEG data.
+ */
+
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+#define DRIVER_AUTHOR "Laurent Pinchart " \
+ "<laurent.pinchart@ideasonboard.com>"
+#define DRIVER_DESC "USB Video Class driver"
+
+unsigned int uvc_clock_param = CLOCK_MONOTONIC;
+unsigned int uvc_no_drop_param;
+static unsigned int uvc_quirks_param = -1;
+unsigned int uvc_trace_param;
+unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
+
+/* ------------------------------------------------------------------------
+ * Video formats
+ */
+
+static struct uvc_format_desc uvc_fmts[] = {
+ {
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .name = "YUV 4:2:0 (NV12)",
+ .guid = UVC_GUID_FORMAT_NV12,
+ .fcc = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .name = "MJPEG",
+ .guid = UVC_GUID_FORMAT_MJPEG,
+ .fcc = V4L2_PIX_FMT_MJPEG,
+ },
+ {
+ .name = "YVU 4:2:0 (YV12)",
+ .guid = UVC_GUID_FORMAT_YV12,
+ .fcc = V4L2_PIX_FMT_YVU420,
+ },
+ {
+ .name = "YUV 4:2:0 (I420)",
+ .guid = UVC_GUID_FORMAT_I420,
+ .fcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .name = "YUV 4:2:0 (M420)",
+ .guid = UVC_GUID_FORMAT_M420,
+ .fcc = V4L2_PIX_FMT_M420,
+ },
+ {
+ .name = "YUV 4:2:2 (UYVY)",
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .name = "Greyscale 8-bit (Y800)",
+ .guid = UVC_GUID_FORMAT_Y800,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .name = "Greyscale 8-bit (Y8 )",
+ .guid = UVC_GUID_FORMAT_Y8,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .name = "Greyscale 10-bit (Y10 )",
+ .guid = UVC_GUID_FORMAT_Y10,
+ .fcc = V4L2_PIX_FMT_Y10,
+ },
+ {
+ .name = "Greyscale 12-bit (Y12 )",
+ .guid = UVC_GUID_FORMAT_Y12,
+ .fcc = V4L2_PIX_FMT_Y12,
+ },
+ {
+ .name = "Greyscale 16-bit (Y16 )",
+ .guid = UVC_GUID_FORMAT_Y16,
+ .fcc = V4L2_PIX_FMT_Y16,
+ },
+ {
+ .name = "RGB Bayer",
+ .guid = UVC_GUID_FORMAT_BY8,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+ {
+ .name = "RGB565",
+ .guid = UVC_GUID_FORMAT_RGBP,
+ .fcc = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .name = "H.264",
+ .guid = UVC_GUID_FORMAT_H264,
+ .fcc = V4L2_PIX_FMT_H264,
+ },
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+ __u8 epaddr)
+{
+ struct usb_host_endpoint *ep;
+ unsigned int i;
+
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ ep = &alts->endpoint[i];
+ if (ep->desc.bEndpointAddress == epaddr)
+ return ep;
+ }
+
+ return NULL;
+}
+
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+{
+ unsigned int len = ARRAY_SIZE(uvc_fmts);
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+ return &uvc_fmts[i];
+ }
+
+ return NULL;
+}
+
+static __u32 uvc_colorspace(const __u8 primaries)
+{
+ static const __u8 colorprimaries[] = {
+ 0,
+ V4L2_COLORSPACE_SRGB,
+ V4L2_COLORSPACE_470_SYSTEM_M,
+ V4L2_COLORSPACE_470_SYSTEM_BG,
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_COLORSPACE_SMPTE240M,
+ };
+
+ if (primaries < ARRAY_SIZE(colorprimaries))
+ return colorprimaries[primaries];
+
+ return 0;
+}
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold)
+{
+ uint32_t *an;
+ uint32_t x, y, r;
+ unsigned int i, n;
+
+ an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+ if (an == NULL)
+ return;
+
+ /* Convert the fraction to a simple continued fraction. See
+ * http://mathforum.org/dr.math/faq/faq.fractions.html
+ * Stop if the current term is bigger than or equal to the given
+ * threshold.
+ */
+ x = *numerator;
+ y = *denominator;
+
+ for (n = 0; n < n_terms && y != 0; ++n) {
+ an[n] = x / y;
+ if (an[n] >= threshold) {
+ if (n < 2)
+ n++;
+ break;
+ }
+
+ r = x - an[n] * y;
+ x = y;
+ y = r;
+ }
+
+ /* Expand the simple continued fraction back to an integer fraction. */
+ x = 0;
+ y = 1;
+
+ for (i = n; i > 0; --i) {
+ r = y;
+ y = an[i-1] * y + x;
+ x = r;
+ }
+
+ *numerator = y;
+ *denominator = x;
+ kfree(an);
+}
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+{
+ uint32_t multiplier;
+
+ /* Saturate the result if the operation would overflow. */
+ if (denominator == 0 ||
+ numerator/denominator >= ((uint32_t)-1)/10000000)
+ return (uint32_t)-1;
+
+ /* Divide both the denominator and the multiplier by two until
+ * numerator * multiplier doesn't overflow. If anyone knows a better
+ * algorithm please let me know.
+ */
+ multiplier = 10000000;
+ while (numerator > ((uint32_t)-1)/multiplier) {
+ multiplier /= 2;
+ denominator /= 2;
+ }
+
+ return denominator ? numerator * multiplier / denominator : 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+{
+ struct uvc_entity *entity;
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ if (entity->id == id)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
+ int id, struct uvc_entity *entity)
+{
+ unsigned int i;
+
+ if (entity == NULL)
+ entity = list_entry(&dev->entities, struct uvc_entity, list);
+
+ list_for_each_entry_continue(entity, &dev->entities, list) {
+ for (i = 0; i < entity->bNrInPins; ++i)
+ if (entity->baSourceID[i] == id)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
+{
+ struct uvc_streaming *stream;
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->header.bTerminalLink == id)
+ return stream;
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------
+ * Descriptors parsing
+ */
+
+static int uvc_parse_format(struct uvc_device *dev,
+ struct uvc_streaming *streaming, struct uvc_format *format,
+ __u32 **intervals, unsigned char *buffer, int buflen)
+{
+ struct usb_interface *intf = streaming->intf;
+ struct usb_host_interface *alts = intf->cur_altsetting;
+ struct uvc_format_desc *fmtdesc;
+ struct uvc_frame *frame;
+ const unsigned char *start = buffer;
+ unsigned int interval;
+ unsigned int i, n;
+ __u8 ftype;
+
+ format->type = buffer[2];
+ format->index = buffer[3];
+
+ switch (buffer[2]) {
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_FRAME_BASED:
+ n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+ if (buflen < n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Find the format descriptor from its GUID. */
+ fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+ if (fmtdesc != NULL) {
+ strlcpy(format->name, fmtdesc->name,
+ sizeof format->name);
+ format->fcc = fmtdesc->fcc;
+ } else {
+ uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
+ &buffer[5]);
+ snprintf(format->name, sizeof(format->name), "%pUl\n",
+ &buffer[5]);
+ format->fcc = 0;
+ }
+
+ format->bpp = buffer[21];
+ if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
+ ftype = UVC_VS_FRAME_UNCOMPRESSED;
+ } else {
+ ftype = UVC_VS_FRAME_FRAME_BASED;
+ if (buffer[27])
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ }
+ break;
+
+ case UVC_VS_FORMAT_MJPEG:
+ if (buflen < 11) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ strlcpy(format->name, "MJPEG", sizeof format->name);
+ format->fcc = V4L2_PIX_FMT_MJPEG;
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ format->bpp = 0;
+ ftype = UVC_VS_FRAME_MJPEG;
+ break;
+
+ case UVC_VS_FORMAT_DV:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ switch (buffer[8] & 0x7f) {
+ case 0:
+ strlcpy(format->name, "SD-DV", sizeof format->name);
+ break;
+ case 1:
+ strlcpy(format->name, "SDL-DV", sizeof format->name);
+ break;
+ case 2:
+ strlcpy(format->name, "HD-DV", sizeof format->name);
+ break;
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d: unknown DV format %u\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[8]);
+ return -EINVAL;
+ }
+
+ strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+ sizeof format->name);
+
+ format->fcc = V4L2_PIX_FMT_DV;
+ format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
+ format->bpp = 0;
+ ftype = 0;
+
+ /* Create a dummy frame descriptor. */
+ frame = &format->frame[0];
+ memset(&format->frame[0], 0, sizeof format->frame[0]);
+ frame->bFrameIntervalType = 1;
+ frame->dwDefaultFrameInterval = 1;
+ frame->dwFrameInterval = *intervals;
+ *(*intervals)++ = 1;
+ format->nframes = 1;
+ break;
+
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
+ /* Not supported yet. */
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d unsupported format %u\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber,
+ buffer[2]);
+ return -EINVAL;
+ }
+
+ uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+ * based formats have frame descriptors.
+ */
+ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+ buffer[2] == ftype) {
+ frame = &format->frame[format->nframes];
+ if (ftype != UVC_VS_FRAME_FRAME_BASED)
+ n = buflen > 25 ? buffer[25] : 0;
+ else
+ n = buflen > 21 ? buffer[21] : 0;
+
+ n = n ? n : 3;
+
+ if (buflen < 26 + 4*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FRAME error\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ frame->bFrameIndex = buffer[3];
+ frame->bmCapabilities = buffer[4];
+ frame->wWidth = get_unaligned_le16(&buffer[5]);
+ frame->wHeight = get_unaligned_le16(&buffer[7]);
+ frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
+ frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
+ if (ftype != UVC_VS_FRAME_FRAME_BASED) {
+ frame->dwMaxVideoFrameBufferSize =
+ get_unaligned_le32(&buffer[17]);
+ frame->dwDefaultFrameInterval =
+ get_unaligned_le32(&buffer[21]);
+ frame->bFrameIntervalType = buffer[25];
+ } else {
+ frame->dwMaxVideoFrameBufferSize = 0;
+ frame->dwDefaultFrameInterval =
+ get_unaligned_le32(&buffer[17]);
+ frame->bFrameIntervalType = buffer[21];
+ }
+ frame->dwFrameInterval = *intervals;
+
+ /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+ * completely. Observed behaviours range from setting the
+ * value to 1.1x the actual frame size to hardwiring the
+ * 16 low bits to 0. This results in a higher than necessary
+ * memory usage as well as a wrong image size information. For
+ * uncompressed formats this can be fixed by computing the
+ * value from the frame size.
+ */
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+ frame->dwMaxVideoFrameBufferSize = format->bpp
+ * frame->wWidth * frame->wHeight / 8;
+
+ /* Some bogus devices report dwMinFrameInterval equal to
+ * dwMaxFrameInterval and have dwFrameIntervalStep set to
+ * zero. Setting all null intervals to 1 fixes the problem and
+ * some other divisions by zero that could happen.
+ */
+ for (i = 0; i < n; ++i) {
+ interval = get_unaligned_le32(&buffer[26+4*i]);
+ *(*intervals)++ = interval ? interval : 1;
+ }
+
+ /* Make sure that the default frame interval stays between
+ * the boundaries.
+ */
+ n -= frame->bFrameIntervalType ? 1 : 2;
+ frame->dwDefaultFrameInterval =
+ min(frame->dwFrameInterval[n],
+ max(frame->dwFrameInterval[0],
+ frame->dwDefaultFrameInterval));
+
+ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
+ frame->bFrameIntervalType = 1;
+ frame->dwFrameInterval[0] =
+ frame->dwDefaultFrameInterval;
+ }
+
+ uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+ frame->wWidth, frame->wHeight,
+ 10000000/frame->dwDefaultFrameInterval,
+ (100000000/frame->dwDefaultFrameInterval)%10);
+
+ format->nframes++;
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+ buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+ buffer[2] == UVC_VS_COLORFORMAT) {
+ if (buflen < 6) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d COLORFORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ format->colorspace = uvc_colorspace(buffer[3]);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ return buffer - start;
+}
+
+static int uvc_parse_streaming(struct uvc_device *dev,
+ struct usb_interface *intf)
+{
+ struct uvc_streaming *streaming = NULL;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ struct usb_host_interface *alts = &intf->altsetting[0];
+ unsigned char *_buffer, *buffer = alts->extra;
+ int _buflen, buflen = alts->extralen;
+ unsigned int nformats = 0, nframes = 0, nintervals = 0;
+ unsigned int size, i, n, p;
+ __u32 *interval;
+ __u16 psize;
+ int ret = -EINVAL;
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass
+ != UVC_SC_VIDEOSTREAMING) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
+ "video streaming interface\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
+ "claimed\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+ if (streaming == NULL) {
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ return -EINVAL;
+ }
+
+ mutex_init(&streaming->mutex);
+ streaming->dev = dev;
+ streaming->intf = usb_get_intf(intf);
+ streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ /* The Pico iMage webcam has its class-specific interface descriptors
+ * after the endpoint descriptors.
+ */
+ if (buflen == 0) {
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ struct usb_host_endpoint *ep = &alts->endpoint[i];
+
+ if (ep->extralen == 0)
+ continue;
+
+ if (ep->extralen > 2 &&
+ ep->extra[1] == USB_DT_CS_INTERFACE) {
+ uvc_trace(UVC_TRACE_DESCR, "trying extra data "
+ "from endpoint %u.\n", i);
+ buffer = alts->endpoint[i].extra;
+ buflen = alts->endpoint[i].extralen;
+ break;
+ }
+ }
+ }
+
+ /* Skip the standard interface descriptors. */
+ while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen <= 2) {
+ uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
+ "interface descriptors found.\n");
+ goto error;
+ }
+
+ /* Parse the header descriptor. */
+ switch (buffer[2]) {
+ case UVC_VS_OUTPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ size = 9;
+ break;
+
+ case UVC_VS_INPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ size = 13;
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d HEADER descriptor not found.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ p = buflen >= 4 ? buffer[3] : 0;
+ n = buflen >= size ? buffer[size-1] : 0;
+
+ if (buflen < size + p*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d HEADER descriptor is invalid.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ streaming->header.bNumFormats = p;
+ streaming->header.bEndpointAddress = buffer[6];
+ if (buffer[2] == UVC_VS_INPUT_HEADER) {
+ streaming->header.bmInfo = buffer[7];
+ streaming->header.bTerminalLink = buffer[8];
+ streaming->header.bStillCaptureMethod = buffer[9];
+ streaming->header.bTriggerSupport = buffer[10];
+ streaming->header.bTriggerUsage = buffer[11];
+ } else {
+ streaming->header.bTerminalLink = buffer[7];
+ }
+ streaming->header.bControlSize = n;
+
+ streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
+ GFP_KERNEL);
+ if (streaming->header.bmaControls == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ _buffer = buffer;
+ _buflen = buflen;
+
+ /* Count the format and frame descriptors. */
+ while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
+ switch (_buffer[2]) {
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_FRAME_BASED:
+ nformats++;
+ break;
+
+ case UVC_VS_FORMAT_DV:
+ /* DV format has no frame descriptor. We will create a
+ * dummy frame descriptor with a dummy frame interval.
+ */
+ nformats++;
+ nframes++;
+ nintervals++;
+ break;
+
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT %u is not supported.\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, _buffer[2]);
+ break;
+
+ case UVC_VS_FRAME_UNCOMPRESSED:
+ case UVC_VS_FRAME_MJPEG:
+ nframes++;
+ if (_buflen > 25)
+ nintervals += _buffer[25] ? _buffer[25] : 3;
+ break;
+
+ case UVC_VS_FRAME_FRAME_BASED:
+ nframes++;
+ if (_buflen > 21)
+ nintervals += _buffer[21] ? _buffer[21] : 3;
+ break;
+ }
+
+ _buflen -= _buffer[0];
+ _buffer += _buffer[0];
+ }
+
+ if (nformats == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d has no supported formats defined.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ size = nformats * sizeof *format + nframes * sizeof *frame
+ + nintervals * sizeof *interval;
+ format = kzalloc(size, GFP_KERNEL);
+ if (format == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ frame = (struct uvc_frame *)&format[nformats];
+ interval = (__u32 *)&frame[nframes];
+
+ streaming->format = format;
+ streaming->nformats = nformats;
+
+ /* Parse the format descriptors. */
+ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
+ switch (buffer[2]) {
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_DV:
+ case UVC_VS_FORMAT_FRAME_BASED:
+ format->frame = frame;
+ ret = uvc_parse_format(dev, streaming, format,
+ &interval, buffer, buflen);
+ if (ret < 0)
+ goto error;
+
+ frame += format->nframes;
+ format++;
+
+ buflen -= ret;
+ buffer += ret;
+ continue;
+
+ default:
+ break;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen)
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d has %u bytes of trailing descriptor garbage.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);
+
+ /* Parse the alternate settings to find the maximum bandwidth. */
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_endpoint *ep;
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (psize > streaming->maxpsize)
+ streaming->maxpsize = psize;
+ }
+
+ list_add_tail(&streaming->list, &dev->streams);
+ return 0;
+
+error:
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ usb_put_intf(intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ return ret;
+}
+
+static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
+ unsigned int num_pads, unsigned int extra_size)
+{
+ struct uvc_entity *entity;
+ unsigned int num_inputs;
+ unsigned int size;
+ unsigned int i;
+
+ extra_size = ALIGN(extra_size, sizeof(*entity->pads));
+ num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
+ size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
+ + num_inputs;
+ entity = kzalloc(size, GFP_KERNEL);
+ if (entity == NULL)
+ return NULL;
+
+ entity->id = id;
+ entity->type = type;
+
+ entity->num_links = 0;
+ entity->num_pads = num_pads;
+ entity->pads = ((void *)(entity + 1)) + extra_size;
+
+ for (i = 0; i < num_inputs; ++i)
+ entity->pads[i].flags = MEDIA_PAD_FL_SINK;
+ if (!UVC_ENTITY_IS_OTERM(entity))
+ entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
+
+ entity->bNrInPins = num_inputs;
+ entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
+
+ return entity;
+}
+
+/* Parse vendor-specific extensions. */
+static int uvc_parse_vendor_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ struct uvc_entity *unit;
+ unsigned int n, p;
+ int handled = 0;
+
+ switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
+ case 0x046d: /* Logitech */
+ if (buffer[1] != 0x41 || buffer[2] != 0x01)
+ break;
+
+ /* Logitech implements several vendor specific functions
+ * through vendor specific extension units (LXU).
+ *
+ * The LXU descriptors are similar to XU descriptors
+ * (see "USB Device Video Class for Video Devices", section
+ * 3.7.2.6 "Extension Unit Descriptor") with the following
+ * differences:
+ *
+ * ----------------------------------------------------------
+ * 0 bLength 1 Number
+ * Size of this descriptor, in bytes: 24+p+n*2
+ * ----------------------------------------------------------
+ * 23+p+n bmControlsType N Bitmap
+ * Individual bits in the set are defined:
+ * 0: Absolute
+ * 1: Relative
+ *
+ * This bitset is mapped exactly the same as bmControls.
+ * ----------------------------------------------------------
+ * 23+p+n*2 bReserved 1 Boolean
+ * ----------------------------------------------------------
+ * 24+p+n*2 iExtension 1 Index
+ * Index of a string descriptor that describes this
+ * extension unit.
+ * ----------------------------------------------------------
+ */
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 25 + p ? buffer[22+p] : 0;
+
+ if (buflen < 25 + p + 2*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ break;
+ }
+
+ unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
+ p + 1, 2*n);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ memcpy(unit->baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof(*unit);
+ unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit)
+ + n;
+ memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
+
+ if (buffer[24+p+2*n] != 0)
+ usb_string(udev, buffer[24+p+2*n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ handled = 1;
+ break;
+ }
+
+ return handled;
+}
+
+static int uvc_parse_standard_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct uvc_entity *unit, *term;
+ struct usb_interface *intf;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned int i, n, p, len;
+ __u16 type;
+
+ switch (buffer[2]) {
+ case UVC_VC_HEADER:
+ n = buflen >= 12 ? buffer[11] : 0;
+
+ if (buflen < 12 || buflen < 12 + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d HEADER error\n", udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ dev->uvc_version = get_unaligned_le16(&buffer[3]);
+ dev->clock_frequency = get_unaligned_le32(&buffer[7]);
+
+ /* Parse all USB Video Streaming interfaces. */
+ for (i = 0; i < n; ++i) {
+ intf = usb_ifnum_to_if(udev, buffer[12+i]);
+ if (intf == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d "
+ "interface %d doesn't exists\n",
+ udev->devnum, i);
+ continue;
+ }
+
+ uvc_parse_streaming(dev, intf);
+ }
+ break;
+
+ case UVC_VC_INPUT_TERMINAL:
+ if (buflen < 8) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = get_unaligned_le16(&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber,
+ buffer[3], type);
+ return 0;
+ }
+
+ n = 0;
+ p = 0;
+ len = 8;
+
+ if (type == UVC_ITT_CAMERA) {
+ n = buflen >= 15 ? buffer[14] : 0;
+ len = 15;
+
+ } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
+ n = buflen >= 9 ? buffer[8] : 0;
+ p = buflen >= 10 + n ? buffer[9+n] : 0;
+ len = 10;
+ }
+
+ if (buflen < len + n + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
+ 1, n + p);
+ if (term == NULL)
+ return -ENOMEM;
+
+ if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
+ term->camera.bControlSize = n;
+ term->camera.bmControls = (__u8 *)term + sizeof *term;
+ term->camera.wObjectiveFocalLengthMin =
+ get_unaligned_le16(&buffer[8]);
+ term->camera.wObjectiveFocalLengthMax =
+ get_unaligned_le16(&buffer[10]);
+ term->camera.wOcularFocalLength =
+ get_unaligned_le16(&buffer[12]);
+ memcpy(term->camera.bmControls, &buffer[15], n);
+ } else if (UVC_ENTITY_TYPE(term) ==
+ UVC_ITT_MEDIA_TRANSPORT_INPUT) {
+ term->media.bControlSize = n;
+ term->media.bmControls = (__u8 *)term + sizeof *term;
+ term->media.bTransportModeSize = p;
+ term->media.bmTransportModes = (__u8 *)term
+ + sizeof *term + n;
+ memcpy(term->media.bmControls, &buffer[9], n);
+ memcpy(term->media.bmTransportModes, &buffer[10+n], p);
+ }
+
+ if (buffer[7] != 0)
+ usb_string(udev, buffer[7], term->name,
+ sizeof term->name);
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
+ sprintf(term->name, "Camera %u", buffer[3]);
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
+ sprintf(term->name, "Media %u", buffer[3]);
+ else
+ sprintf(term->name, "Input %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case UVC_VC_OUTPUT_TERMINAL:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = get_unaligned_le16(&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[3], type);
+ return 0;
+ }
+
+ term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
+ 1, 0);
+ if (term == NULL)
+ return -ENOMEM;
+
+ memcpy(term->baSourceID, &buffer[7], 1);
+
+ if (buffer[8] != 0)
+ usb_string(udev, buffer[8], term->name,
+ sizeof term->name);
+ else
+ sprintf(term->name, "Output %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case UVC_VC_SELECTOR_UNIT:
+ p = buflen >= 5 ? buffer[4] : 0;
+
+ if (buflen < 5 || buflen < 6 + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d SELECTOR_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ memcpy(unit->baSourceID, &buffer[5], p);
+
+ if (buffer[5+p] != 0)
+ usb_string(udev, buffer[5+p], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Selector %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case UVC_VC_PROCESSING_UNIT:
+ n = buflen >= 8 ? buffer[7] : 0;
+ p = dev->uvc_version >= 0x0110 ? 10 : 9;
+
+ if (buflen < p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d PROCESSING_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ memcpy(unit->baSourceID, &buffer[4], 1);
+ unit->processing.wMaxMultiplier =
+ get_unaligned_le16(&buffer[5]);
+ unit->processing.bControlSize = buffer[7];
+ unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->processing.bmControls, &buffer[8], n);
+ if (dev->uvc_version >= 0x0110)
+ unit->processing.bmVideoStandards = buffer[9+n];
+
+ if (buffer[8+n] != 0)
+ usb_string(udev, buffer[8+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Processing %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case UVC_VC_EXTENSION_UNIT:
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 24 + p ? buffer[22+p] : 0;
+
+ if (buflen < 24 + p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ memcpy(unit->baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->extension.bmControls, &buffer[23+p], n);
+
+ if (buffer[23+p+n] != 0)
+ usb_string(udev, buffer[23+p+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
+ "descriptor (%u)\n", buffer[2]);
+ break;
+ }
+
+ return 0;
+}
+
+static int uvc_parse_control(struct uvc_device *dev)
+{
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned char *buffer = alts->extra;
+ int buflen = alts->extralen;
+ int ret;
+
+ /* Parse the default alternate setting only, as the UVC specification
+ * defines a single alternate setting, the default alternate setting
+ * zero.
+ */
+
+ while (buflen > 2) {
+ if (uvc_parse_vendor_control(dev, buffer, buflen) ||
+ buffer[1] != USB_DT_CS_INTERFACE)
+ goto next_descriptor;
+
+ if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+ return ret;
+
+next_descriptor:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ /* Check if the optional status endpoint is present. Built-in iSight
+ * webcams have an interrupt endpoint but spit proprietary data that
+ * don't conform to the UVC status endpoint messages. Don't try to
+ * handle the interrupt endpoint for those cameras.
+ */
+ if (alts->desc.bNumEndpoints == 1 &&
+ !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
+ struct usb_host_endpoint *ep = &alts->endpoint[0];
+ struct usb_endpoint_descriptor *desc = &ep->desc;
+
+ if (usb_endpoint_is_int_in(desc) &&
+ le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
+ desc->bInterval != 0) {
+ uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
+ "(addr %02x).\n", desc->bEndpointAddress);
+ dev->int_ep = ep;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * UVC device scan
+ */
+
+/*
+ * Scan the UVC descriptors to locate a chain starting at an Output Terminal
+ * and containing the following units:
+ *
+ * - one or more Output Terminals (USB Streaming or Display)
+ * - zero or one Processing Unit
+ * - zero, one or more single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ * connected to input terminals
+ * - zero, one or mode single-input Extension Units
+ * - one or more Input Terminals (Camera, External or USB Streaming)
+ *
+ * The terminal and units must match on of the following structures:
+ *
+ * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
+ * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
+ * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
+ *
+ * +---------+ +---------+ -> OTT_*(0)
+ * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
+ * +---------+ +---------+ -> OTT_*(n)
+ *
+ * The Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported. Single-input Selector Units are ignored.
+ */
+static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
+ struct uvc_entity *entity)
+{
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case UVC_VC_EXTENSION_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- XU %d", entity->id);
+
+ if (entity->bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+ "than 1 input pin.\n", entity->id);
+ return -1;
+ }
+
+ break;
+
+ case UVC_VC_PROCESSING_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- PU %d", entity->id);
+
+ if (chain->processing != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+ "Processing Units in chain.\n");
+ return -1;
+ }
+
+ chain->processing = entity;
+ break;
+
+ case UVC_VC_SELECTOR_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- SU %d", entity->id);
+
+ /* Single-input selector units are ignored. */
+ if (entity->bNrInPins == 1)
+ break;
+
+ if (chain->selector != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+ "Units in chain.\n");
+ return -1;
+ }
+
+ chain->selector = entity;
+ break;
+
+ case UVC_ITT_VENDOR_SPECIFIC:
+ case UVC_ITT_CAMERA:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+
+ break;
+
+ case UVC_OTT_VENDOR_SPECIFIC:
+ case UVC_OTT_DISPLAY:
+ case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" OT %d", entity->id);
+
+ break;
+
+ case UVC_TT_STREAMING:
+ if (UVC_ENTITY_IS_ITERM(entity)) {
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+ } else {
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" OT %d", entity->id);
+ }
+
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+ "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
+ return -1;
+ }
+
+ list_add_tail(&entity->chain, &chain->entities);
+ return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
+ struct uvc_entity *entity, struct uvc_entity *prev)
+{
+ struct uvc_entity *forward;
+ int found;
+
+ /* Forward scan */
+ forward = NULL;
+ found = 0;
+
+ while (1) {
+ forward = uvc_entity_by_reference(chain->dev, entity->id,
+ forward);
+ if (forward == NULL)
+ break;
+ if (forward == prev)
+ continue;
+
+ switch (UVC_ENTITY_TYPE(forward)) {
+ case UVC_VC_EXTENSION_UNIT:
+ if (forward->bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
+ "has more than 1 input pin.\n",
+ entity->id);
+ return -EINVAL;
+ }
+
+ list_add_tail(&forward->chain, &chain->entities);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (->");
+
+ printk(" XU %d", forward->id);
+ found = 1;
+ }
+ break;
+
+ case UVC_OTT_VENDOR_SPECIFIC:
+ case UVC_OTT_DISPLAY:
+ case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+ case UVC_TT_STREAMING:
+ if (UVC_ENTITY_IS_ITERM(forward)) {
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+ "terminal %u.\n", forward->id);
+ return -EINVAL;
+ }
+
+ list_add_tail(&forward->chain, &chain->entities);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (->");
+
+ printk(" OT %d", forward->id);
+ found = 1;
+ }
+ break;
+ }
+ }
+ if (found)
+ printk(")");
+
+ return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
+ struct uvc_entity **_entity)
+{
+ struct uvc_entity *entity = *_entity;
+ struct uvc_entity *term;
+ int id = -EINVAL, i;
+
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case UVC_VC_EXTENSION_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
+ id = entity->baSourceID[0];
+ break;
+
+ case UVC_VC_SELECTOR_UNIT:
+ /* Single-input selector units are ignored. */
+ if (entity->bNrInPins == 1) {
+ id = entity->baSourceID[0];
+ break;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT");
+
+ chain->selector = entity;
+ for (i = 0; i < entity->bNrInPins; ++i) {
+ id = entity->baSourceID[i];
+ term = uvc_entity_by_id(chain->dev, id);
+ if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+ uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+ "input %d isn't connected to an "
+ "input terminal\n", entity->id, i);
+ return -1;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" %d", term->id);
+
+ list_add_tail(&term->chain, &chain->entities);
+ uvc_scan_chain_forward(chain, term, entity);
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk("\n");
+
+ id = 0;
+ break;
+
+ case UVC_ITT_VENDOR_SPECIFIC:
+ case UVC_ITT_CAMERA:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_OTT_VENDOR_SPECIFIC:
+ case UVC_OTT_DISPLAY:
+ case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+ case UVC_TT_STREAMING:
+ id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
+ break;
+ }
+
+ if (id <= 0) {
+ *_entity = NULL;
+ return id;
+ }
+
+ entity = uvc_entity_by_id(chain->dev, id);
+ if (entity == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "unknown entity %d.\n", id);
+ return -EINVAL;
+ }
+
+ *_entity = entity;
+ return 0;
+}
+
+static int uvc_scan_chain(struct uvc_video_chain *chain,
+ struct uvc_entity *term)
+{
+ struct uvc_entity *entity, *prev;
+
+ uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
+
+ entity = term;
+ prev = NULL;
+
+ while (entity != NULL) {
+ /* Entity must not be part of an existing chain */
+ if (entity->chain.next || entity->chain.prev) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "entity %d already in chain.\n", entity->id);
+ return -EINVAL;
+ }
+
+ /* Process entity */
+ if (uvc_scan_chain_entity(chain, entity) < 0)
+ return -EINVAL;
+
+ /* Forward scan */
+ if (uvc_scan_chain_forward(chain, entity, prev) < 0)
+ return -EINVAL;
+
+ /* Backward scan */
+ prev = entity;
+ if (uvc_scan_chain_backward(chain, &entity) < 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned int uvc_print_terms(struct list_head *terms, u16 dir,
+ char *buffer)
+{
+ struct uvc_entity *term;
+ unsigned int nterms = 0;
+ char *p = buffer;
+
+ list_for_each_entry(term, terms, chain) {
+ if (!UVC_ENTITY_IS_TERM(term) ||
+ UVC_TERM_DIRECTION(term) != dir)
+ continue;
+
+ if (nterms)
+ p += sprintf(p, ",");
+ if (++nterms >= 4) {
+ p += sprintf(p, "...");
+ break;
+ }
+ p += sprintf(p, "%u", term->id);
+ }
+
+ return p - buffer;
+}
+
+static const char *uvc_print_chain(struct uvc_video_chain *chain)
+{
+ static char buffer[43];
+ char *p = buffer;
+
+ p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p);
+ p += sprintf(p, " -> ");
+ uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p);
+
+ return buffer;
+}
+
+/*
+ * Scan the device for video chains and register video devices.
+ *
+ * Chains are scanned starting at their output terminals and walked backwards.
+ */
+static int uvc_scan_device(struct uvc_device *dev)
+{
+ struct uvc_video_chain *chain;
+ struct uvc_entity *term;
+
+ list_for_each_entry(term, &dev->entities, list) {
+ if (!UVC_ENTITY_IS_OTERM(term))
+ continue;
+
+ /* If the terminal is already included in a chain, skip it.
+ * This can happen for chains that have multiple output
+ * terminals, where all output terminals beside the first one
+ * will be inserted in the chain in forward scans.
+ */
+ if (term->chain.next || term->chain.prev)
+ continue;
+
+ chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+ if (chain == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&chain->entities);
+ mutex_init(&chain->ctrl_mutex);
+ chain->dev = dev;
+
+ if (uvc_scan_chain(chain, term) < 0) {
+ kfree(chain);
+ continue;
+ }
+
+ uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
+ uvc_print_chain(chain));
+
+ list_add_tail(&chain->list, &dev->chains);
+ }
+
+ if (list_empty(&dev->chains)) {
+ uvc_printk(KERN_INFO, "No valid video chain found.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device registration and unregistration
+ */
+
+/*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+static void uvc_delete(struct uvc_device *dev)
+{
+ struct list_head *p, *n;
+
+ usb_put_intf(dev->intf);
+ usb_put_dev(dev->udev);
+
+ uvc_status_cleanup(dev);
+ uvc_ctrl_cleanup_device(dev);
+
+ if (dev->vdev.dev)
+ v4l2_device_unregister(&dev->vdev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (media_devnode_is_registered(&dev->mdev.devnode))
+ media_device_unregister(&dev->mdev);
+#endif
+
+ list_for_each_safe(p, n, &dev->chains) {
+ struct uvc_video_chain *chain;
+ chain = list_entry(p, struct uvc_video_chain, list);
+ kfree(chain);
+ }
+
+ list_for_each_safe(p, n, &dev->entities) {
+ struct uvc_entity *entity;
+ entity = list_entry(p, struct uvc_entity, list);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ uvc_mc_cleanup_entity(entity);
+#endif
+ if (entity->vdev) {
+ video_device_release(entity->vdev);
+ entity->vdev = NULL;
+ }
+ kfree(entity);
+ }
+
+ list_for_each_safe(p, n, &dev->streams) {
+ struct uvc_streaming *streaming;
+ streaming = list_entry(p, struct uvc_streaming, list);
+ usb_driver_release_interface(&uvc_driver.driver,
+ streaming->intf);
+ usb_put_intf(streaming->intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ }
+
+ kfree(dev);
+}
+
+static void uvc_release(struct video_device *vdev)
+{
+ struct uvc_streaming *stream = video_get_drvdata(vdev);
+ struct uvc_device *dev = stream->dev;
+
+ /* Decrement the registered streams count and delete the device when it
+ * reaches zero.
+ */
+ if (atomic_dec_and_test(&dev->nstreams))
+ uvc_delete(dev);
+}
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+ struct uvc_streaming *stream;
+
+ /* Unregistering all video devices might result in uvc_delete() being
+ * called from inside the loop if there's no open file handle. To avoid
+ * that, increment the stream count before iterating over the streams
+ * and decrement it when done.
+ */
+ atomic_inc(&dev->nstreams);
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->vdev == NULL)
+ continue;
+
+ video_unregister_device(stream->vdev);
+ stream->vdev = NULL;
+
+ uvc_debugfs_cleanup_stream(stream);
+ }
+
+ /* Decrement the stream count and call uvc_delete explicitly if there
+ * are no stream left.
+ */
+ if (atomic_dec_and_test(&dev->nstreams))
+ uvc_delete(dev);
+}
+
+static int uvc_register_video(struct uvc_device *dev,
+ struct uvc_streaming *stream)
+{
+ struct video_device *vdev;
+ int ret;
+
+ /* Initialize the streaming interface with default streaming
+ * parameters.
+ */
+ ret = uvc_video_init(stream);
+ if (ret < 0) {
+ uvc_printk(KERN_ERR, "Failed to initialize the device "
+ "(%d).\n", ret);
+ return ret;
+ }
+
+ uvc_debugfs_init_stream(stream);
+
+ /* Register the device with V4L. */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
+ ret);
+ return -ENOMEM;
+ }
+
+ /* We already hold a reference to dev->udev. The video device will be
+ * unregistered before the reference is released, so we don't need to
+ * get another one.
+ */
+ vdev->v4l2_dev = &dev->vdev;
+ vdev->fops = &uvc_fops;
+ vdev->release = uvc_release;
+ strlcpy(vdev->name, dev->name, sizeof vdev->name);
+
+ /* Set the driver data before calling video_register_device, otherwise
+ * uvc_v4l2_open might race us.
+ */
+ stream->vdev = vdev;
+ video_set_drvdata(vdev, stream);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
+ ret);
+ stream->vdev = NULL;
+ video_device_release(vdev);
+ return ret;
+ }
+
+ atomic_inc(&dev->nstreams);
+ return 0;
+}
+
+/*
+ * Register all video devices in all chains.
+ */
+static int uvc_register_terms(struct uvc_device *dev,
+ struct uvc_video_chain *chain)
+{
+ struct uvc_streaming *stream;
+ struct uvc_entity *term;
+ int ret;
+
+ list_for_each_entry(term, &chain->entities, chain) {
+ if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
+ continue;
+
+ stream = uvc_stream_by_id(dev, term->id);
+ if (stream == NULL) {
+ uvc_printk(KERN_INFO, "No streaming interface found "
+ "for terminal %u.", term->id);
+ continue;
+ }
+
+ stream->chain = chain;
+ ret = uvc_register_video(dev, stream);
+ if (ret < 0)
+ return ret;
+
+ term->vdev = stream->vdev;
+ }
+
+ return 0;
+}
+
+static int uvc_register_chains(struct uvc_device *dev)
+{
+ struct uvc_video_chain *chain;
+ int ret;
+
+ list_for_each_entry(chain, &dev->chains, list) {
+ ret = uvc_register_terms(dev, chain);
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ ret = uvc_mc_register_entities(chain);
+ if (ret < 0) {
+ uvc_printk(KERN_INFO, "Failed to register entites "
+ "(%d).\n", ret);
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe, disconnect, suspend and resume
+ */
+
+static int uvc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct uvc_device *dev;
+ int ret;
+
+ if (id->idVendor && id->idProduct)
+ uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
+ "(%04x:%04x)\n", udev->devpath, id->idVendor,
+ id->idProduct);
+ else
+ uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
+ udev->devpath);
+
+ /* Allocate memory for the device and initialize it. */
+ if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dev->entities);
+ INIT_LIST_HEAD(&dev->chains);
+ INIT_LIST_HEAD(&dev->streams);
+ atomic_set(&dev->nstreams, 0);
+ atomic_set(&dev->users, 0);
+ atomic_set(&dev->nmappings, 0);
+
+ dev->udev = usb_get_dev(udev);
+ dev->intf = usb_get_intf(intf);
+ dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->quirks = (uvc_quirks_param == -1)
+ ? id->driver_info : uvc_quirks_param;
+
+ if (udev->product != NULL)
+ strlcpy(dev->name, udev->product, sizeof dev->name);
+ else
+ snprintf(dev->name, sizeof dev->name,
+ "UVC Camera (%04x:%04x)",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ /* Parse the Video Class control descriptor. */
+ if (uvc_parse_control(dev) < 0) {
+ uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
+ "descriptors.\n");
+ goto error;
+ }
+
+ uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
+ dev->uvc_version >> 8, dev->uvc_version & 0xff,
+ udev->product ? udev->product : "<unnamed>",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ if (dev->quirks != id->driver_info) {
+ uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
+ "parameter for testing purpose.\n", dev->quirks);
+ uvc_printk(KERN_INFO, "Please report required quirks to the "
+ "linux-uvc-devel mailing list.\n");
+ }
+
+ /* Register the media and V4L2 devices. */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->mdev.dev = &intf->dev;
+ strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+ if (udev->serial)
+ strlcpy(dev->mdev.serial, udev->serial,
+ sizeof(dev->mdev.serial));
+ strcpy(dev->mdev.bus_info, udev->devpath);
+ dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ dev->mdev.driver_version = LINUX_VERSION_CODE;
+ if (media_device_register(&dev->mdev) < 0)
+ goto error;
+
+ dev->vdev.mdev = &dev->mdev;
+#endif
+ if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
+ goto error;
+
+ /* Initialize controls. */
+ if (uvc_ctrl_init_device(dev) < 0)
+ goto error;
+
+ /* Scan the device for video chains. */
+ if (uvc_scan_device(dev) < 0)
+ goto error;
+
+ /* Register video device nodes. */
+ if (uvc_register_chains(dev) < 0)
+ goto error;
+
+ /* Save our data pointer in the interface data. */
+ usb_set_intfdata(intf, dev);
+
+ /* Initialize the interrupt URB. */
+ if ((ret = uvc_status_init(dev)) < 0) {
+ uvc_printk(KERN_INFO, "Unable to initialize the status "
+ "endpoint (%d), status interrupt will not be "
+ "supported.\n", ret);
+ }
+
+ uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+ usb_enable_autosuspend(udev);
+ return 0;
+
+error:
+ uvc_unregister_video(dev);
+ return -ENODEV;
+}
+
+static void uvc_disconnect(struct usb_interface *intf)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+
+ /* Set the USB interface data to NULL. This can be done outside the
+ * lock, as there's no other reader.
+ */
+ usb_set_intfdata(intf, NULL);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOSTREAMING)
+ return;
+
+ dev->state |= UVC_DEV_DISCONNECTED;
+
+ uvc_unregister_video(dev);
+}
+
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+ struct uvc_streaming *stream;
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ /* Controls are cached on the fly so they don't need to be saved. */
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL)
+ return uvc_status_suspend(dev);
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->intf == intf)
+ return uvc_video_suspend(stream);
+ }
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
+ "mismatch.\n");
+ return -EINVAL;
+}
+
+static int __uvc_resume(struct usb_interface *intf, int reset)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+ struct uvc_streaming *stream;
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL) {
+ if (reset) {
+ int ret = uvc_ctrl_resume_device(dev);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return uvc_status_resume(dev);
+ }
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->intf == intf)
+ return uvc_video_resume(stream, reset);
+ }
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+ "mismatch.\n");
+ return -EINVAL;
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+ return __uvc_resume(intf, 0);
+}
+
+static int uvc_reset_resume(struct usb_interface *intf)
+{
+ return __uvc_resume(intf, 1);
+}
+
+/* ------------------------------------------------------------------------
+ * Module parameters
+ */
+
+static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ return sprintf(buffer, "CLOCK_MONOTONIC");
+ else
+ return sprintf(buffer, "CLOCK_REALTIME");
+}
+
+static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
+{
+ if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
+ val += strlen("clock_");
+
+ if (strcasecmp(val, "monotonic") == 0)
+ uvc_clock_param = CLOCK_MONOTONIC;
+ else if (strcasecmp(val, "realtime") == 0)
+ uvc_clock_param = CLOCK_REALTIME;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
+ &uvc_clock_param, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+
+/* ------------------------------------------------------------------------
+ * Driver initialization and cleanup
+ */
+
+/*
+ * The Logitech cameras listed below have their interface class set to
+ * VENDOR_SPEC because they don't announce themselves as UVC devices, even
+ * 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,
+ .idVendor = 0x0458,
+ .idProduct = 0x706e,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam NX-6000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x00f8,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam VX-7000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x0723,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Logitech Quickcam Fusion */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c1,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Orbit MP */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro for Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c3,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro 5000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c5,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Dell Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c6,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Cisco VT Camera II */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c7,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Chicony CNF7129 (Asus EEE 100HE) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb071,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE },
+ /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x058f,
+ .idProduct = 0x3820,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .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,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8501,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_BUILTIN_ISIGHT },
+ /* Foxlink ("HP Webcam" on HP Mini 5103) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05c8,
+ .idProduct = 0x0403,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* Genesys Logic USB 2.0 PC Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05e3,
+ .idProduct = 0x0505,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Hercules Classic Silver */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x06f8,
+ .idProduct = 0x300c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* ViMicro Vega */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x332d,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* ViMicro - Minoru3D */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x3410,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* ViMicro Venus - Minoru3D */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x3420,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* Ophir Optronics - SPCAM 620U */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0bd3,
+ .idProduct = 0x0555,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* MT6227 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0e8d,
+ .idProduct = 0x0004,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_DEF },
+ /* IMC Networks (Medion Akoya) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x13d3,
+ .idProduct = 0x5103,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* JMicron USB2.0 XGA WebCam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x152d,
+ .idProduct = 0x0310,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Syntek (HP Spartan) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x5212,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Samsung Q310) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x5931,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Packard Bell EasyNote MX52 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a12,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Asus F9SG) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a31,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Asus U3S) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a33,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (JAOtech Smart Terminal) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a34,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Miricle 307K */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x17dc,
+ .idProduct = 0x0202,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Lenovo Thinkpad SL400/SL500 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x17ef,
+ .idProduct = 0x480b,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Aveo Technology USB 2.0 Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1871,
+ .idProduct = 0x0306,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Ecamm Pico iMage */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18cd,
+ .idProduct = 0xcafe,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Manta MM-353 Plako */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3188,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* FSC WebCam V30S */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3288,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Arkmicro unbranded */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3290,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
+ /* The Imaging Source USB CCD cameras */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x199e,
+ .idProduct = 0x8102,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Bodelin ProScopeHR */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_DEV_HI
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x19ab,
+ .idProduct = 0x1000,
+ .bcdDevice_hi = 0x0126,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STATUS_INTERVAL },
+ /* MSI StarCam 370i */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1b3b,
+ .idProduct = 0x2951,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* SiGma Micro USB Web Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1c4f,
+ .idProduct = 0x3000,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
+ /* Generic USB Video Class */
+ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, uvc_ids);
+
+struct uvc_driver uvc_driver = {
+ .driver = {
+ .name = "uvcvideo",
+ .probe = uvc_probe,
+ .disconnect = uvc_disconnect,
+ .suspend = uvc_suspend,
+ .resume = uvc_resume,
+ .reset_resume = uvc_reset_resume,
+ .id_table = uvc_ids,
+ .supports_autosuspend = 1,
+ },
+};
+
+static int __init uvc_init(void)
+{
+ int ret;
+
+ uvc_debugfs_init();
+
+ 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);
+module_exit(uvc_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index 29e239911d0e..29e239911d0e 100644
--- a/drivers/media/video/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c
index 8510e7259e76..8510e7259e76 100644
--- a/drivers/media/video/uvc/uvc_isight.c
+++ b/drivers/media/usb/uvc/uvc_isight.c
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 5577381b5bf0..5577381b5bf0 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index b7492775e6ae..b7492775e6ae 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index f00db3060e0e..f00db3060e0e 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
new file mode 100644
index 000000000000..1c15b4227bdb
--- /dev/null
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -0,0 +1,1879 @@
+/*
+ * uvc_video.c -- USB Video Class driver - Video handling
+ *
+ * Copyright (C) 2005-2010
+ * 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/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/atomic.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size,
+ int timeout)
+{
+ __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ unsigned int pipe;
+
+ pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
+ : usb_sndctrlpipe(dev->udev, 0);
+ type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+ return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+ unit << 8 | intfnum, data, size, timeout);
+}
+
+static const char *uvc_query_name(__u8 query)
+{
+ switch (query) {
+ case UVC_SET_CUR:
+ return "SET_CUR";
+ case UVC_GET_CUR:
+ return "GET_CUR";
+ case UVC_GET_MIN:
+ return "GET_MIN";
+ case UVC_GET_MAX:
+ return "GET_MAX";
+ case UVC_GET_RES:
+ return "GET_RES";
+ case UVC_GET_LEN:
+ return "GET_LEN";
+ case UVC_GET_INFO:
+ return "GET_INFO";
+ case UVC_GET_DEF:
+ return "GET_DEF";
+ default:
+ return "<invalid>";
+ }
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+ int ret;
+
+ ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+ UVC_CTRL_CONTROL_TIMEOUT);
+ if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
+ "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
+ unit, ret, size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
+ struct uvc_streaming_control *ctrl)
+{
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ unsigned int i;
+
+ for (i = 0; i < stream->nformats; ++i) {
+ if (stream->format[i].index == ctrl->bFormatIndex) {
+ format = &stream->format[i];
+ break;
+ }
+ }
+
+ if (format == NULL)
+ return;
+
+ for (i = 0; i < format->nframes; ++i) {
+ if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
+
+ if (frame == NULL)
+ return;
+
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ (ctrl->dwMaxVideoFrameSize == 0 &&
+ stream->dev->uvc_version < 0x0110))
+ ctrl->dwMaxVideoFrameSize =
+ frame->dwMaxVideoFrameBufferSize;
+
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) &&
+ stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+ stream->intf->num_altsetting > 1) {
+ u32 interval;
+ u32 bandwidth;
+
+ interval = (ctrl->dwFrameInterval > 100000)
+ ? ctrl->dwFrameInterval
+ : frame->dwFrameInterval[0];
+
+ /* Compute a bandwidth estimation by multiplying the frame
+ * size by the number of video frames per second, divide the
+ * result by the number of USB frames (or micro-frames for
+ * high-speed devices) per second and add the UVC header size
+ * (assumed to be 12 bytes long).
+ */
+ bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
+ bandwidth *= 10000000 / interval + 1;
+ bandwidth /= 1000;
+ if (stream->dev->udev->speed == USB_SPEED_HIGH)
+ bandwidth /= 8;
+ bandwidth += 12;
+
+ /* The bandwidth estimate is too low for many cameras. Don't use
+ * maximum packet sizes lower than 1024 bytes to try and work
+ * around the problem. According to measurements done on two
+ * different camera models, the value is high enough to get most
+ * resolutions working while not preventing two simultaneous
+ * VGA streams at 15 fps.
+ */
+ bandwidth = max_t(u32, bandwidth, 1024);
+
+ ctrl->dwMaxPayloadTransferSize = bandwidth;
+ }
+}
+
+static int uvc_get_video_ctrl(struct uvc_streaming *stream,
+ struct uvc_streaming_control *ctrl, int probe, __u8 query)
+{
+ __u8 *data;
+ __u16 size;
+ int ret;
+
+ size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
+ if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) &&
+ query == UVC_GET_DEF)
+ return -EIO;
+
+ data = kmalloc(size, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, uvc_timeout_param);
+
+ if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
+ /* Some cameras, mostly based on Bison Electronics chipsets,
+ * answer a GET_MIN or GET_MAX request with the wCompQuality
+ * field only.
+ */
+ uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
+ "compliance - GET_MIN/MAX(PROBE) incorrectly "
+ "supported. Enabling workaround.\n");
+ memset(ctrl, 0, sizeof *ctrl);
+ ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
+ ret = 0;
+ goto out;
+ } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
+ /* Many cameras don't support the GET_DEF request on their
+ * video probe control. Warn once and return, the caller will
+ * fall back to GET_CUR.
+ */
+ uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
+ "compliance - GET_DEF(PROBE) not supported. "
+ "Enabling workaround.\n");
+ ret = -EIO;
+ goto out;
+ } else if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
+ "%d (exp. %u).\n", query, probe ? "probe" : "commit",
+ ret, size);
+ ret = -EIO;
+ goto out;
+ }
+
+ ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
+ ctrl->bFormatIndex = data[2];
+ ctrl->bFrameIndex = data[3];
+ ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
+ ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
+ ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
+ ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
+ ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
+ ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
+ ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
+ ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
+
+ if (size == 34) {
+ ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
+ ctrl->bmFramingInfo = data[30];
+ ctrl->bPreferedVersion = data[31];
+ ctrl->bMinVersion = data[32];
+ ctrl->bMaxVersion = data[33];
+ } else {
+ ctrl->dwClockFrequency = stream->dev->clock_frequency;
+ ctrl->bmFramingInfo = 0;
+ ctrl->bPreferedVersion = 0;
+ ctrl->bMinVersion = 0;
+ ctrl->bMaxVersion = 0;
+ }
+
+ /* Some broken devices return null or wrong dwMaxVideoFrameSize and
+ * dwMaxPayloadTransferSize fields. Try to get the value from the
+ * format and frame descriptors.
+ */
+ uvc_fixup_video_ctrl(stream, ctrl);
+ ret = 0;
+
+out:
+ kfree(data);
+ return ret;
+}
+
+static int uvc_set_video_ctrl(struct uvc_streaming *stream,
+ struct uvc_streaming_control *ctrl, int probe)
+{
+ __u8 *data;
+ __u16 size;
+ int ret;
+
+ size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
+ data = kzalloc(size, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
+ data[2] = ctrl->bFormatIndex;
+ data[3] = ctrl->bFrameIndex;
+ *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
+ *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
+ *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
+ *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
+ *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
+ *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
+ put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
+ put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
+
+ if (size == 34) {
+ put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
+ data[30] = ctrl->bmFramingInfo;
+ data[31] = ctrl->bPreferedVersion;
+ data[32] = ctrl->bMinVersion;
+ data[33] = ctrl->bMaxVersion;
+ }
+
+ ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, uvc_timeout_param);
+ if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
+ "%d (exp. %u).\n", probe ? "probe" : "commit",
+ ret, size);
+ ret = -EIO;
+ }
+
+ kfree(data);
+ return ret;
+}
+
+int uvc_probe_video(struct uvc_streaming *stream,
+ struct uvc_streaming_control *probe)
+{
+ struct uvc_streaming_control probe_min, probe_max;
+ __u16 bandwidth;
+ unsigned int i;
+ int ret;
+
+ /* Perform probing. The device should adjust the requested values
+ * according to its capabilities. However, some devices, namely the
+ * first generation UVC Logitech webcams, don't implement the Video
+ * Probe control properly, and just return the needed bandwidth. For
+ * that reason, if the needed bandwidth exceeds the maximum available
+ * bandwidth, try to lower the quality.
+ */
+ ret = uvc_set_video_ctrl(stream, probe, 1);
+ if (ret < 0)
+ goto done;
+
+ /* Get the minimum and maximum values for compression settings. */
+ if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+ ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
+ if (ret < 0)
+ goto done;
+
+ probe->wCompQuality = probe_max.wCompQuality;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ ret = uvc_set_video_ctrl(stream, probe, 1);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
+ goto done;
+
+ if (stream->intf->num_altsetting == 1)
+ break;
+
+ bandwidth = probe->dwMaxPayloadTransferSize;
+ if (bandwidth <= stream->maxpsize)
+ break;
+
+ if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+ ret = -ENOSPC;
+ goto done;
+ }
+
+ /* TODO: negotiate compression parameters */
+ probe->wKeyFrameRate = probe_min.wKeyFrameRate;
+ probe->wPFrameRate = probe_min.wPFrameRate;
+ probe->wCompQuality = probe_max.wCompQuality;
+ probe->wCompWindowSize = probe_min.wCompWindowSize;
+ }
+
+done:
+ return ret;
+}
+
+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);
+}
+
+/* ------------------------------------------------------------------------
+ * Stream statistics
+ */
+
+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().
+ *
+ * uvc_video_decode_start is called with URB data at the start of a bulk or
+ * isochronous payload. It processes header data and returns the header size
+ * in bytes if successful. If an error occurs, it returns a negative error
+ * code. The following error codes have special meanings.
+ *
+ * - EAGAIN informs the caller that the current video buffer should be marked
+ * as done, and that the function should be called again with the same data
+ * and a new video buffer. This is used when end of frame conditions can be
+ * reliably detected at the beginning of the next frame only.
+ *
+ * If an error other than -EAGAIN is returned, the caller will drop the current
+ * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
+ * made until the next payload. -ENODATA can be used to drop the current
+ * payload if no other error code is appropriate.
+ *
+ * uvc_video_decode_data is called for every URB with URB data. It copies the
+ * data to the video buffer.
+ *
+ * uvc_video_decode_end is called with header data at the end of a bulk or
+ * isochronous payload. It performs any additional header data processing and
+ * returns 0 or a negative error code if an error occurred. As header data have
+ * already been processed by uvc_video_decode_start, this functions isn't
+ * required to perform sanity checks a second time.
+ *
+ * For isochronous transfers where a payload is always transferred in a single
+ * URB, the three functions will be called in a row.
+ *
+ * To let the decoder process header data and update its internal state even
+ * when no video buffer is available, uvc_video_decode_start must be prepared
+ * to be called with a NULL buf parameter. uvc_video_decode_data and
+ * uvc_video_decode_end will never be called with a NULL buffer.
+ */
+static int uvc_video_decode_start(struct uvc_streaming *stream,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ __u8 fid;
+
+ /* Sanity checks:
+ * - packet must be at least 2 bytes long
+ * - 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) {
+ stream->stats.frame.nb_invalid++;
+ return -EINVAL;
+ }
+
+ fid = data[1] & UVC_STREAM_FID;
+
+ /* Increase the sequence number regardless of any buffer states, so
+ * that discontinuous sequence numbers always indicate lost frames.
+ */
+ 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.
+ */
+ if (buf == NULL) {
+ stream->last_fid = fid;
+ 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
+ * frame will always be in sync.
+ *
+ * If the device doesn't toggle the FID bit, invert stream->last_fid
+ * when the EOF bit is set to force synchronisation on the next packet.
+ */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ struct timespec ts;
+
+ if (fid == stream->last_fid) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
+ "sync).\n");
+ if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+ (data[1] & UVC_STREAM_EOF))
+ stream->last_fid ^= UVC_STREAM_FID;
+ return -ENODATA;
+ }
+
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(&ts);
+ else
+ ktime_get_real_ts(&ts);
+
+ 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;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ * End of frame detection is better implemented by checking the EOF
+ * bit (FID bit toggling is delayed by one frame compared to the EOF
+ * bit), but some devices don't set the bit at end of frame (and the
+ * last payload can be lost anyway). We thus must check if the FID has
+ * been toggled.
+ *
+ * stream->last_fid is initialized to -1, so the first isochronous
+ * frame will never trigger an end of frame detection.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer. This also
+ * avoids detecting end of frame conditions at FID toggling if the
+ * previous payload had the EOF bit set.
+ */
+ 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;
+ return -EAGAIN;
+ }
+
+ stream->last_fid = fid;
+
+ return data[0];
+}
+
+static void uvc_video_decode_data(struct uvc_streaming *stream,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ unsigned int maxlen, nbytes;
+ void *mem;
+
+ if (len <= 0)
+ return;
+
+ /* Copy the video data to the buffer. */
+ maxlen = buf->length - buf->bytesused;
+ mem = buf->mem + buf->bytesused;
+ nbytes = min((unsigned int)len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->bytesused += nbytes;
+
+ /* Complete the current frame if the buffer size was exceeded. */
+ if (len > maxlen) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+ buf->state = UVC_BUF_STATE_READY;
+ }
+}
+
+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->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");
+ buf->state = UVC_BUF_STATE_READY;
+ if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+ stream->last_fid ^= UVC_STREAM_FID;
+ }
+}
+
+/* Video payload encoding is handled by uvc_video_encode_header() and
+ * uvc_video_encode_data(). Only bulk transfers are currently supported.
+ *
+ * uvc_video_encode_header is called at the start of a payload. It adds header
+ * data to the transfer buffer and returns the header size. As the only known
+ * UVC output device transfers a whole frame in a single payload, the EOF bit
+ * is always set in the header.
+ *
+ * uvc_video_encode_data is called for every URB and copies the data from the
+ * video buffer to the transfer buffer.
+ */
+static int uvc_video_encode_header(struct uvc_streaming *stream,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ data[0] = 2; /* Header length */
+ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
+ | (stream->last_fid & UVC_STREAM_FID);
+ return 2;
+}
+
+static int uvc_video_encode_data(struct uvc_streaming *stream,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ struct uvc_video_queue *queue = &stream->queue;
+ unsigned int nbytes;
+ void *mem;
+
+ /* Copy video data to the URB buffer. */
+ 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);
+
+ queue->buf_used += nbytes;
+
+ return nbytes;
+}
+
+/* ------------------------------------------------------------------------
+ * URB handling
+ */
+
+/*
+ * Completion handler for video URBs.
+ */
+static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int ret, i;
+
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+ "lost (%d).\n", urb->iso_frame_desc[i].status);
+ /* Mark the buffer as faulty. */
+ if (buf != NULL)
+ buf->error = 1;
+ continue;
+ }
+
+ /* Decode the payload header. */
+ mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ do {
+ ret = uvc_video_decode_start(stream, buf, mem,
+ urb->iso_frame_desc[i].actual_length);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
+ } while (ret == -EAGAIN);
+
+ if (ret < 0)
+ continue;
+
+ /* Decode the payload data. */
+ uvc_video_decode_data(stream, buf, mem + ret,
+ urb->iso_frame_desc[i].actual_length - ret);
+
+ /* Process the header again. */
+ uvc_video_decode_end(stream, buf, mem,
+ urb->iso_frame_desc[i].actual_length);
+
+ if (buf->state == UVC_BUF_STATE_READY) {
+ if (buf->length != buf->bytesused &&
+ !(stream->cur_format->flags &
+ UVC_FMT_FLAG_COMPRESSED))
+ buf->error = 1;
+
+ buf = uvc_queue_next_buffer(&stream->queue, buf);
+ }
+ }
+}
+
+static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int len, ret;
+
+ /*
+ * Ignore ZLPs if they're not part of a frame, otherwise process them
+ * to trigger the end of payload detection.
+ */
+ if (urb->actual_length == 0 && stream->bulk.header_size == 0)
+ return;
+
+ mem = urb->transfer_buffer;
+ len = urb->actual_length;
+ stream->bulk.payload_size += len;
+
+ /* If the URB is the first of its payload, decode and save the
+ * header.
+ */
+ if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
+ do {
+ ret = uvc_video_decode_start(stream, buf, mem, len);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
+ } while (ret == -EAGAIN);
+
+ /* If an error occurred skip the rest of the payload. */
+ if (ret < 0 || buf == NULL) {
+ stream->bulk.skip_payload = 1;
+ } else {
+ memcpy(stream->bulk.header, mem, ret);
+ stream->bulk.header_size = ret;
+
+ mem += ret;
+ len -= ret;
+ }
+ }
+
+ /* The buffer queue might have been cancelled while a bulk transfer
+ * was in progress, so we can reach here with buf equal to NULL. Make
+ * sure buf is never dereferenced if NULL.
+ */
+
+ /* Process video data. */
+ if (!stream->bulk.skip_payload && buf != NULL)
+ uvc_video_decode_data(stream, buf, mem, len);
+
+ /* Detect the payload end by a URB smaller than the maximum size (or
+ * a payload size equal to the maximum) and process the header again.
+ */
+ if (urb->actual_length < urb->transfer_buffer_length ||
+ stream->bulk.payload_size >= stream->bulk.max_payload_size) {
+ if (!stream->bulk.skip_payload && buf != NULL) {
+ uvc_video_decode_end(stream, buf, stream->bulk.header,
+ stream->bulk.payload_size);
+ if (buf->state == UVC_BUF_STATE_READY)
+ buf = uvc_queue_next_buffer(&stream->queue,
+ buf);
+ }
+
+ stream->bulk.header_size = 0;
+ stream->bulk.skip_payload = 0;
+ stream->bulk.payload_size = 0;
+ }
+}
+
+static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
+{
+ u8 *mem = urb->transfer_buffer;
+ int len = stream->urb_size, ret;
+
+ if (buf == NULL) {
+ urb->transfer_buffer_length = 0;
+ return;
+ }
+
+ /* If the URB is the first of its payload, add the header. */
+ if (stream->bulk.header_size == 0) {
+ ret = uvc_video_encode_header(stream, buf, mem, len);
+ stream->bulk.header_size = ret;
+ stream->bulk.payload_size += ret;
+ mem += ret;
+ len -= ret;
+ }
+
+ /* Process video data. */
+ ret = uvc_video_encode_data(stream, buf, mem, len);
+
+ stream->bulk.payload_size += ret;
+ len -= ret;
+
+ if (buf->bytesused == stream->queue.buf_used ||
+ stream->bulk.payload_size == stream->bulk.max_payload_size) {
+ if (buf->bytesused == stream->queue.buf_used) {
+ stream->queue.buf_used = 0;
+ buf->state = UVC_BUF_STATE_READY;
+ buf->buf.v4l2_buf.sequence = ++stream->sequence;
+ uvc_queue_next_buffer(&stream->queue, buf);
+ stream->last_fid ^= UVC_STREAM_FID;
+ }
+
+ stream->bulk.header_size = 0;
+ stream->bulk.payload_size = 0;
+ }
+
+ urb->transfer_buffer_length = stream->urb_size - len;
+}
+
+static void uvc_video_complete(struct urb *urb)
+{
+ struct uvc_streaming *stream = urb->context;
+ struct uvc_video_queue *queue = &stream->queue;
+ struct uvc_buffer *buf = NULL;
+ unsigned long flags;
+ int ret;
+
+ switch (urb->status) {
+ case 0:
+ break;
+
+ default:
+ uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
+ "completion handler.\n", urb->status);
+
+ case -ENOENT: /* usb_kill_urb() called. */
+ if (stream->frozen)
+ return;
+
+ case -ECONNRESET: /* usb_unlink_urb() called. */
+ case -ESHUTDOWN: /* The endpoint is being disabled. */
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (!list_empty(&queue->irqqueue))
+ buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ stream->decode(urb, stream, buf);
+
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+}
+
+/*
+ * Free transfer buffers.
+ */
+static void uvc_free_urb_buffers(struct uvc_streaming *stream)
+{
+ unsigned int i;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (stream->urb_buffer[i]) {
+#ifndef CONFIG_DMA_NONCOHERENT
+ usb_free_coherent(stream->dev->udev, stream->urb_size,
+ stream->urb_buffer[i], stream->urb_dma[i]);
+#else
+ kfree(stream->urb_buffer[i]);
+#endif
+ stream->urb_buffer[i] = NULL;
+ }
+ }
+
+ stream->urb_size = 0;
+}
+
+/*
+ * Allocate transfer buffers. This function can be called with buffers
+ * already allocated when resuming from suspend, in which case it will
+ * return without touching the buffers.
+ *
+ * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
+ * system is too low on memory try successively smaller numbers of packets
+ * until allocation succeeds.
+ *
+ * Return the number of allocated packets on success or 0 when out of memory.
+ */
+static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
+ unsigned int size, unsigned int psize, gfp_t gfp_flags)
+{
+ unsigned int npackets;
+ unsigned int i;
+
+ /* Buffers are already allocated, bail out. */
+ if (stream->urb_size)
+ return stream->urb_size / psize;
+
+ /* Compute the number of packets. Bulk endpoints might transfer UVC
+ * payloads across multiple URBs.
+ */
+ npackets = DIV_ROUND_UP(size, psize);
+ if (npackets > UVC_MAX_PACKETS)
+ npackets = UVC_MAX_PACKETS;
+
+ /* Retry allocations until one succeed. */
+ for (; npackets > 1; npackets /= 2) {
+ for (i = 0; i < UVC_URBS; ++i) {
+ stream->urb_size = psize * npackets;
+#ifndef CONFIG_DMA_NONCOHERENT
+ stream->urb_buffer[i] = usb_alloc_coherent(
+ stream->dev->udev, stream->urb_size,
+ gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+#else
+ stream->urb_buffer[i] =
+ kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
+#endif
+ if (!stream->urb_buffer[i]) {
+ uvc_free_urb_buffers(stream);
+ break;
+ }
+ }
+
+ if (i == UVC_URBS) {
+ uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
+ "of %ux%u bytes each.\n", UVC_URBS, npackets,
+ psize);
+ return npackets;
+ }
+ }
+
+ uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes "
+ "per packet).\n", psize);
+ return 0;
+}
+
+/*
+ * Uninitialize isochronous/bulk URBs and free transfer buffers.
+ */
+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)
+ continue;
+
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ stream->urb[i] = NULL;
+ }
+
+ if (free_buffers)
+ uvc_free_urb_buffers(stream);
+}
+
+/*
+ * Compute the maximum number of bytes per interval for an endpoint.
+ */
+static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
+ struct usb_host_endpoint *ep)
+{
+ u16 psize;
+
+ switch (dev->speed) {
+ case USB_SPEED_SUPER:
+ return ep->ss_ep_comp.wBytesPerInterval;
+ case USB_SPEED_HIGH:
+ psize = usb_endpoint_maxp(&ep->desc);
+ return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ default:
+ psize = usb_endpoint_maxp(&ep->desc);
+ return psize & 0x07ff;
+ }
+}
+
+/*
+ * Initialize isochronous URBs and allocate transfer buffers. The packet size
+ * is given by the endpoint.
+ */
+static int uvc_init_video_isoc(struct uvc_streaming *stream,
+ struct usb_host_endpoint *ep, gfp_t gfp_flags)
+{
+ struct urb *urb;
+ unsigned int npackets, i, j;
+ u16 psize;
+ u32 size;
+
+ psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
+ size = stream->ctrl.dwMaxVideoFrameSize;
+
+ npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
+ if (npackets == 0)
+ return -ENOMEM;
+
+ size = npackets * psize;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(npackets, gfp_flags);
+ if (urb == NULL) {
+ uvc_uninit_video(stream, 1);
+ return -ENOMEM;
+ }
+
+ urb->dev = stream->dev->udev;
+ urb->context = stream;
+ urb->pipe = usb_rcvisocpipe(stream->dev->udev,
+ ep->desc.bEndpointAddress);
+#ifndef CONFIG_DMA_NONCOHERENT
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_dma = stream->urb_dma[i];
+#else
+ urb->transfer_flags = URB_ISO_ASAP;
+#endif
+ urb->interval = ep->desc.bInterval;
+ urb->transfer_buffer = stream->urb_buffer[i];
+ urb->complete = uvc_video_complete;
+ urb->number_of_packets = npackets;
+ urb->transfer_buffer_length = size;
+
+ for (j = 0; j < npackets; ++j) {
+ urb->iso_frame_desc[j].offset = j * psize;
+ urb->iso_frame_desc[j].length = psize;
+ }
+
+ stream->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize bulk URBs and allocate transfer buffers. The packet size is
+ * given by the endpoint.
+ */
+static int uvc_init_video_bulk(struct uvc_streaming *stream,
+ struct usb_host_endpoint *ep, gfp_t gfp_flags)
+{
+ struct urb *urb;
+ unsigned int npackets, pipe, i;
+ u16 psize;
+ u32 size;
+
+ psize = usb_endpoint_maxp(&ep->desc) & 0x7ff;
+ size = stream->ctrl.dwMaxPayloadTransferSize;
+ stream->bulk.max_payload_size = size;
+
+ npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
+ if (npackets == 0)
+ return -ENOMEM;
+
+ size = npackets * psize;
+
+ if (usb_endpoint_dir_in(&ep->desc))
+ pipe = usb_rcvbulkpipe(stream->dev->udev,
+ ep->desc.bEndpointAddress);
+ else
+ pipe = usb_sndbulkpipe(stream->dev->udev,
+ ep->desc.bEndpointAddress);
+
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ size = 0;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(0, gfp_flags);
+ if (urb == NULL) {
+ uvc_uninit_video(stream, 1);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
+ stream->urb_buffer[i], size, uvc_video_complete,
+ stream);
+#ifndef CONFIG_DMA_NONCOHERENT
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_dma = stream->urb_dma[i];
+#endif
+
+ stream->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize isochronous/bulk URBs and allocate transfer buffers.
+ */
+static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
+{
+ struct usb_interface *intf = stream->intf;
+ struct usb_host_endpoint *ep;
+ unsigned int i;
+ int ret;
+
+ stream->sequence = -1;
+ stream->last_fid = -1;
+ stream->bulk.header_size = 0;
+ 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 = UINT_MAX;
+ unsigned int bandwidth;
+ unsigned int uninitialized_var(altsetting);
+ int intfnum = stream->intfnum;
+
+ /* Isochronous endpoint, select the alternate setting. */
+ bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
+
+ if (bandwidth == 0) {
+ uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
+ "bandwidth, defaulting to lowest.\n");
+ bandwidth = 1;
+ } else {
+ uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
+ "B/frame bandwidth.\n", bandwidth);
+ }
+
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_interface *alts;
+ unsigned int psize;
+
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ stream->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ /* Check if the bandwidth is high enough. */
+ psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
+ if (psize >= bandwidth && psize <= best_psize) {
+ altsetting = alts->desc.bAlternateSetting;
+ best_psize = psize;
+ best_ep = ep;
+ }
+ }
+
+ if (best_ep == NULL) {
+ uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
+ "for requested bandwidth.\n");
+ return -EIO;
+ }
+
+ uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
+ "(%u B/frame bandwidth).\n", altsetting, best_psize);
+
+ ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
+ if (ret < 0)
+ return ret;
+
+ ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
+ } else {
+ /* Bulk endpoint, proceed to URB initialization. */
+ ep = uvc_find_endpoint(&intf->altsetting[0],
+ stream->header.bEndpointAddress);
+ if (ep == NULL)
+ return -EIO;
+
+ ret = uvc_init_video_bulk(stream, ep, gfp_flags);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Submit the URBs. */
+ for (i = 0; i < UVC_URBS; ++i) {
+ ret = usb_submit_urb(stream->urb[i], gfp_flags);
+ if (ret < 0) {
+ uvc_printk(KERN_ERR, "Failed to submit URB %u "
+ "(%d).\n", i, ret);
+ uvc_uninit_video(stream, 1);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Stop streaming without disabling the video queue.
+ *
+ * To let userspace applications resume without trouble, we must not touch the
+ * video buffers in any way. We mark the device as frozen to make sure the URB
+ * completion handler won't try to cancel the queue when we kill the URBs.
+ */
+int uvc_video_suspend(struct uvc_streaming *stream)
+{
+ if (!uvc_queue_streaming(&stream->queue))
+ return 0;
+
+ stream->frozen = 1;
+ uvc_uninit_video(stream, 0);
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+ return 0;
+}
+
+/*
+ * Reconfigure the video interface and restart streaming if it was enabled
+ * before suspend.
+ *
+ * If an error occurs, disable the video queue. This will wake all pending
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+int uvc_video_resume(struct uvc_streaming *stream, int reset)
+{
+ int ret;
+
+ /* If the bus has been reset on resume, set the alternate setting to 0.
+ * This should be the default value, but some devices crash or otherwise
+ * misbehave if they don't receive a SET_INTERFACE request before any
+ * other video control request.
+ */
+ if (reset)
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
+ stream->frozen = 0;
+
+ uvc_video_clock_reset(stream);
+
+ ret = uvc_commit_video(stream, &stream->ctrl);
+ if (ret < 0) {
+ uvc_queue_enable(&stream->queue, 0);
+ return ret;
+ }
+
+ if (!uvc_queue_streaming(&stream->queue))
+ return 0;
+
+ ret = uvc_init_video(stream, GFP_NOIO);
+ if (ret < 0)
+ uvc_queue_enable(&stream->queue, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device
+ */
+
+/*
+ * Initialize the UVC video device by switching to alternate setting 0 and
+ * retrieve the default format.
+ *
+ * Some cameras (namely the Fuji Finepix) set the format and frame
+ * indexes to zero. The UVC standard doesn't clearly make this a spec
+ * violation, so try to silently fix the values if possible.
+ *
+ * This function is called before registering the device with V4L.
+ */
+int uvc_video_init(struct uvc_streaming *stream)
+{
+ struct uvc_streaming_control *probe = &stream->ctrl;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ unsigned int i;
+ int ret;
+
+ if (stream->nformats == 0) {
+ uvc_printk(KERN_INFO, "No supported video formats found.\n");
+ return -EINVAL;
+ }
+
+ atomic_set(&stream->active, 0);
+
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
+
+ /* Alternate setting 0 should be the default, yet the XBox Live Vision
+ * Cam (and possibly other devices) crash or otherwise misbehave if
+ * they don't receive a SET_INTERFACE request before any other video
+ * control request.
+ */
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
+ /* Set the streaming probe control with default streaming parameters
+ * retrieved from the device. Webcams that don't suport GET_DEF
+ * requests on the probe control will just keep their current streaming
+ * parameters.
+ */
+ if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
+ uvc_set_video_ctrl(stream, probe, 1);
+
+ /* Initialize the streaming parameters with the probe control current
+ * value. This makes sure SET_CUR requests on the streaming commit
+ * control will always use values retrieved from a successful GET_CUR
+ * request on the probe control, as required by the UVC specification.
+ */
+ ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
+ return ret;
+
+ /* Check if the default format descriptor exists. Use the first
+ * available format otherwise.
+ */
+ for (i = stream->nformats; i > 0; --i) {
+ format = &stream->format[i-1];
+ if (format->index == probe->bFormatIndex)
+ break;
+ }
+
+ if (format->nframes == 0) {
+ uvc_printk(KERN_INFO, "No frame descriptor found for the "
+ "default format.\n");
+ return -EINVAL;
+ }
+
+ /* Zero bFrameIndex might be correct. Stream-based formats (including
+ * MPEG-2 TS and DV) do not support frames but have a dummy frame
+ * descriptor with bFrameIndex set to zero. If the default frame
+ * descriptor is not found, use the first available frame.
+ */
+ for (i = format->nframes; i > 0; --i) {
+ frame = &format->frame[i-1];
+ if (frame->bFrameIndex == probe->bFrameIndex)
+ break;
+ }
+
+ probe->bFormatIndex = format->index;
+ probe->bFrameIndex = frame->bFrameIndex;
+
+ stream->cur_format = format;
+ stream->cur_frame = frame;
+
+ /* Select the video decoding function */
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ stream->decode = uvc_video_decode_isight;
+ else if (stream->intf->num_altsetting > 1)
+ stream->decode = uvc_video_decode_isoc;
+ else
+ stream->decode = uvc_video_decode_bulk;
+ } else {
+ if (stream->intf->num_altsetting == 1)
+ stream->decode = uvc_video_encode_bulk;
+ else {
+ uvc_printk(KERN_INFO, "Isochronous endpoints are not "
+ "supported for video output devices.\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int uvc_video_enable(struct uvc_streaming *stream, int enable)
+{
+ int ret;
+
+ if (!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_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)
+ goto error_commit;
+
+ 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/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
new file mode 100644
index 000000000000..3764040475bb
--- /dev/null
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -0,0 +1,718 @@
+#ifndef _USB_VIDEO_H_
+#define _USB_VIDEO_H_
+
+#ifndef __KERNEL__
+#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
+#endif /* __KERNEL__ */
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/usb/video.h>
+#include <linux/uvcvideo.h>
+#include <linux/videodev2.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+#define UVC_TERM_INPUT 0x0000
+#define UVC_TERM_OUTPUT 0x8000
+#define UVC_TERM_DIRECTION(term) ((term)->type & 0x8000)
+
+#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff)
+#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
+#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
+#define UVC_ENTITY_IS_ITERM(entity) \
+ (UVC_ENTITY_IS_TERM(entity) && \
+ ((entity)->type & 0x8000) == UVC_TERM_INPUT)
+#define UVC_ENTITY_IS_OTERM(entity) \
+ (UVC_ENTITY_IS_TERM(entity) && \
+ ((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+
+#define UVC_GUID_FORMAT_MJPEG \
+ { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+ { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+ { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+ { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+ { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+ { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8 \
+ { 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y10 \
+ { 'Y', '1', '0', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12 \
+ { 'Y', '1', '2', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y16 \
+ { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_M420 \
+ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_H264 \
+ { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants.
+ */
+
+#define DRIVER_VERSION "1.1.1"
+
+/* Number of isochronous URBs. */
+#define UVC_URBS 5
+/* Maximum number of packets per URB. */
+#define UVC_MAX_PACKETS 32
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS 32
+/* Maximum status buffer size in bytes of interrupt URB. */
+#define UVC_MAX_STATUS_SIZE 16
+
+#define UVC_CTRL_CONTROL_TIMEOUT 300
+#define UVC_CTRL_STREAMING_TIMEOUT 5000
+
+/* 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
+#define UVC_QUIRK_PROBE_MINMAX 0x00000002
+#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004
+#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
+#define UVC_QUIRK_STREAM_NO_FID 0x00000010
+#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
+#define UVC_QUIRK_PROBE_DEF 0x00000100
+#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
+
+/* Format flags */
+#define UVC_FMT_FLAG_COMPRESSED 0x00000001
+#define UVC_FMT_FLAG_STREAM 0x00000002
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+struct uvc_device;
+
+/* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+struct uvc_control_info {
+ struct list_head mappings;
+
+ __u8 entity[16];
+ __u8 index; /* Bit index in bmControls */
+ __u8 selector;
+
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_control_mapping {
+ struct list_head list;
+ struct list_head ev_subs;
+
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ enum v4l2_ctrl_type v4l2_type;
+ __u32 data_type;
+
+ struct uvc_menu_info *menu_info;
+ __u32 menu_count;
+
+ __u32 master_id;
+ __s32 master_manual;
+ __u32 slave_ids[2];
+
+ __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
+ const __u8 *data);
+ void (*set) (struct uvc_control_mapping *mapping, __s32 value,
+ __u8 *data);
+};
+
+struct uvc_control {
+ struct uvc_entity *entity;
+ struct uvc_control_info info;
+
+ __u8 index; /* Used to match the uvc_control entry with a
+ uvc_control_info. */
+ __u8 dirty:1,
+ loaded:1,
+ modified:1,
+ cached:1,
+ initialized:1;
+
+ __u8 *uvc_data;
+};
+
+struct uvc_format_desc {
+ char *name;
+ __u8 guid[16];
+ __u32 fcc;
+};
+
+/* The term 'entity' refers to both UVC units and UVC terminals.
+ *
+ * The type field is either the terminal type (wTerminalType in the terminal
+ * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
+ * As the bDescriptorSubtype field is one byte long, the type value will
+ * always have a null MSB for units. All terminal types defined by the UVC
+ * specification have a non-null MSB, so it is safe to use the MSB to
+ * differentiate between units and terminals as long as the descriptor parsing
+ * code makes sure terminal types have a non-null MSB.
+ *
+ * For terminals, the type's most significant bit stores the terminal
+ * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
+ * always be accessed with the UVC_ENTITY_* macros and never directly.
+ */
+
+struct uvc_entity {
+ struct list_head list; /* Entity as part of a UVC device. */
+ struct list_head chain; /* Entity as part of a video device
+ * chain. */
+ __u8 id;
+ __u16 type;
+ char name[64];
+
+ /* Media controller-related fields. */
+ struct video_device *vdev;
+ struct v4l2_subdev subdev;
+ unsigned int num_pads;
+ unsigned int num_links;
+ struct media_pad *pads;
+
+ union {
+ struct {
+ __u16 wObjectiveFocalLengthMin;
+ __u16 wObjectiveFocalLengthMax;
+ __u16 wOcularFocalLength;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ } camera;
+
+ struct {
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bTransportModeSize;
+ __u8 *bmTransportModes;
+ } media;
+
+ struct {
+ } output;
+
+ struct {
+ __u16 wMaxMultiplier;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bmVideoStandards;
+ } processing;
+
+ struct {
+ } selector;
+
+ struct {
+ __u8 guidExtensionCode[16];
+ __u8 bNumControls;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 *bmControlsType;
+ } extension;
+ };
+
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+
+ unsigned int ncontrols;
+ struct uvc_control *controls;
+};
+
+struct uvc_frame {
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwMaxVideoFrameBufferSize;
+ __u8 bFrameIntervalType;
+ __u32 dwDefaultFrameInterval;
+ __u32 *dwFrameInterval;
+};
+
+struct uvc_format {
+ __u8 type;
+ __u8 index;
+ __u8 bpp;
+ __u8 colorspace;
+ __u32 fcc;
+ __u32 flags;
+
+ char name[32];
+
+ unsigned int nframes;
+ struct uvc_frame *frame;
+};
+
+struct uvc_streaming_header {
+ __u8 bNumFormats;
+ __u8 bEndpointAddress;
+ __u8 bTerminalLink;
+ __u8 bControlSize;
+ __u8 *bmaControls;
+ /* The following fields are used by input headers only. */
+ __u8 bmInfo;
+ __u8 bStillCaptureMethod;
+ __u8 bTriggerSupport;
+ __u8 bTriggerUsage;
+};
+
+enum uvc_buffer_state {
+ UVC_BUF_STATE_IDLE = 0,
+ UVC_BUF_STATE_QUEUED = 1,
+ UVC_BUF_STATE_ACTIVE = 2,
+ UVC_BUF_STATE_READY = 3,
+ UVC_BUF_STATE_DONE = 4,
+ UVC_BUF_STATE_ERROR = 5,
+};
+
+struct uvc_buffer {
+ struct vb2_buffer buf;
+ struct list_head queue;
+
+ enum uvc_buffer_state state;
+ unsigned int error;
+
+ void *mem;
+ unsigned int length;
+ unsigned int bytesused;
+
+ u32 pts;
+};
+
+#define UVC_QUEUE_DISCONNECTED (1 << 0)
+#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
+
+struct uvc_video_queue {
+ struct vb2_queue queue;
+ struct mutex mutex; /* Protects queue */
+
+ unsigned int flags;
+ unsigned int buf_used;
+
+ spinlock_t irqlock; /* Protects irqqueue */
+ struct list_head irqqueue;
+};
+
+struct uvc_video_chain {
+ struct uvc_device *dev;
+ struct list_head list;
+
+ struct list_head entities; /* All entities */
+ struct uvc_entity *processing; /* Processing unit */
+ struct uvc_entity *selector; /* Selector unit */
+
+ 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;
+ struct video_device *vdev;
+ struct uvc_video_chain *chain;
+ atomic_t active;
+
+ struct usb_interface *intf;
+ int intfnum;
+ __u16 maxpsize;
+
+ struct uvc_streaming_header header;
+ enum v4l2_buf_type type;
+
+ unsigned int nformats;
+ struct uvc_format *format;
+
+ struct uvc_streaming_control ctrl;
+ struct uvc_format *cur_format;
+ struct uvc_frame *cur_frame;
+ /* Protect access to ctrl, cur_format, cur_frame and hardware video
+ * probe control.
+ */
+ struct mutex mutex;
+
+ /* Buffers queue. */
+ unsigned int frozen : 1;
+ struct uvc_video_queue queue;
+ void (*decode) (struct urb *urb, struct uvc_streaming *video,
+ struct uvc_buffer *buf);
+
+ /* Context data used by the bulk completion handler. */
+ struct {
+ __u8 header[256];
+ unsigned int header_size;
+ int skip_payload;
+ __u32 payload_size;
+ __u32 max_payload_size;
+ } bulk;
+
+ struct urb *urb[UVC_URBS];
+ char *urb_buffer[UVC_URBS];
+ dma_addr_t urb_dma[UVC_URBS];
+ unsigned int urb_size;
+
+ __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 {
+ UVC_DEV_DISCONNECTED = 1,
+};
+
+struct uvc_device {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ unsigned long warnings;
+ __u32 quirks;
+ int intfnum;
+ char name[32];
+
+ enum uvc_device_state state;
+ atomic_t users;
+ atomic_t nmappings;
+
+ /* Video control interface */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+#endif
+ struct v4l2_device vdev;
+ __u16 uvc_version;
+ __u32 clock_frequency;
+
+ struct list_head entities;
+ struct list_head chains;
+
+ /* Video Streaming interfaces */
+ struct list_head streams;
+ atomic_t nstreams;
+
+ /* Status Interrupt Endpoint */
+ struct usb_host_endpoint *int_ep;
+ struct urb *int_urb;
+ __u8 *status;
+ struct input_dev *input;
+ char input_phys[64];
+};
+
+enum uvc_handle_state {
+ UVC_HANDLE_PASSIVE = 0,
+ UVC_HANDLE_ACTIVE = 1,
+};
+
+struct uvc_fh {
+ struct v4l2_fh vfh;
+ struct uvc_video_chain *chain;
+ struct uvc_streaming *stream;
+ enum uvc_handle_state state;
+};
+
+struct uvc_driver {
+ struct usb_driver driver;
+};
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#define UVC_TRACE_PROBE (1 << 0)
+#define UVC_TRACE_DESCR (1 << 1)
+#define UVC_TRACE_CONTROL (1 << 2)
+#define UVC_TRACE_FORMAT (1 << 3)
+#define UVC_TRACE_CAPTURE (1 << 4)
+#define UVC_TRACE_CALLS (1 << 5)
+#define UVC_TRACE_IOCTL (1 << 6)
+#define UVC_TRACE_FRAME (1 << 7)
+#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;
+extern unsigned int uvc_trace_param;
+extern unsigned int uvc_timeout_param;
+
+#define uvc_trace(flag, msg...) \
+ do { \
+ if (uvc_trace_param & flag) \
+ printk(KERN_DEBUG "uvcvideo: " msg); \
+ } while (0)
+
+#define uvc_warn_once(dev, warn, msg...) \
+ do { \
+ if (!test_and_set_bit(warn, &dev->warnings)) \
+ printk(KERN_INFO "uvcvideo: " msg); \
+ } while (0)
+
+#define uvc_printk(level, msg...) \
+ printk(level "uvcvideo: " msg)
+
+/* --------------------------------------------------------------------------
+ * Internal functions.
+ */
+
+/* Core driver */
+extern struct uvc_driver uvc_driver;
+
+extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
+
+/* Video buffers queue management. */
+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,
+ 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,
+ struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf);
+extern int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+ struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff);
+#endif
+extern int uvc_queue_allocated(struct uvc_video_queue *queue);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+ return vb2_is_streaming(&queue->queue);
+}
+
+/* V4L2 interface */
+extern const struct v4l2_file_operations uvc_fops;
+
+/* Media controller */
+extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
+extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
+
+/* Video */
+extern int uvc_video_init(struct uvc_streaming *stream);
+extern int uvc_video_suspend(struct uvc_streaming *stream);
+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_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);
+extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev);
+extern void uvc_status_stop(struct uvc_device *dev);
+extern int uvc_status_suspend(struct uvc_device *dev);
+extern int uvc_status_resume(struct uvc_device *dev);
+
+/* Controls */
+extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
+
+extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ struct v4l2_queryctrl *v4l2_ctrl);
+extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu);
+
+extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+ const struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_init_device(struct uvc_device *dev);
+extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+
+extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
+extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count);
+static inline int uvc_ctrl_commit(struct uvc_fh *handle,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count)
+{
+ return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
+}
+static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
+{
+ return __uvc_ctrl_commit(handle, 1, NULL, 0);
+}
+
+extern int uvc_ctrl_get(struct uvc_video_chain *chain,
+ struct v4l2_ext_control *xctrl);
+extern int uvc_ctrl_set(struct uvc_video_chain *chain,
+ struct v4l2_ext_control *xctrl);
+
+extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
+ struct uvc_xu_control_query *xqry);
+
+/* Utility functions */
+extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold);
+extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
+ uint32_t denominator);
+extern struct usb_host_endpoint *uvc_find_endpoint(
+ struct usb_host_interface *alts, __u8 epaddr);
+
+/* Quirks support */
+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/usb/zr364xx/Kconfig b/drivers/media/usb/zr364xx/Kconfig
new file mode 100644
index 000000000000..0f585662881d
--- /dev/null
+++ b/drivers/media/usb/zr364xx/Kconfig
@@ -0,0 +1,14 @@
+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.
+
diff --git a/drivers/media/usb/zr364xx/Makefile b/drivers/media/usb/zr364xx/Makefile
new file mode 100644
index 000000000000..a5777883a1f8
--- /dev/null
+++ b/drivers/media/usb/zr364xx/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
+
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 9afab35878b4..9afab35878b4 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
new file mode 100644
index 000000000000..0c54e19d9944
--- /dev/null
+++ b/drivers/media/v4l2-core/Kconfig
@@ -0,0 +1,81 @@
+#
+# Generic video config states
+#
+
+# Enable the V4L2 core and API
+config VIDEO_V4L2
+ tristate
+ depends on (I2C || I2C=n) && VIDEO_DEV
+ default (I2C || I2C=n) && VIDEO_DEV
+
+config VIDEO_ADV_DEBUG
+ bool "Enable advanced debug functionality on V4L2 drivers"
+ default n
+ ---help---
+ Say Y here to enable advanced debugging functionality on some
+ V4L devices.
+ In doubt, say N.
+
+config VIDEO_FIXED_MINOR_RANGES
+ bool "Enable old-style fixed minor ranges on drivers/video devices"
+ default n
+ ---help---
+ Say Y here to enable the old-style fixed-range minor assignments.
+ Only useful if you rely on the old behavior and use mknod instead of udev.
+
+ When in doubt, say N.
+
+# Used by drivers that need tuner.ko
+config VIDEO_TUNER
+ tristate
+ depends on MEDIA_TUNER
+
+# Used by drivers that need v4l2-mem2mem.ko
+config V4L2_MEM2MEM_DEV
+ tristate
+ depends on VIDEOBUF2_CORE
+
+# Used by drivers that need Videobuf modules
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
+ tristate
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+
+config VIDEOBUF_VMALLOC
+ tristate
+ select VIDEOBUF_GEN
+
+config VIDEOBUF_DMA_CONTIG
+ tristate
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+
+config VIDEOBUF_DVB
+ tristate
+ select VIDEOBUF_GEN
+
+# Used by drivers that need Videobuf2 modules
+config VIDEOBUF2_CORE
+ tristate
+
+config VIDEOBUF2_MEMOPS
+ tristate
+
+config VIDEOBUF2_DMA_CONTIG
+ tristate
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+
+config VIDEOBUF2_VMALLOC
+ tristate
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+
+config VIDEOBUF2_DMA_SG
+ tristate
+ #depends on HAS_DMA
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
new file mode 100644
index 000000000000..c2d61d4f03d1
--- /dev/null
+++ b/drivers/media/v4l2-core/Makefile
@@ -0,0 +1,35 @@
+#
+# Makefile for the V4L2 core
+#
+
+tuner-objs := tuner-core.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
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
+obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
+
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
+obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
+
+obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
+obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
+obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
+
+obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o
+obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o
+obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
+obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
+obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/tuners
+
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index b5a819af2b8c..b5a819af2b8c 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
new file mode 100644
index 000000000000..105f88cdb9d6
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -0,0 +1,623 @@
+/*
+ * Video for Linux Two
+ *
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
+ *
+ * This file replaces the videodev.c file that comes with the
+ * regular kernel distribution.
+ *
+ * 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.
+ *
+ * Author: Bill Dirks <bill@thedirks.org>
+ * based on code by Alan Cox, <alan@cymru.net>
+ *
+ */
+
+/*
+ * Video capture interface for Linux
+ *
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
+ *
+ * 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.
+ *
+ * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk>
+ *
+ * Fixes:
+ */
+
+/*
+ * Video4linux 1/2 integration by Justin Schoeman
+ * <justin@suntiger.ee.up.ac.za>
+ * 2.4 PROCFS support ported from 2.4 kernels by
+ * Iñaki García Etxebarria <garetxe@euskalnet.net>
+ * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
+ * 2.4 devfs support ported from 2.4 kernels by
+ * Dan Merillat <dan@merillat.org>
+ * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#if defined(CONFIG_SPI)
+#include <linux/spi/spi.h>
+#endif
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+
+#include <linux/videodev2.h>
+
+MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr");
+MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers");
+MODULE_LICENSE("GPL");
+
+/*
+ *
+ * V 4 L 2 D R I V E R H E L P E R A P I
+ *
+ */
+
+/*
+ * Video Standard Operations (contributed by Michael Schimek)
+ */
+
+/* Helper functions for control handling */
+
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char * const *menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
+ (ctrl->value & ~qctrl->maximum))
+ return -ERANGE;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_check);
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
+ &min, &max, &step, &def, &qctrl->flags);
+
+ if (name == NULL)
+ return -EINVAL;
+
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+ the menu. The qctrl pointer may be NULL, in which case it is ignored.
+ If menu_items is NULL, then the menu items are retrieved using
+ v4l2_ctrl_get_menu. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+ const char * const *menu_items)
+{
+ int i;
+
+ qmenu->reserved = 0;
+ if (menu_items == NULL)
+ menu_items = v4l2_ctrl_get_menu(qmenu->id);
+ if (menu_items == NULL ||
+ (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+ return -EINVAL;
+ for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+ strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name));
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+
+/* Fill in a struct v4l2_querymenu based on the specified array of valid
+ menu items (terminated by V4L2_CTRL_MENU_IDS_END).
+ Use this if there are 'holes' in the list of valid menu items. */
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
+{
+ const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
+
+ qmenu->reserved = 0;
+ if (menu_items == NULL || ids == NULL)
+ return -EINVAL;
+ while (*ids != V4L2_CTRL_MENU_IDS_END) {
+ if (*ids++ == qmenu->index) {
+ strlcpy(qmenu->name, menu_items[qmenu->index],
+ sizeof(qmenu->name));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+ a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+ Each array must be sorted low to high and belong to the same control
+ class. The array of u32 pointers must also be sorted, from low class IDs
+ to high class IDs.
+
+ This function returns the first ID that follows after the given ID.
+ When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+ u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
+ const u32 *pctrl;
+
+ if (ctrl_classes == NULL)
+ return 0;
+
+ /* if no query is desired, then check if the ID is part of ctrl_classes */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+ /* find class */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find control ID */
+ while (*pctrl && *pctrl != id) pctrl++;
+ return *pctrl ? id : 0;
+ }
+ id &= V4L2_CTRL_ID_MASK;
+ id++; /* select next control */
+ /* find first class that matches (or is greater than) the class of
+ the ID */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+ ctrl_classes++;
+ /* no more classes */
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find first ctrl within the class that is >= ID */
+ while (*pctrl && *pctrl < id) pctrl++;
+ if (*pctrl)
+ return *pctrl;
+ /* we are at the end of the controls of the current class. */
+ /* continue with next class if available */
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ return **ctrl_classes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_next);
+
+int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
+{
+ switch (match->type) {
+ case V4L2_CHIP_MATCH_HOST:
+ return match->addr == 0;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL(v4l2_chip_match_host);
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
+{
+ int len;
+
+ if (c == NULL || match == NULL)
+ return 0;
+
+ switch (match->type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ if (c->driver == NULL || c->driver->driver.name == NULL)
+ return 0;
+ len = strlen(c->driver->driver.name);
+ /* legacy drivers have a ' suffix, don't try to match that */
+ if (len && c->driver->driver.name[len - 1] == '\'')
+ len--;
+ return len && !strncmp(c->driver->driver.name, match->name, len);
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ return c->addr == match->addr;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
+
+int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
+ u32 ident, u32 revision)
+{
+ if (!v4l2_chip_match_i2c_client(c, &chip->match))
+ return 0;
+ if (chip->ident == V4L2_IDENT_NONE) {
+ chip->ident = ident;
+ chip->revision = revision;
+ }
+ else {
+ chip->ident = V4L2_IDENT_AMBIGUOUS;
+ chip->revision = 0;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
+
+/* ----------------------------------------------------------------- */
+
+/* I2C Helper functions */
+
+
+void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+ const struct v4l2_subdev_ops *ops)
+{
+ v4l2_subdev_init(sd, ops);
+ sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
+ /* the owner is the same as the i2c_client's driver owner */
+ sd->owner = client->driver->driver.owner;
+ /* i2c_client and v4l2_subdev point to one another */
+ v4l2_set_subdevdata(sd, client);
+ i2c_set_clientdata(client, sd);
+ /* initialize name */
+ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
+ client->driver->driver.name, i2c_adapter_id(client->adapter),
+ client->addr);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
+
+
+
+/* Load an i2c sub-device. */
+struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+ const unsigned short *probe_addrs)
+{
+ struct v4l2_subdev *sd = NULL;
+ struct i2c_client *client;
+
+ BUG_ON(!v4l2_dev);
+
+ request_module(I2C_MODULE_PREFIX "%s", info->type);
+
+ /* Create the i2c client */
+ if (info->addr == 0 && probe_addrs)
+ client = i2c_new_probed_device(adapter, info, probe_addrs,
+ NULL);
+ else
+ client = i2c_new_device(adapter, info);
+
+ /* Note: by loading the module first we are certain that c->driver
+ will be set if the driver was found. If the module was not loaded
+ first, then the i2c core tries to delay-load the module for us,
+ and then c->driver is still NULL until the module is finally
+ loaded. This delay-load mechanism doesn't work if other drivers
+ want to use the i2c device, so explicitly loading the module
+ is the best alternative. */
+ if (client == NULL || client->driver == NULL)
+ goto error;
+
+ /* Lock the module so we can safely get the v4l2_subdev pointer */
+ if (!try_module_get(client->driver->driver.owner))
+ goto error;
+ sd = i2c_get_clientdata(client);
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+ if (v4l2_device_register_subdev(v4l2_dev, sd))
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(client->driver->driver.owner);
+
+error:
+ /* If we have a client but no subdev, then something went wrong and
+ we must unregister the client. */
+ if (client && sd == NULL)
+ i2c_unregister_device(client);
+ return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
+
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, const char *client_type,
+ u8 addr, const unsigned short *probe_addrs)
+{
+ struct i2c_board_info info;
+
+ /* Setup the i2c board info with the device type and
+ the device address. */
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.type, client_type, sizeof(info.type));
+ info.addr = addr;
+
+ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return client ? client->addr : I2C_CLIENT_END;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
+
+/* Return a list of I2C tuner addresses to probe. Use only if the tuner
+ addresses are unknown. */
+const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
+{
+ static const unsigned short radio_addrs[] = {
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
+ 0x10,
+#endif
+ 0x60,
+ I2C_CLIENT_END
+ };
+ static const unsigned short demod_addrs[] = {
+ 0x42, 0x43, 0x4a, 0x4b,
+ I2C_CLIENT_END
+ };
+ static const unsigned short tv_addrs[] = {
+ 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
+ 0x60, 0x61, 0x62, 0x63, 0x64,
+ I2C_CLIENT_END
+ };
+
+ switch (type) {
+ case ADDRS_RADIO:
+ return radio_addrs;
+ case ADDRS_DEMOD:
+ return demod_addrs;
+ case ADDRS_TV:
+ return tv_addrs;
+ case ADDRS_TV_WITH_DEMOD:
+ return tv_addrs + 4;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
+
+#endif /* defined(CONFIG_I2C) */
+
+#if defined(CONFIG_SPI)
+
+/* Load an spi sub-device. */
+
+void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+ const struct v4l2_subdev_ops *ops)
+{
+ v4l2_subdev_init(sd, ops);
+ sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
+ /* the owner is the same as the spi_device's driver owner */
+ sd->owner = spi->dev.driver->owner;
+ /* spi_device and v4l2_subdev point to one another */
+ v4l2_set_subdevdata(sd, spi);
+ spi_set_drvdata(spi, sd);
+ /* initialize name */
+ strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name));
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
+
+struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+ struct spi_master *master, struct spi_board_info *info)
+{
+ struct v4l2_subdev *sd = NULL;
+ struct spi_device *spi = NULL;
+
+ BUG_ON(!v4l2_dev);
+
+ if (info->modalias)
+ request_module(info->modalias);
+
+ spi = spi_new_device(master, info);
+
+ if (spi == NULL || spi->dev.driver == NULL)
+ goto error;
+
+ if (!try_module_get(spi->dev.driver->owner))
+ goto error;
+
+ sd = spi_get_drvdata(spi);
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+ if (v4l2_device_register_subdev(v4l2_dev, sd))
+ sd = NULL;
+
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(spi->dev.driver->owner);
+
+error:
+ /* If we have a client but no subdev, then something went wrong and
+ we must unregister the client. */
+ if (spi && sd == NULL)
+ spi_unregister_device(spi);
+
+ return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev);
+
+#endif /* defined(CONFIG_SPI) */
+
+/* Clamp x to be between min and max, aligned to a multiple of 2^align. min
+ * and max don't have to be aligned, but there must be at least one valid
+ * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples
+ * of 16 between 17 and 31. */
+static unsigned int clamp_align(unsigned int x, unsigned int min,
+ unsigned int max, unsigned int align)
+{
+ /* Bits that must be zero to be aligned */
+ unsigned int mask = ~((1 << align) - 1);
+
+ /* Round to nearest aligned value */
+ if (align)
+ x = (x + (1 << (align - 1))) & mask;
+
+ /* Clamp to aligned value of min and max */
+ if (x < min)
+ x = (min + ~mask) & mask;
+ else if (x > max)
+ x = max & mask;
+
+ return x;
+}
+
+/* Bound an image to have a width between wmin and wmax, and height between
+ * hmin and hmax, inclusive. Additionally, the width will be a multiple of
+ * 2^walign, the height will be a multiple of 2^halign, and the overall size
+ * (width*height) will be a multiple of 2^salign. The image may be shrunk
+ * or enlarged to fit the alignment constraints.
+ *
+ * The width or height maximum must not be smaller than the corresponding
+ * minimum. The alignments must not be so high there are no possible image
+ * sizes within the allowed bounds. wmin and hmin must be at least 1
+ * (don't use 0). If you don't care about a certain alignment, specify 0,
+ * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If
+ * you only want to adjust downward, specify a maximum that's the same as
+ * the initial value.
+ */
+void v4l_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, unsigned int salign)
+{
+ *w = clamp_align(*w, wmin, wmax, walign);
+ *h = clamp_align(*h, hmin, hmax, halign);
+
+ /* Usually we don't need to align the size and are done now. */
+ if (!salign)
+ return;
+
+ /* How much alignment do we have? */
+ walign = __ffs(*w);
+ halign = __ffs(*h);
+ /* Enough to satisfy the image alignment? */
+ if (walign + halign < salign) {
+ /* Max walign where there is still a valid width */
+ unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
+ /* Max halign where there is still a valid height */
+ unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
+
+ /* up the smaller alignment until we have enough */
+ do {
+ if (halign >= hmaxa ||
+ (walign <= halign && walign < wmaxa)) {
+ *w = clamp_align(*w, wmin, wmax, walign + 1);
+ walign = __ffs(*w);
+ } else {
+ *h = clamp_align(*h, hmin, hmax, halign + 1);
+ halign = __ffs(*h);
+ }
+ } while (halign + walign < salign);
+ }
+}
+EXPORT_SYMBOL_GPL(v4l_bound_align_image);
+
+/**
+ * v4l_fill_dv_preset_info - fill description of a digital video preset
+ * @preset - preset value
+ * @info - pointer to struct v4l2_dv_enum_preset
+ *
+ * drivers can use this helper function to fill description of dv preset
+ * in info.
+ */
+int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
+{
+ static const struct v4l2_dv_preset_info {
+ u16 width;
+ u16 height;
+ const char *name;
+ } dv_presets[] = {
+ { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */
+ { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */
+ { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */
+ { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */
+ { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */
+ { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */
+ { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */
+ { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */
+ { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */
+ { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */
+ { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */
+ { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */
+ { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */
+ { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */
+ { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */
+ { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */
+ { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */
+ { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */
+ { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */
+ };
+
+ if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
+ return -EINVAL;
+
+ info->preset = preset;
+ info->width = dv_presets[preset].width;
+ info->height = dv_presets[preset].height;
+ strlcpy(info->name, dv_presets[preset].name, sizeof(info->name));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
+
+const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
+ const struct v4l2_discrete_probe *probe,
+ s32 width, s32 height)
+{
+ int i;
+ u32 error, min_error = UINT_MAX;
+ const struct v4l2_frmsize_discrete *size, *best = NULL;
+
+ if (!probe)
+ return best;
+
+ for (i = 0, size = probe->sizes; i < probe->num_sizes; i++, size++) {
+ error = abs(size->width - width) + abs(size->height - height);
+ if (error < min_error) {
+ min_error = error;
+ best = size;
+ }
+ if (!error)
+ break;
+ }
+
+ return best;
+}
+EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 9ebd5c540d10..9ebd5c540d10 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b6a2ee71e5c3..b6a2ee71e5c3 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
new file mode 100644
index 000000000000..71237f5f85f4
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -0,0 +1,1003 @@
+/*
+ * Video capture interface for Linux version 2
+ *
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
+ *
+ * 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.
+ *
+ * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
+ * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
+ *
+ * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
+ * - Added procfs support
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define VIDEO_NUM_DEVICES 256
+#define VIDEO_NAME "video4linux"
+
+/*
+ * sysfs stuff
+ */
+
+static ssize_t show_index(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev = to_video_device(cd);
+
+ return sprintf(buf, "%i\n", vdev->index);
+}
+
+static ssize_t show_debug(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev = to_video_device(cd);
+
+ return sprintf(buf, "%i\n", vdev->debug);
+}
+
+static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct video_device *vdev = to_video_device(cd);
+ int res = 0;
+ u16 value;
+
+ res = kstrtou16(buf, 0, &value);
+ if (res)
+ return res;
+
+ vdev->debug = value;
+ return len;
+}
+
+static ssize_t show_name(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *vdev = to_video_device(cd);
+
+ return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
+}
+
+static struct device_attribute video_device_attrs[] = {
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(debug, 0644, show_debug, set_debug),
+ __ATTR(index, S_IRUGO, show_index, NULL),
+ __ATTR_NULL
+};
+
+/*
+ * Active devices
+ */
+static struct video_device *video_device[VIDEO_NUM_DEVICES];
+static DEFINE_MUTEX(videodev_lock);
+static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
+
+/* Device node utility functions */
+
+/* Note: these utility functions all assume that vfl_type is in the range
+ [0, VFL_TYPE_MAX-1]. */
+
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+/* Return the bitmap corresponding to vfl_type. */
+static inline unsigned long *devnode_bits(int vfl_type)
+{
+ /* Any types not assigned to fixed minor ranges must be mapped to
+ one single bitmap for the purposes of finding a free node number
+ since all those unassigned types use the same minor range. */
+ int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type;
+
+ return devnode_nums[idx];
+}
+#else
+/* Return the bitmap corresponding to vfl_type. */
+static inline unsigned long *devnode_bits(int vfl_type)
+{
+ return devnode_nums[vfl_type];
+}
+#endif
+
+/* Mark device node number vdev->num as used */
+static inline void devnode_set(struct video_device *vdev)
+{
+ set_bit(vdev->num, devnode_bits(vdev->vfl_type));
+}
+
+/* Mark device node number vdev->num as unused */
+static inline void devnode_clear(struct video_device *vdev)
+{
+ clear_bit(vdev->num, devnode_bits(vdev->vfl_type));
+}
+
+/* Try to find a free device node number in the range [from, to> */
+static inline int devnode_find(struct video_device *vdev, int from, int to)
+{
+ return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from);
+}
+
+struct video_device *video_device_alloc(void)
+{
+ return kzalloc(sizeof(struct video_device), GFP_KERNEL);
+}
+EXPORT_SYMBOL(video_device_alloc);
+
+void video_device_release(struct video_device *vdev)
+{
+ kfree(vdev);
+}
+EXPORT_SYMBOL(video_device_release);
+
+void video_device_release_empty(struct video_device *vdev)
+{
+ /* Do nothing */
+ /* Only valid when the video_device struct is a static. */
+}
+EXPORT_SYMBOL(video_device_release_empty);
+
+static inline void video_get(struct video_device *vdev)
+{
+ get_device(&vdev->dev);
+}
+
+static inline void video_put(struct video_device *vdev)
+{
+ put_device(&vdev->dev);
+}
+
+/* Called when the last user of the video device exits. */
+static void v4l2_device_release(struct device *cd)
+{
+ struct video_device *vdev = to_video_device(cd);
+ struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
+
+ mutex_lock(&videodev_lock);
+ if (WARN_ON(video_device[vdev->minor] != vdev)) {
+ /* should not happen */
+ mutex_unlock(&videodev_lock);
+ return;
+ }
+
+ /* Free up this device for reuse */
+ video_device[vdev->minor] = NULL;
+
+ /* Delete the cdev on this minor as well */
+ cdev_del(vdev->cdev);
+ /* Just in case some driver tries to access this from
+ the release() callback. */
+ vdev->cdev = NULL;
+
+ /* Mark device node number as free */
+ devnode_clear(vdev);
+
+ mutex_unlock(&videodev_lock);
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (v4l2_dev && v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV)
+ media_device_unregister_entity(&vdev->entity);
+#endif
+
+ /* Do not call v4l2_device_put if there is no release callback set.
+ * Drivers that have no v4l2_device release callback might free the
+ * v4l2_dev instance in the video_device release callback below, so we
+ * must perform this check here.
+ *
+ * TODO: In the long run all drivers that use v4l2_device should use the
+ * v4l2_device release callback. This check will then be unnecessary.
+ */
+ if (v4l2_dev && v4l2_dev->release == NULL)
+ v4l2_dev = NULL;
+
+ /* Release video_device and perform other
+ cleanups as needed. */
+ vdev->release(vdev);
+
+ /* Decrease v4l2_device refcount */
+ if (v4l2_dev)
+ v4l2_device_put(v4l2_dev);
+}
+
+static struct class video_class = {
+ .name = VIDEO_NAME,
+ .dev_attrs = video_device_attrs,
+};
+
+struct video_device *video_devdata(struct file *file)
+{
+ return video_device[iminor(file->f_path.dentry->d_inode)];
+}
+EXPORT_SYMBOL(video_devdata);
+
+
+/* Priority handling */
+
+static inline bool prio_is_valid(enum v4l2_priority prio)
+{
+ return prio == V4L2_PRIORITY_BACKGROUND ||
+ prio == V4L2_PRIORITY_INTERACTIVE ||
+ prio == V4L2_PRIORITY_RECORD;
+}
+
+void v4l2_prio_init(struct v4l2_prio_state *global)
+{
+ memset(global, 0, sizeof(*global));
+}
+EXPORT_SYMBOL(v4l2_prio_init);
+
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+ enum v4l2_priority new)
+{
+ if (!prio_is_valid(new))
+ return -EINVAL;
+ if (*local == new)
+ return 0;
+
+ atomic_inc(&global->prios[new]);
+ if (prio_is_valid(*local))
+ atomic_dec(&global->prios[*local]);
+ *local = new;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_prio_change);
+
+void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
+{
+ v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
+}
+EXPORT_SYMBOL(v4l2_prio_open);
+
+void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
+{
+ if (prio_is_valid(local))
+ atomic_dec(&global->prios[local]);
+}
+EXPORT_SYMBOL(v4l2_prio_close);
+
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
+{
+ if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0)
+ return V4L2_PRIORITY_RECORD;
+ if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0)
+ return V4L2_PRIORITY_INTERACTIVE;
+ if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0)
+ return V4L2_PRIORITY_BACKGROUND;
+ return V4L2_PRIORITY_UNSET;
+}
+EXPORT_SYMBOL(v4l2_prio_max);
+
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
+{
+ return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
+}
+EXPORT_SYMBOL(v4l2_prio_check);
+
+
+static ssize_t v4l2_read(struct file *filp, char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
+
+ if (!vdev->fops->read)
+ return -EINVAL;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->read(filp, buf, sz, off);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: read: %zd (%d)\n",
+ video_device_node_name(vdev), sz, ret);
+ return ret;
+}
+
+static ssize_t v4l2_write(struct file *filp, const char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
+
+ if (!vdev->fops->write)
+ return -EINVAL;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->write(filp, buf, sz, off);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: write: %zd (%d)\n",
+ video_device_node_name(vdev), sz, ret);
+ return ret;
+}
+
+static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
+{
+ struct video_device *vdev = video_devdata(filp);
+ unsigned int res = POLLERR | POLLHUP;
+
+ if (!vdev->fops->poll)
+ return DEFAULT_POLLMASK;
+ if (video_is_registered(vdev))
+ res = vdev->fops->poll(filp, poll);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: poll: %08x\n",
+ video_device_node_name(vdev), res);
+ return res;
+}
+
+static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
+
+ if (vdev->fops->unlocked_ioctl) {
+ struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd);
+
+ if (lock && mutex_lock_interruptible(lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+ if (lock)
+ mutex_unlock(lock);
+ } else if (vdev->fops->ioctl) {
+ /* This code path is a replacement for the BKL. It is a major
+ * hack but it will have to do for those drivers that are not
+ * yet converted to use unlocked_ioctl.
+ *
+ * There are two options: if the driver implements struct
+ * v4l2_device, then the lock defined there is used to
+ * serialize the ioctls. Otherwise the v4l2 core lock defined
+ * below is used. This lock is really bad since it serializes
+ * completely independent devices.
+ *
+ * Both variants suffer from the same problem: if the driver
+ * sleeps, then it blocks all ioctls since the lock is still
+ * held. This is very common for VIDIOC_DQBUF since that
+ * normally waits for a frame to arrive. As a result any other
+ * ioctl calls will proceed very, very slowly since each call
+ * will have to wait for the VIDIOC_QBUF to finish. Things that
+ * should take 0.01s may now take 10-20 seconds.
+ *
+ * The workaround is to *not* take the lock for VIDIOC_DQBUF.
+ * This actually works OK for videobuf-based drivers, since
+ * videobuf will take its own internal lock.
+ */
+ static DEFINE_MUTEX(v4l2_ioctl_mutex);
+ struct mutex *m = vdev->v4l2_dev ?
+ &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
+
+ if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->ioctl(filp, cmd, arg);
+ if (cmd != VIDIOC_DQBUF)
+ mutex_unlock(m);
+ } else
+ ret = -ENOTTY;
+
+ return ret;
+}
+
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret;
+
+ if (!vdev->fops->get_unmapped_area)
+ return -ENOSYS;
+ if (!video_is_registered(vdev))
+ return -ENODEV;
+ ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n",
+ video_device_node_name(vdev), ret);
+ return ret;
+}
+#endif
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
+
+ if (!vdev->fops->mmap)
+ return -ENODEV;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->mmap(filp, vm);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: mmap (%d)\n",
+ video_device_node_name(vdev), ret);
+ return ret;
+}
+
+/* Override for the open function */
+static int v4l2_open(struct inode *inode, struct file *filp)
+{
+ struct video_device *vdev;
+ int ret = 0;
+
+ /* Check if the video device is available */
+ mutex_lock(&videodev_lock);
+ vdev = video_devdata(filp);
+ /* return ENODEV if the video device has already been removed. */
+ if (vdev == NULL || !video_is_registered(vdev)) {
+ mutex_unlock(&videodev_lock);
+ return -ENODEV;
+ }
+ /* and increase the device refcount */
+ video_get(vdev);
+ mutex_unlock(&videodev_lock);
+ if (vdev->fops->open) {
+ if (video_is_registered(vdev))
+ ret = vdev->fops->open(filp);
+ else
+ ret = -ENODEV;
+ }
+
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: open (%d)\n",
+ video_device_node_name(vdev), ret);
+ /* decrease the refcount in case of an error */
+ if (ret)
+ video_put(vdev);
+ return ret;
+}
+
+/* Override for the release function */
+static int v4l2_release(struct inode *inode, struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ int ret = 0;
+
+ if (vdev->fops->release)
+ ret = vdev->fops->release(filp);
+ if (vdev->debug)
+ printk(KERN_DEBUG "%s: release\n",
+ video_device_node_name(vdev));
+
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ video_put(vdev);
+ return ret;
+}
+
+static const struct file_operations v4l2_fops = {
+ .owner = THIS_MODULE,
+ .read = v4l2_read,
+ .write = v4l2_write,
+ .open = v4l2_open,
+ .get_unmapped_area = v4l2_get_unmapped_area,
+ .mmap = v4l2_mmap,
+ .unlocked_ioctl = v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l2_compat_ioctl32,
+#endif
+ .release = v4l2_release,
+ .poll = v4l2_poll,
+ .llseek = no_llseek,
+};
+
+/**
+ * get_index - assign stream index number based on parent device
+ * @vdev: video_device to assign index number to, vdev->parent should be assigned
+ *
+ * Note that when this is called the new device has not yet been registered
+ * in the video_device array, but it was able to obtain a minor number.
+ *
+ * This means that we can always obtain a free stream index number since
+ * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
+ * use of the video_device array.
+ *
+ * Returns a free index number.
+ */
+static int get_index(struct video_device *vdev)
+{
+ /* This can be static since this function is called with the global
+ videodev_lock held. */
+ static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
+ int i;
+
+ /* Some drivers do not set the parent. In that case always return 0. */
+ if (vdev->parent == NULL)
+ return 0;
+
+ bitmap_zero(used, VIDEO_NUM_DEVICES);
+
+ for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+ if (video_device[i] != NULL &&
+ video_device[i]->parent == vdev->parent) {
+ set_bit(video_device[i]->index, used);
+ }
+ }
+
+ return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
+}
+
+#define SET_VALID_IOCTL(ops, cmd, op) \
+ if (ops->op) \
+ set_bit(_IOC_NR(cmd), valid_ioctls)
+
+/* This determines which ioctls are actually implemented in the driver.
+ It's a one-time thing which simplifies video_ioctl2 as it can just do
+ a bit test.
+
+ Note that drivers can override this by setting bits to 1 in
+ vdev->valid_ioctls. If an ioctl is marked as 1 when this function is
+ called, then that ioctl will actually be marked as unimplemented.
+
+ It does that by first setting up the local valid_ioctls bitmap, and
+ at the end do a:
+
+ vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls)
+ */
+static void determine_valid_ioctls(struct video_device *vdev)
+{
+ DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
+ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+ bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
+
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
+ if (ops->vidioc_g_priority ||
+ test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+ set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
+ if (ops->vidioc_s_priority ||
+ test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+ set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
+ if (ops->vidioc_enum_fmt_vid_cap ||
+ ops->vidioc_enum_fmt_vid_out ||
+ ops->vidioc_enum_fmt_vid_cap_mplane ||
+ ops->vidioc_enum_fmt_vid_out_mplane ||
+ ops->vidioc_enum_fmt_vid_overlay ||
+ ops->vidioc_enum_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
+ if (ops->vidioc_g_fmt_vid_cap ||
+ ops->vidioc_g_fmt_vid_out ||
+ ops->vidioc_g_fmt_vid_cap_mplane ||
+ ops->vidioc_g_fmt_vid_out_mplane ||
+ ops->vidioc_g_fmt_vid_overlay ||
+ ops->vidioc_g_fmt_vbi_cap ||
+ ops->vidioc_g_fmt_vid_out_overlay ||
+ ops->vidioc_g_fmt_vbi_out ||
+ ops->vidioc_g_fmt_sliced_vbi_cap ||
+ ops->vidioc_g_fmt_sliced_vbi_out ||
+ ops->vidioc_g_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
+ if (ops->vidioc_s_fmt_vid_cap ||
+ ops->vidioc_s_fmt_vid_out ||
+ ops->vidioc_s_fmt_vid_cap_mplane ||
+ ops->vidioc_s_fmt_vid_out_mplane ||
+ ops->vidioc_s_fmt_vid_overlay ||
+ ops->vidioc_s_fmt_vbi_cap ||
+ ops->vidioc_s_fmt_vid_out_overlay ||
+ ops->vidioc_s_fmt_vbi_out ||
+ ops->vidioc_s_fmt_sliced_vbi_cap ||
+ ops->vidioc_s_fmt_sliced_vbi_out ||
+ ops->vidioc_s_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
+ if (ops->vidioc_try_fmt_vid_cap ||
+ ops->vidioc_try_fmt_vid_out ||
+ ops->vidioc_try_fmt_vid_cap_mplane ||
+ ops->vidioc_try_fmt_vid_out_mplane ||
+ ops->vidioc_try_fmt_vid_overlay ||
+ ops->vidioc_try_fmt_vbi_cap ||
+ ops->vidioc_try_fmt_vid_out_overlay ||
+ ops->vidioc_try_fmt_vbi_out ||
+ ops->vidioc_try_fmt_sliced_vbi_cap ||
+ ops->vidioc_try_fmt_sliced_vbi_out ||
+ ops->vidioc_try_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
+ SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
+ SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
+ SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
+ if (vdev->tvnorms)
+ set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
+ if (ops->vidioc_g_std || vdev->current_norm)
+ set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
+ SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
+ SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
+ SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
+ SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
+ /* Note: the control handler can also be passed through the filehandle,
+ and that can't be tested here. If the bit for these control ioctls
+ is set, then the ioctl is valid. But if it is 0, then it can still
+ be valid if the filehandle passed the control handler. */
+ if (vdev->ctrl_handler || ops->vidioc_queryctrl)
+ set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_querymenu)
+ set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
+ SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
+ SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout);
+ SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
+ SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
+ SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
+ SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
+ if (ops->vidioc_g_crop || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
+ if (ops->vidioc_s_crop || ops->vidioc_s_selection)
+ set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
+ SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
+ if (ops->vidioc_cropcap || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp);
+ SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp);
+ SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index);
+ SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
+ if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
+ (ops->vidioc_g_std || vdev->tvnorms)))
+ set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
+ SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
+ SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
+ SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
+ SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
+ SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
+ SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register);
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register);
+#endif
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
+ SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets);
+ SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap);
+ /* yes, really vidioc_subscribe_event */
+ SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
+ SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
+ if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
+ set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
+ bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
+ BASE_VIDIOC_PRIVATE);
+}
+
+/**
+ * __video_register_device - register video4linux devices
+ * @vdev: video device structure we want to register
+ * @type: type of device to register
+ * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
+ * -1 == first free)
+ * @warn_if_nr_in_use: warn if the desired device node number
+ * was already in use and another number was chosen instead.
+ * @owner: module that owns the video device node
+ *
+ * The registration code assigns minor numbers and device node numbers
+ * based on the requested type and registers the new device node with
+ * the kernel.
+ *
+ * This function assumes that struct video_device was zeroed when it
+ * was allocated and does not contain any stale date.
+ *
+ * An error is returned if no free minor or device node number could be
+ * found, or if the registration of the device node failed.
+ *
+ * Zero is returned on success.
+ *
+ * Valid types are
+ *
+ * %VFL_TYPE_GRABBER - A frame grabber
+ *
+ * %VFL_TYPE_VBI - Vertical blank data (undecoded)
+ *
+ * %VFL_TYPE_RADIO - A radio card
+ *
+ * %VFL_TYPE_SUBDEV - A subdevice
+ */
+int __video_register_device(struct video_device *vdev, int type, int nr,
+ int warn_if_nr_in_use, struct module *owner)
+{
+ int i = 0;
+ int ret;
+ int minor_offset = 0;
+ int minor_cnt = VIDEO_NUM_DEVICES;
+ const char *name_base;
+
+ /* A minor value of -1 marks this video device as never
+ having been registered */
+ vdev->minor = -1;
+
+ /* the release callback MUST be present */
+ if (WARN_ON(!vdev->release))
+ return -EINVAL;
+
+ /* v4l2_fh support */
+ spin_lock_init(&vdev->fh_lock);
+ INIT_LIST_HEAD(&vdev->fh_list);
+
+ /* Part 1: check device type */
+ switch (type) {
+ case VFL_TYPE_GRABBER:
+ name_base = "video";
+ break;
+ case VFL_TYPE_VBI:
+ name_base = "vbi";
+ break;
+ case VFL_TYPE_RADIO:
+ name_base = "radio";
+ break;
+ case VFL_TYPE_SUBDEV:
+ name_base = "v4l-subdev";
+ break;
+ default:
+ printk(KERN_ERR "%s called with unknown type: %d\n",
+ __func__, type);
+ return -EINVAL;
+ }
+
+ vdev->vfl_type = type;
+ vdev->cdev = NULL;
+ if (vdev->v4l2_dev) {
+ if (vdev->v4l2_dev->dev)
+ vdev->parent = vdev->v4l2_dev->dev;
+ if (vdev->ctrl_handler == NULL)
+ vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+ /* If the prio state pointer is NULL, then use the v4l2_device
+ prio state. */
+ if (vdev->prio == NULL)
+ vdev->prio = &vdev->v4l2_dev->prio;
+ }
+
+ /* Part 2: find a free minor, device node number and device index. */
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+ /* Keep the ranges for the first four types for historical
+ * reasons.
+ * Newer devices (not yet in place) should use the range
+ * of 128-191 and just pick the first free minor there
+ * (new style). */
+ switch (type) {
+ case VFL_TYPE_GRABBER:
+ minor_offset = 0;
+ minor_cnt = 64;
+ break;
+ case VFL_TYPE_RADIO:
+ minor_offset = 64;
+ minor_cnt = 64;
+ break;
+ case VFL_TYPE_VBI:
+ minor_offset = 224;
+ minor_cnt = 32;
+ break;
+ default:
+ minor_offset = 128;
+ minor_cnt = 64;
+ break;
+ }
+#endif
+
+ /* Pick a device node number */
+ mutex_lock(&videodev_lock);
+ nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
+ if (nr == minor_cnt)
+ nr = devnode_find(vdev, 0, minor_cnt);
+ if (nr == minor_cnt) {
+ printk(KERN_ERR "could not get a free device node number\n");
+ mutex_unlock(&videodev_lock);
+ return -ENFILE;
+ }
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+ /* 1-on-1 mapping of device node number to minor number */
+ i = nr;
+#else
+ /* The device node number and minor numbers are independent, so
+ we just find the first free minor number. */
+ for (i = 0; i < VIDEO_NUM_DEVICES; i++)
+ if (video_device[i] == NULL)
+ break;
+ if (i == VIDEO_NUM_DEVICES) {
+ mutex_unlock(&videodev_lock);
+ printk(KERN_ERR "could not get a free minor\n");
+ return -ENFILE;
+ }
+#endif
+ vdev->minor = i + minor_offset;
+ vdev->num = nr;
+ devnode_set(vdev);
+
+ /* Should not happen since we thought this minor was free */
+ WARN_ON(video_device[vdev->minor] != NULL);
+ vdev->index = get_index(vdev);
+ mutex_unlock(&videodev_lock);
+
+ if (vdev->ioctl_ops)
+ determine_valid_ioctls(vdev);
+
+ /* Part 3: Initialize the character device */
+ vdev->cdev = cdev_alloc();
+ if (vdev->cdev == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ vdev->cdev->ops = &v4l2_fops;
+ vdev->cdev->owner = owner;
+ ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+ kfree(vdev->cdev);
+ vdev->cdev = NULL;
+ goto cleanup;
+ }
+
+ /* Part 4: register the device with sysfs */
+ vdev->dev.class = &video_class;
+ vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
+ if (vdev->parent)
+ vdev->dev.parent = vdev->parent;
+ dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
+ ret = device_register(&vdev->dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: device_register failed\n", __func__);
+ goto cleanup;
+ }
+ /* Register the release callback that will be called when the last
+ reference to the device goes away. */
+ vdev->dev.release = v4l2_device_release;
+
+ if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
+ printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
+ name_base, nr, video_device_node_name(vdev));
+
+ /* Increase v4l2_device refcount */
+ if (vdev->v4l2_dev)
+ v4l2_device_get(vdev->v4l2_dev);
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ /* Part 5: Register the entity. */
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ vdev->vfl_type != VFL_TYPE_SUBDEV) {
+ vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ vdev->entity.name = vdev->name;
+ 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)
+ printk(KERN_WARNING
+ "%s: media_device_register_entity failed\n",
+ __func__);
+ }
+#endif
+ /* Part 6: Activate this minor. The char device can now be used. */
+ set_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_lock(&videodev_lock);
+ video_device[vdev->minor] = vdev;
+ mutex_unlock(&videodev_lock);
+
+ return 0;
+
+cleanup:
+ mutex_lock(&videodev_lock);
+ if (vdev->cdev)
+ cdev_del(vdev->cdev);
+ devnode_clear(vdev);
+ mutex_unlock(&videodev_lock);
+ /* Mark this video device as never having been registered. */
+ vdev->minor = -1;
+ return ret;
+}
+EXPORT_SYMBOL(__video_register_device);
+
+/**
+ * video_unregister_device - unregister a video4linux device
+ * @vdev: the device to unregister
+ *
+ * This unregisters the passed device. Future open calls will
+ * be met with errors.
+ */
+void video_unregister_device(struct video_device *vdev)
+{
+ /* Check if vdev was ever registered at all */
+ if (!vdev || !video_is_registered(vdev))
+ return;
+
+ mutex_lock(&videodev_lock);
+ /* This must be in a critical section to prevent a race with v4l2_open.
+ * Once this bit has been cleared video_get may never be called again.
+ */
+ clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_unlock(&videodev_lock);
+ device_unregister(&vdev->dev);
+}
+EXPORT_SYMBOL(video_unregister_device);
+
+/*
+ * Initialise video for linux
+ */
+static int __init videodev_init(void)
+{
+ dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+ int ret;
+
+ printk(KERN_INFO "Linux video capture interface: v2.00\n");
+ ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
+ if (ret < 0) {
+ printk(KERN_WARNING "videodev: unable to get major %d\n",
+ VIDEO_MAJOR);
+ return ret;
+ }
+
+ ret = class_register(&video_class);
+ if (ret < 0) {
+ unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
+ printk(KERN_WARNING "video_dev: class_register failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void __exit videodev_exit(void)
+{
+ dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+
+ class_unregister(&video_class);
+ unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
+}
+
+subsys_initcall(videodev_init);
+module_exit(videodev_exit)
+
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 1f203b85a637..1f203b85a637 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index ef2a33c94045..ef2a33c94045 100644
--- a/drivers/media/video/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c
index 9e3fc040ea20..9e3fc040ea20 100644
--- a/drivers/media/video/v4l2-fh.c
+++ b/drivers/media/v4l2-core/v4l2-fh.c
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/v4l2-core/v4l2-int-device.c
index f4473494af7a..f4473494af7a 100644
--- a/drivers/media/video/v4l2-int-device.c
+++ b/drivers/media/v4l2-core/v4l2-int-device.c
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 6bc47fc82fe2..6bc47fc82fe2 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 97b48318aee1..97b48318aee1 100644
--- a/drivers/media/video/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 9182f81deb5b..9182f81deb5b 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index bf7a326b1cdc..bf7a326b1cdc 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 3a43ba0959bf..3a43ba0959bf 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index f300deafd268..f300deafd268 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
diff --git a/drivers/media/v4l2-core/videobuf-dvb.c b/drivers/media/v4l2-core/videobuf-dvb.c
new file mode 100644
index 000000000000..b7efa4516d36
--- /dev/null
+++ b/drivers/media/v4l2-core/videobuf-dvb.c
@@ -0,0 +1,398 @@
+/*
+ *
+ * some helper function for simple DVB cards which simply DMA the
+ * complete transport stream and let the computer sort everything else
+ * (i.e. we are using the software demux, ...). Also uses the
+ * video-buf to manage DMA buffers.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+
+#include <linux/freezer.h>
+
+#include <media/videobuf-core.h>
+#include <media/videobuf-dvb.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+#define dprintk(fmt, arg...) if (debug) \
+ printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int videobuf_dvb_thread(void *data)
+{
+ struct videobuf_dvb *dvb = data;
+ struct videobuf_buffer *buf;
+ unsigned long flags;
+ void *outp;
+
+ dprintk("dvb thread started\n");
+ set_freezable();
+ videobuf_read_start(&dvb->dvbq);
+
+ for (;;) {
+ /* fetch next buffer */
+ buf = list_entry(dvb->dvbq.stream.next,
+ struct videobuf_buffer, stream);
+ list_del(&buf->stream);
+ videobuf_waiton(&dvb->dvbq, buf, 0, 1);
+
+ /* no more feeds left or stop_feed() asked us to quit */
+ if (0 == dvb->nfeeds)
+ break;
+ if (kthread_should_stop())
+ break;
+ try_to_freeze();
+
+ /* feed buffer data to demux */
+ outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf);
+
+ if (buf->state == VIDEOBUF_DONE)
+ dvb_dmx_swfilter(&dvb->demux, outp,
+ buf->size);
+
+ /* requeue buffer */
+ list_add_tail(&buf->stream,&dvb->dvbq.stream);
+ spin_lock_irqsave(dvb->dvbq.irqlock,flags);
+ dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf);
+ spin_unlock_irqrestore(dvb->dvbq.irqlock,flags);
+ }
+
+ videobuf_read_stop(&dvb->dvbq);
+ dprintk("dvb thread stopped\n");
+
+ /* Hmm, linux becomes *very* unhappy without this ... */
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ return 0;
+}
+
+static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct videobuf_dvb *dvb = demux->priv;
+ int rc;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (NULL != dvb->thread)
+ goto out;
+ dvb->thread = kthread_run(videobuf_dvb_thread,
+ dvb, "%s dvb", dvb->name);
+ if (IS_ERR(dvb->thread)) {
+ rc = PTR_ERR(dvb->thread);
+ dvb->thread = NULL;
+ }
+
+out:
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct videobuf_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+ if (0 == dvb->nfeeds && NULL != dvb->thread) {
+ err = kthread_stop(dvb->thread);
+ dvb->thread = NULL;
+ }
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
+ struct module *module,
+ void *adapter_priv,
+ struct device *device,
+ char *adapter_name,
+ short *adapter_nr,
+ int mfe_shared)
+{
+ int result;
+
+ mutex_init(&fe->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&fe->adapter, adapter_name, module,
+ device, adapter_nr);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+ adapter_name, result);
+ }
+ fe->adapter.priv = adapter_priv;
+ fe->adapter.mfe_shared = mfe_shared;
+
+ return result;
+}
+
+static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
+ struct videobuf_dvb *dvb)
+{
+ int result;
+
+ /* register frontend */
+ result = dvb_register_frontend(adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = videobuf_dvb_start_feed;
+ dvb->demux.stop_feed = videobuf_dvb_stop_feed;
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
+
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ 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;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb->frontend = NULL;
+
+ return result;
+}
+
+/* ------------------------------------------------------------------ */
+/* Register a single adapter and one or more frontends */
+int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
+ struct module *module,
+ void *adapter_priv,
+ struct device *device,
+ short *adapter_nr,
+ int mfe_shared)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe;
+ int res;
+
+ fe = videobuf_dvb_get_frontend(f, 1);
+ if (!fe) {
+ printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
+ return -EINVAL;
+ }
+
+ /* Bring up the adapter */
+ res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
+ fe->dvb.name, adapter_nr, mfe_shared);
+ if (res < 0) {
+ printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
+ return res;
+ }
+
+ /* Attach all of the frontends to the adapter */
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb);
+ if (res < 0) {
+ printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
+ fe->dvb.name, res);
+ goto err;
+ }
+ }
+ mutex_unlock(&f->lock);
+ return 0;
+
+err:
+ mutex_unlock(&f->lock);
+ videobuf_dvb_unregister_bus(f);
+ return res;
+}
+EXPORT_SYMBOL(videobuf_dvb_register_bus);
+
+void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
+{
+ videobuf_dvb_dealloc_frontends(f);
+
+ dvb_unregister_adapter(&f->adapter);
+}
+EXPORT_SYMBOL(videobuf_dvb_unregister_bus);
+
+struct videobuf_dvb_frontend *videobuf_dvb_get_frontend(
+ struct videobuf_dvb_frontends *f, int id)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe, *ret = NULL;
+
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->id == id) {
+ ret = fe;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_get_frontend);
+
+int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f,
+ struct dvb_frontend *p)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe = NULL;
+ int ret = 0;
+
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->dvb.frontend == p) {
+ ret = fe->id;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(videobuf_dvb_find_frontend);
+
+struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend(
+ struct videobuf_dvb_frontends *f, int id)
+{
+ struct videobuf_dvb_frontend *fe;
+
+ fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL);
+ if (fe == NULL)
+ goto fail_alloc;
+
+ fe->id = id;
+ mutex_init(&fe->dvb.lock);
+
+ mutex_lock(&f->lock);
+ list_add_tail(&fe->felist, &f->felist);
+ mutex_unlock(&f->lock);
+
+fail_alloc:
+ return fe;
+}
+EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
+
+void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f)
+{
+ struct list_head *list, *q;
+ struct videobuf_dvb_frontend *fe;
+
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct videobuf_dvb_frontend, felist);
+ if (fe->dvb.net.dvbdev) {
+ dvb_net_release(&fe->dvb.net);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_mem);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_hw);
+ dvb_dmxdev_release(&fe->dvb.dmxdev);
+ dvb_dmx_release(&fe->dvb.demux);
+ dvb_unregister_frontend(fe->dvb.frontend);
+ }
+ if (fe->dvb.frontend)
+ /* always allocated, may have been reset */
+ dvb_frontend_detach(fe->dvb.frontend);
+ list_del(list); /* remove list entry */
+ kfree(fe); /* free frontend allocation */
+ }
+ mutex_unlock(&f->lock);
+}
+EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends);
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c
index df142580e44c..df142580e44c 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf-vmalloc.c
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
new file mode 100644
index 000000000000..4da3df61901f
--- /dev/null
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -0,0 +1,2380 @@
+/*
+ * videobuf2-core.c - V4L2 driver helper framework
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.com>
+ * Marek Szyprowski <m.szyprowski@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.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-core.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "vb2: " fmt, ## arg); \
+ } while (0)
+
+#define call_memop(q, op, args...) \
+ (((q)->mem_ops->op) ? \
+ ((q)->mem_ops->op(args)) : 0)
+
+#define call_qop(q, op, args...) \
+ (((q)->ops->op) ? ((q)->ops->op(args)) : 0)
+
+#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
+ V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
+ V4L2_BUF_FLAG_PREPARED)
+
+/**
+ * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
+ */
+static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ void *mem_priv;
+ int plane;
+
+ /* Allocate memory for all planes in this buffer */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
+ q->plane_sizes[plane]);
+ if (IS_ERR_OR_NULL(mem_priv))
+ goto free;
+
+ /* Associate allocator private data with this plane */
+ vb->planes[plane].mem_priv = mem_priv;
+ vb->v4l2_planes[plane].length = q->plane_sizes[plane];
+ }
+
+ return 0;
+free:
+ /* Free already allocated memory if one of the allocations failed */
+ for (; plane > 0; --plane) {
+ call_memop(q, put, vb->planes[plane - 1].mem_priv);
+ vb->planes[plane - 1].mem_priv = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+/**
+ * __vb2_buf_mem_free() - free memory of the given buffer
+ */
+static void __vb2_buf_mem_free(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ 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);
+ }
+}
+
+/**
+ * __vb2_buf_userptr_put() - release userspace memory associated with
+ * a USERPTR buffer
+ */
+static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ if (vb->planes[plane].mem_priv)
+ call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ vb->planes[plane].mem_priv = NULL;
+ }
+}
+
+/**
+ * __setup_offsets() - setup unique offsets ("cookies") for every plane in
+ * every buffer on the queue
+ */
+static void __setup_offsets(struct vb2_queue *q, unsigned int n)
+{
+ unsigned int buffer, plane;
+ struct vb2_buffer *vb;
+ unsigned long off;
+
+ if (q->num_buffers) {
+ struct v4l2_plane *p;
+ vb = q->bufs[q->num_buffers - 1];
+ p = &vb->v4l2_planes[vb->num_planes - 1];
+ off = PAGE_ALIGN(p->m.mem_offset + p->length);
+ } else {
+ off = 0;
+ }
+
+ for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
+ vb = q->bufs[buffer];
+ if (!vb)
+ continue;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ vb->v4l2_planes[plane].length = q->plane_sizes[plane];
+ vb->v4l2_planes[plane].m.mem_offset = off;
+
+ dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
+ buffer, plane, off);
+
+ off += vb->v4l2_planes[plane].length;
+ off = PAGE_ALIGN(off);
+ }
+ }
+}
+
+/**
+ * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
+ * video buffer memory for all buffers/planes on the queue and initializes the
+ * queue
+ *
+ * Returns the number of buffers successfully allocated.
+ */
+static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
+ unsigned int num_buffers, unsigned int num_planes)
+{
+ unsigned int buffer;
+ struct vb2_buffer *vb;
+ int ret;
+
+ for (buffer = 0; buffer < num_buffers; ++buffer) {
+ /* Allocate videobuf buffer structures */
+ vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
+ if (!vb) {
+ dprintk(1, "Memory alloc for buffer struct failed\n");
+ break;
+ }
+
+ /* Length stores number of planes for multiplanar buffers */
+ if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
+ vb->v4l2_buf.length = num_planes;
+
+ vb->state = VB2_BUF_STATE_DEQUEUED;
+ vb->vb2_queue = q;
+ vb->num_planes = num_planes;
+ vb->v4l2_buf.index = q->num_buffers + buffer;
+ vb->v4l2_buf.type = q->type;
+ vb->v4l2_buf.memory = memory;
+
+ /* Allocate video buffer memory for the MMAP type */
+ if (memory == V4L2_MEMORY_MMAP) {
+ ret = __vb2_buf_mem_alloc(vb);
+ if (ret) {
+ dprintk(1, "Failed allocating memory for "
+ "buffer %d\n", buffer);
+ kfree(vb);
+ break;
+ }
+ /*
+ * Call the driver-provided buffer initialization
+ * callback, if given. An error in initialization
+ * results in queue setup failure.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "Buffer %d %p initialization"
+ " failed\n", buffer, vb);
+ __vb2_buf_mem_free(vb);
+ kfree(vb);
+ break;
+ }
+ }
+
+ q->bufs[q->num_buffers + buffer] = vb;
+ }
+
+ __setup_offsets(q, buffer);
+
+ dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
+ buffer, num_planes);
+
+ return buffer;
+}
+
+/**
+ * __vb2_free_mem() - release all video buffer memory for a given queue
+ */
+static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
+{
+ unsigned int buffer;
+ struct vb2_buffer *vb;
+
+ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ ++buffer) {
+ vb = q->bufs[buffer];
+ if (!vb)
+ continue;
+
+ /* Free MMAP buffers or release USERPTR buffers */
+ if (q->memory == V4L2_MEMORY_MMAP)
+ __vb2_buf_mem_free(vb);
+ else
+ __vb2_buf_userptr_put(vb);
+ }
+}
+
+/**
+ * __vb2_queue_free() - free buffers at the end of the queue - video memory and
+ * related information, if no buffers are left return the queue to an
+ * uninitialized state. Might be called even if the queue has already been freed.
+ */
+static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
+{
+ unsigned int buffer;
+
+ /* Call driver-provided cleanup function for each buffer, if provided */
+ if (q->ops->buf_cleanup) {
+ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ ++buffer) {
+ if (NULL == q->bufs[buffer])
+ continue;
+ q->ops->buf_cleanup(q->bufs[buffer]);
+ }
+ }
+
+ /* Release video buffer memory */
+ __vb2_free_mem(q, buffers);
+
+ /* Free videobuf buffers */
+ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ ++buffer) {
+ kfree(q->bufs[buffer]);
+ q->bufs[buffer] = NULL;
+ }
+
+ q->num_buffers -= buffers;
+ if (!q->num_buffers)
+ q->memory = 0;
+ INIT_LIST_HEAD(&q->queued_list);
+}
+
+/**
+ * __verify_planes_array() - verify that the planes array passed in struct
+ * v4l2_buffer from userspace can be safely used
+ */
+static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ /* Is memory for copying plane information present? */
+ if (NULL == b->m.planes) {
+ dprintk(1, "Multi-planar buffer passed but "
+ "planes array not provided\n");
+ return -EINVAL;
+ }
+
+ if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) {
+ dprintk(1, "Incorrect planes array length, "
+ "expected %d, got %d\n", vb->num_planes, b->length);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * __buffer_in_use() - return true if the buffer is in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
+{
+ unsigned int plane;
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ void *mem_priv = vb->planes[plane].mem_priv;
+ /*
+ * If num_users() has not been provided, call_memop
+ * will return 0, apparently nobody cares about this
+ * 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, num_users, mem_priv) > 1)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * __buffers_in_use() - return true if any buffers on the queue are in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffers_in_use(struct vb2_queue *q)
+{
+ unsigned int buffer;
+ for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+ if (__buffer_in_use(q, q->bufs[buffer]))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
+ * returned to userspace
+ */
+static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ int ret;
+
+ /* Copy back data such as timestamp, flags, etc. */
+ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
+ b->reserved2 = vb->v4l2_buf.reserved2;
+ b->reserved = vb->v4l2_buf.reserved;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
+ ret = __verify_planes_array(vb, b);
+ if (ret)
+ return ret;
+
+ /*
+ * Fill in plane-related data if userspace provided an array
+ * for it. The memory and size is verified above.
+ */
+ memcpy(b->m.planes, vb->v4l2_planes,
+ b->length * sizeof(struct v4l2_plane));
+ } else {
+ /*
+ * We use length and offset in v4l2_planes array even for
+ * single-planar buffers, but userspace does not.
+ */
+ b->length = vb->v4l2_planes[0].length;
+ b->bytesused = vb->v4l2_planes[0].bytesused;
+ if (q->memory == V4L2_MEMORY_MMAP)
+ b->m.offset = vb->v4l2_planes[0].m.mem_offset;
+ else if (q->memory == V4L2_MEMORY_USERPTR)
+ b->m.userptr = vb->v4l2_planes[0].m.userptr;
+ }
+
+ /*
+ * Clear any buffer state related flags.
+ */
+ b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
+
+ switch (vb->state) {
+ case VB2_BUF_STATE_QUEUED:
+ case VB2_BUF_STATE_ACTIVE:
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ break;
+ case VB2_BUF_STATE_ERROR:
+ b->flags |= V4L2_BUF_FLAG_ERROR;
+ /* fall through */
+ case VB2_BUF_STATE_DONE:
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ break;
+ case VB2_BUF_STATE_PREPARED:
+ b->flags |= V4L2_BUF_FLAG_PREPARED;
+ break;
+ case VB2_BUF_STATE_DEQUEUED:
+ /* nothing */
+ break;
+ }
+
+ if (__buffer_in_use(q, vb))
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ return 0;
+}
+
+/**
+ * vb2_querybuf() - query video buffer information
+ * @q: videobuf queue
+ * @b: buffer struct passed from userspace to vidioc_querybuf handler
+ * in driver
+ *
+ * Should be called from vidioc_querybuf ioctl handler in driver.
+ * This function will verify the passed v4l2_buffer structure and fill the
+ * relevant information for the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_querybuf handler in driver.
+ */
+int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+ struct vb2_buffer *vb;
+
+ if (b->type != q->type) {
+ dprintk(1, "querybuf: wrong buffer type\n");
+ return -EINVAL;
+ }
+
+ if (b->index >= q->num_buffers) {
+ dprintk(1, "querybuf: buffer index out of range\n");
+ return -EINVAL;
+ }
+ vb = q->bufs[b->index];
+
+ return __fill_v4l2_buffer(vb, b);
+}
+EXPORT_SYMBOL(vb2_querybuf);
+
+/**
+ * __verify_userptr_ops() - verify that all memory operations required for
+ * USERPTR queue type have been provided
+ */
+static int __verify_userptr_ops(struct vb2_queue *q)
+{
+ if (!(q->io_modes & VB2_USERPTR) || !q->mem_ops->get_userptr ||
+ !q->mem_ops->put_userptr)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * __verify_mmap_ops() - verify that all memory operations required for
+ * MMAP queue type have been provided
+ */
+static int __verify_mmap_ops(struct vb2_queue *q)
+{
+ if (!(q->io_modes & VB2_MMAP) || !q->mem_ops->alloc ||
+ !q->mem_ops->put || !q->mem_ops->mmap)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * __verify_memory_type() - Check whether the memory type and buffer type
+ * passed to a buffer operation are compatible with the queue.
+ */
+static int __verify_memory_type(struct vb2_queue *q,
+ enum v4l2_memory memory, enum v4l2_buf_type type)
+{
+ if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) {
+ dprintk(1, "reqbufs: unsupported memory type\n");
+ return -EINVAL;
+ }
+
+ if (type != q->type) {
+ dprintk(1, "reqbufs: requested type is incorrect\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure all the required memory ops for given memory type
+ * are available.
+ */
+ if (memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
+ dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
+ return -EINVAL;
+ }
+
+ if (memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
+ dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Place the busy tests at the end: -EBUSY can be ignored when
+ * create_bufs is called with count == 0, but count == 0 should still
+ * do the memory and type validation.
+ */
+ if (q->fileio) {
+ dprintk(1, "reqbufs: file io in progress\n");
+ return -EBUSY;
+ }
+ return 0;
+}
+
+/**
+ * __reqbufs() - Initiate streaming
+ * @q: videobuf2 queue
+ * @req: struct passed from userspace to vidioc_reqbufs handler in driver
+ *
+ * Should be called from vidioc_reqbufs ioctl handler of a driver.
+ * This function:
+ * 1) verifies streaming parameters passed from the userspace,
+ * 2) sets up the queue,
+ * 3) negotiates number of buffers and planes per buffer with the driver
+ * to be used during streaming,
+ * 4) allocates internal buffer structures (struct vb2_buffer), according to
+ * the agreed parameters,
+ * 5) for MMAP memory type, allocates actual video memory, using the
+ * memory handling/allocation routines provided during queue initialization
+ *
+ * If req->count is 0, all the memory will be freed instead.
+ * If the queue has been allocated previously (by a previous vb2_reqbufs) call
+ * and the queue is not busy, memory will be reallocated.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_reqbufs handler in driver.
+ */
+static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+ unsigned int num_buffers, allocated_buffers, num_planes = 0;
+ int ret;
+
+ if (q->streaming) {
+ dprintk(1, "reqbufs: streaming active\n");
+ return -EBUSY;
+ }
+
+ if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
+ /*
+ * We already have buffers allocated, so first check if they
+ * are not in use and can be freed.
+ */
+ if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+ dprintk(1, "reqbufs: memory in use, cannot free\n");
+ return -EBUSY;
+ }
+
+ __vb2_queue_free(q, q->num_buffers);
+
+ /*
+ * In case of REQBUFS(0) return immediately without calling
+ * driver's queue_setup() callback and allocating resources.
+ */
+ if (req->count == 0)
+ return 0;
+ }
+
+ /*
+ * Make sure the requested values and current defaults are sane.
+ */
+ num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
+ memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
+ memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
+ q->memory = req->memory;
+
+ /*
+ * Ask the driver how many buffers and planes per buffer it requires.
+ * Driver also sets the size and allocator context for each plane.
+ */
+ ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
+ q->plane_sizes, q->alloc_ctx);
+ if (ret)
+ return ret;
+
+ /* Finally, allocate buffers and video memory */
+ ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
+ if (ret == 0) {
+ dprintk(1, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ allocated_buffers = ret;
+
+ /*
+ * Check if driver can handle the allocated number of buffers.
+ */
+ if (allocated_buffers < num_buffers) {
+ num_buffers = allocated_buffers;
+
+ ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
+ &num_planes, q->plane_sizes, q->alloc_ctx);
+
+ if (!ret && allocated_buffers < num_buffers)
+ ret = -ENOMEM;
+
+ /*
+ * Either the driver has accepted a smaller number of buffers,
+ * or .queue_setup() returned an error
+ */
+ }
+
+ q->num_buffers = allocated_buffers;
+
+ if (ret < 0) {
+ __vb2_queue_free(q, allocated_buffers);
+ return ret;
+ }
+
+ /*
+ * Return the number of successfully allocated buffers
+ * to the userspace.
+ */
+ req->count = allocated_buffers;
+
+ return 0;
+}
+
+/**
+ * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
+ * type values.
+ * @q: videobuf2 queue
+ * @req: struct passed from userspace to vidioc_reqbufs handler in driver
+ */
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+ int ret = __verify_memory_type(q, req->memory, req->type);
+
+ return ret ? ret : __reqbufs(q, req);
+}
+EXPORT_SYMBOL_GPL(vb2_reqbufs);
+
+/**
+ * __create_bufs() - Allocate buffers and any required auxiliary structs
+ * @q: videobuf2 queue
+ * @create: creation parameters, passed from userspace to vidioc_create_bufs
+ * handler in driver
+ *
+ * Should be called from vidioc_create_bufs ioctl handler of a driver.
+ * This function:
+ * 1) verifies parameter sanity
+ * 2) calls the .queue_setup() queue operation
+ * 3) performs any necessary memory allocations
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_create_bufs handler in driver.
+ */
+static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
+{
+ unsigned int num_planes = 0, num_buffers, allocated_buffers;
+ int ret;
+
+ if (q->num_buffers == VIDEO_MAX_FRAME) {
+ dprintk(1, "%s(): maximum number of buffers already allocated\n",
+ __func__);
+ return -ENOBUFS;
+ }
+
+ if (!q->num_buffers) {
+ memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
+ memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
+ q->memory = create->memory;
+ }
+
+ num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers);
+
+ /*
+ * Ask the driver, whether the requested number of buffers, planes per
+ * buffer and their sizes are acceptable
+ */
+ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
+ &num_planes, q->plane_sizes, q->alloc_ctx);
+ if (ret)
+ return ret;
+
+ /* Finally, allocate buffers and video memory */
+ ret = __vb2_queue_alloc(q, create->memory, num_buffers,
+ num_planes);
+ if (ret == 0) {
+ dprintk(1, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ allocated_buffers = ret;
+
+ /*
+ * Check if driver can handle the so far allocated number of buffers.
+ */
+ if (ret < num_buffers) {
+ num_buffers = ret;
+
+ /*
+ * q->num_buffers contains the total number of buffers, that the
+ * queue driver has set up
+ */
+ ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
+ &num_planes, q->plane_sizes, q->alloc_ctx);
+
+ if (!ret && allocated_buffers < num_buffers)
+ ret = -ENOMEM;
+
+ /*
+ * Either the driver has accepted a smaller number of buffers,
+ * or .queue_setup() returned an error
+ */
+ }
+
+ q->num_buffers += allocated_buffers;
+
+ if (ret < 0) {
+ __vb2_queue_free(q, allocated_buffers);
+ return -ENOMEM;
+ }
+
+ /*
+ * Return the number of successfully allocated buffers
+ * to the userspace.
+ */
+ create->count = allocated_buffers;
+
+ return 0;
+}
+
+/**
+ * vb2_create_bufs() - Wrapper for __create_bufs() that also verifies the
+ * memory and type values.
+ * @q: videobuf2 queue
+ * @create: creation parameters, passed from userspace to vidioc_create_bufs
+ * handler in driver
+ */
+int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
+{
+ int ret = __verify_memory_type(q, create->memory, create->format.type);
+
+ create->index = q->num_buffers;
+ if (create->count == 0)
+ return ret != -EBUSY ? ret : 0;
+ return ret ? ret : __create_bufs(q, create);
+}
+EXPORT_SYMBOL_GPL(vb2_create_bufs);
+
+/**
+ * vb2_plane_vaddr() - Return a kernel virtual address of a given plane
+ * @vb: vb2_buffer to which the plane in question belongs to
+ * @plane_no: plane number for which the address is to be returned
+ *
+ * This function returns a kernel virtual address of a given plane if
+ * such a mapping exist, NULL otherwise.
+ */
+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 || !vb->planes[plane_no].mem_priv)
+ return NULL;
+
+ return call_memop(q, vaddr, vb->planes[plane_no].mem_priv);
+
+}
+EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
+
+/**
+ * vb2_plane_cookie() - Return allocator specific cookie for the given plane
+ * @vb: vb2_buffer to which the plane in question belongs to
+ * @plane_no: plane number for which the cookie is to be returned
+ *
+ * This function returns an allocator specific cookie for a given plane if
+ * available, NULL otherwise. The allocator should provide some simple static
+ * inline function, which would convert this cookie to the allocator specific
+ * type that can be used directly by the driver to access the buffer. This can
+ * be for example physical address, pointer to scatter list or IOMMU mapping.
+ */
+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 || !vb->planes[plane_no].mem_priv)
+ return NULL;
+
+ return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
+}
+EXPORT_SYMBOL_GPL(vb2_plane_cookie);
+
+/**
+ * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished
+ * @vb: vb2_buffer returned from the driver
+ * @state: either VB2_BUF_STATE_DONE if the operation finished successfully
+ * or VB2_BUF_STATE_ERROR if the operation finished with an error
+ *
+ * This function should be called by the driver after a hardware operation on
+ * a buffer is finished and the buffer may be returned to userspace. The driver
+ * cannot use this buffer anymore until it is queued back to it by videobuf
+ * by the means of buf_queue callback. Only buffers previously queued to the
+ * driver by buf_queue can be passed to this function.
+ */
+void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned long flags;
+
+ if (vb->state != VB2_BUF_STATE_ACTIVE)
+ return;
+
+ if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
+ return;
+
+ dprintk(4, "Done processing on buffer %d, state: %d\n",
+ vb->v4l2_buf.index, vb->state);
+
+ /* Add the buffer to the done buffers list */
+ spin_lock_irqsave(&q->done_lock, flags);
+ vb->state = state;
+ list_add_tail(&vb->done_entry, &q->done_list);
+ atomic_dec(&q->queued_count);
+ spin_unlock_irqrestore(&q->done_lock, flags);
+
+ /* Inform any processes that may be waiting for buffers */
+ wake_up(&q->done_wq);
+}
+EXPORT_SYMBOL_GPL(vb2_buffer_done);
+
+/**
+ * __fill_vb2_buffer() - fill a vb2_buffer with information provided in
+ * a v4l2_buffer by the userspace
+ */
+static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
+ struct v4l2_plane *v4l2_planes)
+{
+ unsigned int plane;
+ int ret;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+ /*
+ * Verify that the userspace gave us a valid array for
+ * plane information.
+ */
+ ret = __verify_planes_array(vb, b);
+ if (ret)
+ return ret;
+
+ /* Fill in driver-provided information for OUTPUT types */
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * Will have to go up to b->length when API starts
+ * accepting variable number of planes.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ v4l2_planes[plane].bytesused =
+ b->m.planes[plane].bytesused;
+ v4l2_planes[plane].data_offset =
+ b->m.planes[plane].data_offset;
+ }
+ }
+
+ if (b->memory == V4L2_MEMORY_USERPTR) {
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ v4l2_planes[plane].m.userptr =
+ b->m.planes[plane].m.userptr;
+ v4l2_planes[plane].length =
+ b->m.planes[plane].length;
+ }
+ }
+ } else {
+ /*
+ * Single-planar buffers do not use planes array,
+ * so fill in relevant v4l2_buffer struct fields instead.
+ * In videobuf we use our internal V4l2_planes struct for
+ * single-planar buffers as well, for simplicity.
+ */
+ if (V4L2_TYPE_IS_OUTPUT(b->type))
+ v4l2_planes[0].bytesused = b->bytesused;
+
+ if (b->memory == V4L2_MEMORY_USERPTR) {
+ v4l2_planes[0].m.userptr = b->m.userptr;
+ v4l2_planes[0].length = b->length;
+ }
+ }
+
+ vb->v4l2_buf.field = b->field;
+ vb->v4l2_buf.timestamp = b->timestamp;
+ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
+
+ return 0;
+}
+
+/**
+ * __qbuf_userptr() - handle qbuf of a USERPTR buffer
+ */
+static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct vb2_queue *q = vb->vb2_queue;
+ void *mem_priv;
+ unsigned int plane;
+ int ret;
+ int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+
+ /* Verify and copy relevant information provided by the userspace */
+ ret = __fill_vb2_buffer(vb, b, planes);
+ if (ret)
+ return ret;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ /* Skip the plane if already verified */
+ 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;
+
+ dprintk(3, "qbuf: userspace address for plane %d changed, "
+ "reacquiring memory\n", plane);
+
+ /* Check if the provided plane buffer is large enough */
+ if (planes[plane].length < q->plane_sizes[plane]) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Release previously acquired memory if present */
+ if (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 */
+ 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 = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
+ goto err;
+ }
+ vb->planes[plane].mem_priv = mem_priv;
+ }
+
+ /*
+ * Call driver-specific initialization on the newly acquired buffer,
+ * if provided.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ goto err;
+ }
+
+ /*
+ * Now that everything is in order, copy relevant information
+ * provided by userspace.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ vb->v4l2_planes[plane] = planes[plane];
+
+ return 0;
+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, 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;
+ }
+
+ return ret;
+}
+
+/**
+ * __qbuf_mmap() - handle qbuf of an MMAP buffer
+ */
+static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
+}
+
+/**
+ * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
+ */
+static void __enqueue_in_driver(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+
+ vb->state = VB2_BUF_STATE_ACTIVE;
+ atomic_inc(&q->queued_count);
+ q->ops->buf_queue(vb);
+}
+
+static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ int ret;
+
+ switch (q->memory) {
+ case V4L2_MEMORY_MMAP:
+ ret = __qbuf_mmap(vb, b);
+ break;
+ case V4L2_MEMORY_USERPTR:
+ ret = __qbuf_userptr(vb, b);
+ break;
+ default:
+ WARN(1, "Invalid queue type\n");
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ ret = call_qop(q, buf_prepare, vb);
+ if (ret)
+ dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
+ else
+ vb->state = VB2_BUF_STATE_PREPARED;
+
+ return ret;
+}
+
+/**
+ * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel
+ * @q: videobuf2 queue
+ * @b: buffer structure passed from userspace to vidioc_prepare_buf
+ * handler in driver
+ *
+ * Should be called from vidioc_prepare_buf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_prepare callback in the driver (if provided), in which
+ * driver-specific buffer initialization can be performed,
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_prepare_buf handler in driver.
+ */
+int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+ struct vb2_buffer *vb;
+ int ret;
+
+ if (q->fileio) {
+ dprintk(1, "%s(): file io in progress\n", __func__);
+ return -EBUSY;
+ }
+
+ if (b->type != q->type) {
+ dprintk(1, "%s(): invalid buffer type\n", __func__);
+ return -EINVAL;
+ }
+
+ if (b->index >= q->num_buffers) {
+ dprintk(1, "%s(): buffer index out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ vb = q->bufs[b->index];
+ if (NULL == vb) {
+ /* Should never happen */
+ dprintk(1, "%s(): buffer is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (b->memory != q->memory) {
+ dprintk(1, "%s(): invalid memory type\n", __func__);
+ return -EINVAL;
+ }
+
+ if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+ dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state);
+ return -EINVAL;
+ }
+
+ ret = __buf_prepare(vb, b);
+ if (ret < 0)
+ return ret;
+
+ __fill_v4l2_buffer(vb, b);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_prepare_buf);
+
+/**
+ * vb2_qbuf() - Queue a buffer from userspace
+ * @q: videobuf2 queue
+ * @b: buffer structure passed from userspace to vidioc_qbuf handler
+ * in driver
+ *
+ * Should be called from vidioc_qbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) if necessary, calls buf_prepare callback in the driver (if provided), in
+ * which driver-specific buffer initialization can be performed,
+ * 3) if streaming is on, queues the buffer in driver by the means of buf_queue
+ * callback for processing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_qbuf handler in driver.
+ */
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+ struct rw_semaphore *mmap_sem = NULL;
+ struct vb2_buffer *vb;
+ 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");
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ if (b->type != q->type) {
+ dprintk(1, "qbuf: invalid buffer type\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (b->index >= q->num_buffers) {
+ dprintk(1, "qbuf: buffer index out of range\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ vb = q->bufs[b->index];
+ if (NULL == vb) {
+ /* Should never happen */
+ dprintk(1, "qbuf: buffer is NULL\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (b->memory != q->memory) {
+ dprintk(1, "qbuf: invalid memory type\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ switch (vb->state) {
+ case VB2_BUF_STATE_DEQUEUED:
+ ret = __buf_prepare(vb, b);
+ if (ret)
+ goto unlock;
+ case VB2_BUF_STATE_PREPARED:
+ break;
+ default:
+ dprintk(1, "qbuf: buffer already in use\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ /*
+ * Add to the queued buffers list, a buffer will stay on it until
+ * dequeued in dqbuf.
+ */
+ list_add_tail(&vb->queued_entry, &q->queued_list);
+ vb->state = VB2_BUF_STATE_QUEUED;
+
+ /*
+ * If already streaming, give the buffer to driver for processing.
+ * If not, the buffer will be given to driver on next streamon.
+ */
+ if (q->streaming)
+ __enqueue_in_driver(vb);
+
+ /* Fill buffer information for the userspace */
+ __fill_v4l2_buffer(vb, b);
+
+ dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
+unlock:
+ if (mmap_sem)
+ up_read(mmap_sem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf);
+
+/**
+ * __vb2_wait_for_done_vb() - wait for a buffer to become available
+ * for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
+{
+ /*
+ * All operations on vb_done_list are performed under done_lock
+ * spinlock protection. However, buffers may be removed from
+ * it and returned to userspace only while holding both driver's
+ * lock and the done_lock spinlock. Thus we can be sure that as
+ * long as we hold the driver's lock, the list will remain not
+ * empty if list_empty() check succeeds.
+ */
+
+ for (;;) {
+ int ret;
+
+ if (!q->streaming) {
+ dprintk(1, "Streaming off, will not wait for buffers\n");
+ return -EINVAL;
+ }
+
+ if (!list_empty(&q->done_list)) {
+ /*
+ * Found a buffer that we were waiting for.
+ */
+ break;
+ }
+
+ if (nonblocking) {
+ dprintk(1, "Nonblocking and no buffers to dequeue, "
+ "will not wait\n");
+ return -EAGAIN;
+ }
+
+ /*
+ * We are streaming and blocking, wait for another buffer to
+ * become ready or for streamoff. Driver's lock is released to
+ * allow streamoff or qbuf to be called while waiting.
+ */
+ call_qop(q, wait_prepare, q);
+
+ /*
+ * All locks have been released, it is safe to sleep now.
+ */
+ dprintk(3, "Will sleep waiting for buffers\n");
+ ret = wait_event_interruptible(q->done_wq,
+ !list_empty(&q->done_list) || !q->streaming);
+
+ /*
+ * We need to reevaluate both conditions again after reacquiring
+ * the locks or return an error if one occurred.
+ */
+ call_qop(q, wait_finish, q);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/**
+ * __vb2_get_done_vb() - get a buffer ready for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
+ int nonblocking)
+{
+ unsigned long flags;
+ int ret;
+
+ /*
+ * Wait for at least one buffer to become available on the done_list.
+ */
+ ret = __vb2_wait_for_done_vb(q, nonblocking);
+ if (ret)
+ return ret;
+
+ /*
+ * Driver's lock has been held since we last verified that done_list
+ * is not empty, so no need for another list_empty(done_list) check.
+ */
+ spin_lock_irqsave(&q->done_lock, flags);
+ *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
+ list_del(&(*vb)->done_entry);
+ spin_unlock_irqrestore(&q->done_lock, flags);
+
+ return 0;
+}
+
+/**
+ * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2
+ * @q: videobuf2 queue
+ *
+ * This function will wait until all buffers that have been given to the driver
+ * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call
+ * wait_prepare, wait_finish pair. It is intended to be called with all locks
+ * taken, for example from stop_streaming() callback.
+ */
+int vb2_wait_for_all_buffers(struct vb2_queue *q)
+{
+ if (!q->streaming) {
+ dprintk(1, "Streaming off, will not wait for buffers\n");
+ return -EINVAL;
+ }
+
+ wait_event(q->done_wq, !atomic_read(&q->queued_count));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
+
+/**
+ * vb2_dqbuf() - Dequeue a buffer to the userspace
+ * @q: videobuf2 queue
+ * @b: buffer structure passed from userspace to vidioc_dqbuf handler
+ * in driver
+ * @nonblocking: if true, this call will not sleep waiting for a buffer if no
+ * buffers ready for dequeuing are present. Normally the driver
+ * would be passing (file->f_flags & O_NONBLOCK) here
+ *
+ * Should be called from vidioc_dqbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_finish callback in the driver (if provided), in which
+ * driver can perform any additional operations that may be required before
+ * returning the buffer to userspace, such as cache sync,
+ * 3) the buffer struct members are filled with relevant information for
+ * the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_dqbuf handler in driver.
+ */
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+ struct vb2_buffer *vb = NULL;
+ int ret;
+
+ if (q->fileio) {
+ dprintk(1, "dqbuf: file io in progress\n");
+ return -EBUSY;
+ }
+
+ if (b->type != q->type) {
+ dprintk(1, "dqbuf: invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ ret = __vb2_get_done_vb(q, &vb, nonblocking);
+ if (ret < 0) {
+ dprintk(1, "dqbuf: error getting next done buffer\n");
+ return ret;
+ }
+
+ ret = call_qop(q, buf_finish, vb);
+ if (ret) {
+ dprintk(1, "dqbuf: buffer finish failed\n");
+ return ret;
+ }
+
+ switch (vb->state) {
+ case VB2_BUF_STATE_DONE:
+ dprintk(3, "dqbuf: Returning done buffer\n");
+ break;
+ case VB2_BUF_STATE_ERROR:
+ dprintk(3, "dqbuf: Returning done buffer with errors\n");
+ break;
+ default:
+ dprintk(1, "dqbuf: Invalid buffer state\n");
+ return -EINVAL;
+ }
+
+ /* Fill buffer information for the userspace */
+ __fill_v4l2_buffer(vb, b);
+ /* Remove from videobuf queue */
+ list_del(&vb->queued_entry);
+
+ dprintk(1, "dqbuf of buffer %d, with state %d\n",
+ vb->v4l2_buf.index, vb->state);
+
+ vb->state = VB2_BUF_STATE_DEQUEUED;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_dqbuf);
+
+/**
+ * __vb2_queue_cancel() - cancel and stop (pause) streaming
+ *
+ * Removes all queued buffers from driver's queue and all buffers queued by
+ * userspace from videobuf's queue. Returns to state after reqbufs.
+ */
+static void __vb2_queue_cancel(struct vb2_queue *q)
+{
+ unsigned int i;
+
+ /*
+ * Tell driver to stop all transactions and release all queued
+ * buffers.
+ */
+ if (q->streaming)
+ call_qop(q, stop_streaming, q);
+ q->streaming = 0;
+
+ /*
+ * Remove all buffers from videobuf's list...
+ */
+ INIT_LIST_HEAD(&q->queued_list);
+ /*
+ * ...and done list; userspace will not receive any buffers it
+ * has not already dequeued before initiating cancel.
+ */
+ INIT_LIST_HEAD(&q->done_list);
+ atomic_set(&q->queued_count, 0);
+ wake_up_all(&q->done_wq);
+
+ /*
+ * Reinitialize all buffers for next use.
+ */
+ for (i = 0; i < q->num_buffers; ++i)
+ q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
+}
+
+/**
+ * vb2_streamon - start streaming
+ * @q: videobuf2 queue
+ * @type: type argument passed from userspace to vidioc_streamon handler
+ *
+ * Should be called from vidioc_streamon handler of a driver.
+ * This function:
+ * 1) verifies current state
+ * 2) passes any previously queued buffers to the driver and starts streaming
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamon handler in the driver.
+ */
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+ struct vb2_buffer *vb;
+ int ret;
+
+ if (q->fileio) {
+ dprintk(1, "streamon: file io in progress\n");
+ return -EBUSY;
+ }
+
+ if (type != q->type) {
+ dprintk(1, "streamon: invalid stream type\n");
+ return -EINVAL;
+ }
+
+ if (q->streaming) {
+ dprintk(1, "streamon: already streaming\n");
+ return -EBUSY;
+ }
+
+ /*
+ * If any buffers were queued before streamon,
+ * we can now pass them to driver for processing.
+ */
+ list_for_each_entry(vb, &q->queued_list, queued_entry)
+ __enqueue_in_driver(vb);
+
+ /*
+ * Let driver notice that streaming state has been enabled.
+ */
+ ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+ if (ret) {
+ dprintk(1, "streamon: driver refused to start streaming\n");
+ __vb2_queue_cancel(q);
+ return ret;
+ }
+
+ q->streaming = 1;
+
+ dprintk(3, "Streamon successful\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_streamon);
+
+
+/**
+ * vb2_streamoff - stop streaming
+ * @q: videobuf2 queue
+ * @type: type argument passed from userspace to vidioc_streamoff handler
+ *
+ * Should be called from vidioc_streamoff handler of a driver.
+ * This function:
+ * 1) verifies current state,
+ * 2) stop streaming and dequeues any queued buffers, including those previously
+ * passed to the driver (after waiting for the driver to finish).
+ *
+ * This call can be used for pausing playback.
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamoff handler in the driver
+ */
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+ if (q->fileio) {
+ dprintk(1, "streamoff: file io in progress\n");
+ return -EBUSY;
+ }
+
+ if (type != q->type) {
+ dprintk(1, "streamoff: invalid stream type\n");
+ return -EINVAL;
+ }
+
+ if (!q->streaming) {
+ dprintk(1, "streamoff: not streaming\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Cancel will pause streaming and remove all buffers from the driver
+ * and videobuf, effectively returning control over them to userspace.
+ */
+ __vb2_queue_cancel(q);
+
+ dprintk(3, "Streamoff successful\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_streamoff);
+
+/**
+ * __find_plane_by_offset() - find plane associated with the given offset off
+ */
+static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
+ unsigned int *_buffer, unsigned int *_plane)
+{
+ struct vb2_buffer *vb;
+ unsigned int buffer, plane;
+
+ /*
+ * Go over all buffers and their planes, comparing the given offset
+ * with an offset assigned to each plane. If a match is found,
+ * return its buffer and plane numbers.
+ */
+ for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+ vb = q->bufs[buffer];
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ if (vb->v4l2_planes[plane].m.mem_offset == off) {
+ *_buffer = buffer;
+ *_plane = plane;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * vb2_mmap() - map video buffers into application address space
+ * @q: videobuf2 queue
+ * @vma: vma passed to the mmap file operation handler in the driver
+ *
+ * Should be called from mmap file operation handler of a driver.
+ * This function maps one plane of one of the available video buffers to
+ * userspace. To map whole video memory allocated on reqbufs, this function
+ * has to be called once per each plane per each buffer previously allocated.
+ *
+ * When the userspace application calls mmap, it passes to it an offset returned
+ * to it earlier by the means of vidioc_querybuf handler. That offset acts as
+ * a "cookie", which is then used to identify the plane to be mapped.
+ * This function finds a plane with a matching offset and a mapping is performed
+ * by the means of a provided memory operation.
+ *
+ * The return values from this function are intended to be directly returned
+ * from the mmap handler in driver.
+ */
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
+{
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+ struct vb2_buffer *vb;
+ unsigned int buffer, plane;
+ int ret;
+
+ if (q->memory != V4L2_MEMORY_MMAP) {
+ dprintk(1, "Queue is not currently set up for mmap\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Check memory area access mode.
+ */
+ if (!(vma->vm_flags & VM_SHARED)) {
+ dprintk(1, "Invalid vma flags, VM_SHARED needed\n");
+ return -EINVAL;
+ }
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ if (!(vma->vm_flags & VM_WRITE)) {
+ dprintk(1, "Invalid vma flags, VM_WRITE needed\n");
+ return -EINVAL;
+ }
+ } else {
+ if (!(vma->vm_flags & VM_READ)) {
+ dprintk(1, "Invalid vma flags, VM_READ needed\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Find the plane corresponding to the offset passed by userspace.
+ */
+ ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ if (ret)
+ return ret;
+
+ vb = q->bufs[buffer];
+
+ ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
+ if (ret)
+ return ret;
+
+ dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_mmap);
+
+#ifndef CONFIG_MMU
+unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ unsigned long off = pgoff << PAGE_SHIFT;
+ struct vb2_buffer *vb;
+ unsigned int buffer, plane;
+ int ret;
+
+ if (q->memory != V4L2_MEMORY_MMAP) {
+ dprintk(1, "Queue is not currently set up for mmap\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Find the plane corresponding to the offset passed by userspace.
+ */
+ ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ if (ret)
+ return ret;
+
+ vb = q->bufs[buffer];
+
+ return (unsigned long)vb2_plane_vaddr(vb, plane);
+}
+EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
+#endif
+
+static int __vb2_init_fileio(struct vb2_queue *q, int read);
+static int __vb2_cleanup_fileio(struct vb2_queue *q);
+
+/**
+ * vb2_poll() - implements poll userspace operation
+ * @q: videobuf2 queue
+ * @file: file argument passed to the poll file operation handler
+ * @wait: wait argument passed to the poll file operation handler
+ *
+ * This function implements poll file operation handler for a driver.
+ * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
+ * be informed that the file descriptor of a video device is available for
+ * reading.
+ * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
+ * will be reported as available for writing.
+ *
+ * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any
+ * pending events.
+ *
+ * The return values from this function are intended to be directly returned
+ * from poll handler in driver.
+ */
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
+{
+ struct video_device *vfd = video_devdata(file);
+ unsigned long req_events = poll_requested_events(wait);
+ struct vb2_buffer *vb = NULL;
+ unsigned int res = 0;
+ unsigned long flags;
+
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+ struct v4l2_fh *fh = file->private_data;
+
+ if (v4l2_event_pending(fh))
+ res = POLLPRI;
+ else if (req_events & POLLPRI)
+ poll_wait(file, &fh->wait, wait);
+ }
+
+ /*
+ * Start file I/O emulator only if streaming API has not been used yet.
+ */
+ if (q->num_buffers == 0 && q->fileio == NULL) {
+ if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
+ if (__vb2_init_fileio(q, 1))
+ return res | POLLERR;
+ }
+ if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
+ (req_events & (POLLOUT | POLLWRNORM))) {
+ if (__vb2_init_fileio(q, 0))
+ return res | POLLERR;
+ /*
+ * Write to OUTPUT queue can be done immediately.
+ */
+ return res | POLLOUT | POLLWRNORM;
+ }
+ }
+
+ /*
+ * There is nothing to wait for if no buffers have already been queued.
+ */
+ if (list_empty(&q->queued_list))
+ return res | POLLERR;
+
+ poll_wait(file, &q->done_wq, wait);
+
+ /*
+ * Take first buffer available for dequeuing.
+ */
+ spin_lock_irqsave(&q->done_lock, flags);
+ if (!list_empty(&q->done_list))
+ vb = list_first_entry(&q->done_list, struct vb2_buffer,
+ done_entry);
+ spin_unlock_irqrestore(&q->done_lock, flags);
+
+ if (vb && (vb->state == VB2_BUF_STATE_DONE
+ || vb->state == VB2_BUF_STATE_ERROR)) {
+ return (V4L2_TYPE_IS_OUTPUT(q->type)) ?
+ res | POLLOUT | POLLWRNORM :
+ res | POLLIN | POLLRDNORM;
+ }
+ return res;
+}
+EXPORT_SYMBOL_GPL(vb2_poll);
+
+/**
+ * vb2_queue_init() - initialize a videobuf2 queue
+ * @q: videobuf2 queue; this structure should be allocated in driver
+ *
+ * The vb2_queue structure should be allocated by the driver. The driver is
+ * responsible of clearing it's content and setting initial values for some
+ * required entries before calling this function.
+ * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
+ * to the struct vb2_queue description in include/media/videobuf2-core.h
+ * for more information.
+ */
+int vb2_queue_init(struct vb2_queue *q)
+{
+ BUG_ON(!q);
+ BUG_ON(!q->ops);
+ BUG_ON(!q->mem_ops);
+ BUG_ON(!q->type);
+ BUG_ON(!q->io_modes);
+
+ BUG_ON(!q->ops->queue_setup);
+ BUG_ON(!q->ops->buf_queue);
+
+ INIT_LIST_HEAD(&q->queued_list);
+ INIT_LIST_HEAD(&q->done_list);
+ spin_lock_init(&q->done_lock);
+ init_waitqueue_head(&q->done_wq);
+
+ if (q->buf_struct_size == 0)
+ q->buf_struct_size = sizeof(struct vb2_buffer);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_init);
+
+/**
+ * vb2_queue_release() - stop streaming, release the queue and free memory
+ * @q: videobuf2 queue
+ *
+ * This function stops streaming and performs necessary clean ups, including
+ * freeing video buffer memory. The driver is responsible for freeing
+ * the vb2_queue structure itself.
+ */
+void vb2_queue_release(struct vb2_queue *q)
+{
+ __vb2_cleanup_fileio(q);
+ __vb2_queue_cancel(q);
+ __vb2_queue_free(q, q->num_buffers);
+}
+EXPORT_SYMBOL_GPL(vb2_queue_release);
+
+/**
+ * struct vb2_fileio_buf - buffer context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. This structure is used for
+ * tracking context related to the buffers.
+ */
+struct vb2_fileio_buf {
+ void *vaddr;
+ unsigned int size;
+ unsigned int pos;
+ unsigned int queued:1;
+};
+
+/**
+ * struct vb2_fileio_data - queue context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. For proper operation it required
+ * this structure to save the driver state between each call of the read
+ * or write function.
+ */
+struct vb2_fileio_data {
+ struct v4l2_requestbuffers req;
+ struct v4l2_buffer b;
+ struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
+ unsigned int index;
+ unsigned int q_count;
+ unsigned int dq_count;
+ unsigned int flags;
+};
+
+/**
+ * __vb2_init_fileio() - initialize file io emulator
+ * @q: videobuf2 queue
+ * @read: mode selector (1 means read, 0 means write)
+ */
+static int __vb2_init_fileio(struct vb2_queue *q, int read)
+{
+ struct vb2_fileio_data *fileio;
+ int i, ret;
+ unsigned int count = 0;
+
+ /*
+ * Sanity check
+ */
+ if ((read && !(q->io_modes & VB2_READ)) ||
+ (!read && !(q->io_modes & VB2_WRITE)))
+ BUG();
+
+ /*
+ * Check if device supports mapping buffers to kernel virtual space.
+ */
+ if (!q->mem_ops->vaddr)
+ return -EBUSY;
+
+ /*
+ * Check if streaming api has not been already activated.
+ */
+ if (q->streaming || q->num_buffers > 0)
+ return -EBUSY;
+
+ /*
+ * Start with count 1, driver can increase it in queue_setup()
+ */
+ count = 1;
+
+ dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n",
+ (read) ? "read" : "write", count, q->io_flags);
+
+ fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
+ if (fileio == NULL)
+ return -ENOMEM;
+
+ fileio->flags = q->io_flags;
+
+ /*
+ * Request buffers and use MMAP type to force driver
+ * to allocate buffers by itself.
+ */
+ fileio->req.count = count;
+ fileio->req.memory = V4L2_MEMORY_MMAP;
+ fileio->req.type = q->type;
+ ret = vb2_reqbufs(q, &fileio->req);
+ if (ret)
+ goto err_kfree;
+
+ /*
+ * Check if plane_count is correct
+ * (multiplane buffers are not supported).
+ */
+ if (q->bufs[0]->num_planes != 1) {
+ ret = -EBUSY;
+ goto err_reqbufs;
+ }
+
+ /*
+ * Get kernel address of each buffer.
+ */
+ for (i = 0; i < q->num_buffers; i++) {
+ fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+ if (fileio->bufs[i].vaddr == NULL)
+ goto err_reqbufs;
+ fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+ }
+
+ /*
+ * Read mode requires pre queuing of all buffers.
+ */
+ if (read) {
+ /*
+ * Queue all buffers.
+ */
+ for (i = 0; i < q->num_buffers; i++) {
+ struct v4l2_buffer *b = &fileio->b;
+ memset(b, 0, sizeof(*b));
+ b->type = q->type;
+ b->memory = q->memory;
+ b->index = i;
+ ret = vb2_qbuf(q, b);
+ if (ret)
+ goto err_reqbufs;
+ fileio->bufs[i].queued = 1;
+ }
+
+ /*
+ * Start streaming.
+ */
+ ret = vb2_streamon(q, q->type);
+ if (ret)
+ goto err_reqbufs;
+ }
+
+ q->fileio = fileio;
+
+ return ret;
+
+err_reqbufs:
+ fileio->req.count = 0;
+ vb2_reqbufs(q, &fileio->req);
+
+err_kfree:
+ kfree(fileio);
+ return ret;
+}
+
+/**
+ * __vb2_cleanup_fileio() - free resourced used by file io emulator
+ * @q: videobuf2 queue
+ */
+static int __vb2_cleanup_fileio(struct vb2_queue *q)
+{
+ struct vb2_fileio_data *fileio = q->fileio;
+
+ if (fileio) {
+ /*
+ * Hack fileio context to enable direct calls to vb2 ioctl
+ * interface.
+ */
+ q->fileio = NULL;
+
+ vb2_streamoff(q, q->type);
+ fileio->req.count = 0;
+ vb2_reqbufs(q, &fileio->req);
+ kfree(fileio);
+ dprintk(3, "file io emulator closed\n");
+ }
+ return 0;
+}
+
+/**
+ * __vb2_perform_fileio() - perform a single file io (read or write) operation
+ * @q: videobuf2 queue
+ * @data: pointed to target userspace buffer
+ * @count: number of bytes to read or write
+ * @ppos: file handle position tracking pointer
+ * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
+ * @read: access mode selector (1 means read, 0 means write)
+ */
+static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblock, int read)
+{
+ struct vb2_fileio_data *fileio;
+ struct vb2_fileio_buf *buf;
+ int ret, index;
+
+ dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n",
+ read ? "read" : "write", (long)*ppos, count,
+ nonblock ? "non" : "");
+
+ if (!data)
+ return -EINVAL;
+
+ /*
+ * Initialize emulator on first call.
+ */
+ if (!q->fileio) {
+ ret = __vb2_init_fileio(q, read);
+ dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+ if (ret)
+ return ret;
+ }
+ fileio = q->fileio;
+
+ /*
+ * Hack fileio context to enable direct calls to vb2 ioctl interface.
+ * The pointer will be restored before returning from this function.
+ */
+ q->fileio = NULL;
+
+ index = fileio->index;
+ buf = &fileio->bufs[index];
+
+ /*
+ * Check if we need to dequeue the buffer.
+ */
+ if (buf->queued) {
+ struct vb2_buffer *vb;
+
+ /*
+ * Call vb2_dqbuf to get buffer back.
+ */
+ memset(&fileio->b, 0, sizeof(fileio->b));
+ fileio->b.type = q->type;
+ fileio->b.memory = q->memory;
+ fileio->b.index = index;
+ ret = vb2_dqbuf(q, &fileio->b, nonblock);
+ dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+ if (ret)
+ goto end;
+ fileio->dq_count += 1;
+
+ /*
+ * Get number of bytes filled by the driver
+ */
+ vb = q->bufs[index];
+ buf->size = vb2_get_plane_payload(vb, 0);
+ buf->queued = 0;
+ }
+
+ /*
+ * Limit count on last few bytes of the buffer.
+ */
+ if (buf->pos + count > buf->size) {
+ count = buf->size - buf->pos;
+ dprintk(5, "reducing read count: %zd\n", count);
+ }
+
+ /*
+ * Transfer data to userspace.
+ */
+ dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n",
+ count, index, buf->pos);
+ if (read)
+ ret = copy_to_user(data, buf->vaddr + buf->pos, count);
+ else
+ ret = copy_from_user(buf->vaddr + buf->pos, data, count);
+ if (ret) {
+ dprintk(3, "file io: error copying data\n");
+ ret = -EFAULT;
+ goto end;
+ }
+
+ /*
+ * Update counters.
+ */
+ buf->pos += count;
+ *ppos += count;
+
+ /*
+ * Queue next buffer if required.
+ */
+ if (buf->pos == buf->size ||
+ (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) {
+ /*
+ * Check if this is the last buffer to read.
+ */
+ if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
+ fileio->dq_count == 1) {
+ dprintk(3, "file io: read limit reached\n");
+ /*
+ * Restore fileio pointer and release the context.
+ */
+ q->fileio = fileio;
+ return __vb2_cleanup_fileio(q);
+ }
+
+ /*
+ * Call vb2_qbuf and give buffer to the driver.
+ */
+ memset(&fileio->b, 0, sizeof(fileio->b));
+ fileio->b.type = q->type;
+ fileio->b.memory = q->memory;
+ fileio->b.index = index;
+ fileio->b.bytesused = buf->pos;
+ ret = vb2_qbuf(q, &fileio->b);
+ dprintk(5, "file io: vb2_dbuf result: %d\n", ret);
+ if (ret)
+ goto end;
+
+ /*
+ * Buffer has been queued, update the status
+ */
+ buf->pos = 0;
+ buf->queued = 1;
+ buf->size = q->bufs[0]->v4l2_planes[0].length;
+ fileio->q_count += 1;
+
+ /*
+ * Switch to the next buffer
+ */
+ fileio->index = (index + 1) % q->num_buffers;
+
+ /*
+ * Start streaming if required.
+ */
+ if (!read && !q->streaming) {
+ ret = vb2_streamon(q, q->type);
+ if (ret)
+ goto end;
+ }
+ }
+
+ /*
+ * Return proper number of bytes processed.
+ */
+ if (ret == 0)
+ ret = count;
+end:
+ /*
+ * Restore the fileio context and block vb2 ioctl interface.
+ */
+ q->fileio = fileio;
+ return ret;
+}
+
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblocking)
+{
+ return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
+}
+EXPORT_SYMBOL_GPL(vb2_read);
+
+size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblocking)
+{
+ return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0);
+}
+EXPORT_SYMBOL_GPL(vb2_write);
+
+
+/*
+ * The following functions are not part of the vb2 core API, but are helper
+ * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
+ * and struct vb2_ops.
+ * They contain boilerplate code that most if not all drivers have to do
+ * and so they simplify the driver code.
+ */
+
+/* The queue is busy if there is a owner and you are not that owner. */
+static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
+{
+ return vdev->queue->owner && vdev->queue->owner != file->private_data;
+}
+
+/* vb2 ioctl helpers */
+
+int vb2_ioctl_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ int res = __verify_memory_type(vdev->queue, p->memory, p->type);
+
+ if (res)
+ return res;
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ res = __reqbufs(vdev->queue, p);
+ /* If count == 0, then the owner has released all buffers and he
+ is no longer owner of the queue. Otherwise we have a new owner. */
+ if (res == 0)
+ vdev->queue->owner = p->count ? file->private_data : NULL;
+ return res;
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_reqbufs);
+
+int vb2_ioctl_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ int res = __verify_memory_type(vdev->queue, p->memory, p->format.type);
+
+ p->index = vdev->queue->num_buffers;
+ /* If count == 0, then just check if memory and type are valid.
+ Any -EBUSY result from __verify_memory_type can be mapped to 0. */
+ if (p->count == 0)
+ return res != -EBUSY ? res : 0;
+ if (res)
+ return res;
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ res = __create_bufs(vdev->queue, p);
+ if (res == 0)
+ vdev->queue->owner = file->private_data;
+ return res;
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs);
+
+int vb2_ioctl_prepare_buf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ return vb2_prepare_buf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf);
+
+int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ /* No need to call vb2_queue_is_busy(), anyone can query buffers. */
+ return vb2_querybuf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
+
+int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ return vb2_qbuf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
+
+int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_dqbuf);
+
+int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ return vb2_streamon(vdev->queue, i);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_streamon);
+
+int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vb2_queue_is_busy(vdev, file))
+ return -EBUSY;
+ return vb2_streamoff(vdev->queue, i);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff);
+
+/* v4l2_file_operations helpers */
+
+int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ return vb2_mmap(vdev->queue, vma);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_mmap);
+
+int vb2_fop_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (file->private_data == vdev->queue->owner) {
+ vb2_queue_release(vdev->queue);
+ vdev->queue->owner = NULL;
+ }
+ return v4l2_fh_release(file);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_release);
+
+ssize_t vb2_fop_write(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
+ int err = -EBUSY;
+
+ if (lock && mutex_lock_interruptible(lock))
+ return -ERESTARTSYS;
+ if (vb2_queue_is_busy(vdev, file))
+ goto exit;
+ err = vb2_write(vdev->queue, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ if (err >= 0)
+ vdev->queue->owner = file->private_data;
+exit:
+ if (lock)
+ mutex_unlock(lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_write);
+
+ssize_t vb2_fop_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
+ int err = -EBUSY;
+
+ if (lock && mutex_lock_interruptible(lock))
+ return -ERESTARTSYS;
+ if (vb2_queue_is_busy(vdev, file))
+ goto exit;
+ err = vb2_read(vdev->queue, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ if (err >= 0)
+ vdev->queue->owner = file->private_data;
+exit:
+ if (lock)
+ mutex_unlock(lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_read);
+
+unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct vb2_queue *q = vdev->queue;
+ struct mutex *lock = q->lock ? q->lock : vdev->lock;
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned res;
+ void *fileio;
+ bool must_lock = false;
+
+ /* Try to be smart: only lock if polling might start fileio,
+ otherwise locking will only introduce unwanted delays. */
+ if (q->num_buffers == 0 && q->fileio == NULL) {
+ if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
+ (req_events & (POLLIN | POLLRDNORM)))
+ must_lock = true;
+ else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
+ (req_events & (POLLOUT | POLLWRNORM)))
+ must_lock = true;
+ }
+
+ /* If locking is needed, but this helper doesn't know how, then you
+ shouldn't be using this helper but you should write your own. */
+ WARN_ON(must_lock && !lock);
+
+ if (must_lock && lock && mutex_lock_interruptible(lock))
+ return POLLERR;
+
+ fileio = q->fileio;
+
+ res = vb2_poll(vdev->queue, file, wait);
+
+ /* If fileio was started, then we have a new queue owner. */
+ if (must_lock && !fileio && q->fileio)
+ q->owner = file->private_data;
+ if (must_lock && lock)
+ mutex_unlock(lock);
+ return res;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_poll);
+
+#ifndef CONFIG_MMU
+unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
+#endif
+
+/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
+
+void vb2_ops_wait_prepare(struct vb2_queue *vq)
+{
+ mutex_unlock(vq->lock);
+}
+EXPORT_SYMBOL_GPL(vb2_ops_wait_prepare);
+
+void vb2_ops_wait_finish(struct vb2_queue *vq)
+{
+ mutex_lock(vq->lock);
+}
+EXPORT_SYMBOL_GPL(vb2_ops_wait_finish);
+
+MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 4b7132660a93..4b7132660a93 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 25c3b360e1ad..25c3b360e1ad 100644
--- a/drivers/media/video/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c
index 504cd4cbe29e..504cd4cbe29e 100644
--- a/drivers/media/video/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c
new file mode 100644
index 000000000000..94efa04d8d55
--- /dev/null
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -0,0 +1,223 @@
+/*
+ * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-memops.h>
+
+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;
+};
+
+static void vb2_vmalloc_put(void *buf_priv);
+
+static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct vb2_vmalloc_buf *buf;
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->size = size;
+ buf->vaddr = vmalloc_user(buf->size);
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_vmalloc_put;
+ buf->handler.arg = buf;
+
+ if (!buf->vaddr) {
+ pr_debug("vmalloc of size %ld failed\n", buf->size);
+ kfree(buf);
+ return NULL;
+ }
+
+ atomic_inc(&buf->refcount);
+ return buf;
+}
+
+static void vb2_vmalloc_put(void *buf_priv)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
+
+ if (atomic_dec_and_test(&buf->refcount)) {
+ vfree(buf->vaddr);
+ kfree(buf);
+ }
+}
+
+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);
+}
+
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
+
+ if (!buf->vaddr) {
+ pr_err("Address of an unallocated plane requested "
+ "or cannot map user pointer\n");
+ return NULL;
+ }
+
+ return buf->vaddr;
+}
+
+static unsigned int vb2_vmalloc_num_users(void *buf_priv)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
+ return atomic_read(&buf->refcount);
+}
+
+static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
+ int ret;
+
+ if (!buf) {
+ pr_err("No memory to map\n");
+ return -EINVAL;
+ }
+
+ ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+ if (ret) {
+ pr_err("Remapping vmalloc memory, error: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Make sure that vm_areas for 2 buffers won't be merged together
+ */
+ vma->vm_flags |= VM_DONTEXPAND;
+
+ /*
+ * Use common vm_area operations to track buffer refcount.
+ */
+ vma->vm_private_data = &buf->handler;
+ vma->vm_ops = &vb2_common_vm_ops;
+
+ vma->vm_ops->open(vma);
+
+ return 0;
+}
+
+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,
+};
+EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
+
+MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
deleted file mode 100644
index c128fac0ce2c..000000000000
--- a/drivers/media/video/Kconfig
+++ /dev/null
@@ -1,1263 +0,0 @@
-#
-# Generic video config states
-#
-
-config VIDEO_V4L2
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON
- default y
-
-config VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_DMA_SG
- depends on HAS_DMA
- select VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_VMALLOC
- select VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_DMA_CONTIG
- depends on HAS_DMA
- select VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_DVB
- tristate
- select VIDEOBUF_GEN
-
-config VIDEO_BTCX
- depends on PCI
- tristate
-
-config VIDEO_TVEEPROM
- tristate
- depends on I2C
-
-config VIDEO_TUNER
- tristate
- depends on MEDIA_TUNER
-
-config V4L2_MEM2MEM_DEV
- tristate
- depends on VIDEOBUF2_CORE
-
-config VIDEOBUF2_CORE
- tristate
-
-config VIDEOBUF2_MEMOPS
- tristate
-
-config VIDEOBUF2_DMA_CONTIG
- select VIDEOBUF2_CORE
- select VIDEOBUF2_MEMOPS
- tristate
-
-config VIDEOBUF2_VMALLOC
- select VIDEOBUF2_CORE
- select VIDEOBUF2_MEMOPS
- tristate
-
-
-config VIDEOBUF2_DMA_SG
- #depends on HAS_DMA
- select VIDEOBUF2_CORE
- select VIDEOBUF2_MEMOPS
- tristate
-#
-# Multimedia Video device configuration
-#
-
-menuconfig VIDEO_CAPTURE_DRIVERS
- bool "Video capture adapters"
- depends on VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT
- default y
- ---help---
- Say Y here to enable selecting the video adapters for
- webcams, analog TV, and hybrid analog/digital TV.
- Some of those devices also supports FM radio.
-
-if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2
-
-config VIDEO_ADV_DEBUG
- bool "Enable advanced debug functionality"
- default n
- ---help---
- Say Y here to enable advanced debugging functionality on some
- V4L devices.
- In doubt, say N.
-
-config VIDEO_FIXED_MINOR_RANGES
- bool "Enable old-style fixed minor ranges for video devices"
- default n
- ---help---
- Say Y here to enable the old-style fixed-range minor assignments.
- Only useful if you rely on the old behavior and use mknod instead of udev.
-
- When in doubt, say N.
-
-config VIDEO_HELPER_CHIPS_AUTO
- bool "Autoselect pertinent encoders/decoders and other helper chips"
- default y if !EXPERT
- ---help---
- Most video cards may require additional modules to encode or
- decode audio/video standards. This option will autoselect
- all pertinent modules to each selected video module.
-
- Unselect this only if you know exactly what you are doing, since
- it may break support on some boards.
-
- In doubt, say Y.
-
-config VIDEO_IR_I2C
- tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
- depends on I2C && RC_CORE
- default y
- ---help---
- Most boards have an IR chip directly connected via GPIO. However,
- some video boards have the IR connected via I2C bus.
-
- If your board doesn't have an I2C IR chip, you may disable this
- option.
-
- In doubt, say Y.
-
-#
-# Encoder / Decoder module configuration
-#
-
-menu "Encoders, decoders, sensors and other helper chips"
- visible if !VIDEO_HELPER_CHIPS_AUTO
-
-comment "Audio decoders, processors and mixers"
-
-config VIDEO_TVAUDIO
- tristate "Simple audio decoder chips"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for several audio decoder chips found on some bt8xx boards:
- Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
- tea6320, tea6420, tda8425, ta8874z.
- Microchip: pic16c54 based design on ProVideo PV951 board.
-
- To compile this driver as a module, choose M here: the
- module will be called tvaudio.
-
-config VIDEO_TDA7432
- tristate "Philips TDA7432 audio processor"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for tda7432 audio decoder chip found on some bt8xx boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tda7432.
-
-config VIDEO_TDA9840
- tristate "Philips TDA9840 audio processor"
- depends on I2C
- ---help---
- Support for tda9840 audio decoder chip found on some Zoran boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tda9840.
-
-config VIDEO_TEA6415C
- tristate "Philips TEA6415C audio processor"
- depends on I2C
- ---help---
- Support for tea6415c audio decoder chip found on some bt8xx boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tea6415c.
-
-config VIDEO_TEA6420
- tristate "Philips TEA6420 audio processor"
- depends on I2C
- ---help---
- Support for tea6420 audio decoder chip found on some bt8xx boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tea6420.
-
-config VIDEO_MSP3400
- tristate "Micronas MSP34xx audio decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Micronas MSP34xx series of audio decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called msp3400.
-
-config VIDEO_CS5345
- tristate "Cirrus Logic CS5345 audio ADC"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Cirrus Logic CS5345 24-bit, 192 kHz
- stereo A/D converter.
-
- To compile this driver as a module, choose M here: the
- module will be called cs5345.
-
-config VIDEO_CS53L32A
- tristate "Cirrus Logic CS53L32A audio ADC"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Cirrus Logic CS53L32A low voltage
- stereo A/D converter.
-
- To compile this driver as a module, choose M here: the
- module will be called cs53l32a.
-
-config VIDEO_TLV320AIC23B
- tristate "Texas Instruments TLV320AIC23B audio codec"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
- ---help---
- Support for the Texas Instruments TLV320AIC23B audio codec.
-
- To compile this driver as a module, choose M here: the
- module will be called tlv320aic23b.
-
-config VIDEO_WM8775
- tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Wolfson Microelectronics WM8775 high
- performance stereo A/D Converter with a 4 channel input mixer.
-
- To compile this driver as a module, choose M here: the
- module will be called wm8775.
-
-config VIDEO_WM8739
- tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Wolfson Microelectronics WM8739
- stereo A/D Converter.
-
- To compile this driver as a module, choose M here: the
- module will be called wm8739.
-
-config VIDEO_VP27SMPX
- tristate "Panasonic VP27s internal MPX"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the internal MPX of the Panasonic VP27s tuner.
-
- To compile this driver as a module, choose M here: the
- module will be called vp27smpx.
-
-comment "RDS decoders"
-
-config VIDEO_SAA6588
- tristate "SAA6588 Radio Chip RDS decoder support"
- depends on VIDEO_V4L2 && I2C
-
- help
- Support for this Radio Data System (RDS) decoder. This allows
- seeing radio station identification transmitted using this
- standard.
-
- To compile this driver as a module, choose M here: the
- module will be called saa6588.
-
-comment "Video decoders"
-
-config VIDEO_ADV7180
- tristate "Analog Devices ADV7180 decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Analog Devices ADV7180 video decoder.
-
- 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
- ---help---
- Support for BT819A video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called bt819.
-
-config VIDEO_BT856
- tristate "BT856 VideoStream decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for BT856 video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called bt856.
-
-config VIDEO_BT866
- tristate "BT866 VideoStream decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for BT866 video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called bt866.
-
-config VIDEO_KS0127
- tristate "KS0127 video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for KS0127 video decoder.
-
- This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
- cards.
-
- To compile this driver as a module, choose M here: the
- module will be called ks0127.
-
-config VIDEO_SAA7110
- tristate "Philips SAA7110 video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7110 video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7110.
-
-config VIDEO_SAA711X
- tristate "Philips SAA7111/3/4/5 video decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7111/3/4/5 video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7115.
-
-config VIDEO_SAA7191
- tristate "Philips SAA7191 video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7191 video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7191.
-
-config VIDEO_TVP514X
- tristate "Texas Instruments TVP514x video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
- decoder. It is currently working with the TI OMAP3 camera
- controller.
-
- To compile this driver as a module, choose M here: the
- module will be called tvp514x.
-
-config VIDEO_TVP5150
- tristate "Texas Instruments TVP5150 video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Texas Instruments TVP5150 video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called tvp5150.
-
-config VIDEO_TVP7002
- tristate "Texas Instruments TVP7002 video decoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Texas Instruments TVP7002 video decoder.
-
- To compile this driver as a module, choose M here: the
- module will be called tvp7002.
-
-config VIDEO_VPX3220
- tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for VPX322x video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called vpx3220.
-
-comment "Video and audio decoders"
-
-config VIDEO_SAA717X
- tristate "Philips SAA7171/3/4 audio/video decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7171/3/4 audio/video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa717x.
-
-source "drivers/media/video/cx25840/Kconfig"
-
-comment "MPEG video encoders"
-
-config VIDEO_CX2341X
- tristate "Conexant CX2341x MPEG encoders"
- depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON
- ---help---
- Support for the Conexant CX23416 MPEG encoders
- and CX23415 MPEG encoder/decoders.
-
- This module currently supports the encoding functions only.
-
- To compile this driver as a module, choose M here: the
- module will be called cx2341x.
-
-comment "Video encoders"
-
-config VIDEO_SAA7127
- tristate "Philips SAA7127/9 digital video encoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7127/9 digital video encoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7127.
-
-config VIDEO_SAA7185
- tristate "Philips SAA7185 video encoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7185 video encoder.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7185.
-
-config VIDEO_ADV7170
- tristate "Analog Devices ADV7170 video encoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Analog Devices ADV7170 video encoder driver
-
- To compile this driver as a module, choose M here: the
- module will be called adv7170.
-
-config VIDEO_ADV7175
- tristate "Analog Devices ADV7175 video encoder"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Analog Devices ADV7175 video encoder driver
-
- To compile this driver as a module, choose M here: the
- module will be called adv7175.
-
-config VIDEO_ADV7343
- tristate "ADV7343 video encoder"
- depends on I2C
- help
- Support for Analog Devices I2C bus based ADV7343 encoder.
-
- To compile this driver as a module, choose M here: the
- module will be called adv7343.
-
-config VIDEO_ADV7393
- tristate "ADV7393 video encoder"
- depends on I2C
- help
- Support for Analog Devices I2C bus based ADV7393 encoder.
-
- To compile this driver as a module, choose M here: the
- module will be called adv7393.
-
-config VIDEO_AK881X
- tristate "AK8813/AK8814 video encoders"
- depends on I2C
- help
- Video output driver for AKM AK8813 and AK8814 TV encoders
-
-comment "Camera sensor devices"
-
-config VIDEO_APTINA_PLL
- tristate
-
-config VIDEO_SMIAPP_PLL
- tristate
-
-config VIDEO_OV7670
- tristate "OmniVision OV7670 sensor support"
- depends on I2C && VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This is a Video4Linux2 sensor-level driver for the OmniVision
- OV7670 VGA camera. It currently only works with the M88ALP01
- controller.
-
-config VIDEO_VS6624
- tristate "ST VS6624 sensor support"
- depends on VIDEO_V4L2 && I2C
- depends on MEDIA_CAMERA_SUPPORT
- ---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 && VIDEO_V4L2_SUBDEV_API
- depends on MEDIA_CAMERA_SUPPORT
- 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
- depends on MEDIA_CAMERA_SUPPORT
- select VIDEO_APTINA_PLL
- ---help---
- This is a Video4Linux2 sensor-level driver for the Aptina
- (Micron) mt9p031 5 Mpixel camera.
-
-config VIDEO_MT9T001
- tristate "Aptina MT9T001 support"
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This is a Video4Linux2 sensor-level driver for the Aptina
- (Micron) mt0t001 3 Mpixel camera.
-
-config VIDEO_MT9V011
- tristate "Micron mt9v011 sensor support"
- depends on I2C && VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This is a Video4Linux2 sensor-level driver for the Micron
- mt0v011 1.3 Mpixel camera. It currently only works with the
- em28xx driver.
-
-config VIDEO_MT9V032
- tristate "Micron MT9V032 sensor support"
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This is a Video4Linux2 sensor-level driver for the Micron
- MT9V032 752x480 CMOS sensor.
-
-config VIDEO_TCM825X
- tristate "TCM825x camera sensor support"
- depends on I2C && VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This is a driver for the Toshiba TCM825x VGA camera sensor.
- It is used for example in Nokia N800.
-
-config VIDEO_SR030PC30
- tristate "Siliconfile SR030PC30 sensor support"
- depends on I2C && VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This driver supports SR030PC30 VGA camera from Siliconfile
-
-config VIDEO_NOON010PC30
- tristate "Siliconfile NOON010PC30 sensor support"
- depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- This driver supports NOON010PC30 CIF camera from Siliconfile
-
-source "drivers/media/video/m5mols/Kconfig"
-
-config VIDEO_S5K6AA
- tristate "Samsung S5K6AAFX sensor support"
- depends on MEDIA_CAMERA_SUPPORT
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
- ---help---
- This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
- camera sensor with an embedded SoC image signal processor.
-
-source "drivers/media/video/smiapp/Kconfig"
-
-comment "Flash devices"
-
-config VIDEO_ADP1653
- tristate "ADP1653 flash support"
- depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
- depends on MEDIA_CAMERA_SUPPORT
- ---help---
- 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
- depends on MEDIA_CAMERA_SUPPORT
- ---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
- tristate "NEC Electronics uPD64031A Ghost Reduction"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the NEC Electronics uPD64031A Ghost Reduction
- video chip. It is most often found in NTSC TV cards made for
- Japan and is used to reduce the 'ghosting' effect that can
- be present in analog TV broadcasts.
-
- To compile this driver as a module, choose M here: the
- module will be called upd64031a.
-
-config VIDEO_UPD64083
- tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the NEC Electronics uPD64083 3-Dimensional Y/C
- separation video chip. It is used to improve the quality of
- the colors of a composite signal.
-
- To compile this driver as a module, choose M here: the
- module will be called upd64083.
-
-comment "Miscelaneous helper chips"
-
-config VIDEO_THS7303
- tristate "THS7303 Video Amplifier"
- depends on I2C
- help
- Support for TI THS7303 video amplifier
-
- To compile this driver as a module, choose M here: the
- module will be called ths7303.
-
-config VIDEO_M52790
- tristate "Mitsubishi M52790 A/V switch"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Mitsubishi M52790 A/V switch.
-
- To compile this driver as a module, choose M here: the
- module will be called m52790.
-
-endmenu # encoder / decoder chips
-
-config VIDEO_VIVI
- tristate "Virtual Video Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
- depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
- select FONT_8x16
- select VIDEOBUF2_VMALLOC
- default n
- ---help---
- Enables a virtual video driver. This device shows a color bar
- and a timestamp, as a real device would generate by using V4L2
- api.
- Say Y here if you want to test video apps or debug V4L devices.
- In doubt, say N.
-
-#
-# USB Multimedia device configuration
-#
-
-menuconfig V4L_USB_DRIVERS
- bool "V4L USB devices"
- depends on USB
- default y
-
-if V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT
-
- comment "Webcam devices"
-
-source "drivers/media/video/uvc/Kconfig"
-
-source "drivers/media/video/gspca/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 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.
-
-source "drivers/media/video/sn9c102/Kconfig"
-
-endif # V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT
-
-if V4L_USB_DRIVERS
-
- comment "Webcam and/or TV USB devices"
-
-source "drivers/media/video/em28xx/Kconfig"
-
-endif
-
-if V4L_USB_DRIVERS && MEDIA_ANALOG_TV_SUPPORT
-
- comment "TV USB devices"
-
-source "drivers/media/video/au0828/Kconfig"
-
-source "drivers/media/video/pvrusb2/Kconfig"
-
-source "drivers/media/video/hdpvr/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"
-
-endif # V4L_USB_DRIVERS
-
-#
-# PCI drivers configuration - No devices here are for webcams
-#
-
-menuconfig V4L_PCI_DRIVERS
- bool "V4L PCI(e) devices"
- depends on PCI
- depends on MEDIA_ANALOG_TV_SUPPORT
- default y
- ---help---
- Say Y here to enable support for these PCI(e) drivers.
-
-if V4L_PCI_DRIVERS
-
-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"
- depends on PCI && SONY_LAPTOP && VIDEO_V4L2
- ---help---
- This is the video4linux driver for the Motion Eye camera found
- in the Vaio Picturebook laptops. Please read the material in
- <file:Documentation/video4linux/meye.txt> for more information.
-
- If you say Y or M here, you need to say Y or M to "Sony Laptop
- Extras" in the misc device section.
-
- To compile this driver as a module, choose M here: the
- module will be called meye.
-
-config VIDEO_MXB
- tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
- depends on PCI && VIDEO_V4L2 && I2C
- select VIDEO_SAA7146_VV
- select VIDEO_TUNER
- select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- This is a video4linux driver for the 'Multimedia eXtension Board'
- TV card by Siemens-Nixdorf.
-
- To compile this driver as a module, choose M here: the
- module will be called mxb.
-
-source "drivers/media/video/saa7134/Kconfig"
-
-source "drivers/media/video/saa7164/Kconfig"
-
-source "drivers/media/video/zoran/Kconfig"
-
-config STA2X11_VIP
- tristate "STA2X11 VIP Video For Linux"
- depends on STA2X11
- select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEOBUF_DMA_CONTIG
- depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
- help
- Say Y for support for STA2X11 VIP (Video Input Port) capture
- device.
-
- To compile this driver as a module, choose M here: the
- module will be called sta2x11_vip.
-
-endif # V4L_PCI_DRIVERS
-
-#
-# ISA & parallel port drivers configuration
-# All devices here are webcam or grabber devices
-#
-
-menuconfig V4L_ISA_PARPORT_DRIVERS
- bool "V4L ISA and parallel port devices"
- depends on ISA || PARPORT
- depends on MEDIA_CAMERA_SUPPORT
- default n
- ---help---
- 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 bw-qcam.
-
-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 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
-
-#
-# Platform drivers
-# All drivers here are currently for webcam support
-
-menuconfig V4L_PLATFORM_DRIVERS
- bool "V4L platform devices"
- depends on MEDIA_CAMERA_SUPPORT
- 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"
- depends on VIDEO_V4L2 && I2C && DMADEVICES
- select DMA_ENGINE
- select TIMB_DMA
- select VIDEO_ADV7180
- select VIDEOBUF_DMA_CONTIG
- ---help---
- Add support for the Video In peripherial of the timberdale FPGA.
-
-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"
- depends on M32R && VIDEO_V4L2
- ---help---
- This is a video4linux driver for the Renesas AR (Artificial Retina)
- camera module.
-
-config VIDEO_M32R_AR_M64278
- tristate "AR device with color module M64278(VGA)"
- depends on PLAT_M32700UT
- select VIDEO_M32R_AR
- ---help---
- This is a video4linux driver for the Renesas AR (Artificial
- Retina) with M64278E-800 camera module.
- This module supports VGA(640x480 pixels) resolutions.
-
- To compile this driver as a module, choose M here: the
- module will be called arv.
-
-config VIDEO_OMAP3
- tristate "OMAP 3 Camera support (EXPERIMENTAL)"
- depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
- ---help---
- Driver for an OMAP 3 camera controller.
-
-config VIDEO_OMAP3_DEBUG
- bool "OMAP 3 Camera debug messages"
- depends on VIDEO_OMAP3
- ---help---
- Enable debug messages on OMAP 3 camera controller driver.
-
-config SOC_CAMERA
- tristate "SoC camera support"
- depends on VIDEO_V4L2 && HAS_DMA && I2C
- select VIDEOBUF_GEN
- select VIDEOBUF2_CORE
- help
- SoC Camera is a common API to several cameras, not connecting
- over a bus like PCI or USB. For example some i2c camera connected
- directly to the data bus of an SoC.
-
-config SOC_CAMERA_IMX074
- tristate "imx074 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports IMX074 cameras from Sony
-
-config SOC_CAMERA_MT9M001
- tristate "mt9m001 support"
- depends on SOC_CAMERA && I2C
- select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
- help
- This driver supports MT9M001 cameras from Micron, monochrome
- and colour models.
-
-config SOC_CAMERA_MT9M111
- tristate "mt9m111, mt9m112 and mt9m131 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports MT9M111, MT9M112 and MT9M131 cameras from
- Micron/Aptina
-
-config SOC_CAMERA_MT9T031
- tristate "mt9t031 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports MT9T031 cameras from Micron.
-
-config SOC_CAMERA_MT9T112
- tristate "mt9t112 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports MT9T112 cameras from Aptina.
-
-config SOC_CAMERA_MT9V022
- tristate "mt9v022 support"
- depends on SOC_CAMERA && I2C
- select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
- help
- This driver supports MT9V022 cameras from Micron
-
-config SOC_CAMERA_RJ54N1
- tristate "rj54n1cb0c support"
- depends on SOC_CAMERA && I2C
- help
- This is a rj54n1cb0c video driver
-
-config SOC_CAMERA_TW9910
- tristate "tw9910 support"
- depends on SOC_CAMERA && I2C
- help
- This is a tw9910 video driver
-
-config SOC_CAMERA_PLATFORM
- tristate "platform camera support"
- depends on SOC_CAMERA
- help
- This is a generic SoC camera platform driver, useful for testing
-
-config SOC_CAMERA_OV2640
- tristate "ov2640 camera support"
- depends on SOC_CAMERA && I2C
- help
- This is a ov2640 camera driver
-
-config SOC_CAMERA_OV5642
- tristate "ov5642 camera support"
- depends on SOC_CAMERA && I2C
- help
- This is a V4L2 camera driver for the OmniVision OV5642 sensor
-
-config SOC_CAMERA_OV6650
- tristate "ov6650 sensor support"
- depends on SOC_CAMERA && I2C
- ---help---
- This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
-
-config SOC_CAMERA_OV772X
- tristate "ov772x camera support"
- depends on SOC_CAMERA && I2C
- help
- This is a ov772x camera driver
-
-config SOC_CAMERA_OV9640
- tristate "ov9640 camera support"
- depends on SOC_CAMERA && I2C
- help
- This is a ov9640 camera driver
-
-config SOC_CAMERA_OV9740
- tristate "ov9740 camera support"
- depends on SOC_CAMERA && I2C
- help
- This is a ov9740 camera driver
-
-config MX1_VIDEO
- bool
-
-config VIDEO_MX1
- tristate "i.MX1/i.MXL CMOS Sensor Interface driver"
- depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA
- select FIQ
- select VIDEOBUF_DMA_CONTIG
- select MX1_VIDEO
- ---help---
- This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
-
-config MX3_VIDEO
- bool
-
-config VIDEO_MX3
- tristate "i.MX3x Camera Sensor Interface driver"
- depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
- select VIDEOBUF2_DMA_CONTIG
- select MX3_VIDEO
- ---help---
- This is a v4l2 driver for the i.MX3x Camera Sensor Interface
-
-config VIDEO_PXA27x
- tristate "PXA27x Quick Capture Interface driver"
- depends on VIDEO_DEV && PXA27x && SOC_CAMERA
- select VIDEOBUF_DMA_SG
- ---help---
- This is a v4l2 driver for the PXA27x Quick Capture Interface
-
-config VIDEO_SH_MOBILE_CSI2
- tristate "SuperH Mobile MIPI CSI-2 Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
- ---help---
- This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
-
-config VIDEO_SH_MOBILE_CEU
- tristate "SuperH Mobile CEU Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
- select VIDEOBUF2_DMA_CONTIG
- ---help---
- This is a v4l2 driver for the SuperH Mobile CEU Interface
-
-config VIDEO_OMAP1
- tristate "OMAP1 Camera Interface driver"
- depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
- select VIDEOBUF_DMA_CONTIG
- select VIDEOBUF_DMA_SG
- ---help---
- This is a v4l2 driver for the TI OMAP1 camera interface
-
-config VIDEO_OMAP2
- tristate "OMAP2 Camera Capture Interface driver"
- depends on VIDEO_DEV && ARCH_OMAP2
- select VIDEOBUF_DMA_SG
- ---help---
- This is a v4l2 driver for the TI OMAP2 camera capture interface
-
-config VIDEO_MX2_HOSTSUPPORT
- bool
-
-config VIDEO_MX2
- tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
- select VIDEOBUF2_DMA_CONTIG
- select VIDEO_MX2_HOSTSUPPORT
- ---help---
- This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
- Interface
-
-config VIDEO_ATMEL_ISI
- tristate "ATMEL Image Sensor Interface (ISI) support"
- depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
- select VIDEOBUF2_DMA_CONTIG
- ---help---
- This module makes the ATMEL Image Sensor Interface available
- as a v4l2 device.
-
-source "drivers/media/video/s5p-fimc/Kconfig"
-source "drivers/media/video/s5p-tv/Kconfig"
-
-endif # V4L_PLATFORM_DRIVERS
-endif # VIDEO_CAPTURE_DRIVERS
-
-menuconfig V4L_MEM2MEM_DRIVERS
- bool "Memory-to-memory multimedia devices"
- depends on VIDEO_V4L2
- default n
- ---help---
- Say Y here to enable selecting drivers for V4L devices that
- use system memory for both source and destination buffers, as opposed
- to capture and output drivers, which use memory buffers for just
- one of those.
-
-if V4L_MEM2MEM_DRIVERS
-
-config VIDEO_MEM2MEM_TESTDEV
- tristate "Virtual test device for mem2mem framework"
- depends on VIDEO_DEV && VIDEO_V4L2
- select VIDEOBUF2_VMALLOC
- select V4L2_MEM2MEM_DEV
- default n
- ---help---
- 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"
- depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
- select VIDEOBUF2_DMA_CONTIG
- default n
- 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
deleted file mode 100644
index b7da9faa3b0a..000000000000
--- a/drivers/media/video/Makefile
+++ /dev/null
@@ -1,218 +0,0 @@
-#
-# Makefile for the video capture/playback device drivers.
-#
-
-tuner-objs := tuner-core.o
-
-msp3400-objs := msp3400-driver.o msp3400-kthreads.o
-
-stkwebcam-objs := stk-webcam.o stk-sensor.o
-
-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
-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
-obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
-obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
-obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
-obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
-obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
-obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
-obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
-obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
-obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
-obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
-obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
-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_ADV7393) += adv7393.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
-obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
-obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
-obj-$(CONFIG_VIDEO_VINO) += indycam.o
-obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
-obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
-obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
-obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
-obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
-obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
-obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
-obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
-obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
-obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
-obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
-obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
-obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
-obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
-obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
-obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
-obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
-obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
-obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
-obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/
-obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
-obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
-
-obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
-
-obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
-obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o
-obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o
-obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
-obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
-obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
-obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
-obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
-obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
-
-# And now the v4l2 drivers:
-
-obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_ZORAN) += zoran/
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_PMS) += pms.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
-obj-$(CONFIG_VIDEO_CX88) += cx88/
-obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
-obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
-obj-$(CONFIG_VIDEO_CX25821) += cx25821/
-obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
-obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
-obj-$(CONFIG_VIDEO_TM6000) += tm6000/
-obj-$(CONFIG_VIDEO_MXB) += mxb.o
-obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
-obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
-obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
-
-obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
-obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
-obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
-obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
-obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
-obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
-
-obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o
-obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o
-obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
-obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
-obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
-
-obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
-
-obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
-
-obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
-
-obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
-obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
-
-obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
-
-obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/
-
-obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
-obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
-
-obj-$(CONFIG_USB_SN9C102) += sn9c102/
-obj-$(CONFIG_USB_PWC) += pwc/
-obj-$(CONFIG_USB_GSPCA) += gspca/
-
-obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
-
-obj-$(CONFIG_USB_S2255) += s2255drv.o
-
-obj-$(CONFIG_VIDEO_IVTV) += ivtv/
-obj-$(CONFIG_VIDEO_CX18) += cx18/
-
-obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
-obj-$(CONFIG_VIDEO_VIVI) += vivi.o
-obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
-obj-$(CONFIG_VIDEO_CX23885) += cx23885/
-
-obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
-
-obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
-obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o
-obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
-# soc-camera host drivers have to be linked after camera drivers
-obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
-obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
-obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
-obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
-obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
-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
-
-obj-$(CONFIG_VIDEO_AU0828) += au0828/
-
-obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
-obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
-
-obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
-
-obj-y += davinci/
-
-obj-$(CONFIG_ARCH_OMAP) += omap/
-
-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
deleted file mode 100644
index 57e87090388d..000000000000
--- a/drivers/media/video/adp1653.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * drivers/media/video/adp1653.c
- *
- * Copyright (C) 2008--2011 Nokia Corporation
- *
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
- *
- * Contributors:
- * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
- * Tuukka Toivonen <tuukkat76@gmail.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:
- * - fault interrupt handling
- * - hardware strobe
- * - power doesn't need to be ON if all lights are off
- *
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <media/adp1653.h>
-#include <media/v4l2-device.h>
-
-#define TIMEOUT_MAX 820000
-#define TIMEOUT_STEP 54600
-#define TIMEOUT_MIN (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \
- * TIMEOUT_STEP)
-#define TIMEOUT_US_TO_CODE(t) ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \
- / TIMEOUT_STEP)
-#define TIMEOUT_CODE_TO_US(c) (TIMEOUT_MAX - (c) * TIMEOUT_STEP)
-
-/* Write values into ADP1653 registers. */
-static int adp1653_update_hw(struct adp1653_flash *flash)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
- u8 out_sel;
- u8 config = 0;
- int rval;
-
- out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
- flash->indicator_intensity->val)
- << ADP1653_REG_OUT_SEL_ILED_SHIFT;
-
- switch (flash->led_mode->val) {
- case V4L2_FLASH_LED_MODE_NONE:
- break;
- case V4L2_FLASH_LED_MODE_FLASH:
- /* Flash mode, light on with strobe, duration from timer */
- config = ADP1653_REG_CONFIG_TMR_CFG;
- config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val)
- << ADP1653_REG_CONFIG_TMR_SET_SHIFT;
- break;
- case V4L2_FLASH_LED_MODE_TORCH:
- /* Torch mode, light immediately on, duration indefinite */
- out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
- flash->torch_intensity->val)
- << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
- break;
- }
-
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
- if (rval < 0)
- return rval;
-
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config);
- if (rval < 0)
- return rval;
-
- return 0;
-}
-
-static int adp1653_get_fault(struct adp1653_flash *flash)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
- int fault;
- int rval;
-
- fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
- if (IS_ERR_VALUE(fault))
- return fault;
-
- flash->fault |= fault;
-
- if (!flash->fault)
- return 0;
-
- /* Clear faults. */
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
- if (IS_ERR_VALUE(rval))
- return rval;
-
- flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
-
- rval = adp1653_update_hw(flash);
- if (IS_ERR_VALUE(rval))
- return rval;
-
- return flash->fault;
-}
-
-static int adp1653_strobe(struct adp1653_flash *flash, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
- u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
- flash->indicator_intensity->val)
- << ADP1653_REG_OUT_SEL_ILED_SHIFT;
- int rval;
-
- if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH)
- return -EBUSY;
-
- if (!enable)
- return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL,
- out_sel);
-
- out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
- flash->flash_intensity->val)
- << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
- if (rval)
- return rval;
-
- /* Software strobe using i2c */
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE,
- ADP1653_REG_SW_STROBE_SW_STROBE);
- if (rval)
- return rval;
- return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0);
-}
-
-/* --------------------------------------------------------------------------
- * V4L2 controls
- */
-
-static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct adp1653_flash *flash =
- container_of(ctrl->handler, struct adp1653_flash, ctrls);
- int rval;
-
- rval = adp1653_get_fault(flash);
- if (IS_ERR_VALUE(rval))
- return rval;
-
- ctrl->cur.val = 0;
-
- if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
- ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
- if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
- ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
- if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
- ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
- if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
- ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
-
- flash->fault = 0;
-
- return 0;
-}
-
-static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct adp1653_flash *flash =
- container_of(ctrl->handler, struct adp1653_flash, ctrls);
- int rval;
-
- rval = adp1653_get_fault(flash);
- if (IS_ERR_VALUE(rval))
- return rval;
- if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
- ADP1653_REG_FAULT_FLT_OT |
- ADP1653_REG_FAULT_FLT_OV)) &&
- (ctrl->id == V4L2_CID_FLASH_STROBE ||
- ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY ||
- ctrl->id == V4L2_CID_FLASH_LED_MODE))
- return -EBUSY;
-
- switch (ctrl->id) {
- case V4L2_CID_FLASH_STROBE:
- return adp1653_strobe(flash, 1);
- case V4L2_CID_FLASH_STROBE_STOP:
- return adp1653_strobe(flash, 0);
- }
-
- return adp1653_update_hw(flash);
-}
-
-static const struct v4l2_ctrl_ops adp1653_ctrl_ops = {
- .g_volatile_ctrl = adp1653_get_ctrl,
- .s_ctrl = adp1653_set_ctrl,
-};
-
-static int adp1653_init_controls(struct adp1653_flash *flash)
-{
- struct v4l2_ctrl *fault;
-
- v4l2_ctrl_handler_init(&flash->ctrls, 9);
-
- flash->led_mode =
- v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_LED_MODE,
- V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0);
- v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_STROBE_SOURCE,
- V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0);
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
- flash->flash_timeout =
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN,
- flash->platform_data->max_flash_timeout,
- TIMEOUT_STEP,
- flash->platform_data->max_flash_timeout);
- flash->flash_intensity =
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_INTENSITY,
- ADP1653_FLASH_INTENSITY_MIN,
- flash->platform_data->max_flash_intensity,
- 1, flash->platform_data->max_flash_intensity);
- flash->torch_intensity =
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_TORCH_INTENSITY,
- ADP1653_TORCH_INTENSITY_MIN,
- flash->platform_data->max_torch_intensity,
- ADP1653_FLASH_INTENSITY_STEP,
- flash->platform_data->max_torch_intensity);
- flash->indicator_intensity =
- v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_INDICATOR_INTENSITY,
- ADP1653_INDICATOR_INTENSITY_MIN,
- flash->platform_data->max_indicator_intensity,
- ADP1653_INDICATOR_INTENSITY_STEP,
- ADP1653_INDICATOR_INTENSITY_MIN);
- fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
- V4L2_CID_FLASH_FAULT, 0,
- V4L2_FLASH_FAULT_OVER_VOLTAGE
- | V4L2_FLASH_FAULT_OVER_TEMPERATURE
- | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
-
- if (flash->ctrls.error)
- return flash->ctrls.error;
-
- fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
-
- flash->subdev.ctrl_handler = &flash->ctrls;
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * V4L2 subdev operations
- */
-
-static int
-adp1653_init_device(struct adp1653_flash *flash)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
- int rval;
-
- /* Clear FAULT register by writing zero to OUT_SEL */
- rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
- if (rval < 0) {
- dev_err(&client->dev, "failed writing fault register\n");
- return -EIO;
- }
-
- mutex_lock(flash->ctrls.lock);
- /* Reset faults before reading new ones. */
- flash->fault = 0;
- rval = adp1653_get_fault(flash);
- mutex_unlock(flash->ctrls.lock);
- if (rval > 0) {
- dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
- return -EIO;
- }
-
- mutex_lock(flash->ctrls.lock);
- rval = adp1653_update_hw(flash);
- mutex_unlock(flash->ctrls.lock);
- if (rval) {
- dev_err(&client->dev,
- "adp1653_update_hw failed at %s\n", __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static int
-__adp1653_set_power(struct adp1653_flash *flash, int on)
-{
- int ret;
-
- ret = flash->platform_data->power(&flash->subdev, on);
- if (ret < 0)
- return ret;
-
- if (!on)
- return 0;
-
- ret = adp1653_init_device(flash);
- if (ret < 0)
- flash->platform_data->power(&flash->subdev, 0);
-
- return ret;
-}
-
-static int
-adp1653_set_power(struct v4l2_subdev *subdev, int on)
-{
- struct adp1653_flash *flash = to_adp1653_flash(subdev);
- int ret = 0;
-
- mutex_lock(&flash->power_lock);
-
- /* If the power count is modified from 0 to != 0 or from != 0 to 0,
- * update the power state.
- */
- if (flash->power_count == !on) {
- ret = __adp1653_set_power(flash, !!on);
- if (ret < 0)
- goto done;
- }
-
- /* Update the power count. */
- flash->power_count += on ? 1 : -1;
- WARN_ON(flash->power_count < 0);
-
-done:
- mutex_unlock(&flash->power_lock);
- return ret;
-}
-
-static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- return adp1653_set_power(sd, 1);
-}
-
-static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- return adp1653_set_power(sd, 0);
-}
-
-static const struct v4l2_subdev_core_ops adp1653_core_ops = {
- .s_power = adp1653_set_power,
-};
-
-static const struct v4l2_subdev_ops adp1653_ops = {
- .core = &adp1653_core_ops,
-};
-
-static const struct v4l2_subdev_internal_ops adp1653_internal_ops = {
- .open = adp1653_open,
- .close = adp1653_close,
-};
-
-/* --------------------------------------------------------------------------
- * I2C driver
- */
-#ifdef CONFIG_PM
-
-static int adp1653_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct adp1653_flash *flash = to_adp1653_flash(subdev);
-
- if (!flash->power_count)
- return 0;
-
- return __adp1653_set_power(flash, 0);
-}
-
-static int adp1653_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct adp1653_flash *flash = to_adp1653_flash(subdev);
-
- if (!flash->power_count)
- return 0;
-
- return __adp1653_set_power(flash, 1);
-}
-
-#else
-
-#define adp1653_suspend NULL
-#define adp1653_resume NULL
-
-#endif /* CONFIG_PM */
-
-static int adp1653_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
-{
- struct adp1653_flash *flash;
- int ret;
-
- /* we couldn't work without platform data */
- if (client->dev.platform_data == NULL)
- return -ENODEV;
-
- flash = kzalloc(sizeof(*flash), GFP_KERNEL);
- if (flash == NULL)
- return -ENOMEM;
-
- flash->platform_data = client->dev.platform_data;
-
- mutex_init(&flash->power_lock);
-
- v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops);
- flash->subdev.internal_ops = &adp1653_internal_ops;
- flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- ret = adp1653_init_controls(flash);
- if (ret)
- goto free_and_quit;
-
- ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
- if (ret < 0)
- goto free_and_quit;
-
- flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
-
- return 0;
-
-free_and_quit:
- v4l2_ctrl_handler_free(&flash->ctrls);
- kfree(flash);
- return ret;
-}
-
-static int __exit adp1653_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct adp1653_flash *flash = to_adp1653_flash(subdev);
-
- v4l2_device_unregister_subdev(&flash->subdev);
- v4l2_ctrl_handler_free(&flash->ctrls);
- media_entity_cleanup(&flash->subdev.entity);
- kfree(flash);
- return 0;
-}
-
-static const struct i2c_device_id adp1653_id_table[] = {
- { ADP1653_NAME, 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, adp1653_id_table);
-
-static struct dev_pm_ops adp1653_pm_ops = {
- .suspend = adp1653_suspend,
- .resume = adp1653_resume,
-};
-
-static struct i2c_driver adp1653_i2c_driver = {
- .driver = {
- .name = ADP1653_NAME,
- .pm = &adp1653_pm_ops,
- },
- .probe = adp1653_probe,
- .remove = __exit_p(adp1653_remove),
- .id_table = adp1653_id_table,
-};
-
-module_i2c_driver(adp1653_i2c_driver);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
-MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
deleted file mode 100644
index c4b03572dce8..000000000000
--- a/drivers/media/video/as3645a.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * 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 __devinit 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 __devinit 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 __devexit 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 = __devexit_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/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
deleted file mode 100644
index 23f7fd22f0eb..000000000000
--- a/drivers/media/video/au0828/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-
-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
- select DVB_AU8522_DTV if !DVB_FE_CUSTOMISE
- select DVB_AU8522_V4L if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- ---help---
- This is a video4linux driver for Auvitek's USB device.
-
- To compile this driver as a module, choose M here: the
- module will be called au0828
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
deleted file mode 100644
index bd22223f8d9f..000000000000
--- a/drivers/media/video/au0828/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
-
-obj-$(CONFIG_VIDEO_AU0828) += au0828.o
-
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-
-ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
deleted file mode 100644
index e3fe9a6637f6..000000000000
--- a/drivers/media/video/au0828/au0828-cards.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Driver for the Auvitek USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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 "au0828.h"
-#include "au0828-cards.h"
-#include "au8522.h"
-#include "media/tuner.h"
-#include "media/v4l2-common.h"
-
-void hvr950q_cs5340_audio(void *priv, int enable)
-{
- /* Because the HVR-950q shares an i2s bus between the cs5340 and the
- au8522, we need to hold cs5340 in reset when using the au8522 */
- struct au0828_dev *dev = priv;
- if (enable == 1)
- au0828_set(dev, REG_000, 0x10);
- else
- au0828_clear(dev, REG_000, 0x10);
-}
-
-struct au0828_board au0828_boards[] = {
- [AU0828_BOARD_UNKNOWN] = {
- .name = "Unknown board",
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- },
- [AU0828_BOARD_HAUPPAUGE_HVR850] = {
- .name = "Hauppauge HVR850",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x61,
- .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
- .input = {
- {
- .type = AU0828_VMUX_TELEVISION,
- .vmux = AU8522_COMPOSITE_CH4_SIF,
- .amux = AU8522_AUDIO_SIF,
- },
- {
- .type = AU0828_VMUX_COMPOSITE,
- .vmux = AU8522_COMPOSITE_CH1,
- .amux = AU8522_AUDIO_NONE,
- .audio_setup = hvr950q_cs5340_audio,
- },
- {
- .type = AU0828_VMUX_SVIDEO,
- .vmux = AU8522_SVIDEO_CH13,
- .amux = AU8522_AUDIO_NONE,
- .audio_setup = hvr950q_cs5340_audio,
- },
- },
- },
- [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
- .name = "Hauppauge HVR950Q",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x61,
- /* The au0828 hardware i2c implementation does not properly
- support the xc5000's i2c clock stretching. So we need to
- lower the clock frequency enough where the 15us clock
- stretch fits inside of a normal clock cycle, or else the
- au0828 fails to set the STOP bit. A 30 KHz clock puts the
- clock pulse width at 18us */
- .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
- .input = {
- {
- .type = AU0828_VMUX_TELEVISION,
- .vmux = AU8522_COMPOSITE_CH4_SIF,
- .amux = AU8522_AUDIO_SIF,
- },
- {
- .type = AU0828_VMUX_COMPOSITE,
- .vmux = AU8522_COMPOSITE_CH1,
- .amux = AU8522_AUDIO_NONE,
- .audio_setup = hvr950q_cs5340_audio,
- },
- {
- .type = AU0828_VMUX_SVIDEO,
- .vmux = AU8522_SVIDEO_CH13,
- .amux = AU8522_AUDIO_NONE,
- .audio_setup = hvr950q_cs5340_audio,
- },
- },
- },
- [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
- .name = "Hauppauge HVR950Q rev xxF8",
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
- },
- [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
- .name = "DViCO FusionHDTV USB",
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
- },
- [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
- .name = "Hauppauge Woodbury",
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
- },
-};
-
-/* Tuner callback function for au0828 boards. Currently only needed
- * for HVR1500Q, which has an xc5000 tuner.
- */
-int au0828_tuner_callback(void *priv, int component, int command, int arg)
-{
- struct au0828_dev *dev = priv;
-
- dprintk(1, "%s()\n", __func__);
-
- switch (dev->boardnr) {
- case AU0828_BOARD_HAUPPAUGE_HVR850:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
- case AU0828_BOARD_DVICO_FUSIONHDTV7:
- if (command == 0) {
- /* Tuner Reset Command from xc5000 */
- /* Drive the tuner into reset and out */
- au0828_clear(dev, REG_001, 2);
- mdelay(10);
- au0828_set(dev, REG_001, 2);
- mdelay(10);
- return 0;
- } else {
- printk(KERN_ERR
- "%s(): Unknown command.\n", __func__);
- return -EINVAL;
- }
- break;
- }
-
- return 0; /* Should never be here */
-}
-
-static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
-{
- struct tveeprom tv;
-
- tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
- dev->board.tuner_type = tv.tuner_type;
-
- /* Make sure we support the board model */
- switch (tv.model) {
- case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
- case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
- case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
- case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
- case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
- case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
- case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
- case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
- case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
- case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
- case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
- case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
- break;
- default:
- printk(KERN_WARNING "%s: warning: "
- "unknown hauppauge model #%d\n", __func__, tv.model);
- break;
- }
-
- printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
- __func__, tv.model);
-}
-
-void au0828_card_setup(struct au0828_dev *dev)
-{
- static u8 eeprom[256];
- struct tuner_setup tun_setup;
- struct v4l2_subdev *sd;
- unsigned int mode_mask = T_ANALOG_TV;
-
- dprintk(1, "%s()\n", __func__);
-
- memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
-
- if (dev->i2c_rc == 0) {
- dev->i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
- }
-
- switch (dev->boardnr) {
- case AU0828_BOARD_HAUPPAUGE_HVR850:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
- case AU0828_BOARD_HAUPPAUGE_WOODBURY:
- if (dev->i2c_rc == 0)
- hauppauge_eeprom(dev, eeprom+0xa0);
- break;
- }
-
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
- /* Load the analog demodulator driver (note this would need to
- be abstracted out if we ever need to support a different
- demod) */
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "au8522", 0x8e >> 1, NULL);
- if (sd == NULL)
- printk(KERN_ERR "analog subdev registration failed\n");
- }
-
- /* Setup tuners */
- if (dev->board.tuner_type != TUNER_ABSENT) {
- /* Load the tuner module, which does the attach */
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", dev->board.tuner_addr, NULL);
- if (sd == NULL)
- printk(KERN_ERR "tuner subdev registration fail\n");
-
- tun_setup.mode_mask = mode_mask;
- tun_setup.type = dev->board.tuner_type;
- tun_setup.addr = dev->board.tuner_addr;
- tun_setup.tuner_callback = au0828_tuner_callback;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
- &tun_setup);
- }
-}
-
-/*
- * The bridge has between 8 and 12 gpios.
- * Regs 1 and 0 deal with output enables.
- * Regs 3 and 2 deal with direction.
- */
-void au0828_gpio_setup(struct au0828_dev *dev)
-{
- dprintk(1, "%s()\n", __func__);
-
- switch (dev->boardnr) {
- case AU0828_BOARD_HAUPPAUGE_HVR850:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
- case AU0828_BOARD_HAUPPAUGE_WOODBURY:
- /* GPIO's
- * 4 - CS5340
- * 5 - AU8522 Demodulator
- * 6 - eeprom W/P
- * 7 - power supply
- * 9 - XC5000 Tuner
- */
-
- /* Into reset */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
- au0828_write(dev, REG_001, 0x0);
- au0828_write(dev, REG_000, 0x0);
- msleep(100);
-
- /* Out of reset (leave the cs5340 in reset until needed) */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
- au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
-
- msleep(250);
- break;
- case AU0828_BOARD_DVICO_FUSIONHDTV7:
- /* GPIO's
- * 6 - ?
- * 8 - AU8522 Demodulator
- * 9 - XC5000 Tuner
- */
-
- /* Into reset */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_002, 0xa0);
- au0828_write(dev, REG_001, 0x0);
- au0828_write(dev, REG_000, 0x0);
- msleep(100);
-
- /* Out of reset */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_002, 0xa0);
- au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_000, 0xa0);
- msleep(250);
- break;
- }
-}
-
-/* table of devices that work with this driver */
-struct usb_device_id au0828_usb_id_table[] = {
- { USB_DEVICE(0x2040, 0x7200),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x7240),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
- { USB_DEVICE(0x0fe9, 0xd620),
- .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
- { USB_DEVICE(0x2040, 0x7210),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x7217),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x721b),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x721e),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x721f),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x7280),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x0fd9, 0x0008),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x7201),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
- { USB_DEVICE(0x2040, 0x7211),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
- { USB_DEVICE(0x2040, 0x7281),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
- { USB_DEVICE(0x05e1, 0x0480),
- .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
- { USB_DEVICE(0x2040, 0x8200),
- .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
- { USB_DEVICE(0x2040, 0x7260),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { USB_DEVICE(0x2040, 0x7213),
- .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
- { },
-};
-
-MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
deleted file mode 100644
index 1e4ce5068ec2..000000000000
--- a/drivers/media/video/au0828/au0828-core.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Driver for the Auvitek USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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/module.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/mutex.h>
-
-#include "au0828.h"
-
-/*
- * 1 = General debug messages
- * 2 = USB handling
- * 4 = I2C related
- * 8 = Bridge related
- */
-int au0828_debug;
-module_param_named(debug, au0828_debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-static unsigned int disable_usb_speed_check;
-module_param(disable_usb_speed_check, int, 0444);
-MODULE_PARM_DESC(disable_usb_speed_check,
- "override min bandwidth requirement of 480M bps");
-
-#define _AU0828_BULKPIPE 0x03
-#define _BULKPIPESIZE 0xffff
-
-static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
- u16 index, unsigned char *cp, u16 size);
-static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
- u16 index, unsigned char *cp, u16 size);
-
-/* USB Direction */
-#define CMD_REQUEST_IN 0x00
-#define CMD_REQUEST_OUT 0x01
-
-u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
-{
- recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
- dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
- return dev->ctrlmsg[0];
-}
-
-u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
-{
- dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
- return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
- dev->ctrlmsg, 0);
-}
-
-static void cmd_msg_dump(struct au0828_dev *dev)
-{
- int i;
-
- for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
- dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n",
- __func__,
- dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
- dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
- dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
- dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
- dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
- dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
- dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
- dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
-}
-
-static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
- u16 index, unsigned char *cp, u16 size)
-{
- int status = -ENODEV;
- mutex_lock(&dev->mutex);
- if (dev->usbdev) {
-
- /* cp must be memory that has been allocated by kmalloc */
- status = usb_control_msg(dev->usbdev,
- usb_sndctrlpipe(dev->usbdev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE,
- value, index,
- cp, size, 1000);
-
- status = min(status, 0);
-
- if (status < 0) {
- printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
- __func__, status);
- }
-
- }
- mutex_unlock(&dev->mutex);
- return status;
-}
-
-static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
- u16 index, unsigned char *cp, u16 size)
-{
- int status = -ENODEV;
- mutex_lock(&dev->mutex);
- if (dev->usbdev) {
-
- memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
-
- /* cp must be memory that has been allocated by kmalloc */
- status = usb_control_msg(dev->usbdev,
- usb_rcvctrlpipe(dev->usbdev, 0),
- request,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index,
- cp, size, 1000);
-
- status = min(status, 0);
-
- if (status < 0) {
- printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
- __func__, status);
- } else
- cmd_msg_dump(dev);
- }
- mutex_unlock(&dev->mutex);
- return status;
-}
-
-static void au0828_usb_disconnect(struct usb_interface *interface)
-{
- struct au0828_dev *dev = usb_get_intfdata(interface);
-
- dprintk(1, "%s()\n", __func__);
-
- /* Digital TV */
- au0828_dvb_unregister(dev);
-
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_unregister(dev);
-
- /* I2C */
- au0828_i2c_unregister(dev);
-
- v4l2_device_unregister(&dev->v4l2_dev);
-
- usb_set_intfdata(interface, NULL);
-
- mutex_lock(&dev->mutex);
- dev->usbdev = NULL;
- mutex_unlock(&dev->mutex);
-
- kfree(dev);
-
-}
-
-static int au0828_usb_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- int ifnum, retval;
- struct au0828_dev *dev;
- struct usb_device *usbdev = interface_to_usbdev(interface);
-
- ifnum = interface->altsetting->desc.bInterfaceNumber;
-
- if (ifnum != 0)
- return -ENODEV;
-
- dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
- le16_to_cpu(usbdev->descriptor.idVendor),
- le16_to_cpu(usbdev->descriptor.idProduct),
- ifnum);
-
- /*
- * Make sure we have 480 Mbps of bandwidth, otherwise things like
- * video stream wouldn't likely work, since 12 Mbps is generally
- * not enough even for most Digital TV streams.
- */
- if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
- printk(KERN_ERR "au0828: Device initialization failed.\n");
- printk(KERN_ERR "au0828: Device must be connected to a "
- "high-speed USB 2.0 port.\n");
- return -ENODEV;
- }
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
- return -ENOMEM;
- }
-
- mutex_init(&dev->mutex);
- mutex_init(&dev->dvb.lock);
- dev->usbdev = usbdev;
- dev->boardnr = id->driver_info;
-
- /* Create the v4l2_device */
- retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
- if (retval) {
- printk(KERN_ERR "%s() v4l2_device_register failed\n",
- __func__);
- kfree(dev);
- return -EIO;
- }
-
- /* Power Up the bridge */
- au0828_write(dev, REG_600, 1 << 4);
-
- /* Bring up the GPIO's and supporting devices */
- au0828_gpio_setup(dev);
-
- /* I2C */
- au0828_i2c_register(dev);
-
- /* Setup */
- au0828_card_setup(dev);
-
- /* Analog TV */
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_register(dev, interface);
-
- /* Digital TV */
- au0828_dvb_register(dev);
-
- /* Store the pointer to the au0828_dev so it can be accessed in
- au0828_usb_disconnect */
- usb_set_intfdata(interface, dev);
-
- printk(KERN_INFO "Registered device AU0828 [%s]\n",
- dev->board.name == NULL ? "Unset" : dev->board.name);
-
- return 0;
-}
-
-static struct usb_driver au0828_usb_driver = {
- .name = DRIVER_NAME,
- .probe = au0828_usb_probe,
- .disconnect = au0828_usb_disconnect,
- .id_table = au0828_usb_id_table,
-};
-
-static int __init au0828_init(void)
-{
- int ret;
-
- if (au0828_debug & 1)
- printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
-
- if (au0828_debug & 2)
- printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
-
- if (au0828_debug & 4)
- printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
-
- if (au0828_debug & 8)
- printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
- __func__);
-
- printk(KERN_INFO "au0828 driver loaded\n");
-
- ret = usb_register(&au0828_usb_driver);
- if (ret)
- printk(KERN_ERR "usb_register failed, error = %d\n", ret);
-
- return ret;
-}
-
-static void __exit au0828_exit(void)
-{
- usb_deregister(&au0828_usb_driver);
-}
-
-module_init(au0828_init);
-module_exit(au0828_exit);
-
-MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
-MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.2");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
deleted file mode 100644
index 39ece8e24985..000000000000
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Driver for the Auvitek USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/suspend.h>
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-
-#include "au0828.h"
-#include "au8522.h"
-#include "xc5000.h"
-#include "mxl5007t.h"
-#include "tda18271.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define _AU0828_BULKPIPE 0x83
-#define _BULKPIPESIZE 0xe522
-
-static u8 hauppauge_hvr950q_led_states[] = {
- 0x00, /* off */
- 0x02, /* yellow */
- 0x04, /* green */
-};
-
-static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
- .gpio_output = 0x00e0,
- .gpio_output_enable = 0x6006,
- .gpio_output_disable = 0x0660,
-
- .gpio_leds = 0x00e2,
- .led_states = hauppauge_hvr950q_led_states,
- .num_led_states = sizeof(hauppauge_hvr950q_led_states),
-
- .vsb8_strong = 20 /* dB */ * 10,
- .qam64_strong = 25 /* dB */ * 10,
- .qam256_strong = 32 /* dB */ * 10,
-};
-
-static struct au8522_config hauppauge_hvr950q_config = {
- .demod_address = 0x8e >> 1,
- .status_mode = AU8522_DEMODLOCKING,
- .qam_if = AU8522_IF_6MHZ,
- .vsb_if = AU8522_IF_6MHZ,
- .led_cfg = &hauppauge_hvr950q_led_cfg,
-};
-
-static struct au8522_config fusionhdtv7usb_config = {
- .demod_address = 0x8e >> 1,
- .status_mode = AU8522_DEMODLOCKING,
- .qam_if = AU8522_IF_6MHZ,
- .vsb_if = AU8522_IF_6MHZ,
-};
-
-static struct au8522_config hauppauge_woodbury_config = {
- .demod_address = 0x8e >> 1,
- .status_mode = AU8522_DEMODLOCKING,
- .qam_if = AU8522_IF_4MHZ,
- .vsb_if = AU8522_IF_3_25MHZ,
-};
-
-static struct xc5000_config hauppauge_xc5000a_config = {
- .i2c_address = 0x61,
- .if_khz = 6000,
- .chip_id = XC5000A,
-};
-
-static struct xc5000_config hauppauge_xc5000c_config = {
- .i2c_address = 0x61,
- .if_khz = 6000,
- .chip_id = XC5000C,
-};
-
-static struct mxl5007t_config mxl5007t_hvr950q_config = {
- .xtal_freq_hz = MxL_XTAL_24_MHZ,
- .if_freq_hz = MxL_IF_6_MHZ,
-};
-
-static struct tda18271_config hauppauge_woodbury_tunerconfig = {
- .gate = TDA18271_GATE_DIGITAL,
-};
-
-/*-------------------------------------------------------------------*/
-static void urb_completion(struct urb *purb)
-{
- struct au0828_dev *dev = purb->context;
- int ptype = usb_pipetype(purb->pipe);
-
- dprintk(2, "%s()\n", __func__);
-
- if (!dev)
- return;
-
- if (dev->urb_streaming == 0)
- return;
-
- if (ptype != PIPE_BULK) {
- printk(KERN_ERR "%s() Unsupported URB type %d\n",
- __func__, ptype);
- return;
- }
-
- /* Feed the transport payload into the kernel demux */
- dvb_dmx_swfilter_packets(&dev->dvb.demux,
- purb->transfer_buffer, purb->actual_length / 188);
-
- /* Clean the buffer before we requeue */
- memset(purb->transfer_buffer, 0, URB_BUFSIZE);
-
- /* Requeue URB */
- usb_submit_urb(purb, GFP_ATOMIC);
-}
-
-static int stop_urb_transfer(struct au0828_dev *dev)
-{
- int i;
-
- dprintk(2, "%s()\n", __func__);
-
- for (i = 0; i < URB_COUNT; i++) {
- usb_kill_urb(dev->urbs[i]);
- kfree(dev->urbs[i]->transfer_buffer);
- usb_free_urb(dev->urbs[i]);
- }
-
- dev->urb_streaming = 0;
-
- return 0;
-}
-
-static int start_urb_transfer(struct au0828_dev *dev)
-{
- struct urb *purb;
- int i, ret = -ENOMEM;
-
- dprintk(2, "%s()\n", __func__);
-
- if (dev->urb_streaming) {
- dprintk(2, "%s: bulk xfer already running!\n", __func__);
- return 0;
- }
-
- for (i = 0; i < URB_COUNT; i++) {
-
- dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->urbs[i])
- goto err;
-
- purb = dev->urbs[i];
-
- purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
- if (!purb->transfer_buffer) {
- usb_free_urb(purb);
- dev->urbs[i] = NULL;
- goto err;
- }
-
- purb->status = -EINPROGRESS;
- usb_fill_bulk_urb(purb,
- dev->usbdev,
- usb_rcvbulkpipe(dev->usbdev,
- _AU0828_BULKPIPE),
- purb->transfer_buffer,
- URB_BUFSIZE,
- urb_completion,
- dev);
-
- }
-
- for (i = 0; i < URB_COUNT; i++) {
- ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
- if (ret != 0) {
- stop_urb_transfer(dev);
- printk(KERN_ERR "%s: failed urb submission, "
- "err = %d\n", __func__, ret);
- return ret;
- }
- }
-
- dev->urb_streaming = 1;
- ret = 0;
-
-err:
- return ret;
-}
-
-static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
- struct au0828_dvb *dvb = &dev->dvb;
- int ret = 0;
-
- dprintk(1, "%s()\n", __func__);
-
- if (!demux->dmx.frontend)
- return -EINVAL;
-
- if (dvb) {
- mutex_lock(&dvb->lock);
- if (dvb->feeding++ == 0) {
- /* Start transport */
- au0828_write(dev, 0x608, 0x90);
- au0828_write(dev, 0x609, 0x72);
- au0828_write(dev, 0x60a, 0x71);
- au0828_write(dev, 0x60b, 0x01);
- ret = start_urb_transfer(dev);
- }
- mutex_unlock(&dvb->lock);
- }
-
- return ret;
-}
-
-static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
- struct au0828_dvb *dvb = &dev->dvb;
- int ret = 0;
-
- dprintk(1, "%s()\n", __func__);
-
- if (dvb) {
- mutex_lock(&dvb->lock);
- if (--dvb->feeding == 0) {
- /* Stop transport */
- au0828_write(dev, 0x608, 0x00);
- au0828_write(dev, 0x609, 0x00);
- au0828_write(dev, 0x60a, 0x00);
- au0828_write(dev, 0x60b, 0x00);
- ret = stop_urb_transfer(dev);
- }
- mutex_unlock(&dvb->lock);
- }
-
- return ret;
-}
-
-static int dvb_register(struct au0828_dev *dev)
-{
- struct au0828_dvb *dvb = &dev->dvb;
- int result;
-
- dprintk(1, "%s()\n", __func__);
-
- /* register adapter */
- result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
- &dev->usbdev->dev, adapter_nr);
- if (result < 0) {
- printk(KERN_ERR "%s: dvb_register_adapter failed "
- "(errno = %d)\n", DRIVER_NAME, result);
- goto fail_adapter;
- }
- dvb->adapter.priv = dev;
-
- /* register frontend */
- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
- if (result < 0) {
- printk(KERN_ERR "%s: dvb_register_frontend failed "
- "(errno = %d)\n", DRIVER_NAME, result);
- goto fail_frontend;
- }
-
- /* register demux stuff */
- dvb->demux.dmx.capabilities =
- DMX_TS_FILTERING | DMX_SECTION_FILTERING |
- DMX_MEMORY_BASED_FILTERING;
- dvb->demux.priv = dev;
- dvb->demux.filternum = 256;
- dvb->demux.feednum = 256;
- dvb->demux.start_feed = au0828_dvb_start_feed;
- dvb->demux.stop_feed = au0828_dvb_stop_feed;
- result = dvb_dmx_init(&dvb->demux);
- if (result < 0) {
- printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
- DRIVER_NAME, result);
- goto fail_dmx;
- }
-
- dvb->dmxdev.filternum = 256;
- dvb->dmxdev.demux = &dvb->demux.dmx;
- dvb->dmxdev.capabilities = 0;
- result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
- if (result < 0) {
- printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
- DRIVER_NAME, result);
- goto fail_dmxdev;
- }
-
- dvb->fe_hw.source = DMX_FRONTEND_0;
- result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- if (result < 0) {
- printk(KERN_ERR "%s: add_frontend failed "
- "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
- goto fail_fe_hw;
- }
-
- dvb->fe_mem.source = DMX_MEMORY_FE;
- result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
- if (result < 0) {
- printk(KERN_ERR "%s: add_frontend failed "
- "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
- goto fail_fe_mem;
- }
-
- result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- if (result < 0) {
- printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
- DRIVER_NAME, result);
- goto fail_fe_conn;
- }
-
- /* register network adapter */
- dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
- return 0;
-
-fail_fe_conn:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
-fail_fe_mem:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
-fail_fe_hw:
- dvb_dmxdev_release(&dvb->dmxdev);
-fail_dmxdev:
- dvb_dmx_release(&dvb->demux);
-fail_dmx:
- dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
- dvb_frontend_detach(dvb->frontend);
- dvb_unregister_adapter(&dvb->adapter);
-fail_adapter:
- return result;
-}
-
-void au0828_dvb_unregister(struct au0828_dev *dev)
-{
- struct au0828_dvb *dvb = &dev->dvb;
-
- dprintk(1, "%s()\n", __func__);
-
- if (dvb->frontend == NULL)
- return;
-
- dvb_net_release(&dvb->net);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- dvb_dmxdev_release(&dvb->dmxdev);
- dvb_dmx_release(&dvb->demux);
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
- dvb_unregister_adapter(&dvb->adapter);
-}
-
-/* All the DVB attach calls go here, this function get's modified
- * for each new card. No other function in this file needs
- * to change.
- */
-int au0828_dvb_register(struct au0828_dev *dev)
-{
- struct au0828_dvb *dvb = &dev->dvb;
- int ret;
-
- dprintk(1, "%s()\n", __func__);
-
- /* init frontend */
- switch (dev->boardnr) {
- case AU0828_BOARD_HAUPPAUGE_HVR850:
- case AU0828_BOARD_HAUPPAUGE_HVR950Q:
- dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_hvr950q_config,
- &dev->i2c_adap);
- if (dvb->frontend != NULL)
- switch (dev->board.tuner_type) {
- default:
- case TUNER_XC5000:
- dvb_attach(xc5000_attach, dvb->frontend,
- &dev->i2c_adap,
- &hauppauge_xc5000a_config);
- break;
- case TUNER_XC5000C:
- dvb_attach(xc5000_attach, dvb->frontend,
- &dev->i2c_adap,
- &hauppauge_xc5000c_config);
- break;
- }
- break;
- case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
- dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_hvr950q_config,
- &dev->i2c_adap);
- if (dvb->frontend != NULL)
- dvb_attach(mxl5007t_attach, dvb->frontend,
- &dev->i2c_adap, 0x60,
- &mxl5007t_hvr950q_config);
- break;
- case AU0828_BOARD_HAUPPAUGE_WOODBURY:
- dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_woodbury_config,
- &dev->i2c_adap);
- if (dvb->frontend != NULL)
- dvb_attach(tda18271_attach, dvb->frontend,
- 0x60, &dev->i2c_adap,
- &hauppauge_woodbury_tunerconfig);
- break;
- case AU0828_BOARD_DVICO_FUSIONHDTV7:
- dvb->frontend = dvb_attach(au8522_attach,
- &fusionhdtv7usb_config,
- &dev->i2c_adap);
- if (dvb->frontend != NULL) {
- dvb_attach(xc5000_attach, dvb->frontend,
- &dev->i2c_adap,
- &hauppauge_xc5000a_config);
- }
- break;
- default:
- printk(KERN_WARNING "The frontend of your DVB/ATSC card "
- "isn't supported yet\n");
- break;
- }
- if (NULL == dvb->frontend) {
- printk(KERN_ERR "%s() Frontend initialization failed\n",
- __func__);
- return -1;
- }
- /* define general-purpose callback pointer */
- dvb->frontend->callback = au0828_tuner_callback;
-
- /* register everything */
- ret = dvb_register(dev);
- if (ret < 0) {
- if (dvb->frontend->ops.release)
- dvb->frontend->ops.release(dvb->frontend);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
deleted file mode 100644
index 05c299fa5d79..000000000000
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Driver for the Auvitek AU0828 USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include "au0828.h"
-
-#include <media/v4l2-common.h>
-
-static int i2c_scan;
-module_param(i2c_scan, int, 0444);
-MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
-
-#define I2C_WAIT_DELAY 512
-#define I2C_WAIT_RETRY 64
-
-static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- return au0828_read(dev, AU0828_I2C_STATUS_201) &
- AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1;
-}
-
-static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- return au0828_read(dev, AU0828_I2C_STATUS_201) &
- AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1;
-}
-
-static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
-{
- int count;
-
- for (count = 0; count < I2C_WAIT_RETRY; count++) {
- if (!i2c_slave_did_read_ack(i2c_adap))
- break;
- udelay(I2C_WAIT_DELAY);
- }
-
- if (I2C_WAIT_RETRY == count)
- return 0;
-
- return 1;
-}
-
-static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- return au0828_read(dev, AU0828_I2C_STATUS_201) &
- AU0828_I2C_STATUS_READ_DONE ? 0 : 1;
-}
-
-static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
-{
- int count;
-
- for (count = 0; count < I2C_WAIT_RETRY; count++) {
- if (!i2c_is_read_busy(i2c_adap))
- break;
- udelay(I2C_WAIT_DELAY);
- }
-
- if (I2C_WAIT_RETRY == count)
- return 0;
-
- return 1;
-}
-
-static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- return au0828_read(dev, AU0828_I2C_STATUS_201) &
- AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0;
-}
-
-static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
-{
- int count;
-
- for (count = 0; count < I2C_WAIT_RETRY; count++) {
- if (i2c_is_write_done(i2c_adap))
- break;
- udelay(I2C_WAIT_DELAY);
- }
-
- if (I2C_WAIT_RETRY == count)
- return 0;
-
- return 1;
-}
-
-static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- return au0828_read(dev, AU0828_I2C_STATUS_201) &
- AU0828_I2C_STATUS_BUSY ? 1 : 0;
-}
-
-static int i2c_wait_done(struct i2c_adapter *i2c_adap)
-{
- int count;
-
- for (count = 0; count < I2C_WAIT_RETRY; count++) {
- if (!i2c_is_busy(i2c_adap))
- break;
- udelay(I2C_WAIT_DELAY);
- }
-
- if (I2C_WAIT_RETRY == count)
- return 0;
-
- return 1;
-}
-
-/* FIXME: Implement join handling correctly */
-static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
- const struct i2c_msg *msg, int joined_rlen)
-{
- int i, strobe = 0;
- struct au0828_dev *dev = i2c_adap->algo_data;
-
- dprintk(4, "%s()\n", __func__);
-
- au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
-
- /* Set the I2C clock */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- dev->board.i2c_clk_divider);
-
- /* Hardware needs 8 bit addresses */
- au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
-
- dprintk(4, "SEND: %02x\n", msg->addr);
-
- /* Deal with i2c_scan */
- if (msg->len == 0) {
- /* The analog tuner detection code makes use of the SMBUS_QUICK
- message (which involves a zero length i2c write). To avoid
- checking the status register when we didn't strobe out any
- actual bytes to the bus, just do a read check. This is
- consistent with how I saw i2c device checking done in the
- USB trace of the Windows driver */
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_READ);
-
- if (!i2c_wait_done(i2c_adap))
- return -EIO;
-
- if (i2c_wait_read_ack(i2c_adap))
- return -EIO;
-
- return 0;
- }
-
- for (i = 0; i < msg->len;) {
-
- dprintk(4, " %02x\n", msg->buf[i]);
-
- au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
-
- strobe++;
- i++;
-
- if ((strobe >= 4) || (i >= msg->len)) {
-
- /* Strobe the byte into the bus */
- if (i < msg->len)
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_WRITE |
- AU0828_I2C_TRIGGER_HOLD);
- else
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_WRITE);
-
- /* Reset strobe trigger */
- strobe = 0;
-
- if (!i2c_wait_write_done(i2c_adap))
- return -EIO;
-
- }
-
- }
- if (!i2c_wait_done(i2c_adap))
- return -EIO;
-
- dprintk(4, "\n");
-
- return msg->len;
-}
-
-/* FIXME: Implement join handling correctly */
-static int i2c_readbytes(struct i2c_adapter *i2c_adap,
- const struct i2c_msg *msg, int joined)
-{
- struct au0828_dev *dev = i2c_adap->algo_data;
- int i;
-
- dprintk(4, "%s()\n", __func__);
-
- au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
-
- /* Set the I2C clock */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- dev->board.i2c_clk_divider);
-
- /* Hardware needs 8 bit addresses */
- au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
-
- dprintk(4, " RECV:\n");
-
- /* Deal with i2c_scan */
- if (msg->len == 0) {
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_READ);
-
- if (i2c_wait_read_ack(i2c_adap))
- return -EIO;
- return 0;
- }
-
- for (i = 0; i < msg->len;) {
-
- i++;
-
- if (i < msg->len)
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_READ |
- AU0828_I2C_TRIGGER_HOLD);
- else
- au0828_write(dev, AU0828_I2C_TRIGGER_200,
- AU0828_I2C_TRIGGER_READ);
-
- if (!i2c_wait_read_done(i2c_adap))
- return -EIO;
-
- msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
- 0xff;
-
- dprintk(4, " %02x\n", msg->buf[i-1]);
- }
- if (!i2c_wait_done(i2c_adap))
- return -EIO;
-
- dprintk(4, "\n");
-
- return msg->len;
-}
-
-static int i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs, int num)
-{
- int i, retval = 0;
-
- dprintk(4, "%s(num = %d)\n", __func__, num);
-
- for (i = 0; i < num; i++) {
- dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
- __func__, num, msgs[i].addr, msgs[i].len);
- if (msgs[i].flags & I2C_M_RD) {
- /* read */
- retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
- } 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);
- if (retval < 0)
- goto err;
- i++;
- retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
- } else {
- /* write */
- retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
- }
- if (retval < 0)
- goto err;
- }
- return num;
-
-err:
- return retval;
-}
-
-static u32 au0828_functionality(struct i2c_adapter *adap)
-{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm au0828_i2c_algo_template = {
- .master_xfer = i2c_xfer,
- .functionality = au0828_functionality,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_adapter au0828_i2c_adap_template = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .algo = &au0828_i2c_algo_template,
-};
-
-static struct i2c_client au0828_i2c_client_template = {
- .name = "au0828 internal",
-};
-
-static char *i2c_devs[128] = {
- [0x8e >> 1] = "au8522",
- [0xa0 >> 1] = "eeprom",
- [0xc2 >> 1] = "tuner/xc5000",
-};
-
-static void do_i2c_scan(char *name, struct i2c_client *c)
-{
- unsigned char buf;
- int i, rc;
-
- for (i = 0; i < 128; i++) {
- c->addr = i;
- rc = i2c_master_recv(c, &buf, 0);
- if (rc < 0)
- continue;
- printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
- name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
- }
-}
-
-/* init + register i2c adapter */
-int au0828_i2c_register(struct au0828_dev *dev)
-{
- dprintk(1, "%s()\n", __func__);
-
- memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
- sizeof(dev->i2c_adap));
- memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
- sizeof(dev->i2c_algo));
- memcpy(&dev->i2c_client, &au0828_i2c_client_template,
- sizeof(dev->i2c_client));
-
- dev->i2c_adap.dev.parent = &dev->usbdev->dev;
-
- strlcpy(dev->i2c_adap.name, DRIVER_NAME,
- sizeof(dev->i2c_adap.name));
-
- dev->i2c_adap.algo = &dev->i2c_algo;
- dev->i2c_adap.algo_data = dev;
- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
- i2c_add_adapter(&dev->i2c_adap);
-
- dev->i2c_client.adapter = &dev->i2c_adap;
-
- if (0 == dev->i2c_rc) {
- printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
- if (i2c_scan)
- do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
- } else
- printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
-
- return dev->i2c_rc;
-}
-
-int au0828_i2c_unregister(struct au0828_dev *dev)
-{
- i2c_del_adapter(&dev->i2c_adap);
- return 0;
-}
-
diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
deleted file mode 100644
index c39f3d2b721e..000000000000
--- a/drivers/media/video/au0828/au0828-reg.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Driver for the Auvitek USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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.
- */
-
-/* We'll start to rename these registers once we have a better
- * understanding of their meaning.
- */
-#define REG_000 0x000
-#define REG_001 0x001
-#define REG_002 0x002
-#define REG_003 0x003
-
-#define AU0828_SENSORCTRL_100 0x100
-#define AU0828_SENSORCTRL_VBI_103 0x103
-
-/* I2C registers */
-#define AU0828_I2C_TRIGGER_200 0x200
-#define AU0828_I2C_STATUS_201 0x201
-#define AU0828_I2C_CLK_DIVIDER_202 0x202
-#define AU0828_I2C_DEST_ADDR_203 0x203
-#define AU0828_I2C_WRITE_FIFO_205 0x205
-#define AU0828_I2C_READ_FIFO_209 0x209
-#define AU0828_I2C_MULTIBYTE_MODE_2FF 0x2ff
-
-/* Audio registers */
-#define AU0828_AUDIOCTRL_50C 0x50C
-
-#define REG_600 0x600
-
-/*********************************************************************/
-/* Here are constants for values associated with the above registers */
-
-/* I2C Trigger (Reg 0x200) */
-#define AU0828_I2C_TRIGGER_WRITE 0x01
-#define AU0828_I2C_TRIGGER_READ 0x20
-#define AU0828_I2C_TRIGGER_HOLD 0x40
-
-/* I2C Status (Reg 0x201) */
-#define AU0828_I2C_STATUS_READ_DONE 0x01
-#define AU0828_I2C_STATUS_NO_READ_ACK 0x02
-#define AU0828_I2C_STATUS_WRITE_DONE 0x04
-#define AU0828_I2C_STATUS_NO_WRITE_ACK 0x08
-#define AU0828_I2C_STATUS_BUSY 0x10
-
-/* I2C Clock Divider (Reg 0x202) */
-#define AU0828_I2C_CLK_250KHZ 0x07
-#define AU0828_I2C_CLK_100KHZ 0x14
-#define AU0828_I2C_CLK_30KHZ 0x40
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
deleted file mode 100644
index ac3dd733ab81..000000000000
--- a/drivers/media/video/au0828/au0828-video.c
+++ /dev/null
@@ -1,1998 +0,0 @@
-/*
- * Auvitek AU0828 USB Bridge (Analog video support)
- *
- * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
- * Copyright (C) 2005-2008 Auvitek International, Ltd.
- *
- * 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.
- */
-
-/* Developer Notes:
- *
- * VBI support is not yet working
- * The hardware scaler supported is unimplemented
- * AC97 audio support is unimplemented (only i2s audio mode)
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/suspend.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/tuner.h>
-#include "au0828.h"
-#include "au0828-reg.h"
-
-static DEFINE_MUTEX(au0828_sysfs_lock);
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
-#define au0828_isocdbg(fmt, arg...) \
-do {\
- if (isoc_debug) { \
- printk(KERN_INFO "au0828 %s :"fmt, \
- __func__ , ##arg); \
- } \
- } while (0)
-
-static inline void print_err_status(struct au0828_dev *dev,
- int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronuously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronuously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
- } else {
- au0828_isocdbg("URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-static int check_dev(struct au0828_dev *dev)
-{
- if (dev->dev_state & DEV_DISCONNECTED) {
- printk(KERN_INFO "v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
-
- if (dev->dev_state & DEV_MISCONFIGURED) {
- printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
- "close and open it again\n");
- return -EIO;
- }
- return 0;
-}
-
-/*
- * IRQ callback, called by URB callback
- */
-static void au0828_irq_callback(struct urb *urb)
-{
- struct au0828_dmaqueue *dma_q = urb->context;
- struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
- unsigned long flags = 0;
- int i;
-
- switch (urb->status) {
- case 0: /* success */
- case -ETIMEDOUT: /* NAK */
- break;
- case -ECONNRESET: /* kill */
- case -ENOENT:
- case -ESHUTDOWN:
- au0828_isocdbg("au0828_irq_callback called: status kill\n");
- return;
- default: /* unknown error */
- au0828_isocdbg("urb completition error %d.\n", urb->status);
- break;
- }
-
- /* Copy data from URB */
- spin_lock_irqsave(&dev->slock, flags);
- dev->isoc_ctl.isoc_copy(dev, urb);
- spin_unlock_irqrestore(&dev->slock, flags);
-
- /* Reset urb buffers */
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
- urb->status = 0;
-
- urb->status = usb_submit_urb(urb, GFP_ATOMIC);
- if (urb->status) {
- au0828_isocdbg("urb resubmit failed (error=%i)\n",
- urb->status);
- }
-}
-
-/*
- * Stop and Deallocate URBs
- */
-void au0828_uninit_isoc(struct au0828_dev *dev)
-{
- struct urb *urb;
- int i;
-
- au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
-
- dev->isoc_ctl.nfields = -1;
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = dev->isoc_ctl.urb[i];
- if (urb) {
- if (!irqs_disabled())
- usb_kill_urb(urb);
- else
- usb_unlink_urb(urb);
-
- if (dev->isoc_ctl.transfer_buffer[i]) {
- usb_free_coherent(dev->usbdev,
- urb->transfer_buffer_length,
- dev->isoc_ctl.transfer_buffer[i],
- urb->transfer_dma);
- }
- usb_free_urb(urb);
- dev->isoc_ctl.urb[i] = NULL;
- }
- dev->isoc_ctl.transfer_buffer[i] = NULL;
- }
-
- kfree(dev->isoc_ctl.urb);
- kfree(dev->isoc_ctl.transfer_buffer);
-
- dev->isoc_ctl.urb = NULL;
- dev->isoc_ctl.transfer_buffer = NULL;
- dev->isoc_ctl.num_bufs = 0;
-}
-
-/*
- * Allocate URBs and start IRQ
- */
-int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
- int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
-{
- struct au0828_dmaqueue *dma_q = &dev->vidq;
- int i;
- int sb_size, pipe;
- struct urb *urb;
- int j, k;
- int rc;
-
- au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
-
- /* De-allocates all pending stuff */
- au0828_uninit_isoc(dev);
-
- dev->isoc_ctl.isoc_copy = isoc_copy;
- dev->isoc_ctl.num_bufs = num_bufs;
-
- dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
- if (!dev->isoc_ctl.urb) {
- au0828_isocdbg("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) {
- au0828_isocdbg("cannot allocate memory for usb transfer\n");
- kfree(dev->isoc_ctl.urb);
- return -ENOMEM;
- }
-
- dev->isoc_ctl.max_pkt_size = max_pkt_size;
- dev->isoc_ctl.buf = NULL;
-
- sb_size = max_packets * dev->isoc_ctl.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);
- if (!urb) {
- au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
- au0828_uninit_isoc(dev);
- return -ENOMEM;
- }
- dev->isoc_ctl.urb[i] = urb;
-
- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!dev->isoc_ctl.transfer_buffer[i]) {
- printk("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
- au0828_uninit_isoc(dev);
- return -ENOMEM;
- }
- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
-
- pipe = usb_rcvisocpipe(dev->usbdev,
- dev->isoc_in_endpointaddr),
-
- usb_fill_int_urb(urb, dev->usbdev, pipe,
- dev->isoc_ctl.transfer_buffer[i], sb_size,
- au0828_irq_callback, dma_q, 1);
-
- urb->number_of_packets = max_packets;
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-
- k = 0;
- for (j = 0; j < max_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;
- }
- }
-
- init_waitqueue_head(&dma_q->wq);
-
- /* 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);
- if (rc) {
- au0828_isocdbg("submit of urb %i failed (error=%i)\n",
- i, rc);
- au0828_uninit_isoc(dev);
- return rc;
- }
- }
-
- return 0;
-}
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf)
-{
- /* Advice that buffer was filled */
- au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- dev->isoc_ctl.buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-static inline void vbi_buffer_filled(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf)
-{
- /* Advice that buffer was filled */
- au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- dev->isoc_ctl.vbi_buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-/*
- * Identify the buffer header type and properly handles
- */
-static void au0828_copy_video(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
-{
- void *fieldstart, *startwrite, *startread;
- int linesdone, currlinedone, offset, lencopy, remain;
- int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
-
- if (len == 0)
- return;
-
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
-
- startread = p;
- remain = len;
-
- /* Interlaces frame */
- if (buf->top_field)
- fieldstart = outp;
- else
- fieldstart = outp + bytesperline;
-
- linesdone = dma_q->pos / bytesperline;
- currlinedone = dma_q->pos % bytesperline;
- offset = linesdone * bytesperline * 2 + currlinedone;
- startwrite = fieldstart + offset;
- lencopy = bytesperline - currlinedone;
- lencopy = lencopy > remain ? remain : lencopy;
-
- if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
- au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
- ((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- remain = (char *)outp + buf->vb.size - (char *)startwrite;
- lencopy = remain;
- }
- if (lencopy <= 0)
- return;
- memcpy(startwrite, startread, lencopy);
-
- remain -= lencopy;
-
- while (remain > 0) {
- startwrite += lencopy + bytesperline;
- startread += lencopy;
- if (bytesperline > remain)
- lencopy = remain;
- else
- lencopy = bytesperline;
-
- if ((char *)startwrite + lencopy > (char *)outp +
- buf->vb.size) {
- au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
- ((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- lencopy = remain = (char *)outp + buf->vb.size -
- (char *)startwrite;
- }
- if (lencopy <= 0)
- break;
-
- memcpy(startwrite, startread, lencopy);
-
- remain -= lencopy;
- }
-
- if (offset > 1440) {
- /* We have enough data to check for greenscreen */
- if (outp[0] < 0x60 && outp[1440] < 0x60)
- dev->greenscreen_detected = 1;
- }
-
- dma_q->pos += len;
-}
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
- struct au0828_buffer **buf)
-{
- struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
-
- if (list_empty(&dma_q->active)) {
- au0828_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.buf = NULL;
- *buf = NULL;
- return;
- }
-
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
- dev->isoc_ctl.buf = *buf;
-
- return;
-}
-
-static void au0828_copy_vbi(struct au0828_dev *dev,
- struct au0828_dmaqueue *dma_q,
- struct au0828_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
-{
- unsigned char *startwrite, *startread;
- int bytesperline;
- int i, j = 0;
-
- if (dev == NULL) {
- au0828_isocdbg("dev is null\n");
- return;
- }
-
- if (dma_q == NULL) {
- au0828_isocdbg("dma_q is null\n");
- return;
- }
- if (buf == NULL)
- return;
- if (p == NULL) {
- au0828_isocdbg("p is null\n");
- return;
- }
- if (outp == NULL) {
- au0828_isocdbg("outp is null\n");
- return;
- }
-
- bytesperline = dev->vbi_width;
-
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
-
- startread = p;
- startwrite = outp + (dma_q->pos / 2);
-
- /* Make sure the bottom field populates the second half of the frame */
- if (buf->top_field == 0)
- startwrite += bytesperline * dev->vbi_height;
-
- for (i = 0; i < len; i += 2)
- startwrite[j++] = startread[i+1];
-
- dma_q->pos += len;
-}
-
-
-/*
- * video-buf generic routine to get the next available VBI buffer
- */
-static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
- struct au0828_buffer **buf)
-{
- struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
- char *outp;
-
- if (list_empty(&dma_q->active)) {
- au0828_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.vbi_buf = NULL;
- *buf = NULL;
- return;
- }
-
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0x00, (*buf)->vb.size);
-
- dev->isoc_ctl.vbi_buf = *buf;
-
- return;
-}
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
-{
- struct au0828_buffer *buf;
- struct au0828_buffer *vbi_buf;
- struct au0828_dmaqueue *dma_q = urb->context;
- struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq;
- unsigned char *outp = NULL;
- unsigned char *vbioutp = NULL;
- int i, len = 0, rc = 1;
- unsigned char *p;
- unsigned char fbyte;
- unsigned int vbi_field_size;
- unsigned int remain, lencopy;
-
- if (!dev)
- return 0;
-
- if ((dev->dev_state & DEV_DISCONNECTED) ||
- (dev->dev_state & DEV_MISCONFIGURED))
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- buf = dev->isoc_ctl.buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- vbi_buf = dev->isoc_ctl.vbi_buf;
- if (vbi_buf != NULL)
- vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
-
- if (urb->iso_frame_desc[i].actual_length <= 0)
- continue;
-
- if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
- au0828_isocdbg("packet bigger than packet size");
- continue;
- }
-
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- fbyte = p[0];
- len = urb->iso_frame_desc[i].actual_length - 4;
- p += 4;
-
- if (fbyte & 0x80) {
- len -= 4;
- p += 4;
- au0828_isocdbg("Video frame %s\n",
- (fbyte & 0x40) ? "odd" : "even");
- if (fbyte & 0x40) {
- /* VBI */
- if (vbi_buf != NULL)
- vbi_buffer_filled(dev,
- vbi_dma_q,
- vbi_buf);
- vbi_get_next_buf(vbi_dma_q, &vbi_buf);
- if (vbi_buf == NULL)
- vbioutp = NULL;
- else
- vbioutp = videobuf_to_vmalloc(
- &vbi_buf->vb);
-
- /* Video */
- if (buf != NULL)
- buffer_filled(dev, dma_q, buf);
- get_next_buf(dma_q, &buf);
- if (buf == NULL)
- outp = NULL;
- else
- outp = videobuf_to_vmalloc(&buf->vb);
-
- /* As long as isoc traffic is arriving, keep
- resetting the timer */
- if (dev->vid_timeout_running)
- mod_timer(&dev->vid_timeout,
- jiffies + (HZ / 10));
- if (dev->vbi_timeout_running)
- mod_timer(&dev->vbi_timeout,
- jiffies + (HZ / 10));
- }
-
- if (buf != NULL) {
- if (fbyte & 0x40)
- buf->top_field = 1;
- else
- buf->top_field = 0;
- }
-
- if (vbi_buf != NULL) {
- if (fbyte & 0x40)
- vbi_buf->top_field = 1;
- else
- vbi_buf->top_field = 0;
- }
-
- dev->vbi_read = 0;
- vbi_dma_q->pos = 0;
- dma_q->pos = 0;
- }
-
- vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
- if (dev->vbi_read < vbi_field_size) {
- remain = vbi_field_size - dev->vbi_read;
- if (len < remain)
- lencopy = len;
- else
- lencopy = remain;
-
- if (vbi_buf != NULL)
- au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
- vbioutp, len);
-
- len -= lencopy;
- p += lencopy;
- dev->vbi_read += lencopy;
- }
-
- if (dev->vbi_read >= vbi_field_size && buf != NULL)
- au0828_copy_video(dev, dma_q, buf, p, outp, len);
- }
- return rc;
-}
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct au0828_fh *fh = vq->priv_data;
- *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
-
- if (0 == *count)
- *count = AU0828_DEF_BUF;
-
- if (*count < AU0828_MIN_BUF)
- *count = AU0828_MIN_BUF;
- return 0;
-}
-
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
-{
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.buf == buf)
- dev->isoc_ctl.buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
- struct au0828_dev *dev = fh->dev;
- int rc = 0, urb_init = 0;
-
- buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
-
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0) {
- printk(KERN_INFO "videobuf_iolock failed\n");
- goto fail;
- }
- }
-
- if (!dev->isoc_ctl.num_bufs)
- urb_init = 1;
-
- if (urb_init) {
- rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
- AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
- au0828_isoc_copy);
- if (rc < 0) {
- printk(KERN_INFO "au0828_init_isoc failed\n");
- goto fail;
- }
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct au0828_buffer *buf = container_of(vb,
- struct au0828_buffer,
- vb);
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
- struct au0828_dmaqueue *vidq = &dev->vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct au0828_buffer *buf = container_of(vb,
- struct au0828_buffer,
- vb);
-
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops au0828_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------
- V4L2 interface
- ------------------------------------------------------------------*/
-
-static int au0828_i2s_init(struct au0828_dev *dev)
-{
- /* Enable i2s mode */
- au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
- return 0;
-}
-
-/*
- * Auvitek au0828 analog stream enable
- * Please set interface0 to AS5 before enable the stream
- */
-int au0828_analog_stream_enable(struct au0828_dev *d)
-{
- dprintk(1, "au0828_analog_stream_enable called\n");
- au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
- au0828_writereg(d, 0x106, 0x00);
- /* set x position */
- au0828_writereg(d, 0x110, 0x00);
- au0828_writereg(d, 0x111, 0x00);
- au0828_writereg(d, 0x114, 0xa0);
- au0828_writereg(d, 0x115, 0x05);
- /* set y position */
- au0828_writereg(d, 0x112, 0x00);
- au0828_writereg(d, 0x113, 0x00);
- au0828_writereg(d, 0x116, 0xf2);
- au0828_writereg(d, 0x117, 0x00);
- au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
-
- return 0;
-}
-
-int au0828_analog_stream_disable(struct au0828_dev *d)
-{
- dprintk(1, "au0828_analog_stream_disable called\n");
- au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
- return 0;
-}
-
-void au0828_analog_stream_reset(struct au0828_dev *dev)
-{
- dprintk(1, "au0828_analog_stream_reset called\n");
- au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
- mdelay(30);
- au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
-}
-
-/*
- * Some operations needs to stop current streaming
- */
-static int au0828_stream_interrupt(struct au0828_dev *dev)
-{
- int ret = 0;
-
- dev->stream_state = STREAM_INTERRUPT;
- if (dev->dev_state == DEV_DISCONNECTED)
- return -ENODEV;
- else if (ret) {
- dev->dev_state = DEV_MISCONFIGURED;
- dprintk(1, "%s device is misconfigured!\n", __func__);
- return ret;
- }
- return 0;
-}
-
-/*
- * au0828_release_resources
- * unregister v4l2 devices
- */
-void au0828_analog_unregister(struct au0828_dev *dev)
-{
- dprintk(1, "au0828_release_resources called\n");
- mutex_lock(&au0828_sysfs_lock);
-
- if (dev->vdev)
- video_unregister_device(dev->vdev);
- if (dev->vbi_dev)
- video_unregister_device(dev->vbi_dev);
-
- mutex_unlock(&au0828_sysfs_lock);
-}
-
-
-/* Usage lock check functions */
-static int res_get(struct au0828_fh *fh, unsigned int bit)
-{
- struct au0828_dev *dev = fh->dev;
-
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources & bit) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- dprintk(1, "res: get %d\n", bit);
- mutex_unlock(&dev->lock);
- return 1;
-}
-
-static int res_check(struct au0828_fh *fh, unsigned int bit)
-{
- return fh->resources & bit;
-}
-
-static int res_locked(struct au0828_dev *dev, unsigned int bit)
-{
- return dev->resources & bit;
-}
-
-static void res_free(struct au0828_fh *fh, unsigned int bits)
-{
- struct au0828_dev *dev = fh->dev;
-
- BUG_ON((fh->resources & bits) != bits);
-
- mutex_lock(&dev->lock);
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- dprintk(1, "res: put %d\n", bits);
- mutex_unlock(&dev->lock);
-}
-
-static int get_ressource(struct au0828_fh *fh)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return AU0828_RESOURCE_VIDEO;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return AU0828_RESOURCE_VBI;
- default:
- BUG();
- return 0;
- }
-}
-
-/* This function ensures that video frames continue to be delivered even if
- the ITU-656 input isn't receiving any data (thereby preventing applications
- such as tvtime from hanging) */
-void au0828_vid_buffer_timeout(unsigned long data)
-{
- struct au0828_dev *dev = (struct au0828_dev *) data;
- struct au0828_dmaqueue *dma_q = &dev->vidq;
- struct au0828_buffer *buf;
- unsigned char *vid_data;
- unsigned long flags = 0;
-
- spin_lock_irqsave(&dev->slock, flags);
-
- buf = dev->isoc_ctl.buf;
- if (buf != NULL) {
- vid_data = videobuf_to_vmalloc(&buf->vb);
- memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
- buffer_filled(dev, dma_q, buf);
- }
- get_next_buf(dma_q, &buf);
-
- if (dev->vid_timeout_running == 1)
- mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
-
- spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-void au0828_vbi_buffer_timeout(unsigned long data)
-{
- struct au0828_dev *dev = (struct au0828_dev *) data;
- struct au0828_dmaqueue *dma_q = &dev->vbiq;
- struct au0828_buffer *buf;
- unsigned char *vbi_data;
- unsigned long flags = 0;
-
- spin_lock_irqsave(&dev->slock, flags);
-
- buf = dev->isoc_ctl.vbi_buf;
- if (buf != NULL) {
- vbi_data = videobuf_to_vmalloc(&buf->vb);
- memset(vbi_data, 0x00, buf->vb.size);
- vbi_buffer_filled(dev, dma_q, buf);
- }
- vbi_get_next_buf(dma_q, &buf);
-
- if (dev->vbi_timeout_running == 1)
- mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
- spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-
-static int au0828_v4l2_open(struct file *filp)
-{
- int ret = 0;
- struct video_device *vdev = video_devdata(filp);
- struct au0828_dev *dev = video_drvdata(filp);
- struct au0828_fh *fh;
- int type;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- default:
- return -EINVAL;
- }
-
- fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
- if (NULL == fh) {
- dprintk(1, "Failed allocate au0828_fh struct!\n");
- return -ENOMEM;
- }
-
- fh->type = type;
- fh->dev = dev;
- filp->private_data = fh;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- /* set au0828 interface0 to AS5 here again */
- ret = usb_set_interface(dev->usbdev, 0, 5);
- if (ret < 0) {
- printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
- return -EBUSY;
- }
- dev->width = NTSC_STD_W;
- dev->height = NTSC_STD_H;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->width * dev->height;
- dev->bytesperline = dev->width * 2;
-
- au0828_analog_stream_enable(dev);
- au0828_analog_stream_reset(dev);
-
- /* If we were doing ac97 instead of i2s, it would go here...*/
- au0828_i2s_init(dev);
-
- dev->stream_state = STREAM_OFF;
- dev->dev_state |= DEV_INITIALIZED;
- }
-
- dev->users++;
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct au0828_buffer), fh, NULL);
-
- /* VBI Setup */
- dev->vbi_width = 720;
- dev->vbi_height = 1;
- videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct au0828_buffer), fh, NULL);
-
- return ret;
-}
-
-static int au0828_v4l2_close(struct file *filp)
-{
- int ret;
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
-
- if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
- /* Cancel timeout thread in case they didn't call streamoff */
- dev->vid_timeout_running = 0;
- del_timer_sync(&dev->vid_timeout);
-
- videobuf_stop(&fh->vb_vidq);
- res_free(fh, AU0828_RESOURCE_VIDEO);
- }
-
- if (res_check(fh, AU0828_RESOURCE_VBI)) {
- /* Cancel timeout thread in case they didn't call streamoff */
- dev->vbi_timeout_running = 0;
- del_timer_sync(&dev->vbi_timeout);
-
- videobuf_stop(&fh->vb_vbiq);
- res_free(fh, AU0828_RESOURCE_VBI);
- }
-
- if (dev->users == 1) {
- if (dev->dev_state & DEV_DISCONNECTED) {
- au0828_analog_unregister(dev);
- kfree(dev);
- return 0;
- }
-
- au0828_analog_stream_disable(dev);
-
- au0828_uninit_isoc(dev);
-
- /* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
-
- /* When close the device, set the usb intf0 into alt0 to free
- USB bandwidth */
- ret = usb_set_interface(dev->usbdev, 0, 0);
- if (ret < 0)
- printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
- }
-
- videobuf_mmap_free(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vbiq);
- kfree(fh);
- dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
- return 0;
-}
-
-static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
- size_t count, loff_t *pos)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(dev, AU0828_RESOURCE_VIDEO))
- return -EBUSY;
-
- return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VBI))
- return -EBUSY;
-
- if (dev->vbi_timeout_running == 0) {
- /* Handle case where caller tries to read without
- calling streamon first */
- dev->vbi_timeout_running = 1;
- mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
- }
-
- return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
- return 0;
-}
-
-static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VIDEO))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VBI))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
- }
-}
-
-static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
-
- return rc;
-}
-
-static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
- struct v4l2_format *format)
-{
- int ret;
- int width = format->fmt.pix.width;
- int height = format->fmt.pix.height;
-
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- /* If they are demanding a format other than the one we support,
- bail out (tvtime asks for UYVY and then retries with YUYV) */
- if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
- return -EINVAL;
-
- /* format->fmt.pix.width only support 720 and height 480 */
- if (width != 720)
- width = 720;
- if (height != 480)
- height = 480;
-
- format->fmt.pix.width = width;
- format->fmt.pix.height = height;
- format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
- format->fmt.pix.bytesperline = width * 2;
- format->fmt.pix.sizeimage = width * height * 2;
- format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- format->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
- if (cmd == VIDIOC_TRY_FMT)
- return 0;
-
- /* maybe set new image format, driver current only support 720*480 */
- dev->width = width;
- dev->height = height;
- dev->frame_size = width * height * 2;
- dev->field_size = width * height;
- dev->bytesperline = width * 2;
-
- if (dev->stream_state == STREAM_ON) {
- dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
- ret = au0828_stream_interrupt(dev);
- if (ret != 0) {
- dprintk(1, "error interrupting video stream!\n");
- return ret;
- }
- }
-
- /* set au0828 interface0 to AS5 here again */
- ret = usb_set_interface(dev->usbdev, 0, 5);
- if (ret < 0) {
- printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
- return -EBUSY;
- }
-
- au0828_analog_stream_enable(dev);
-
- return 0;
-}
-
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- strlcpy(cap->driver, "au0828", sizeof(cap->driver));
- strlcpy(cap->card, dev->board.name, sizeof(cap->card));
- strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
-
- /*set the device capabilities */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_TUNER;
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (f->index)
- return -EINVAL;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(f->description, "Packed YUV2");
-
- f->flags = 0;
- f->pixelformat = V4L2_PIX_FMT_UYVY;
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
- f->fmt.pix.bytesperline = dev->bytesperline;
- f->fmt.pix.sizeimage = dev->frame_size;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- mutex_lock(&dev->lock);
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- printk(KERN_INFO "%s queue busy\n", __func__);
- rc = -EBUSY;
- goto out;
- }
-
- rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
-out:
- mutex_unlock(&dev->lock);
- return rc;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- /* FIXME: when we support something other than NTSC, we are going to
- have to make the au0828 bridge adjust the size of its capture
- buffer, which is currently hardcoded at 720x480 */
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
- return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *input)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- unsigned int tmp;
-
- static const char *inames[] = {
- [AU0828_VMUX_UNDEFINED] = "Undefined",
- [AU0828_VMUX_COMPOSITE] = "Composite",
- [AU0828_VMUX_SVIDEO] = "S-Video",
- [AU0828_VMUX_CABLE] = "Cable TV",
- [AU0828_VMUX_TELEVISION] = "Television",
- [AU0828_VMUX_DVB] = "DVB",
- [AU0828_VMUX_DEBUG] = "tv debug"
- };
-
- tmp = input->index;
-
- if (tmp >= AU0828_MAX_INPUT)
- return -EINVAL;
- if (AUVI_INPUT(tmp).type == 0)
- return -EINVAL;
-
- input->index = tmp;
- strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
- if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
- (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
- input->type |= V4L2_INPUT_TYPE_TUNER;
- else
- input->type |= V4L2_INPUT_TYPE_CAMERA;
-
- input->std = dev->vdev->tvnorms;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- *i = dev->ctrl_input;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int i;
-
- dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
- index);
- if (index >= AU0828_MAX_INPUT)
- return -EINVAL;
- if (AUVI_INPUT(index).type == 0)
- return -EINVAL;
- dev->ctrl_input = index;
-
- switch (AUVI_INPUT(index).type) {
- case AU0828_VMUX_SVIDEO:
- dev->input_type = AU0828_VMUX_SVIDEO;
- break;
- case AU0828_VMUX_COMPOSITE:
- dev->input_type = AU0828_VMUX_COMPOSITE;
- break;
- case AU0828_VMUX_TELEVISION:
- dev->input_type = AU0828_VMUX_TELEVISION;
- break;
- default:
- dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
- AUVI_INPUT(index).type);
- break;
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
- AUVI_INPUT(index).vmux, 0, 0);
-
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- int enable = 0;
- if (AUVI_INPUT(i).audio_setup == NULL)
- continue;
-
- if (i == index)
- enable = 1;
- else
- enable = 0;
- if (enable) {
- (AUVI_INPUT(i).audio_setup)(dev, enable);
- } else {
- /* Make sure we leave it turned on if some
- other input is routed to this callback */
- if ((AUVI_INPUT(i).audio_setup) !=
- ((AUVI_INPUT(index).audio_setup))) {
- (AUVI_INPUT(i).audio_setup)(dev, enable);
- }
- }
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
- AUVI_INPUT(index).amux, 0, 0);
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- unsigned int index = a->index;
-
- if (a->index > 1)
- return -EINVAL;
-
- index = dev->ctrl_ainput;
- if (index == 0)
- strcpy(a->name, "Television");
- else
- strcpy(a->name, "Line in");
-
- a->capability = V4L2_AUDCAP_STEREO;
- a->index = index;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- if (a->index != dev->ctrl_ainput)
- return -EINVAL;
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- return 0;
-
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- if (t->index != 0)
- return -EINVAL;
-
- strcpy(t->name, "Auvitek tuner");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- if (t->index != 0)
- return -EINVAL;
-
- t->type = V4L2_TUNER_ANALOG_TV;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
- dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
- t->afc);
- return 0;
-
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- freq->type = V4L2_TUNER_ANALOG_TV;
- freq->frequency = dev->ctrl_freq;
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- if (freq->tuner != 0)
- return -EINVAL;
- if (freq->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
-
- dev->ctrl_freq = freq->frequency;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
-
- au0828_analog_stream_reset(dev);
-
- return 0;
-}
-
-
-/* RAW VBI ioctls */
-
-static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *format)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- format->fmt.vbi.samples_per_line = dev->vbi_width;
- format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 0;
- format->fmt.vbi.flags = 0;
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
-
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
- format->fmt.vbi.start[0] = 21;
- format->fmt.vbi.start[1] = 284;
-
- return 0;
-}
-
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
-
- if (v4l2_chip_match_host(&chip->match)) {
- chip->ident = V4L2_IDENT_AU0828;
- return 0;
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
- if (chip->ident == V4L2_IDENT_NONE)
- return -EINVAL;
-
- return 0;
-}
-
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
-
- cc->defrect = cc->bounds;
-
- cc->pixelaspect.numerator = 54;
- cc->pixelaspect.denominator = 59;
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc = -EINVAL;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (unlikely(type != fh->type))
- return -EINVAL;
-
- dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (unlikely(!res_get(fh, get_ressource(fh))))
- return -EBUSY;
-
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- au0828_analog_stream_enable(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
- }
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- rc = videobuf_streamon(&fh->vb_vidq);
- dev->vid_timeout_running = 1;
- mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- rc = videobuf_streamon(&fh->vb_vbiq);
- dev->vbi_timeout_running = 1;
- mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
- }
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
- int i;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
- return -EINVAL;
- if (type != fh->type)
- return -EINVAL;
-
- dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev->vid_timeout_running = 0;
- del_timer_sync(&dev->vid_timeout);
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
- rc = au0828_stream_interrupt(dev);
- if (rc != 0)
- return rc;
-
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- if (AUVI_INPUT(i).audio_setup == NULL)
- continue;
- (AUVI_INPUT(i).audio_setup)(dev, 0);
- }
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, AU0828_RESOURCE_VIDEO);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- dev->vbi_timeout_running = 0;
- del_timer_sync(&dev->vbi_timeout);
-
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, AU0828_RESOURCE_VBI);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-#endif
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_reqbufs(&fh->vb_vidq, rb);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
-
- return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_querybuf(&fh->vb_vidq, b);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_querybuf(&fh->vb_vbiq, b);
-
- return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_qbuf(&fh->vb_vidq, b);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_qbuf(&fh->vb_vbiq, b);
-
- return rc;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- /* Workaround for a bug in the au0828 hardware design that sometimes
- results in the colorspace being inverted */
- if (dev->greenscreen_detected == 1) {
- dprintk(1, "Detected green frame. Resetting stream...\n");
- au0828_analog_stream_reset(dev);
- dev->greenscreen_detected = 0;
- }
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
-
- return rc;
-}
-
-static struct v4l2_file_operations au0828_v4l_fops = {
- .owner = THIS_MODULE,
- .open = au0828_v4l2_open,
- .release = au0828_v4l2_close,
- .read = au0828_v4l2_read,
- .poll = au0828_v4l2_poll,
- .mmap = au0828_v4l2_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_cropcap = vidioc_cropcap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
-#endif
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
-};
-
-static const struct video_device au0828_video_template = {
- .fops = &au0828_v4l_fops,
- .release = video_device_release,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-/**************************************************************************/
-
-int au0828_analog_register(struct au0828_dev *dev,
- struct usb_interface *interface)
-{
- int retval = -ENOMEM;
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
- int i, ret;
-
- dprintk(1, "au0828_analog_register called!\n");
-
- /* set au0828 usb interface0 to as5 */
- retval = usb_set_interface(dev->usbdev,
- interface->cur_altsetting->desc.bInterfaceNumber, 5);
- if (retval != 0) {
- printk(KERN_INFO "Failure setting usb interface0 to as5\n");
- return retval;
- }
-
- /* Figure out which endpoint has the isoc interface */
- iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_ISOC)) {
-
- /* we find our isoc in endpoint */
- u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
- dev->max_pkt_size = (tmp & 0x07ff) *
- (((tmp & 0x1800) >> 11) + 1);
- dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
- }
- }
- if (!(dev->isoc_in_endpointaddr)) {
- printk(KERN_INFO "Could not locate isoc endpoint\n");
- kfree(dev);
- return -ENODEV;
- }
-
- init_waitqueue_head(&dev->open);
- spin_lock_init(&dev->slock);
- mutex_init(&dev->lock);
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
- INIT_LIST_HEAD(&dev->vbiq.active);
- INIT_LIST_HEAD(&dev->vbiq.queued);
-
- dev->vid_timeout.function = au0828_vid_buffer_timeout;
- dev->vid_timeout.data = (unsigned long) dev;
- init_timer(&dev->vid_timeout);
-
- dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
- dev->vbi_timeout.data = (unsigned long) dev;
- init_timer(&dev->vbi_timeout);
-
- dev->width = NTSC_STD_W;
- dev->height = NTSC_STD_H;
- dev->field_size = dev->width * dev->height;
- dev->frame_size = dev->field_size << 1;
- dev->bytesperline = dev->width << 1;
- dev->ctrl_ainput = 0;
-
- /* allocate and fill v4l2 video struct */
- dev->vdev = video_device_alloc();
- if (NULL == dev->vdev) {
- dprintk(1, "Can't allocate video_device.\n");
- return -ENOMEM;
- }
-
- /* allocate the VBI struct */
- dev->vbi_dev = video_device_alloc();
- if (NULL == dev->vbi_dev) {
- dprintk(1, "Can't allocate vbi_device.\n");
- ret = -ENOMEM;
- goto err_vdev;
- }
-
- /* Fill the video capture device struct */
- *dev->vdev = au0828_video_template;
- dev->vdev->parent = &dev->usbdev->dev;
- strcpy(dev->vdev->name, "au0828a video");
-
- /* Setup the VBI device */
- *dev->vbi_dev = au0828_video_template;
- dev->vbi_dev->parent = &dev->usbdev->dev;
- strcpy(dev->vbi_dev->name, "au0828a vbi");
-
- /* Register the v4l2 device */
- video_set_drvdata(dev->vdev, dev);
- retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
- if (retval != 0) {
- dprintk(1, "unable to register video device (error = %d).\n",
- retval);
- ret = -ENODEV;
- goto err_vbi_dev;
- }
-
- /* Register the vbi device */
- video_set_drvdata(dev->vbi_dev, dev);
- retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
- if (retval != 0) {
- dprintk(1, "unable to register vbi device (error = %d).\n",
- retval);
- ret = -ENODEV;
- goto err_vbi_dev;
- }
-
- dprintk(1, "%s completed!\n", __func__);
-
- return 0;
-
-err_vbi_dev:
- video_device_release(dev->vbi_dev);
-err_vdev:
- video_device_release(dev->vdev);
- return ret;
-}
-
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
deleted file mode 100644
index 9cde35321824..000000000000
--- a/drivers/media/video/au0828/au0828.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Driver for the Auvitek AU0828 USB bridge
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- *
- * 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/usb.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <media/tveeprom.h>
-
-/* Analog */
-#include <linux/videodev2.h>
-#include <media/videobuf-vmalloc.h>
-#include <media/v4l2-device.h>
-
-/* DVB */
-#include "demux.h"
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dvb_net.h"
-#include "dvbdev.h"
-
-#include "au0828-reg.h"
-#include "au0828-cards.h"
-
-#define DRIVER_NAME "au0828"
-#define URB_COUNT 16
-#define URB_BUFSIZE (0xe522)
-
-/* Analog constants */
-#define NTSC_STD_W 720
-#define NTSC_STD_H 480
-
-#define AU0828_INTERLACED_DEFAULT 1
-#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
-
-/* Defination for AU0828 USB transfer */
-#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
-#define AU0828_ISO_PACKETS_PER_URB 128
-
-#define AU0828_MIN_BUF 4
-#define AU0828_DEF_BUF 8
-
-#define AU0828_MAX_INPUT 4
-
-/* au0828 resource types (used for res_get/res_lock etc */
-#define AU0828_RESOURCE_VIDEO 0x01
-#define AU0828_RESOURCE_VBI 0x02
-
-enum au0828_itype {
- AU0828_VMUX_UNDEFINED = 0,
- AU0828_VMUX_COMPOSITE,
- AU0828_VMUX_SVIDEO,
- AU0828_VMUX_CABLE,
- AU0828_VMUX_TELEVISION,
- AU0828_VMUX_DVB,
- AU0828_VMUX_DEBUG
-};
-
-struct au0828_input {
- enum au0828_itype type;
- unsigned int vmux;
- unsigned int amux;
- void (*audio_setup) (void *priv, int enable);
-};
-
-struct au0828_board {
- char *name;
- unsigned int tuner_type;
- unsigned char tuner_addr;
- unsigned char i2c_clk_divider;
- struct au0828_input input[AU0828_MAX_INPUT];
-
-};
-
-struct au0828_dvb {
- struct mutex lock;
- struct dvb_adapter adapter;
- struct dvb_frontend *frontend;
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dmx_frontend fe_hw;
- struct dmx_frontend fe_mem;
- struct dvb_net net;
- int feeding;
-};
-
-enum au0828_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON
-};
-
-#define AUVI_INPUT(nr) (dev->board.input[nr])
-
-/* device state */
-enum au0828_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04
-};
-
-struct au0828_fh {
- struct au0828_dev *dev;
- unsigned int resources;
-
- struct videobuf_queue vb_vidq;
- struct videobuf_queue vb_vbiq;
- enum v4l2_buf_type type;
-};
-
-struct au0828_usb_isoc_ctl {
- /* max packet size of isoc transaction */
- int max_pkt_size;
-
- /* number of allocated urbs */
- int num_bufs;
-
- /* urb for isoc transfers */
- struct urb **urb;
-
- /* transfer buffers for isoc transfer */
- char **transfer_buffer;
-
- /* Last buffer command and region */
- u8 cmd;
- int pos, size, pktsize;
-
- /* Last field: ODD or EVEN? */
- int field;
-
- /* Stores incomplete commands */
- u32 tmp_buf;
- int tmp_buf_len;
-
- /* Stores already requested buffers */
- struct au0828_buffer *buf;
- struct au0828_buffer *vbi_buf;
-
- /* Stores the number of received fields */
- int nfields;
-
- /* isoc urb callback */
- int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
-
-};
-
-/* buffer for one video frame */
-struct au0828_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
-
- struct list_head frame;
- int top_field;
- int receiving;
-};
-
-struct au0828_dmaqueue {
- struct list_head active;
- struct list_head queued;
-
- wait_queue_head_t wq;
-
- /* Counters to control buffer fill */
- int pos;
-};
-
-struct au0828_dev {
- struct mutex mutex;
- struct usb_device *usbdev;
- int boardnr;
- struct au0828_board board;
- u8 ctrlmsg[64];
-
- /* I2C */
- struct i2c_adapter i2c_adap;
- struct i2c_algorithm i2c_algo;
- struct i2c_client i2c_client;
- u32 i2c_rc;
-
- /* Digital */
- struct au0828_dvb dvb;
-
- /* Analog */
- struct v4l2_device v4l2_dev;
- int users;
- unsigned int resources; /* resources in use */
- struct video_device *vdev;
- struct video_device *vbi_dev;
- struct timer_list vid_timeout;
- int vid_timeout_running;
- struct timer_list vbi_timeout;
- int vbi_timeout_running;
- int width;
- int height;
- int vbi_width;
- int vbi_height;
- u32 vbi_read;
- u32 field_size;
- u32 frame_size;
- u32 bytesperline;
- int type;
- u8 ctrl_ainput;
- __u8 isoc_in_endpointaddr;
- u8 isoc_init_ok;
- int greenscreen_detected;
- unsigned int frame_count;
- int ctrl_freq;
- int input_type;
- unsigned int ctrl_input;
- enum au0828_dev_state dev_state;
- enum au0828_stream_state stream_state;
- wait_queue_head_t open;
-
- struct mutex lock;
-
- /* Isoc control struct */
- struct au0828_dmaqueue vidq;
- struct au0828_dmaqueue vbiq;
- struct au0828_usb_isoc_ctl isoc_ctl;
- spinlock_t slock;
-
- /* usb transfer */
- int alt; /* alternate */
- 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[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
- char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
- transfer */
-
- /* USB / URB Related */
- int urb_streaming;
- struct urb *urbs[URB_COUNT];
-};
-
-/* ----------------------------------------------------------- */
-#define au0828_read(dev, reg) au0828_readreg(dev, reg)
-#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
-#define au0828_andor(dev, reg, mask, value) \
- au0828_writereg(dev, reg, \
- (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
-
-#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
-#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
-
-/* ----------------------------------------------------------- */
-/* au0828-core.c */
-extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
-extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
-extern int au0828_debug;
-
-/* ----------------------------------------------------------- */
-/* au0828-cards.c */
-extern struct au0828_board au0828_boards[];
-extern struct usb_device_id au0828_usb_id_table[];
-extern void au0828_gpio_setup(struct au0828_dev *dev);
-extern int au0828_tuner_callback(void *priv, int component,
- int command, int arg);
-extern void au0828_card_setup(struct au0828_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* au0828-i2c.c */
-extern int au0828_i2c_register(struct au0828_dev *dev);
-extern int au0828_i2c_unregister(struct au0828_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* au0828-video.c */
-int au0828_analog_register(struct au0828_dev *dev,
- struct usb_interface *interface);
-int au0828_analog_stream_disable(struct au0828_dev *d);
-void au0828_analog_unregister(struct au0828_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* au0828-dvb.c */
-extern int au0828_dvb_register(struct au0828_dev *dev);
-extern void au0828_dvb_unregister(struct au0828_dev *dev);
-
-/* au0828-vbi.c */
-extern struct videobuf_queue_ops au0828_vbi_qops;
-
-#define dprintk(level, fmt, arg...)\
- do { if (au0828_debug & level)\
- printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
- } while (0)
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
deleted file mode 100644
index 0aba45e34f70..000000000000
--- a/drivers/media/video/blackfin/bfin_capture.c
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * 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;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
-
- /* 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/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
deleted file mode 100644
index 7da5c2e1fc12..000000000000
--- a/drivers/media/video/bt8xx/Kconfig
+++ /dev/null
@@ -1,27 +0,0 @@
-config VIDEO_BT848
- tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
- select I2C_ALGOBIT
- select VIDEO_BTCX
- select VIDEOBUF_DMA_SG
- depends on RC_CORE
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- Support for BT848 based frame grabber/overlay boards. This includes
- the Miro, Hauppauge and STB boards. Please read the material in
- <file:Documentation/video4linux/bttv/> for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called bttv.
-
-config VIDEO_BT848_DVB
- bool "DVB/ATSC Support for bt878 based TV cards"
- depends on VIDEO_BT848 && DVB_CORE
- select DVB_BT8XX
- ---help---
- This adds support for DVB/ATSC cards based on the BT878 chip.
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
deleted file mode 100644
index 3f9a2b22d3d4..000000000000
--- a/drivers/media/video/bt8xx/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the video capture/playback device drivers.
-#
-
-bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
- bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
- bttv-input.o bttv-audio-hook.o
-
-obj-$(CONFIG_VIDEO_BT848) += bttv.o
-
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
deleted file mode 100644
index 17188e234770..000000000000
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ /dev/null
@@ -1,2413 +0,0 @@
-/****************************************************************************
- *
- * Filename: cpia2_core.c
- *
- * Copyright 2001, STMicrolectronics, Inc.
- * Contact: steve.miller@st.com
- *
- * Description:
- * This is a USB driver for CPia2 based video cameras.
- * The infrastructure of this driver is based on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- * 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.
- *
- * Stripped of 2.4 stuff ready for main kernel submit by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- ****************************************************************************/
-
-#include "cpia2.h"
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/firmware.h>
-
-/* #define _CPIA2_DEBUG_ */
-
-#ifdef _CPIA2_DEBUG_
-
-static const char *block_name[] = {
- "System",
- "VC",
- "VP",
- "IDATA"
-};
-#endif
-
-static unsigned int debugs_on; /* default 0 - DEBUG_REG */
-
-
-/******************************************************************************
- *
- * Forward Declarations
- *
- *****************************************************************************/
-static int apply_vp_patch(struct camera_data *cam);
-static int set_default_user_mode(struct camera_data *cam);
-static int set_vw_size(struct camera_data *cam, int size);
-static int configure_sensor(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int config_sensor_410(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int config_sensor_500(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int set_all_properties(struct camera_data *cam);
-static void wake_system(struct camera_data *cam);
-static void set_lowlight_boost(struct camera_data *cam);
-static void reset_camera_struct(struct camera_data *cam);
-static int cpia2_set_high_power(struct camera_data *cam);
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
- kva |= adr & (PAGE_SIZE-1); /* restore the offset */
- ret = __pa(kva);
- return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- /* Round it off to PAGE_SIZE */
- size = PAGE_ALIGN(size);
-
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
-
- while ((long)size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- size = PAGE_ALIGN(size);
-
- adr = (unsigned long) mem;
- while ((long)size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/******************************************************************************
- *
- * cpia2_do_command
- *
- * Send an arbitrary command to the camera. For commands that read from
- * the camera, copy the buffers into the proper param structures.
- *****************************************************************************/
-int cpia2_do_command(struct camera_data *cam,
- u32 command, u8 direction, u8 param)
-{
- int retval = 0;
- struct cpia2_command cmd;
- unsigned int device = cam->params.pnp_id.device_type;
-
- cmd.command = command;
- cmd.reg_count = 2; /* default */
- cmd.direction = direction;
-
- /***
- * Set up the command.
- ***/
- switch (command) {
- case CPIA2_CMD_GET_VERSION:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.start = CPIA2_SYSTEM_DEVICE_HI;
- break;
- case CPIA2_CMD_GET_PNP_ID:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 8;
- cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
- break;
- case CPIA2_CMD_GET_ASIC_TYPE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.start = CPIA2_VC_ASIC_ID;
- break;
- case CPIA2_CMD_GET_SENSOR:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.start = CPIA2_VP_SENSOR_FLAGS;
- break;
- case CPIA2_CMD_GET_VP_DEVICE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.start = CPIA2_VP_DEVICEH;
- break;
- case CPIA2_CMD_SET_VP_BRIGHTNESS:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_BRIGHTNESS:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
- else
- cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
- break;
- case CPIA2_CMD_SET_CONTRAST:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_CONTRAST:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_YRANGE;
- break;
- case CPIA2_CMD_SET_VP_SATURATION:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_SATURATION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP_SATURATION;
- else
- cmd.start = CPIA2_VP5_MCUVSATURATION;
- break;
- case CPIA2_CMD_SET_VP_GPIO_DATA:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_GPIO_DATA:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_GPIO_DATA;
- break;
- case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_GPIO_DIRECTION;
- break;
- case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_MP_DATA;
- break;
- case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_MP_DIR;
- break;
- case CPIA2_CMD_ENABLE_PACKET_CTRL:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
- cmd.reg_count = 1;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_FLICKER_MODES:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_FLICKER_MODES:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_FLICKER_MODES;
- break;
- case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 2;
- cmd.start = 0;
- cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
- cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB |
- CPIA2_VC_ST_CTRL_EOF_DETECT |
- CPIA2_VC_ST_CTRL_FIFO_ENABLE;
- break;
- case CPIA2_CMD_SET_HI_POWER:
- cmd.req_mode =
- CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 2;
- cmd.buffer.registers[0].index =
- CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.registers[1].index =
- CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
- cmd.buffer.registers[1].value =
- CPIA2_SYSTEM_CONTROL_HIGH_POWER;
- break;
- case CPIA2_CMD_SET_LOW_POWER:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.block_data[0] = 0;
- break;
- case CPIA2_CMD_CLEAR_V2W_ERR:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
- break;
- case CPIA2_CMD_SET_USER_MODE: /* Then fall through */
- cmd.buffer.block_data[0] = param;
- case CPIA2_CMD_GET_USER_MODE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_USER_MODE;
- else
- cmd.start = CPIA2_VP5_USER_MODE;
- break;
- case CPIA2_CMD_FRAMERATE_REQ:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
- else
- cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_WAKEUP:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_WAKEUP:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_WAKEUP;
- break;
- case CPIA2_CMD_SET_PW_CONTROL:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_PW_CONTROL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_PW_CTRL;
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_STATE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_SYSTEMSTATE;
- break;
- case CPIA2_CMD_SET_SYSTEM_CTRL:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_SYSTEM_CTRL:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- break;
- case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_SYSTEMCTRL;
- break;
- case CPIA2_CMD_SET_VP_EXP_MODES:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VP_EXP_MODES:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_EXPOSURE_MODES;
- break;
- case CPIA2_CMD_SET_DEVICE_CONFIG:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_DEVICE_CONFIG:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_DEVICE_CONFIG;
- break;
- case CPIA2_CMD_SET_SERIAL_ADDR:
- cmd.buffer.block_data[0] = param;
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
- break;
- case CPIA2_CMD_SET_SENSOR_CR1:
- cmd.buffer.block_data[0] = param;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SENSOR_CR1;
- break;
- case CPIA2_CMD_SET_VC_CONTROL:
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_VC_CONTROL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_VC_CTRL;
- break;
- case CPIA2_CMD_SET_TARGET_KB:
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
- cmd.buffer.registers[0].value = param;
- break;
- case CPIA2_CMD_SET_DEF_JPEG_OPT:
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 4;
- cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
- cmd.buffer.registers[0].value =
- CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
- cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
- cmd.buffer.registers[1].value = 20;
- cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
- cmd.buffer.registers[2].value = 2;
- cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
- cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
- break;
- case CPIA2_CMD_REHASH_VP4:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_REHASH_VALUES;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as
- this register can also affect
- flicker modes */
- cmd.buffer.block_data[0] = param; /* Then fall through */
- case CPIA2_CMD_GET_USER_EFFECTS:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_USER_EFFECTS;
- else
- cmd.start = CPIA2_VP5_USER_EFFECTS;
- break;
- default:
- LOG("DoCommand received invalid command\n");
- return -EINVAL;
- }
-
- retval = cpia2_send_command(cam, &cmd);
- if (retval) {
- return retval;
- }
-
- /***
- * Now copy any results from a read into the appropriate param struct.
- ***/
- switch (command) {
- case CPIA2_CMD_GET_VERSION:
- cam->params.version.firmware_revision_hi =
- cmd.buffer.block_data[0];
- cam->params.version.firmware_revision_lo =
- cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_PNP_ID:
- cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
- cmd.buffer.block_data[1];
- cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
- cmd.buffer.block_data[3];
- cam->params.pnp_id.device_revision =
- (cmd.buffer.block_data[4] << 8) |
- cmd.buffer.block_data[5];
- if (cam->params.pnp_id.vendor == 0x553) {
- if (cam->params.pnp_id.product == 0x100) {
- cam->params.pnp_id.device_type = DEVICE_STV_672;
- } else if (cam->params.pnp_id.product == 0x140 ||
- cam->params.pnp_id.product == 0x151) {
- cam->params.pnp_id.device_type = DEVICE_STV_676;
- }
- }
- break;
- case CPIA2_CMD_GET_ASIC_TYPE:
- cam->params.version.asic_id = cmd.buffer.block_data[0];
- cam->params.version.asic_rev = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_SENSOR:
- cam->params.version.sensor_flags = cmd.buffer.block_data[0];
- cam->params.version.sensor_rev = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_VP_DEVICE:
- cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
- cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_VP_GPIO_DATA:
- cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
- cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
- cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
- cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_FLICKER_MODES:
- cam->params.flicker_control.cam_register =
- cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_WAKEUP:
- cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_PW_CONTROL:
- cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_SYSTEM_CTRL:
- cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_STATE:
- cam->params.vp_params.system_state = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
- cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_EXP_MODES:
- cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_DEVICE_CONFIG:
- cam->params.vp_params.device_config = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_CONTROL:
- cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_USER_MODE:
- cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_USER_EFFECTS:
- cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
- break;
- default:
- break;
- }
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_send_command
- *
- *****************************************************************************/
-
-#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read")
-#define BINDEX(cmd) (cmd->req_mode & 0x03)
-
-int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
-{
- u8 count;
- u8 start;
- u8 *buffer;
- int retval;
-
- switch (cmd->req_mode & 0x0c) {
- case CAMERAACCESS_TYPE_RANDOM:
- count = cmd->reg_count * sizeof(struct cpia2_register);
- start = 0;
- buffer = (u8 *) & cmd->buffer;
- if (debugs_on & DEBUG_REG)
- DBG("%s Random: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_BLOCK:
- count = cmd->reg_count;
- start = cmd->start;
- buffer = cmd->buffer.block_data;
- if (debugs_on & DEBUG_REG)
- DBG("%s Block: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_MASK:
- count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
- start = 0;
- buffer = (u8 *) & cmd->buffer;
- if (debugs_on & DEBUG_REG)
- DBG("%s Mask: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */
- count = cmd->reg_count;
- start = cmd->start;
- buffer = cmd->buffer.block_data;
- if (debugs_on & DEBUG_REG)
- DBG("%s Repeat: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- default:
- LOG("%s: invalid request mode\n",__func__);
- return -EINVAL;
- }
-
- retval = cpia2_usb_transfer_cmd(cam,
- buffer,
- cmd->req_mode,
- start, count, cmd->direction);
-#ifdef _CPIA2_DEBUG_
- if (debugs_on & DEBUG_REG) {
- int i;
- for (i = 0; i < cmd->reg_count; i++) {
- if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
- KINFO("%s Block: [0x%02X] = 0x%02X\n",
- DIR(cmd), start + i, buffer[i]);
- if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
- KINFO("%s Random: [0x%02X] = 0x%02X\n",
- DIR(cmd), cmd->buffer.registers[i].index,
- cmd->buffer.registers[i].value);
- }
- }
-#endif
-
- return retval;
-};
-
-/*************
- * Functions to implement camera functionality
- *************/
-/******************************************************************************
- *
- * cpia2_get_version_info
- *
- *****************************************************************************/
-static void cpia2_get_version_info(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
-}
-
-/******************************************************************************
- *
- * cpia2_reset_camera
- *
- * Called at least during the open process, sets up initial params.
- *****************************************************************************/
-int cpia2_reset_camera(struct camera_data *cam)
-{
- u8 tmp_reg;
- int retval = 0;
- int target_kb;
- int i;
- struct cpia2_command cmd;
-
- /***
- * VC setup
- ***/
- retval = configure_sensor(cam,
- cam->params.roi.width,
- cam->params.roi.height);
- if (retval < 0) {
- ERR("Couldn't configure sensor, error=%d\n", retval);
- return retval;
- }
-
- /* Clear FIFO and route/enable stream block */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
- cmd.reg_count = 2;
- cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
- cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB |
- CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
-
- cpia2_send_command(cam, &cmd);
-
- cpia2_set_high_power(cam);
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- /* Enable button notification */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
- cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
- cmd.buffer.registers[0].value =
- CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- }
-
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- retval = apply_vp_patch(cam);
-
- /* wait for vp to go to sleep */
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- /***
- * If this is a 676, apply VP5 fixes before we start streaming
- ***/
- if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
-
- /* The following writes improve the picture */
- cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
- cmd.buffer.registers[0].value = 0; /* reduce from the default
- * rec 601 pedestal of 16 */
- cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
- cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
- * (256/256 - 31) to fill
- * available range */
- cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
- cmd.buffer.registers[2].value = 0xFF; /* Increase from the
- * default rec 601 ceiling
- * of 240 */
- cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
- cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
- * 601 100% level (128)
- * to 145-192 */
- cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
- cmd.buffer.registers[4].value = 0x80; /* Inhibit the
- * anti-flicker */
-
- /* The following 4 writes are a fix to allow QVGA to work at 30 fps */
- cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
- cmd.buffer.registers[5].value = 0x01;
- cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
- cmd.buffer.registers[6].value = 0xE3;
- cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
- cmd.buffer.registers[7].value = 0x02;
- cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
- cmd.buffer.registers[8].value = 0xFC;
-
- cmd.direction = TRANSFER_WRITE;
- cmd.reg_count = 9;
-
- cpia2_send_command(cam, &cmd);
- }
-
- /* Activate all settings and start the data stream */
- /* Set user mode */
- set_default_user_mode(cam);
-
- /* Give VP time to wake up */
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- set_all_properties(cam);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
- DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
- cam->params.vp_params.video_mode);
-
- /***
- * Set audio regulator off. This and the code to set the compresison
- * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
- * intertwined. This stuff came straight from the windows driver.
- ***/
- /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
- tmp_reg = cam->params.vp_params.system_ctrl;
- cmd.buffer.registers[0].value = tmp_reg &
- (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
-
- cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
- cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
- CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
- cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
- cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
- cmd.reg_count = 2;
- cmd.direction = TRANSFER_WRITE;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
-
- /* Set the correct I2C address in the CPiA-2 system register */
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
-
- /* Now have sensor access - set bit to turn the audio regulator off */
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SENSOR_CR1,
- TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
-
- /* Set the correct I2C address in the CPiA-2 system register */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
- else
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
-
- /* increase signal drive strength */
- if (cam->params.pnp_id.device_type == DEVICE_STV_676)
- cpia2_do_command(cam,
- CPIA2_CMD_SET_VP_EXP_MODES,
- TRANSFER_WRITE,
- CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
-
- /* Start autoexposure */
- cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
- cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
- (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
- cmd.buffer.registers[1].value =
- cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
-
- cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
- cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
- cmd.reg_count = 2;
- cmd.direction = TRANSFER_WRITE;
-
- cpia2_send_command(cam, &cmd);
-
- /* Set compression state */
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
- if (cam->params.compression.inhibit_htables) {
- tmp_reg = cam->params.vc_params.vc_control |
- CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
- } else {
- tmp_reg = cam->params.vc_params.vc_control &
- ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
- }
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- /* Set target size (kb) on vc
- This is a heuristic based on the quality parameter and the raw
- framesize in kB divided by 16 (the compression factor when the
- quality is 100%) */
- target_kb = (cam->width * cam->height * 2 / 16384) *
- cam->params.vc_params.quality / 100;
- if (target_kb < 1)
- target_kb = 1;
- cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
- TRANSFER_WRITE, target_kb);
-
- /* Wiggle VC Reset */
- /***
- * First read and wait a bit.
- ***/
- for (i = 0; i < 50; i++) {
- cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
- TRANSFER_READ, 0);
- }
-
- tmp_reg = cam->params.vc_params.pw_control;
- tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
-
- cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
- cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
- DBG("After VC RESET, user mode is 0x%0X\n",
- cam->params.vp_params.video_mode);
-
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_set_high_power
- *
- *****************************************************************************/
-static int cpia2_set_high_power(struct camera_data *cam)
-{
- int i;
- for (i = 0; i <= 50; i++) {
- /* Read system status */
- cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
-
- /* If there is an error, clear it */
- if(cam->params.camera_state.system_ctrl &
- CPIA2_SYSTEM_CONTROL_V2W_ERR)
- cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
- TRANSFER_WRITE, 0);
-
- /* Try to set high power mode */
- cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
- TRANSFER_WRITE, 1);
-
- /* Try to read something in VP to check if everything is awake */
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
- TRANSFER_READ, 0);
- if (cam->params.vp_params.system_state &
- CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
- break;
- } else if (i == 50) {
- cam->params.camera_state.power_mode = LO_POWER_MODE;
- ERR("Camera did not wake up\n");
- return -EIO;
- }
- }
-
- DBG("System now in high power state\n");
- cam->params.camera_state.power_mode = HI_POWER_MODE;
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_set_low_power
- *
- *****************************************************************************/
-int cpia2_set_low_power(struct camera_data *cam)
-{
- cam->params.camera_state.power_mode = LO_POWER_MODE;
- cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
- return 0;
-}
-
-/******************************************************************************
- *
- * apply_vp_patch
- *
- *****************************************************************************/
-static int cpia2_send_onebyte_command(struct camera_data *cam,
- struct cpia2_command *cmd,
- u8 start, u8 datum)
-{
- cmd->buffer.block_data[0] = datum;
- cmd->start = start;
- cmd->reg_count = 1;
- return cpia2_send_command(cam, cmd);
-}
-
-static int apply_vp_patch(struct camera_data *cam)
-{
- const struct firmware *fw;
- const char fw_name[] = "cpia2/stv0672_vp4.bin";
- int i, ret;
- struct cpia2_command cmd;
-
- ret = request_firmware(&fw, fw_name, &cam->dev->dev);
- if (ret) {
- printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n",
- fw_name);
- return ret;
- }
-
- cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
- cmd.direction = TRANSFER_WRITE;
-
- /* First send the start address... */
- cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
- cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
-
- /* ... followed by the data payload */
- for (i = 2; i < fw->size; i += 64) {
- cmd.start = 0x0C; /* Data */
- cmd.reg_count = min_t(int, 64, fw->size - i);
- memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count);
- cpia2_send_command(cam, &cmd);
- }
-
- /* Next send the start address... */
- cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
- cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
-
- /* ... followed by the 'goto' command */
- cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1);
-
- release_firmware(fw);
- return 0;
-}
-
-/******************************************************************************
- *
- * set_default_user_mode
- *
- *****************************************************************************/
-static int set_default_user_mode(struct camera_data *cam)
-{
- unsigned char user_mode;
- unsigned char frame_rate;
- int width = cam->params.roi.width;
- int height = cam->params.roi.height;
-
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- case CPIA2_VP_SENSOR_FLAGS_407:
- case CPIA2_VP_SENSOR_FLAGS_409:
- case CPIA2_VP_SENSOR_FLAGS_410:
- if ((width > STV_IMAGE_QCIF_COLS)
- || (height > STV_IMAGE_QCIF_ROWS)) {
- user_mode = CPIA2_VP_USER_MODE_CIF;
- } else {
- user_mode = CPIA2_VP_USER_MODE_QCIFDS;
- }
- frame_rate = CPIA2_VP_FRAMERATE_30;
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- if ((width > STV_IMAGE_CIF_COLS)
- || (height > STV_IMAGE_CIF_ROWS)) {
- user_mode = CPIA2_VP_USER_MODE_VGA;
- } else {
- user_mode = CPIA2_VP_USER_MODE_QVGADS;
- }
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- frame_rate = CPIA2_VP_FRAMERATE_15;
- else
- frame_rate = CPIA2_VP_FRAMERATE_30;
- break;
- default:
- LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
- cam->params.version.sensor_flags);
- return -EINVAL;
- }
-
- DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
- cam->params.version.sensor_flags, user_mode, frame_rate);
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
- user_mode);
- if(cam->params.vp_params.frame_rate > 0 &&
- frame_rate > cam->params.vp_params.frame_rate)
- frame_rate = cam->params.vp_params.frame_rate;
-
- cpia2_set_fps(cam, frame_rate);
-
-// if (cam->params.pnp_id.device_type == DEVICE_STV_676)
-// cpia2_do_command(cam,
-// CPIA2_CMD_SET_VP_SYSTEM_CTRL,
-// TRANSFER_WRITE,
-// CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
-// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_match_video_size
- *
- * return the best match, where 'best' is as always
- * the largest that is not bigger than what is requested.
- *****************************************************************************/
-int cpia2_match_video_size(int width, int height)
-{
- if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
- return VIDEOSIZE_VGA;
-
- if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
- return VIDEOSIZE_CIF;
-
- if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
- return VIDEOSIZE_QVGA;
-
- if (width >= 288 && height >= 216)
- return VIDEOSIZE_288_216;
-
- if (width >= 256 && height >= 192)
- return VIDEOSIZE_256_192;
-
- if (width >= 224 && height >= 168)
- return VIDEOSIZE_224_168;
-
- if (width >= 192 && height >= 144)
- return VIDEOSIZE_192_144;
-
- if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
- return VIDEOSIZE_QCIF;
-
- return -1;
-}
-
-/******************************************************************************
- *
- * SetVideoSize
- *
- *****************************************************************************/
-static int set_vw_size(struct camera_data *cam, int size)
-{
- int retval = 0;
-
- cam->params.vp_params.video_size = size;
-
- switch (size) {
- case VIDEOSIZE_VGA:
- DBG("Setting size to VGA\n");
- cam->params.roi.width = STV_IMAGE_VGA_COLS;
- cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- cam->width = STV_IMAGE_VGA_COLS;
- cam->height = STV_IMAGE_VGA_ROWS;
- break;
- case VIDEOSIZE_CIF:
- DBG("Setting size to CIF\n");
- cam->params.roi.width = STV_IMAGE_CIF_COLS;
- cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- cam->width = STV_IMAGE_CIF_COLS;
- cam->height = STV_IMAGE_CIF_ROWS;
- break;
- case VIDEOSIZE_QVGA:
- DBG("Setting size to QVGA\n");
- cam->params.roi.width = STV_IMAGE_QVGA_COLS;
- cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
- cam->width = STV_IMAGE_QVGA_COLS;
- cam->height = STV_IMAGE_QVGA_ROWS;
- break;
- case VIDEOSIZE_288_216:
- cam->params.roi.width = 288;
- cam->params.roi.height = 216;
- cam->width = 288;
- cam->height = 216;
- break;
- case VIDEOSIZE_256_192:
- cam->width = 256;
- cam->height = 192;
- cam->params.roi.width = 256;
- cam->params.roi.height = 192;
- break;
- case VIDEOSIZE_224_168:
- cam->width = 224;
- cam->height = 168;
- cam->params.roi.width = 224;
- cam->params.roi.height = 168;
- break;
- case VIDEOSIZE_192_144:
- cam->width = 192;
- cam->height = 144;
- cam->params.roi.width = 192;
- cam->params.roi.height = 144;
- break;
- case VIDEOSIZE_QCIF:
- DBG("Setting size to QCIF\n");
- cam->params.roi.width = STV_IMAGE_QCIF_COLS;
- cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
- cam->width = STV_IMAGE_QCIF_COLS;
- cam->height = STV_IMAGE_QCIF_ROWS;
- break;
- default:
- retval = -EINVAL;
- }
- return retval;
-}
-
-/******************************************************************************
- *
- * configure_sensor
- *
- *****************************************************************************/
-static int configure_sensor(struct camera_data *cam,
- int req_width, int req_height)
-{
- int retval;
-
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- case CPIA2_VP_SENSOR_FLAGS_407:
- case CPIA2_VP_SENSOR_FLAGS_409:
- case CPIA2_VP_SENSOR_FLAGS_410:
- retval = config_sensor_410(cam, req_width, req_height);
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- retval = config_sensor_500(cam, req_width, req_height);
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-/******************************************************************************
- *
- * config_sensor_410
- *
- *****************************************************************************/
-static int config_sensor_410(struct camera_data *cam,
- int req_width, int req_height)
-{
- struct cpia2_command cmd;
- int i = 0;
- int image_size;
- int image_type;
- int width = req_width;
- int height = req_height;
-
- /***
- * Make sure size doesn't exceed CIF.
- ***/
- if (width > STV_IMAGE_CIF_COLS)
- width = STV_IMAGE_CIF_COLS;
- if (height > STV_IMAGE_CIF_ROWS)
- height = STV_IMAGE_CIF_ROWS;
-
- image_size = cpia2_match_video_size(width, height);
-
- DBG("Config 410: width = %d, height = %d\n", width, height);
- DBG("Image size returned is %d\n", image_size);
- if (image_size >= 0) {
- set_vw_size(cam, image_size);
- width = cam->params.roi.width;
- height = cam->params.roi.height;
-
- DBG("After set_vw_size(), width = %d, height = %d\n",
- width, height);
- if (width <= 176 && height <= 144) {
- DBG("image type = VIDEOSIZE_QCIF\n");
- image_type = VIDEOSIZE_QCIF;
- }
- else if (width <= 320 && height <= 240) {
- DBG("image type = VIDEOSIZE_QVGA\n");
- image_type = VIDEOSIZE_QVGA;
- }
- else {
- DBG("image type = VIDEOSIZE_CIF\n");
- image_type = VIDEOSIZE_CIF;
- }
- } else {
- ERR("ConfigSensor410 failed\n");
- return -EINVAL;
- }
-
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
-
- /* VC Format */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
- if (image_type == VIDEOSIZE_CIF) {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
- CPIA2_VC_VC_FORMAT_SHORTLINE);
- } else {
- cmd.buffer.registers[i++].value =
- (u8) CPIA2_VC_VC_FORMAT_UFIRST;
- }
-
- /* VC Clocks */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
- if (image_type == VIDEOSIZE_QCIF) {
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.buffer.registers[i++].value=
- (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_672_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- DBG("VC_Clocks (0xc4) should be B\n");
- }
- else {
- cmd.buffer.registers[i++].value=
- (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- }
- } else {
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_CLOCKS_LOGDIV0);
- }
- else {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_676_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV0);
- }
- }
- DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
-
- /* Input reqWidth from VC */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (STV_IMAGE_QCIF_COLS / 4);
- else
- cmd.buffer.registers[i++].value =
- (u8) (STV_IMAGE_CIF_COLS / 4);
-
- /* Timings */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 208;
- else
- cmd.buffer.registers[i++].value = (u8) 160;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 160;
- else
- cmd.buffer.registers[i++].value = (u8) 64;
-
- /* Output Image Size */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
- cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
- cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
-
- /* Cropping */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
- else
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
- else
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
-
- /* Scaling registers (defaults) */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
- cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
- cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
-
- cmd.reg_count = i;
-
- cpia2_send_command(cam, &cmd);
-
- return i;
-}
-
-
-/******************************************************************************
- *
- * config_sensor_500(cam)
- *
- *****************************************************************************/
-static int config_sensor_500(struct camera_data *cam,
- int req_width, int req_height)
-{
- struct cpia2_command cmd;
- int i = 0;
- int image_size = VIDEOSIZE_CIF;
- int image_type = VIDEOSIZE_VGA;
- int width = req_width;
- int height = req_height;
- unsigned int device = cam->params.pnp_id.device_type;
-
- image_size = cpia2_match_video_size(width, height);
-
- if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
- image_type = VIDEOSIZE_VGA;
- else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
- image_type = VIDEOSIZE_CIF;
- else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
- image_type = VIDEOSIZE_QVGA;
- else
- image_type = VIDEOSIZE_QCIF;
-
- if (image_size >= 0) {
- set_vw_size(cam, image_size);
- width = cam->params.roi.width;
- height = cam->params.roi.height;
- } else {
- ERR("ConfigSensor500 failed\n");
- return -EINVAL;
- }
-
- DBG("image_size = %d, width = %d, height = %d, type = %d\n",
- image_size, width, height, image_type);
-
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
- i = 0;
-
- /* VC Format */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
- cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
- i++;
-
- /* VC Clocks */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
- if (device == DEVICE_STV_672) {
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
- else
- cmd.buffer.registers[i].value =
- (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV3);
- } else {
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
- else
- cmd.buffer.registers[i].value =
- (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- }
- i++;
-
- DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
-
- /* Input width from VP */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8) (STV_IMAGE_VGA_COLS / 4);
- else
- cmd.buffer.registers[i].value =
- (u8) (STV_IMAGE_QVGA_COLS / 4);
- i++;
- DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
-
- /* Timings */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 2;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 250;
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value = (u8) 125;
- else
- cmd.buffer.registers[i++].value = (u8) 160;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 2;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 12;
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value = (u8) 64;
- else
- cmd.buffer.registers[i++].value = (u8) 6;
-
- /* Output Image Size */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4;
- else
- cmd.buffer.registers[i++].value = width / 4;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4;
- else
- cmd.buffer.registers[i++].value = height / 4;
-
- /* Cropping */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
- else if (image_type == VIDEOSIZE_CIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
- else /*if (image_type == VIDEOSIZE_QCIF)*/
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
- else if (image_type == VIDEOSIZE_CIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
- else /*if (image_type == VIDEOSIZE_QCIF)*/
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
-
- /* Scaling registers (defaults) */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 36;
- else
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 32;
- else
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 26;
- else
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 21;
- else
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */
- else
- cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */
- else
- cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
-
- cmd.reg_count = i;
-
- cpia2_send_command(cam, &cmd);
-
- return i;
-}
-
-
-/******************************************************************************
- *
- * setallproperties
- *
- * This sets all user changeable properties to the values in cam->params.
- *****************************************************************************/
-static int set_all_properties(struct camera_data *cam)
-{
- /**
- * Don't set target_kb here, it will be set later.
- * framerate and user_mode were already set (set_default_user_mode).
- **/
-
- cpia2_usb_change_streaming_alternate(cam,
- cam->params.camera_state.stream_mode);
-
- cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
- cam->params.vp_params.gpio_data);
-
- v4l2_ctrl_handler_setup(&cam->hdl);
-
- wake_system(cam);
-
- set_lowlight_boost(cam);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_save_camera_state
- *
- *****************************************************************************/
-void cpia2_save_camera_state(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
- 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
- /* Don't get framerate or target_kb. Trust the values we already have */
-}
-
-
-/******************************************************************************
- *
- * cpia2_set_flicker_mode
- *
- *****************************************************************************/
-int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
-{
- unsigned char cam_reg;
- int err = 0;
-
- if(cam->params.pnp_id.device_type != DEVICE_STV_672)
- return -EINVAL;
-
- /* Set the appropriate bits in FLICKER_MODES, preserving the rest */
- if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
- TRANSFER_READ, 0)))
- return err;
- cam_reg = cam->params.flicker_control.cam_register;
-
- switch(mode) {
- case NEVER_FLICKER:
- cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- case FLICKER_60:
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- case FLICKER_50:
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- default:
- return -EINVAL;
- }
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
- TRANSFER_WRITE, cam_reg)))
- return err;
-
- /* Set the appropriate bits in EXP_MODES, preserving the rest */
- if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
- TRANSFER_READ, 0)))
- return err;
- cam_reg = cam->params.vp_params.exposure_modes;
-
- if (mode == NEVER_FLICKER) {
- cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
- } else {
- cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
- }
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
- TRANSFER_WRITE, cam_reg)))
- return err;
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
- TRANSFER_WRITE, 1)))
- return err;
-
- switch(mode) {
- case NEVER_FLICKER:
- case FLICKER_60:
- case FLICKER_50:
- cam->params.flicker_control.flicker_mode_req = mode;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-/******************************************************************************
- *
- * cpia2_set_property_flip
- *
- *****************************************************************************/
-void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
-{
- unsigned char cam_reg;
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cam_reg = cam->params.vp_params.user_effects;
-
- if (prop_val)
- {
- cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
- }
- else
- {
- cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
- }
- cam->params.vp_params.user_effects = cam_reg;
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam_reg);
-}
-
-/******************************************************************************
- *
- * cpia2_set_property_mirror
- *
- *****************************************************************************/
-void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
-{
- unsigned char cam_reg;
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cam_reg = cam->params.vp_params.user_effects;
-
- if (prop_val)
- {
- cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
- }
- else
- {
- cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
- }
- cam->params.vp_params.user_effects = cam_reg;
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam_reg);
-}
-
-/******************************************************************************
- *
- * cpia2_set_gpio
- *
- *****************************************************************************/
-int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
-{
- int ret;
-
- /* Set the microport direction (register 0x90, should be defined
- * already) to 1 (user output), and set the microport data (0x91) to
- * the value in the ioctl argument.
- */
-
- ret = cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- CPIA2_VC_MP_DIR_OUTPUT,
- 255);
- if (ret < 0)
- return ret;
- cam->params.vp_params.gpio_direction = 255;
-
- ret = cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DATA,
- CPIA2_VC_MP_DIR_OUTPUT,
- setting);
- if (ret < 0)
- return ret;
- cam->params.vp_params.gpio_data = setting;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_set_fps
- *
- *****************************************************************************/
-int cpia2_set_fps(struct camera_data *cam, int framerate)
-{
- int retval;
-
- switch(framerate) {
- case CPIA2_VP_FRAMERATE_30:
- case CPIA2_VP_FRAMERATE_25:
- if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags ==
- CPIA2_VP_SENSOR_FLAGS_500) {
- return -EINVAL;
- }
- /* Fall through */
- case CPIA2_VP_FRAMERATE_15:
- case CPIA2_VP_FRAMERATE_12_5:
- case CPIA2_VP_FRAMERATE_7_5:
- case CPIA2_VP_FRAMERATE_6_25:
- break;
- default:
- return -EINVAL;
- }
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- framerate == CPIA2_VP_FRAMERATE_15)
- framerate = 0; /* Work around bug in VP4 */
-
- retval = cpia2_do_command(cam,
- CPIA2_CMD_FRAMERATE_REQ,
- TRANSFER_WRITE,
- framerate);
-
- if(retval == 0)
- cam->params.vp_params.frame_rate = framerate;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_set_brightness
- *
- *****************************************************************************/
-void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
-{
- /***
- * Don't let the register be set to zero - bug in VP4 - flash of full
- * brightness
- ***/
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
- value++;
- DBG("Setting brightness to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
-}
-
-/******************************************************************************
- *
- * cpia2_set_contrast
- *
- *****************************************************************************/
-void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
-{
- DBG("Setting contrast to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
-}
-
-/******************************************************************************
- *
- * cpia2_set_saturation
- *
- *****************************************************************************/
-void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
-{
- DBG("Setting saturation to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
-}
-
-/******************************************************************************
- *
- * wake_system
- *
- *****************************************************************************/
-static void wake_system(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
-}
-
-/******************************************************************************
- *
- * set_lowlight_boost
- *
- * Valid for STV500 sensor only
- *****************************************************************************/
-static void set_lowlight_boost(struct camera_data *cam)
-{
- struct cpia2_command cmd;
-
- if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
- cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
- return;
-
- cmd.direction = TRANSFER_WRITE;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 3;
- cmd.start = CPIA2_VP_RAM_ADDR_H;
-
- cmd.buffer.block_data[0] = 0; /* High byte of address to write to */
- cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */
- cmd.buffer.block_data[2] = 0; /* High byte of data to write */
-
- cpia2_send_command(cam, &cmd);
-
- if (cam->params.vp_params.lowlight_boost) {
- cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */
- } else {
- cmd.buffer.block_data[0] = 0x06;
- }
- cmd.start = CPIA2_VP_RAM_DATA;
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
-
- /* Rehash the VP4 values */
- cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
-}
-
-/******************************************************************************
- *
- * cpia2_set_format
- *
- * Assumes that new size is already set in param struct.
- *****************************************************************************/
-void cpia2_set_format(struct camera_data *cam)
-{
- cam->flush = true;
-
- cpia2_usb_stream_pause(cam);
-
- /* reset camera to new size */
- cpia2_set_low_power(cam);
- cpia2_reset_camera(cam);
- cam->flush = false;
-
- cpia2_dbg_dump_registers(cam);
-
- cpia2_usb_stream_resume(cam);
-}
-
-/******************************************************************************
- *
- * cpia2_dbg_dump_registers
- *
- *****************************************************************************/
-void cpia2_dbg_dump_registers(struct camera_data *cam)
-{
-#ifdef _CPIA2_DEBUG_
- struct cpia2_command cmd;
-
- if (!(debugs_on & DEBUG_DUMP_REGS))
- return;
-
- cmd.direction = TRANSFER_READ;
-
- /* Start with bank 0 (SYSTEM) */
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 3;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "System Device Hi = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "System Device Lo = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "System_system control = 0x%X\n",
- cmd.buffer.block_data[2]);
-
- /* Bank 1 (VC) */
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 4;
- cmd.start = 0x80;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "ASIC_ID = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "ASIC_REV = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "PW_CONTRL = 0x%X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "WAKEUP = 0x%X\n",
- cmd.buffer.block_data[3]);
-
- cmd.start = 0xA0; /* ST_CTRL */
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "Stream ctrl = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xA4; /* Stream status */
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "Stream status = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xA8; /* USB status */
- cmd.reg_count = 3;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "USB_CTRL = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "USB_STRM = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "USB_STATUS = 0x%X\n",
- cmd.buffer.block_data[2]);
-
- cmd.start = 0xAF; /* USB settings */
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "USB settings = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xC0; /* VC stuff */
- cmd.reg_count = 26;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VC Control = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VC Format = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VC Clocks = 0x%0X\n",
- cmd.buffer.block_data[4]);
- printk(KERN_DEBUG "VC IHSize = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n",
- cmd.buffer.block_data[8]);
- printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n",
- cmd.buffer.block_data[9]);
- printk(KERN_DEBUG "VC OHSize = 0x%0X\n",
- cmd.buffer.block_data[10]);
- printk(KERN_DEBUG "VC OVSize = 0x%0X\n",
- cmd.buffer.block_data[11]);
- printk(KERN_DEBUG "VC HCrop = 0x%0X\n",
- cmd.buffer.block_data[12]);
- printk(KERN_DEBUG "VC VCrop = 0x%0X\n",
- cmd.buffer.block_data[13]);
- printk(KERN_DEBUG "VC HPhase = 0x%0X\n",
- cmd.buffer.block_data[14]);
- printk(KERN_DEBUG "VC VPhase = 0x%0X\n",
- cmd.buffer.block_data[15]);
- printk(KERN_DEBUG "VC HIspan = 0x%0X\n",
- cmd.buffer.block_data[16]);
- printk(KERN_DEBUG "VC VIspan = 0x%0X\n",
- cmd.buffer.block_data[17]);
- printk(KERN_DEBUG "VC HiCrop = 0x%0X\n",
- cmd.buffer.block_data[18]);
- printk(KERN_DEBUG "VC ViCrop = 0x%0X\n",
- cmd.buffer.block_data[19]);
- printk(KERN_DEBUG "VC HiFract = 0x%0X\n",
- cmd.buffer.block_data[20]);
- printk(KERN_DEBUG "VC ViFract = 0x%0X\n",
- cmd.buffer.block_data[21]);
- printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n",
- cmd.buffer.block_data[22]);
- printk(KERN_DEBUG "VC Creep Per = 0x%0X\n",
- cmd.buffer.block_data[23]);
- printk(KERN_DEBUG "VC User Sq. = 0x%0X\n",
- cmd.buffer.block_data[24]);
- printk(KERN_DEBUG "VC Target KB = 0x%0X\n",
- cmd.buffer.block_data[25]);
-
- /*** VP ***/
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 14;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
-
- printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Sys State = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n",
- cmd.buffer.block_data[8]);
- printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n",
- cmd.buffer.block_data[9]);
- printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
- cmd.buffer.block_data[10]);
- printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
- cmd.buffer.block_data[11]);
- printk(KERN_DEBUG "VP RAM Data = 0x%0X\n",
- cmd.buffer.block_data[12]);
- printk(KERN_DEBUG "Do Call = 0x%0X\n",
- cmd.buffer.block_data[13]);
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.reg_count = 9;
- cmd.start = 0x0E;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
- cmd.buffer.block_data[4]);
- printk(KERN_DEBUG "VP White Bal = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP WB thresh = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
- cmd.buffer.block_data[8]);
-
- cmd.reg_count = 1;
- cmd.start = 0x1B;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
- cmd.buffer.block_data[0]);
- } else {
- cmd.reg_count = 8 ;
- cmd.start = 0x0E;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
- cmd.buffer.block_data[7]);
-
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
- cmd.buffer.block_data[0]);
-
- cmd.reg_count = 4;
- cmd.start = 0x3A;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n",
- cmd.buffer.block_data[3]);
- }
-#endif
-}
-
-/******************************************************************************
- *
- * reset_camera_struct
- *
- * Sets all values to the defaults
- *****************************************************************************/
-static void reset_camera_struct(struct camera_data *cam)
-{
- /***
- * The following parameter values are the defaults from the register map.
- ***/
- cam->params.vp_params.lowlight_boost = 0;
-
- /* FlickerModes */
- cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
-
- /* jpeg params */
- cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
- cam->params.compression.creep_period = 2;
- cam->params.compression.user_squeeze = 20;
- cam->params.compression.inhibit_htables = false;
-
- /* gpio params */
- cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */
- cam->params.vp_params.gpio_data = 0;
-
- /* Target kb params */
- cam->params.vc_params.quality = 100;
-
- /***
- * Set Sensor FPS as fast as possible.
- ***/
- if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
- if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
- else
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
- } else {
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
- }
-
- /***
- * Set default video mode as large as possible :
- * for vga sensor set to vga, for cif sensor set to CIF.
- ***/
- if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
- cam->sensor_type = CPIA2_SENSOR_500;
- cam->video_size = VIDEOSIZE_VGA;
- cam->params.roi.width = STV_IMAGE_VGA_COLS;
- cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- } else {
- cam->sensor_type = CPIA2_SENSOR_410;
- cam->video_size = VIDEOSIZE_CIF;
- cam->params.roi.width = STV_IMAGE_CIF_COLS;
- cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- }
-
- cam->width = cam->params.roi.width;
- cam->height = cam->params.roi.height;
-}
-
-/******************************************************************************
- *
- * cpia2_init_camera_struct
- *
- * Initializes camera struct, does not call reset to fill in defaults.
- *****************************************************************************/
-struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
-{
- struct camera_data *cam;
-
- cam = kzalloc(sizeof(*cam), GFP_KERNEL);
-
- if (!cam) {
- ERR("couldn't kmalloc cpia2 struct\n");
- return NULL;
- }
-
- cam->v4l2_dev.release = cpia2_camera_release;
- if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
- v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
- kfree(cam);
- return NULL;
- }
-
- mutex_init(&cam->v4l2_lock);
- init_waitqueue_head(&cam->wq_stream);
-
- return cam;
-}
-
-/******************************************************************************
- *
- * cpia2_init_camera
- *
- * Initializes camera.
- *****************************************************************************/
-int cpia2_init_camera(struct camera_data *cam)
-{
- DBG("Start\n");
-
- cam->mmapped = false;
-
- /* Get sensor and asic types before reset. */
- cpia2_set_high_power(cam);
- cpia2_get_version_info(cam);
- if (cam->params.version.asic_id != CPIA2_ASIC_672) {
- ERR("Device IO error (asicID has incorrect value of 0x%X\n",
- cam->params.version.asic_id);
- return -ENODEV;
- }
-
- /* Set GPIO direction and data to a safe state. */
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- TRANSFER_WRITE, 0);
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
- TRANSFER_WRITE, 0);
-
- /* resetting struct requires version info for sensor and asic types */
- reset_camera_struct(cam);
-
- cpia2_set_low_power(cam);
-
- DBG("End\n");
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_allocate_buffers
- *
- *****************************************************************************/
-int cpia2_allocate_buffers(struct camera_data *cam)
-{
- int i;
-
- if(!cam->buffers) {
- u32 size = cam->num_frames*sizeof(struct framebuf);
- cam->buffers = kmalloc(size, GFP_KERNEL);
- if(!cam->buffers) {
- ERR("couldn't kmalloc frame buffer structures\n");
- return -ENOMEM;
- }
- }
-
- if(!cam->frame_buffer) {
- cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
- if (!cam->frame_buffer) {
- ERR("couldn't vmalloc frame buffer data area\n");
- kfree(cam->buffers);
- cam->buffers = NULL;
- return -ENOMEM;
- }
- }
-
- for(i=0; i<cam->num_frames-1; ++i) {
- cam->buffers[i].next = &cam->buffers[i+1];
- cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
- cam->buffers[i].status = FRAME_EMPTY;
- cam->buffers[i].length = 0;
- cam->buffers[i].max_length = 0;
- cam->buffers[i].num = i;
- }
- cam->buffers[i].next = cam->buffers;
- cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
- cam->buffers[i].status = FRAME_EMPTY;
- cam->buffers[i].length = 0;
- cam->buffers[i].max_length = 0;
- cam->buffers[i].num = i;
- cam->curbuff = cam->buffers;
- cam->workbuff = cam->curbuff->next;
- DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
- cam->workbuff);
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_free_buffers
- *
- *****************************************************************************/
-void cpia2_free_buffers(struct camera_data *cam)
-{
- if(cam->buffers) {
- kfree(cam->buffers);
- cam->buffers = NULL;
- }
- if(cam->frame_buffer) {
- rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
- cam->frame_buffer = NULL;
- }
-}
-
-/******************************************************************************
- *
- * cpia2_read
- *
- *****************************************************************************/
-long cpia2_read(struct camera_data *cam,
- char __user *buf, unsigned long count, int noblock)
-{
- struct framebuf *frame;
-
- if (!count)
- return 0;
-
- if (!buf) {
- ERR("%s: buffer NULL\n",__func__);
- return -EINVAL;
- }
-
- if (!cam) {
- ERR("%s: Internal error, camera_data NULL!\n",__func__);
- return -EINVAL;
- }
-
- if (!cam->streaming) {
- /* Start streaming */
- cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- }
-
- /* Copy cam->curbuff in case it changes while we're processing */
- frame = cam->curbuff;
- if (noblock && frame->status != FRAME_READY) {
- return -EAGAIN;
- }
-
- if (frame->status != FRAME_READY) {
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !video_is_registered(&cam->vdev) ||
- (frame = cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return 0;
- }
-
- /* copy data to user space */
- if (frame->length > count)
- return -EFAULT;
- if (copy_to_user(buf, frame->data, frame->length))
- return -EFAULT;
-
- count = frame->length;
-
- frame->status = FRAME_EMPTY;
-
- return count;
-}
-
-/******************************************************************************
- *
- * cpia2_poll
- *
- *****************************************************************************/
-unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
- poll_table *wait)
-{
- unsigned int status = v4l2_ctrl_poll(filp, wait);
-
- if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
- !cam->streaming) {
- /* Start streaming */
- cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- }
-
- poll_wait(filp, &cam->wq_stream, wait);
-
- if (cam->curbuff->status == FRAME_READY)
- status |= POLLIN | POLLRDNORM;
-
- return status;
-}
-
-/******************************************************************************
- *
- * cpia2_remap_buffer
- *
- *****************************************************************************/
-int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
-{
- const char *adr = (const char *)vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long start = (unsigned long) adr;
- unsigned long page, pos;
-
- DBG("mmap offset:%ld size:%ld\n", start_offset, size);
-
- if (!video_is_registered(&cam->vdev))
- return -ENODEV;
-
- if (size > cam->frame_size*cam->num_frames ||
- (start_offset % cam->frame_size) != 0 ||
- (start_offset+size > cam->frame_size*cam->num_frames))
- return -EINVAL;
-
- pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- cam->mmapped = true;
- return 0;
-}
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
deleted file mode 100644
index a62a7b739991..000000000000
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ /dev/null
@@ -1,1250 +0,0 @@
-/****************************************************************************
- *
- * Filename: cpia2_v4l.c
- *
- * Copyright 2001, STMicrolectronics, Inc.
- * Contact: steve.miller@st.com
- * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
- *
- * Description:
- * This is a USB driver for CPia2 based video cameras.
- * The infrastructure of this driver is based on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- * 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.
- *
- * Stripped of 2.4 stuff ready for main kernel submit by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- ****************************************************************************/
-
-#define CPIA_VERSION "3.0.1"
-
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/videodev2.h>
-#include <linux/stringify.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-
-#include "cpia2.h"
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
-
-static int buffer_size = 68 * 1024;
-module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
-
-static int num_buffers = 3;
-module_param(num_buffers, int, 0);
-MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
- __stringify(VIDEO_MAX_FRAME) ", default 3)");
-
-static int alternate = DEFAULT_ALT;
-module_param(alternate, int, 0);
-MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
- __stringify(USBIF_ISO_6) ", default "
- __stringify(DEFAULT_ALT) ")");
-
-static int flicker_mode;
-module_param(flicker_mode, int, 0);
-MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
- __stringify(60) ", default 0)");
-
-MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
-MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
-MODULE_SUPPORTED_DEVICE("video");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(CPIA_VERSION);
-
-#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
-
-/******************************************************************************
- *
- * cpia2_open
- *
- *****************************************************************************/
-static int cpia2_open(struct file *file)
-{
- struct camera_data *cam = video_drvdata(file);
- int retval = v4l2_fh_open(file);
-
- if (retval)
- return retval;
-
- if (v4l2_fh_is_singular_file(file)) {
- if (cpia2_allocate_buffers(cam)) {
- v4l2_fh_release(file);
- return -ENOMEM;
- }
-
- /* reset the camera */
- if (cpia2_reset_camera(cam) < 0) {
- v4l2_fh_release(file);
- return -EIO;
- }
-
- cam->APP_len = 0;
- cam->COM_len = 0;
- }
-
- cpia2_dbg_dump_registers(cam);
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_close
- *
- *****************************************************************************/
-static int cpia2_close(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct camera_data *cam = video_get_drvdata(dev);
-
- if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
- cpia2_usb_stream_stop(cam);
-
- /* save camera state for later open */
- cpia2_save_camera_state(cam);
-
- cpia2_set_low_power(cam);
- cpia2_free_buffers(cam);
- }
-
- if (cam->stream_fh == file->private_data) {
- cam->stream_fh = NULL;
- cam->mmapped = 0;
- }
- return v4l2_fh_release(file);
-}
-
-/******************************************************************************
- *
- * cpia2_v4l_read
- *
- *****************************************************************************/
-static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
- loff_t *off)
-{
- struct camera_data *cam = video_drvdata(file);
- int noblock = file->f_flags&O_NONBLOCK;
-
- if(!cam)
- return -EINVAL;
-
- return cpia2_read(cam, buf, count, noblock);
-}
-
-
-/******************************************************************************
- *
- * cpia2_v4l_poll
- *
- *****************************************************************************/
-static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
-{
- struct camera_data *cam = video_drvdata(filp);
-
- return cpia2_poll(cam, filp, wait);
-}
-
-
-static int sync(struct camera_data *cam, int frame_nr)
-{
- struct framebuf *frame = &cam->buffers[frame_nr];
-
- while (1) {
- if (frame->status == FRAME_READY)
- return 0;
-
- if (!cam->streaming) {
- frame->status = FRAME_READY;
- frame->length = 0;
- return 0;
- }
-
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !cam->streaming ||
- frame->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return -ENOTTY;
- }
-}
-
-/******************************************************************************
- *
- * ioctl_querycap
- *
- * V4L2 device capabilities
- *
- *****************************************************************************/
-
-static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc)
-{
- struct camera_data *cam = video_drvdata(file);
-
- strcpy(vc->driver, "cpia2");
-
- if (cam->params.pnp_id.product == 0x151)
- strcpy(vc->card, "QX5 Microscope");
- else
- strcpy(vc->card, "CPiA2 Camera");
- switch (cam->params.pnp_id.device_type) {
- case DEVICE_STV_672:
- strcat(vc->card, " (672/");
- break;
- case DEVICE_STV_676:
- strcat(vc->card, " (676/");
- break;
- default:
- strcat(vc->card, " (XXX/");
- break;
- }
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- strcat(vc->card, "404)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_407:
- strcat(vc->card, "407)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_409:
- strcat(vc->card, "409)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_410:
- strcat(vc->card, "410)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- strcat(vc->card, "500)");
- break;
- default:
- strcat(vc->card, "XXX)");
- break;
- }
-
- if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
- memset(vc->bus_info,0, sizeof(vc->bus_info));
-
- vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- vc->capabilities = vc->device_caps |
- V4L2_CAP_DEVICE_CAPS;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_input
- *
- * V4L2 input get/set/enumerate
- *
- *****************************************************************************/
-
-static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
-{
- if (i->index)
- return -EINVAL;
- strcpy(i->name, "Camera");
- i->type = V4L2_INPUT_TYPE_CAMERA;
- return 0;
-}
-
-static int cpia2_g_input(struct file *file, void *fh, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-/******************************************************************************
- *
- * ioctl_enum_fmt
- *
- * V4L2 format enumerate
- *
- *****************************************************************************/
-
-static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- int index = f->index;
-
- if (index < 0 || index > 1)
- return -EINVAL;
-
- memset(f, 0, sizeof(*f));
- f->index = index;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = V4L2_FMT_FLAG_COMPRESSED;
- switch(index) {
- case 0:
- strcpy(f->description, "MJPEG");
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- break;
- case 1:
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_try_fmt
- *
- * V4L2 format try
- *
- *****************************************************************************/
-
-static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = cam->frame_size;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- f->fmt.pix.priv = 0;
-
- switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
- case VIDEOSIZE_VGA:
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- break;
- case VIDEOSIZE_CIF:
- f->fmt.pix.width = 352;
- f->fmt.pix.height = 288;
- break;
- case VIDEOSIZE_QVGA:
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- break;
- case VIDEOSIZE_288_216:
- f->fmt.pix.width = 288;
- f->fmt.pix.height = 216;
- break;
- case VIDEOSIZE_256_192:
- f->fmt.pix.width = 256;
- f->fmt.pix.height = 192;
- break;
- case VIDEOSIZE_224_168:
- f->fmt.pix.width = 224;
- f->fmt.pix.height = 168;
- break;
- case VIDEOSIZE_192_144:
- f->fmt.pix.width = 192;
- f->fmt.pix.height = 144;
- break;
- case VIDEOSIZE_QCIF:
- default:
- f->fmt.pix.width = 176;
- f->fmt.pix.height = 144;
- break;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_set_fmt
- *
- * V4L2 format set
- *
- *****************************************************************************/
-
-static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
- int err, frame;
-
- err = cpia2_try_fmt_vid_cap(file, _fh, f);
- if(err != 0)
- return err;
-
- cam->pixelformat = f->fmt.pix.pixelformat;
-
- /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
- * the missing Huffman table properly. */
- cam->params.compression.inhibit_htables = 0;
- /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- DBG("Requested width = %d, height = %d\n",
- f->fmt.pix.width, f->fmt.pix.height);
- if (f->fmt.pix.width != cam->width ||
- f->fmt.pix.height != cam->height) {
- cam->width = f->fmt.pix.width;
- cam->height = f->fmt.pix.height;
- cam->params.roi.width = f->fmt.pix.width;
- cam->params.roi.height = f->fmt.pix.height;
- cpia2_set_format(cam);
- }
-
- for (frame = 0; frame < cam->num_frames; ++frame) {
- if (cam->buffers[frame].status == FRAME_READING)
- if ((err = sync(cam, frame)) < 0)
- return err;
-
- cam->buffers[frame].status = FRAME_EMPTY;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_get_fmt
- *
- * V4L2 format get
- *
- *****************************************************************************/
-
-static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
-
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
- f->fmt.pix.pixelformat = cam->pixelformat;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = cam->frame_size;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- f->fmt.pix.priv = 0;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_cropcap
- *
- * V4L2 query cropping capabilities
- * NOTE: cropping is currently disabled
- *
- *****************************************************************************/
-
-static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- c->bounds.left = 0;
- c->bounds.top = 0;
- c->bounds.width = cam->width;
- c->bounds.height = cam->height;
- c->defrect.left = 0;
- c->defrect.top = 0;
- c->defrect.width = cam->width;
- c->defrect.height = cam->height;
- c->pixelaspect.numerator = 1;
- c->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-struct framerate_info {
- int value;
- struct v4l2_fract period;
-};
-
-static const struct framerate_info framerate_controls[] = {
- { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
- { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } },
- { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
- { CPIA2_VP_FRAMERATE_15, { 1, 15 } },
- { CPIA2_VP_FRAMERATE_25, { 1, 25 } },
- { CPIA2_VP_FRAMERATE_30, { 1, 30 } },
-};
-
-static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
-{
- struct camera_data *cam = video_drvdata(file);
- struct v4l2_captureparm *cap = &p->parm.capture;
- int i;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cap->capability = V4L2_CAP_TIMEPERFRAME;
- cap->readbuffers = cam->num_frames;
- for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
- if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
- cap->timeperframe = framerate_controls[i].period;
- break;
- }
- return 0;
-}
-
-static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
-{
- struct camera_data *cam = video_drvdata(file);
- struct v4l2_captureparm *cap = &p->parm.capture;
- struct v4l2_fract tpf = cap->timeperframe;
- int max = ARRAY_SIZE(framerate_controls) - 1;
- int ret;
- int i;
-
- ret = cpia2_g_parm(file, fh, p);
- if (ret || !tpf.denominator || !tpf.numerator)
- return ret;
-
- /* Maximum 15 fps for this model */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- max -= 2;
- for (i = 0; i <= max; i++) {
- struct v4l2_fract f1 = tpf;
- struct v4l2_fract f2 = framerate_controls[i].period;
-
- f1.numerator *= f2.denominator;
- f2.numerator *= f1.denominator;
- if (f1.numerator >= f2.numerator)
- break;
- }
- if (i > max)
- i = max;
- cap->timeperframe = framerate_controls[i].period;
- return cpia2_set_fps(cam, framerate_controls[i].value);
-}
-
-static const struct {
- u32 width;
- u32 height;
-} cpia2_framesizes[] = {
- { 640, 480 },
- { 352, 288 },
- { 320, 240 },
- { 288, 216 },
- { 256, 192 },
- { 224, 168 },
- { 192, 144 },
- { 176, 144 },
-};
-
-static int cpia2_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
-{
-
- if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
- fsize->pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
- return -EINVAL;
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = cpia2_framesizes[fsize->index].width;
- fsize->discrete.height = cpia2_framesizes[fsize->index].height;
-
- return 0;
-}
-
-static int cpia2_enum_frameintervals(struct file *file, void *fh,
- struct v4l2_frmivalenum *fival)
-{
- struct camera_data *cam = video_drvdata(file);
- int max = ARRAY_SIZE(framerate_controls) - 1;
- int i;
-
- if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
- fival->pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- /* Maximum 15 fps for this model */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- max -= 2;
- if (fival->index > max)
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
- if (fival->width == cpia2_framesizes[i].width &&
- fival->height == cpia2_framesizes[i].height)
- break;
- if (i == ARRAY_SIZE(cpia2_framesizes))
- return -EINVAL;
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete = framerate_controls[fival->index].period;
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_s_ctrl
- *
- * V4L2 set the value of a control variable
- *
- *****************************************************************************/
-
-static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct camera_data *cam =
- container_of(ctrl->handler, struct camera_data, hdl);
- static const int flicker_table[] = {
- NEVER_FLICKER,
- FLICKER_50,
- FLICKER_60,
- };
-
- DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- cpia2_set_brightness(cam, ctrl->val);
- break;
- case V4L2_CID_CONTRAST:
- cpia2_set_contrast(cam, ctrl->val);
- break;
- case V4L2_CID_SATURATION:
- cpia2_set_saturation(cam, ctrl->val);
- break;
- case V4L2_CID_HFLIP:
- cpia2_set_property_mirror(cam, ctrl->val);
- break;
- case V4L2_CID_VFLIP:
- cpia2_set_property_flip(cam, ctrl->val);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
- case V4L2_CID_ILLUMINATORS_1:
- return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
- (cam->bottom_light->val << 7));
- case V4L2_CID_JPEG_ACTIVE_MARKER:
- cam->params.compression.inhibit_htables =
- !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
- break;
- case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- cam->params.vc_params.quality = ctrl->val;
- break;
- case CPIA2_CID_USB_ALT:
- cam->params.camera_state.stream_mode = ctrl->val;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_g_jpegcomp
- *
- * V4L2 get the JPEG compression parameters
- *
- *****************************************************************************/
-
-static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
-{
- struct camera_data *cam = video_drvdata(file);
-
- memset(parms, 0, sizeof(*parms));
-
- parms->quality = 80; // TODO: Can this be made meaningful?
-
- parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
- if(!cam->params.compression.inhibit_htables) {
- parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
- }
-
- parms->APPn = cam->APPn;
- parms->APP_len = cam->APP_len;
- if(cam->APP_len > 0) {
- memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
- parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
- }
-
- parms->COM_len = cam->COM_len;
- if(cam->COM_len > 0) {
- memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
- parms->jpeg_markers |= JPEG_MARKER_COM;
- }
-
- DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
- parms->APP_len, parms->COM_len);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_s_jpegcomp
- *
- * V4L2 set the JPEG compression parameters
- * NOTE: quality and some jpeg_markers are ignored.
- *
- *****************************************************************************/
-
-static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
-{
- struct camera_data *cam = video_drvdata(file);
-
- DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
- parms->APP_len, parms->COM_len);
-
- cam->params.compression.inhibit_htables =
- !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
- parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
- V4L2_JPEG_MARKER_DHT;
-
- if(parms->APP_len != 0) {
- if(parms->APP_len > 0 &&
- parms->APP_len <= sizeof(cam->APP_data) &&
- parms->APPn >= 0 && parms->APPn <= 15) {
- cam->APPn = parms->APPn;
- cam->APP_len = parms->APP_len;
- memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
- } else {
- LOG("Bad APPn Params n=%d len=%d\n",
- parms->APPn, parms->APP_len);
- return -EINVAL;
- }
- } else {
- cam->APP_len = 0;
- }
-
- if(parms->COM_len != 0) {
- if(parms->COM_len > 0 &&
- parms->COM_len <= sizeof(cam->COM_data)) {
- cam->COM_len = parms->COM_len;
- memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
- } else {
- LOG("Bad COM_len=%d\n", parms->COM_len);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_reqbufs
- *
- * V4L2 Initiate memory mapping.
- * NOTE: The user's request is ignored. For now the buffers are fixed.
- *
- *****************************************************************************/
-
-static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
- req->count = cam->num_frames;
- memset(&req->reserved, 0, sizeof(req->reserved));
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_querybuf
- *
- * V4L2 Query memory buffer status.
- *
- *****************************************************************************/
-
-static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->index > cam->num_frames)
- return -EINVAL;
-
- buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
- buf->length = cam->frame_size;
-
- buf->memory = V4L2_MEMORY_MMAP;
-
- if(cam->mmapped)
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- else
- buf->flags = 0;
-
- switch (cam->buffers[buf->index].status) {
- case FRAME_EMPTY:
- case FRAME_ERROR:
- case FRAME_READING:
- buf->bytesused = 0;
- buf->flags = V4L2_BUF_FLAG_QUEUED;
- break;
- case FRAME_READY:
- buf->bytesused = cam->buffers[buf->index].length;
- buf->timestamp = cam->buffers[buf->index].timestamp;
- buf->sequence = cam->buffers[buf->index].seq;
- buf->flags = V4L2_BUF_FLAG_DONE;
- break;
- }
-
- DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
- buf->index, buf->m.offset, buf->flags, buf->sequence,
- buf->bytesused);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_qbuf
- *
- * V4L2 User is freeing buffer
- *
- *****************************************************************************/
-
-static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP ||
- buf->index > cam->num_frames)
- return -EINVAL;
-
- DBG("QBUF #%d\n", buf->index);
-
- if(cam->buffers[buf->index].status == FRAME_READY)
- cam->buffers[buf->index].status = FRAME_EMPTY;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * find_earliest_filled_buffer
- *
- * Helper for ioctl_dqbuf. Find the next ready buffer.
- *
- *****************************************************************************/
-
-static int find_earliest_filled_buffer(struct camera_data *cam)
-{
- int i;
- int found = -1;
- for (i=0; i<cam->num_frames; i++) {
- if(cam->buffers[i].status == FRAME_READY) {
- if(found < 0) {
- found = i;
- } else {
- /* find which buffer is earlier */
- struct timeval *tv1, *tv2;
- tv1 = &cam->buffers[i].timestamp;
- tv2 = &cam->buffers[found].timestamp;
- if(tv1->tv_sec < tv2->tv_sec ||
- (tv1->tv_sec == tv2->tv_sec &&
- tv1->tv_usec < tv2->tv_usec))
- found = i;
- }
- }
- }
- return found;
-}
-
-/******************************************************************************
- *
- * ioctl_dqbuf
- *
- * V4L2 User is asking for a filled buffer.
- *
- *****************************************************************************/
-
-static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
- int frame;
-
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- frame = find_earliest_filled_buffer(cam);
-
- if(frame < 0 && file->f_flags&O_NONBLOCK)
- return -EAGAIN;
-
- if(frame < 0) {
- /* Wait for a frame to become available */
- struct framebuf *cb=cam->curbuff;
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !video_is_registered(&cam->vdev) ||
- (cb=cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return -ENOTTY;
- frame = cb->num;
- }
-
-
- buf->index = frame;
- buf->bytesused = cam->buffers[buf->index].length;
- buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
- buf->field = V4L2_FIELD_NONE;
- buf->timestamp = cam->buffers[buf->index].timestamp;
- buf->sequence = cam->buffers[buf->index].seq;
- buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
- buf->length = cam->frame_size;
- buf->reserved2 = 0;
- buf->reserved = 0;
- memset(&buf->timecode, 0, sizeof(buf->timecode));
-
- DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
- cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
-
- return 0;
-}
-
-static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct camera_data *cam = video_drvdata(file);
- int ret = -EINVAL;
-
- DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
- if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (!cam->streaming) {
- ret = cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- if (!ret)
- v4l2_ctrl_grab(cam->usb_alt, true);
- }
- return ret;
-}
-
-static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct camera_data *cam = video_drvdata(file);
- int ret = -EINVAL;
-
- DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
- if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->streaming) {
- ret = cpia2_usb_stream_stop(cam);
- if (!ret)
- v4l2_ctrl_grab(cam->usb_alt, false);
- }
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_mmap
- *
- *****************************************************************************/
-static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
-{
- struct camera_data *cam = video_drvdata(file);
- int retval;
-
- retval = cpia2_remap_buffer(cam, area);
-
- if(!retval)
- cam->stream_fh = file->private_data;
- return retval;
-}
-
-/******************************************************************************
- *
- * reset_camera_struct_v4l
- *
- * Sets all values to the defaults
- *****************************************************************************/
-static void reset_camera_struct_v4l(struct camera_data *cam)
-{
- cam->width = cam->params.roi.width;
- cam->height = cam->params.roi.height;
-
- cam->frame_size = buffer_size;
- cam->num_frames = num_buffers;
-
- /* Flicker modes */
- cam->params.flicker_control.flicker_mode_req = flicker_mode;
-
- /* stream modes */
- cam->params.camera_state.stream_mode = alternate;
-
- cam->pixelformat = V4L2_PIX_FMT_JPEG;
-}
-
-static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
- .vidioc_querycap = cpia2_querycap,
- .vidioc_enum_input = cpia2_enum_input,
- .vidioc_g_input = cpia2_g_input,
- .vidioc_s_input = cpia2_s_input,
- .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap,
- .vidioc_g_jpegcomp = cpia2_g_jpegcomp,
- .vidioc_s_jpegcomp = cpia2_s_jpegcomp,
- .vidioc_cropcap = cpia2_cropcap,
- .vidioc_reqbufs = cpia2_reqbufs,
- .vidioc_querybuf = cpia2_querybuf,
- .vidioc_qbuf = cpia2_qbuf,
- .vidioc_dqbuf = cpia2_dqbuf,
- .vidioc_streamon = cpia2_streamon,
- .vidioc_streamoff = cpia2_streamoff,
- .vidioc_s_parm = cpia2_s_parm,
- .vidioc_g_parm = cpia2_g_parm,
- .vidioc_enum_framesizes = cpia2_enum_framesizes,
- .vidioc_enum_frameintervals = cpia2_enum_frameintervals,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-/***
- * The v4l video device structure initialized for this device
- ***/
-static const struct v4l2_file_operations cpia2_fops = {
- .owner = THIS_MODULE,
- .open = cpia2_open,
- .release = cpia2_close,
- .read = cpia2_v4l_read,
- .poll = cpia2_v4l_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = cpia2_mmap,
-};
-
-static struct video_device cpia2_template = {
- /* I could not find any place for the old .initialize initializer?? */
- .name = "CPiA2 Camera",
- .fops = &cpia2_fops,
- .ioctl_ops = &cpia2_ioctl_ops,
- .release = video_device_release_empty,
-};
-
-void cpia2_camera_release(struct v4l2_device *v4l2_dev)
-{
- struct camera_data *cam =
- container_of(v4l2_dev, struct camera_data, v4l2_dev);
-
- v4l2_ctrl_handler_free(&cam->hdl);
- v4l2_device_unregister(&cam->v4l2_dev);
- kfree(cam);
-}
-
-static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
- .s_ctrl = cpia2_s_ctrl,
-};
-
-/******************************************************************************
- *
- * cpia2_register_camera
- *
- *****************************************************************************/
-int cpia2_register_camera(struct camera_data *cam)
-{
- struct v4l2_ctrl_handler *hdl = &cam->hdl;
- struct v4l2_ctrl_config cpia2_usb_alt = {
- .ops = &cpia2_ctrl_ops,
- .id = CPIA2_CID_USB_ALT,
- .name = "USB Alternate",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = USBIF_ISO_1,
- .max = USBIF_ISO_6,
- .step = 1,
- };
- int ret;
-
- v4l2_ctrl_handler_init(hdl, 12);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_BRIGHTNESS,
- cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
- 255, 1, DEFAULT_BRIGHTNESS);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_ACTIVE_MARKER, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
- 100, 1, 100);
- cpia2_usb_alt.def = alternate;
- cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
- /* VP5 Only */
- if (cam->params.pnp_id.device_type != DEVICE_STV_672)
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- /* Flicker control only valid for 672 */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
- V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
- /* Light control only valid for the QX5 Microscope */
- if (cam->params.pnp_id.product == 0x151) {
- cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
- cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
- v4l2_ctrl_cluster(2, &cam->top_light);
- }
-
- if (hdl->error) {
- ret = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return ret;
- }
-
- cam->vdev = cpia2_template;
- video_set_drvdata(&cam->vdev, cam);
- cam->vdev.lock = &cam->v4l2_lock;
- cam->vdev.ctrl_handler = hdl;
- cam->vdev.v4l2_dev = &cam->v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &cam->vdev.flags);
-
- reset_camera_struct_v4l(cam);
-
- /* register v4l device */
- if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- ERR("video_register_device failed\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_unregister_camera
- *
- *****************************************************************************/
-void cpia2_unregister_camera(struct camera_data *cam)
-{
- video_unregister_device(&cam->vdev);
-}
-
-/******************************************************************************
- *
- * check_parameters
- *
- * Make sure that all user-supplied parameters are sensible
- *****************************************************************************/
-static void __init check_parameters(void)
-{
- if(buffer_size < PAGE_SIZE) {
- buffer_size = PAGE_SIZE;
- LOG("buffer_size too small, setting to %d\n", buffer_size);
- } else if(buffer_size > 1024*1024) {
- /* arbitrary upper limiit */
- buffer_size = 1024*1024;
- LOG("buffer_size ridiculously large, setting to %d\n",
- buffer_size);
- } else {
- buffer_size += PAGE_SIZE-1;
- buffer_size &= ~(PAGE_SIZE-1);
- }
-
- if(num_buffers < 1) {
- num_buffers = 1;
- LOG("num_buffers too small, setting to %d\n", num_buffers);
- } else if(num_buffers > VIDEO_MAX_FRAME) {
- num_buffers = VIDEO_MAX_FRAME;
- LOG("num_buffers too large, setting to %d\n", num_buffers);
- }
-
- if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
- alternate = DEFAULT_ALT;
- LOG("alternate specified is invalid, using %d\n", alternate);
- }
-
- if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
- flicker_mode = 0;
- LOG("Flicker mode specified is invalid, using %d\n",
- flicker_mode);
- }
-
- DBG("Using %d buffers, each %d bytes, alternate=%d\n",
- num_buffers, buffer_size, alternate);
-}
-
-/************ Module Stuff ***************/
-
-
-/******************************************************************************
- *
- * cpia2_init/module_init
- *
- *****************************************************************************/
-static int __init cpia2_init(void)
-{
- LOG("%s v%s\n",
- ABOUT, CPIA_VERSION);
- check_parameters();
- cpia2_usb_init();
- return 0;
-}
-
-
-/******************************************************************************
- *
- * cpia2_exit/module_exit
- *
- *****************************************************************************/
-static void __exit cpia2_exit(void)
-{
- cpia2_usb_cleanup();
- schedule_timeout(2 * HZ);
-}
-
-module_init(cpia2_init);
-module_exit(cpia2_exit);
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
deleted file mode 100644
index 53b3c7702573..000000000000
--- a/drivers/media/video/cx18/Kconfig
+++ /dev/null
@@ -1,35 +0,0 @@
-config VIDEO_CX18
- tristate "Conexant cx23418 MPEG encoder support"
- depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
- select I2C_ALGOBIT
- select VIDEOBUF_VMALLOC
- depends on RC_CORE
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_CX2341X
- select VIDEO_CS5345
- select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
- ---help---
- This is a video4linux driver for Conexant cx23418 based
- PCI combo video recorder devices.
-
- This is used in devices such as the Hauppauge HVR-1600
- cards.
-
- To compile this driver as a module, choose M here: the
- module will be called cx18.
-
-config VIDEO_CX18_ALSA
- tristate "Conexant 23418 DMA audio support"
- depends on VIDEO_CX18 && SND && EXPERIMENTAL
- select SND_PCM
- ---help---
- This is a video4linux driver for direct (DMA) audio on
- Conexant 23418 based TV cards using ALSA.
-
- To compile this driver as a module, choose M here: the
- module will be called cx18-alsa.
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
deleted file mode 100644
index a86bab5893ef..000000000000
--- a/drivers/media/video/cx18/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
- cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
- cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
- cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
- cx18-dvb.o cx18-io.o
-cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
-
-obj-$(CONFIG_VIDEO_CX18) += cx18.o
-obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
deleted file mode 100644
index 280aa4d22488..000000000000
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * cx18 ADEC firmware functions
- *
- * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
- *
- * 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 "cx18-driver.h"
-#include "cx18-io.h"
-#include <linux/firmware.h>
-
-#define CX18_AUDIO_ENABLE 0xc72014
-#define CX18_AI1_MUX_MASK 0x30
-#define CX18_AI1_MUX_I2S1 0x00
-#define CX18_AI1_MUX_I2S2 0x10
-#define CX18_AI1_MUX_843_I2S 0x20
-#define CX18_AI1_MUX_INVALID 0x30
-
-#define FWFILE "v4l-cx23418-dig.fw"
-
-static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
-{
- struct v4l2_subdev *sd = &cx->av_state.sd;
- int ret = 0;
- const u8 *data;
- u32 size;
- int addr;
- u32 expected, dl_control;
-
- /* Ensure we put the 8051 in reset and enable firmware upload mode */
- dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
- do {
- dl_control &= 0x00ffffff;
- dl_control |= 0x0f000000;
- cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
- dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
- } while ((dl_control & 0xff000000) != 0x0f000000);
-
- /* Read and auto increment until at address 0x0000 */
- while (dl_control & 0x3fff)
- dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
-
- data = fw->data;
- size = fw->size;
- for (addr = 0; addr < size; addr++) {
- dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
- expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
- if (expected != dl_control) {
- CX18_ERR_DEV(sd, "verification of %s firmware load "
- "failed: expected %#010x got %#010x\n",
- FWFILE, expected, dl_control);
- ret = -EIO;
- break;
- }
- dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
- }
- if (ret == 0)
- CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
- FWFILE, size);
- return ret;
-}
-
-int cx18_av_loadfw(struct cx18 *cx)
-{
- struct v4l2_subdev *sd = &cx->av_state.sd;
- const struct firmware *fw = NULL;
- u32 size;
- u32 u, v;
- const u8 *ptr;
- int i;
- int retries1 = 0;
-
- if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) {
- CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE);
- return -EINVAL;
- }
-
- /* The firmware load often has byte errors, so allow for several
- retries, both at byte level and at the firmware load level. */
- while (retries1 < 5) {
- cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
- 0x00008430, 0xffffffff); /* cx25843 */
- cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
-
- /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
- cx18_av_write4_expect(cx, 0x8100, 0x00010000,
- 0x00008430, 0xffffffff); /* cx25843 */
-
- /* Put the 8051 in reset and enable firmware upload */
- cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
-
- ptr = fw->data;
- size = fw->size;
-
- for (i = 0; i < size; i++) {
- u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
- u32 value = 0;
- int retries2;
- int unrec_err = 0;
-
- for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES;
- retries2++) {
- cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
- dl_control);
- udelay(10);
- value = cx18_av_read4(cx, CXADEC_DL_CTL);
- if (value == dl_control)
- break;
- /* Check if we can correct the byte by changing
- the address. We can only write the lower
- address byte of the address. */
- if ((value & 0x3F00) != (dl_control & 0x3F00)) {
- unrec_err = 1;
- break;
- }
- }
- if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES)
- break;
- }
- if (i == size)
- break;
- retries1++;
- }
- if (retries1 >= 5) {
- CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE);
- release_firmware(fw);
- return -EIO;
- }
-
- cx18_av_write4_expect(cx, CXADEC_DL_CTL,
- 0x03000000 | fw->size, 0x03000000, 0x13000000);
-
- CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
-
- if (cx18_av_verifyfw(cx, fw) == 0)
- cx18_av_write4_expect(cx, CXADEC_DL_CTL,
- 0x13000000 | fw->size, 0x13000000, 0x13000000);
-
- /* Output to the 416 */
- cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
-
- /* Audio input control 1 set to Sony mode */
- /* Audio output input 2 is 0 for slave operation input */
- /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
- /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
- after WS transition for first bit of audio word. */
- cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
-
- /* Audio output control 1 is set to Sony mode */
- /* Audio output control 2 is set to 1 for master mode */
- /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
- /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
- after WS transition for first bit of audio word. */
- /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
- are generated) */
- cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
-
- /* set alt I2s master clock to /0x16 and enable alt divider i2s
- passthrough */
- cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687);
-
- cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
- 0x3F00FFFF);
- /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
-
- /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
- /* Register 0x09CC is defined by the Merlin firmware, and doesn't
- have a name in the spec. */
- cx18_av_write4(cx, 0x09CC, 1);
-
- v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
- /* If bit 11 is 1, clear bit 10 */
- if (v & 0x800)
- cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
- 0, 0x400);
-
- /* Toggle the AI1 MUX */
- v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
- u = v & CX18_AI1_MUX_MASK;
- v &= ~CX18_AI1_MUX_MASK;
- if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
- /* Switch to I2S1 */
- v |= CX18_AI1_MUX_I2S1;
- cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
- v, CX18_AI1_MUX_MASK);
- /* Switch back to the A/V decoder core I2S output */
- v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
- } else {
- /* Switch to the A/V decoder core I2S output */
- v |= CX18_AI1_MUX_843_I2S;
- cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
- v, CX18_AI1_MUX_MASK);
- /* Switch back to I2S1 or I2S2 */
- v = (v & ~CX18_AI1_MUX_MASK) | u;
- }
- cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
- v, CX18_AI1_MUX_MASK);
-
- /* Enable WW auto audio standard detection */
- v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
- v |= 0xFF; /* Auto by default */
- v |= 0x400; /* Stereo by default */
- v |= 0x14000000;
- cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
-
- release_firmware(fw);
- return 0;
-}
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
deleted file mode 100644
index 7e5ffd6f5178..000000000000
--- a/drivers/media/video/cx18/cx18-driver.c
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * cx18 driver initialization and card probing
- *
- * Derived from ivtv-driver.c
- *
- * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
- *
- * 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
- */
-
-#include "cx18-driver.h"
-#include "cx18-io.h"
-#include "cx18-version.h"
-#include "cx18-cards.h"
-#include "cx18-i2c.h"
-#include "cx18-irq.h"
-#include "cx18-gpio.h"
-#include "cx18-firmware.h"
-#include "cx18-queue.h"
-#include "cx18-streams.h"
-#include "cx18-av-core.h"
-#include "cx18-scb.h"
-#include "cx18-mailbox.h"
-#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
- the device numbers stay matched. Example: you have a WinTV card
- without radio and a Compro H900 with. Normally this would give a
- video1 device together with a radio0 device for the Compro. By
- setting this to 1 you ensure that radio0 is now also radio1. */
-int cx18_first_minor;
-
-/* Callback for registering extensions */
-int (*cx18_ext_init)(struct cx18 *);
-EXPORT_SYMBOL(cx18_ext_init);
-
-/* add your revision and whatnot here */
-static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
- {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
-
-static atomic_t cx18_instance = ATOMIC_INIT(0);
-
-/* Parameter declarations */
-static int cardtype[CX18_MAX_CARDS];
-static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1 };
-static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1 };
-static unsigned cardtype_c = 1;
-static unsigned tuner_c = 1;
-static unsigned radio_c = 1;
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-/* Buffers */
-static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
-static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
-static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
-static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
-static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
-static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
-
-static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
-static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
-static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
-static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
-static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
-
-static int enc_ts_bufs = -1;
-static int enc_mpg_bufs = -1;
-static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM;
-static int enc_yuv_bufs = -1;
-static int enc_vbi_bufs = -1;
-static int enc_pcm_bufs = -1;
-
-
-static int cx18_pci_latency = 1;
-
-static int mmio_ndelay;
-static int retry_mmio = 1;
-
-int cx18_debug;
-
-module_param_array(tuner, int, &tuner_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);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-module_param_named(debug, cx18_debug, int, 0644);
-module_param(mmio_ndelay, int, 0644);
-module_param(retry_mmio, int, 0644);
-module_param(cx18_pci_latency, int, 0644);
-module_param(cx18_first_minor, int, 0644);
-
-module_param(enc_ts_buffers, int, 0644);
-module_param(enc_mpg_buffers, int, 0644);
-module_param(enc_idx_buffers, int, 0644);
-module_param(enc_yuv_buffers, int, 0644);
-module_param(enc_vbi_buffers, int, 0644);
-module_param(enc_pcm_buffers, int, 0644);
-
-module_param(enc_ts_bufsize, int, 0644);
-module_param(enc_mpg_bufsize, int, 0644);
-module_param(enc_idx_bufsize, int, 0644);
-module_param(enc_yuv_bufsize, int, 0644);
-module_param(enc_pcm_bufsize, int, 0644);
-
-module_param(enc_ts_bufs, int, 0644);
-module_param(enc_mpg_bufs, int, 0644);
-module_param(enc_idx_bufs, int, 0644);
-module_param(enc_yuv_bufs, int, 0644);
-module_param(enc_vbi_bufs, int, 0644);
-module_param(enc_pcm_bufs, int, 0644);
-
-MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
- "\t\t\tsee tuner.h for values");
-MODULE_PARM_DESC(radio,
- "Enable or disable the radio. Use only if autodetection\n"
- "\t\t\tfails. 0 = disable, 1 = enable");
-MODULE_PARM_DESC(cardtype,
- "Only use this option if your card is not detected properly.\n"
- "\t\tSpecify card type:\n"
- "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
- "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
- "\t\t\t 3 = Compro VideoMate H900\n"
- "\t\t\t 4 = Yuan MPC718\n"
- "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
- "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
- "\t\t\t 7 = Leadtek WinFast PVR2100\n"
- "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
- "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
- "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n"
- "\t\t\t 0 = Autodetect (default)\n"
- "\t\t\t-1 = Ignore this card\n\t\t");
-MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
-MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
-MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
-MODULE_PARM_DESC(debug,
- "Debug level (bitmask). Default: 0\n"
- "\t\t\t 1/0x0001: warning\n"
- "\t\t\t 2/0x0002: info\n"
- "\t\t\t 4/0x0004: mailbox\n"
- "\t\t\t 8/0x0008: dma\n"
- "\t\t\t 16/0x0010: ioctl\n"
- "\t\t\t 32/0x0020: file\n"
- "\t\t\t 64/0x0040: i2c\n"
- "\t\t\t128/0x0080: irq\n"
- "\t\t\t256/0x0100: high volume\n");
-MODULE_PARM_DESC(cx18_pci_latency,
- "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
- "\t\t\tDefault: Yes");
-MODULE_PARM_DESC(retry_mmio,
- "(Deprecated) MMIO writes are now always checked and retried\n"
- "\t\t\tEffectively: 1 [Yes]");
-MODULE_PARM_DESC(mmio_ndelay,
- "(Deprecated) MMIO accesses are now never purposely delayed\n"
- "\t\t\tEffectively: 0 ns");
-MODULE_PARM_DESC(enc_ts_buffers,
- "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
-MODULE_PARM_DESC(enc_ts_bufsize,
- "Size of an encoder TS buffer (kB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
-MODULE_PARM_DESC(enc_ts_bufs,
- "Number of encoder TS buffers\n"
- "\t\t\tDefault is computed from other enc_ts_* parameters");
-MODULE_PARM_DESC(enc_mpg_buffers,
- "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
-MODULE_PARM_DESC(enc_mpg_bufsize,
- "Size of an encoder MPG buffer (kB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
-MODULE_PARM_DESC(enc_mpg_bufs,
- "Number of encoder MPG buffers\n"
- "\t\t\tDefault is computed from other enc_mpg_* parameters");
-MODULE_PARM_DESC(enc_idx_buffers,
- "(Deprecated) Encoder IDX buffer memory (MB)\n"
- "\t\t\tIgnored, except 0 disables IDX buffer allocations\n"
- "\t\t\tDefault: 1 [Enabled]");
-MODULE_PARM_DESC(enc_idx_bufsize,
- "Size of an encoder IDX buffer (kB)\n"
- "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n"
- "\t\t\t(multiples of size required for 64 index entries)\n"
- "\t\t\tDefault: 2");
-MODULE_PARM_DESC(enc_idx_bufs,
- "Number of encoder IDX buffers\n"
- "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM));
-MODULE_PARM_DESC(enc_yuv_buffers,
- "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
-MODULE_PARM_DESC(enc_yuv_bufsize,
- "Size of an encoder YUV buffer (kB)\n"
- "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
- "\t\t\t(multiples of size required for 32 screen lines)\n"
- "\t\t\tDefault: 102");
-MODULE_PARM_DESC(enc_yuv_bufs,
- "Number of encoder YUV buffers\n"
- "\t\t\tDefault is computed from other enc_yuv_* parameters");
-MODULE_PARM_DESC(enc_vbi_buffers,
- "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
-MODULE_PARM_DESC(enc_vbi_bufs,
- "Number of encoder VBI buffers\n"
- "\t\t\tDefault is computed from enc_vbi_buffers");
-MODULE_PARM_DESC(enc_pcm_buffers,
- "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
-MODULE_PARM_DESC(enc_pcm_bufsize,
- "Size of an encoder PCM buffer (kB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
-MODULE_PARM_DESC(enc_pcm_bufs,
- "Number of encoder PCM buffers\n"
- "\t\t\tDefault is computed from other enc_pcm_* parameters");
-
-MODULE_PARM_DESC(cx18_first_minor,
- "Set device node number assigned to first card");
-
-MODULE_AUTHOR("Hans Verkuil");
-MODULE_DESCRIPTION("CX23418 driver");
-MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
-MODULE_LICENSE("GPL");
-
-MODULE_VERSION(CX18_VERSION);
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-static void request_module_async(struct work_struct *work)
-{
- struct cx18 *dev = container_of(work, struct cx18, request_module_wk);
-
- /* Make sure cx18-alsa module is loaded */
- request_module("cx18-alsa");
-
- /* Initialize cx18-alsa for this instance of the cx18 device */
- if (cx18_ext_init != NULL)
- cx18_ext_init(dev);
-}
-
-static void request_modules(struct cx18 *dev)
-{
- INIT_WORK(&dev->request_module_wk, request_module_async);
- schedule_work(&dev->request_module_wk);
-}
-
-static void flush_request_modules(struct cx18 *dev)
-{
- flush_work_sync(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#define flush_request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-/* Generic utility functions */
-int cx18_msleep_timeout(unsigned int msecs, int intr)
-{
- long int timeout = msecs_to_jiffies(msecs);
- int sig;
-
- do {
- set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- sig = intr ? signal_pending(current) : 0;
- } while (!sig && timeout);
- return sig;
-}
-
-/* Release ioremapped memory */
-static void cx18_iounmap(struct cx18 *cx)
-{
- if (cx == NULL)
- return;
-
- /* Release io memory */
- if (cx->enc_mem != NULL) {
- CX18_DEBUG_INFO("releasing enc_mem\n");
- iounmap(cx->enc_mem);
- cx->enc_mem = NULL;
- }
-}
-
-static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
-{
- int i;
-
- CX18_INFO("eeprom dump:\n");
- for (i = 0; i < len; i++) {
- if (0 == (i % 16))
- CX18_INFO("eeprom %02x:", i);
- printk(KERN_CONT " %02x", eedata[i]);
- if (15 == (i % 16))
- printk(KERN_CONT "\n");
- }
-}
-
-/* Hauppauge card? get values from tveeprom */
-void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
-{
- struct i2c_client c;
- u8 eedata[256];
-
- memset(&c, 0, sizeof(c));
- strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
- c.adapter = &cx->i2c_adap[0];
- c.addr = 0xA0 >> 1;
-
- memset(tv, 0, sizeof(*tv));
- if (tveeprom_read(&c, eedata, sizeof(eedata)))
- return;
-
- switch (cx->card->type) {
- case CX18_CARD_HVR_1600_ESMT:
- case CX18_CARD_HVR_1600_SAMSUNG:
- case CX18_CARD_HVR_1600_S5H1411:
- tveeprom_hauppauge_analog(&c, tv, eedata);
- break;
- case CX18_CARD_YUAN_MPC718:
- case CX18_CARD_GOTVIEW_PCI_DVD3:
- tv->model = 0x718;
- cx18_eeprom_dump(cx, eedata, sizeof(eedata));
- CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
- eedata[2], eedata[1], eedata[4], eedata[3]);
- break;
- default:
- tv->model = 0xffffffff;
- cx18_eeprom_dump(cx, eedata, sizeof(eedata));
- break;
- }
-}
-
-static void cx18_process_eeprom(struct cx18 *cx)
-{
- struct tveeprom tv;
-
- cx18_read_eeprom(cx, &tv);
-
- /* Many thanks to Steven Toth from Hauppauge for providing the
- model numbers */
- /* Note: the Samsung memory models cannot be reliably determined
- from the model number. Use the cardtype module option if you
- have one of these preproduction models. */
- switch (tv.model) {
- case 74301: /* Retail models */
- case 74321:
- case 74351: /* OEM models */
- case 74361:
- /* Digital side is s5h1411/tda18271 */
- cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411);
- break;
- case 74021: /* Retail models */
- case 74031:
- case 74041:
- case 74141:
- case 74541: /* OEM models */
- case 74551:
- case 74591:
- case 74651:
- case 74691:
- case 74751:
- case 74891:
- /* Digital side is s5h1409/mxl5005s */
- cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
- break;
- case 0x718:
- return;
- case 0xffffffff:
- CX18_INFO("Unknown EEPROM encoding\n");
- return;
- case 0:
- CX18_ERR("Invalid EEPROM\n");
- return;
- default:
- CX18_ERR("Unknown model %d, defaulting to original HVR-1600 "
- "(cardtype=1)\n", tv.model);
- cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
- break;
- }
-
- cx->v4l2_cap = cx->card->v4l2_capabilities;
- cx->card_name = cx->card->name;
- cx->card_i2c = cx->card->i2c;
-
- CX18_INFO("Autodetected %s\n", cx->card_name);
-
- if (tv.tuner_type == TUNER_ABSENT)
- CX18_ERR("tveeprom cannot autodetect tuner!\n");
-
- if (cx->options.tuner == -1)
- cx->options.tuner = tv.tuner_type;
- if (cx->options.radio == -1)
- cx->options.radio = (tv.has_radio != 0);
-
- if (cx->std != 0)
- /* user specified tuner standard */
- return;
-
- /* autodetect tuner standard */
-#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \
- V4L2_STD_MN | \
- V4L2_STD_PAL_I | \
- V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
- V4L2_STD_DK)
- if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
- == TVEEPROM_TUNER_FORMAT_ALL) {
- CX18_DEBUG_INFO("Worldwide tuner detected\n");
- cx->std = V4L2_STD_ALL;
- } else if (tv.tuner_formats & V4L2_STD_PAL) {
- CX18_DEBUG_INFO("PAL tuner detected\n");
- cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
- } else if (tv.tuner_formats & V4L2_STD_NTSC) {
- CX18_DEBUG_INFO("NTSC tuner detected\n");
- cx->std |= V4L2_STD_NTSC_M;
- } else if (tv.tuner_formats & V4L2_STD_SECAM) {
- CX18_DEBUG_INFO("SECAM tuner detected\n");
- cx->std |= V4L2_STD_SECAM_L;
- } else {
- CX18_INFO("No tuner detected, default to NTSC-M\n");
- cx->std |= V4L2_STD_NTSC_M;
- }
-}
-
-static v4l2_std_id cx18_parse_std(struct cx18 *cx)
-{
- switch (pal[0]) {
- case '6':
- return V4L2_STD_PAL_60;
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- return V4L2_STD_PAL_BG;
- case 'h':
- case 'H':
- return V4L2_STD_PAL_H;
- case 'n':
- case 'N':
- if (pal[1] == 'c' || pal[1] == 'C')
- return V4L2_STD_PAL_Nc;
- return V4L2_STD_PAL_N;
- case 'i':
- case 'I':
- return V4L2_STD_PAL_I;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- return V4L2_STD_PAL_DK;
- case 'M':
- case 'm':
- return V4L2_STD_PAL_M;
- case '-':
- break;
- default:
- CX18_WARN("pal= argument not recognised\n");
- return 0;
- }
-
- switch (secam[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- return V4L2_STD_SECAM_DK;
- case 'l':
- case 'L':
- if (secam[1] == 'C' || secam[1] == 'c')
- return V4L2_STD_SECAM_LC;
- return V4L2_STD_SECAM_L;
- case '-':
- break;
- default:
- CX18_WARN("secam= argument not recognised\n");
- return 0;
- }
-
- switch (ntsc[0]) {
- case 'm':
- case 'M':
- return V4L2_STD_NTSC_M;
- case 'j':
- case 'J':
- return V4L2_STD_NTSC_M_JP;
- case 'k':
- case 'K':
- return V4L2_STD_NTSC_M_KR;
- case '-':
- break;
- default:
- CX18_WARN("ntsc= argument not recognised\n");
- return 0;
- }
-
- /* no match found */
- return 0;
-}
-
-static void cx18_process_options(struct cx18 *cx)
-{
- int i, j;
-
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
- cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
-
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
- cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
-
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
-
- /* Ensure stream_buffers & stream_buf_size are valid */
- for (i = 0; i < CX18_MAX_STREAMS; i++) {
- if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */
- cx->options.megabytes[i] <= 0 || /* User said 0 MB total */
- cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */
- cx->options.megabytes[i] = 0;
- cx->stream_buffers[i] = 0;
- cx->stream_buf_size[i] = 0;
- continue;
- }
- /*
- * YUV is a special case where the stream_buf_size needs to be
- * an integral multiple of 33.75 kB (storage for 32 screens
- * lines to maintain alignment in case of lost buffers).
- *
- * IDX is a special case where the stream_buf_size should be
- * an integral multiple of 1.5 kB (storage for 64 index entries
- * to maintain alignment in case of lost buffers).
- *
- */
- if (i == CX18_ENC_STREAM_TYPE_YUV) {
- cx->stream_buf_size[i] *= 1024;
- cx->stream_buf_size[i] -=
- (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
-
- if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
- cx->stream_buf_size[i] =
- CX18_UNIT_ENC_YUV_BUFSIZE;
- } else if (i == CX18_ENC_STREAM_TYPE_IDX) {
- cx->stream_buf_size[i] *= 1024;
- cx->stream_buf_size[i] -=
- (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE);
-
- if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE)
- cx->stream_buf_size[i] =
- CX18_UNIT_ENC_IDX_BUFSIZE;
- }
- /*
- * YUV and IDX are special cases where the stream_buf_size is
- * now in bytes.
- * VBI is a special case where the stream_buf_size is fixed
- * and already in bytes
- */
- if (i == CX18_ENC_STREAM_TYPE_VBI ||
- i == CX18_ENC_STREAM_TYPE_YUV ||
- i == CX18_ENC_STREAM_TYPE_IDX) {
- if (cx->stream_buffers[i] < 0) {
- cx->stream_buffers[i] =
- cx->options.megabytes[i] * 1024 * 1024
- / cx->stream_buf_size[i];
- } else {
- /* N.B. This might round down to 0 */
- cx->options.megabytes[i] =
- cx->stream_buffers[i]
- * cx->stream_buf_size[i]/(1024 * 1024);
- }
- } else {
- /* All other streams have stream_buf_size in kB here */
- if (cx->stream_buffers[i] < 0) {
- cx->stream_buffers[i] =
- cx->options.megabytes[i] * 1024
- / cx->stream_buf_size[i];
- } else {
- /* N.B. This might round down to 0 */
- cx->options.megabytes[i] =
- cx->stream_buffers[i]
- * cx->stream_buf_size[i] / 1024;
- }
- /* convert from kB to bytes */
- cx->stream_buf_size[i] *= 1024;
- }
- CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
- "%d bytes\n", i, cx->options.megabytes[i],
- cx->stream_buffers[i], cx->stream_buf_size[i]);
- }
-
- cx->options.cardtype = cardtype[cx->instance];
- cx->options.tuner = tuner[cx->instance];
- cx->options.radio = radio[cx->instance];
-
- cx->std = cx18_parse_std(cx);
- if (cx->options.cardtype == -1) {
- CX18_INFO("Ignore card\n");
- return;
- }
- cx->card = cx18_get_card(cx->options.cardtype - 1);
- if (cx->card)
- CX18_INFO("User specified %s card\n", cx->card->name);
- else if (cx->options.cardtype != 0)
- CX18_ERR("Unknown user specified type, trying to autodetect card\n");
- if (cx->card == NULL) {
- if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
- cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
- CX18_INFO("Autodetected Hauppauge card\n");
- }
- }
- if (cx->card == NULL) {
- for (i = 0; (cx->card = cx18_get_card(i)); i++) {
- if (cx->card->pci_list == NULL)
- continue;
- for (j = 0; cx->card->pci_list[j].device; j++) {
- if (cx->pci_dev->device !=
- cx->card->pci_list[j].device)
- continue;
- if (cx->pci_dev->subsystem_vendor !=
- cx->card->pci_list[j].subsystem_vendor)
- continue;
- if (cx->pci_dev->subsystem_device !=
- cx->card->pci_list[j].subsystem_device)
- continue;
- CX18_INFO("Autodetected %s card\n", cx->card->name);
- goto done;
- }
- }
- }
-done:
-
- if (cx->card == NULL) {
- cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
- CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
- cx->pci_dev->vendor, cx->pci_dev->device);
- CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n",
- cx->pci_dev->subsystem_vendor,
- cx->pci_dev->subsystem_device);
- CX18_ERR("Defaulting to %s card\n", cx->card->name);
- CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
- CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
- CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
- }
- cx->v4l2_cap = cx->card->v4l2_capabilities;
- cx->card_name = cx->card->name;
- cx->card_i2c = cx->card->i2c;
-}
-
-static int __devinit cx18_create_in_workq(struct cx18 *cx)
-{
- snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
- cx->v4l2_dev.name);
- cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
- if (cx->in_work_queue == NULL) {
- CX18_ERR("Unable to create incoming mailbox handler thread\n");
- return -ENOMEM;
- }
- return 0;
-}
-
-static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
-{
- int i;
- for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
- cx->in_work_order[i].cx = cx;
- cx->in_work_order[i].str = cx->epu_debug_str;
- INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
- }
-}
-
-/* Precondition: the cx18 structure has been memset to 0. Only
- the dev and instance fields have been filled in.
- No assumptions on the card type may be made here (see cx18_init_struct2
- for that).
- */
-static int __devinit cx18_init_struct1(struct cx18 *cx)
-{
- int ret;
-
- cx->base_addr = pci_resource_start(cx->pci_dev, 0);
-
- mutex_init(&cx->serialize_lock);
- mutex_init(&cx->gpio_lock);
- mutex_init(&cx->epu2apu_mb_lock);
- mutex_init(&cx->epu2cpu_mb_lock);
-
- ret = cx18_create_in_workq(cx);
- if (ret)
- return ret;
-
- cx18_init_in_work_orders(cx);
-
- /* start counting open_id at 1 */
- cx->open_id = 1;
-
- /* Initial settings */
- cx->cxhdl.port = CX2341X_PORT_MEMORY;
- cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
- cx->cxhdl.ops = &cx18_cxhdl_ops;
- cx->cxhdl.func = cx18_api_func;
- cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
- ret = cx2341x_handler_init(&cx->cxhdl, 50);
- if (ret)
- return ret;
- cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
-
- cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
- cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
- cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
- (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
- (cx->cxhdl.video_median_filter_type->cur.val << 2);
-
- init_waitqueue_head(&cx->cap_w);
- init_waitqueue_head(&cx->mb_apu_waitq);
- init_waitqueue_head(&cx->mb_cpu_waitq);
- init_waitqueue_head(&cx->dma_waitq);
-
- /* VBI */
- cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
- cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
-
- /* IVTV style VBI insertion into MPEG streams */
- INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list);
- INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list);
- INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list);
- list_add(&cx->vbi.sliced_mpeg_buf.list,
- &cx->vbi.sliced_mpeg_mdl.buf_list);
- return 0;
-}
-
-/* Second initialization part. Here the card type has been
- autodetected. */
-static void __devinit cx18_init_struct2(struct cx18 *cx)
-{
- int i;
-
- for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
- if (cx->card->video_inputs[i].video_type == 0)
- break;
- cx->nof_inputs = i;
- for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
- if (cx->card->audio_inputs[i].audio_type == 0)
- break;
- cx->nof_audio_inputs = i;
-
- /* Find tuner input */
- for (i = 0; i < cx->nof_inputs; i++) {
- if (cx->card->video_inputs[i].video_type ==
- CX18_CARD_INPUT_VID_TUNER)
- break;
- }
- if (i == cx->nof_inputs)
- i = 0;
- cx->active_input = i;
- cx->audio_input = cx->card->video_inputs[i].audio_index;
-}
-
-static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- u16 cmd;
- unsigned char pci_latency;
-
- CX18_DEBUG_INFO("Enabling pci device\n");
-
- if (pci_enable_device(pci_dev)) {
- CX18_ERR("Can't enable device %d!\n", cx->instance);
- return -EIO;
- }
- if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
- CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
- return -EIO;
- }
- if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
- CX18_ERR("Cannot request encoder memory region, card %d\n",
- cx->instance);
- return -EIO;
- }
-
- /* Enable bus mastering and memory mapped IO for the CX23418 */
- pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
- pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
-
- cx->card_rev = pci_dev->revision;
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
-
- if (pci_latency < 64 && cx18_pci_latency) {
- CX18_INFO("Unreasonably low latency timer, "
- "setting to 64 (was %d)\n", pci_latency);
- pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
- }
-
- CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
- "irq: %d, latency: %d, memory: 0x%llx\n",
- cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
- PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
- cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
-
- return 0;
-}
-
-static void cx18_init_subdevs(struct cx18 *cx)
-{
- u32 hw = cx->card->hw_all;
- u32 device;
- int i;
-
- for (i = 0, device = 1; i < 32; i++, device <<= 1) {
-
- if (!(device & hw))
- continue;
-
- switch (device) {
- case CX18_HW_DVB:
- case CX18_HW_TVEEPROM:
- /* These subordinate devices do not use probing */
- cx->hw_flags |= device;
- break;
- case CX18_HW_418_AV:
- /* The A/V decoder gets probed earlier to set PLLs */
- /* Just note that the card uses it (i.e. has analog) */
- cx->hw_flags |= device;
- break;
- case CX18_HW_GPIO_RESET_CTRL:
- /*
- * The Reset Controller gets probed and added to
- * hw_flags earlier for i2c adapter/bus initialization
- */
- break;
- case CX18_HW_GPIO_MUX:
- if (cx18_gpio_register(cx, device) == 0)
- cx->hw_flags |= device;
- break;
- default:
- if (cx18_i2c_register(cx, i) == 0)
- cx->hw_flags |= device;
- break;
- }
- }
-
- if (cx->hw_flags & CX18_HW_418_AV)
- cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
-
- if (cx->card->hw_muxer != 0)
- cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
-}
-
-static int __devinit cx18_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- int retval = 0;
- int i;
- u32 devtype;
- struct cx18 *cx;
-
- /* FIXME - module parameter arrays constrain max instances */
- i = atomic_inc_return(&cx18_instance) - 1;
- if (i >= CX18_MAX_CARDS) {
- printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
- "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
- return -ENOMEM;
- }
-
- cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
- if (cx == NULL) {
- printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
- i);
- return -ENOMEM;
- }
- cx->pci_dev = pci_dev;
- cx->instance = i;
-
- retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
- if (retval) {
- printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
- "\n", cx->instance);
- kfree(cx);
- return retval;
- }
- snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
- cx->instance);
- CX18_INFO("Initializing card %d\n", cx->instance);
-
- cx18_process_options(cx);
- if (cx->options.cardtype == -1) {
- retval = -ENODEV;
- goto err;
- }
-
- retval = cx18_init_struct1(cx);
- if (retval)
- goto err;
-
- CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr);
-
- /* PCI Device Setup */
- retval = cx18_setup_pci(cx, pci_dev, pci_id);
- if (retval != 0)
- goto free_workqueues;
-
- /* map io memory */
- CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
- (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
- cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
- CX18_MEM_SIZE);
- if (!cx->enc_mem) {
- CX18_ERR("ioremap failed. Can't get a window into CX23418 "
- "memory and register space\n");
- CX18_ERR("Each capture card with a CX23418 needs 64 MB of "
- "vmalloc address space for the window\n");
- CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
- CX18_ERR("Use the vmalloc= kernel command line option to set "
- "VmallocTotal to a larger value\n");
- retval = -ENOMEM;
- goto free_mem;
- }
- cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
- devtype = cx18_read_reg(cx, 0xC72028);
- switch (devtype & 0xff000000) {
- case 0xff000000:
- CX18_INFO("cx23418 revision %08x (A)\n", devtype);
- break;
- case 0x01000000:
- CX18_INFO("cx23418 revision %08x (B)\n", devtype);
- break;
- default:
- CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
- break;
- }
-
- cx18_init_power(cx, 1);
- cx18_init_memory(cx);
-
- cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
- cx18_init_scb(cx);
-
- cx18_gpio_init(cx);
-
- /* Initialize integrated A/V decoder early to set PLLs, just in case */
- retval = cx18_av_probe(cx);
- if (retval) {
- CX18_ERR("Could not register A/V decoder subdevice\n");
- goto free_map;
- }
-
- /* Initialize GPIO Reset Controller to do chip resets during i2c init */
- if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
- if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
- CX18_WARN("Could not register GPIO reset controller"
- "subdevice; proceeding anyway.\n");
- else
- cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
- }
-
- /* active i2c */
- CX18_DEBUG_INFO("activating i2c...\n");
- retval = init_cx18_i2c(cx);
- if (retval) {
- CX18_ERR("Could not initialize i2c\n");
- goto free_map;
- }
-
- if (cx->card->hw_all & CX18_HW_TVEEPROM) {
- /* Based on the model number the cardtype may be changed.
- The PCI IDs are not always reliable. */
- const struct cx18_card *orig_card = cx->card;
- cx18_process_eeprom(cx);
-
- if (cx->card != orig_card) {
- /* Changed the cardtype; re-reset the I2C chips */
- cx18_gpio_init(cx);
- cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
- core, reset, (u32) CX18_GPIO_RESET_I2C);
- }
- }
- if (cx->card->comment)
- CX18_INFO("%s", cx->card->comment);
- if (cx->card->v4l2_capabilities == 0) {
- retval = -ENODEV;
- goto free_i2c;
- }
- cx18_init_memory(cx);
- cx18_init_scb(cx);
-
- /* Register IRQ */
- retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
- IRQF_SHARED | IRQF_DISABLED,
- cx->v4l2_dev.name, (void *)cx);
- if (retval) {
- CX18_ERR("Failed to register irq %d\n", retval);
- goto free_i2c;
- }
-
- if (cx->std == 0)
- cx->std = V4L2_STD_NTSC_M;
-
- if (cx->options.tuner == -1) {
- for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
- if ((cx->std & cx->card->tuners[i].std) == 0)
- continue;
- cx->options.tuner = cx->card->tuners[i].tuner;
- break;
- }
- }
- /* if no tuner was found, then pick the first tuner in the card list */
- if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
- cx->std = cx->card->tuners[0].std;
- if (cx->std & V4L2_STD_PAL)
- cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
- else if (cx->std & V4L2_STD_NTSC)
- cx->std = V4L2_STD_NTSC_M;
- else if (cx->std & V4L2_STD_SECAM)
- cx->std = V4L2_STD_SECAM_L;
- cx->options.tuner = cx->card->tuners[0].tuner;
- }
- if (cx->options.radio == -1)
- cx->options.radio = (cx->card->radio_input.audio_type != 0);
-
- /* The card is now fully identified, continue with card-specific
- initialization. */
- cx18_init_struct2(cx);
-
- cx18_init_subdevs(cx);
-
- if (cx->std & V4L2_STD_525_60)
- cx->is_60hz = 1;
- else
- cx->is_50hz = 1;
-
- cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
-
- if (cx->options.radio > 0)
- cx->v4l2_cap |= V4L2_CAP_RADIO;
-
- if (cx->options.tuner > -1) {
- struct tuner_setup setup;
-
- setup.addr = ADDR_UNSET;
- setup.type = cx->options.tuner;
- setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
- if (cx->options.radio > 0)
- setup.mode_mask |= T_RADIO;
- setup.tuner_callback = (setup.type == TUNER_XC2028) ?
- cx18_reset_tuner_gpio : NULL;
- cx18_call_all(cx, tuner, s_type_addr, &setup);
- if (setup.type == TUNER_XC2028) {
- static struct xc2028_ctrl ctrl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- };
- struct v4l2_priv_tun_config cfg = {
- .tuner = cx->options.tuner,
- .priv = &ctrl,
- };
- cx18_call_all(cx, tuner, s_config, &cfg);
- }
- }
-
- /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
- are not. */
- cx->tuner_std = cx->std;
- if (cx->std == V4L2_STD_ALL)
- cx->std = V4L2_STD_NTSC_M;
-
- retval = cx18_streams_setup(cx);
- if (retval) {
- CX18_ERR("Error %d setting up streams\n", retval);
- goto free_irq;
- }
- retval = cx18_streams_register(cx);
- if (retval) {
- CX18_ERR("Error %d registering devices\n", retval);
- goto free_streams;
- }
-
- CX18_INFO("Initialized card: %s\n", cx->card_name);
-
- /* Load cx18 submodules (cx18-alsa) */
- request_modules(cx);
- return 0;
-
-free_streams:
- cx18_streams_cleanup(cx, 1);
-free_irq:
- free_irq(cx->pci_dev->irq, (void *)cx);
-free_i2c:
- exit_cx18_i2c(cx);
-free_map:
- cx18_iounmap(cx);
-free_mem:
- release_mem_region(cx->base_addr, CX18_MEM_SIZE);
-free_workqueues:
- destroy_workqueue(cx->in_work_queue);
-err:
- if (retval == 0)
- retval = -ENODEV;
- CX18_ERR("Error %d on initialization\n", retval);
-
- v4l2_device_unregister(&cx->v4l2_dev);
- kfree(cx);
- return retval;
-}
-
-int cx18_init_on_first_open(struct cx18 *cx)
-{
- int video_input;
- int fw_retry_count = 3;
- struct v4l2_frequency vf;
- struct cx18_open_id fh;
- v4l2_std_id std;
-
- fh.cx = cx;
-
- if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
- return -ENXIO;
-
- if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
- return 0;
-
- while (--fw_retry_count > 0) {
- /* load firmware */
- if (cx18_firmware_init(cx) == 0)
- break;
- if (fw_retry_count > 1)
- CX18_WARN("Retry loading firmware\n");
- }
-
- if (fw_retry_count == 0) {
- set_bit(CX18_F_I_FAILED, &cx->i_flags);
- return -ENXIO;
- }
- set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
-
- /*
- * Init the firmware twice to work around a silicon bug
- * with the digital TS.
- *
- * The second firmware load requires us to normalize the APU state,
- * or the audio for the first analog capture will be badly incorrect.
- *
- * I can't seem to call APU_RESETAI and have it succeed without the
- * APU capturing audio, so we start and stop it here to do the reset
- */
-
- /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
- cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
- cx18_vapi(cx, CX18_APU_RESETAI, 0);
- cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
-
- fw_retry_count = 3;
- while (--fw_retry_count > 0) {
- /* load firmware */
- if (cx18_firmware_init(cx) == 0)
- break;
- if (fw_retry_count > 1)
- CX18_WARN("Retry loading firmware\n");
- }
-
- if (fw_retry_count == 0) {
- set_bit(CX18_F_I_FAILED, &cx->i_flags);
- return -ENXIO;
- }
-
- /*
- * The second firmware load requires us to normalize the APU state,
- * or the audio for the first analog capture will be badly incorrect.
- *
- * I can't seem to call APU_RESETAI and have it succeed without the
- * APU capturing audio, so we start and stop it here to do the reset
- */
-
- /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
- cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
- cx18_vapi(cx, CX18_APU_RESETAI, 0);
- cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
-
- /* Init the A/V decoder, if it hasn't been already */
- v4l2_subdev_call(cx->sd_av, core, load_fw);
-
- vf.tuner = 0;
- vf.type = V4L2_TUNER_ANALOG_TV;
- vf.frequency = 6400; /* the tuner 'baseline' frequency */
-
- /* Set initial frequency. For PAL/SECAM broadcasts no
- 'default' channel exists AFAIK. */
- if (cx->std == V4L2_STD_NTSC_M_JP)
- vf.frequency = 1460; /* ch. 1 91250*16/1000 */
- else if (cx->std & V4L2_STD_NTSC_M)
- vf.frequency = 1076; /* ch. 4 67250*16/1000 */
-
- video_input = cx->active_input;
- cx->active_input++; /* Force update of input */
- cx18_s_input(NULL, &fh, video_input);
-
- /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
- in one place. */
- cx->std++; /* Force full standard initialization */
- std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
- cx18_s_std(NULL, &fh, &std);
- cx18_s_frequency(NULL, &fh, &vf);
- return 0;
-}
-
-static void cx18_cancel_in_work_orders(struct cx18 *cx)
-{
- int i;
- for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
- cancel_work_sync(&cx->in_work_order[i].work);
-}
-
-static void cx18_cancel_out_work_orders(struct cx18 *cx)
-{
- int i;
- for (i = 0; i < CX18_MAX_STREAMS; i++)
- if (&cx->streams[i].video_dev != NULL)
- cancel_work_sync(&cx->streams[i].out_work_order);
-}
-
-static void cx18_remove(struct pci_dev *pci_dev)
-{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
- struct cx18 *cx = to_cx18(v4l2_dev);
- int i;
-
- CX18_DEBUG_INFO("Removing Card\n");
-
- flush_request_modules(cx);
-
- /* Stop all captures */
- CX18_DEBUG_INFO("Stopping all streams\n");
- if (atomic_read(&cx->tot_capturing) > 0)
- cx18_stop_all_captures(cx);
-
- /* Stop interrupts that cause incoming work to be queued */
- cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
-
- /* Incoming work can cause outgoing work, so clean up incoming first */
- cx18_cancel_in_work_orders(cx);
- cx18_cancel_out_work_orders(cx);
-
- /* Stop ack interrupts that may have been needed for work to finish */
- cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
-
- cx18_halt_firmware(cx);
-
- destroy_workqueue(cx->in_work_queue);
-
- cx18_streams_cleanup(cx, 1);
-
- exit_cx18_i2c(cx);
-
- free_irq(cx->pci_dev->irq, (void *)cx);
-
- cx18_iounmap(cx);
-
- release_mem_region(cx->base_addr, CX18_MEM_SIZE);
-
- pci_disable_device(cx->pci_dev);
-
- if (cx->vbi.sliced_mpeg_data[0] != NULL)
- for (i = 0; i < CX18_VBI_FRAMES; i++)
- kfree(cx->vbi.sliced_mpeg_data[i]);
-
- v4l2_ctrl_handler_free(&cx->av_state.hdl);
-
- CX18_INFO("Removed %s\n", cx->card_name);
-
- v4l2_device_unregister(v4l2_dev);
- kfree(cx);
-}
-
-
-/* define a pci_driver for card detection */
-static struct pci_driver cx18_pci_driver = {
- .name = "cx18",
- .id_table = cx18_pci_tbl,
- .probe = cx18_probe,
- .remove = cx18_remove,
-};
-
-static int __init module_start(void)
-{
- printk(KERN_INFO "cx18: Start initialization, version %s\n",
- CX18_VERSION);
-
- /* Validate parameters */
- if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
- printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
- CX18_MAX_CARDS - 1);
- return -1;
- }
-
- if (cx18_debug < 0 || cx18_debug > 511) {
- cx18_debug = 0;
- printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
- }
-
- if (pci_register_driver(&cx18_pci_driver)) {
- printk(KERN_ERR "cx18: Error detecting PCI card\n");
- return -ENODEV;
- }
- printk(KERN_INFO "cx18: End initialization\n");
- return 0;
-}
-
-static void __exit module_cleanup(void)
-{
- pci_unregister_driver(&cx18_pci_driver);
-}
-
-module_init(module_start);
-module_exit(module_cleanup);
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
deleted file mode 100644
index f41922bd4020..000000000000
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * cx18 functions for DVB support
- *
- * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
- *
- * 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 "cx18-version.h"
-#include "cx18-dvb.h"
-#include "cx18-io.h"
-#include "cx18-queue.h"
-#include "cx18-streams.h"
-#include "cx18-cards.h"
-#include "cx18-gpio.h"
-#include "s5h1409.h"
-#include "mxl5005s.h"
-#include "s5h1411.h"
-#include "tda18271.h"
-#include "zl10353.h"
-
-#include <linux/firmware.h>
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "tuner-xc2028.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
-#define CX18_CLOCK_ENABLE2 0xc71024
-#define CX18_DMUX_CLK_MASK 0x0080
-
-/*
- * CX18_CARD_HVR_1600_ESMT
- * CX18_CARD_HVR_1600_SAMSUNG
- */
-
-static struct mxl5005s_config hauppauge_hvr1600_tuner = {
- .i2c_address = 0xC6 >> 1,
- .if_freq = IF_FREQ_5380000HZ,
- .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,
- .qam_gain = 0x02,
- .AgcMasterByte = 0x00,
-};
-
-static struct s5h1409_config hauppauge_hvr1600_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_ON,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
- .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE
-};
-
-/*
- * CX18_CARD_HVR_1600_S5H1411
- */
-static struct s5h1411_config hcw_s5h1411_config = {
- .output_mode = S5H1411_SERIAL_OUTPUT,
- .gpio = S5H1411_GPIO_OFF,
- .vsb_if = S5H1411_IF_44000,
- .qam_if = S5H1411_IF_4000,
- .inversion = S5H1411_INVERSION_ON,
- .status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct tda18271_std_map hauppauge_tda18271_std_map = {
- .atsc_6 = { .if_freq = 5380, .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 hauppauge_tda18271_config = {
- .std_map = &hauppauge_tda18271_std_map,
- .gate = TDA18271_GATE_DIGITAL,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-/*
- * CX18_CARD_LEADTEK_DVR3100H
- */
-/* Information/confirmation of proper config values provided by Terry Wu */
-static struct zl10353_config leadtek_dvr3100h_demod = {
- .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
- .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
- .parallel_ts = 1, /* Not a serial TS */
- .no_tuner = 1, /* XC3028 is not behind the gate */
- .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
-};
-
-/*
- * CX18_CARD_YUAN_MPC718
- */
-/*
- * Due to
- *
- * 1. an absence of information on how to prgram the MT352
- * 2. the Linux mt352 module pushing MT352 initialzation off onto us here
- *
- * We have to use an init sequence that *you* must extract from the Windows
- * driver (yuanrap.sys) and which we load as a firmware.
- *
- * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual
- * with chip programming details, then I can remove this annoyance.
- */
-static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
- const struct firmware **fw)
-{
- struct cx18 *cx = stream->cx;
- const char *fn = "dvb-cx18-mpc718-mt352.fw";
- int ret;
-
- ret = request_firmware(fw, fn, &cx->pci_dev->dev);
- if (ret)
- CX18_ERR("Unable to open firmware file %s\n", fn);
- else {
- size_t sz = (*fw)->size;
- if (sz < 2 || sz > 64 || (sz % 2) != 0) {
- CX18_ERR("Firmware %s has a bad size: %lu bytes\n",
- fn, (unsigned long) sz);
- ret = -EILSEQ;
- release_firmware(*fw);
- *fw = NULL;
- }
- }
-
- if (ret) {
- CX18_ERR("The MPC718 board variant with the MT352 DVB-T"
- "demodualtor will not work without it\n");
- CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware "
- "mpc718' if you need the firmware\n");
- }
- return ret;
-}
-
-static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
-{
- struct cx18_dvb *dvb = container_of(fe->dvb,
- struct cx18_dvb, dvb_adapter);
- struct cx18_stream *stream = dvb->stream;
- const struct firmware *fw = NULL;
- int ret;
- int i;
- u8 buf[3];
-
- ret = yuan_mpc718_mt352_reqfw(stream, &fw);
- if (ret)
- return ret;
-
- /* Loop through all the register-value pairs in the firmware file */
- for (i = 0; i < fw->size; i += 2) {
- buf[0] = fw->data[i];
- /* Intercept a few registers we want to set ourselves */
- switch (buf[0]) {
- case TRL_NOMINAL_RATE_0:
- /* Set our custom OFDM bandwidth in the case below */
- break;
- case TRL_NOMINAL_RATE_1:
- /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */
- /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */
- /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */
- buf[1] = 0x72;
- buf[2] = 0x49;
- mt352_write(fe, buf, 3);
- break;
- case INPUT_FREQ_0:
- /* Set our custom IF in the case below */
- break;
- case INPUT_FREQ_1:
- /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */
- buf[1] = 0x31;
- buf[2] = 0xc0;
- mt352_write(fe, buf, 3);
- break;
- default:
- /* Pass through the register-value pair from the fw */
- buf[1] = fw->data[i+1];
- mt352_write(fe, buf, 2);
- break;
- }
- }
-
- buf[0] = (u8) TUNER_GO;
- buf[1] = 0x01; /* Go */
- mt352_write(fe, buf, 2);
- release_firmware(fw);
- return 0;
-}
-
-static struct mt352_config yuan_mpc718_mt352_demod = {
- .demod_address = 0x1e >> 1,
- .adc_clock = 20480, /* 20.480 MHz */
- .if2 = 4560, /* 4.560 MHz */
- .no_tuner = 1, /* XC3028 is not behind the gate */
- .demod_init = yuan_mpc718_mt352_init,
-};
-
-static struct zl10353_config yuan_mpc718_zl10353_demod = {
- .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
- .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
- .parallel_ts = 1, /* Not a serial TS */
- .no_tuner = 1, /* XC3028 is not behind the gate */
- .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
-};
-
-static struct zl10353_config gotview_dvd3_zl10353_demod = {
- .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
- .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
- .parallel_ts = 1, /* Not a serial TS */
- .no_tuner = 1, /* XC3028 is not behind the gate */
- .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
-};
-
-static int dvb_register(struct cx18_stream *stream);
-
-/* Kernel DVB framework calls this when the feed needs to start.
- * The CX18 framework should enable the transport DMA handling
- * and queue processing.
- */
-static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
- struct cx18 *cx;
- int ret;
- u32 v;
-
- if (!stream)
- return -EINVAL;
-
- cx = stream->cx;
- CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
- feed->pid, feed->index);
-
- mutex_lock(&cx->serialize_lock);
- ret = cx18_init_on_first_open(cx);
- mutex_unlock(&cx->serialize_lock);
- if (ret) {
- CX18_ERR("Failed to initialize firmware starting DVB feed\n");
- return ret;
- }
- ret = -EINVAL;
-
- switch (cx->card->type) {
- case CX18_CARD_HVR_1600_ESMT:
- case CX18_CARD_HVR_1600_SAMSUNG:
- case CX18_CARD_HVR_1600_S5H1411:
- v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
- v |= 0x00400000; /* Serial Mode */
- v |= 0x00002000; /* Data Length - Byte */
- v |= 0x00010000; /* Error - Polarity */
- v |= 0x00020000; /* Error - Passthru */
- v |= 0x000c0000; /* Error - Ignore */
- cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
- break;
-
- case CX18_CARD_LEADTEK_DVR3100H:
- case CX18_CARD_YUAN_MPC718:
- case CX18_CARD_GOTVIEW_PCI_DVD3:
- default:
- /* Assumption - Parallel transport - Signalling
- * undefined or default.
- */
- break;
- }
-
- if (!demux->dmx.frontend)
- return -EINVAL;
-
- mutex_lock(&stream->dvb->feedlock);
- if (stream->dvb->feeding++ == 0) {
- CX18_DEBUG_INFO("Starting Transport DMA\n");
- mutex_lock(&cx->serialize_lock);
- set_bit(CX18_F_S_STREAMING, &stream->s_flags);
- ret = cx18_start_v4l2_encode_stream(stream);
- if (ret < 0) {
- CX18_DEBUG_INFO("Failed to start Transport DMA\n");
- stream->dvb->feeding--;
- if (stream->dvb->feeding == 0)
- clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
- }
- mutex_unlock(&cx->serialize_lock);
- } else
- ret = 0;
- mutex_unlock(&stream->dvb->feedlock);
-
- return ret;
-}
-
-/* Kernel DVB framework calls this when the feed needs to stop. */
-static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
- struct cx18 *cx;
- int ret = -EINVAL;
-
- if (stream) {
- cx = stream->cx;
- CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
- feed->pid, feed->index);
-
- mutex_lock(&stream->dvb->feedlock);
- if (--stream->dvb->feeding == 0) {
- CX18_DEBUG_INFO("Stopping Transport DMA\n");
- mutex_lock(&cx->serialize_lock);
- ret = cx18_stop_v4l2_encode_stream(stream, 0);
- mutex_unlock(&cx->serialize_lock);
- } else
- ret = 0;
- mutex_unlock(&stream->dvb->feedlock);
- }
-
- return ret;
-}
-
-int cx18_dvb_register(struct cx18_stream *stream)
-{
- struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = stream->dvb;
- struct dvb_adapter *dvb_adapter;
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
- int ret;
-
- if (!dvb)
- return -EINVAL;
-
- dvb->enabled = 0;
- dvb->stream = stream;
-
- ret = dvb_register_adapter(&dvb->dvb_adapter,
- CX18_DRIVER_NAME,
- THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
- if (ret < 0)
- goto err_out;
-
- dvb_adapter = &dvb->dvb_adapter;
-
- dvbdemux = &dvb->demux;
-
- dvbdemux->priv = (void *)stream;
-
- dvbdemux->filternum = 256;
- dvbdemux->feednum = 256;
- dvbdemux->start_feed = cx18_dvb_start_feed;
- dvbdemux->stop_feed = cx18_dvb_stop_feed;
- dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
- DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
- ret = dvb_dmx_init(dvbdemux);
- if (ret < 0)
- goto err_dvb_unregister_adapter;
-
- dmx = &dvbdemux->dmx;
-
- dvb->hw_frontend.source = DMX_FRONTEND_0;
- dvb->mem_frontend.source = DMX_MEMORY_FE;
- dvb->dmxdev.filternum = 256;
- dvb->dmxdev.demux = dmx;
-
- ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
- if (ret < 0)
- goto err_dvb_dmx_release;
-
- ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
- if (ret < 0)
- goto err_dvb_dmxdev_release;
-
- ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
- if (ret < 0)
- goto err_remove_hw_frontend;
-
- ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
- if (ret < 0)
- goto err_remove_mem_frontend;
-
- ret = dvb_register(stream);
- if (ret < 0)
- goto err_disconnect_frontend;
-
- dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
-
- CX18_INFO("DVB Frontend registered\n");
- CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
- stream->dvb->dvb_adapter.num, stream->name,
- stream->buffers, stream->buf_size/1024,
- (stream->buf_size * 100 / 1024) % 100);
-
- mutex_init(&dvb->feedlock);
- dvb->enabled = 1;
- return ret;
-
-err_disconnect_frontend:
- dmx->disconnect_frontend(dmx);
-err_remove_mem_frontend:
- dmx->remove_frontend(dmx, &dvb->mem_frontend);
-err_remove_hw_frontend:
- dmx->remove_frontend(dmx, &dvb->hw_frontend);
-err_dvb_dmxdev_release:
- dvb_dmxdev_release(&dvb->dmxdev);
-err_dvb_dmx_release:
- dvb_dmx_release(dvbdemux);
-err_dvb_unregister_adapter:
- dvb_unregister_adapter(dvb_adapter);
-err_out:
- return ret;
-}
-
-void cx18_dvb_unregister(struct cx18_stream *stream)
-{
- struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = stream->dvb;
- struct dvb_adapter *dvb_adapter;
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
-
- CX18_INFO("unregister DVB\n");
-
- if (dvb == NULL || !dvb->enabled)
- return;
-
- dvb_adapter = &dvb->dvb_adapter;
- dvbdemux = &dvb->demux;
- dmx = &dvbdemux->dmx;
-
- dmx->close(dmx);
- dvb_net_release(&dvb->dvbnet);
- dmx->remove_frontend(dmx, &dvb->mem_frontend);
- dmx->remove_frontend(dmx, &dvb->hw_frontend);
- dvb_dmxdev_release(&dvb->dmxdev);
- dvb_dmx_release(dvbdemux);
- dvb_unregister_frontend(dvb->fe);
- dvb_frontend_detach(dvb->fe);
- dvb_unregister_adapter(dvb_adapter);
-}
-
-/* All the DVB attach calls go here, this function get's modified
- * for each new card. cx18_dvb_start_feed() will also need changes.
- */
-static int dvb_register(struct cx18_stream *stream)
-{
- struct cx18_dvb *dvb = stream->dvb;
- struct cx18 *cx = stream->cx;
- int ret = 0;
-
- switch (cx->card->type) {
- case CX18_CARD_HVR_1600_ESMT:
- case CX18_CARD_HVR_1600_SAMSUNG:
- dvb->fe = dvb_attach(s5h1409_attach,
- &hauppauge_hvr1600_config,
- &cx->i2c_adap[0]);
- if (dvb->fe != NULL) {
- dvb_attach(mxl5005s_attach, dvb->fe,
- &cx->i2c_adap[0],
- &hauppauge_hvr1600_tuner);
- ret = 0;
- }
- break;
- case CX18_CARD_HVR_1600_S5H1411:
- dvb->fe = dvb_attach(s5h1411_attach,
- &hcw_s5h1411_config,
- &cx->i2c_adap[0]);
- if (dvb->fe != NULL)
- dvb_attach(tda18271_attach, dvb->fe,
- 0x60, &cx->i2c_adap[0],
- &hauppauge_tda18271_config);
- break;
- case CX18_CARD_LEADTEK_DVR3100H:
- dvb->fe = dvb_attach(zl10353_attach,
- &leadtek_dvr3100h_demod,
- &cx->i2c_adap[1]);
- if (dvb->fe != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &cx->i2c_adap[1],
- .i2c_addr = 0xc2 >> 1,
- .ctrl = NULL,
- };
- static struct xc2028_ctrl ctrl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_ZARLINK456,
- .type = XC2028_AUTO,
- };
-
- fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctrl);
- }
- break;
- case CX18_CARD_YUAN_MPC718:
- /*
- * TODO
- * Apparently, these cards also could instead have a
- * DiBcom demod supported by one of the db7000 drivers
- */
- dvb->fe = dvb_attach(mt352_attach,
- &yuan_mpc718_mt352_demod,
- &cx->i2c_adap[1]);
- if (dvb->fe == NULL)
- dvb->fe = dvb_attach(zl10353_attach,
- &yuan_mpc718_zl10353_demod,
- &cx->i2c_adap[1]);
- if (dvb->fe != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &cx->i2c_adap[1],
- .i2c_addr = 0xc2 >> 1,
- .ctrl = NULL,
- };
- static struct xc2028_ctrl ctrl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_ZARLINK456,
- .type = XC2028_AUTO,
- };
-
- fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctrl);
- }
- break;
- case CX18_CARD_GOTVIEW_PCI_DVD3:
- dvb->fe = dvb_attach(zl10353_attach,
- &gotview_dvd3_zl10353_demod,
- &cx->i2c_adap[1]);
- if (dvb->fe != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &cx->i2c_adap[1],
- .i2c_addr = 0xc2 >> 1,
- .ctrl = NULL,
- };
- static struct xc2028_ctrl ctrl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_ZARLINK456,
- .type = XC2028_AUTO,
- };
-
- fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctrl);
- }
- break;
- default:
- /* No Digital Tv Support */
- break;
- }
-
- if (dvb->fe == NULL) {
- CX18_ERR("frontend initialization failed\n");
- return -1;
- }
-
- dvb->fe->callback = cx18_reset_tuner_gpio;
-
- ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
- if (ret < 0) {
- if (dvb->fe->ops.release)
- dvb->fe->ops.release(dvb->fe);
- return ret;
- }
-
- /*
- * The firmware seems to enable the TS DMUX clock
- * under various circumstances. However, since we know we
- * might use it, let's just turn it on ourselves here.
- */
- cx18_write_reg_expect(cx,
- (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
- CX18_CLOCK_ENABLE2,
- CX18_DMUX_CLK_MASK,
- (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
-
- return ret;
-}
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
deleted file mode 100644
index b85c292a849a..000000000000
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * cx18 firmware functions
- *
- * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
- *
- * 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
- */
-
-#include "cx18-driver.h"
-#include "cx18-io.h"
-#include "cx18-scb.h"
-#include "cx18-irq.h"
-#include "cx18-firmware.h"
-#include "cx18-cards.h"
-#include <linux/firmware.h>
-
-#define CX18_PROC_SOFT_RESET 0xc70010
-#define CX18_DDR_SOFT_RESET 0xc70014
-#define CX18_CLOCK_SELECT1 0xc71000
-#define CX18_CLOCK_SELECT2 0xc71004
-#define CX18_HALF_CLOCK_SELECT1 0xc71008
-#define CX18_HALF_CLOCK_SELECT2 0xc7100C
-#define CX18_CLOCK_POLARITY1 0xc71010
-#define CX18_CLOCK_POLARITY2 0xc71014
-#define CX18_ADD_DELAY_ENABLE1 0xc71018
-#define CX18_ADD_DELAY_ENABLE2 0xc7101C
-#define CX18_CLOCK_ENABLE1 0xc71020
-#define CX18_CLOCK_ENABLE2 0xc71024
-
-#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
-
-#define CX18_FAST_CLOCK_PLL_INT 0xc78000
-#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
-#define CX18_FAST_CLOCK_PLL_POST 0xc78008
-#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
-#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
-
-#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
-#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
-#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
-#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
-#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
-#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
-#define CX18_PLL_POWER_DOWN 0xc78088
-#define CX18_SW1_INT_STATUS 0xc73104
-#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
-#define CX18_SW2_INT_SET 0xc73140
-#define CX18_SW2_INT_STATUS 0xc73144
-#define CX18_ADEC_CONTROL 0xc78120
-
-#define CX18_DDR_REQUEST_ENABLE 0xc80000
-#define CX18_DDR_CHIP_CONFIG 0xc80004
-#define CX18_DDR_REFRESH 0xc80008
-#define CX18_DDR_TIMING1 0xc8000C
-#define CX18_DDR_TIMING2 0xc80010
-#define CX18_DDR_POWER_REG 0xc8001C
-
-#define CX18_DDR_TUNE_LANE 0xc80048
-#define CX18_DDR_INITIAL_EMRS 0xc80054
-#define CX18_DDR_MB_PER_ROW_7 0xc8009C
-#define CX18_DDR_BASE_63_ADDR 0xc804FC
-
-#define CX18_WMB_CLIENT02 0xc90108
-#define CX18_WMB_CLIENT05 0xc90114
-#define CX18_WMB_CLIENT06 0xc90118
-#define CX18_WMB_CLIENT07 0xc9011C
-#define CX18_WMB_CLIENT08 0xc90120
-#define CX18_WMB_CLIENT09 0xc90124
-#define CX18_WMB_CLIENT10 0xc90128
-#define CX18_WMB_CLIENT11 0xc9012C
-#define CX18_WMB_CLIENT12 0xc90130
-#define CX18_WMB_CLIENT13 0xc90134
-#define CX18_WMB_CLIENT14 0xc90138
-
-#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
-
-#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
-#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
-
-struct cx18_apu_rom_seghdr {
- u32 sync1;
- u32 sync2;
- u32 addr;
- u32 size;
-};
-
-static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
-{
- const struct firmware *fw = NULL;
- int i, j;
- unsigned size;
- u32 __iomem *dst = (u32 __iomem *)mem;
- const u32 *src;
-
- if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
- CX18_ERR("Unable to open firmware %s\n", fn);
- CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
- return -ENOMEM;
- }
-
- src = (const u32 *)fw->data;
-
- for (i = 0; i < fw->size; i += 4096) {
- cx18_setup_page(cx, i);
- for (j = i; j < fw->size && j < i + 4096; j += 4) {
- /* no need for endianness conversion on the ppc */
- cx18_raw_writel(cx, *src, dst);
- if (cx18_raw_readl(cx, dst) != *src) {
- CX18_ERR("Mismatch at offset %x\n", i);
- release_firmware(fw);
- cx18_setup_page(cx, 0);
- return -EIO;
- }
- dst++;
- src++;
- }
- }
- if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
- CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
- size = fw->size;
- release_firmware(fw);
- cx18_setup_page(cx, SCB_OFFSET);
- return size;
-}
-
-static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
- u32 *entry_addr)
-{
- const struct firmware *fw = NULL;
- int i, j;
- unsigned size;
- const u32 *src;
- struct cx18_apu_rom_seghdr seghdr;
- const u8 *vers;
- u32 offset = 0;
- u32 apu_version = 0;
- int sz;
-
- if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
- CX18_ERR("unable to open firmware %s\n", fn);
- CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
- cx18_setup_page(cx, 0);
- return -ENOMEM;
- }
-
- *entry_addr = 0;
- src = (const u32 *)fw->data;
- vers = fw->data + sizeof(seghdr);
- sz = fw->size;
-
- apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
- while (offset + sizeof(seghdr) < fw->size) {
- const u32 *shptr = src + offset / 4;
-
- seghdr.sync1 = le32_to_cpu(shptr[0]);
- seghdr.sync2 = le32_to_cpu(shptr[1]);
- seghdr.addr = le32_to_cpu(shptr[2]);
- seghdr.size = le32_to_cpu(shptr[3]);
-
- offset += sizeof(seghdr);
- if (seghdr.sync1 != APU_ROM_SYNC1 ||
- seghdr.sync2 != APU_ROM_SYNC2) {
- offset += seghdr.size;
- continue;
- }
- CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
- seghdr.addr + seghdr.size - 1);
- if (*entry_addr == 0)
- *entry_addr = seghdr.addr;
- if (offset + seghdr.size > sz)
- break;
- for (i = 0; i < seghdr.size; i += 4096) {
- cx18_setup_page(cx, seghdr.addr + i);
- for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
- /* no need for endianness conversion on the ppc */
- cx18_raw_writel(cx, src[(offset + j) / 4],
- dst + seghdr.addr + j);
- if (cx18_raw_readl(cx, dst + seghdr.addr + j)
- != src[(offset + j) / 4]) {
- CX18_ERR("Mismatch at offset %x\n",
- offset + j);
- release_firmware(fw);
- cx18_setup_page(cx, 0);
- return -EIO;
- }
- }
- }
- offset += seghdr.size;
- }
- if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
- CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
- fn, apu_version, fw->size);
- size = fw->size;
- release_firmware(fw);
- cx18_setup_page(cx, 0);
- return size;
-}
-
-void cx18_halt_firmware(struct cx18 *cx)
-{
- CX18_DEBUG_INFO("Preparing for firmware halt.\n");
- cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
- 0x0000000F, 0x000F000F);
- cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
- 0x00000002, 0x00020002);
-}
-
-void cx18_init_power(struct cx18 *cx, int lowpwr)
-{
- /* power-down Spare and AOM PLLs */
- /* power-up fast, slow and mpeg PLLs */
- cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
-
- /* ADEC out of sleep */
- cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
- 0x00000000, 0x00020002);
-
- /*
- * The PLL parameters are based on the external crystal frequency that
- * would ideally be:
- *
- * NTSC Color subcarrier freq * 8 =
- * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
- *
- * The accidents of history and rationale that explain from where this
- * combination of magic numbers originate can be found in:
- *
- * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
- * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
- *
- * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
- * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
- *
- * As Mike Bradley has rightly pointed out, it's not the exact crystal
- * frequency that matters, only that all parts of the driver and
- * firmware are using the same value (close to the ideal value).
- *
- * Since I have a strong suspicion that, if the firmware ever assumes a
- * crystal value at all, it will assume 28.636360 MHz, the crystal
- * freq used in calculations in this driver will be:
- *
- * xtal_freq = 28.636360 MHz
- *
- * an error of less than 0.13 ppm which is way, way better than any off
- * the shelf crystal will have for accuracy anyway.
- *
- * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
- *
- * Many thanks to Jeff Campbell and Mike Bradley for their extensive
- * investigation, experimentation, testing, and suggested solutions of
- * of audio/video sync problems with SVideo and CVBS captures.
- */
-
- /* the fast clock is at 200/245 MHz */
- /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
- /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
- cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
- cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
- CX18_FAST_CLOCK_PLL_FRAC);
-
- cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
- cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
- cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
-
- /* set slow clock to 125/120 MHz */
- /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
- /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
- cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
- cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
- CX18_SLOW_CLOCK_PLL_FRAC);
- cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
-
- /* mpeg clock pll 54MHz */
- /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
- cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
- cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
- cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
-
- /* Defaults */
- /* APU = SC or SC/2 = 125/62.5 */
- /* EPU = SC = 125 */
- /* DDR = FC = 180 */
- /* ENC = SC = 125 */
- /* AI1 = SC = 125 */
- /* VIM2 = disabled */
- /* PCI = FC/2 = 90 */
- /* AI2 = disabled */
- /* DEMUX = disabled */
- /* AO = SC/2 = 62.5 */
- /* SER = 54MHz */
- /* VFC = disabled */
- /* USB = disabled */
-
- if (lowpwr) {
- cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
- 0x00000020, 0xFFFFFFFF);
- cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
- 0x00000004, 0xFFFFFFFF);
- } else {
- /* This doesn't explicitly set every clock select */
- cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
- 0x00000004, 0x00060006);
- cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
- 0x00000006, 0x00060006);
- }
-
- cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
- 0x00000002, 0xFFFFFFFF);
- cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
- 0x00000104, 0xFFFFFFFF);
- cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
- 0x00009026, 0xFFFFFFFF);
- cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
- 0x00003105, 0xFFFFFFFF);
-}
-
-void cx18_init_memory(struct cx18 *cx)
-{
- cx18_msleep_timeout(10, 0);
- cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
- 0x00000000, 0x00010001);
- cx18_msleep_timeout(10, 0);
-
- cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
-
- cx18_msleep_timeout(10, 0);
-
- cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
- cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
- cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
-
- cx18_msleep_timeout(10, 0);
-
- /* Initialize DQS pad time */
- cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
- cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
-
- cx18_msleep_timeout(10, 0);
-
- cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
- 0x00000000, 0x00020002);
- cx18_msleep_timeout(10, 0);
-
- /* use power-down mode when idle */
- cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
-
- cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
- 0x00000001, 0x00010001);
-
- cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
- cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
-
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */
- cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */
-}
-
-int cx18_firmware_init(struct cx18 *cx)
-{
- u32 fw_entry_addr;
- int sz, retries;
- u32 api_args[MAX_MB_ARGUMENTS];
-
- /* Allow chip to control CLKRUN */
- cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
-
- /* Stop the firmware */
- cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
- 0x0000000F, 0x000F000F);
-
- cx18_msleep_timeout(1, 0);
-
- /* If the CPU is still running */
- if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
- CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
- return -EIO;
- }
-
- cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
- cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
-
- sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
- if (sz <= 0)
- return sz;
-
- /* The SCB & IPC area *must* be correct before starting the firmwares */
- cx18_init_scb(cx);
-
- fw_entry_addr = 0;
- sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
- &fw_entry_addr);
- if (sz <= 0)
- return sz;
-
- /* Start the CPU. The CPU will take care of the APU for us. */
- cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
- 0x00000000, 0x00080008);
-
- /* Wait up to 500 ms for the APU to come out of reset */
- for (retries = 0;
- retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
- retries++)
- cx18_msleep_timeout(10, 0);
-
- cx18_msleep_timeout(200, 0);
-
- if (retries == 50 &&
- (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
- CX18_ERR("Could not start the CPU\n");
- return -EIO;
- }
-
- /*
- * The CPU had once before set up to receive an interrupt for it's
- * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an
- * interrupt when it sends us an ack, but by the time we process it,
- * that flag in the SW2 status register has been cleared by the CPU
- * firmware. We'll prevent that not so useful condition from happening
- * by clearing the CPU's interrupt enables for Ack IRQ's we want to
- * process.
- */
- cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
-
- /* Try a benign command to see if the CPU is alive and well */
- sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
- if (sz < 0)
- return sz;
-
- /* initialize GPIO */
- cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
- return 0;
-}
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
deleted file mode 100644
index 446f692aabb7..000000000000
--- a/drivers/media/video/cx231xx/Kconfig
+++ /dev/null
@@ -1,51 +0,0 @@
-config VIDEO_CX231XX
- tristate "Conexant cx231xx USB video capture support"
- depends on VIDEO_DEV && I2C
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- depends on RC_CORE
- select VIDEOBUF_VMALLOC
- select VIDEO_CX25840
- select VIDEO_CX2341X
-
- ---help---
- This is a video4linux driver for Conexant 231xx USB based TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called cx231xx
-
-config VIDEO_CX231XX_RC
- bool "Conexant cx231xx Remote Controller additional support"
- depends on RC_CORE
- depends on VIDEO_CX231XX
- default y
- ---help---
- cx231xx hardware has a builtin RX/TX support. However, a few
- designs opted to not use it, but, instead, some other hardware.
- This module enables the usage of those other hardware, like the
- ones used with ISDB-T boards.
-
- On most cases, all you need for IR is mceusb module.
-
-config VIDEO_CX231XX_ALSA
- tristate "Conexant Cx231xx ALSA audio module"
- depends on VIDEO_CX231XX && SND
- select SND_PCM
-
- ---help---
- This is an ALSA driver for Cx231xx USB based TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called cx231xx-alsa
-
-config VIDEO_CX231XX_DVB
- tristate "DVB/ATSC Support for Cx231xx based TV cards"
- depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS
- select VIDEOBUF_DVB
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select DVB_MB86A20S if !DVB_FE_CUSTOMISE
-
- ---help---
- This adds support for DVB cards based on the
- Conexant cx231xx chips.
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
deleted file mode 100644
index b3348975c7c2..000000000000
--- a/drivers/media/video/cx231xx/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o
-cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
-cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o
-
-cx231xx-alsa-objs := cx231xx-audio.o
-
-obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o
-obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o
-obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-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 += -Idrivers/media/dvb/dvb-usb
-
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
deleted file mode 100644
index ce2f62238a19..000000000000
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ /dev/null
@@ -1,2195 +0,0 @@
-/*
- *
- * Support for a cx23417 mpeg encoder via cx231xx host port.
- *
- * (c) 2004 Jelle Foks <jelle@foks.us>
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
- * (c) 2008 Steven Toth <stoth@linuxtv.org>
- * - CX23885/7/8 support
- *
- * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/cx2341x.h>
-#include <linux/usb.h>
-
-#include "cx231xx.h"
-/*#include "cx23885-ioctl.h"*/
-
-#define CX231xx_FIRM_IMAGE_SIZE 376836
-#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
-
-/* for polaris ITVC */
-#define ITVC_WRITE_DIR 0x03FDFC00
-#define ITVC_READ_DIR 0x0001FC00
-
-#define MCI_MEMORY_DATA_BYTE0 0x00
-#define MCI_MEMORY_DATA_BYTE1 0x08
-#define MCI_MEMORY_DATA_BYTE2 0x10
-#define MCI_MEMORY_DATA_BYTE3 0x18
-
-#define MCI_MEMORY_ADDRESS_BYTE2 0x20
-#define MCI_MEMORY_ADDRESS_BYTE1 0x28
-#define MCI_MEMORY_ADDRESS_BYTE0 0x30
-
-#define MCI_REGISTER_DATA_BYTE0 0x40
-#define MCI_REGISTER_DATA_BYTE1 0x48
-#define MCI_REGISTER_DATA_BYTE2 0x50
-#define MCI_REGISTER_DATA_BYTE3 0x58
-
-#define MCI_REGISTER_ADDRESS_BYTE0 0x60
-#define MCI_REGISTER_ADDRESS_BYTE1 0x68
-
-#define MCI_REGISTER_MODE 0x70
-
-/* Read and write modes for polaris ITVC */
-#define MCI_MODE_REGISTER_READ 0x000
-#define MCI_MODE_REGISTER_WRITE 0x100
-#define MCI_MODE_MEMORY_READ 0x000
-#define MCI_MODE_MEMORY_WRITE 0x4000
-
-static unsigned int mpegbufs = 8;
-module_param(mpegbufs, int, 0644);
-MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
-static unsigned int mpeglines = 128;
-module_param(mpeglines, int, 0644);
-MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
-static unsigned int mpeglinesize = 512;
-module_param(mpeglinesize, int, 0644);
-MODULE_PARM_DESC(mpeglinesize,
- "number of bytes in each line of an MPEG buffer, range 512-1024");
-
-static unsigned int v4l_debug = 1;
-module_param(v4l_debug, int, 0644);
-MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
-struct cx231xx_dmaqueue *dma_qq;
-#define dprintk(level, fmt, arg...)\
- do { if (v4l_debug >= level) \
- printk(KERN_INFO "%s: " fmt, \
- (dev) ? dev->name : "cx231xx[?]", ## arg); \
- } while (0)
-
-static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- }, {
- .name = "NTSC-JP",
- .id = V4L2_STD_NTSC_M_JP,
- }, {
- .name = "PAL-BG",
- .id = V4L2_STD_PAL_BG,
- }, {
- .name = "PAL-DK",
- .id = V4L2_STD_PAL_DK,
- }, {
- .name = "PAL-I",
- .id = V4L2_STD_PAL_I,
- }, {
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- }, {
- .name = "PAL-N",
- .id = V4L2_STD_PAL_N,
- }, {
- .name = "PAL-Nc",
- .id = V4L2_STD_PAL_Nc,
- }, {
- .name = "PAL-60",
- .id = V4L2_STD_PAL_60,
- }, {
- .name = "SECAM-L",
- .id = V4L2_STD_SECAM_L,
- }, {
- .name = "SECAM-DK",
- .id = V4L2_STD_SECAM_DK,
- }
-};
-
-/* ------------------------------------------------------------------ */
-enum cx231xx_capture_type {
- CX231xx_MPEG_CAPTURE,
- CX231xx_RAW_CAPTURE,
- CX231xx_RAW_PASSTHRU_CAPTURE
-};
-enum cx231xx_capture_bits {
- CX231xx_RAW_BITS_NONE = 0x00,
- CX231xx_RAW_BITS_YUV_CAPTURE = 0x01,
- CX231xx_RAW_BITS_PCM_CAPTURE = 0x02,
- CX231xx_RAW_BITS_VBI_CAPTURE = 0x04,
- CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
- CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10
-};
-enum cx231xx_capture_end {
- CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
- CX231xx_END_NOW, /* stop immediately, no irq */
-};
-enum cx231xx_framerate {
- CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
- CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */
-};
-enum cx231xx_stream_port {
- CX231xx_OUTPUT_PORT_MEMORY,
- CX231xx_OUTPUT_PORT_STREAMING,
- CX231xx_OUTPUT_PORT_SERIAL
-};
-enum cx231xx_data_xfer_status {
- CX231xx_MORE_BUFFERS_FOLLOW,
- CX231xx_LAST_BUFFER,
-};
-enum cx231xx_picture_mask {
- CX231xx_PICTURE_MASK_NONE,
- CX231xx_PICTURE_MASK_I_FRAMES,
- CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
- CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
-};
-enum cx231xx_vbi_mode_bits {
- CX231xx_VBI_BITS_SLICED,
- CX231xx_VBI_BITS_RAW,
-};
-enum cx231xx_vbi_insertion_bits {
- CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
- CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
- CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
- CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
- CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
-};
-enum cx231xx_dma_unit {
- CX231xx_DMA_BYTES,
- CX231xx_DMA_FRAMES,
-};
-enum cx231xx_dma_transfer_status_bits {
- CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
- CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
- CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
-};
-enum cx231xx_pause {
- CX231xx_PAUSE_ENCODING,
- CX231xx_RESUME_ENCODING,
-};
-enum cx231xx_copyright {
- CX231xx_COPYRIGHT_OFF,
- CX231xx_COPYRIGHT_ON,
-};
-enum cx231xx_notification_type {
- CX231xx_NOTIFICATION_REFRESH,
-};
-enum cx231xx_notification_status {
- CX231xx_NOTIFICATION_OFF,
- CX231xx_NOTIFICATION_ON,
-};
-enum cx231xx_notification_mailbox {
- CX231xx_NOTIFICATION_NO_MAILBOX = -1,
-};
-enum cx231xx_field1_lines {
- CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
- CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
- CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
-};
-enum cx231xx_field2_lines {
- CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
- CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
- CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
-};
-enum cx231xx_custom_data_type {
- CX231xx_CUSTOM_EXTENSION_USR_DATA,
- CX231xx_CUSTOM_PRIVATE_PACKET,
-};
-enum cx231xx_mute {
- CX231xx_UNMUTE,
- CX231xx_MUTE,
-};
-enum cx231xx_mute_video_mask {
- CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
- CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
- CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
-};
-enum cx231xx_mute_video_shift {
- CX231xx_MUTE_VIDEO_V_SHIFT = 8,
- CX231xx_MUTE_VIDEO_U_SHIFT = 16,
- CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
-};
-
-/* defines below are from ivtv-driver.h */
-#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
-
-/* Firmware API commands */
-#define IVTV_API_STD_TIMEOUT 500
-
-/* Registers */
-/* IVTV_REG_OFFSET */
-#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
-#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
-#define IVTV_REG_SPU (0x9050)
-#define IVTV_REG_HW_BLOCKS (0x9054)
-#define IVTV_REG_VPU (0x9058)
-#define IVTV_REG_APU (0xA064)
-
-/*
- * Bit definitions for MC417_RWD and MC417_OEN registers
- *
- * bits 31-16
- *+-----------+
- *| Reserved |
- *|+-----------+
- *| bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
- *|+-------+-------+-------+-------+-------+-------+-------+-------+
- *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
- *|+-------+-------+-------+-------+-------+-------+-------+-------+
- *| bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
- *|+-------+-------+-------+-------+-------+-------+-------+-------+
- *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
- *|+-------+-------+-------+-------+-------+-------+-------+-------+
- */
-#define MC417_MIWR 0x8000
-#define MC417_MIRD 0x4000
-#define MC417_MICS 0x2000
-#define MC417_MIRDY 0x1000
-#define MC417_MIADDR 0x0F00
-#define MC417_MIDATA 0x00FF
-
-
-/* Bit definitions for MC417_CTL register ****
- *bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
- *+--------+-------------+--------+--------------+------------+
- *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
- *+--------+-------------+--------+--------------+------------+
- */
-#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
-#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
-#define MC417_UART_GPIO_EN 0x00000001
-
-/* Values for speed control */
-#define MC417_SPD_CTL_SLOW 0x1
-#define MC417_SPD_CTL_MEDIUM 0x0
-#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
-
-/* Values for GPIO select */
-#define MC417_GPIO_SEL_GPIO3 0x3
-#define MC417_GPIO_SEL_GPIO2 0x2
-#define MC417_GPIO_SEL_GPIO1 0x1
-#define MC417_GPIO_SEL_GPIO0 0x0
-
-
-#define CX23417_GPIO_MASK 0xFC0003FF
-static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
-{
- int status = 0;
- u32 _gpio_direction = 0;
-
- _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
- status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
- (u8 *)&value, 4, 0, 0);
- return status;
-}
-static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
-{
- int status = 0;
- u32 _gpio_direction = 0;
-
- _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
-
- status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
- (u8 *)pValue, 4, 0, 1);
- return status;
-}
-
-static int waitForMciComplete(struct cx231xx *dev)
-{
- u32 gpio;
- u32 gpio_driection = 0;
- u8 count = 0;
- getITVCReg(dev, gpio_driection, &gpio);
-
- while (!(gpio&0x020000)) {
- msleep(10);
-
- getITVCReg(dev, gpio_driection, &gpio);
-
- if (count++ > 100) {
- dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
- return -1;
- }
- }
- return 0;
-}
-
-static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
-{
- u32 temp;
- int status = 0;
-
- temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
- status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
- if (status < 0)
- return status;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 1;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 2;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 3;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write address byte 0;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write address byte 1;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*Write that the mode is write.*/
- temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- return waitForMciComplete(dev);
-}
-
-static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
-{
- /*write address byte 0;*/
- u32 temp;
- u32 return_value = 0;
- int ret = 0;
-
- temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
- temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write address byte 1;*/
- temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write that the mode is read;*/
- temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
- temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*wait for the MIRDY line to be asserted ,
- signalling that the read is done;*/
- ret = waitForMciComplete(dev);
-
- /*switch the DATA- GPIO to input mode;*/
-
- /*Read data byte 0;*/
- temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp & 0x03FC0000) >> 18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
-
- /* Read data byte 1;*/
- temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
-
- return_value |= ((temp & 0x03FC0000) >> 10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
-
- /*Read data byte 2;*/
- temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp & 0x03FC0000) >> 2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
-
- /*Read data byte 3;*/
- temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp & 0x03FC0000) << 6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
-
- *value = return_value;
-
-
- return ret;
-}
-
-static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
-{
- /*write data byte 0;*/
-
- u32 temp;
- int ret = 0;
-
- temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
- temp = temp << 10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
- if (ret < 0)
- return ret;
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 1;*/
- temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
- temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*wait for MIRDY line;*/
- waitForMciComplete(dev);
-
- return 0;
-}
-
-static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
-{
- u32 temp = 0;
- u32 return_value = 0;
- int ret = 0;
-
- /*write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
- if (ret < 0)
- return ret;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write address byte 1*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*write address byte 0*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
-
- /*Wait for MIRDY line*/
- ret = waitForMciComplete(dev);
-
-
- /*Read data byte 3;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)<<6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
-
- /*Read data byte 2;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
-
- /* Read data byte 1;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
-
- /*Read data byte 0;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
-
- *value = return_value;
- return ret;
-}
-
-/* ------------------------------------------------------------------ */
-
-/* MPEG encoder API */
-static char *cmd_to_str(int cmd)
-{
- switch (cmd) {
- case CX2341X_ENC_PING_FW:
- return "PING_FW";
- case CX2341X_ENC_START_CAPTURE:
- return "START_CAPTURE";
- case CX2341X_ENC_STOP_CAPTURE:
- return "STOP_CAPTURE";
- case CX2341X_ENC_SET_AUDIO_ID:
- return "SET_AUDIO_ID";
- case CX2341X_ENC_SET_VIDEO_ID:
- return "SET_VIDEO_ID";
- case CX2341X_ENC_SET_PCR_ID:
- return "SET_PCR_PID";
- case CX2341X_ENC_SET_FRAME_RATE:
- return "SET_FRAME_RATE";
- case CX2341X_ENC_SET_FRAME_SIZE:
- return "SET_FRAME_SIZE";
- case CX2341X_ENC_SET_BIT_RATE:
- return "SET_BIT_RATE";
- case CX2341X_ENC_SET_GOP_PROPERTIES:
- return "SET_GOP_PROPERTIES";
- case CX2341X_ENC_SET_ASPECT_RATIO:
- return "SET_ASPECT_RATIO";
- case CX2341X_ENC_SET_DNR_FILTER_MODE:
- return "SET_DNR_FILTER_PROPS";
- case CX2341X_ENC_SET_DNR_FILTER_PROPS:
- return "SET_DNR_FILTER_PROPS";
- case CX2341X_ENC_SET_CORING_LEVELS:
- return "SET_CORING_LEVELS";
- case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
- return "SET_SPATIAL_FILTER_TYPE";
- case CX2341X_ENC_SET_VBI_LINE:
- return "SET_VBI_LINE";
- case CX2341X_ENC_SET_STREAM_TYPE:
- return "SET_STREAM_TYPE";
- case CX2341X_ENC_SET_OUTPUT_PORT:
- return "SET_OUTPUT_PORT";
- case CX2341X_ENC_SET_AUDIO_PROPERTIES:
- return "SET_AUDIO_PROPERTIES";
- case CX2341X_ENC_HALT_FW:
- return "HALT_FW";
- case CX2341X_ENC_GET_VERSION:
- return "GET_VERSION";
- case CX2341X_ENC_SET_GOP_CLOSURE:
- return "SET_GOP_CLOSURE";
- case CX2341X_ENC_GET_SEQ_END:
- return "GET_SEQ_END";
- case CX2341X_ENC_SET_PGM_INDEX_INFO:
- return "SET_PGM_INDEX_INFO";
- case CX2341X_ENC_SET_VBI_CONFIG:
- return "SET_VBI_CONFIG";
- case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
- return "SET_DMA_BLOCK_SIZE";
- case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
- return "GET_PREV_DMA_INFO_MB_10";
- case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
- return "GET_PREV_DMA_INFO_MB_9";
- case CX2341X_ENC_SCHED_DMA_TO_HOST:
- return "SCHED_DMA_TO_HOST";
- case CX2341X_ENC_INITIALIZE_INPUT:
- return "INITIALIZE_INPUT";
- case CX2341X_ENC_SET_FRAME_DROP_RATE:
- return "SET_FRAME_DROP_RATE";
- case CX2341X_ENC_PAUSE_ENCODER:
- return "PAUSE_ENCODER";
- case CX2341X_ENC_REFRESH_INPUT:
- return "REFRESH_INPUT";
- case CX2341X_ENC_SET_COPYRIGHT:
- return "SET_COPYRIGHT";
- case CX2341X_ENC_SET_EVENT_NOTIFICATION:
- return "SET_EVENT_NOTIFICATION";
- case CX2341X_ENC_SET_NUM_VSYNC_LINES:
- return "SET_NUM_VSYNC_LINES";
- case CX2341X_ENC_SET_PLACEHOLDER:
- return "SET_PLACEHOLDER";
- case CX2341X_ENC_MUTE_VIDEO:
- return "MUTE_VIDEO";
- case CX2341X_ENC_MUTE_AUDIO:
- return "MUTE_AUDIO";
- case CX2341X_ENC_MISC:
- return "MISC";
- default:
- return "UNKNOWN";
- }
-}
-
-static int cx231xx_mbox_func(void *priv,
- u32 command,
- int in,
- int out,
- u32 data[CX2341X_MBOX_MAX_DATA])
-{
- struct cx231xx *dev = priv;
- unsigned long timeout;
- u32 value, flag, retval = 0;
- int i;
-
- dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
- cmd_to_str(command));
-
- /* this may not be 100% safe if we can't read any memory location
- without side effects */
- mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
- if (value != 0x12345678) {
- dprintk(3,
- "Firmware and/or mailbox pointer not initialized "
- "or corrupted, signature = 0x%x, cmd = %s\n", value,
- cmd_to_str(command));
- return -1;
- }
-
- /* This read looks at 32 bits, but flag is only 8 bits.
- * Seems we also bail if CMD or TIMEOUT bytes are set???
- */
- mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
- if (flag) {
- dprintk(3, "ERROR: Mailbox appears to be in use "
- "(%x), cmd = %s\n", flag, cmd_to_str(command));
- return -1;
- }
-
- flag |= 1; /* tell 'em we're working on it */
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- /* write command + args + fill remaining with zeros */
- /* command code */
- mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
- mc417_memory_write(dev, dev->cx23417_mailbox + 3,
- IVTV_API_STD_TIMEOUT); /* timeout */
- for (i = 0; i < in; i++) {
- mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
- dprintk(3, "API Input %d = %d\n", i, data[i]);
- }
- for (; i < CX2341X_MBOX_MAX_DATA; i++)
- mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
-
- flag |= 3; /* tell 'em we're done writing */
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- /* wait for firmware to handle the API command */
- timeout = jiffies + msecs_to_jiffies(10);
- for (;;) {
- mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
- if (0 != (flag & 4))
- break;
- if (time_after(jiffies, timeout)) {
- dprintk(3, "ERROR: API Mailbox timeout\n");
- return -1;
- }
- udelay(10);
- }
-
- /* read output values */
- for (i = 0; i < out; i++) {
- mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
- dprintk(3, "API Output %d = %d\n", i, data[i]);
- }
-
- mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
- dprintk(3, "API result = %d\n", retval);
-
- flag = 0;
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- return retval;
-}
-
-/* We don't need to call the API often, so using just one
- * mailbox will probably suffice
- */
-static int cx231xx_api_cmd(struct cx231xx *dev,
- u32 command,
- u32 inputcnt,
- u32 outputcnt,
- ...)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
- va_list vargs;
- int i, err;
-
- dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
-
- va_start(vargs, outputcnt);
- for (i = 0; i < inputcnt; i++)
- data[i] = va_arg(vargs, int);
-
- err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
- for (i = 0; i < outputcnt; i++) {
- int *vptr = va_arg(vargs, int *);
- *vptr = data[i];
- }
- va_end(vargs);
-
- return err;
-}
-
-static int cx231xx_find_mailbox(struct cx231xx *dev)
-{
- u32 signature[4] = {
- 0x12345678, 0x34567812, 0x56781234, 0x78123456
- };
- int signaturecnt = 0;
- u32 value;
- int i;
- int ret = 0;
-
- dprintk(2, "%s()\n", __func__);
-
- for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
- ret = mc417_memory_read(dev, i, &value);
- if (ret < 0)
- return ret;
- if (value == signature[signaturecnt])
- signaturecnt++;
- else
- signaturecnt = 0;
- if (4 == signaturecnt) {
- dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
- return i+1;
- }
- }
- dprintk(3, "Mailbox signature values not found!\n");
- return -1;
-}
-
-static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
- u32 *p_fw_image)
-{
-
- u32 temp = 0;
- int i = 0;
-
- temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /*write data byte 1;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- /* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
- *p_fw_image = temp;
- p_fw_image++;
- temp = temp|((0x05)<<10);
- *p_fw_image = temp;
- p_fw_image++;
-
- for (i = 0; i < 6; i++) {
- *p_fw_image = 0xFFFFFFFF;
- p_fw_image++;
- }
-}
-
-
-static int cx231xx_load_firmware(struct cx231xx *dev)
-{
- static const unsigned char magic[8] = {
- 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
- };
- const struct firmware *firmware;
- int i, retval = 0;
- u32 value = 0;
- u32 gpio_output = 0;
- /*u32 checksum = 0;*/
- /*u32 *dataptr;*/
- u32 transfer_size = 0;
- u32 fw_data = 0;
- u32 address = 0;
- /*u32 current_fw[800];*/
- u32 *p_current_fw, *p_fw;
- u32 *p_fw_data;
- int frame = 0;
- u16 _buffer_size = 4096;
- u8 *p_buffer;
-
- p_current_fw = vmalloc(1884180 * 4);
- p_fw = p_current_fw;
- if (p_current_fw == NULL) {
- dprintk(2, "FAIL!!!\n");
- return -1;
- }
-
- p_buffer = vmalloc(4096);
- if (p_buffer == NULL) {
- dprintk(2, "FAIL!!!\n");
- return -1;
- }
-
- dprintk(2, "%s()\n", __func__);
-
- /* Save GPIO settings before reset of APU */
- retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
- retval |= mc417_memory_read(dev, 0x900C, &value);
-
- retval = mc417_register_write(dev,
- IVTV_REG_VPU, 0xFFFFFFED);
- retval |= mc417_register_write(dev,
- IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= mc417_register_write(dev,
- IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
- retval |= mc417_register_write(dev,
- IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
- retval |= mc417_register_write(dev,
- IVTV_REG_APU, 0);
-
- if (retval != 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
- return -1;
- }
-
- retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
- &dev->udev->dev);
-
- if (retval != 0) {
- printk(KERN_ERR
- "ERROR: Hotplug firmware request failed (%s).\n",
- CX231xx_FIRM_IMAGE_NAME);
- printk(KERN_ERR "Please fix your hotplug setup, the board will "
- "not work without firmware loaded!\n");
- return -1;
- }
-
- if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
- printk(KERN_ERR "ERROR: Firmware size mismatch "
- "(have %zd, expected %d)\n",
- firmware->size, CX231xx_FIRM_IMAGE_SIZE);
- release_firmware(firmware);
- return -1;
- }
-
- if (0 != memcmp(firmware->data, magic, 8)) {
- printk(KERN_ERR
- "ERROR: Firmware magic mismatch, wrong file?\n");
- release_firmware(firmware);
- return -1;
- }
-
- initGPIO(dev);
-
- /* transfer to the chip */
- dprintk(2, "Loading firmware to GPIO...\n");
- p_fw_data = (u32 *)firmware->data;
- dprintk(2, "firmware->size=%zd\n", firmware->size);
- for (transfer_size = 0; transfer_size < firmware->size;
- transfer_size += 4) {
- fw_data = *p_fw_data;
-
- mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
- address = address + 1;
- p_current_fw += 20;
- p_fw_data += 1;
- }
-
- /*download the firmware by ep5-out*/
-
- for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
- frame++) {
- for (i = 0; i < _buffer_size; i++) {
- *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
- i++;
- *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
- i++;
- *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
- i++;
- *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
- }
- cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
- }
-
- p_current_fw = p_fw;
- vfree(p_current_fw);
- p_current_fw = NULL;
- uninitGPIO(dev);
- release_firmware(firmware);
- dprintk(1, "Firmware upload successful.\n");
-
- retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
- IVTV_CMD_HW_BLOCKS_RST);
- if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
- return retval;
- }
- /* 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_read(dev, IVTV_REG_VPU, &value);
- retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
-
- if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
- return retval;
- }
- return 0;
-}
-
-static void cx231xx_417_check_encoder(struct cx231xx *dev)
-{
- u32 status, seq;
-
- status = 0;
- seq = 0;
- cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
- dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
-}
-
-static void cx231xx_codec_settings(struct cx231xx *dev)
-{
- dprintk(1, "%s()\n", __func__);
-
- /* assign frame size */
- cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
- dev->ts1.height, dev->ts1.width);
-
- dev->mpeg_params.width = dev->ts1.width;
- dev->mpeg_params.height = dev->ts1.height;
-
- cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
-
- cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
- cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
-}
-
-static int cx231xx_initialize_codec(struct cx231xx *dev)
-{
- int version;
- int retval;
- u32 i;
- u32 val = 0;
-
- dprintk(1, "%s()\n", __func__);
- cx231xx_disable656(dev);
- retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
- if (retval < 0) {
- dprintk(2, "%s() PING OK\n", __func__);
- retval = cx231xx_load_firmware(dev);
- if (retval < 0) {
- printk(KERN_ERR "%s() f/w load failed\n", __func__);
- return retval;
- }
- retval = cx231xx_find_mailbox(dev);
- if (retval < 0) {
- printk(KERN_ERR "%s() mailbox < 0, error\n",
- __func__);
- return -1;
- }
- dev->cx23417_mailbox = retval;
- retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
- if (retval < 0) {
- printk(KERN_ERR
- "ERROR: cx23417 firmware ping failed!\n");
- return -1;
- }
- retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
- &version);
- if (retval < 0) {
- printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
- "version failed!\n");
- return -1;
- }
- dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
- msleep(200);
- }
-
- for (i = 0; i < 1; i++) {
- retval = mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
- val);
- if (retval < 0)
- return retval;
- }
-
- cx231xx_enable656(dev);
- /* stop mpeg capture */
- cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
- 3, 0, 1, 3, 4);
-
- cx231xx_codec_settings(dev);
- msleep(60);
-
-/* cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
- CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
- cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
- CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0);
-*/
-
-#if 0
- /* TODO */
- u32 data[7];
-
- /* Setup to capture VBI */
- data[0] = 0x0001BD00;
- data[1] = 1; /* frames per interrupt */
- data[2] = 4; /* total bufs */
- data[3] = 0x91559155; /* start codes */
- data[4] = 0x206080C0; /* stop codes */
- data[5] = 6; /* lines */
- data[6] = 64; /* BPL */
-
- cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
- data[2], data[3], data[4], data[5], data[6]);
-
- for (i = 2; i <= 24; i++) {
- int valid;
-
- valid = ((i >= 19) && (i <= 21));
- cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
- valid, 0 , 0, 0);
- cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
- i | 0x80000000, valid, 0, 0, 0);
- }
-#endif
-/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
- msleep(60);
-*/
- /* initialize the video input */
- retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
- if (retval < 0)
- return retval;
- msleep(60);
-
- /* Enable VIP style pixel invalidation so we work with scaled mode */
- mc417_memory_write(dev, 2120, 0x00000080);
-
- /* start capturing to the host interface */
- retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
- CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
- if (retval < 0)
- return retval;
- msleep(10);
-
- for (i = 0; i < 1; i++) {
- mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***VIM Capture Lines =%d ***\n", val);
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int bb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
-{
- struct cx231xx_fh *fh = q->priv_data;
-
- fh->dev->ts1.ts_packet_size = mpeglinesize;
- fh->dev->ts1.ts_packet_count = mpeglines;
-
- *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
- *count = mpegbufs;
-
- return 0;
-}
-static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
-{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
- unsigned long flags = 0;
-
- if (in_interrupt())
- BUG();
-
- spin_lock_irqsave(&dev->video_mode.slock, flags);
- if (dev->USE_ISO) {
- if (dev->video_mode.isoc_ctl.buf == buf)
- dev->video_mode.isoc_ctl.buf = NULL;
- } else {
- if (dev->video_mode.bulk_ctl.buf == buf)
- dev->video_mode.bulk_ctl.buf = NULL;
- }
- spin_unlock_irqrestore(&dev->video_mode.slock, flags);
- videobuf_waiton(vq, &buf->vb, 0, 0);
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
- struct cx231xx_dmaqueue *dma_q)
-{
- void *vbuf;
- struct cx231xx_buffer *buf;
- u32 tail_data = 0;
- char *p_data;
-
- if (dma_q->mpeg_buffer_done == 0) {
- if (list_empty(&dma_q->active))
- return;
-
- buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
- dev->video_mode.isoc_ctl.buf = buf;
- dma_q->mpeg_buffer_done = 1;
- }
- /* Fill buffer */
- buf = dev->video_mode.isoc_ctl.buf;
- vbuf = videobuf_to_vmalloc(&buf->vb);
-
- if ((dma_q->mpeg_buffer_completed+len) <
- mpeglines*mpeglinesize) {
- if (dma_q->add_ps_package_head ==
- CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- dma_q->ps_head, 3);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + 3;
- dma_q->add_ps_package_head =
- CX231XX_NONEED_PS_PACKAGE_HEAD;
- }
- memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + len;
- } else {
- dma_q->mpeg_buffer_done = 0;
-
- tail_data =
- mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- data, tail_data);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- dma_q->mpeg_buffer_completed = 0;
-
- if (len - tail_data > 0) {
- p_data = data + tail_data;
- dma_q->left_data_count = len - tail_data;
- memcpy(dma_q->p_left_data,
- p_data, len - tail_data);
- }
-
- }
-
- return;
-}
-
-static void buffer_filled(char *data, int len, struct urb *urb,
- struct cx231xx_dmaqueue *dma_q)
-{
- void *vbuf;
- struct cx231xx_buffer *buf;
-
- if (list_empty(&dma_q->active))
- return;
-
-
- buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
-
-
- /* Fill buffer */
- vbuf = videobuf_to_vmalloc(&buf->vb);
- memcpy(vbuf, data, len);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-
- return;
-}
-static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
-{
- struct cx231xx_dmaqueue *dma_q = urb->context;
- unsigned char *p_buffer;
- u32 buffer_size = 0;
- u32 i = 0;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- if (dma_q->left_data_count > 0) {
- buffer_copy(dev, dma_q->p_left_data,
- dma_q->left_data_count, urb, dma_q);
- dma_q->mpeg_buffer_completed = dma_q->left_data_count;
- dma_q->left_data_count = 0;
- }
-
- p_buffer = urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- buffer_size = urb->iso_frame_desc[i].actual_length;
-
- if (buffer_size > 0)
- buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
- }
-
- return 0;
-}
-static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
-{
-
- /*char *outp;*/
- /*struct cx231xx_buffer *buf;*/
- struct cx231xx_dmaqueue *dma_q = urb->context;
- unsigned char *p_buffer, *buffer;
- u32 buffer_size = 0;
-
- p_buffer = urb->transfer_buffer;
- buffer_size = urb->actual_length;
-
- buffer = kmalloc(buffer_size, GFP_ATOMIC);
-
- memcpy(buffer, dma_q->ps_head, 3);
- memcpy(buffer+3, p_buffer, buffer_size-3);
- memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
-
- p_buffer = buffer;
- buffer_filled(p_buffer, buffer_size, urb, dma_q);
-
- kfree(buffer);
- return 0;
-}
-
-static int bb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct cx231xx_fh *fh = q->priv_data;
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx *dev = fh->dev;
- int rc = 0, urb_init = 0;
- int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
-
- dma_qq = &dev->video_mode.vidq;
-
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
- return -EINVAL;
- buf->vb.width = fh->dev->ts1.ts_packet_size;
- buf->vb.height = fh->dev->ts1.ts_packet_count;
- buf->vb.size = size;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- if (dev->USE_ISO) {
- if (!dev->video_mode.isoc_ctl.num_bufs)
- urb_init = 1;
- } else {
- if (!dev->video_mode.bulk_ctl.num_bufs)
- urb_init = 1;
- }
- /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
- urb_init, dev->video_mode.max_pkt_size);*/
- dev->mode_tv = 1;
-
- if (urb_init) {
- rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
- rc = cx231xx_unmute_audio(dev);
- if (dev->USE_ISO) {
- cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
- rc = cx231xx_init_isoc(dev, mpeglines,
- mpegbufs,
- dev->ts1_mode.max_pkt_size,
- cx231xx_isoc_copy);
- } else {
- cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- rc = cx231xx_init_bulk(dev, mpeglines,
- mpegbufs,
- dev->ts1_mode.max_pkt_size,
- cx231xx_bulk_copy);
- }
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(q, buf);
- return rc;
-}
-
-static void bb_buf_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct cx231xx_fh *fh = q->priv_data;
-
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx *dev = fh->dev;
- struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-
-}
-
-static void bb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- /*struct cx231xx_fh *fh = q->priv_data;*/
- /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
-
- free_buffer(q, buf);
-}
-
-static struct videobuf_queue_ops cx231xx_qops = {
- .buf_setup = bb_buf_setup,
- .buf_prepare = bb_buf_prepare,
- .buf_queue = bb_buf_queue,
- .buf_release = bb_buf_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-static const u32 *ctrl_classes[] = {
- cx2341x_mpeg_ctrls,
- NULL
-};
-
-static int cx231xx_queryctrl(struct cx231xx *dev,
- struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
-
- /* MPEG V4L2 controls */
- if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-
- return 0;
-}
-
-static int cx231xx_querymenu(struct cx231xx *dev,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = qmenu->id;
- cx231xx_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
-
-static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- *norm = dev->encodernorm.id;
- return 0;
-}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
- if (*id & cx231xx_tvnorms[i].id)
- break;
- if (i == ARRAY_SIZE(cx231xx_tvnorms))
- return -EINVAL;
- dev->encodernorm = cx231xx_tvnorms[i];
-
- if (dev->encodernorm.id & 0xb000) {
- dprintk(3, "encodernorm set to NTSC\n");
- dev->norm = V4L2_STD_NTSC;
- dev->ts1.height = 480;
- dev->mpeg_params.is_50hz = 0;
- } else {
- dprintk(3, "encodernorm set to PAL\n");
- dev->norm = V4L2_STD_PAL_B;
- dev->ts1.height = 576;
- dev->mpeg_params.is_50hz = 1;
- }
- call_all(dev, core, s_std, dev->norm);
- /* do mode control overrides */
- cx231xx_do_mode_ctrl_overrides(dev);
-
- dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
- return 0;
-}
-static int vidioc_g_audio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-return 0;
-}
-static int vidioc_enumaudio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
-
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-
-
-return 0;
-}
-static const char *iname[] = {
- [CX231XX_VMUX_COMPOSITE1] = "Composite1",
- [CX231XX_VMUX_SVIDEO] = "S-Video",
- [CX231XX_VMUX_TELEVISION] = "Television",
- [CX231XX_VMUX_CABLE] = "Cable TV",
- [CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
-};
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- struct cx231xx_input *input;
- int n;
- dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
-
- if (i->index >= 4)
- return -EINVAL;
-
-
- input = &cx231xx_boards[dev->model].input[i->index];
-
- if (input->type == 0)
- return -EINVAL;
-
- /* FIXME
- * strcpy(i->name, input->name); */
-
- n = i->index;
- strcpy(i->name, iname[INPUT(n)->type]);
-
- if (input->type == CX231XX_VMUX_TELEVISION ||
- input->type == CX231XX_VMUX_CABLE)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- dprintk(3, "enter vidioc_s_input() i=%d\n", i);
-
- mutex_lock(&dev->lock);
-
- video_mux(dev, i);
-
- mutex_unlock(&dev->lock);
-
- if (i >= 4)
- return -EINVAL;
- dev->input = i;
- dprintk(3, "exit vidioc_s_input()\n");
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
-
-
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_s_ctrl()\n");
- /* Update the A/V core */
- call_all(dev, core, s_ctrl, ctl);
- dprintk(3, "exit vidioc_s_ctrl()\n");
- return 0;
-}
-static struct v4l2_capability pvr_capability = {
- .driver = "cx231xx",
- .card = "VideoGrabber",
- .bus_info = "usb",
- .version = 1,
- .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
-};
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
-
-
-
- memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
-
- if (f->index != 0)
- return -EINVAL;
-
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->pixelformat = V4L2_PIX_FMT_MPEG;
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->ts1.width;
- f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->vidq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
- dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
- dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct cx231xx_fh *fh = file->private_data;
-
- return videobuf_reqbufs(&fh->vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx231xx_fh *fh = file->private_data;
-
- return videobuf_querybuf(&fh->vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx231xx_fh *fh = file->private_data;
-
- return videobuf_qbuf(&fh->vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct cx231xx_fh *fh = file->private_data;
-
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_streamon()\n");
- cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
- if (dev->USE_ISO)
- cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_isoc_copy);
- else {
- cx231xx_init_bulk(dev, 320,
- 5,
- dev->ts1_mode.max_pkt_size,
- cx231xx_bulk_copy);
- }
- dprintk(3, "exit vidioc_streamon()\n");
- return videobuf_streamon(&fh->vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx231xx_fh *fh = file->private_data;
-
- return videobuf_streamoff(&fh->vidq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_g_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- dprintk(3, "exit vidioc_g_ext_ctrls()\n");
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_s_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- if (err == 0) {
- err = cx2341x_update(dev, cx231xx_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
-
- return err;
-
-
-return 0;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_try_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
- return err;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- dprintk(3,
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- call_all(dev, core, log_status);
- cx2341x_log_status(&dev->mpeg_params, name);
- dprintk(3,
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_querymenu()\n");
- dprintk(3, "exit vidioc_querymenu()\n");
- return cx231xx_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_queryctrl()\n");
- dprintk(3, "exit vidioc_queryctrl()\n");
- return cx231xx_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
- int minor = video_devdata(file)->minor;
- struct cx231xx *h, *dev = NULL;
- /*struct list_head *list;*/
- struct cx231xx_fh *fh;
- /*u32 value = 0;*/
-
- dprintk(2, "%s()\n", __func__);
-
- list_for_each_entry(h, &cx231xx_devlist, devlist) {
- if (h->v4l_device->minor == minor)
- dev = h;
- }
-
- if (dev == NULL)
- return -ENODEV;
-
- mutex_lock(&dev->lock);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
-
- file->private_data = fh;
- fh->dev = dev;
-
-
- videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
- NULL, &dev->video_mode.slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer), fh, NULL);
-/*
- videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
- &dev->udev->dev, &dev->ts1.slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer),
- fh, NULL);
-*/
-
-
- cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
- cx231xx_set_gpio_value(dev, 2, 0);
-
- cx231xx_initialize_codec(dev);
-
- mutex_unlock(&dev->lock);
- cx231xx_start_TS1(dev);
-
- return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
-
- if (!dev) {
- dprintk(3, "abort!!!\n");
- return 0;
- }
-
- mutex_lock(&dev->lock);
-
- cx231xx_stop_TS1(dev);
-
- /* do this before setting alternate! */
- if (dev->USE_ISO)
- cx231xx_uninit_isoc(dev);
- else
- cx231xx_uninit_bulk(dev);
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
-
- cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
- CX231xx_RAW_BITS_NONE);
-
- /* FIXME: Review this crap */
- /* Shut device down on last close */
- if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
- if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
- /* stop mpeg capture */
-
- msleep(500);
- cx231xx_417_check_encoder(dev);
-
- }
- }
-
- if (fh->vidq.streaming)
- videobuf_streamoff(&fh->vidq);
- if (fh->vidq.reading)
- videobuf_read_stop(&fh->vidq);
-
- videobuf_mmap_free(&fh->vidq);
- file->private_data = NULL;
- kfree(fh);
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
-
- /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
- /* 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 (cx231xx_initialize_codec(dev) < 0)
- return -EINVAL;
- }
- }
-
- return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx231xx_fh *fh = file->private_data;
- /*struct cx231xx *dev = fh->dev;*/
-
- /*dprintk(2, "%s\n", __func__);*/
-
- return videobuf_poll_stream(file, &fh->vidq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- return videobuf_mmap_mapper(&fh->vidq, vma);
-}
-
-static struct v4l2_file_operations mpeg_fops = {
- .owner = THIS_MODULE,
- .open = mpeg_open,
- .release = mpeg_release,
- .read = mpeg_read,
- .poll = mpeg_poll,
- .mmap = mpeg_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_enumaudio = vidioc_enumaudio,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .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_s_ctrl = vidioc_s_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,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .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_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_querymenu = vidioc_querymenu,
- .vidioc_queryctrl = vidioc_queryctrl,
-/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/* .vidioc_g_register = cx231xx_g_register,*/
-/* .vidioc_s_register = cx231xx_s_register,*/
-#endif
-};
-
-static struct video_device cx231xx_mpeg_template = {
- .name = "cx231xx",
- .fops = &mpeg_fops,
- .ioctl_ops = &mpeg_ioctl_ops,
- .minor = -1,
- .tvnorms = CX231xx_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-void cx231xx_417_unregister(struct cx231xx *dev)
-{
- dprintk(1, "%s()\n", __func__);
- dprintk(3, "%s()\n", __func__);
-
- if (dev->v4l_device) {
- if (-1 != dev->v4l_device->minor)
- video_unregister_device(dev->v4l_device);
- else
- video_device_release(dev->v4l_device);
- dev->v4l_device = NULL;
- }
-}
-
-static struct video_device *cx231xx_video_dev_alloc(
- struct cx231xx *dev,
- struct usb_device *usbdev,
- struct video_device *template,
- char *type)
-{
- struct video_device *vfd;
-
- dprintk(1, "%s()\n", __func__);
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template;
- vfd->minor = -1;
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
- type, cx231xx_boards[dev->model].name);
-
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
-
- return vfd;
-
-}
-
-int cx231xx_417_register(struct cx231xx *dev)
-{
- /* FIXME: Port1 hardcoded here */
- int err = -ENODEV;
- struct cx231xx_tsport *tsport = &dev->ts1;
-
- dprintk(1, "%s()\n", __func__);
-
- /* Set default TV standard */
- dev->encodernorm = cx231xx_tvnorms[0];
-
- if (dev->encodernorm.id & V4L2_STD_525_60)
- tsport->height = 480;
- else
- tsport->height = 576;
-
- tsport->width = 720;
- cx2341x_fill_defaults(&dev->mpeg_params);
- dev->norm = V4L2_STD_NTSC;
-
- dev->mpeg_params.port = CX2341X_PORT_SERIAL;
-
- /* Allocate and initialize V4L video device */
- dev->v4l_device = cx231xx_video_dev_alloc(dev,
- dev->udev, &cx231xx_mpeg_template, "mpeg");
- err = video_register_device(dev->v4l_device,
- VFL_TYPE_GRABBER, -1);
- if (err < 0) {
- dprintk(3, "%s: can't register mpeg device\n", dev->name);
- return err;
- }
-
- dprintk(3, "%s: registered device video%d [mpeg]\n",
- dev->name, dev->v4l_device->num);
-
- return 0;
-}
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
deleted file mode 100644
index 523aa49d6b86..000000000000
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ /dev/null
@@ -1,2645 +0,0 @@
-/*
- cx231xx-video.c - driver for Conexant Cx23100/101/102
- USB video capture devices
-
- Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
- Based on em28xx driver
- Based on cx23885 driver
- Based on cx88 driver
-
- 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/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitmap.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/msp3400.h>
-#include <media/tuner.h>
-
-#include "dvb_frontend.h"
-
-#include "cx231xx.h"
-#include "cx231xx-vbi.h"
-
-#define CX231XX_VERSION "0.0.2"
-
-#define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
-#define DRIVER_DESC "Conexant cx231xx based USB video device driver"
-
-#define cx231xx_videodbg(fmt, arg...) do {\
- if (video_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
-#define cx231xx_isocdbg(fmt, arg...) \
-do {\
- if (isoc_debug) { \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); \
- } \
- } while (0)
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(CX231XX_VERSION);
-
-static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(card, int, NULL, 0444);
-module_param_array(video_nr, int, NULL, 0444);
-module_param_array(vbi_nr, int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
-
-MODULE_PARM_DESC(card, "card type");
-MODULE_PARM_DESC(video_nr, "video device numbers");
-MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
-
-static unsigned int video_debug;
-module_param(video_debug, int, 0644);
-MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
-
-/* supported video standards */
-static struct cx231xx_fmt format[] = {
- {
- .name = "16bpp YUY2, 4:2:2, packed",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- .reg = 0,
- },
-};
-
-/* supported controls */
-/* Common to all boards */
-
-/* ------------------------------------------------------------------- */
-
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx231xx_ctrl cx231xx_ctls[] = {
- /* --- video --- */
- {
- .v = {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = LUMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- .v = {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = LUMA_CTRL,
- .mask = 0xff00,
- .shift = 8,
- }, {
- .v = {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = CHROMA_CTRL,
- .mask = 0xff0000,
- .shift = 16,
- }, {
- /* strictly, this only describes only U saturation.
- * V saturation is handled specially through code.
- */
- .v = {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = CHROMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- /* --- audio --- */
- .v = {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
- .reg = PATH1_CTL1,
- .mask = (0x1f << 24),
- .shift = 24,
- }, {
- .v = {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .reg = PATH1_VOL_CTL,
- .mask = 0xff,
- .shift = 0,
- }
-};
-static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
-
-static const u32 cx231xx_user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_AUDIO_VOLUME,
-#if 0
- V4L2_CID_AUDIO_BALANCE,
-#endif
- V4L2_CID_AUDIO_MUTE,
- 0
-};
-
-static const u32 *ctrl_classes[] = {
- cx231xx_user_ctrls,
- NULL
-};
-
-/* ------------------------------------------------------------------
- Video buffer and parser functions
- ------------------------------------------------------------------*/
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct cx231xx *dev,
- struct cx231xx_dmaqueue *dma_q,
- struct cx231xx_buffer *buf)
-{
- /* Advice that buffer was filled */
- cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- if (dev->USE_ISO)
- dev->video_mode.isoc_ctl.buf = NULL;
- else
- dev->video_mode.bulk_ctl.buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-static inline void print_err_status(struct cx231xx *dev, int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronuously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronuously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg);
- } else {
- cx231xx_isocdbg("URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
- struct cx231xx_buffer **buf)
-{
- struct cx231xx_video_mode *vmode =
- container_of(dma_q, struct cx231xx_video_mode, vidq);
- struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
-
- char *outp;
-
- if (list_empty(&dma_q->active)) {
- cx231xx_isocdbg("No active queue to serve\n");
- if (dev->USE_ISO)
- dev->video_mode.isoc_ctl.buf = NULL;
- else
- dev->video_mode.bulk_ctl.buf = NULL;
- *buf = NULL;
- return;
- }
-
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue);
-
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0, (*buf)->vb.size);
-
- if (dev->USE_ISO)
- dev->video_mode.isoc_ctl.buf = *buf;
- else
- dev->video_mode.bulk_ctl.buf = *buf;
-
- return;
-}
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
-{
- struct cx231xx_dmaqueue *dma_q = urb->context;
- int i, rc = 1;
- unsigned char *p_buffer;
- u32 bytes_parsed = 0, buffer_size = 0;
- u8 sav_eav = 0;
-
- if (!dev)
- return 0;
-
- if (dev->state & DEV_DISCONNECTED)
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
-
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- /* cx231xx_isocdbg("packet %d is empty",i); - spammy */
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- dev->video_mode.max_pkt_size) {
- cx231xx_isocdbg("packet bigger than packet size");
- continue;
- }
-
- /* get buffer pointer and length */
- p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- buffer_size = urb->iso_frame_desc[i].actual_length;
- bytes_parsed = 0;
-
- if (dma_q->is_partial_line) {
- /* Handle the case of a partial line */
- sav_eav = dma_q->last_sav;
- } else {
- /* Check for a SAV/EAV overlapping
- the buffer boundary */
- sav_eav =
- cx231xx_find_boundary_SAV_EAV(p_buffer,
- dma_q->partial_buf,
- &bytes_parsed);
- }
-
- sav_eav &= 0xF0;
- /* Get the first line if we have some portion of an SAV/EAV from
- the last buffer or a partial line */
- if (sav_eav) {
- bytes_parsed += cx231xx_get_video_line(dev, dma_q,
- sav_eav, /* SAV/EAV */
- p_buffer + bytes_parsed, /* p_buffer */
- buffer_size - bytes_parsed);/* buf size */
- }
-
- /* Now parse data that is completely in this buffer */
- /* dma_q->is_partial_line = 0; */
-
- while (bytes_parsed < buffer_size) {
- u32 bytes_used = 0;
-
- sav_eav = cx231xx_find_next_SAV_EAV(
- p_buffer + bytes_parsed, /* p_buffer */
- buffer_size - bytes_parsed, /* buf size */
- &bytes_used);/* bytes used to get SAV/EAV */
-
- bytes_parsed += bytes_used;
-
- sav_eav &= 0xF0;
- if (sav_eav && (bytes_parsed < buffer_size)) {
- bytes_parsed += cx231xx_get_video_line(dev,
- dma_q, sav_eav, /* SAV/EAV */
- p_buffer + bytes_parsed,/* p_buffer */
- buffer_size - bytes_parsed);/*buf size*/
- }
- }
-
- /* Save the last four bytes of the buffer so we can check the
- buffer boundary condition next time */
- memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
- bytes_parsed = 0;
-
- }
- return rc;
-}
-
-static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
-{
- struct cx231xx_dmaqueue *dma_q = urb->context;
- int rc = 1;
- unsigned char *p_buffer;
- u32 bytes_parsed = 0, buffer_size = 0;
- u8 sav_eav = 0;
-
- if (!dev)
- return 0;
-
- if (dev->state & DEV_DISCONNECTED)
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- if (1) {
-
- /* get buffer pointer and length */
- p_buffer = urb->transfer_buffer;
- buffer_size = urb->actual_length;
- bytes_parsed = 0;
-
- if (dma_q->is_partial_line) {
- /* Handle the case of a partial line */
- sav_eav = dma_q->last_sav;
- } else {
- /* Check for a SAV/EAV overlapping
- the buffer boundary */
- sav_eav =
- cx231xx_find_boundary_SAV_EAV(p_buffer,
- dma_q->partial_buf,
- &bytes_parsed);
- }
-
- sav_eav &= 0xF0;
- /* Get the first line if we have some portion of an SAV/EAV from
- the last buffer or a partial line */
- if (sav_eav) {
- bytes_parsed += cx231xx_get_video_line(dev, dma_q,
- sav_eav, /* SAV/EAV */
- p_buffer + bytes_parsed, /* p_buffer */
- buffer_size - bytes_parsed);/* buf size */
- }
-
- /* Now parse data that is completely in this buffer */
- /* dma_q->is_partial_line = 0; */
-
- while (bytes_parsed < buffer_size) {
- u32 bytes_used = 0;
-
- sav_eav = cx231xx_find_next_SAV_EAV(
- p_buffer + bytes_parsed, /* p_buffer */
- buffer_size - bytes_parsed, /* buf size */
- &bytes_used);/* bytes used to get SAV/EAV */
-
- bytes_parsed += bytes_used;
-
- sav_eav &= 0xF0;
- if (sav_eav && (bytes_parsed < buffer_size)) {
- bytes_parsed += cx231xx_get_video_line(dev,
- dma_q, sav_eav, /* SAV/EAV */
- p_buffer + bytes_parsed,/* p_buffer */
- buffer_size - bytes_parsed);/*buf size*/
- }
- }
-
- /* Save the last four bytes of the buffer so we can check the
- buffer boundary condition next time */
- memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
- bytes_parsed = 0;
-
- }
- return rc;
-}
-
-
-u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
- u32 *p_bytes_used)
-{
- u32 bytes_used;
- u8 boundary_bytes[8];
- u8 sav_eav = 0;
-
- *p_bytes_used = 0;
-
- /* Create an array of the last 4 bytes of the last buffer and the first
- 4 bytes of the current buffer. */
-
- memcpy(boundary_bytes, partial_buf, 4);
- memcpy(boundary_bytes + 4, p_buffer, 4);
-
- /* Check for the SAV/EAV in the boundary buffer */
- sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8,
- &bytes_used);
-
- if (sav_eav) {
- /* found a boundary SAV/EAV. Updates the bytes used to reflect
- only those used in the new buffer */
- *p_bytes_used = bytes_used - 4;
- }
-
- return sav_eav;
-}
-
-u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used)
-{
- u32 i;
- u8 sav_eav = 0;
-
- /*
- * Don't search if the buffer size is less than 4. It causes a page
- * fault since buffer_size - 4 evaluates to a large number in that
- * case.
- */
- if (buffer_size < 4) {
- *p_bytes_used = buffer_size;
- return 0;
- }
-
- for (i = 0; i < (buffer_size - 3); i++) {
-
- if ((p_buffer[i] == 0xFF) &&
- (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) {
-
- *p_bytes_used = i + 4;
- sav_eav = p_buffer[i + 3];
- return sav_eav;
- }
- }
-
- *p_bytes_used = buffer_size;
- return 0;
-}
-
-u32 cx231xx_get_video_line(struct cx231xx *dev,
- struct cx231xx_dmaqueue *dma_q, u8 sav_eav,
- u8 *p_buffer, u32 buffer_size)
-{
- u32 bytes_copied = 0;
- int current_field = -1;
-
- switch (sav_eav) {
- case SAV_ACTIVE_VIDEO_FIELD1:
- /* looking for skipped line which occurred in PAL 720x480 mode.
- In this case, there will be no active data contained
- between the SAV and EAV */
- if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
- (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
- ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
- (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
- (p_buffer[3] == EAV_VBLANK_FIELD1) ||
- (p_buffer[3] == EAV_VBLANK_FIELD2)))
- return bytes_copied;
- current_field = 1;
- break;
-
- case SAV_ACTIVE_VIDEO_FIELD2:
- /* looking for skipped line which occurred in PAL 720x480 mode.
- In this case, there will be no active data contained between
- the SAV and EAV */
- if ((buffer_size > 3) && (p_buffer[0] == 0xFF) &&
- (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) &&
- ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) ||
- (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) ||
- (p_buffer[3] == EAV_VBLANK_FIELD1) ||
- (p_buffer[3] == EAV_VBLANK_FIELD2)))
- return bytes_copied;
- current_field = 2;
- break;
- }
-
- dma_q->last_sav = sav_eav;
-
- bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer,
- buffer_size, current_field);
-
- return bytes_copied;
-}
-
-u32 cx231xx_copy_video_line(struct cx231xx *dev,
- struct cx231xx_dmaqueue *dma_q, u8 *p_line,
- u32 length, int field_number)
-{
- u32 bytes_to_copy;
- struct cx231xx_buffer *buf;
- u32 _line_size = dev->width * 2;
-
- if (dma_q->current_field != field_number)
- cx231xx_reset_video_buffer(dev, dma_q);
-
- /* get the buffer pointer */
- if (dev->USE_ISO)
- buf = dev->video_mode.isoc_ctl.buf;
- else
- buf = dev->video_mode.bulk_ctl.buf;
-
- /* Remember the field number for next time */
- dma_q->current_field = field_number;
-
- bytes_to_copy = dma_q->bytes_left_in_line;
- if (bytes_to_copy > length)
- bytes_to_copy = length;
-
- if (dma_q->lines_completed >= dma_q->lines_per_field) {
- dma_q->bytes_left_in_line -= bytes_to_copy;
- dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ?
- 0 : 1;
- return 0;
- }
-
- dma_q->is_partial_line = 1;
-
- /* If we don't have a buffer, just return the number of bytes we would
- have copied if we had a buffer. */
- if (!buf) {
- dma_q->bytes_left_in_line -= bytes_to_copy;
- dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0)
- ? 0 : 1;
- return bytes_to_copy;
- }
-
- /* copy the data to video buffer */
- cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy);
-
- dma_q->pos += bytes_to_copy;
- dma_q->bytes_left_in_line -= bytes_to_copy;
-
- if (dma_q->bytes_left_in_line == 0) {
- dma_q->bytes_left_in_line = _line_size;
- dma_q->lines_completed++;
- dma_q->is_partial_line = 0;
-
- if (cx231xx_is_buffer_done(dev, dma_q) && buf) {
- buffer_filled(dev, dma_q, buf);
-
- dma_q->pos = 0;
- buf = NULL;
- dma_q->lines_completed = 0;
- }
- }
-
- return bytes_to_copy;
-}
-
-void cx231xx_reset_video_buffer(struct cx231xx *dev,
- struct cx231xx_dmaqueue *dma_q)
-{
- struct cx231xx_buffer *buf;
-
- /* handle the switch from field 1 to field 2 */
- if (dma_q->current_field == 1) {
- if (dma_q->lines_completed >= dma_q->lines_per_field)
- dma_q->field1_done = 1;
- else
- dma_q->field1_done = 0;
- }
-
- if (dev->USE_ISO)
- buf = dev->video_mode.isoc_ctl.buf;
- else
- buf = dev->video_mode.bulk_ctl.buf;
-
- if (buf == NULL) {
- /* first try to get the buffer */
- get_next_buf(dma_q, &buf);
-
- dma_q->pos = 0;
- dma_q->field1_done = 0;
- dma_q->current_field = -1;
- }
-
- /* reset the counters */
- dma_q->bytes_left_in_line = dev->width << 1;
- dma_q->lines_completed = 0;
-}
-
-int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
- u8 *p_buffer, u32 bytes_to_copy)
-{
- u8 *p_out_buffer = NULL;
- u32 current_line_bytes_copied = 0;
- struct cx231xx_buffer *buf;
- u32 _line_size = dev->width << 1;
- void *startwrite;
- int offset, lencopy;
-
- if (dev->USE_ISO)
- buf = dev->video_mode.isoc_ctl.buf;
- else
- buf = dev->video_mode.bulk_ctl.buf;
-
- if (buf == NULL)
- return -1;
-
- p_out_buffer = videobuf_to_vmalloc(&buf->vb);
-
- current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line;
-
- /* Offset field 2 one line from the top of the buffer */
- offset = (dma_q->current_field == 1) ? 0 : _line_size;
-
- /* Offset for field 2 */
- startwrite = p_out_buffer + offset;
-
- /* lines already completed in the current field */
- startwrite += (dma_q->lines_completed * _line_size * 2);
-
- /* bytes already completed in the current line */
- startwrite += current_line_bytes_copied;
-
- lencopy = dma_q->bytes_left_in_line > bytes_to_copy ?
- bytes_to_copy : dma_q->bytes_left_in_line;
-
- if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size))
- return 0;
-
- /* The below copies the UYVY data straight into video buffer */
- cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy);
-
- return 0;
-}
-
-void cx231xx_swab(u16 *from, u16 *to, u16 len)
-{
- u16 i;
-
- if (len <= 0)
- return;
-
- for (i = 0; i < len / 2; i++)
- to[i] = (from[i] << 8) | (from[i] >> 8);
-}
-
-u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q)
-{
- u8 buffer_complete = 0;
-
- /* Dual field stream */
- buffer_complete = ((dma_q->current_field == 2) &&
- (dma_q->lines_completed >= dma_q->lines_per_field) &&
- dma_q->field1_done);
-
- return buffer_complete;
-}
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
-{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
-
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
- if (0 == *count)
- *count = CX231XX_DEF_BUF;
-
- if (*count < CX231XX_MIN_BUF)
- *count = CX231XX_MIN_BUF;
-
- return 0;
-}
-
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
-{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
- unsigned long flags = 0;
-
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->video_mode.slock, flags);
- if (dev->USE_ISO) {
- if (dev->video_mode.isoc_ctl.buf == buf)
- dev->video_mode.isoc_ctl.buf = NULL;
- } else {
- if (dev->video_mode.bulk_ctl.buf == buf)
- dev->video_mode.bulk_ctl.buf = NULL;
- }
- spin_unlock_irqrestore(&dev->video_mode.slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx *dev = fh->dev;
- int rc = 0, urb_init = 0;
-
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
- + 7) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- if (dev->USE_ISO) {
- if (!dev->video_mode.isoc_ctl.num_bufs)
- urb_init = 1;
- } else {
- if (!dev->video_mode.bulk_ctl.num_bufs)
- urb_init = 1;
- }
- /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
- urb_init, dev->video_mode.max_pkt_size);*/
- if (urb_init) {
- dev->mode_tv = 0;
- if (dev->USE_ISO)
- rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_isoc_copy);
- else
- rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_bulk_copy);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = fh->dev;
- struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct cx231xx_buffer *buf =
- container_of(vb, struct cx231xx_buffer, vb);
- struct cx231xx_fh *fh = vq->priv_data;
- struct cx231xx *dev = (struct cx231xx *)fh->dev;
-
- cx231xx_isocdbg("cx231xx: called buffer_release\n");
-
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops cx231xx_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/********************* v4l2 interface **************************************/
-
-void video_mux(struct cx231xx *dev, int index)
-{
- dev->video_input = index;
- dev->ctl_ainput = INPUT(index)->amux;
-
- cx231xx_set_video_input_mux(dev, index);
-
- cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0);
-
- cx231xx_set_audio_input(dev, dev->ctl_ainput);
-
- cx231xx_info("video_mux : %d\n", index);
-
- /* do mode control overrides if required */
- cx231xx_do_mode_ctrl_overrides(dev);
-}
-
-/* Usage lock check functions */
-static int res_get(struct cx231xx_fh *fh)
-{
- struct cx231xx *dev = fh->dev;
- int rc = 0;
-
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (dev->stream_on)
- return -EBUSY;
- dev->stream_on = 1;
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (dev->vbi_stream_on)
- return -EBUSY;
- dev->vbi_stream_on = 1;
- } else
- return -EINVAL;
-
- fh->stream_on = 1;
-
- return rc;
-}
-
-static int res_check(struct cx231xx_fh *fh)
-{
- return fh->stream_on;
-}
-
-static void res_free(struct cx231xx_fh *fh)
-{
- struct cx231xx *dev = fh->dev;
-
- fh->stream_on = 0;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- dev->stream_on = 0;
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- dev->vbi_stream_on = 0;
-}
-
-static int check_dev(struct cx231xx *dev)
-{
- if (dev->state & DEV_DISCONNECTED) {
- cx231xx_errdev("v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------
- IOCTL vidioc handling
- ------------------------------------------------------------------*/
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
- return 0;
-}
-
-static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(format); i++)
- if (format[i].fourcc == fourcc)
- return &format[i];
-
- return NULL;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- unsigned int width = f->fmt.pix.width;
- unsigned int height = f->fmt.pix.height;
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
- struct cx231xx_fmt *fmt;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt) {
- cx231xx_videodbg("Fourcc format (%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- /* width must even because of the YUYV format
- height must be even because of interlacing */
- v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
-
- f->fmt.pix.width = width;
- f->fmt.pix.height = height;
- f->fmt.pix.pixelformat = fmt->fourcc;
- f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
- struct cx231xx_fmt *fmt;
- struct v4l2_mbus_framefmt mbus_fmt;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- vidioc_try_fmt_vid_cap(file, priv, f);
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt)
- return -EINVAL;
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- cx231xx_errdev("%s queue busy\n", __func__);
- return -EBUSY;
- }
-
- if (dev->stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
- return -EBUSY;
- }
-
- /* set new image size */
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
- dev->format = fmt;
-
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
- call_all(dev, video, s_mbus_fmt, &mbus_fmt);
- v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
-
- return rc;
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- *id = dev->norm;
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct v4l2_mbus_framefmt mbus_fmt;
- struct v4l2_format f;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
-
- dev->norm = *norm;
-
- /* Adjusts width/height, if needed */
- f.fmt.pix.width = dev->width;
- f.fmt.pix.height = dev->height;
- vidioc_try_fmt_vid_cap(file, priv, &f);
-
- call_all(dev, core, s_std, dev->norm);
-
- /* We need to reset basic properties in the decoder related to
- resolution (since a standard change effects things like the number
- of lines in VACT, etc) */
- v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
- call_all(dev, video, s_mbus_fmt, &mbus_fmt);
- v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
-
- /* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
-
- /* do mode control overrides */
- cx231xx_do_mode_ctrl_overrides(dev);
-
- return 0;
-}
-
-static const char *iname[] = {
- [CX231XX_VMUX_COMPOSITE1] = "Composite1",
- [CX231XX_VMUX_SVIDEO] = "S-Video",
- [CX231XX_VMUX_TELEVISION] = "Television",
- [CX231XX_VMUX_CABLE] = "Cable TV",
- [CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
-};
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- u32 gen_stat;
- unsigned int ret, n;
-
- n = i->index;
- if (n >= MAX_CX231XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
-
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- strcpy(i->name, iname[INPUT(n)->type]);
-
- if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX231XX_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- i->std = dev->vdev->tvnorms;
-
- /* If they are asking about the active input, read signal status */
- if (n == dev->video_input) {
- ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
- GEN_STAT, 2, &gen_stat, 4);
- if (ret > 0) {
- if ((gen_stat & FLD_VPRES) == 0x00)
- i->status |= V4L2_IN_ST_NO_SIGNAL;
- if ((gen_stat & FLD_HLOCK) == 0x00)
- i->status |= V4L2_IN_ST_NO_H_LOCK;
- }
- }
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- *i = dev->video_input;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- dev->mode_tv = 0;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (i >= MAX_CX231XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(i)->type)
- return -EINVAL;
-
- video_mux(dev, i);
-
- if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
- INPUT(i)->type == CX231XX_VMUX_CABLE) {
- /* There's a tuner, so reset the standard and put it on the
- last known frequency (since it was probably powered down
- until now */
- call_all(dev, core, s_std, dev->norm);
- }
-
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- switch (a->index) {
- case CX231XX_AMUX_VIDEO:
- strcpy(a->name, "Television");
- break;
- case CX231XX_AMUX_LINE_IN:
- strcpy(a->name, "Line In");
- break;
- default:
- return -EINVAL;
- }
-
- a->index = dev->ctl_ainput;
- a->capability = V4L2_AUDCAP_STEREO;
-
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int status = 0;
-
- /* Doesn't allow manual routing */
- if (a->index != dev->ctl_ainput)
- return -EINVAL;
-
- dev->ctl_ainput = INPUT(a->index)->amux;
- status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
-
- return status;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int id = qc->id;
- int i;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
- if (unlikely(qc->id == 0))
- return -EINVAL;
-
- memset(qc, 0, sizeof(*qc));
-
- qc->id = id;
-
- if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- for (i = 0; i < CX231XX_CTLS; i++)
- if (cx231xx_ctls[i].v.id == qc->id)
- break;
-
- if (i == CX231XX_CTLS) {
- *qc = no_ctl;
- return 0;
- }
- *qc = cx231xx_ctls[i].v;
-
- call_all(dev, core, queryctrl, qc);
-
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, g_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, s_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != t->index)
- return -EINVAL;
-
- strcpy(t->name, "Tuner");
-
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
- t->signal = 0xffff; /* LOCKED */
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != t->index)
- return -EINVAL;
-#if 0
- call_all(dev, tuner, s_tuner, t);
-#endif
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
-
- call_all(dev, tuner, g_frequency, f);
-
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
- u32 if_frequency = 5400000;
-
- cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
- f->frequency, f->type);
- /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != f->tuner)
- return -EINVAL;
-
- 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;
-
- /* set pre channel change settings in DIF first */
- rc = cx231xx_tuner_pre_channel_change(dev);
-
- dev->ctl_freq = f->frequency;
- call_all(dev, tuner, s_frequency, f);
-
- /* set post channel change settings in DIF first */
- rc = cx231xx_tuner_post_channel_change(dev);
-
- if (dev->tuner_type == TUNER_NXP_TDA18271) {
- if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
- if_frequency = 5400000; /*5.4MHz */
- else if (dev->norm & V4L2_STD_B)
- if_frequency = 6000000; /*6.0MHz */
- else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
- if_frequency = 6900000; /*6.9MHz */
- else if (dev->norm & V4L2_STD_GH)
- if_frequency = 7100000; /*7.1MHz */
- else if (dev->norm & V4L2_STD_PAL_I)
- if_frequency = 7250000; /*7.25MHz */
- else if (dev->norm & V4L2_STD_SECAM_L)
- if_frequency = 6900000; /*6.9MHz */
- else if (dev->norm & V4L2_STD_SECAM_LC)
- if_frequency = 1250000; /*1.25MHz */
-
- cx231xx_info("if_frequency is set to %d\n", if_frequency);
- cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
-
- update_HH_register_after_set_DIF(dev);
- }
-
- cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
-
- return rc;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-/*
- -R, --list-registers=type=<host/i2cdrv/i2caddr>,
- chip=<chip>[,min=<addr>,max=<addr>]
- dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
- -r, --set-register=type=<host/i2cdrv/i2caddr>,
- chip=<chip>,reg=<addr>,val=<val>
- set the register [VIDIOC_DBG_S_REGISTER]
-
- if type == host, then <chip> is the hosts chip ID (default 0)
- if type == i2cdrv (default), then <chip> is the I2C driver name or ID
- if type == i2caddr, then <chip> is the 7-bit I2C address
-*/
-
-static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int ret = 0;
- u8 value[4] = { 0, 0, 0, 0 };
- u32 data = 0;
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- switch (reg->match.addr) {
- case 0: /* Cx231xx - internal registers */
- ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
- (u16)reg->reg, value, 4);
- reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
- break;
- case 1: /* AFE - read byte */
- ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2, &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 14: /* AFE - read dword */
- ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- case 2: /* Video Block - read byte */
- ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2, &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 24: /* Video Block - read dword */
- ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- case 3: /* I2S block - read byte */
- ret = cx231xx_read_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- &data, 1);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 34: /* I2S Block - read dword */
- ret =
- cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1, &data, 4);
- reg->val = le32_to_cpu(data);
- break;
- }
- return ret < 0 ? ret : 0;
-
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- call_all(dev, core, g_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
- switch (reg->match.addr) {
- case 0: /* Cx231xx - internal registers */
- ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
- (u16)reg->reg, value, 4);
- reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
-
- break;
- case 0x600:/* AFE - read byte */
- ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
-
- case 0x880:/* Video Block - read byte */
- if (reg->reg < 0x0b) {
- ret = cx231xx_read_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- } else {
- ret = cx231xx_read_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- &data, 4 , 0);
- reg->val = le32_to_cpu(data);
- }
- break;
- case 0x980:
- ret = cx231xx_read_i2c_master(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0x400:
- ret =
- cx231xx_read_i2c_master(dev, 0x40,
- (u16)reg->reg, 1,
- &data, 1 , 0);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0xc01:
- ret =
- cx231xx_read_i2c_master(dev, 0xc0,
- (u16)reg->reg, 2,
- &data, 38, 1);
- reg->val = le32_to_cpu(data);
- break;
- case 0x022:
- ret =
- cx231xx_read_i2c_master(dev, 0x02,
- (u16)reg->reg, 1,
- &data, 1, 2);
- reg->val = le32_to_cpu(data & 0xff);
- break;
- case 0x322:
- ret = cx231xx_read_i2c_master(dev,
- 0x32,
- (u16)reg->reg, 1,
- &data, 4 , 2);
- reg->val = le32_to_cpu(data);
- break;
- case 0x342:
- ret = cx231xx_read_i2c_master(dev,
- 0x34,
- (u16)reg->reg, 1,
- &data, 4 , 2);
- reg->val = le32_to_cpu(data);
- break;
-
- default:
- cx231xx_info("no match device address!!\n");
- break;
- }
- return ret < 0 ? ret : 0;
- /*return -EINVAL;*/
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
- call_all(dev, core, g_register, reg);
-
- return ret;
-}
-
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int ret = 0;
- __le64 buf;
- u32 value;
- u8 data[4] = { 0, 0, 0, 0 };
-
- buf = cpu_to_le64(reg->val);
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_HOST:
- {
- value = (u32) buf & 0xffffffff;
-
- switch (reg->match.addr) {
- case 0: /* cx231xx internal registers */
- data[0] = (u8) value;
- data[1] = (u8) (value >> 8);
- data[2] = (u8) (value >> 16);
- data[3] = (u8) (value >> 24);
- ret = cx231xx_write_ctrl_reg(dev,
- VRT_SET_REGISTER,
- (u16)reg->reg, data,
- 4);
- break;
- case 1: /* AFE - read byte */
- ret = cx231xx_write_i2c_data(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 1);
- break;
- case 14: /* AFE - read dword */
- ret = cx231xx_write_i2c_data(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 4);
- break;
- case 2: /* Video Block - read byte */
- ret =
- cx231xx_write_i2c_data(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 1);
- break;
- case 24: /* Video Block - read dword */
- ret =
- cx231xx_write_i2c_data(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 4);
- break;
- case 3: /* I2S block - read byte */
- ret =
- cx231xx_write_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 1);
- break;
- case 34: /* I2S block - read dword */
- ret =
- cx231xx_write_i2c_data(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 4);
- break;
- }
- }
- return ret < 0 ? ret : 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- {
- value = (u32) buf & 0xffffffff;
-
- switch (reg->match.addr) {
- case 0:/*cx231xx internal registers*/
- data[0] = (u8) value;
- data[1] = (u8) (value >> 8);
- data[2] = (u8) (value >> 16);
- data[3] = (u8) (value >> 24);
- ret = cx231xx_write_ctrl_reg(dev,
- VRT_SET_REGISTER,
- (u16)reg->reg, data,
- 4);
- break;
- case 0x600:/* AFE - read byte */
- ret = cx231xx_write_i2c_master(dev,
- AFE_DEVICE_ADDRESS,
- (u16)reg->reg, 2,
- value, 1 , 0);
- break;
-
- case 0x880:/* Video Block - read byte */
- if (reg->reg < 0x0b)
- cx231xx_write_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 1, 0);
- else
- cx231xx_write_i2c_master(dev,
- VID_BLK_I2C_ADDRESS,
- (u16)reg->reg, 2,
- value, 4, 0);
- break;
- case 0x980:
- ret =
- cx231xx_write_i2c_master(dev,
- I2S_BLK_DEVICE_ADDRESS,
- (u16)reg->reg, 1,
- value, 1, 0);
- break;
- case 0x400:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x40,
- (u16)reg->reg, 1,
- value, 1, 0);
- break;
- case 0xc01:
- ret =
- cx231xx_write_i2c_master(dev,
- 0xc0,
- (u16)reg->reg, 1,
- value, 1, 1);
- break;
-
- case 0x022:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x02,
- (u16)reg->reg, 1,
- value, 1, 2);
- case 0x322:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x32,
- (u16)reg->reg, 1,
- value, 4, 2);
- break;
-
- case 0x342:
- ret =
- cx231xx_write_i2c_master(dev,
- 0x34,
- (u16)reg->reg, 1,
- value, 4, 2);
- break;
- default:
- cx231xx_info("no match device address, "
- "the value is %x\n", reg->match.addr);
- break;
-
- }
-
- }
- default:
- break;
- }
-
- call_all(dev, core, s_register, reg);
-
- return ret;
-}
-#endif
-
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- rc = res_get(fh);
-
- if (likely(rc >= 0))
- rc = videobuf_streamon(&fh->vb_vidq);
-
- call_all(dev, video, s_stream, 1);
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
- if (type != fh->type)
- return -EINVAL;
-
- cx25840_call(dev, video, s_stream, 0);
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
-
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_VBI_CAPTURE |
-#if 0
- V4L2_CAP_SLICED_VBI_CAPTURE |
-#endif
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (unlikely(f->index >= ARRAY_SIZE(format)))
- return -EINVAL;
-
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
- f->pixelformat = format[f->index].fourcc;
-
- return 0;
-}
-
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- f->fmt.sliced.service_set = 0;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- rc = -EINVAL;
-
- return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- return -EINVAL;
-
- return 0;
-}
-
-/* RAW VBI ioctls */
-
-static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- f->fmt.vbi.sampling_rate = 6750000 * 4;
- f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 0;
- f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
- f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_LINES : NTSC_VBI_LINES;
- f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
- f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
-
- return 0;
-
-}
-
-static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- if (dev->vbi_stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
- return -EBUSY;
- }
-
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = 6750000 * 4;
- f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 0;
- f->fmt.vbi.flags = 0;
- f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
- f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_LINES : NTSC_VBI_LINES;
- f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
- PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
- f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
-
- return 0;
-
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_reqbufs(&fh->vb_vidq, rb);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_querybuf(&fh->vb_vidq, b);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_qbuf(&fh->vb_vidq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
-}
-
-/* ----------------------------------------------------------- */
-/* RADIO ESPECIFIC IOCTLS */
-/* ----------------------------------------------------------- */
-
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
-
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
-static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
-
- if (unlikely(t->index > 0))
- return -EINVAL;
-
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- call_all(dev, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
-
- if (0 != t->index)
- return -EINVAL;
-
- call_all(dev, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- int i;
-
- if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX231XX_CTLS; i++) {
- if (cx231xx_ctls[i].v.id == c->id)
- break;
- }
- if (i == CX231XX_CTLS)
- return -EINVAL;
- *c = cx231xx_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
-}
-
-/*
- * cx231xx_v4l2_open()
- * inits the device and starts isoc transfer
- */
-static int cx231xx_v4l2_open(struct file *filp)
-{
- int errCode = 0, radio = 0;
- struct video_device *vdev = video_devdata(filp);
- struct cx231xx *dev = video_drvdata(filp);
- struct cx231xx_fh *fh;
- enum v4l2_buf_type fh_type = 0;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- cx231xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- dev->users);
-
-#if 0
- errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
- if (errCode < 0) {
- cx231xx_errdev
- ("Device locked on digital mode. Can't open analog\n");
- return -EBUSY;
- }
-#endif
-
- fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
- if (!fh) {
- cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
- return -ENOMEM;
- }
- fh->dev = dev;
- fh->radio = radio;
- fh->type = fh_type;
- filp->private_data = fh;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- dev->width = norm_maxw(dev);
- dev->height = norm_maxh(dev);
-
- /* Power up in Analog TV mode */
- if (dev->board.external_av)
- cx231xx_set_power_mode(dev,
- POLARIS_AVMODE_ENXTERNAL_AV);
- else
- cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
-
-#if 0
- cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
-#endif
-
- /* set video alternate setting */
- cx231xx_set_video_alternate(dev);
-
- /* Needed, since GPIO might have disabled power of
- some i2c device */
- cx231xx_config_i2c(dev);
-
- /* device needs to be initialized before isoc transfer */
- dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
-
- }
- if (fh->radio) {
- cx231xx_videodbg("video_open: setting radio device\n");
-
- /* cx231xx_start_radio(dev); */
-
- call_all(dev, tuner, s_radio);
- }
-
- dev->users++;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
- NULL, &dev->video_mode.slock,
- fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer),
- fh, &dev->lock);
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- /* Set the required alternate setting VBI interface works in
- Bulk mode only */
- cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
- NULL, &dev->vbi_mode.slock,
- fh->type, V4L2_FIELD_SEQ_TB,
- sizeof(struct cx231xx_buffer),
- fh, &dev->lock);
- }
-
- return errCode;
-}
-
-/*
- * cx231xx_realease_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
-*/
-void cx231xx_release_analog_resources(struct cx231xx *dev)
-{
-
- /*FIXME: I2C IR should be disconnected */
-
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
- if (dev->vbi_dev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
- }
- if (dev->vdev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
-
- if (dev->board.has_417)
- cx231xx_417_unregister(dev);
-
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
- }
-}
-
-/*
- * cx231xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2
- * calls and ioctls
- */
-static int cx231xx_v4l2_close(struct file *filp)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
-
- cx231xx_videodbg("users=%d\n", dev->users);
-
- cx231xx_videodbg("users=%d\n", dev->users);
- if (res_check(fh))
- res_free(fh);
-
- /*
- * To workaround error number=-71 on EP0 for VideoGrabber,
- * need exclude following.
- * FIXME: It is probably safe to remove most of these, as we're
- * now avoiding the alternate setting for INDEX_VANC
- */
- if (!dev->board.no_alt_vanc)
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- if (atomic_read(&dev->devlist_count) > 0) {
- cx231xx_release_resources(dev);
- fh->dev = NULL;
- return 0;
- }
- return 0;
- }
-
- /* do this before setting alternate! */
- cx231xx_uninit_vbi_isoc(dev);
-
- /* set alternate 0 */
- if (!dev->vbi_or_sliced_cc_mode)
- cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
- else
- cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
-
- kfree(fh);
- dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
- return 0;
- }
-
- dev->users--;
- if (!dev->users) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- cx231xx_release_resources(dev);
- fh->dev = NULL;
- return 0;
- }
-
- /* Save some power by putting tuner to sleep */
- call_all(dev, core, s_power, 0);
-
- /* do this before setting alternate! */
- if (dev->USE_ISO)
- cx231xx_uninit_isoc(dev);
- else
- cx231xx_uninit_bulk(dev);
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
-
- /* set alternate 0 */
- cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
- }
- kfree(fh);
- wake_up_interruptible_nr(&dev->open, 1);
- return 0;
-}
-
-/*
- * cx231xx_v4l2_read()
- * will allocate buffers when called for the first time
- */
-static ssize_t
-cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return rc;
-
- return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
- return 0;
-}
-
-/*
- * cx231xx_v4l2_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return POLLERR;
-
- if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
- (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type))
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- else
- return POLLERR;
-}
-
-/*
- * cx231xx_v4l2_mmap()
- */
-static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct cx231xx_fh *fh = filp->private_data;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- rc = res_get(fh);
-
- if (unlikely(rc < 0))
- return rc;
-
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-
- cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end -
- (unsigned long)vma->vm_start, rc);
-
- return rc;
-}
-
-static const struct v4l2_file_operations cx231xx_v4l_fops = {
- .owner = THIS_MODULE,
- .open = cx231xx_v4l2_open,
- .release = cx231xx_v4l2_close,
- .read = cx231xx_v4l2_read,
- .poll = cx231xx_v4l2_poll,
- .mmap = cx231xx_v4l2_mmap,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
-#endif
-};
-
-static struct video_device cx231xx_vbi_template;
-
-static const struct video_device cx231xx_video_template = {
- .fops = &cx231xx_v4l_fops,
- .release = video_device_release,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_PAL,
-};
-
-static const struct v4l2_file_operations radio_fops = {
- .owner = THIS_MODULE,
- .open = cx231xx_v4l2_open,
- .release = cx231xx_v4l2_close,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
- .vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
- .vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
-#endif
-};
-
-static struct video_device cx231xx_radio_template = {
- .name = "cx231xx-radio",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
-};
-
-/******************************** usb interface ******************************/
-
-static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
- const struct video_device
- *template, const char *type_name)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
- *vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
- vfd->debug = video_debug;
- vfd->lock = &dev->lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
-
- snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
-
- video_set_drvdata(vfd, dev);
- return vfd;
-}
-
-int cx231xx_register_analog_devices(struct cx231xx *dev)
-{
- int ret;
-
- cx231xx_info("%s: v4l2 driver version %s\n",
- dev->name, CX231XX_VERSION);
-
- /* set default norm */
- /*dev->norm = cx231xx_video_template.current_norm; */
- dev->width = norm_maxw(dev);
- dev->height = norm_maxh(dev);
- dev->interlaced = 0;
-
- /* Analog specific initialization */
- dev->format = &format[0];
-
- /* Set the initial input */
- video_mux(dev, dev->video_input);
-
- /* Audio defaults */
- dev->mute = 1;
- dev->volume = 0x1f;
-
- /* enable vbi capturing */
- /* write code here... */
-
- /* allocate and fill video video_device struct */
- dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
- if (!dev->vdev) {
- cx231xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
- }
-
- /* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
- video_nr[dev->devno]);
- if (ret) {
- cx231xx_errdev("unable to register video device (error=%i).\n",
- ret);
- return ret;
- }
-
- cx231xx_info("%s/0: registered device %s [v4l2]\n",
- dev->name, video_device_node_name(dev->vdev));
-
- /* Initialize VBI template */
- memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
- sizeof(cx231xx_vbi_template));
- strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
-
- /* Allocate and fill vbi video_device struct */
- dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
-
- /* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
- vbi_nr[dev->devno]);
- if (ret < 0) {
- cx231xx_errdev("unable to register vbi device\n");
- return ret;
- }
-
- cx231xx_info("%s/0: registered device %s\n",
- dev->name, video_device_node_name(dev->vbi_dev));
-
- if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
- dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
- cx231xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
- }
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
- radio_nr[dev->devno]);
- if (ret < 0) {
- cx231xx_errdev("can't register radio device\n");
- return ret;
- }
- cx231xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
- }
-
- cx231xx_info("V4L2 device registered as %s and %s\n",
- video_device_node_name(dev->vdev),
- video_device_node_name(dev->vbi_dev));
-
- return 0;
-}
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
deleted file mode 100644
index b391e9bda877..000000000000
--- a/drivers/media/video/cx23885/Kconfig
+++ /dev/null
@@ -1,46 +0,0 @@
-config VIDEO_CX23885
- tristate "Conexant cx23885 (2388x successor) support"
- depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
- select SND_PCM
- select I2C_ALGOBIT
- select VIDEO_BTCX
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- depends on RC_CORE
- select VIDEOBUF_DVB
- select VIDEOBUF_DMA_SG
- select VIDEO_CX25840
- select VIDEO_CX2341X
- select DVB_DIB7000P if !DVB_FE_CUSTOMISE
- select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_STV6110 if !DVB_FE_CUSTOMISE
- select DVB_CX24116 if !DVB_FE_CUSTOMISE
- select DVB_STV0900 if !DVB_FE_CUSTOMISE
- select DVB_DS3000 if !DVB_FE_CUSTOMISE
- select DVB_STV0367 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
- ---help---
- This is a video4linux driver for Conexant 23885 based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called cx23885
-
-config MEDIA_ALTERA_CI
- tristate "Altera FPGA based CI module"
- depends on VIDEO_CX23885 && DVB_CORE
- select ALTERA_STAPL
- ---help---
- An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card.
-
- To compile this driver as a module, choose M here: the
- module will be called altera-ci
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
deleted file mode 100644
index f81f2796a0f9..000000000000
--- a/drivers/media/video/cx23885/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
- cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
- cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \
- cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \
- cx23885-f300.o cx23885-alsa.o
-
-obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
-obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.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 += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
deleted file mode 100644
index f5c79e53e5a1..000000000000
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ /dev/null
@@ -1,1788 +0,0 @@
-/*
- *
- * Support for a cx23417 mpeg encoder via cx23885 host port.
- *
- * (c) 2004 Jelle Foks <jelle@foks.us>
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
- * (c) 2008 Steven Toth <stoth@linuxtv.org>
- * - CX23885/7/8 support
- *
- * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/cx2341x.h>
-
-#include "cx23885.h"
-#include "cx23885-ioctl.h"
-
-#define CX23885_FIRM_IMAGE_SIZE 376836
-#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
-
-static unsigned int mpegbufs = 32;
-module_param(mpegbufs, int, 0644);
-MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
-static unsigned int mpeglines = 32;
-module_param(mpeglines, int, 0644);
-MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
-static unsigned int mpeglinesize = 512;
-module_param(mpeglinesize, int, 0644);
-MODULE_PARM_DESC(mpeglinesize,
- "number of bytes in each line of an MPEG buffer, range 512-1024");
-
-static unsigned int v4l_debug;
-module_param(v4l_debug, int, 0644);
-MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
-
-#define dprintk(level, fmt, arg...)\
- do { if (v4l_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, \
- (dev) ? dev->name : "cx23885[?]", ## arg); \
- } while (0)
-
-static struct cx23885_tvnorm cx23885_tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- }, {
- .name = "NTSC-JP",
- .id = V4L2_STD_NTSC_M_JP,
- }, {
- .name = "PAL-BG",
- .id = V4L2_STD_PAL_BG,
- }, {
- .name = "PAL-DK",
- .id = V4L2_STD_PAL_DK,
- }, {
- .name = "PAL-I",
- .id = V4L2_STD_PAL_I,
- }, {
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- }, {
- .name = "PAL-N",
- .id = V4L2_STD_PAL_N,
- }, {
- .name = "PAL-Nc",
- .id = V4L2_STD_PAL_Nc,
- }, {
- .name = "PAL-60",
- .id = V4L2_STD_PAL_60,
- }, {
- .name = "SECAM-L",
- .id = V4L2_STD_SECAM_L,
- }, {
- .name = "SECAM-DK",
- .id = V4L2_STD_SECAM_DK,
- }
-};
-
-/* ------------------------------------------------------------------ */
-enum cx23885_capture_type {
- CX23885_MPEG_CAPTURE,
- CX23885_RAW_CAPTURE,
- CX23885_RAW_PASSTHRU_CAPTURE
-};
-enum cx23885_capture_bits {
- CX23885_RAW_BITS_NONE = 0x00,
- CX23885_RAW_BITS_YUV_CAPTURE = 0x01,
- CX23885_RAW_BITS_PCM_CAPTURE = 0x02,
- CX23885_RAW_BITS_VBI_CAPTURE = 0x04,
- CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
- CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
-};
-enum cx23885_capture_end {
- CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
- CX23885_END_NOW, /* stop immediately, no irq */
-};
-enum cx23885_framerate {
- CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
- CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
-};
-enum cx23885_stream_port {
- CX23885_OUTPUT_PORT_MEMORY,
- CX23885_OUTPUT_PORT_STREAMING,
- CX23885_OUTPUT_PORT_SERIAL
-};
-enum cx23885_data_xfer_status {
- CX23885_MORE_BUFFERS_FOLLOW,
- CX23885_LAST_BUFFER,
-};
-enum cx23885_picture_mask {
- CX23885_PICTURE_MASK_NONE,
- CX23885_PICTURE_MASK_I_FRAMES,
- CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
- CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
-};
-enum cx23885_vbi_mode_bits {
- CX23885_VBI_BITS_SLICED,
- CX23885_VBI_BITS_RAW,
-};
-enum cx23885_vbi_insertion_bits {
- CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
- CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
- CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
- CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
- CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
-};
-enum cx23885_dma_unit {
- CX23885_DMA_BYTES,
- CX23885_DMA_FRAMES,
-};
-enum cx23885_dma_transfer_status_bits {
- CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
- CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
- CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
-};
-enum cx23885_pause {
- CX23885_PAUSE_ENCODING,
- CX23885_RESUME_ENCODING,
-};
-enum cx23885_copyright {
- CX23885_COPYRIGHT_OFF,
- CX23885_COPYRIGHT_ON,
-};
-enum cx23885_notification_type {
- CX23885_NOTIFICATION_REFRESH,
-};
-enum cx23885_notification_status {
- CX23885_NOTIFICATION_OFF,
- CX23885_NOTIFICATION_ON,
-};
-enum cx23885_notification_mailbox {
- CX23885_NOTIFICATION_NO_MAILBOX = -1,
-};
-enum cx23885_field1_lines {
- CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
- CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
- CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
-};
-enum cx23885_field2_lines {
- CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
- CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
- CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
-};
-enum cx23885_custom_data_type {
- CX23885_CUSTOM_EXTENSION_USR_DATA,
- CX23885_CUSTOM_PRIVATE_PACKET,
-};
-enum cx23885_mute {
- CX23885_UNMUTE,
- CX23885_MUTE,
-};
-enum cx23885_mute_video_mask {
- CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
- CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
- CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
-};
-enum cx23885_mute_video_shift {
- CX23885_MUTE_VIDEO_V_SHIFT = 8,
- CX23885_MUTE_VIDEO_U_SHIFT = 16,
- CX23885_MUTE_VIDEO_Y_SHIFT = 24,
-};
-
-/* defines below are from ivtv-driver.h */
-#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
-
-/* Firmware API commands */
-#define IVTV_API_STD_TIMEOUT 500
-
-/* Registers */
-/* IVTV_REG_OFFSET */
-#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
-#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
-#define IVTV_REG_SPU (0x9050)
-#define IVTV_REG_HW_BLOCKS (0x9054)
-#define IVTV_REG_VPU (0x9058)
-#define IVTV_REG_APU (0xA064)
-
-/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
- bits 31-16
-+-----------+
-| Reserved |
-+-----------+
- bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
-+-------+-------+-------+-------+-------+-------+-------+-------+
-| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
-+-------+-------+-------+-------+-------+-------+-------+-------+
- bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
-+-------+-------+-------+-------+-------+-------+-------+-------+
-|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
-+-------+-------+-------+-------+-------+-------+-------+-------+
-***/
-#define MC417_MIWR 0x8000
-#define MC417_MIRD 0x4000
-#define MC417_MICS 0x2000
-#define MC417_MIRDY 0x1000
-#define MC417_MIADDR 0x0F00
-#define MC417_MIDATA 0x00FF
-
-/* MIADDR* nibble definitions */
-#define MCI_MEMORY_DATA_BYTE0 0x000
-#define MCI_MEMORY_DATA_BYTE1 0x100
-#define MCI_MEMORY_DATA_BYTE2 0x200
-#define MCI_MEMORY_DATA_BYTE3 0x300
-#define MCI_MEMORY_ADDRESS_BYTE2 0x400
-#define MCI_MEMORY_ADDRESS_BYTE1 0x500
-#define MCI_MEMORY_ADDRESS_BYTE0 0x600
-#define MCI_REGISTER_DATA_BYTE0 0x800
-#define MCI_REGISTER_DATA_BYTE1 0x900
-#define MCI_REGISTER_DATA_BYTE2 0xA00
-#define MCI_REGISTER_DATA_BYTE3 0xB00
-#define MCI_REGISTER_ADDRESS_BYTE0 0xC00
-#define MCI_REGISTER_ADDRESS_BYTE1 0xD00
-#define MCI_REGISTER_MODE 0xE00
-
-/* Read and write modes */
-#define MCI_MODE_REGISTER_READ 0
-#define MCI_MODE_REGISTER_WRITE 1
-#define MCI_MODE_MEMORY_READ 0
-#define MCI_MODE_MEMORY_WRITE 0x40
-
-/*** Bit definitions for MC417_CTL register ****
- bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
-+--------+-------------+--------+--------------+------------+
-|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
-+--------+-------------+--------+--------------+------------+
-***/
-#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
-#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
-#define MC417_UART_GPIO_EN 0x00000001
-
-/* Values for speed control */
-#define MC417_SPD_CTL_SLOW 0x1
-#define MC417_SPD_CTL_MEDIUM 0x0
-#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
-
-/* Values for GPIO select */
-#define MC417_GPIO_SEL_GPIO3 0x3
-#define MC417_GPIO_SEL_GPIO2 0x2
-#define MC417_GPIO_SEL_GPIO1 0x1
-#define MC417_GPIO_SEL_GPIO0 0x0
-
-void cx23885_mc417_init(struct cx23885_dev *dev)
-{
- u32 regval;
-
- dprintk(2, "%s()\n", __func__);
-
- /* Configure MC417_CTL register to defaults. */
- regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) |
- MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) |
- MC417_UART_GPIO_EN;
- cx_write(MC417_CTL, regval);
-
- /* Configure MC417_OEN to defaults. */
- regval = MC417_MIRDY;
- cx_write(MC417_OEN, regval);
-
- /* Configure MC417_RWD to defaults. */
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
- cx_write(MC417_RWD, regval);
-}
-
-static int mc417_wait_ready(struct cx23885_dev *dev)
-{
- u32 mi_ready;
- unsigned long timeout = jiffies + msecs_to_jiffies(1);
-
- for (;;) {
- mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
- if (mi_ready != 0)
- return 0;
- if (time_after(jiffies, timeout))
- return -1;
- udelay(1);
- }
-}
-
-int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
-{
- u32 regval;
-
- /* Enable MC417 GPIO outputs except for MC417_MIRDY,
- * which is an input.
- */
- cx_write(MC417_OEN, MC417_MIRDY);
-
- /* Write data byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
- (value & 0x000000FF);
- cx_write(MC417_RWD, regval);
-
- /* Transition CS/WR to effect write transaction across bus. */
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
- ((value >> 8) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
- ((value >> 16) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 3 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
- ((value >> 24) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
- (address & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
- ((address >> 8) & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Indicate that this is a write. */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
- MCI_MODE_REGISTER_WRITE;
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Wait for the trans to complete (MC417_MIRDY asserted). */
- return mc417_wait_ready(dev);
-}
-
-int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
-{
- int retval;
- u32 regval;
- u32 tempval;
- u32 dataval;
-
- /* Enable MC417 GPIO outputs except for MC417_MIRDY,
- * which is an input.
- */
- cx_write(MC417_OEN, MC417_MIRDY);
-
- /* Write address byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
- ((address & 0x00FF));
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
- ((address >> 8) & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Indicate that this is a register read. */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
- MCI_MODE_REGISTER_READ;
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Wait for the trans to complete (MC417_MIRDY asserted). */
- retval = mc417_wait_ready(dev);
-
- /* switch the DAT0-7 GPIO[10:3] to input mode */
- cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
-
- /* Read data byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
- cx_write(MC417_RWD, regval);
-
- /* Transition RD to effect read transaction across bus.
- * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
- * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
- * input only...)
- */
- regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
- cx_write(MC417_RWD, regval);
-
- /* Collect byte */
- tempval = cx_read(MC417_RWD);
- dataval = tempval & 0x000000FF;
-
- /* Bring CS and RD high. */
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= ((tempval & 0x000000FF) << 8);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= ((tempval & 0x000000FF) << 16);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 3 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= ((tempval & 0x000000FF) << 24);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- *value = dataval;
-
- return retval;
-}
-
-int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
-{
- u32 regval;
-
- /* Enable MC417 GPIO outputs except for MC417_MIRDY,
- * which is an input.
- */
- cx_write(MC417_OEN, MC417_MIRDY);
-
- /* Write data byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
- (value & 0x000000FF);
- cx_write(MC417_RWD, regval);
-
- /* Transition CS/WR to effect write transaction across bus. */
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
- ((value >> 8) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
- ((value >> 16) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write data byte 3 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
- ((value >> 24) & 0x000000FF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
- MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
- ((address >> 8) & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
- (address & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Wait for the trans to complete (MC417_MIRDY asserted). */
- return mc417_wait_ready(dev);
-}
-
-int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
-{
- int retval;
- u32 regval;
- u32 tempval;
- u32 dataval;
-
- /* Enable MC417 GPIO outputs except for MC417_MIRDY,
- * which is an input.
- */
- cx_write(MC417_OEN, MC417_MIRDY);
-
- /* Write address byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
- MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
- ((address >> 8) & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Write address byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
- (address & 0xFF);
- cx_write(MC417_RWD, regval);
- regval |= MC417_MICS | MC417_MIWR;
- cx_write(MC417_RWD, regval);
-
- /* Wait for the trans to complete (MC417_MIRDY asserted). */
- retval = mc417_wait_ready(dev);
-
- /* switch the DAT0-7 GPIO[10:3] to input mode */
- cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
-
- /* Read data byte 3 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
- cx_write(MC417_RWD, regval);
-
- /* Transition RD to effect read transaction across bus. */
- regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
- cx_write(MC417_RWD, regval);
-
- /* Collect byte */
- tempval = cx_read(MC417_RWD);
- dataval = ((tempval & 0x000000FF) << 24);
-
- /* Bring CS and RD high. */
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 2 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= ((tempval & 0x000000FF) << 16);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 1 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= ((tempval & 0x000000FF) << 8);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- /* Read data byte 0 */
- regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
- cx_write(MC417_RWD, regval);
- regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
- cx_write(MC417_RWD, regval);
- tempval = cx_read(MC417_RWD);
- dataval |= (tempval & 0x000000FF);
- regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
- cx_write(MC417_RWD, regval);
-
- *value = dataval;
-
- return retval;
-}
-
-void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
-{
- u32 val;
-
- /* Set the gpio value */
- mc417_register_read(dev, 0x900C, &val);
- val |= (mask & 0x000ffff);
- mc417_register_write(dev, 0x900C, val);
-}
-
-void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
-{
- u32 val;
-
- /* Clear the gpio value */
- mc417_register_read(dev, 0x900C, &val);
- val &= ~(mask & 0x0000ffff);
- mc417_register_write(dev, 0x900C, val);
-}
-
-void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
-{
- u32 val;
-
- /* Enable GPIO direction bits */
- mc417_register_read(dev, 0x9020, &val);
- if (asoutput)
- val |= (mask & 0x0000ffff);
- else
- val &= ~(mask & 0x0000ffff);
-
- mc417_register_write(dev, 0x9020, val);
-}
-/* ------------------------------------------------------------------ */
-
-/* MPEG encoder API */
-static char *cmd_to_str(int cmd)
-{
- switch (cmd) {
- case CX2341X_ENC_PING_FW:
- return "PING_FW";
- case CX2341X_ENC_START_CAPTURE:
- return "START_CAPTURE";
- case CX2341X_ENC_STOP_CAPTURE:
- return "STOP_CAPTURE";
- case CX2341X_ENC_SET_AUDIO_ID:
- return "SET_AUDIO_ID";
- case CX2341X_ENC_SET_VIDEO_ID:
- return "SET_VIDEO_ID";
- case CX2341X_ENC_SET_PCR_ID:
- return "SET_PCR_ID";
- case CX2341X_ENC_SET_FRAME_RATE:
- return "SET_FRAME_RATE";
- case CX2341X_ENC_SET_FRAME_SIZE:
- return "SET_FRAME_SIZE";
- case CX2341X_ENC_SET_BIT_RATE:
- return "SET_BIT_RATE";
- case CX2341X_ENC_SET_GOP_PROPERTIES:
- return "SET_GOP_PROPERTIES";
- case CX2341X_ENC_SET_ASPECT_RATIO:
- return "SET_ASPECT_RATIO";
- case CX2341X_ENC_SET_DNR_FILTER_MODE:
- return "SET_DNR_FILTER_MODE";
- case CX2341X_ENC_SET_DNR_FILTER_PROPS:
- return "SET_DNR_FILTER_PROPS";
- case CX2341X_ENC_SET_CORING_LEVELS:
- return "SET_CORING_LEVELS";
- case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
- return "SET_SPATIAL_FILTER_TYPE";
- case CX2341X_ENC_SET_VBI_LINE:
- return "SET_VBI_LINE";
- case CX2341X_ENC_SET_STREAM_TYPE:
- return "SET_STREAM_TYPE";
- case CX2341X_ENC_SET_OUTPUT_PORT:
- return "SET_OUTPUT_PORT";
- case CX2341X_ENC_SET_AUDIO_PROPERTIES:
- return "SET_AUDIO_PROPERTIES";
- case CX2341X_ENC_HALT_FW:
- return "HALT_FW";
- case CX2341X_ENC_GET_VERSION:
- return "GET_VERSION";
- case CX2341X_ENC_SET_GOP_CLOSURE:
- return "SET_GOP_CLOSURE";
- case CX2341X_ENC_GET_SEQ_END:
- return "GET_SEQ_END";
- case CX2341X_ENC_SET_PGM_INDEX_INFO:
- return "SET_PGM_INDEX_INFO";
- case CX2341X_ENC_SET_VBI_CONFIG:
- return "SET_VBI_CONFIG";
- case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
- return "SET_DMA_BLOCK_SIZE";
- case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
- return "GET_PREV_DMA_INFO_MB_10";
- case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
- return "GET_PREV_DMA_INFO_MB_9";
- case CX2341X_ENC_SCHED_DMA_TO_HOST:
- return "SCHED_DMA_TO_HOST";
- case CX2341X_ENC_INITIALIZE_INPUT:
- return "INITIALIZE_INPUT";
- case CX2341X_ENC_SET_FRAME_DROP_RATE:
- return "SET_FRAME_DROP_RATE";
- case CX2341X_ENC_PAUSE_ENCODER:
- return "PAUSE_ENCODER";
- case CX2341X_ENC_REFRESH_INPUT:
- return "REFRESH_INPUT";
- case CX2341X_ENC_SET_COPYRIGHT:
- return "SET_COPYRIGHT";
- case CX2341X_ENC_SET_EVENT_NOTIFICATION:
- return "SET_EVENT_NOTIFICATION";
- case CX2341X_ENC_SET_NUM_VSYNC_LINES:
- return "SET_NUM_VSYNC_LINES";
- case CX2341X_ENC_SET_PLACEHOLDER:
- return "SET_PLACEHOLDER";
- case CX2341X_ENC_MUTE_VIDEO:
- return "MUTE_VIDEO";
- case CX2341X_ENC_MUTE_AUDIO:
- return "MUTE_AUDIO";
- case CX2341X_ENC_MISC:
- return "MISC";
- default:
- return "UNKNOWN";
- }
-}
-
-static int cx23885_mbox_func(void *priv,
- u32 command,
- int in,
- int out,
- u32 data[CX2341X_MBOX_MAX_DATA])
-{
- struct cx23885_dev *dev = priv;
- unsigned long timeout;
- u32 value, flag, retval = 0;
- int i;
-
- dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
- cmd_to_str(command));
-
- /* this may not be 100% safe if we can't read any memory location
- without side effects */
- mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
- if (value != 0x12345678) {
- printk(KERN_ERR
- "Firmware and/or mailbox pointer not initialized "
- "or corrupted, signature = 0x%x, cmd = %s\n", value,
- cmd_to_str(command));
- return -1;
- }
-
- /* This read looks at 32 bits, but flag is only 8 bits.
- * Seems we also bail if CMD or TIMEOUT bytes are set???
- */
- mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
- if (flag) {
- printk(KERN_ERR "ERROR: Mailbox appears to be in use "
- "(%x), cmd = %s\n", flag, cmd_to_str(command));
- return -1;
- }
-
- flag |= 1; /* tell 'em we're working on it */
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- /* write command + args + fill remaining with zeros */
- /* command code */
- mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
- mc417_memory_write(dev, dev->cx23417_mailbox + 3,
- IVTV_API_STD_TIMEOUT); /* timeout */
- for (i = 0; i < in; i++) {
- mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
- dprintk(3, "API Input %d = %d\n", i, data[i]);
- }
- for (; i < CX2341X_MBOX_MAX_DATA; i++)
- mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
-
- flag |= 3; /* tell 'em we're done writing */
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- /* wait for firmware to handle the API command */
- timeout = jiffies + msecs_to_jiffies(10);
- for (;;) {
- mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
- if (0 != (flag & 4))
- break;
- if (time_after(jiffies, timeout)) {
- printk(KERN_ERR "ERROR: API Mailbox timeout\n");
- return -1;
- }
- udelay(10);
- }
-
- /* read output values */
- for (i = 0; i < out; i++) {
- mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
- dprintk(3, "API Output %d = %d\n", i, data[i]);
- }
-
- mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
- dprintk(3, "API result = %d\n", retval);
-
- flag = 0;
- mc417_memory_write(dev, dev->cx23417_mailbox, flag);
-
- return retval;
-}
-
-/* We don't need to call the API often, so using just one
- * mailbox will probably suffice
- */
-static int cx23885_api_cmd(struct cx23885_dev *dev,
- u32 command,
- u32 inputcnt,
- u32 outputcnt,
- ...)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
- va_list vargs;
- int i, err;
-
- dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
-
- va_start(vargs, outputcnt);
- for (i = 0; i < inputcnt; i++)
- data[i] = va_arg(vargs, int);
-
- err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
- for (i = 0; i < outputcnt; i++) {
- int *vptr = va_arg(vargs, int *);
- *vptr = data[i];
- }
- va_end(vargs);
-
- return err;
-}
-
-static int cx23885_find_mailbox(struct cx23885_dev *dev)
-{
- u32 signature[4] = {
- 0x12345678, 0x34567812, 0x56781234, 0x78123456
- };
- int signaturecnt = 0;
- u32 value;
- int i;
-
- dprintk(2, "%s()\n", __func__);
-
- for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
- mc417_memory_read(dev, i, &value);
- if (value == signature[signaturecnt])
- signaturecnt++;
- else
- signaturecnt = 0;
- if (4 == signaturecnt) {
- dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
- return i+1;
- }
- }
- printk(KERN_ERR "Mailbox signature values not found!\n");
- return -1;
-}
-
-static int cx23885_load_firmware(struct cx23885_dev *dev)
-{
- static const unsigned char magic[8] = {
- 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
- };
- const struct firmware *firmware;
- int i, retval = 0;
- u32 value = 0;
- u32 gpio_output = 0;
- u32 gpio_value;
- u32 checksum = 0;
- u32 *dataptr;
-
- dprintk(2, "%s()\n", __func__);
-
- /* Save GPIO settings before reset of APU */
- retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
- retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
-
- retval = mc417_register_write(dev,
- IVTV_REG_VPU, 0xFFFFFFED);
- retval |= mc417_register_write(dev,
- IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= mc417_register_write(dev,
- IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
- retval |= mc417_register_write(dev,
- IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
- retval |= mc417_register_write(dev,
- IVTV_REG_APU, 0);
-
- if (retval != 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
- return -1;
- }
-
- retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
- &dev->pci->dev);
-
- if (retval != 0) {
- printk(KERN_ERR
- "ERROR: Hotplug firmware request failed (%s).\n",
- CX23885_FIRM_IMAGE_NAME);
- printk(KERN_ERR "Please fix your hotplug setup, the board will "
- "not work without firmware loaded!\n");
- return -1;
- }
-
- if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
- printk(KERN_ERR "ERROR: Firmware size mismatch "
- "(have %zd, expected %d)\n",
- firmware->size, CX23885_FIRM_IMAGE_SIZE);
- release_firmware(firmware);
- return -1;
- }
-
- if (0 != memcmp(firmware->data, magic, 8)) {
- printk(KERN_ERR
- "ERROR: Firmware magic mismatch, wrong file?\n");
- release_firmware(firmware);
- return -1;
- }
-
- /* transfer to the chip */
- dprintk(2, "Loading firmware ...\n");
- dataptr = (u32 *)firmware->data;
- for (i = 0; i < (firmware->size >> 2); i++) {
- value = *dataptr;
- checksum += ~value;
- if (mc417_memory_write(dev, i, value) != 0) {
- printk(KERN_ERR "ERROR: Loading firmware failed!\n");
- release_firmware(firmware);
- return -1;
- }
- dataptr++;
- }
-
- /* read back to verify with the checksum */
- dprintk(1, "Verifying firmware ...\n");
- for (i--; i >= 0; i--) {
- if (mc417_memory_read(dev, i, &value) != 0) {
- printk(KERN_ERR "ERROR: Reading firmware failed!\n");
- release_firmware(firmware);
- return -1;
- }
- checksum -= ~value;
- }
- if (checksum) {
- printk(KERN_ERR
- "ERROR: Firmware load failed (checksum mismatch).\n");
- release_firmware(firmware);
- return -1;
- }
- release_firmware(firmware);
- dprintk(1, "Firmware upload successful.\n");
-
- retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
- IVTV_CMD_HW_BLOCKS_RST);
-
- /* F/W power up disturbs the GPIOs, restore state */
- retval |= mc417_register_write(dev, 0x9020, gpio_output);
- 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__);
- return 0;
-}
-
-void cx23885_417_check_encoder(struct cx23885_dev *dev)
-{
- u32 status, seq;
-
- status = seq = 0;
- cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
- dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
-}
-
-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);
-
- dev->mpeg_params.width = dev->ts1.width;
- dev->mpeg_params.height = dev->ts1.height;
- dev->mpeg_params.is_50hz =
- (dev->encodernorm.id & V4L2_STD_625_50) != 0;
-
- cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
-
- cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
- cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
-}
-
-static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
-{
- int version;
- int retval;
- u32 i, data[7];
-
- dprintk(1, "%s()\n", __func__);
-
- retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
- if (retval < 0) {
- dprintk(2, "%s() PING OK\n", __func__);
- retval = cx23885_load_firmware(dev);
- if (retval < 0) {
- printk(KERN_ERR "%s() f/w load failed\n", __func__);
- return retval;
- }
- retval = cx23885_find_mailbox(dev);
- if (retval < 0) {
- printk(KERN_ERR "%s() mailbox < 0, error\n",
- __func__);
- return -1;
- }
- dev->cx23417_mailbox = retval;
- retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
- if (retval < 0) {
- printk(KERN_ERR
- "ERROR: cx23417 firmware ping failed!\n");
- return -1;
- }
- retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
- &version);
- if (retval < 0) {
- printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
- "version failed!\n");
- return -1;
- }
- dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
- msleep(200);
- }
-
- cx23885_codec_settings(dev);
- msleep(60);
-
- cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
- CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
- cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
- CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0);
-
- /* Setup to capture VBI */
- data[0] = 0x0001BD00;
- data[1] = 1; /* frames per interrupt */
- data[2] = 4; /* total bufs */
- data[3] = 0x91559155; /* start codes */
- data[4] = 0x206080C0; /* stop codes */
- data[5] = 6; /* lines */
- data[6] = 64; /* BPL */
-
- cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
- data[2], data[3], data[4], data[5], data[6]);
-
- for (i = 2; i <= 24; i++) {
- int valid;
-
- valid = ((i >= 19) && (i <= 21));
- cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
- valid, 0 , 0, 0);
- cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
- i | 0x80000000, valid, 0, 0, 0);
- }
-
- cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
- msleep(60);
-
- /* initialize the video input */
- cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
- msleep(60);
-
- /* Enable VIP style pixel invalidation so we work with scaled mode */
- mc417_memory_write(dev, 2120, 0x00000080);
-
- /* start capturing to the host interface */
- if (startencoder) {
- cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
- CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
- msleep(10);
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int bb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
-{
- struct cx23885_fh *fh = q->priv_data;
-
- fh->dev->ts1.ts_packet_size = mpeglinesize;
- fh->dev->ts1.ts_packet_count = mpeglines;
-
- *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
- *count = mpegbufs;
-
- return 0;
-}
-
-static int bb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct cx23885_fh *fh = q->priv_data;
- return cx23885_buf_prepare(q, &fh->dev->ts1,
- (struct cx23885_buffer *)vb,
- field);
-}
-
-static void bb_buf_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct cx23885_fh *fh = q->priv_data;
- cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
-}
-
-static void bb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
-}
-
-static struct videobuf_queue_ops cx23885_qops = {
- .buf_setup = bb_buf_setup,
- .buf_prepare = bb_buf_prepare,
- .buf_queue = bb_buf_queue,
- .buf_release = bb_buf_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-static const u32 *ctrl_classes[] = {
- cx2341x_mpeg_ctrls,
- NULL
-};
-
-static int cx23885_queryctrl(struct cx23885_dev *dev,
- struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
-
- /* MPEG V4L2 controls */
- if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-
- return 0;
-}
-
-static int cx23885_querymenu(struct cx23885_dev *dev,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = qmenu->id;
- cx23885_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- 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;
- struct cx23885_dev *dev = fh->dev;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
- if (*id & cx23885_tvnorms[i].id)
- break;
- 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 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)
-{
- return cx23885_get_input(file, priv, i);
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- return cx23885_set_input(file, priv, i);
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
- strcpy(t->name, "Television");
- call_all(dev, tuner, g_tuner, t);
-
- dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -EINVAL;
-
- /* Update the A/V core */
- call_all(dev, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- f->type = V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->freq;
-
- call_all(dev, tuner, g_frequency, f);
-
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- return cx23885_set_frequency(file, priv, f);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_set_control(dev, ctl);
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
- struct cx23885_tsport *tsport = &dev->ts1;
-
- strlcpy(cap->driver, dev->name, sizeof(cap->driver));
- strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- 0;
- if (UNSET != dev->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (f->index != 0)
- return -EINVAL;
-
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->pixelformat = V4L2_PIX_FMT_MPEG;
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->ts1.width;
- f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_reqbufs(&fh->mpegq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_querybuf(&fh->mpegq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_qbuf(&fh->mpegq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx23885_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-
- if (err == 0) {
- err = cx2341x_update(dev, cx23885_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
- return err;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- return err;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- call_all(dev, core, log_status);
- cx2341x_log_status(&dev->mpeg_params, name);
- printk(KERN_INFO
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *a)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- return cx23885_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- return cx23885_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
- struct cx23885_dev *dev = video_drvdata(file);
- struct cx23885_fh *fh;
-
- dprintk(2, "%s()\n", __func__);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (!fh)
- return -ENOMEM;
-
- file->private_data = fh;
- fh->dev = dev;
-
- videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
- &dev->pci->dev, &dev->ts1.slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx23885_buffer),
- fh, NULL);
- return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- /* FIXME: Review this crap */
- /* Shut device down on last close */
- if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
- if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
- /* stop mpeg capture */
- cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX23885_END_NOW, CX23885_MPEG_CAPTURE,
- CX23885_RAW_BITS_NONE);
-
- msleep(500);
- cx23885_417_check_encoder(dev);
-
- cx23885_cancel_buffers(&fh->dev->ts1);
- }
- }
-
- if (fh->mpegq.streaming)
- videobuf_streamoff(&fh->mpegq);
- if (fh->mpegq.reading)
- videobuf_read_stop(&fh->mpegq);
-
- videobuf_mmap_free(&fh->mpegq);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
- /* 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, 1) < 0)
- return -EINVAL;
- }
- }
-
- return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s\n", __func__);
-
- return videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- return videobuf_mmap_mapper(&fh->mpegq, vma);
-}
-
-static struct v4l2_file_operations mpeg_fops = {
- .owner = THIS_MODULE,
- .open = mpeg_open,
- .release = mpeg_release,
- .read = mpeg_read,
- .poll = mpeg_poll,
- .mmap = mpeg_mmap,
- .ioctl = video_ioctl2,
-};
-
-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,
- .vidioc_s_input = vidioc_s_input,
- .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_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,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .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_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_querymenu = vidioc_querymenu,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_chip_ident = cx23885_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx23885_g_register,
- .vidioc_s_register = cx23885_s_register,
-#endif
-};
-
-static struct video_device cx23885_mpeg_template = {
- .name = "cx23885",
- .fops = &mpeg_fops,
- .ioctl_ops = &mpeg_ioctl_ops,
- .tvnorms = CX23885_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-void cx23885_417_unregister(struct cx23885_dev *dev)
-{
- dprintk(1, "%s()\n", __func__);
-
- if (dev->v4l_device) {
- if (video_is_registered(dev->v4l_device))
- video_unregister_device(dev->v4l_device);
- else
- video_device_release(dev->v4l_device);
- dev->v4l_device = NULL;
- }
-}
-
-static struct video_device *cx23885_video_dev_alloc(
- struct cx23885_tsport *tsport,
- struct pci_dev *pci,
- struct video_device *template,
- char *type)
-{
- struct video_device *vfd;
- struct cx23885_dev *dev = tsport->dev;
-
- dprintk(1, "%s()\n", __func__);
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template;
- 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;
-}
-
-int cx23885_417_register(struct cx23885_dev *dev)
-{
- /* FIXME: Port1 hardcoded here */
- int err = -ENODEV;
- struct cx23885_tsport *tsport = &dev->ts1;
-
- dprintk(1, "%s()\n", __func__);
-
- if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
- return err;
-
- /* Set default TV standard */
- dev->encodernorm = cx23885_tvnorms[0];
-
- if (dev->encodernorm.id & V4L2_STD_525_60)
- tsport->height = 480;
- else
- tsport->height = 576;
-
- tsport->width = 720;
- cx2341x_fill_defaults(&dev->mpeg_params);
-
- dev->mpeg_params.port = CX2341X_PORT_SERIAL;
-
- /* Allocate and initialize V4L video device */
- dev->v4l_device = cx23885_video_dev_alloc(tsport,
- dev->pci, &cx23885_mpeg_template, "mpeg");
- video_set_drvdata(dev->v4l_device, dev);
- err = video_register_device(dev->v4l_device,
- VFL_TYPE_GRABBER, -1);
- if (err < 0) {
- printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
- return err;
- }
-
- 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
deleted file mode 100644
index 080e11157e5f..000000000000
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ /dev/null
@@ -1,1680 +0,0 @@
-/*
- * Driver for the Conexant CX23885 PCIe bridge
- *
- * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
- *
- * 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/pci.h>
-#include <linux/delay.h>
-#include <media/cx25840.h>
-#include <linux/firmware.h>
-#include <misc/altera.h>
-
-#include "cx23885.h"
-#include "tuner-xc2028.h"
-#include "netup-eeprom.h"
-#include "netup-init.h"
-#include "altera-ci.h"
-#include "xc4000.h"
-#include "xc5000.h"
-#include "cx23888-ir.h"
-
-static unsigned int netup_card_rev = 1;
-module_param(netup_card_rev, int, 0644);
-MODULE_PARM_DESC(netup_card_rev,
- "NetUP Dual DVB-T/C CI card revision");
-static unsigned int enable_885_ir;
-module_param(enable_885_ir, int, 0644);
-MODULE_PARM_DESC(enable_885_ir,
- "Enable integrated IR controller for supported\n"
- "\t\t CX2388[57] boards that are wired for it:\n"
- "\t\t\tHVR-1250 (reported safe)\n"
- "\t\t\tTeVii S470 (reported unsafe)\n"
- "\t\t This can cause an interrupt storm with some cards.\n"
- "\t\t Default: 0 [Disabled]");
-
-/* ------------------------------------------------------------------ */
-/* board config info */
-
-struct cx23885_board cx23885_boards[] = {
- [CX23885_BOARD_UNKNOWN] = {
- .name = "UNKNOWN/GENERIC",
- /* Ensure safe default for unknown boards */
- .clk_freq = 0,
- .input = {{
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE2,
- .vmux = 1,
- }, {
- .type = CX23885_VMUX_COMPOSITE3,
- .vmux = 2,
- }, {
- .type = CX23885_VMUX_COMPOSITE4,
- .vmux = 3,
- } },
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
- .name = "Hauppauge WinTV-HVR1800lp",
- .portc = CX23885_MPEG_DVB,
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0xff00,
- }, {
- .type = CX23885_VMUX_DEBUG,
- .vmux = 0,
- .gpio0 = 0xff01,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0xff02,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0xff02,
- } },
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
- .name = "Hauppauge WinTV-HVR1800",
- .porta = CX23885_ANALOG_VIDEO,
- .portb = CX23885_MPEG_ENCODER,
- .portc = CX23885_MPEG_DVB,
- .tuner_type = TUNER_PHILIPS_TDA8290,
- .tuner_addr = 0x42, /* 0x84 >> 1 */
- .tuner_bus = 1,
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN5_CH2 |
- CX25840_VIN2_CH1,
- .amux = CX25840_AUDIO8,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN6_CH1,
- .amux = CX25840_AUDIO7,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN8_CH1 |
- CX25840_SVIDEO_ON,
- .amux = CX25840_AUDIO7,
- .gpio0 = 0,
- } },
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
- .name = "Hauppauge WinTV-HVR1250",
- .porta = CX23885_ANALOG_VIDEO,
- .portc = CX23885_MPEG_DVB,
-#ifdef MT2131_NO_ANALOG_SUPPORT_YET
- .tuner_type = TUNER_PHILIPS_TDA8290,
- .tuner_addr = 0x42, /* 0x84 >> 1 */
- .tuner_bus = 1,
-#endif
- .force_bff = 1,
- .input = {{
-#ifdef MT2131_NO_ANALOG_SUPPORT_YET
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN5_CH2 |
- CX25840_VIN2_CH1,
- .amux = CX25840_AUDIO8,
- .gpio0 = 0xff00,
- }, {
-#endif
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN6_CH1,
- .amux = CX25840_AUDIO7,
- .gpio0 = 0xff02,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN8_CH1 |
- CX25840_SVIDEO_ON,
- .amux = CX25840_AUDIO7,
- .gpio0 = 0xff02,
- } },
- },
- [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
- .name = "DViCO FusionHDTV5 Express",
- .portb = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
- .name = "Hauppauge WinTV-HVR1500Q",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1500] = {
- .name = "Hauppauge WinTV-HVR1500",
- .porta = CX23885_ANALOG_VIDEO,
- .portc = CX23885_MPEG_DVB,
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0x61, /* 0xc2 >> 1 */
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN5_CH2 |
- CX25840_VIN2_CH1,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN6_CH1,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN8_CH1 |
- CX25840_SVIDEO_ON,
- .gpio0 = 0,
- } },
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1200] = {
- .name = "Hauppauge WinTV-HVR1200",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1700] = {
- .name = "Hauppauge WinTV-HVR1700",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1400] = {
- .name = "Hauppauge WinTV-HVR1400",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = {
- .name = "DViCO FusionHDTV7 Dual Express",
- .portb = CX23885_MPEG_DVB,
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
- .name = "DViCO FusionHDTV DVB-T Dual Express",
- .portb = CX23885_MPEG_DVB,
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = {
- .name = "Leadtek Winfast PxDVR3200 H",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
- .name = "Leadtek Winfast PxDVR3200 H XC4000",
- .porta = CX23885_ANALOG_VIDEO,
- .portc = CX23885_MPEG_DVB,
- .tuner_type = TUNER_XC4000,
- .tuner_addr = 0x61,
- .radio_type = UNSET,
- .radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN2_CH1 |
- CX25840_VIN5_CH2 |
- CX25840_NONE0_CH3,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_COMPOSITE1,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_SVIDEO_LUMA3 |
- CX25840_SVIDEO_CHROMA4,
- }, {
- .type = CX23885_VMUX_COMPONENT,
- .vmux = CX25840_VIN7_CH1 |
- CX25840_VIN6_CH2 |
- CX25840_VIN8_CH3 |
- CX25840_COMPONENT_ON,
- } },
- },
- [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
- .name = "Compro VideoMate E650F",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_TBS_6920] = {
- .name = "TurboSight TBS 6920",
- .portb = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_TEVII_S470] = {
- .name = "TeVii S470",
- .portb = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_DVBWORLD_2005] = {
- .name = "DVBWorld DVB-S2 2005",
- .portb = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
- .ci_type = 1,
- .name = "NetUP Dual DVB-S2 CI",
- .portb = CX23885_MPEG_DVB,
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1270] = {
- .name = "Hauppauge WinTV-HVR1270",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1275] = {
- .name = "Hauppauge WinTV-HVR1275",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1255] = {
- .name = "Hauppauge WinTV-HVR1255",
- .porta = CX23885_ANALOG_VIDEO,
- .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_HAUPPAUGE_HVR1255_22111] = {
- .name = "Hauppauge WinTV-HVR1255",
- .porta = CX23885_ANALOG_VIDEO,
- .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_SVIDEO,
- .vmux = CX25840_VIN7_CH3 |
- CX25840_VIN4_CH2 |
- CX25840_VIN8_CH1 |
- CX25840_SVIDEO_ON,
- .amux = CX25840_AUDIO7,
- } },
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1210] = {
- .name = "Hauppauge WinTV-HVR1210",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_MYGICA_X8506] = {
- .name = "Mygica X8506 DMB-TH",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x61,
- .tuner_bus = 1,
- .porta = CX23885_ANALOG_VIDEO,
- .portb = CX23885_MPEG_DVB,
- .input = {
- {
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_COMPOSITE2,
- },
- {
- .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_MAGICPRO_PROHDTVE2] = {
- .name = "Magic-Pro ProHDTV Extreme 2",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x61,
- .tuner_bus = 1,
- .porta = CX23885_ANALOG_VIDEO,
- .portb = CX23885_MPEG_DVB,
- .input = {
- {
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_COMPOSITE2,
- },
- {
- .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_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",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_HAUPPAUGE_HVR1290] = {
- .name = "Hauppauge WinTV-HVR1290",
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_MYGICA_X8558PRO] = {
- .name = "Mygica X8558 PRO DMB-TH",
- .portb = CX23885_MPEG_DVB,
- .portc = CX23885_MPEG_DVB,
- },
- [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = {
- .name = "LEADTEK WinFast PxTV1200",
- .porta = CX23885_ANALOG_VIDEO,
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0x61,
- .tuner_bus = 1,
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN2_CH1 |
- CX25840_VIN5_CH2 |
- CX25840_NONE0_CH3,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_COMPOSITE1,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_SVIDEO_LUMA3 |
- CX25840_SVIDEO_CHROMA4,
- }, {
- .type = CX23885_VMUX_COMPONENT,
- .vmux = CX25840_VIN7_CH1 |
- CX25840_VIN6_CH2 |
- CX25840_VIN8_CH3 |
- CX25840_COMPONENT_ON,
- } },
- },
- [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = {
- .name = "GoTView X5 3D Hybrid",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x64,
- .tuner_bus = 1,
- .porta = CX23885_ANALOG_VIDEO,
- .portb = CX23885_MPEG_DVB,
- .input = {{
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_VIN2_CH1 |
- CX25840_VIN5_CH2,
- .gpio0 = 0x02,
- }, {
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX23885_VMUX_COMPOSITE1,
- }, {
- .type = CX23885_VMUX_SVIDEO,
- .vmux = CX25840_SVIDEO_LUMA3 |
- CX25840_SVIDEO_CHROMA4,
- } },
- },
- [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = {
- .ci_type = 2,
- .name = "NetUP Dual DVB-T/C-CI RF",
- .porta = CX23885_ANALOG_VIDEO,
- .portb = CX23885_MPEG_DVB,
- .portc = CX23885_MPEG_DVB,
- .num_fds_portb = 2,
- .num_fds_portc = 2,
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0x64,
- .input = { {
- .type = CX23885_VMUX_TELEVISION,
- .vmux = CX25840_COMPOSITE1,
- } },
- },
- [CX23885_BOARD_MPX885] = {
- .name = "MPX-885",
- .porta = CX23885_ANALOG_VIDEO,
- .input = {{
- .type = CX23885_VMUX_COMPOSITE1,
- .vmux = CX25840_COMPOSITE1,
- .amux = CX25840_AUDIO6,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE2,
- .vmux = CX25840_COMPOSITE2,
- .amux = CX25840_AUDIO6,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE3,
- .vmux = CX25840_COMPOSITE3,
- .amux = CX25840_AUDIO7,
- .gpio0 = 0,
- }, {
- .type = CX23885_VMUX_COMPOSITE4,
- .vmux = CX25840_COMPOSITE4,
- .amux = CX25840_AUDIO7,
- .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,
- },
- [CX23885_BOARD_TEVII_S471] = {
- .name = "TeVii S471",
- .portb = CX23885_MPEG_DVB,
- }
-};
-const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
-
-/* ------------------------------------------------------------------ */
-/* PCI subsystem IDs */
-
-struct cx23885_subid cx23885_subids[] = {
- {
- .subvendor = 0x0070,
- .subdevice = 0x3400,
- .card = CX23885_BOARD_UNKNOWN,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7600,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7800,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7801,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7809,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7911,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1250,
- }, {
- .subvendor = 0x18ac,
- .subdevice = 0xd500,
- .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7790,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7797,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7710,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1500,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x7717,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1500,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x71d1,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x71d3,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x8101,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1700,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x8010,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1400,
- }, {
- .subvendor = 0x18ac,
- .subdevice = 0xd618,
- .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
- }, {
- .subvendor = 0x18ac,
- .subdevice = 0xdb78,
- .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
- }, {
- .subvendor = 0x107d,
- .subdevice = 0x6681,
- .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
- }, {
- .subvendor = 0x107d,
- .subdevice = 0x6f39,
- .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000,
- }, {
- .subvendor = 0x185b,
- .subdevice = 0xe800,
- .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
- }, {
- .subvendor = 0x6920,
- .subdevice = 0x8888,
- .card = CX23885_BOARD_TBS_6920,
- }, {
- .subvendor = 0xd470,
- .subdevice = 0x9022,
- .card = CX23885_BOARD_TEVII_S470,
- }, {
- .subvendor = 0x0001,
- .subdevice = 0x2005,
- .card = CX23885_BOARD_DVBWORLD_2005,
- }, {
- .subvendor = 0x1b55,
- .subdevice = 0x2a2c,
- .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2211,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1270,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2215,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x221d,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2251,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2259,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1255_22111,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2291,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2295,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x2299,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x229d,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f0,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f1,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f2,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f3,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f4,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x22f5,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
- }, {
- .subvendor = 0x14f1,
- .subdevice = 0x8651,
- .card = CX23885_BOARD_MYGICA_X8506,
- }, {
- .subvendor = 0x14f1,
- .subdevice = 0x8657,
- .card = CX23885_BOARD_MAGICPRO_PROHDTVE2,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x8541,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1850,
- }, {
- .subvendor = 0x1858,
- .subdevice = 0xe800,
- .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
- }, {
- .subvendor = 0x0070,
- .subdevice = 0x8551,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1290,
- }, {
- .subvendor = 0x14f1,
- .subdevice = 0x8578,
- .card = CX23885_BOARD_MYGICA_X8558PRO,
- }, {
- .subvendor = 0x107d,
- .subdevice = 0x6f22,
- .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
- }, {
- .subvendor = 0x5654,
- .subdevice = 0x2390,
- .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
- }, {
- .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,
- }, {
- .subvendor = 0xd471,
- .subdevice = 0x9022,
- .card = CX23885_BOARD_TEVII_S471,
- },
-};
-const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
-
-void cx23885_card_list(struct cx23885_dev *dev)
-{
- int i;
-
- if (0 == dev->pci->subsystem_vendor &&
- 0 == dev->pci->subsystem_device) {
- printk(KERN_INFO
- "%s: Board has no valid PCIe Subsystem ID and can't\n"
- "%s: be autodetected. Pass card=<n> insmod option\n"
- "%s: to workaround that. Redirect complaints to the\n"
- "%s: vendor of the TV card. Best regards,\n"
- "%s: -- tux\n",
- dev->name, dev->name, dev->name, dev->name, dev->name);
- } else {
- printk(KERN_INFO
- "%s: Your board isn't known (yet) to the driver.\n"
- "%s: Try to pick one of the existing card configs via\n"
- "%s: card=<n> insmod option. Updating to the latest\n"
- "%s: version might help as well.\n",
- dev->name, dev->name, dev->name, dev->name);
- }
- printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n",
- dev->name);
- for (i = 0; i < cx23885_bcount; i++)
- printk(KERN_INFO "%s: card=%d -> %s\n",
- dev->name, i, cx23885_boards[i].name);
-}
-
-static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
-{
- struct tveeprom tv;
-
- tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv,
- eeprom_data);
-
- /* Make sure we support the board model */
- switch (tv.model) {
- case 22001:
- /* WinTV-HVR1270 (PCIe, Retail, half height)
- * ATSC/QAM and basic analog, IR Blast */
- case 22009:
- /* WinTV-HVR1210 (PCIe, Retail, half height)
- * DVB-T and basic analog, IR Blast */
- case 22011:
- /* WinTV-HVR1270 (PCIe, Retail, half height)
- * ATSC/QAM and basic analog, IR Recv */
- case 22019:
- /* WinTV-HVR1210 (PCIe, Retail, half height)
- * DVB-T and basic analog, IR Recv */
- case 22021:
- /* WinTV-HVR1275 (PCIe, Retail, half height)
- * ATSC/QAM and basic analog, IR Recv */
- case 22029:
- /* WinTV-HVR1210 (PCIe, Retail, half height)
- * DVB-T and basic analog, IR Recv */
- case 22101:
- /* WinTV-HVR1270 (PCIe, Retail, full height)
- * ATSC/QAM and basic analog, IR Blast */
- case 22109:
- /* WinTV-HVR1210 (PCIe, Retail, full height)
- * DVB-T and basic analog, IR Blast */
- case 22111:
- /* WinTV-HVR1270 (PCIe, Retail, full height)
- * ATSC/QAM and basic analog, IR Recv */
- case 22119:
- /* WinTV-HVR1210 (PCIe, Retail, full height)
- * DVB-T and basic analog, IR Recv */
- case 22121:
- /* WinTV-HVR1275 (PCIe, Retail, full height)
- * ATSC/QAM and basic analog, IR Recv */
- case 22129:
- /* WinTV-HVR1210 (PCIe, Retail, full height)
- * DVB-T and basic analog, IR Recv */
- case 71009:
- /* WinTV-HVR1200 (PCIe, Retail, full height)
- * DVB-T and basic analog */
- case 71359:
- /* WinTV-HVR1200 (PCIe, OEM, half height)
- * DVB-T and basic analog */
- case 71439:
- /* WinTV-HVR1200 (PCIe, OEM, half height)
- * DVB-T and basic analog */
- case 71449:
- /* WinTV-HVR1200 (PCIe, OEM, full height)
- * DVB-T and basic analog */
- case 71939:
- /* WinTV-HVR1200 (PCIe, OEM, half height)
- * DVB-T and basic analog */
- case 71949:
- /* WinTV-HVR1200 (PCIe, OEM, full height)
- * DVB-T and basic analog */
- case 71959:
- /* WinTV-HVR1200 (PCIe, OEM, full height)
- * DVB-T and basic analog */
- case 71979:
- /* WinTV-HVR1200 (PCIe, OEM, half height)
- * DVB-T and basic analog */
- case 71999:
- /* WinTV-HVR1200 (PCIe, OEM, full height)
- * DVB-T and basic analog */
- case 76601:
- /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual
- channel ATSC and MPEG2 HW Encoder */
- case 77001:
- /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC
- and Basic analog */
- case 77011:
- /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC
- and Basic analog */
- case 77041:
- /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM
- and Basic analog */
- case 77051:
- /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM
- and Basic analog */
- case 78011:
- /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- case 78501:
- /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- case 78521:
- /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- case 78531:
- /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- case 78631:
- /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- case 79001:
- /* WinTV-HVR1250 (PCIe, Retail, IR, full height,
- ATSC and Basic analog */
- case 79101:
- /* WinTV-HVR1250 (PCIe, Retail, IR, half height,
- ATSC and Basic analog */
- case 79501:
- /* WinTV-HVR1250 (PCIe, No IR, half height,
- ATSC [at least] and Basic analog) */
- case 79561:
- /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
- ATSC and Basic analog */
- case 79571:
- /* WinTV-HVR1250 (PCIe, OEM, No IR, full height,
- ATSC and Basic analog */
- case 79671:
- /* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
- ATSC and Basic analog */
- case 80019:
- /* WinTV-HVR1400 (Express Card, Retail, IR,
- * DVB-T and Basic analog */
- case 81509:
- /* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
- * DVB-T and MPEG2 HW Encoder */
- case 81519:
- /* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
- * DVB-T and MPEG2 HW Encoder */
- break;
- case 85021:
- /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM,
- Dual channel ATSC and MPEG2 HW Encoder */
- break;
- case 85721:
- /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
- Dual channel ATSC and Basic analog */
- break;
- default:
- printk(KERN_WARNING "%s: warning: "
- "unknown hauppauge model #%d\n",
- dev->name, tv.model);
- break;
- }
-
- printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
- dev->name, tv.model);
-}
-
-int cx23885_tuner_callback(void *priv, int component, int command, int arg)
-{
- struct cx23885_tsport *port = priv;
- struct cx23885_dev *dev = port->dev;
- u32 bitmask = 0;
-
- if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH))
- return 0;
-
- if (command != 0) {
- printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
- __func__, command);
- return -EINVAL;
- }
-
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
- case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
- /* Tuner Reset Command */
- bitmask = 0x04;
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
- case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
- /* Two identical tuners on two different i2c buses,
- * we need to reset the correct gpio. */
- if (port->nr == 1)
- bitmask = 0x01;
- else if (port->nr == 2)
- bitmask = 0x04;
- break;
- case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
- /* Tuner Reset Command */
- bitmask = 0x02;
- break;
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
- altera_ci_tuner_reset(dev, port->nr);
- break;
- }
-
- if (bitmask) {
- /* Drive the tuner into reset and back out */
- cx_clear(GP0_IO, bitmask);
- mdelay(200);
- cx_set(GP0_IO, bitmask);
- }
-
- return 0;
-}
-
-void cx23885_gpio_setup(struct cx23885_dev *dev)
-{
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- /* GPIO-0 cx24227 demodulator reset */
- cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- /* GPIO-0 cx24227 demodulator */
- /* GPIO-2 xc3028 tuner */
-
- /* Put the parts into reset */
- cx_set(GP0_IO, 0x00050000);
- cx_clear(GP0_IO, 0x00000005);
- msleep(5);
-
- /* Bring the parts out of reset */
- cx_set(GP0_IO, 0x00050005);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- /* GPIO-0 cx24227 demodulator reset */
- /* GPIO-2 xc5000 tuner reset */
- cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
- /* GPIO-0 656_CLK */
- /* GPIO-1 656_D0 */
- /* GPIO-2 8295A Reset */
- /* GPIO-3-10 cx23417 data0-7 */
- /* GPIO-11-14 cx23417 addr0-3 */
- /* GPIO-15-18 cx23417 READY, CS, RD, WR */
- /* GPIO-19 IR_RX */
-
- /* CX23417 GPIO's */
- /* EIO15 Zilog Reset */
- /* EIO14 S5H1409/CX24227 Reset */
- mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
-
- /* Put the demod into reset and protect the eeprom */
- mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
- mdelay(100);
-
- /* Bring the demod and blaster out of reset */
- mc417_gpio_set(dev, GPIO_15 | GPIO_14);
- mdelay(100);
-
- /* Force the TDA8295A into reset and back */
- cx23885_gpio_enable(dev, GPIO_2, 1);
- cx23885_gpio_set(dev, GPIO_2);
- mdelay(20);
- cx23885_gpio_clear(dev, GPIO_2);
- mdelay(20);
- cx23885_gpio_set(dev, GPIO_2);
- mdelay(20);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1200:
- /* GPIO-0 tda10048 demodulator reset */
- /* GPIO-2 tda18271 tuner reset */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x00050000);
- mdelay(20);
- cx_clear(GP0_IO, 0x00000005);
- mdelay(20);
- cx_set(GP0_IO, 0x00050005);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1700:
- /* GPIO-0 TDA10048 demodulator reset */
- /* GPIO-2 TDA8295A Reset */
- /* GPIO-3-10 cx23417 data0-7 */
- /* GPIO-11-14 cx23417 addr0-3 */
- /* GPIO-15-18 cx23417 READY, CS, RD, WR */
-
- /* The following GPIO's are on the interna AVCore (cx25840) */
- /* GPIO-19 IR_RX */
- /* GPIO-20 IR_TX 416/DVBT Select */
- /* GPIO-21 IIS DAT */
- /* GPIO-22 IIS WCLK */
- /* GPIO-23 IIS BCLK */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x00050000);
- mdelay(20);
- cx_clear(GP0_IO, 0x00000005);
- mdelay(20);
- cx_set(GP0_IO, 0x00050005);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- /* GPIO-0 Dibcom7000p demodulator reset */
- /* GPIO-2 xc3028L tuner reset */
- /* GPIO-13 LED */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x00050000);
- mdelay(20);
- cx_clear(GP0_IO, 0x00000005);
- mdelay(20);
- cx_set(GP0_IO, 0x00050005);
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
- /* GPIO-0 xc5000 tuner reset i2c bus 0 */
- /* GPIO-1 s5h1409 demod reset i2c bus 0 */
- /* GPIO-2 xc5000 tuner reset i2c bus 1 */
- /* GPIO-3 s5h1409 demod reset i2c bus 0 */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x000f0000);
- mdelay(20);
- cx_clear(GP0_IO, 0x0000000f);
- mdelay(20);
- cx_set(GP0_IO, 0x000f000f);
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
- /* GPIO-0 portb xc3028 reset */
- /* GPIO-1 portb zl10353 reset */
- /* GPIO-2 portc xc3028 reset */
- /* GPIO-3 portc zl10353 reset */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x000f0000);
- mdelay(20);
- cx_clear(GP0_IO, 0x0000000f);
- mdelay(20);
- cx_set(GP0_IO, 0x000f000f);
- break;
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
- case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
- /* GPIO-2 xc3028 tuner reset */
-
- /* The following GPIO's are on the internal AVCore (cx25840) */
- /* GPIO-? zl10353 demod reset */
-
- /* Put the parts into reset and back */
- cx_set(GP0_IO, 0x00040000);
- mdelay(20);
- cx_clear(GP0_IO, 0x00000004);
- mdelay(20);
- cx_set(GP0_IO, 0x00040004);
- break;
- case CX23885_BOARD_TBS_6920:
- cx_write(MC417_CTL, 0x00000036);
- cx_write(MC417_OEN, 0x00001000);
- cx_set(MC417_RWD, 0x00000002);
- mdelay(200);
- cx_clear(MC417_RWD, 0x00000800);
- mdelay(200);
- cx_set(MC417_RWD, 0x00000800);
- mdelay(200);
- break;
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- /* GPIO-0 INTA from CiMax1
- GPIO-1 INTB from CiMax2
- GPIO-2 reset chips
- GPIO-3 to GPIO-10 data/addr for CA
- GPIO-11 ~CS0 to CiMax1
- GPIO-12 ~CS1 to CiMax2
- GPIO-13 ADL0 load LSB addr
- GPIO-14 ADL1 load MSB addr
- GPIO-15 ~RDY from CiMax
- GPIO-17 ~RD to CiMax
- GPIO-18 ~WR to CiMax
- */
- cx_set(GP0_IO, 0x00040000); /* GPIO as out */
- /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
- cx_clear(GP0_IO, 0x00030004);
- mdelay(100);/* reset delay */
- cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
- cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
- /* GPIO-15 IN as ~ACK, rest as OUT */
- cx_write(MC417_OEN, 0x00001000);
- /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
- cx_write(MC417_RWD, 0x0000c300);
- /* enable irq */
- cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1275:
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- case CX23885_BOARD_HAUPPAUGE_HVR1210:
- /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
- /* GPIO-6 I2C Gate which can isolate the demod from the bus */
- /* GPIO-9 Demod reset */
-
- /* Put the parts into reset and back */
- cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1);
- cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5);
- cx23885_gpio_clear(dev, GPIO_9);
- mdelay(20);
- cx23885_gpio_set(dev, GPIO_9);
- 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 */
- cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1);
- cx23885_gpio_clear(dev, GPIO_1 | GPIO_2);
- mdelay(100);
- cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2);
- mdelay(100);
- break;
- case CX23885_BOARD_MYGICA_X8558PRO:
- /* GPIO-0 reset first ATBM8830 */
- /* GPIO-1 reset second ATBM8830 */
- cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
- cx23885_gpio_clear(dev, GPIO_0 | GPIO_1);
- mdelay(100);
- cx23885_gpio_set(dev, GPIO_0 | GPIO_1);
- mdelay(100);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- /* GPIO-0 656_CLK */
- /* GPIO-1 656_D0 */
- /* GPIO-2 Wake# */
- /* GPIO-3-10 cx23417 data0-7 */
- /* GPIO-11-14 cx23417 addr0-3 */
- /* GPIO-15-18 cx23417 READY, CS, RD, WR */
- /* GPIO-19 IR_RX */
- /* GPIO-20 C_IR_TX */
- /* GPIO-21 I2S DAT */
- /* GPIO-22 I2S WCLK */
- /* GPIO-23 I2S BCLK */
- /* ALT GPIO: EXP GPIO LATCH */
-
- /* CX23417 GPIO's */
- /* GPIO-14 S5H1411/CX24228 Reset */
- /* GPIO-13 EEPROM write protect */
- mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
-
- /* Put the demod into reset and protect the eeprom */
- mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
- mdelay(100);
-
- /* Bring the demod out of reset */
- mc417_gpio_set(dev, GPIO_14);
- mdelay(100);
-
- /* CX24228 GPIO */
- /* Connected to IF / Mux */
- break;
- case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
- cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
- break;
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
- /* GPIO-0 ~INT in
- GPIO-1 TMS out
- GPIO-2 ~reset chips out
- GPIO-3 to GPIO-10 data/addr for CA in/out
- GPIO-11 ~CS out
- GPIO-12 ADDR out
- GPIO-13 ~WR out
- GPIO-14 ~RD out
- GPIO-15 ~RDY in
- GPIO-16 TCK out
- GPIO-17 TDO in
- GPIO-18 TDI out
- */
- cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */
- /* GPIO-0 as INT, reset & TMS low */
- cx_clear(GP0_IO, 0x00010006);
- mdelay(100);/* reset delay */
- cx_set(GP0_IO, 0x00000004); /* reset high */
- cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */
- /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */
- cx_write(MC417_OEN, 0x00005000);
- /* ~RD, ~WR high; ADDR low; ~CS high */
- cx_write(MC417_RWD, 0x00000d00);
- /* enable irq */
- cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
- break;
- }
-}
-
-int cx23885_ir_init(struct cx23885_dev *dev)
-{
- static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
- {
- .flags = V4L2_SUBDEV_IO_PIN_INPUT,
- .pin = CX23885_PIN_IR_RX_GPIO19,
- .function = CX23885_PAD_IR_RX,
- .value = 0,
- .strength = CX25840_PIN_DRIVE_MEDIUM,
- }, {
- .flags = V4L2_SUBDEV_IO_PIN_OUTPUT,
- .pin = CX23885_PIN_IR_TX_GPIO20,
- .function = CX23885_PAD_IR_TX,
- .value = 0,
- .strength = CX25840_PIN_DRIVE_MEDIUM,
- }
- };
- const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg);
-
- static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = {
- {
- .flags = V4L2_SUBDEV_IO_PIN_INPUT,
- .pin = CX23885_PIN_IR_RX_GPIO19,
- .function = CX23885_PAD_IR_RX,
- .value = 0,
- .strength = CX25840_PIN_DRIVE_MEDIUM,
- }
- };
- const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
-
- struct v4l2_subdev_ir_parameters params;
- int ret = 0;
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
- case CX23885_BOARD_HAUPPAUGE_HVR1200:
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- case CX23885_BOARD_HAUPPAUGE_HVR1275:
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- case CX23885_BOARD_HAUPPAUGE_HVR1210:
- /* FIXME: Implement me */
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- ret = cx23888_ir_probe(dev);
- if (ret)
- break;
- dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
- v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
- ir_rx_pin_cfg_count, ir_rx_pin_cfg);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- ret = cx23888_ir_probe(dev);
- if (ret)
- break;
- dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
- v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
- ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
- /*
- * For these boards we need to invert the Tx output via the
- * IR controller to have the LED off while idle
- */
- v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, &params);
- params.enable = false;
- params.shutdown = false;
- params.invert_level = true;
- v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
- params.shutdown = true;
- v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
- break;
- case CX23885_BOARD_TEVII_S470:
- if (!enable_885_ir)
- break;
- dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
- if (dev->sd_ir == NULL) {
- ret = -ENODEV;
- break;
- }
- v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
- ir_rx_pin_cfg_count, ir_rx_pin_cfg);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- if (!enable_885_ir)
- break;
- dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
- if (dev->sd_ir == NULL) {
- ret = -ENODEV;
- break;
- }
- v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
- ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
- request_module("ir-kbd-i2c");
- break;
- }
-
- return ret;
-}
-
-void cx23885_ir_fini(struct cx23885_dev *dev)
-{
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- cx23885_irq_remove(dev, PCI_MSK_IR);
- cx23888_ir_remove(dev);
- dev->sd_ir = NULL;
- break;
- case CX23885_BOARD_TEVII_S470:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
- /* sd_ir is a duplicate pointer to the AV Core, just clear it */
- dev->sd_ir = NULL;
- break;
- }
-}
-
-int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
-{
- int data;
- int tdo = 0;
- struct cx23885_dev *dev = (struct cx23885_dev *)device;
- /*TMS*/
- data = ((cx_read(GP0_IO)) & (~0x00000002));
- data |= (tms ? 0x00020002 : 0x00020000);
- cx_write(GP0_IO, data);
-
- /*TDI*/
- data = ((cx_read(MC417_RWD)) & (~0x0000a000));
- data |= (tdi ? 0x00008000 : 0);
- cx_write(MC417_RWD, data);
- if (read_tdo)
- tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/
-
- cx_write(MC417_RWD, data | 0x00002000);
- udelay(1);
- /*TCK*/
- cx_write(MC417_RWD, data);
-
- return tdo;
-}
-
-void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
-{
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- if (dev->sd_ir)
- cx23885_irq_add_enable(dev, PCI_MSK_IR);
- break;
- case CX23885_BOARD_TEVII_S470:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- if (dev->sd_ir)
- cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
- break;
- }
-}
-
-void cx23885_card_setup(struct cx23885_dev *dev)
-{
- struct cx23885_tsport *ts1 = &dev->ts1;
- struct cx23885_tsport *ts2 = &dev->ts2;
-
- static u8 eeprom[256];
-
- 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));
- }
-
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- if (dev->i2c_bus[0].i2c_rc == 0) {
- if (eeprom[0x80] != 0x84)
- hauppauge_eeprom(dev, eeprom+0xc0);
- else
- hauppauge_eeprom(dev, eeprom+0x80);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- if (dev->i2c_bus[0].i2c_rc == 0)
- hauppauge_eeprom(dev, eeprom+0x80);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
- case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- case CX23885_BOARD_HAUPPAUGE_HVR1200:
- case CX23885_BOARD_HAUPPAUGE_HVR1700:
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1275:
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- case CX23885_BOARD_HAUPPAUGE_HVR1210:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- if (dev->i2c_bus[0].i2c_rc == 0)
- hauppauge_eeprom(dev, eeprom+0xc0);
- break;
- }
-
- switch (dev->board) {
- case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
- case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
- ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
- ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- /* break omitted intentionally */
- case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
- 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;
- 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 */
- ts1->gen_ctrl_val = 0x10e;
- ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
-
- /* 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 */
- ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- break;
- case CX23885_BOARD_TBS_6920:
- ts1->gen_ctrl_val = 0x4; /* Parallel */
- ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- break;
- case CX23885_BOARD_TEVII_S470:
- case CX23885_BOARD_TEVII_S471:
- case CX23885_BOARD_DVBWORLD_2005:
- ts1->gen_ctrl_val = 0x5; /* Parallel */
- ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- 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;
- ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
- ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- break;
- case CX23885_BOARD_MYGICA_X8506:
- case CX23885_BOARD_MAGICPRO_PROHDTVE2:
- ts1->gen_ctrl_val = 0x5; /* Parallel */
- ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- break;
- case CX23885_BOARD_MYGICA_X8558PRO:
- ts1->gen_ctrl_val = 0x5; /* Parallel */
- ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
- ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- case CX23885_BOARD_HAUPPAUGE_HVR1200:
- case CX23885_BOARD_HAUPPAUGE_HVR1700:
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1275:
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- case CX23885_BOARD_HAUPPAUGE_HVR1210:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
- default:
- ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
- ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
- ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
- }
-
- /* Certain boards support analog, or require the avcore to be
- * loaded, ensure this happens.
- */
- switch (dev->board) {
- case CX23885_BOARD_TEVII_S470:
- /* Currently only enabled for the integrated IR controller */
- if (!enable_885_ir)
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
- case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- case CX23885_BOARD_HAUPPAUGE_HVR1700:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_MYGICA_X8506:
- case CX23885_BOARD_MAGICPRO_PROHDTVE2:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
- 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);
- if (dev->sd_cx25840) {
- dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
- v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
- }
- break;
- }
-
- /* AUX-PLL 27MHz CLK */
- switch (dev->board) {
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- netup_initialize(dev);
- break;
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
- int ret;
- const struct firmware *fw;
- const char *filename = "dvb-netup-altera-01.fw";
- char *action = "configure";
- static struct netup_card_info cinfo;
- struct altera_config netup_config = {
- .dev = dev,
- .action = action,
- .jtag_io = netup_jtag_io,
- };
-
- netup_initialize(dev);
-
- netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
- if (netup_card_rev)
- cinfo.rev = netup_card_rev;
-
- switch (cinfo.rev) {
- case 0x4:
- filename = "dvb-netup-altera-04.fw";
- break;
- default:
- filename = "dvb-netup-altera-01.fw";
- break;
- }
- printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n",
- cinfo.rev, filename);
-
- ret = request_firmware(&fw, filename, &dev->pci->dev);
- if (ret != 0)
- printk(KERN_ERR "did not find the firmware file. (%s) "
- "Please see linux/Documentation/dvb/ for more details "
- "on firmware-problems.", filename);
- else
- altera_init(&netup_config, fw);
-
- release_firmware(fw);
- break;
- }
- }
-}
-
-/* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
deleted file mode 100644
index cd542684ba02..000000000000
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ /dev/null
@@ -1,1357 +0,0 @@
-/*
- * Driver for the Conexant CX23885 PCIe bridge
- *
- * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/kthread.h>
-#include <linux/file.h>
-#include <linux/suspend.h>
-
-#include "cx23885.h"
-#include <media/v4l2-common.h>
-
-#include "dvb_ca_en50221.h"
-#include "s5h1409.h"
-#include "s5h1411.h"
-#include "mt2131.h"
-#include "tda8290.h"
-#include "tda18271.h"
-#include "lgdt330x.h"
-#include "xc4000.h"
-#include "xc5000.h"
-#include "max2165.h"
-#include "tda10048.h"
-#include "tuner-xc2028.h"
-#include "tuner-simple.h"
-#include "dib7000p.h"
-#include "dibx000_common.h"
-#include "zl10353.h"
-#include "stv0900.h"
-#include "stv0900_reg.h"
-#include "stv6110.h"
-#include "lnbh24.h"
-#include "cx24116.h"
-#include "cimax2.h"
-#include "lgs8gxx.h"
-#include "netup-eeprom.h"
-#include "netup-init.h"
-#include "lgdt3305.h"
-#include "atbm8830.h"
-#include "ds3000.h"
-#include "cx23885-f300.h"
-#include "altera-ci.h"
-#include "stv0367.h"
-#include "drxk.h"
-#include "mt2063.h"
-
-static unsigned int debug;
-
-#define dprintk(level, fmt, arg...)\
- do { if (debug >= level)\
- printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
- } while (0)
-
-/* ------------------------------------------------------------------ */
-
-static unsigned int alt_tuner;
-module_param(alt_tuner, int, 0644);
-MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/* ------------------------------------------------------------------ */
-
-static int dvb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
-{
- struct cx23885_tsport *port = q->priv_data;
-
- port->ts_packet_size = 188 * 4;
- port->ts_packet_count = 32;
-
- *size = port->ts_packet_size * port->ts_packet_count;
- *count = 32;
- return 0;
-}
-
-static int dvb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct cx23885_tsport *port = q->priv_data;
- return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
-}
-
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
- struct cx23885_tsport *port = q->priv_data;
- cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
-}
-
-static void dvb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- 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;
- struct videobuf_dvb_frontend *fe;
-
- f = &port->frontends;
-
- if (f->gate <= 1) /* undefined or fe0 */
- fe = videobuf_dvb_get_frontend(f, 1);
- else
- fe = videobuf_dvb_get_frontend(f, f->gate);
-
- 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 = {
- .buf_setup = dvb_buf_setup,
- .buf_prepare = dvb_buf_prepare,
- .buf_queue = dvb_buf_queue,
- .buf_release = dvb_buf_release,
-};
-
-static struct s5h1409_config hauppauge_generic_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_ON,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct tda10048_config hauppauge_hvr1200_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_SERIAL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_200,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3800,
- .dtv8_if_freq_khz = TDA10048_IF_4300,
- .clk_freq_khz = TDA10048_CLK_16000,
-};
-
-static struct tda10048_config hauppauge_hvr1210_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_SERIAL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_200,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3500,
- .dtv8_if_freq_khz = TDA10048_IF_4000,
- .clk_freq_khz = TDA10048_CLK_16000,
-};
-
-static struct s5h1409_config hauppauge_ezqam_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .qam_if = 4000,
- .inversion = S5H1409_INVERSION_ON,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct s5h1409_config hauppauge_hvr1800lp_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct s5h1409_config hauppauge_hvr1500_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct mt2131_config hauppauge_generic_tunerconfig = {
- 0x61
-};
-
-static struct lgdt330x_config fusionhdtv_5_express = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x40,
-};
-
-static struct s5h1409_config hauppauge_hvr1500q_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_ON,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct s5h1409_config dvico_s5h1409_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_ON,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct s5h1411_config dvico_s5h1411_config = {
- .output_mode = S5H1411_SERIAL_OUTPUT,
- .gpio = S5H1411_GPIO_ON,
- .qam_if = S5H1411_IF_44000,
- .vsb_if = S5H1411_IF_44000,
- .inversion = S5H1411_INVERSION_OFF,
- .status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct s5h1411_config hcw_s5h1411_config = {
- .output_mode = S5H1411_SERIAL_OUTPUT,
- .gpio = S5H1411_GPIO_OFF,
- .vsb_if = S5H1411_IF_44000,
- .qam_if = S5H1411_IF_4000,
- .inversion = S5H1411_INVERSION_ON,
- .status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
- .i2c_address = 0x61,
- .if_khz = 5380,
-};
-
-static struct xc5000_config dvico_xc5000_tunerconfig = {
- .i2c_address = 0x64,
- .if_khz = 5380,
-};
-
-static struct tda829x_config tda829x_no_probe = {
- .probe_tuner = TDA829X_DONT_PROBE,
-};
-
-static struct tda18271_std_map hauppauge_tda18271_std_map = {
- .atsc_6 = { .if_freq = 5380, .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_std_map hauppauge_hvr1200_tda18271_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_config = {
- .std_map = &hauppauge_tda18271_std_map,
- .gate = TDA18271_GATE_ANALOG,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static struct tda18271_config hauppauge_hvr1200_tuner_config = {
- .std_map = &hauppauge_hvr1200_tda18271_std_map,
- .gate = TDA18271_GATE_ANALOG,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static struct tda18271_config hauppauge_hvr1210_tuner_config = {
- .gate = TDA18271_GATE_DIGITAL,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static struct tda18271_std_map hauppauge_hvr127x_std_map = {
- .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
- .if_lvl = 1, .rfagc_top = 0x58 },
- .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
- .if_lvl = 1, .rfagc_top = 0x58 },
-};
-
-static struct tda18271_config hauppauge_hvr127x_config = {
- .std_map = &hauppauge_hvr127x_std_map,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static struct lgdt3305_config hauppauge_lgdt3305_config = {
- .i2c_addr = 0x0e,
- .mpeg_mode = LGDT3305_MPEG_SERIAL,
- .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
- .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 1,
- .qam_if_khz = 4000,
- .vsb_if_khz = 3250,
-};
-
-static struct dibx000_agc_config xc3028_agc_config = {
- BAND_VHF | BAND_UHF, /* band_caps */
-
- /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
- * 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=2, P_agc_write=0
- */
- (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
- (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
-
- 712, /* inv_gain */
- 21, /* time_stabiliz */
-
- 0, /* alpha_level */
- 118, /* thlock */
-
- 0, /* wbd_inv */
- 2867, /* wbd_ref */
- 0, /* wbd_sel */
- 2, /* wbd_alpha */
-
- 0, /* agc1_max */
- 0, /* agc1_min */
- 39718, /* agc2_max */
- 9930, /* agc2_min */
- 0, /* agc1_pt1 */
- 0, /* agc1_pt2 */
- 0, /* agc1_pt3 */
- 0, /* agc1_slope1 */
- 0, /* agc1_slope2 */
- 0, /* agc2_pt1 */
- 128, /* agc2_pt2 */
- 29, /* agc2_slope1 */
- 29, /* agc2_slope2 */
-
- 17, /* alpha_mant */
- 27, /* alpha_exp */
- 23, /* beta_mant */
- 51, /* beta_exp */
-
- 1, /* perform_agc_softsplit */
-};
-
-/* PLL Configuration for COFDM BW_MHz = 8.000000
- * With external clock = 30.000000 */
-static struct dibx000_bandwidth_config xc3028_bw_config = {
- 60000, /* internal */
- 30000, /* sampling */
- 1, /* pll_cfg: prediv */
- 8, /* pll_cfg: ratio */
- 3, /* pll_cfg: range */
- 1, /* pll_cfg: reset */
- 0, /* pll_cfg: bypass */
- 0, /* misc: refdiv */
- 0, /* misc: bypclk_div */
- 1, /* misc: IO_CLK_en_core */
- 1, /* misc: ADClkSrc */
- 0, /* misc: modulo */
- (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
- (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
- 20452225, /* timf */
- 30000000 /* xtal_hz */
-};
-
-static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
- .output_mpeg2_in_188_bytes = 1,
- .hostbus_diversity = 1,
- .tuner_is_baseband = 0,
- .update_lna = NULL,
-
- .agc_config_count = 1,
- .agc = &xc3028_agc_config,
- .bw = &xc3028_bw_config,
-
- .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 = NULL,
- .spur_protect = 0,
-
- .output_mode = OUTMODE_MPEG2_SERIAL,
-};
-
-static struct zl10353_config dvico_fusionhdtv_xc3028 = {
- .demod_address = 0x0f,
- .if2 = 45600,
- .no_tuner = 1,
- .disable_i2c_gate_ctrl = 1,
-};
-
-static struct stv0900_reg stv0900_ts_regs[] = {
- { R0900_TSGENERAL, 0x00 },
- { R0900_P1_TSSPEED, 0x40 },
- { R0900_P2_TSSPEED, 0x40 },
- { R0900_P1_TSCFGM, 0xc0 },
- { R0900_P2_TSCFGM, 0xc0 },
- { R0900_P1_TSCFGH, 0xe0 },
- { R0900_P2_TSCFGH, 0xe0 },
- { R0900_P1_TSCFGL, 0x20 },
- { R0900_P2_TSCFGL, 0x20 },
- { 0xffff, 0xff }, /* terminate */
-};
-
-static struct stv0900_config netup_stv0900_config = {
- .demod_address = 0x68,
- .demod_mode = 1, /* dual */
- .xtal = 8000000,
- .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
- .diseqc_mode = 2,/* 2/3 PWM */
- .ts_config_regs = stv0900_ts_regs,
- .tun1_maddress = 0,/* 0x60 */
- .tun2_maddress = 3,/* 0x63 */
- .tun1_adc = 1,/* 1 Vpp */
- .tun2_adc = 1,/* 1 Vpp */
-};
-
-static struct stv6110_config netup_stv6110_tunerconfig_a = {
- .i2c_address = 0x60,
- .mclk = 16000000,
- .clk_div = 1,
- .gain = 8, /* +16 dB - maximum gain */
-};
-
-static struct stv6110_config netup_stv6110_tunerconfig_b = {
- .i2c_address = 0x63,
- .mclk = 16000000,
- .clk_div = 1,
- .gain = 8, /* +16 dB - maximum gain */
-};
-
-static struct cx24116_config tbs_cx24116_config = {
- .demod_address = 0x55,
-};
-
-static struct ds3000_config tevii_ds3000_config = {
- .demod_address = 0x68,
-};
-
-static struct cx24116_config dvbworld_cx24116_config = {
- .demod_address = 0x05,
-};
-
-static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
- .prod = LGS8GXX_PROD_LGS8GL5,
- .demod_address = 0x19,
- .serial_ts = 0,
- .ts_clk_pol = 1,
- .ts_clk_gated = 1,
- .if_clk_freq = 30400, /* 30.4 MHz */
- .if_freq = 5380, /* 5.38 MHz */
- .if_neg_center = 1,
- .ext_adc = 0,
- .adc_signed = 0,
- .if_neg_edge = 0,
-};
-
-static struct xc5000_config mygica_x8506_xc5000_config = {
- .i2c_address = 0x61,
- .if_khz = 5380,
-};
-
-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 (p->modulation) {
- case VSB_8:
- cx23885_gpio_clear(dev, GPIO_5);
- break;
- case QAM_64:
- case QAM_256:
- default:
- cx23885_gpio_set(dev, GPIO_5);
- break;
- }
- break;
- case CX23885_BOARD_MYGICA_X8506:
- case CX23885_BOARD_MAGICPRO_PROHDTVE2:
- /* Select Digital TV */
- cx23885_gpio_set(dev, GPIO_0);
- break;
- }
- return 0;
-}
-
-static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
- .prod = LGS8GXX_PROD_LGS8G75,
- .demod_address = 0x19,
- .serial_ts = 0,
- .ts_clk_pol = 1,
- .ts_clk_gated = 1,
- .if_clk_freq = 30400, /* 30.4 MHz */
- .if_freq = 6500, /* 6.50 MHz */
- .if_neg_center = 1,
- .ext_adc = 0,
- .adc_signed = 1,
- .adc_vpp = 2, /* 1.6 Vpp */
- .if_neg_edge = 1,
-};
-
-static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
- .i2c_address = 0x61,
- .if_khz = 6500,
-};
-
-static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
- .prod = ATBM8830_PROD_8830,
- .demod_address = 0x44,
- .serial_ts = 0,
- .ts_sampling_edge = 1,
- .ts_clk_gated = 0,
- .osc_clk_freq = 30400, /* in kHz */
- .if_freq = 0, /* zero IF */
- .zif_swap_iq = 1,
- .agc_min = 0x2E,
- .agc_max = 0xFF,
- .agc_hold_loop = 0,
-};
-
-static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
- .i2c_address = 0x60,
- .osc_clk = 20
-};
-
-static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
- .prod = ATBM8830_PROD_8830,
- .demod_address = 0x44,
- .serial_ts = 1,
- .ts_sampling_edge = 1,
- .ts_clk_gated = 0,
- .osc_clk_freq = 30400, /* in kHz */
- .if_freq = 0, /* zero IF */
- .zif_swap_iq = 1,
- .agc_min = 0x2E,
- .agc_max = 0xFF,
- .agc_hold_loop = 0,
-};
-
-static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
- .i2c_address = 0x60,
- .osc_clk = 20
-};
-static struct stv0367_config netup_stv0367_config[] = {
- {
- .demod_address = 0x1c,
- .xtal = 27000000,
- .if_khz = 4500,
- .if_iq_mode = 0,
- .ts_mode = 1,
- .clk_pol = 0,
- }, {
- .demod_address = 0x1d,
- .xtal = 27000000,
- .if_khz = 4500,
- .if_iq_mode = 0,
- .ts_mode = 1,
- .clk_pol = 0,
- },
-};
-
-static struct xc5000_config netup_xc5000_config[] = {
- {
- .i2c_address = 0x61,
- .if_khz = 4500,
- }, {
- .i2c_address = 0x64,
- .if_khz = 4500,
- },
-};
-
-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;
- unsigned long timeout = jiffies + msecs_to_jiffies(1);
- uint32_t mem = 0;
-
- mem = cx_read(MC417_RWD);
- if (read)
- cx_set(MC417_OEN, ALT_DATA);
- else {
- cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */
- mem &= ~ALT_DATA;
- mem |= (data & ALT_DATA);
- }
-
- if (flag)
- mem |= ALT_AD_RG;
- else
- mem &= ~ALT_AD_RG;
-
- mem &= ~ALT_CS;
- if (read)
- mem = (mem & ~ALT_RD) | ALT_WR;
- else
- mem = (mem & ~ALT_WR) | ALT_RD;
-
- cx_write(MC417_RWD, mem); /* start RW cycle */
-
- for (;;) {
- mem = cx_read(MC417_RWD);
- if ((mem & ALT_RDY) == 0)
- break;
- if (time_after(jiffies, timeout))
- break;
- udelay(1);
- }
-
- cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS);
- if (read)
- return mem & ALT_DATA;
-
- return 0;
-};
-
-static int dvb_register(struct cx23885_tsport *port)
-{
- struct cx23885_dev *dev = port->dev;
- struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
- struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
- int mfe_shared = 0; /* bus not shared by default */
- int ret;
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
- if (!fe0)
- return -EINVAL;
-
- /* init struct videobuf_dvb */
- fe0->dvb.name = dev->name;
-
- /* multi-frontend gate control is undefined or defaults to fe0 */
- port->frontends.gate = 0;
-
- /* Sets the gate control callback to be used by i2c command calls */
- port->gate_ctrl = cx23885_dvb_gate_ctrl;
-
- /* init frontend */
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &hauppauge_generic_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1275:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
- &hauppauge_lgdt3305_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_hvr127x_config);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1255:
- case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
- 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[1].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_HVR1800:
- i2c_bus = &dev->i2c_bus[0];
- switch (alt_tuner) {
- case 1:
- fe0->dvb.frontend =
- dvb_attach(s5h1409_attach,
- &hauppauge_ezqam_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, fe0->dvb.frontend,
- &dev->i2c_bus[1].i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_tda18271_config);
- }
- break;
- case 0:
- default:
- fe0->dvb.frontend =
- dvb_attach(s5h1409_attach,
- &hauppauge_generic_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- break;
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &hauppauge_hvr1800lp_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- }
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
- &fusionhdtv_5_express,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- i2c_bus = &dev->i2c_bus[1];
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &hauppauge_hvr1500q_config,
- &dev->i2c_bus[0].i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_hvr1500q_tunerconfig);
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1500:
- i2c_bus = &dev->i2c_bus[1];
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &hauppauge_hvr1500_config,
- &dev->i2c_bus[0].i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &i2c_bus->i2c_adap,
- .i2c_addr = 0x61,
- };
- static struct xc2028_ctrl ctl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_OREN538,
- };
-
- fe = dvb_attach(xc2028_attach,
- fe0->dvb.frontend, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctl);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1200:
- case CX23885_BOARD_HAUPPAUGE_HVR1700:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(tda10048_attach,
- &hauppauge_hvr1200_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, fe0->dvb.frontend,
- &dev->i2c_bus[1].i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_hvr1200_tuner_config);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1210:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(tda10048_attach,
- &hauppauge_hvr1210_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_hvr1210_tuner_config);
- }
- break;
- case CX23885_BOARD_HAUPPAUGE_HVR1400:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(dib7000p_attach,
- &i2c_bus->i2c_adap,
- 0x12, &hauppauge_hvr1400_dib7000_config);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &dev->i2c_bus[1].i2c_adap,
- .i2c_addr = 0x64,
- };
- static struct xc2028_ctrl ctl = {
- .fname = XC3028L_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_DIBCOM52,
- /* This is true for all demods with
- v36 firmware? */
- .type = XC2028_D2633,
- };
-
- fe = dvb_attach(xc2028_attach,
- fe0->dvb.frontend, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctl);
- }
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
- i2c_bus = &dev->i2c_bus[port->nr - 1];
-
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &dvico_s5h1409_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend == NULL)
- fe0->dvb.frontend = dvb_attach(s5h1411_attach,
- &dvico_s5h1411_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &dvico_xc5000_tunerconfig);
- break;
- case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
- i2c_bus = &dev->i2c_bus[port->nr - 1];
-
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_xc3028,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &i2c_bus->i2c_adap,
- .i2c_addr = 0x61,
- };
- static struct xc2028_ctrl ctl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_ZARLINK456,
- };
-
- fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
- &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctl);
- }
- break;
- }
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
- case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
- i2c_bus = &dev->i2c_bus[0];
-
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_xc3028,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &dev->i2c_bus[1].i2c_adap,
- .i2c_addr = 0x61,
- };
- static struct xc2028_ctrl ctl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .demod = XC3028_FE_ZARLINK456,
- };
-
- fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
- &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctl);
- }
- break;
- case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
- i2c_bus = &dev->i2c_bus[0];
-
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_xc3028,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc4000_config cfg = {
- .i2c_address = 0x61,
- .default_pm = 0,
- .dvb_amplitude = 134,
- .set_smoothedcvbs = 1,
- .if_khz = 4560
- };
-
- 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:
- i2c_bus = &dev->i2c_bus[1];
-
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &tbs_cx24116_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
-
- break;
- case CX23885_BOARD_TEVII_S470:
- i2c_bus = &dev->i2c_bus[1];
-
- fe0->dvb.frontend = dvb_attach(ds3000_attach,
- &tevii_ds3000_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
-
- break;
- case CX23885_BOARD_DVBWORLD_2005:
- i2c_bus = &dev->i2c_bus[1];
-
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &dvbworld_cx24116_config,
- &i2c_bus->i2c_adap);
- break;
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- i2c_bus = &dev->i2c_bus[0];
- switch (port->nr) {
- /* port B */
- case 1:
- fe0->dvb.frontend = dvb_attach(stv0900_attach,
- &netup_stv0900_config,
- &i2c_bus->i2c_adap, 0);
- if (fe0->dvb.frontend != NULL) {
- if (dvb_attach(stv6110_attach,
- fe0->dvb.frontend,
- &netup_stv6110_tunerconfig_a,
- &i2c_bus->i2c_adap)) {
- if (!dvb_attach(lnbh24_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- LNBH24_PCL | LNBH24_TTX,
- LNBH24_TEN, 0x09))
- printk(KERN_ERR
- "No LNBH24 found!\n");
-
- }
- }
- break;
- /* port C */
- case 2:
- fe0->dvb.frontend = dvb_attach(stv0900_attach,
- &netup_stv0900_config,
- &i2c_bus->i2c_adap, 1);
- if (fe0->dvb.frontend != NULL) {
- if (dvb_attach(stv6110_attach,
- fe0->dvb.frontend,
- &netup_stv6110_tunerconfig_b,
- &i2c_bus->i2c_adap)) {
- if (!dvb_attach(lnbh24_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- LNBH24_PCL | LNBH24_TTX,
- LNBH24_TEN, 0x0a))
- printk(KERN_ERR
- "No LNBH24 found!\n");
-
- }
- }
- break;
- }
- break;
- case CX23885_BOARD_MYGICA_X8506:
- i2c_bus = &dev->i2c_bus[0];
- i2c_bus2 = &dev->i2c_bus[1];
- fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
- &mygica_x8506_lgs8gl5_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus2->i2c_adap,
- &mygica_x8506_xc5000_config);
- }
- break;
- case CX23885_BOARD_MAGICPRO_PROHDTVE2:
- i2c_bus = &dev->i2c_bus[0];
- i2c_bus2 = &dev->i2c_bus[1];
- fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
- &magicpro_prohdtve2_lgs8g75_config,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus2->i2c_adap,
- &magicpro_prohdtve2_xc5000_config);
- }
- 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,
- &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);
- break;
- case CX23885_BOARD_MYGICA_X8558PRO:
- switch (port->nr) {
- /* port B */
- case 1:
- i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(atbm8830_attach,
- &mygica_x8558pro_atbm8830_cfg1,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(max2165_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &mygic_x8558pro_max2165_cfg1);
- }
- break;
- /* port C */
- case 2:
- i2c_bus = &dev->i2c_bus[1];
- fe0->dvb.frontend = dvb_attach(atbm8830_attach,
- &mygica_x8558pro_atbm8830_cfg2,
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(max2165_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &mygic_x8558pro_max2165_cfg2);
- }
- break;
- }
- break;
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
- i2c_bus = &dev->i2c_bus[0];
- mfe_shared = 1;/* MFE */
- port->frontends.gate = 0;/* not clear for me yet */
- /* ports B, C */
- /* MFE frontend 1 DVB-T */
- fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
- &netup_stv0367_config[port->nr - 1],
- &i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (NULL == dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &netup_xc5000_config[port->nr - 1]))
- goto frontend_detach;
- /* load xc5000 firmware */
- fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
- }
- /* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
- if (fe1 == NULL)
- goto frontend_detach;
- /* DVB-C init */
- fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
- &netup_stv0367_config[port->nr - 1],
- &i2c_bus->i2c_adap);
- if (fe1->dvb.frontend != NULL) {
- fe1->dvb.frontend->id = 1;
- if (NULL == dvb_attach(xc5000_attach,
- fe1->dvb.frontend,
- &i2c_bus->i2c_adap,
- &netup_xc5000_config[port->nr - 1]))
- 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;
- case CX23885_BOARD_TEVII_S471:
- i2c_bus = &dev->i2c_bus[1];
-
- fe0->dvb.frontend = dvb_attach(ds3000_attach,
- &tevii_ds3000_config,
- &i2c_bus->i2c_adap);
- break;
- default:
- printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
- " isn't supported yet\n",
- dev->name);
- break;
- }
-
- if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
- printk(KERN_ERR "%s: frontend initialization failed\n",
- dev->name);
- goto frontend_detach;
- }
-
- /* define general-purpose callback pointer */
- fe0->dvb.frontend->callback = cx23885_tuner_callback;
- if (fe1)
- fe1->dvb.frontend->callback = cx23885_tuner_callback;
-#if 0
- /* Ensure all frontends negotiate bus access */
- fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
- if (fe1)
- fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
-#endif
-
- /* Put the analog decoder in standby to keep it quiet */
- call_all(dev, core, s_power, 0);
-
- if (fe0->dvb.frontend->ops.analog_ops.standby)
- fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
-
- /* register everything */
- ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
- &dev->pci->dev, adapter_nr, mfe_shared,
- NULL);
- if (ret)
- goto frontend_detach;
-
- /* init CI & MAC */
- switch (dev->board) {
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
- static struct netup_card_info cinfo;
-
- netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
- memcpy(port->frontends.adapter.proposed_mac,
- cinfo.port[port->nr - 1].mac, 6);
- printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
- port->nr, port->frontends.adapter.proposed_mac);
-
- netup_ci_init(port);
- break;
- }
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
- struct altera_ci_config netup_ci_cfg = {
- .dev = dev,/* magic number to identify*/
- .adapter = &port->frontends.adapter,/* for CI */
- .demux = &fe0->dvb.demux,/* for hw pid filter */
- .fpga_rw = netup_altera_fpga_rw,
- };
-
- altera_ci_init(&netup_ci_cfg, port->nr);
- break;
- }
- case CX23885_BOARD_TEVII_S470: {
- u8 eeprom[256]; /* 24C02 i2c eeprom */
-
- if (port->nr != 1)
- break;
-
- /* Read entire EEPROM */
- dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
- printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
- memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
- break;
- }
- }
-
- return ret;
-
-frontend_detach:
- port->gate_ctrl = NULL;
- videobuf_dvb_dealloc_frontends(&port->frontends);
- return -EINVAL;
-}
-
-int cx23885_dvb_register(struct cx23885_tsport *port)
-{
-
- struct videobuf_dvb_frontend *fe0;
- struct cx23885_dev *dev = port->dev;
- int err, i;
-
- /* Here we need to allocate the correct number of frontends,
- * as reflected in the cards struct. The reality is that currently
- * no cx23885 boards support this - yet. But, if we don't modify this
- * code then the second frontend would never be allocated (later)
- * and fail with error before the attach in dvb_register().
- * Without these changes we risk an OOPS later. The changes here
- * are for safety, and should provide a good foundation for the
- * future addition of any multi-frontend cx23885 based boards.
- */
- printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
- port->num_frontends);
-
- for (i = 1; i <= port->num_frontends; i++) {
- if (videobuf_dvb_alloc_frontend(
- &port->frontends, i) == NULL) {
- printk(KERN_ERR "%s() failed to alloc\n", __func__);
- return -ENOMEM;
- }
-
- fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
- if (!fe0)
- err = -EINVAL;
-
- dprintk(1, "%s\n", __func__);
- dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
- dev->board,
- dev->name,
- dev->pci_bus,
- dev->pci_slot);
-
- err = -ENODEV;
-
- /* dvb stuff */
- /* We have to init the queue for each frontend on a port. */
- printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
- videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
- &dev->pci->dev, &port->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
- sizeof(struct cx23885_buffer), port, NULL);
- }
- err = dvb_register(port);
- if (err != 0)
- printk(KERN_ERR "%s() dvb_register failed err = %d\n",
- __func__, err);
-
- return err;
-}
-
-int cx23885_dvb_unregister(struct cx23885_tsport *port)
-{
- struct videobuf_dvb_frontend *fe0;
-
- /* FIXME: in an error condition where the we have
- * an expected number of frontends (attach problem)
- * then this might not clean up correctly, if 1
- * is invalid.
- * This comment only applies to future boards IF they
- * implement MFE support.
- */
- fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
- if (fe0 && fe0->dvb.frontend)
- videobuf_dvb_unregister_bus(&port->frontends);
-
- switch (port->dev->board) {
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- netup_ci_exit(port);
- break;
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
- altera_ci_release(port->dev, port->nr);
- break;
- }
-
- port->gate_ctrl = NULL;
-
- return 0;
-}
-
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
deleted file mode 100644
index ce765e3f77bd..000000000000
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Driver for the Conexant CX23885/7/8 PCIe bridge
- *
- * Infrared remote control input device
- *
- * Most of this file is
- *
- * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
- *
- * However, the cx23885_input_{init,fini} functions contained herein are
- * derived from Linux kernel files linux/media/video/.../...-input.c marked as:
- *
- * Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
- * Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- * Markus Rechberger <mrechberger@gmail.com>
- * Mauro Carvalho Chehab <mchehab@infradead.org>
- * Sascha Sommer <saschasommer@freenet.de>
- * Copyright (C) 2004, 2005 Chris Pascoe
- * Copyright (C) 2003, 2004 Gerd Knorr
- * Copyright (C) 2003 Pavel Machek
- *
- * 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 <linux/slab.h>
-#include <media/rc-core.h>
-#include <media/v4l2-subdev.h>
-
-#include "cx23885.h"
-
-#define MODULE_NAME "cx23885"
-
-static void cx23885_input_process_measurements(struct cx23885_dev *dev,
- bool overrun)
-{
- struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
-
- ssize_t num;
- int count, i;
- bool handle = false;
- struct ir_raw_event ir_core_event[64];
-
- do {
- num = 0;
- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
- sizeof(ir_core_event), &num);
-
- count = num / sizeof(struct ir_raw_event);
-
- for (i = 0; i < count; i++) {
- ir_raw_event_store(kernel_ir->rc,
- &ir_core_event[i]);
- handle = true;
- }
- } while (num != 0);
-
- if (overrun)
- ir_raw_event_reset(kernel_ir->rc);
- else if (handle)
- ir_raw_event_handle(kernel_ir->rc);
-}
-
-void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
-{
- struct v4l2_subdev_ir_parameters params;
- int overrun, data_available;
-
- if (dev->sd_ir == NULL || events == 0)
- return;
-
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- case CX23885_BOARD_TEVII_S470:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- /*
- * The only boards we handle right now. However other boards
- * using the CX2388x integrated IR controller should be similar
- */
- break;
- default:
- return;
- }
-
- overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN |
- V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN);
-
- data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED |
- V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ);
-
- if (overrun) {
- /* If there was a FIFO overrun, stop the device */
- v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
- params.enable = false;
- /* Mitigate race with cx23885_input_ir_stop() */
- params.shutdown = atomic_read(&dev->ir_input_stopping);
- v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
- }
-
- if (data_available)
- cx23885_input_process_measurements(dev, overrun);
-
- if (overrun) {
- /* If there was a FIFO overrun, clear & restart the device */
- params.enable = true;
- /* Mitigate race with cx23885_input_ir_stop() */
- params.shutdown = atomic_read(&dev->ir_input_stopping);
- v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
- }
-}
-
-static int cx23885_input_ir_start(struct cx23885_dev *dev)
-{
- struct v4l2_subdev_ir_parameters params;
-
- if (dev->sd_ir == NULL)
- return -ENODEV;
-
- atomic_set(&dev->ir_input_stopping, 0);
-
- v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- /*
- * The IR controller on this board only returns pulse widths.
- * Any other mode setting will fail to set up the device.
- */
- params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
- params.enable = true;
- params.interrupt_enable = true;
- params.shutdown = false;
-
- /* Setup for baseband compatible with both RC-5 and RC-6A */
- params.modulation = false;
- /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/
- /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/
- params.max_pulse_width = 3333333; /* ns */
- /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
- /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
- params.noise_filter_min_width = 333333; /* ns */
- /*
- * This board has inverted receive sense:
- * mark is received as low logic level;
- * falling edges are detected as rising edges; etc.
- */
- params.invert_level = true;
- break;
- case CX23885_BOARD_TEVII_S470:
- /*
- * The IR controller on this board only returns pulse widths.
- * Any other mode setting will fail to set up the device.
- */
- params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
- params.enable = true;
- params.interrupt_enable = true;
- params.shutdown = false;
-
- /* Setup for a standard NEC protocol */
- params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
- params.carrier_range_lower = 33000; /* Hz */
- params.carrier_range_upper = 43000; /* Hz */
- params.duty_cycle = 33; /* percent, 33 percent for NEC */
-
- /*
- * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
- * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
- */
- params.max_pulse_width = 12378022; /* ns */
-
- /*
- * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
- * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
- */
- params.noise_filter_min_width = 351648; /* ns */
-
- params.modulation = false;
- params.invert_level = true;
- break;
- }
- v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
- return 0;
-}
-
-static int cx23885_input_ir_open(struct rc_dev *rc)
-{
- struct cx23885_kernel_ir *kernel_ir = rc->priv;
-
- if (kernel_ir->cx == NULL)
- return -ENODEV;
-
- return cx23885_input_ir_start(kernel_ir->cx);
-}
-
-static void cx23885_input_ir_stop(struct cx23885_dev *dev)
-{
- struct v4l2_subdev_ir_parameters params;
-
- if (dev->sd_ir == NULL)
- return;
-
- /*
- * Stop the sd_ir subdevice from generating notifications and
- * scheduling work.
- * It is shutdown this way in order to mitigate a race with
- * cx23885_input_rx_work_handler() in the overrun case, which could
- * re-enable the subdevice.
- */
- atomic_set(&dev->ir_input_stopping, 1);
- v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
- while (params.shutdown == false) {
- params.enable = false;
- params.interrupt_enable = false;
- params.shutdown = true;
- v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
- v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
- }
- flush_work_sync(&dev->cx25840_work);
- flush_work_sync(&dev->ir_rx_work);
- flush_work_sync(&dev->ir_tx_work);
-}
-
-static void cx23885_input_ir_close(struct rc_dev *rc)
-{
- struct cx23885_kernel_ir *kernel_ir = rc->priv;
-
- if (kernel_ir->cx != NULL)
- cx23885_input_ir_stop(kernel_ir->cx);
-}
-
-int cx23885_input_init(struct cx23885_dev *dev)
-{
- struct cx23885_kernel_ir *kernel_ir;
- struct rc_dev *rc;
- char *rc_map;
- enum rc_driver_type driver_type;
- unsigned long allowed_protos;
-
- int ret;
-
- /*
- * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't
- * encapsulated in a v4l2_subdev, then I'm not going to deal with it.
- */
- if (dev->sd_ir == NULL)
- return -ENODEV;
-
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1270:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
- /* Integrated CX2388[58] IR controller */
- driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = RC_TYPE_ALL;
- /* The grey Hauppauge RC-5 remote */
- rc_map = RC_MAP_HAUPPAUGE;
- break;
- case CX23885_BOARD_TEVII_S470:
- /* Integrated CX23885 IR controller */
- driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = RC_TYPE_ALL;
- /* A guess at the remote */
- rc_map = RC_MAP_TEVII_NEC;
- break;
- default:
- return -ENODEV;
- }
-
- /* cx23885 board instance kernel IR state */
- kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
- if (kernel_ir == NULL)
- return -ENOMEM;
-
- kernel_ir->cx = dev;
- kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
- cx23885_boards[dev->board].name);
- kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
- pci_name(dev->pci));
-
- /* input device */
- rc = rc_allocate_device();
- if (!rc) {
- ret = -ENOMEM;
- goto err_out_free;
- }
-
- kernel_ir->rc = rc;
- rc->input_name = kernel_ir->name;
- rc->input_phys = kernel_ir->phys;
- rc->input_id.bustype = BUS_PCI;
- rc->input_id.version = 1;
- if (dev->pci->subsystem_vendor) {
- rc->input_id.vendor = dev->pci->subsystem_vendor;
- rc->input_id.product = dev->pci->subsystem_device;
- } else {
- rc->input_id.vendor = dev->pci->vendor;
- rc->input_id.product = dev->pci->device;
- }
- rc->dev.parent = &dev->pci->dev;
- rc->driver_type = driver_type;
- rc->allowed_protos = allowed_protos;
- rc->priv = kernel_ir;
- rc->open = cx23885_input_ir_open;
- rc->close = cx23885_input_ir_close;
- rc->map_name = rc_map;
- rc->driver_name = MODULE_NAME;
-
- /* Go */
- dev->kernel_ir = kernel_ir;
- ret = rc_register_device(rc);
- if (ret)
- goto err_out_stop;
-
- return 0;
-
-err_out_stop:
- cx23885_input_ir_stop(dev);
- dev->kernel_ir = NULL;
- rc_free_device(rc);
-err_out_free:
- kfree(kernel_ir->phys);
- kfree(kernel_ir->name);
- kfree(kernel_ir);
- return ret;
-}
-
-void cx23885_input_fini(struct cx23885_dev *dev)
-{
- /* Always stop the IR hardware from generating interrupts */
- cx23885_input_ir_stop(dev);
-
- if (dev->kernel_ir == NULL)
- return;
- rc_unregister_device(dev->kernel_ir->rc);
- kfree(dev->kernel_ir->phys);
- kfree(dev->kernel_ir->name);
- kfree(dev->kernel_ir);
- dev->kernel_ir = NULL;
-}
diff --git a/drivers/media/video/cx25821/Makefile b/drivers/media/video/cx25821/Makefile
deleted file mode 100644
index aedde18c68f9..000000000000
--- a/drivers/media/video/cx25821/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
- cx25821-gpio.o cx25821-medusa-video.o \
- cx25821-video.o cx25821-video-upstream.o \
- cx25821-video-upstream-ch2.o \
- cx25821-audio-upstream.o
-
-obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
-obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.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
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
deleted file mode 100644
index dc40dde2e0c8..000000000000
--- a/drivers/media/video/cx25840/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
- cx25840-vbi.o cx25840-ir.o
-
-obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
-
-ccflags-y += -Idrivers/media/video
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
deleted file mode 100644
index 8150200511da..000000000000
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/* cx25840 firmware functions
- *
- * 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 <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <media/v4l2-common.h>
-#include <media/cx25840.h>
-
-#include "cx25840-core.h"
-
-/*
- * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
- * size of the firmware chunks sent down the I2C bus to the chip.
- * Previously this had been set to 1024 but unfortunately some I2C
- * implementations can't transfer data in such big gulps.
- * Specifically, the pvrusb2 driver has a hard limit of around 60
- * bytes, due to the encapsulation there of I2C traffic into USB
- * messages. So we have to significantly reduce this parameter.
- */
-#define FWSEND 48
-
-#define FWDEV(x) &((x)->dev)
-
-static char *firmware = "";
-
-module_param(firmware, charp, 0444);
-
-MODULE_PARM_DESC(firmware, "Firmware image to load");
-
-static void start_fw_load(struct i2c_client *client)
-{
- /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
- cx25840_write(client, 0x800, 0x00);
- cx25840_write(client, 0x801, 0x00);
- // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
- cx25840_write(client, 0x803, 0x0b);
- /* AUTO_INC_DIS=1 */
- cx25840_write(client, 0x000, 0x20);
-}
-
-static void end_fw_load(struct i2c_client *client)
-{
- /* AUTO_INC_DIS=0 */
- cx25840_write(client, 0x000, 0x00);
- /* DL_ENABLE=0 */
- cx25840_write(client, 0x803, 0x03);
-}
-
-static const char *get_fw_name(struct i2c_client *client)
-{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
-
- if (firmware[0])
- return firmware;
- if (is_cx2388x(state))
- return "v4l-cx23885-avcore-01.fw";
- if (is_cx231xx(state))
- return "v4l-cx231xx-avcore-01.fw";
- return "v4l-cx25840.fw";
-}
-
-static int check_fw_load(struct i2c_client *client, int size)
-{
- /* DL_ADDR_HB DL_ADDR_LB */
- int s = cx25840_read(client, 0x801) << 8;
- s |= cx25840_read(client, 0x800);
-
- if (size != s) {
- v4l_err(client, "firmware %s load failed\n",
- get_fw_name(client));
- return -EINVAL;
- }
-
- v4l_info(client, "loaded %s firmware (%d bytes)\n",
- get_fw_name(client), size);
- return 0;
-}
-
-static int fw_write(struct i2c_client *client, const u8 *data, int size)
-{
- if (i2c_master_send(client, data, size) < size) {
- v4l_err(client, "firmware load i2c failure\n");
- return -ENOSYS;
- }
-
- return 0;
-}
-
-int cx25840_loadfw(struct i2c_client *client)
-{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
- const struct firmware *fw = NULL;
- u8 buffer[FWSEND];
- const u8 *ptr;
- const char *fwname = get_fw_name(client);
- int size, retval;
- int MAX_BUF_SIZE = FWSEND;
- u32 gpio_oe = 0, gpio_da = 0;
-
- if (is_cx2388x(state)) {
- /* Preserve the GPIO OE and output bits */
- gpio_oe = cx25840_read(client, 0x160);
- gpio_da = cx25840_read(client, 0x164);
- }
-
- if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
- v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
- MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
- }
-
- if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
- v4l_err(client, "unable to open firmware %s\n", fwname);
- return -EINVAL;
- }
-
- start_fw_load(client);
-
- buffer[0] = 0x08;
- buffer[1] = 0x02;
-
- size = fw->size;
- ptr = fw->data;
- while (size > 0) {
- int len = min(MAX_BUF_SIZE - 2, size);
-
- memcpy(buffer + 2, ptr, len);
-
- retval = fw_write(client, buffer, len + 2);
-
- if (retval < 0) {
- release_firmware(fw);
- return retval;
- }
-
- size -= len;
- ptr += len;
- }
-
- end_fw_load(client);
-
- size = fw->size;
- release_firmware(fw);
-
- if (is_cx2388x(state)) {
- /* Restore GPIO configuration after f/w load */
- cx25840_write(client, 0x160, gpio_oe);
- cx25840_write(client, 0x164, gpio_da);
- }
-
- return check_fw_load(client, size);
-}
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
deleted file mode 100644
index 3598dc087b08..000000000000
--- a/drivers/media/video/cx88/Kconfig
+++ /dev/null
@@ -1,86 +0,0 @@
-config VIDEO_CX88
- tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && RC_CORE
- select I2C_ALGOBIT
- select VIDEO_BTCX
- select VIDEOBUF_DMA_SG
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- This is a video4linux driver for Conexant 2388x based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called cx8800
-
-config VIDEO_CX88_ALSA
- tristate "Conexant 2388x DMA audio support"
- depends on VIDEO_CX88 && SND
- select SND_PCM
- ---help---
- This is a video4linux driver for direct (DMA) audio on
- Conexant 2388x based TV cards using ALSA.
-
- It only works with boards with function 01 enabled.
- To check if your board supports, use lspci -n.
- If supported, you should see 14f1:8801 or 14f1:8811
- PCI device.
-
- To compile this driver as a module, choose M here: the
- module will be called cx88-alsa.
-
-config VIDEO_CX88_BLACKBIRD
- tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
- depends on VIDEO_CX88
- select VIDEO_CX2341X
- ---help---
- This adds support for MPEG encoder cards based on the
- Blackbird reference design, using the Conexant 2388x
- and 23416 chips.
-
- To compile this driver as a module, choose M here: the
- module will be called cx88-blackbird.
-
-config VIDEO_CX88_DVB
- tristate "DVB/ATSC Support for cx2388x based TV cards"
- depends on VIDEO_CX88 && DVB_CORE
- select VIDEOBUF_DVB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_OR51132 if !DVB_FE_CUSTOMISE
- select DVB_CX22702 if !DVB_FE_CUSTOMISE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_NXT200X if !DVB_FE_CUSTOMISE
- select DVB_CX24123 if !DVB_FE_CUSTOMISE
- select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_CX24116 if !DVB_FE_CUSTOMISE
- select DVB_STV0299 if !DVB_FE_CUSTOMISE
- select DVB_STV0288 if !DVB_FE_CUSTOMISE
- select DVB_STB6000 if !DVB_FE_CUSTOMISE
- select DVB_STV0900 if !DVB_FE_CUSTOMISE
- select DVB_STB6100 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- ---help---
- This adds support for DVB/ATSC cards based on the
- Conexant 2388x chip.
-
- To compile this driver as a module, choose M here: the
- module will be called cx88-dvb.
-
-config VIDEO_CX88_VP3054
- tristate "VP-3054 Secondary I2C Bus Support"
- default m
- depends on VIDEO_CX88_DVB && DVB_MT352
- ---help---
- This adds DVB-T support for cards based on the
- 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/Makefile b/drivers/media/video/cx88/Makefile
deleted file mode 100644
index c1a2785ba243..000000000000
--- a/drivers/media/video/cx88/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
- cx88-dsp.o cx88-input.o
-cx8800-objs := cx88-video.o cx88-vbi.o
-cx8802-objs := cx88-mpeg.o
-
-obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
-obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o
-obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
-obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
-obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.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
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
deleted file mode 100644
index dfac6e34859f..000000000000
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- *
- * Support for audio capture
- * PCI function #1 of the cx2388x.
- *
- * (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
- * (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- * (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
- * Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
- * Based on dummy.c by Jaroslav Kysela <perex@perex.cz>
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/dma-mapping.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <media/wm8775.h>
-
-#include "cx88.h"
-#include "cx88-reg.h"
-
-#define dprintk(level,fmt, arg...) if (debug >= level) \
- printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
-
-#define dprintk_core(level,fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
-
-/****************************************************************************
- Data type declarations - Can be moded to a header file later
- ****************************************************************************/
-
-struct cx88_audio_buffer {
- unsigned int bpl;
- struct btcx_riscmem risc;
- struct videobuf_dmabuf dma;
-};
-
-struct cx88_audio_dev {
- struct cx88_core *core;
- struct cx88_dmaqueue q;
-
- /* pci i/o */
- struct pci_dev *pci;
-
- /* audio controls */
- int irq;
-
- struct snd_card *card;
-
- spinlock_t reg_lock;
- atomic_t count;
-
- unsigned int dma_size;
- unsigned int period_size;
- unsigned int num_periods;
-
- struct videobuf_dmabuf *dma_risc;
-
- struct cx88_audio_buffer *buf;
-
- struct snd_pcm_substream *substream;
-};
-typedef struct cx88_audio_dev snd_cx88_card_t;
-
-
-
-/****************************************************************************
- Module global static vars
- ****************************************************************************/
-
-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 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.");
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
-
-
-/****************************************************************************
- Module macros
- ****************************************************************************/
-
-MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
-MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(CX88_VERSION);
-
-MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
- "{{Conexant,23882},"
- "{{Conexant,23883}");
-static unsigned int debug;
-module_param(debug,int,0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
-
-/****************************************************************************
- Module specific funtions
- ****************************************************************************/
-
-/*
- * BOARD Specific: Sets audio DMA
- */
-
-static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
-{
- struct cx88_audio_buffer *buf = chip->buf;
- struct cx88_core *core=chip->core;
- const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
-
- /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
- cx_clear(MO_AUD_DMACNTRL, 0x11);
-
- /* setup fifo + format - out channel */
- cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
-
- /* sets bpl size */
- cx_write(MO_AUDD_LNGTH, buf->bpl);
-
- /* reset counter */
- cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
- atomic_set(&chip->count, 0);
-
- dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
- "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
- chip->num_periods, buf->bpl * chip->num_periods);
-
- /* Enables corresponding bits at AUD_INT_STAT */
- cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
- AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
-
- /* Clean any pending interrupt bits already set */
- cx_write(MO_AUD_INTSTAT, ~0);
-
- /* enable audio irqs */
- cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
-
- /* start dma */
- cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
- cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
-
- if (debug)
- cx88_sram_channel_dump(chip->core, audio_ch);
-
- return 0;
-}
-
-/*
- * BOARD Specific: Resets audio DMA
- */
-static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
-{
- struct cx88_core *core=chip->core;
- dprintk(1, "Stopping audio DMA\n");
-
- /* stop dma */
- cx_clear(MO_AUD_DMACNTRL, 0x11);
-
- /* disable irqs */
- cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
- cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
- AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
-
- if (debug)
- cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
-
- return 0;
-}
-
-#define MAX_IRQ_LOOP 50
-
-/*
- * BOARD Specific: IRQ dma bits
- */
-static const char *cx88_aud_irqs[32] = {
- "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
- 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 */
-};
-
-/*
- * BOARD Specific: Threats IRQ audio specific calls
- */
-static void cx8801_aud_irq(snd_cx88_card_t *chip)
-{
- struct cx88_core *core = chip->core;
- u32 status, mask;
-
- status = cx_read(MO_AUD_INTSTAT);
- mask = cx_read(MO_AUD_INTMSK);
- if (0 == (status & mask))
- return;
- cx_write(MO_AUD_INTSTAT, status);
- if (debug > 1 || (status & mask & ~0xff))
- cx88_print_irqbits(core->name, "irq aud",
- cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
- status, mask);
- /* risc op code error */
- if (status & AUD_INT_OPC_ERR) {
- printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
- cx_clear(MO_AUD_DMACNTRL, 0x11);
- cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
- }
- if (status & AUD_INT_DN_SYNC) {
- dprintk(1, "Downstream sync error\n");
- cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
- return;
- }
- /* risc1 downstream */
- if (status & AUD_INT_DN_RISCI1) {
- atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
- snd_pcm_period_elapsed(chip->substream);
- }
- /* FIXME: Any other status should deserve a special handling? */
-}
-
-/*
- * BOARD Specific: Handles IRQ calls
- */
-static irqreturn_t cx8801_irq(int irq, void *dev_id)
-{
- snd_cx88_card_t *chip = dev_id;
- struct cx88_core *core = chip->core;
- u32 status;
- int loop, handled = 0;
-
- for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) &
- (core->pci_irqmask | PCI_INT_AUDINT);
- if (0 == status)
- goto out;
- dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
- loop, MAX_IRQ_LOOP, status);
- handled = 1;
- cx_write(MO_PCI_INTSTAT, status);
-
- if (status & core->pci_irqmask)
- cx88_core_irq(core, status);
- if (status & PCI_INT_AUDINT)
- cx8801_aud_irq(chip);
- }
-
- if (MAX_IRQ_LOOP == loop) {
- printk(KERN_ERR
- "%s/1: IRQ loop detected, disabling interrupts\n",
- core->name);
- cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
- }
-
- out:
- return IRQ_RETVAL(handled);
-}
-
-
-static int dsp_buffer_free(snd_cx88_card_t *chip)
-{
- BUG_ON(!chip->dma_size);
-
- dprintk(2,"Freeing buffer\n");
- videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
- videobuf_dma_free(chip->dma_risc);
- btcx_riscmem_free(chip->pci,&chip->buf->risc);
- kfree(chip->buf);
-
- chip->dma_risc = NULL;
- chip->dma_size = 0;
-
- return 0;
-}
-
-/****************************************************************************
- ALSA PCM Interface
- ****************************************************************************/
-
-/*
- * Digital hardware definition
- */
-#define DEFAULT_FIFO_SIZE 4096
-static const struct snd_pcm_hardware snd_cx88_digital_hw = {
- .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,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- /* Analog audio output will be full of clicks and pops if there
- are not exactly four lines in the SRAM FIFO buffer. */
- .period_bytes_min = DEFAULT_FIFO_SIZE/4,
- .period_bytes_max = DEFAULT_FIFO_SIZE/4,
- .periods_min = 1,
- .periods_max = 1024,
- .buffer_bytes_max = (1024*1024),
-};
-
-/*
- * audio pcm capture open callback
- */
-static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
-{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- if (!chip) {
- printk(KERN_ERR "BUG: cx88 can't find device struct."
- " Can't proceed with open\n");
- return -ENODEV;
- }
-
- err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0)
- goto _error;
-
- chip->substream = substream;
-
- runtime->hw = snd_cx88_digital_hw;
-
- if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
- unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
- bpl &= ~7; /* must be multiple of 8 */
- runtime->hw.period_bytes_min = bpl;
- runtime->hw.period_bytes_max = bpl;
- }
-
- return 0;
-_error:
- dprintk(1,"Error opening PCM!\n");
- return err;
-}
-
-/*
- * audio close callback
- */
-static int snd_cx88_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/*
- * hw_params callback
- */
-static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
- struct snd_pcm_hw_params * hw_params)
-{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
- struct videobuf_dmabuf *dma;
-
- struct cx88_audio_buffer *buf;
- int ret;
-
- if (substream->runtime->dma_area) {
- dsp_buffer_free(chip);
- substream->runtime->dma_area = NULL;
- }
-
- chip->period_size = params_period_bytes(hw_params);
- chip->num_periods = params_periods(hw_params);
- chip->dma_size = chip->period_size * params_periods(hw_params);
-
- BUG_ON(!chip->dma_size);
- BUG_ON(chip->num_periods & (chip->num_periods-1));
-
- buf = kzalloc(sizeof(*buf), GFP_KERNEL);
- if (NULL == buf)
- return -ENOMEM;
-
- buf->bpl = chip->period_size;
-
- dma = &buf->dma;
- videobuf_dma_init(dma);
- ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
- (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
- if (ret < 0)
- goto error;
-
- ret = videobuf_dma_map(&chip->pci->dev, dma);
- if (ret < 0)
- goto error;
-
- ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
- chip->period_size, chip->num_periods, 1);
- if (ret < 0)
- goto error;
-
- /* Loop back to start of program */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- chip->buf = buf;
- chip->dma_risc = dma;
-
- substream->runtime->dma_area = chip->dma_risc->vaddr;
- substream->runtime->dma_bytes = chip->dma_size;
- substream->runtime->dma_addr = 0;
- return 0;
-
-error:
- kfree(buf);
- return ret;
-}
-
-/*
- * hw free callback
- */
-static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
-{
-
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-
- if (substream->runtime->dma_area) {
- dsp_buffer_free(chip);
- substream->runtime->dma_area = NULL;
- }
-
- return 0;
-}
-
-/*
- * prepare callback
- */
-static int snd_cx88_prepare(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/*
- * trigger callback
- */
-static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
- int err;
-
- /* Local interrupts are already disabled by ALSA */
- spin_lock(&chip->reg_lock);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- err=_cx88_start_audio_dma(chip);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- err=_cx88_stop_audio_dma(chip);
- break;
- default:
- err=-EINVAL;
- break;
- }
-
- spin_unlock(&chip->reg_lock);
-
- return err;
-}
-
-/*
- * pointer callback
- */
-static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
-{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- u16 count;
-
- count = atomic_read(&chip->count);
-
-// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
-// count, new, count & (runtime->periods-1),
-// runtime->period_size * (count & (runtime->periods-1)));
- return runtime->period_size * (count & (runtime->periods-1));
-}
-
-/*
- * page callback (needed for mmap)
- */
-static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
- unsigned long offset)
-{
- void *pageptr = substream->runtime->dma_area + offset;
- return vmalloc_to_page(pageptr);
-}
-
-/*
- * operators
- */
-static struct snd_pcm_ops snd_cx88_pcm_ops = {
- .open = snd_cx88_pcm_open,
- .close = snd_cx88_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_cx88_hw_params,
- .hw_free = snd_cx88_hw_free,
- .prepare = snd_cx88_prepare,
- .trigger = snd_cx88_card_trigger,
- .pointer = snd_cx88_pointer,
- .page = snd_cx88_page,
-};
-
-/*
- * create a PCM device
- */
-static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
-{
- int err;
- struct snd_pcm *pcm;
-
- err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = chip;
- strcpy(pcm->name, name);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
-
- return 0;
-}
-
-/****************************************************************************
- CONTROL INTERFACE
- ****************************************************************************/
-static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *info)
-{
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 2;
- info->value.integer.min = 0;
- info->value.integer.max = 0x3f;
-
- return 0;
-}
-
-static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core=chip->core;
- int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
- bal = cx_read(AUD_BAL_CTL);
-
- value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
- vol -= (bal & 0x3f);
- value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
-
- return 0;
-}
-
-static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- int left = value->value.integer.value[0];
- int right = value->value.integer.value[1];
- int v, b;
-
- /* Pass volume & balance onto any WM8775 */
- if (left >= right) {
- v = left << 10;
- b = left ? (0x8000 * right) / left : 0x8000;
- } else {
- v = right << 10;
- b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
- }
- wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);
- wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);
-}
-
-/* OK - TODO: test it */
-static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core=chip->core;
- int left, right, v, b;
- int changed = 0;
- u32 old;
-
- if (core->board.audio_chip == V4L2_IDENT_WM8775)
- snd_cx88_wm8775_volume_put(kcontrol, value);
-
- left = value->value.integer.value[0] & 0x3f;
- right = value->value.integer.value[1] & 0x3f;
- b = right - left;
- if (b < 0) {
- v = 0x3f - left;
- b = (-b) | 0x40;
- } else {
- v = 0x3f - right;
- }
- /* Do we really know this will always be called with IRQs on? */
- spin_lock_irq(&chip->reg_lock);
- old = cx_read(AUD_VOL_CTL);
- if (v != (old & 0x3f)) {
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
- changed = 1;
- }
- if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
- cx_write(AUD_BAL_CTL, b);
- changed = 1;
- }
- spin_unlock_irq(&chip->reg_lock);
-
- return changed;
-}
-
-static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
-
-static const struct snd_kcontrol_new snd_cx88_volume = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .name = "Analog-TV Volume",
- .info = snd_cx88_volume_info,
- .get = snd_cx88_volume_get,
- .put = snd_cx88_volume_put,
- .tlv.p = snd_cx88_db_scale,
-};
-
-static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- u32 bit = kcontrol->private_value;
-
- value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
- return 0;
-}
-
-static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- u32 bit = kcontrol->private_value;
- int ret = 0;
- u32 vol;
-
- spin_lock_irq(&chip->reg_lock);
- vol = cx_read(AUD_VOL_CTL);
- if (value->value.integer.value[0] != !(vol & bit)) {
- vol ^= bit;
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
- /* Pass mute onto any WM8775 */
- if ((core->board.audio_chip == V4L2_IDENT_WM8775) &&
- ((1<<6) == bit))
- wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));
- ret = 1;
- }
- spin_unlock_irq(&chip->reg_lock);
- return ret;
-}
-
-static const struct snd_kcontrol_new snd_cx88_dac_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Audio-Out Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = snd_cx88_switch_get,
- .put = snd_cx88_switch_put,
- .private_value = (1<<8),
-};
-
-static const struct snd_kcontrol_new snd_cx88_source_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog-TV Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = snd_cx88_switch_get,
- .put = snd_cx88_switch_put,
- .private_value = (1<<6),
-};
-
-static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- s32 val;
-
- val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);
- value->value.integer.value[0] = val ? 1 : 0;
- return 0;
-}
-
-static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- struct v4l2_control client_ctl;
-
- memset(&client_ctl, 0, sizeof(client_ctl));
- client_ctl.value = 0 != value->value.integer.value[0];
- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
- return 0;
-}
-
-static struct snd_kcontrol_new snd_cx88_alc_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In ALC Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = snd_cx88_alc_get,
- .put = snd_cx88_alc_put,
-};
-
-/****************************************************************************
- Basic Flow for Sound Devices
- ****************************************************************************/
-
-/*
- * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
- * Only boards with eeprom and byte 1 at eeprom=1 have it
- */
-
-static const struct pci_device_id const cx88_audio_pci_tbl[] __devinitdata = {
- {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {0, }
-};
-MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
-
-/*
- * Chip-specific destructor
- */
-
-static int snd_cx88_free(snd_cx88_card_t *chip)
-{
-
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
-
- cx88_core_put(chip->core,chip->pci);
-
- pci_disable_device(chip->pci);
- return 0;
-}
-
-/*
- * Component Destructor
- */
-static void snd_cx88_dev_free(struct snd_card * card)
-{
- snd_cx88_card_t *chip = card->private_data;
-
- snd_cx88_free(chip);
-}
-
-
-/*
- * Alsa Constructor - Component probe
- */
-
-static int devno;
-static int __devinit snd_cx88_create(struct snd_card *card,
- struct pci_dev *pci,
- snd_cx88_card_t **rchip,
- struct cx88_core **core_ptr)
-{
- snd_cx88_card_t *chip;
- struct cx88_core *core;
- int err;
- unsigned char pci_lat;
-
- *rchip = NULL;
-
- err = pci_enable_device(pci);
- if (err < 0)
- return err;
-
- pci_set_master(pci);
-
- chip = card->private_data;
-
- core = cx88_core_get(pci);
- if (NULL == core) {
- err = -EINVAL;
- return err;
- }
-
- if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
- dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
- err = -EIO;
- cx88_core_put(core, pci);
- return err;
- }
-
-
- /* pci init */
- chip->card = card;
- chip->pci = pci;
- chip->irq = -1;
- spin_lock_init(&chip->reg_lock);
-
- chip->core = core;
-
- /* get irq */
- err = request_irq(chip->pci->irq, cx8801_irq,
- IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip);
- if (err < 0) {
- dprintk(0, "%s: can't get IRQ %d\n",
- chip->core->name, chip->pci->irq);
- return err;
- }
-
- /* print pci info */
- pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
-
- dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
- "latency: %d, mmio: 0x%llx\n", core->name, devno,
- pci_name(pci), pci->revision, pci->irq,
- pci_lat, (unsigned long long)pci_resource_start(pci,0));
-
- chip->irq = pci->irq;
- synchronize_irq(chip->irq);
-
- snd_card_set_dev(card, &pci->dev);
-
- *rchip = chip;
- *core_ptr = core;
-
- return 0;
-}
-
-static int __devinit cx88_audio_initdev(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
-{
- struct snd_card *card;
- snd_cx88_card_t *chip;
- struct cx88_core *core = NULL;
- int err;
-
- if (devno >= SNDRV_CARDS)
- return (-ENODEV);
-
- if (!enable[devno]) {
- ++devno;
- return (-ENOENT);
- }
-
- err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(snd_cx88_card_t), &card);
- if (err < 0)
- return err;
-
- card->private_free = snd_cx88_dev_free;
-
- err = snd_cx88_create(card, pci, &chip, &core);
- if (err < 0)
- goto error;
-
- err = snd_cx88_pcm(chip, 0, "CX88 Digital");
- if (err < 0)
- goto error;
-
- err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
- if (err < 0)
- goto error;
- err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
- if (err < 0)
- goto error;
- err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
- if (err < 0)
- goto error;
-
- /* If there's a wm8775 then add a Line-In ALC switch */
- if (core->board.audio_chip == V4L2_IDENT_WM8775)
- snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));
-
- strcpy (card->driver, "CX88x");
- sprintf(card->shortname, "Conexant CX%x", pci->device);
- sprintf(card->longname, "%s at %#llx",
- card->shortname,(unsigned long long)pci_resource_start(pci, 0));
- strcpy (card->mixername, "CX88");
-
- dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
- card->driver,devno);
-
- err = snd_card_register(card);
- if (err < 0)
- goto error;
- pci_set_drvdata(pci,card);
-
- devno++;
- return 0;
-
-error:
- snd_card_free(card);
- return err;
-}
-/*
- * ALSA destructor
- */
-static void __devexit cx88_audio_finidev(struct pci_dev *pci)
-{
- struct cx88_audio_dev *card = pci_get_drvdata(pci);
-
- snd_card_free((void *)card);
-
- pci_set_drvdata(pci, NULL);
-
- devno--;
-}
-
-/*
- * PCI driver definition
- */
-
-static struct pci_driver cx88_audio_pci_driver = {
- .name = "cx88_audio",
- .id_table = cx88_audio_pci_tbl,
- .probe = cx88_audio_initdev,
- .remove = __devexit_p(cx88_audio_finidev),
-};
-
-/****************************************************************************
- LINUX MODULE INIT
- ****************************************************************************/
-
-/*
- * module init
- */
-static int __init cx88_audio_init(void)
-{
- printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
- CX88_VERSION);
- return pci_register_driver(&cx88_audio_pci_driver);
-}
-
-/*
- * module remove
- */
-static void __exit cx88_audio_fini(void)
-{
- pci_unregister_driver(&cx88_audio_pci_driver);
-}
-
-module_init(cx88_audio_init);
-module_exit(cx88_audio_fini);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
deleted file mode 100644
index e81c735f012a..000000000000
--- a/drivers/media/video/cx88/cx88-core.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/*
- *
- * device driver for Conexant 2388x based TV cards
- * driver core
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- * - Multituner support
- * - video_ioctl2 conversion
- * - PAL/M fixes
- *
- * 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/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/kmod.h>
-#include <linux/sound.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <linux/mutex.h>
-
-#include "cx88.h"
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-/* ------------------------------------------------------------------ */
-
-static unsigned int core_debug;
-module_param(core_debug,int,0644);
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-
-static unsigned int nicam;
-module_param(nicam,int,0644);
-MODULE_PARM_DESC(nicam,"tv audio is nicam");
-
-static unsigned int nocomb;
-module_param(nocomb,int,0644);
-MODULE_PARM_DESC(nocomb,"disable comb filter");
-
-#define dprintk(level,fmt, arg...) if (core_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
-
-static unsigned int cx88_devcount;
-static LIST_HEAD(cx88_devlist);
-static DEFINE_MUTEX(devlist);
-
-#define NO_SYNC_LINE (-1U)
-
-/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
- generated _after_ lpi lines are transferred. */
-static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
- unsigned int offset, u32 sync_line,
- unsigned int bpl, unsigned int padding,
- unsigned int lines, unsigned int lpi)
-{
- struct scatterlist *sg;
- unsigned int line,todo,sol;
-
- /* sync instruction */
- if (sync_line != NO_SYNC_LINE)
- *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-
- /* scan lines */
- sg = sglist;
- for (line = 0; line < lines; line++) {
- while (offset && offset >= sg_dma_len(sg)) {
- offset -= sg_dma_len(sg);
- sg++;
- }
- if (lpi && line>0 && !(line % lpi))
- sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
- else
- sol = RISC_SOL;
- 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(sg_dma_address(sg)+offset);
- offset+=bpl;
- } else {
- /* scanline needs to be split */
- todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|sol|
- (sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- todo -= (sg_dma_len(sg)-offset);
- offset = 0;
- sg++;
- while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(RISC_WRITE|
- sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
- todo -= sg_dma_len(sg);
- sg++;
- }
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
- offset += todo;
- }
- offset += padding;
- }
-
- return rp;
-}
-
-int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- struct scatterlist *sglist,
- unsigned int top_offset, unsigned int bottom_offset,
- unsigned int bpl, unsigned int padding, unsigned int lines)
-{
- u32 instructions,fields;
- __le32 *rp;
- int rc;
-
- fields = 0;
- if (UNSET != top_offset)
- fields++;
- if (UNSET != bottom_offset)
- fields++;
-
- /* estimate risc mem: worst case is one write per page border +
- one write per scan line + syncs + jump (all 2 dwords). Padding
- can cause next bpl to start close to a page border. First DMA
- region may be smaller than PAGE_SIZE */
- instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
- if (UNSET != top_offset)
- rp = cx88_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines, 0);
- if (UNSET != bottom_offset)
- rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines, 0);
-
- /* save pointer to jmp instruction address */
- risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
- return 0;
-}
-
-int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines, unsigned int lpi)
-{
- u32 instructions;
- __le32 *rp;
- int rc;
-
- /* estimate risc mem: worst case is one write per page border +
- one write per scan line + syncs + jump (all 2 dwords). Here
- there is no padding and no sync. First DMA region may be smaller
- than PAGE_SIZE */
- instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
- instructions += 1;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
- rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
-
- /* save pointer to jmp instruction address */
- risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
- return 0;
-}
-
-int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value)
-{
- __le32 *rp;
- int rc;
-
- if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
- *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
- *(rp++) = cpu_to_le32(reg);
- *(rp++) = cpu_to_le32(value);
- *(rp++) = cpu_to_le32(mask);
- *(rp++) = cpu_to_le32(RISC_JUMP);
- *(rp++) = cpu_to_le32(risc->dma);
- return 0;
-}
-
-void
-cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
-{
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
- BUG_ON(in_interrupt());
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-/* ------------------------------------------------------------------ */
-/* our SRAM memory layout */
-
-/* we are going to put all thr risc programs into host memory, so we
- * can use the whole SDRAM for the DMA fifos. To simplify things, we
- * use a static memory layout. That surely will waste memory in case
- * we don't use all DMA channels at the same time (which will be the
- * case most of the time). But that still gives us enough FIFO space
- * to be able to deal with insane long pci latencies ...
- *
- * FIFO space allocations:
- * channel 21 (y video) - 10.0k
- * channel 22 (u video) - 2.0k
- * channel 23 (v video) - 2.0k
- * channel 24 (vbi) - 4.0k
- * channels 25+26 (audio) - 4.0k
- * channel 28 (mpeg) - 4.0k
- * channel 27 (audio rds)- 3.0k
- * TOTAL = 29.0k
- *
- * Every channel has 160 bytes control data (64 bytes instruction
- * queue and 6 CDT entries), which is close to 2k total.
- *
- * Address layout:
- * 0x0000 - 0x03ff CMDs / reserved
- * 0x0400 - 0x0bff instruction queues + CDs
- * 0x0c00 - FIFOs
- */
-
-const struct sram_channel const cx88_sram_channels[] = {
- [SRAM_CH21] = {
- .name = "video y / packed",
- .cmds_start = 0x180040,
- .ctrl_start = 0x180400,
- .cdt = 0x180400 + 64,
- .fifo_start = 0x180c00,
- .fifo_size = 0x002800,
- .ptr1_reg = MO_DMA21_PTR1,
- .ptr2_reg = MO_DMA21_PTR2,
- .cnt1_reg = MO_DMA21_CNT1,
- .cnt2_reg = MO_DMA21_CNT2,
- },
- [SRAM_CH22] = {
- .name = "video u",
- .cmds_start = 0x180080,
- .ctrl_start = 0x1804a0,
- .cdt = 0x1804a0 + 64,
- .fifo_start = 0x183400,
- .fifo_size = 0x000800,
- .ptr1_reg = MO_DMA22_PTR1,
- .ptr2_reg = MO_DMA22_PTR2,
- .cnt1_reg = MO_DMA22_CNT1,
- .cnt2_reg = MO_DMA22_CNT2,
- },
- [SRAM_CH23] = {
- .name = "video v",
- .cmds_start = 0x1800c0,
- .ctrl_start = 0x180540,
- .cdt = 0x180540 + 64,
- .fifo_start = 0x183c00,
- .fifo_size = 0x000800,
- .ptr1_reg = MO_DMA23_PTR1,
- .ptr2_reg = MO_DMA23_PTR2,
- .cnt1_reg = MO_DMA23_CNT1,
- .cnt2_reg = MO_DMA23_CNT2,
- },
- [SRAM_CH24] = {
- .name = "vbi",
- .cmds_start = 0x180100,
- .ctrl_start = 0x1805e0,
- .cdt = 0x1805e0 + 64,
- .fifo_start = 0x184400,
- .fifo_size = 0x001000,
- .ptr1_reg = MO_DMA24_PTR1,
- .ptr2_reg = MO_DMA24_PTR2,
- .cnt1_reg = MO_DMA24_CNT1,
- .cnt2_reg = MO_DMA24_CNT2,
- },
- [SRAM_CH25] = {
- .name = "audio from",
- .cmds_start = 0x180140,
- .ctrl_start = 0x180680,
- .cdt = 0x180680 + 64,
- .fifo_start = 0x185400,
- .fifo_size = 0x001000,
- .ptr1_reg = MO_DMA25_PTR1,
- .ptr2_reg = MO_DMA25_PTR2,
- .cnt1_reg = MO_DMA25_CNT1,
- .cnt2_reg = MO_DMA25_CNT2,
- },
- [SRAM_CH26] = {
- .name = "audio to",
- .cmds_start = 0x180180,
- .ctrl_start = 0x180720,
- .cdt = 0x180680 + 64, /* same as audio IN */
- .fifo_start = 0x185400, /* same as audio IN */
- .fifo_size = 0x001000, /* same as audio IN */
- .ptr1_reg = MO_DMA26_PTR1,
- .ptr2_reg = MO_DMA26_PTR2,
- .cnt1_reg = MO_DMA26_CNT1,
- .cnt2_reg = MO_DMA26_CNT2,
- },
- [SRAM_CH28] = {
- .name = "mpeg",
- .cmds_start = 0x180200,
- .ctrl_start = 0x1807C0,
- .cdt = 0x1807C0 + 64,
- .fifo_start = 0x186400,
- .fifo_size = 0x001000,
- .ptr1_reg = MO_DMA28_PTR1,
- .ptr2_reg = MO_DMA28_PTR2,
- .cnt1_reg = MO_DMA28_CNT1,
- .cnt2_reg = MO_DMA28_CNT2,
- },
- [SRAM_CH27] = {
- .name = "audio rds",
- .cmds_start = 0x1801C0,
- .ctrl_start = 0x180860,
- .cdt = 0x180860 + 64,
- .fifo_start = 0x187400,
- .fifo_size = 0x000C00,
- .ptr1_reg = MO_DMA27_PTR1,
- .ptr2_reg = MO_DMA27_PTR2,
- .cnt1_reg = MO_DMA27_CNT1,
- .cnt2_reg = MO_DMA27_CNT2,
- },
-};
-
-int cx88_sram_channel_setup(struct cx88_core *core,
- const struct sram_channel *ch,
- unsigned int bpl, u32 risc)
-{
- unsigned int i,lines;
- u32 cdt;
-
- bpl = (bpl + 7) & ~7; /* alignment */
- cdt = ch->cdt;
- lines = ch->fifo_size / bpl;
- if (lines > 6)
- lines = 6;
- BUG_ON(lines < 2);
-
- /* write CDT */
- for (i = 0; i < lines; i++)
- cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
-
- /* write CMDS */
- cx_write(ch->cmds_start + 0, risc);
- cx_write(ch->cmds_start + 4, cdt);
- cx_write(ch->cmds_start + 8, (lines*16) >> 3);
- cx_write(ch->cmds_start + 12, ch->ctrl_start);
- cx_write(ch->cmds_start + 16, 64 >> 2);
- for (i = 20; i < 64; i += 4)
- cx_write(ch->cmds_start + i, 0);
-
- /* fill registers */
- cx_write(ch->ptr1_reg, ch->fifo_start);
- cx_write(ch->ptr2_reg, cdt);
- cx_write(ch->cnt1_reg, (bpl >> 3) -1);
- cx_write(ch->cnt2_reg, (lines*16) >> 3);
-
- dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-/* debug helper code */
-
-static int cx88_risc_decode(u32 risc)
-{
- static const char * const instr[16] = {
- [ RISC_SYNC >> 28 ] = "sync",
- [ RISC_WRITE >> 28 ] = "write",
- [ RISC_WRITEC >> 28 ] = "writec",
- [ RISC_READ >> 28 ] = "read",
- [ RISC_READC >> 28 ] = "readc",
- [ RISC_JUMP >> 28 ] = "jump",
- [ RISC_SKIP >> 28 ] = "skip",
- [ RISC_WRITERM >> 28 ] = "writerm",
- [ RISC_WRITECM >> 28 ] = "writecm",
- [ RISC_WRITECR >> 28 ] = "writecr",
- };
- static int const incr[16] = {
- [ RISC_WRITE >> 28 ] = 2,
- [ RISC_JUMP >> 28 ] = 2,
- [ RISC_WRITERM >> 28 ] = 3,
- [ RISC_WRITECM >> 28 ] = 3,
- [ RISC_WRITECR >> 28 ] = 4,
- };
- static const char * const bits[] = {
- "12", "13", "14", "resync",
- "cnt0", "cnt1", "18", "19",
- "20", "21", "22", "23",
- "irq1", "irq2", "eol", "sol",
- };
- int i;
-
- printk("0x%08x [ %s", risc,
- instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
- for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
- if (risc & (1 << (i + 12)))
- printk(" %s",bits[i]);
- printk(" count=%d ]\n", risc & 0xfff);
- return incr[risc >> 28] ? incr[risc >> 28] : 1;
-}
-
-
-void cx88_sram_channel_dump(struct cx88_core *core,
- const struct sram_channel *ch)
-{
- static const char * const name[] = {
- "initial risc",
- "cdt base",
- "cdt size",
- "iq base",
- "iq size",
- "risc pc",
- "iq wr ptr",
- "iq rd ptr",
- "cdt current",
- "pci target",
- "line / byte",
- };
- u32 risc;
- unsigned int i,j,n;
-
- printk("%s: %s - dma channel status dump\n",
- core->name,ch->name);
- for (i = 0; i < ARRAY_SIZE(name); i++)
- printk("%s: cmds: %-12s: 0x%08x\n",
- core->name,name[i],
- cx_read(ch->cmds_start + 4*i));
- for (n = 1, i = 0; i < 4; i++) {
- risc = cx_read(ch->cmds_start + 4 * (i+11));
- printk("%s: risc%d: ", core->name, i);
- if (--n)
- printk("0x%08x [ arg #%d ]\n", risc, n);
- else
- n = cx88_risc_decode(risc);
- }
- for (i = 0; i < 16; i += n) {
- risc = cx_read(ch->ctrl_start + 4 * i);
- printk("%s: iq %x: ", core->name, i);
- n = cx88_risc_decode(risc);
- for (j = 1; j < n; j++) {
- risc = cx_read(ch->ctrl_start + 4 * (i+j));
- printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
- core->name, i+j, risc, j);
- }
- }
-
- printk("%s: fifo: 0x%08x -> 0x%x\n",
- core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
- printk("%s: ctrl: 0x%08x -> 0x%x\n",
- core->name, ch->ctrl_start, ch->ctrl_start+6*16);
- printk("%s: ptr1_reg: 0x%08x\n",
- core->name,cx_read(ch->ptr1_reg));
- printk("%s: ptr2_reg: 0x%08x\n",
- core->name,cx_read(ch->ptr2_reg));
- printk("%s: cnt1_reg: 0x%08x\n",
- core->name,cx_read(ch->cnt1_reg));
- printk("%s: cnt2_reg: 0x%08x\n",
- core->name,cx_read(ch->cnt2_reg));
-}
-
-static const char *cx88_pci_irqs[32] = {
- "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
- "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
- "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
- "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
-};
-
-void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
- int len, u32 bits, u32 mask)
-{
- unsigned int i;
-
- printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
- for (i = 0; i < len; i++) {
- if (!(bits & (1 << i)))
- continue;
- if (strings[i])
- printk(" %s", strings[i]);
- else
- printk(" %d", i);
- if (!(mask & (1 << i)))
- continue;
- printk("*");
- }
- printk("\n");
-}
-
-/* ------------------------------------------------------------------ */
-
-int cx88_core_irq(struct cx88_core *core, u32 status)
-{
- int handled = 0;
-
- if (status & PCI_INT_IR_SMPINT) {
- cx88_ir_irq(core);
- handled++;
- }
- if (!handled)
- cx88_print_irqbits(core->name, "irq pci",
- cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
- status, core->pci_irqmask);
- return handled;
-}
-
-void cx88_wakeup(struct cx88_core *core,
- struct cx88_dmaqueue *q, u32 count)
-{
- struct cx88_buffer *buf;
- int bc;
-
- for (bc = 0;; bc++) {
- if (list_empty(&q->active))
- break;
- buf = list_entry(q->active.next,
- struct cx88_buffer, vb.queue);
- /* count comes from the hw and is is 16bit wide --
- * this trick handles wrap-arounds correctly for
- * up to 32767 buffers in flight... */
- if ((s16) (count - buf->count) < 0)
- break;
- do_gettimeofday(&buf->vb.ts);
- dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
- count, buf->count);
- buf->vb.state = VIDEOBUF_DONE;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- }
- if (list_empty(&q->active)) {
- del_timer(&q->timeout);
- } else {
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- }
- if (bc != 1)
- dprintk(2, "%s: %d buffers handled (should be 1)\n",
- __func__, bc);
-}
-
-void cx88_shutdown(struct cx88_core *core)
-{
- /* disable RISC controller + IRQs */
- cx_write(MO_DEV_CNTRL2, 0);
-
- /* stop dma transfers */
- cx_write(MO_VID_DMACNTRL, 0x0);
- cx_write(MO_AUD_DMACNTRL, 0x0);
- cx_write(MO_TS_DMACNTRL, 0x0);
- cx_write(MO_VIP_DMACNTRL, 0x0);
- cx_write(MO_GPHST_DMACNTRL, 0x0);
-
- /* stop interrupts */
- cx_write(MO_PCI_INTMSK, 0x0);
- cx_write(MO_VID_INTMSK, 0x0);
- cx_write(MO_AUD_INTMSK, 0x0);
- cx_write(MO_TS_INTMSK, 0x0);
- cx_write(MO_VIP_INTMSK, 0x0);
- cx_write(MO_GPHST_INTMSK, 0x0);
-
- /* stop capturing */
- cx_write(VID_CAPTURE_CONTROL, 0);
-}
-
-int cx88_reset(struct cx88_core *core)
-{
- dprintk(1,"%s\n",__func__);
- cx88_shutdown(core);
-
- /* clear irq status */
- cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
- cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
- cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
-
- /* wait a bit */
- msleep(100);
-
- /* init sram */
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0);
-
- /* misc init ... */
- cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
- (1 << 12) | // agc gain
- (1 << 11) | // adaptibe agc
- (0 << 10) | // chroma agc
- (0 << 9) | // ckillen
- (7)));
-
- /* setup image format */
- cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
-
- /* setup FIFO Thresholds */
- cx_write(MO_PDMA_STHRSH, 0x0807);
- cx_write(MO_PDMA_DTHRSH, 0x0807);
-
- /* fixes flashing of image */
- cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
- cx_write(MO_AGC_BACK_VBI, 0x00E00555);
-
- cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
- cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
- cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
-
- /* Reset on-board parts */
- cx_write(MO_SRST_IO, 0);
- msleep(10);
- cx_write(MO_SRST_IO, 1);
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static unsigned int inline norm_swidth(v4l2_std_id norm)
-{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
-}
-
-static unsigned int inline norm_hdelay(v4l2_std_id norm)
-{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
-}
-
-static unsigned int inline norm_vdelay(v4l2_std_id norm)
-{
- return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
-}
-
-static unsigned int inline norm_fsc8(v4l2_std_id norm)
-{
- if (norm & V4L2_STD_PAL_M)
- return 28604892; // 3.575611 MHz
-
- if (norm & (V4L2_STD_PAL_Nc))
- return 28656448; // 3.582056 MHz
-
- if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
- return 28636360; // 3.57954545 MHz +/- 10 Hz
-
- /* SECAM have also different sub carrier for chroma,
- but step_db and step_dr, at cx88_set_tvnorm already handles that.
-
- The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
- */
-
- return 35468950; // 4.43361875 MHz +/- 5 Hz
-}
-
-static unsigned int inline norm_htotal(v4l2_std_id norm)
-{
-
- unsigned int fsc4=norm_fsc8(norm)/2;
-
- /* returns 4*FSC / vtotal / frames per seconds */
- return (norm & V4L2_STD_625_50) ?
- ((fsc4+312)/625+12)/25 :
- ((fsc4+262)/525*1001+15000)/30000;
-}
-
-static unsigned int inline norm_vbipack(v4l2_std_id norm)
-{
- return (norm & V4L2_STD_625_50) ? 511 : 400;
-}
-
-int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
- enum v4l2_field field)
-{
- unsigned int swidth = norm_swidth(core->tvnorm);
- unsigned int sheight = norm_maxh(core->tvnorm);
- u32 value;
-
- dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
- V4L2_FIELD_HAS_TOP(field) ? "T" : "",
- V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- v4l2_norm_to_name(core->tvnorm));
- if (!V4L2_FIELD_HAS_BOTH(field))
- height *= 2;
-
- // recalc H delay and scale registers
- value = (width * norm_hdelay(core->tvnorm)) / swidth;
- value &= 0x3fe;
- cx_write(MO_HDELAY_EVEN, value);
- cx_write(MO_HDELAY_ODD, value);
- dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
-
- value = (swidth * 4096 / width) - 4096;
- cx_write(MO_HSCALE_EVEN, value);
- cx_write(MO_HSCALE_ODD, value);
- dprintk(1,"set_scale: hscale 0x%04x\n", value);
-
- cx_write(MO_HACTIVE_EVEN, width);
- cx_write(MO_HACTIVE_ODD, width);
- dprintk(1,"set_scale: hactive 0x%04x\n", width);
-
- // recalc V scale Register (delay is constant)
- cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
- cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
- dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
-
- value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
- cx_write(MO_VSCALE_EVEN, value);
- cx_write(MO_VSCALE_ODD, value);
- dprintk(1,"set_scale: vscale 0x%04x\n", value);
-
- cx_write(MO_VACTIVE_EVEN, sheight);
- cx_write(MO_VACTIVE_ODD, sheight);
- dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
-
- // setup filters
- value = 0;
- value |= (1 << 19); // CFILT (default)
- if (core->tvnorm & V4L2_STD_SECAM) {
- value |= (1 << 15);
- value |= (1 << 16);
- }
- if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
- value |= (1 << 13) | (1 << 5);
- if (V4L2_FIELD_INTERLACED == field)
- value |= (1 << 3); // VINT (interlaced vertical scaling)
- if (width < 385)
- value |= (1 << 0); // 3-tap interpolation
- if (width < 193)
- value |= (1 << 1); // 5-tap interpolation
- if (nocomb)
- value |= (3 << 5); // disable comb filter
-
- cx_andor(MO_FILTER_EVEN, 0x7ffc7f, value); /* preserve PEAKEN, PSEL */
- cx_andor(MO_FILTER_ODD, 0x7ffc7f, value);
- dprintk(1,"set_scale: filter 0x%04x\n", value);
-
- return 0;
-}
-
-static const u32 xtal = 28636363;
-
-static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
-{
- static const u32 pre[] = { 0, 0, 0, 3, 2, 1 };
- u64 pll;
- u32 reg;
- int i;
-
- if (prescale < 2)
- prescale = 2;
- if (prescale > 5)
- prescale = 5;
-
- pll = ofreq * 8 * prescale * (u64)(1 << 20);
- do_div(pll,xtal);
- reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
- if (((reg >> 20) & 0x3f) < 14) {
- printk("%s/0: pll out of range\n",core->name);
- return -1;
- }
-
- dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
- reg, cx_read(MO_PLL_REG), ofreq);
- cx_write(MO_PLL_REG, reg);
- for (i = 0; i < 100; i++) {
- reg = cx_read(MO_DEVICE_STATUS);
- if (reg & (1<<2)) {
- dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
- prescale,ofreq);
- return 0;
- }
- dprintk(1,"pll not locked yet, waiting ...\n");
- msleep(10);
- }
- dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
- return -1;
-}
-
-int cx88_start_audio_dma(struct cx88_core *core)
-{
- /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
- int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
-
- int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES;
-
- /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
- if (cx_read(MO_AUD_DMACNTRL) & 0x10)
- return 0;
-
- /* setup fifo + format */
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
- cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27],
- rds_bpl, 0);
-
- cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
- cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */
-
- /* enable Up, Down and Audio RDS fifo */
- cx_write(MO_AUD_DMACNTRL, 0x0007);
-
- return 0;
-}
-
-int cx88_stop_audio_dma(struct cx88_core *core)
-{
- /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
- if (cx_read(MO_AUD_DMACNTRL) & 0x10)
- return 0;
-
- /* stop dma */
- cx_write(MO_AUD_DMACNTRL, 0x0000);
-
- return 0;
-}
-
-static int set_tvaudio(struct cx88_core *core)
-{
- v4l2_std_id norm = core->tvnorm;
-
- if (CX88_VMUX_TELEVISION != INPUT(core->input).type &&
- CX88_VMUX_CABLE != INPUT(core->input).type)
- return 0;
-
- if (V4L2_STD_PAL_BG & norm) {
- core->tvaudio = WW_BG;
-
- } else if (V4L2_STD_PAL_DK & norm) {
- core->tvaudio = WW_DK;
-
- } else if (V4L2_STD_PAL_I & norm) {
- core->tvaudio = WW_I;
-
- } else if (V4L2_STD_SECAM_L & norm) {
- core->tvaudio = WW_L;
-
- } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) {
- core->tvaudio = WW_BG;
-
- } else if (V4L2_STD_SECAM_DK & norm) {
- core->tvaudio = WW_DK;
-
- } else if ((V4L2_STD_NTSC_M & norm) ||
- (V4L2_STD_PAL_M & norm)) {
- core->tvaudio = WW_BTSC;
-
- } else if (V4L2_STD_NTSC_M_JP & norm) {
- core->tvaudio = WW_EIAJ;
-
- } else {
- printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
- core->name, v4l2_norm_to_name(core->tvnorm));
- core->tvaudio = WW_NONE;
- return 0;
- }
-
- cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
- cx88_set_tvaudio(core);
- /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
-
-/*
- This should be needed only on cx88-alsa. It seems that some cx88 chips have
- bugs and does require DMA enabled for it to work.
- */
- cx88_start_audio_dma(core);
- return 0;
-}
-
-
-
-int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
-{
- u32 fsc8;
- u32 adc_clock;
- u32 vdec_clock;
- u32 step_db,step_dr;
- u64 tmp64;
- u32 bdelay,agcdelay,htotal;
- u32 cxiformat, cxoformat;
-
- core->tvnorm = norm;
- fsc8 = norm_fsc8(norm);
- adc_clock = xtal;
- vdec_clock = fsc8;
- step_db = fsc8;
- step_dr = fsc8;
-
- if (norm & V4L2_STD_NTSC_M_JP) {
- cxiformat = VideoFormatNTSCJapan;
- cxoformat = 0x181f0008;
- } else if (norm & V4L2_STD_NTSC_443) {
- cxiformat = VideoFormatNTSC443;
- cxoformat = 0x181f0008;
- } else if (norm & V4L2_STD_PAL_M) {
- cxiformat = VideoFormatPALM;
- cxoformat = 0x1c1f0008;
- } else if (norm & V4L2_STD_PAL_N) {
- cxiformat = VideoFormatPALN;
- cxoformat = 0x1c1f0008;
- } else if (norm & V4L2_STD_PAL_Nc) {
- cxiformat = VideoFormatPALNC;
- cxoformat = 0x1c1f0008;
- } else if (norm & V4L2_STD_PAL_60) {
- cxiformat = VideoFormatPAL60;
- cxoformat = 0x181f0008;
- } else if (norm & V4L2_STD_NTSC) {
- cxiformat = VideoFormatNTSC;
- cxoformat = 0x181f0008;
- } else if (norm & V4L2_STD_SECAM) {
- step_db = 4250000 * 8;
- step_dr = 4406250 * 8;
-
- cxiformat = VideoFormatSECAM;
- cxoformat = 0x181f0008;
- } else { /* PAL */
- cxiformat = VideoFormatPAL;
- cxoformat = 0x181f0008;
- }
-
- dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
- v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
- step_db, step_dr);
- set_pll(core,2,vdec_clock);
-
- dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- /* Chroma AGC must be disabled if SECAM is used, we enable it
- by default on PAL and NTSC */
- cx_andor(MO_INPUT_FORMAT, 0x40f,
- norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);
-
- // FIXME: as-is from DScaler
- dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, cxoformat);
-
- // MO_SCONV_REG = adc clock / video dec clock * 2^17
- tmp64 = adc_clock * (u64)(1 << 17);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SCONV_REG));
- cx_write(MO_SCONV_REG, (u32)tmp64);
-
- // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
- tmp64 = step_db * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP));
- cx_write(MO_SUB_STEP, (u32)tmp64);
-
- // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
- tmp64 = step_dr * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP_DR));
- cx_write(MO_SUB_STEP_DR, (u32)tmp64);
-
- // bdelay + agcdelay
- bdelay = vdec_clock * 65 / 20000000 + 21;
- agcdelay = vdec_clock * 68 / 20000000 + 15;
- dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
- (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
- cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
-
- // htotal
- tmp64 = norm_htotal(norm) * (u64)vdec_clock;
- do_div(tmp64, fsc8);
- htotal = (u32)tmp64;
- dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
- htotal, cx_read(MO_HTOTAL), (u32)tmp64);
- cx_andor(MO_HTOTAL, 0x07ff, htotal);
-
- // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
- // the effective vbi offset ~244 samples, the same as the Bt8x8
- cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
-
- // this is needed as well to set all tvnorm parameter
- cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
-
- // audio
- set_tvaudio(core);
-
- // tell i2c chips
- call_all(core, core, s_std, norm);
-
- /* The chroma_agc control should be inaccessible if the video format is SECAM */
- v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM);
-
- // done
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-struct video_device *cx88_vdev_init(struct cx88_core *core,
- struct pci_dev *pci,
- const struct video_device *template_,
- const char *type)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template_;
- vfd->v4l2_dev = &core->v4l2_dev;
- vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- core->name, type, core->board.name);
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
- return vfd;
-}
-
-struct cx88_core* cx88_core_get(struct pci_dev *pci)
-{
- struct cx88_core *core;
-
- mutex_lock(&devlist);
- list_for_each_entry(core, &cx88_devlist, devlist) {
- if (pci->bus->number != core->pci_bus)
- continue;
- if (PCI_SLOT(pci->devfn) != core->pci_slot)
- continue;
-
- if (0 != cx88_get_resources(core, pci)) {
- mutex_unlock(&devlist);
- return NULL;
- }
- atomic_inc(&core->refcount);
- mutex_unlock(&devlist);
- return core;
- }
-
- core = cx88_core_create(pci, cx88_devcount);
- if (NULL != core) {
- cx88_devcount++;
- list_add_tail(&core->devlist, &cx88_devlist);
- }
-
- mutex_unlock(&devlist);
- return core;
-}
-
-void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
-{
- release_mem_region(pci_resource_start(pci,0),
- pci_resource_len(pci,0));
-
- if (!atomic_dec_and_test(&core->refcount))
- return;
-
- mutex_lock(&devlist);
- cx88_ir_fini(core);
- if (0 == core->i2c_rc) {
- if (core->i2c_rtc)
- i2c_unregister_device(core->i2c_rtc);
- i2c_del_adapter(&core->i2c_adap);
- }
- list_del(&core->devlist);
- iounmap(core->lmmio);
- cx88_devcount--;
- mutex_unlock(&devlist);
- v4l2_ctrl_handler_free(&core->video_hdl);
- v4l2_ctrl_handler_free(&core->audio_hdl);
- v4l2_device_unregister(&core->v4l2_dev);
- kfree(core);
-}
-
-/* ------------------------------------------------------------------ */
-
-EXPORT_SYMBOL(cx88_print_irqbits);
-
-EXPORT_SYMBOL(cx88_core_irq);
-EXPORT_SYMBOL(cx88_wakeup);
-EXPORT_SYMBOL(cx88_reset);
-EXPORT_SYMBOL(cx88_shutdown);
-
-EXPORT_SYMBOL(cx88_risc_buffer);
-EXPORT_SYMBOL(cx88_risc_databuffer);
-EXPORT_SYMBOL(cx88_risc_stopper);
-EXPORT_SYMBOL(cx88_free_buffer);
-
-EXPORT_SYMBOL(cx88_sram_channels);
-EXPORT_SYMBOL(cx88_sram_channel_setup);
-EXPORT_SYMBOL(cx88_sram_channel_dump);
-
-EXPORT_SYMBOL(cx88_set_tvnorm);
-EXPORT_SYMBOL(cx88_set_scale);
-
-EXPORT_SYMBOL(cx88_vdev_init);
-EXPORT_SYMBOL(cx88_core_get);
-EXPORT_SYMBOL(cx88_core_put);
-
-EXPORT_SYMBOL(cx88_ir_start);
-EXPORT_SYMBOL(cx88_ir_stop);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
deleted file mode 100644
index 003937cd72f5..000000000000
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ /dev/null
@@ -1,1778 +0,0 @@
-/*
- *
- * device driver for Conexant 2388x based TV cards
- * MPEG Transport Stream (DVB) routines
- *
- * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/kthread.h>
-#include <linux/file.h>
-#include <linux/suspend.h>
-
-#include "cx88.h"
-#include "dvb-pll.h"
-#include <media/v4l2-common.h>
-
-#include "mt352.h"
-#include "mt352_priv.h"
-#include "cx88-vp3054-i2c.h"
-#include "zl10353.h"
-#include "cx22702.h"
-#include "or51132.h"
-#include "lgdt330x.h"
-#include "s5h1409.h"
-#include "xc4000.h"
-#include "xc5000.h"
-#include "nxt200x.h"
-#include "cx24123.h"
-#include "isl6421.h"
-#include "tuner-simple.h"
-#include "tda9887.h"
-#include "s5h1411.h"
-#include "stv0299.h"
-#include "z0194a.h"
-#include "stv0288.h"
-#include "stb6000.h"
-#include "cx24116.h"
-#include "stv0900.h"
-#include "stb6100.h"
-#include "stb6100_proc.h"
-#include "mb86a16.h"
-#include "ds3000.h"
-
-MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
-MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(CX88_VERSION);
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
-
-static unsigned int dvb_buf_tscnt = 32;
-module_param(dvb_buf_tscnt, int, 0644);
-MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(level,fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
-
-/* ------------------------------------------------------------------ */
-
-static int dvb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
-{
- struct cx8802_dev *dev = q->priv_data;
-
- dev->ts_packet_size = 188 * 4;
- dev->ts_packet_count = dvb_buf_tscnt;
-
- *size = dev->ts_packet_size * dev->ts_packet_count;
- *count = dvb_buf_tscnt;
- return 0;
-}
-
-static int dvb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct cx8802_dev *dev = q->priv_data;
- return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
-}
-
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
- struct cx8802_dev *dev = q->priv_data;
- cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
-}
-
-static void dvb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- cx88_free_buffer(q, (struct cx88_buffer*)vb);
-}
-
-static const struct videobuf_queue_ops dvb_qops = {
- .buf_setup = dvb_buf_setup,
- .buf_prepare = dvb_buf_prepare,
- .buf_queue = dvb_buf_queue,
- .buf_release = dvb_buf_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx8802_driver *drv = NULL;
- int ret = 0;
- int fe_id;
-
- fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
- if (!fe_id) {
- printk(KERN_ERR "%s() No frontend found\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&dev->core->lock);
- drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
- if (drv) {
- if (acquire){
- dev->frontends.active_fe_id = fe_id;
- ret = drv->request_acquire(drv);
- } else {
- ret = drv->request_release(drv);
- dev->frontends.active_fe_id = 0;
- }
- }
- mutex_unlock(&dev->core->lock);
-
- return ret;
-}
-
-static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
-{
- struct videobuf_dvb_frontends *f;
- struct videobuf_dvb_frontend *fe;
-
- if (!core->dvbdev)
- return;
-
- f = &core->dvbdev->frontends;
-
- if (!f)
- return;
-
- if (f->gate <= 1) /* undefined or fe0 */
- fe = videobuf_dvb_get_frontend(f, 1);
- else
- fe = videobuf_dvb_get_frontend(f, f->gate);
-
- if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
- fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
-}
-
-/* ------------------------------------------------------------------ */
-
-static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
-{
- static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
- static const u8 reset [] = { RESET, 0x80 };
- static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
- static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
- static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
-
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
- return 0;
-}
-
-static int dvico_dual_demod_init(struct dvb_frontend *fe)
-{
- static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
- static const u8 reset [] = { RESET, 0x80 };
- static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
- static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
- static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
-
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
- return 0;
-}
-
-static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
-{
- static const u8 clock_config [] = { 0x89, 0x38, 0x39 };
- static const u8 reset [] = { 0x50, 0x80 };
- static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
- 0x00, 0xFF, 0x00, 0x40, 0x40 };
- static const u8 dntv_extra[] = { 0xB5, 0x7A };
- static const u8 capt_range_cfg[] = { 0x75, 0x32 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(2000);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
-
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- udelay(2000);
- mt352_write(fe, dntv_extra, sizeof(dntv_extra));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
- return 0;
-}
-
-static const struct mt352_config dvico_fusionhdtv = {
- .demod_address = 0x0f,
- .demod_init = dvico_fusionhdtv_demod_init,
-};
-
-static const struct mt352_config dntv_live_dvbt_config = {
- .demod_address = 0x0f,
- .demod_init = dntv_live_dvbt_demod_init,
-};
-
-static const struct mt352_config dvico_fusionhdtv_dual = {
- .demod_address = 0x0f,
- .demod_init = dvico_dual_demod_init,
-};
-
-static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .if2 = 45600,
-};
-
-static struct mb86a16_config twinhan_vp1027 = {
- .demod_address = 0x08,
-};
-
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
-static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
-{
- static const u8 clock_config [] = { 0x89, 0x38, 0x38 };
- static const u8 reset [] = { 0x50, 0x80 };
- static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
- 0x00, 0xFF, 0x00, 0x40, 0x40 };
- static const u8 dntv_extra[] = { 0xB5, 0x7A };
- static const u8 capt_range_cfg[] = { 0x75, 0x32 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(2000);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
-
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- udelay(2000);
- mt352_write(fe, dntv_extra, sizeof(dntv_extra));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
- return 0;
-}
-
-static const struct mt352_config dntv_live_dvbt_pro_config = {
- .demod_address = 0x0f,
- .no_tuner = 1,
- .demod_init = dntv_live_dvbt_pro_demod_init,
-};
-#endif
-
-static const struct zl10353_config dvico_fusionhdtv_hybrid = {
- .demod_address = 0x0f,
- .no_tuner = 1,
-};
-
-static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
- .demod_address = 0x0f,
- .if2 = 45600,
- .no_tuner = 1,
-};
-
-static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
- .demod_address = 0x0f,
- .if2 = 4560,
- .no_tuner = 1,
- .demod_init = dvico_fusionhdtv_demod_init,
-};
-
-static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
- .demod_address = 0x0f,
-};
-
-static const struct cx22702_config connexant_refboard_config = {
- .demod_address = 0x43,
- .output_mode = CX22702_SERIAL_OUTPUT,
-};
-
-static const struct cx22702_config hauppauge_hvr_config = {
- .demod_address = 0x63,
- .output_mode = CX22702_SERIAL_OUTPUT,
-};
-
-static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
- return 0;
-}
-
-static const struct or51132_config pchdtv_hd3000 = {
- .demod_address = 0x15,
- .set_ts_params = or51132_set_ts_param,
-};
-
-static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- dprintk(1, "%s: index = %d\n", __func__, index);
- if (index == 0)
- cx_clear(MO_GP0_IO, 8);
- else
- cx_set(MO_GP0_IO, 8);
- return 0;
-}
-
-static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- if (is_punctured)
- dev->ts_gen_cntrl |= 0x04;
- else
- dev->ts_gen_cntrl &= ~0x04;
- return 0;
-}
-
-static struct lgdt330x_config fusionhdtv_3_gold = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3302,
- .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
-};
-
-static const struct lgdt330x_config fusionhdtv_5_gold = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
-};
-
-static const struct lgdt330x_config pchdtv_hd5500 = {
- .demod_address = 0x59,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
-};
-
-static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
- return 0;
-}
-
-static const struct nxt200x_config ati_hdtvwonder = {
- .demod_address = 0x0a,
- .set_ts_params = nxt200x_set_ts_param,
-};
-
-static int cx24123_set_ts_param(struct dvb_frontend* fe,
- int is_punctured)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- dev->ts_gen_cntrl = 0x02;
- return 0;
-}
-
-static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
- fe_sec_voltage_t voltage)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- if (voltage == SEC_VOLTAGE_OFF)
- cx_write(MO_GP0_IO, 0x000006fb);
- else
- cx_write(MO_GP0_IO, 0x000006f9);
-
- if (core->prev_set_voltage)
- return core->prev_set_voltage(fe, voltage);
- return 0;
-}
-
-static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
- fe_sec_voltage_t voltage)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- if (voltage == SEC_VOLTAGE_OFF) {
- dprintk(1,"LNB Voltage OFF\n");
- cx_write(MO_GP0_IO, 0x0000efff);
- }
-
- if (core->prev_set_voltage)
- return core->prev_set_voltage(fe, voltage);
- return 0;
-}
-
-static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
- fe_sec_voltage_t voltage)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- cx_set(MO_GP0_IO, 0x6040);
- switch (voltage) {
- case SEC_VOLTAGE_13:
- cx_clear(MO_GP0_IO, 0x20);
- break;
- case SEC_VOLTAGE_18:
- cx_set(MO_GP0_IO, 0x20);
- break;
- case SEC_VOLTAGE_OFF:
- cx_clear(MO_GP0_IO, 0x20);
- break;
- }
-
- if (core->prev_set_voltage)
- return core->prev_set_voltage(fe, voltage);
- return 0;
-}
-
-static int vp1027_set_voltage(struct dvb_frontend *fe,
- fe_sec_voltage_t voltage)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk(1, "LNB SEC Voltage=13\n");
- cx_write(MO_GP0_IO, 0x00001220);
- break;
- case SEC_VOLTAGE_18:
- dprintk(1, "LNB SEC Voltage=18\n");
- cx_write(MO_GP0_IO, 0x00001222);
- break;
- case SEC_VOLTAGE_OFF:
- dprintk(1, "LNB Voltage OFF\n");
- cx_write(MO_GP0_IO, 0x00001230);
- break;
- }
-
- if (core->prev_set_voltage)
- return core->prev_set_voltage(fe, voltage);
- return 0;
-}
-
-static const struct cx24123_config geniatech_dvbs_config = {
- .demod_address = 0x55,
- .set_ts_params = cx24123_set_ts_param,
-};
-
-static const struct cx24123_config hauppauge_novas_config = {
- .demod_address = 0x55,
- .set_ts_params = cx24123_set_ts_param,
-};
-
-static const struct cx24123_config kworld_dvbs_100_config = {
- .demod_address = 0x15,
- .set_ts_params = cx24123_set_ts_param,
- .lnb_polarity = 1,
-};
-
-static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_PARALLEL_OUTPUT,
- .gpio = S5H1409_GPIO_ON,
- .qam_if = 44000,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
-};
-
-static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static const struct s5h1409_config kworld_atsc_120_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_SERIAL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .inversion = S5H1409_INVERSION_OFF,
- .status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-};
-
-static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
- .i2c_address = 0x64,
- .if_khz = 5380,
-};
-
-static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .if2 = 45600,
-};
-
-static const struct zl10353_config cx88_geniatech_x8000_mt = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .disable_i2c_gate_ctrl = 1,
-};
-
-static const struct s5h1411_config dvico_fusionhdtv7_config = {
- .output_mode = S5H1411_SERIAL_OUTPUT,
- .gpio = S5H1411_GPIO_ON,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
- .qam_if = S5H1411_IF_44000,
- .vsb_if = S5H1411_IF_44000,
- .inversion = S5H1411_INVERSION_OFF,
- .status_mode = S5H1411_DEMODLOCKING
-};
-
-static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
- .i2c_address = 0xc2 >> 1,
- .if_khz = 5380,
-};
-
-static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
-{
- struct dvb_frontend *fe;
- struct videobuf_dvb_frontend *fe0 = NULL;
- struct xc2028_ctrl ctl;
- struct xc2028_config cfg = {
- .i2c_adap = &dev->core->i2c_adap,
- .i2c_addr = addr,
- .ctrl = &ctl,
- };
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
- if (!fe0)
- return -EINVAL;
-
- if (!fe0->dvb.frontend) {
- printk(KERN_ERR "%s/2: dvb frontend not attached. "
- "Can't attach xc3028\n",
- dev->core->name);
- return -EINVAL;
- }
-
- /*
- * Some xc3028 devices may be hidden by an I2C gate. This is known
- * to happen with some s5h1409-based devices.
- * Now that I2C gate is open, sets up xc3028 configuration
- */
- cx88_setup_xc3028(dev->core, &ctl);
-
- fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
- if (!fe) {
- printk(KERN_ERR "%s/2: xc3028 attach failed\n",
- dev->core->name);
- dvb_frontend_detach(fe0->dvb.frontend);
- dvb_unregister_frontend(fe0->dvb.frontend);
- fe0->dvb.frontend = NULL;
- return -EINVAL;
- }
-
- printk(KERN_INFO "%s/2: xc3028 attached\n",
- dev->core->name);
-
- return 0;
-}
-
-static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
-{
- struct dvb_frontend *fe;
- struct videobuf_dvb_frontend *fe0 = NULL;
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
- if (!fe0)
- return -EINVAL;
-
- if (!fe0->dvb.frontend) {
- printk(KERN_ERR "%s/2: dvb frontend not attached. "
- "Can't attach xc4000\n",
- dev->core->name);
- return -EINVAL;
- }
-
- fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
- cfg);
- if (!fe) {
- printk(KERN_ERR "%s/2: xc4000 attach failed\n",
- dev->core->name);
- dvb_frontend_detach(fe0->dvb.frontend);
- dvb_unregister_frontend(fe0->dvb.frontend);
- fe0->dvb.frontend = NULL;
- return -EINVAL;
- }
-
- printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name);
-
- return 0;
-}
-
-static int cx24116_set_ts_param(struct dvb_frontend *fe,
- int is_punctured)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- dev->ts_gen_cntrl = 0x2;
-
- return 0;
-}
-
-static int stv0900_set_ts_param(struct dvb_frontend *fe,
- int is_punctured)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- dev->ts_gen_cntrl = 0;
-
- return 0;
-}
-
-static int cx24116_reset_device(struct dvb_frontend *fe)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- /* Reset the part */
- /* Put the cx24116 into reset */
- cx_write(MO_SRST_IO, 0);
- msleep(10);
- /* Take the cx24116 out of reset */
- cx_write(MO_SRST_IO, 1);
- msleep(10);
-
- return 0;
-}
-
-static const struct cx24116_config hauppauge_hvr4000_config = {
- .demod_address = 0x05,
- .set_ts_params = cx24116_set_ts_param,
- .reset_device = cx24116_reset_device,
-};
-
-static const struct cx24116_config tevii_s460_config = {
- .demod_address = 0x55,
- .set_ts_params = cx24116_set_ts_param,
- .reset_device = cx24116_reset_device,
-};
-
-static int ds3000_set_ts_param(struct dvb_frontend *fe,
- int is_punctured)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- dev->ts_gen_cntrl = 4;
-
- return 0;
-}
-
-static struct ds3000_config tevii_ds3000_config = {
- .demod_address = 0x68,
- .set_ts_params = ds3000_set_ts_param,
-};
-
-static const struct stv0900_config prof_7301_stv0900_config = {
- .demod_address = 0x6a,
-/* demod_mode = 0,*/
- .xtal = 27000000,
- .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
- .diseqc_mode = 2,/* 2/3 PWM */
- .tun1_maddress = 0,/* 0x60 */
- .tun1_adc = 0,/* 2 Vpp */
- .path1_mode = 3,
- .set_ts_params = stv0900_set_ts_param,
-};
-
-static const struct stb6100_config prof_7301_stb6100_config = {
- .tuner_address = 0x60,
- .refclock = 27000000,
-};
-
-static const struct stv0299_config tevii_tuner_sharp_config = {
- .demod_address = 0x68,
- .inittab = sharp_z0194a_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = 1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = sharp_z0194a_set_symbol_rate,
- .set_ts_params = cx24116_set_ts_param,
-};
-
-static const struct stv0288_config tevii_tuner_earda_config = {
- .demod_address = 0x68,
- .min_delay_ms = 100,
- .set_ts_params = cx24116_set_ts_param,
-};
-
-static int cx8802_alloc_frontends(struct cx8802_dev *dev)
-{
- struct cx88_core *core = dev->core;
- struct videobuf_dvb_frontend *fe = NULL;
- int i;
-
- mutex_init(&dev->frontends.lock);
- INIT_LIST_HEAD(&dev->frontends.felist);
-
- if (!core->board.num_frontends)
- return -ENODEV;
-
- printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
- core->board.num_frontends);
- for (i = 1; i <= core->board.num_frontends; i++) {
- fe = videobuf_dvb_alloc_frontend(&dev->frontends, i);
- if (!fe) {
- printk(KERN_ERR "%s() failed to alloc\n", __func__);
- videobuf_dvb_dealloc_frontends(&dev->frontends);
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-
-
-static const u8 samsung_smt_7020_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x0F,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0x60,
-
- 0x0A, 0xC2,
- 0x0B, 0x00,
- 0x0C, 0x01,
- 0x0D, 0x81,
- 0x0E, 0x44,
- 0x0F, 0x09,
- 0x10, 0x3C,
- 0x11, 0x84,
- 0x12, 0xDA,
- 0x13, 0x99,
- 0x14, 0x8D,
- 0x15, 0xCE,
- 0x16, 0xE8,
- 0x17, 0x43,
- 0x18, 0x1C,
- 0x19, 0x1B,
- 0x1A, 0x1D,
-
- 0x1C, 0x12,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x00,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
-
- 0x28, 0x02,
- 0x29, 0x28,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
-
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFC,
- 0x34, 0x13,
- 0xff, 0xff,
-};
-
-
-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;
- struct i2c_msg msg = {
- .addr = 0x61,
- .flags = 0,
- .buf = buf,
- .len = sizeof(buf) };
-
- div = c->frequency / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; /* 0xC4 */
- buf[3] = 0x00;
-
- if (c->frequency < 1500000)
- buf[3] |= 0x10;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
-static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
- fe_sec_tone_mode_t tone)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- cx_set(MO_GP0_IO, 0x0800);
-
- switch (tone) {
- case SEC_TONE_ON:
- cx_set(MO_GP0_IO, 0x08);
- break;
- case SEC_TONE_OFF:
- cx_clear(MO_GP0_IO, 0x08);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
- fe_sec_voltage_t voltage)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- u8 data;
- struct i2c_msg msg = {
- .addr = 8,
- .flags = 0,
- .buf = &data,
- .len = sizeof(data) };
-
- cx_set(MO_GP0_IO, 0x8000);
-
- switch (voltage) {
- case SEC_VOLTAGE_OFF:
- break;
- case SEC_VOLTAGE_13:
- data = ISL6421_EN1 | ISL6421_LLC1;
- cx_clear(MO_GP0_IO, 0x80);
- break;
- case SEC_VOLTAGE_18:
- data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
- cx_clear(MO_GP0_IO, 0x80);
- break;
- default:
- return -EINVAL;
- };
-
- return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
- u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) {
- aclk = 0xb7;
- bclk = 0x47;
- } else if (srate < 3000000) {
- aclk = 0xb7;
- bclk = 0x4b;
- } else if (srate < 7000000) {
- aclk = 0xb7;
- bclk = 0x4f;
- } else if (srate < 14000000) {
- aclk = 0xb7;
- bclk = 0x53;
- } else if (srate < 30000000) {
- aclk = 0xb6;
- bclk = 0x53;
- } else if (srate < 45000000) {
- aclk = 0xb4;
- bclk = 0x51;
- }
-
- stv0299_writereg(fe, 0x13, aclk);
- stv0299_writereg(fe, 0x14, bclk);
- stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg(fe, 0x21, ratio & 0xf0);
-
- return 0;
-}
-
-
-static const struct stv0299_config samsung_stv0299_config = {
- .demod_address = 0x68,
- .inittab = samsung_smt_7020_inittab,
- .mclk = 88000000UL,
- .invert = 0,
- .skip_reinit = 0,
- .lock_output = STV0299_LOCKOUTPUT_LK,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
-};
-
-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);
- goto frontend_detach;
- }
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
- if (!fe0)
- goto frontend_detach;
-
- /* multi-frontend gate control is undefined or defaults to fe0 */
- dev->frontends.gate = 0;
-
- /* Sets the gate control callback to be used by i2c command calls */
- core->gate_ctrl = cx88_dvb_gate_ctrl;
-
- /* init frontend(s) */
- switch (core->boardnr) {
- case CX88_BOARD_HAUPPAUGE_DVB_T1:
- fe0->dvb.frontend = dvb_attach(cx22702_attach,
- &connexant_refboard_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x61, &core->i2c_adap,
- DVB_PLL_THOMSON_DTT759X))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
- case CX88_BOARD_CONEXANT_DVB_T1:
- case CX88_BOARD_KWORLD_DVB_T_CX22702:
- case CX88_BOARD_WINFAST_DTV1000:
- fe0->dvb.frontend = dvb_attach(cx22702_attach,
- &connexant_refboard_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x60, &core->i2c_adap,
- DVB_PLL_THOMSON_DTT7579))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_WINFAST_DTV2000H:
- case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1100LP:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
- 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_FMD1216ME_MK3))
- 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;
- dev->frontends.gate = 2;
- /* DVB-S init */
- fe0->dvb.frontend = dvb_attach(cx24123_attach,
- &hauppauge_novas_config,
- &dev->core->i2c_adap);
- if (fe0->dvb.frontend) {
- if (!dvb_attach(isl6421_attach,
- fe0->dvb.frontend,
- &dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
- goto frontend_detach;
- }
- /* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
- if (!fe1)
- goto frontend_detach;
- /* DVB-T init */
- fe1->dvb.frontend = dvb_attach(cx22702_attach,
- &hauppauge_hvr_config,
- &dev->core->i2c_adap);
- if (fe1->dvb.frontend) {
- fe1->dvb.frontend->id = 1;
- if (!dvb_attach(simple_tuner_attach,
- fe1->dvb.frontend,
- &dev->core->i2c_adap,
- 0x61, TUNER_PHILIPS_FMD1216ME_MK3))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &dvico_fusionhdtv,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
- goto frontend_detach;
- break;
- }
- /* ZL10353 replaces MT352 on later cards */
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_plus_v1_1,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
- /* The tin box says DEE1601, but it seems to be DTT7579
- * compatible, with a slightly different MT352 AGC gain. */
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &dvico_fusionhdtv_dual,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
- goto frontend_detach;
- break;
- }
- /* ZL10353 replaces MT352 on later cards */
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_plus_v1_1,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &dvico_fusionhdtv,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x61, NULL, DVB_PLL_LG_Z201))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_KWORLD_DVB_T:
- case CX88_BOARD_DNTV_LIVE_DVB_T:
- case CX88_BOARD_ADSTECH_DVB_T_PCI:
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &dntv_live_dvbt_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
- 0x61, NULL, DVB_PLL_UNKNOWN_1))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
- /* MT352 is on a secondary I2C bus made from some GPIO lines */
- fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
- &dev->vp3054->adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3))
- goto frontend_detach;
- }
-#else
- printk(KERN_ERR "%s/2: built without vp3054 support\n",
- core->name);
-#endif
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_hybrid,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_THOMSON_FE6600))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &dvico_fusionhdtv_xc3028,
- &core->i2c_adap);
- if (fe0->dvb.frontend == NULL)
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &dvico_fusionhdtv_mt352_xc3028,
- &core->i2c_adap);
- /*
- * On this board, the demod provides the I2C bus pullup.
- * We must not permit gate_ctrl to be performed, or
- * the xc3028 cannot communicate on the bus.
- */
- if (fe0->dvb.frontend)
- fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
- if (attach_xc3028(0x61, dev) < 0)
- goto frontend_detach;
- break;
- case CX88_BOARD_PCHDTV_HD3000:
- fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
- dev->ts_gen_cntrl = 0x08;
-
- /* Do a hardware reset of chip before using it. */
- cx_clear(MO_GP0_IO, 1);
- mdelay(100);
- cx_set(MO_GP0_IO, 1);
- mdelay(200);
-
- /* Select RF connector callback */
- fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
- fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
- &fusionhdtv_3_gold,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_MICROTUNE_4042FI5))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
- dev->ts_gen_cntrl = 0x08;
-
- /* Do a hardware reset of chip before using it. */
- cx_clear(MO_GP0_IO, 1);
- mdelay(100);
- cx_set(MO_GP0_IO, 9);
- mdelay(200);
- fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
- &fusionhdtv_3_gold,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
- dev->ts_gen_cntrl = 0x08;
-
- /* Do a hardware reset of chip before using it. */
- cx_clear(MO_GP0_IO, 1);
- mdelay(100);
- cx_set(MO_GP0_IO, 1);
- mdelay(200);
- fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
- &fusionhdtv_5_gold,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF))
- goto frontend_detach;
- if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x43))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_PCHDTV_HD5500:
- dev->ts_gen_cntrl = 0x08;
-
- /* Do a hardware reset of chip before using it. */
- cx_clear(MO_GP0_IO, 1);
- mdelay(100);
- cx_set(MO_GP0_IO, 1);
- mdelay(200);
- fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
- &pchdtv_hd5500,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF))
- goto frontend_detach;
- if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x43))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_ATI_HDTVWONDER:
- fe0->dvb.frontend = dvb_attach(nxt200x_attach,
- &ati_hdtvwonder,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x61,
- TUNER_PHILIPS_TUV1236D))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
- case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
- fe0->dvb.frontend = dvb_attach(cx24123_attach,
- &hauppauge_novas_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_KWORLD_DVBS_100:
- fe0->dvb.frontend = dvb_attach(cx24123_attach,
- &kworld_dvbs_100_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
- }
- break;
- case CX88_BOARD_GENIATECH_DVBS:
- fe0->dvb.frontend = dvb_attach(cx24123_attach,
- &geniatech_dvbs_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
- }
- break;
- case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &pinnacle_pctv_hd_800i_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &core->i2c_adap,
- &pinnacle_pctv_hd_800i_tuner_config))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &dvico_hdtv5_pci_nano_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &core->i2c_adap,
- .i2c_addr = 0x61,
- };
- static struct xc2028_ctrl ctl = {
- .fname = XC2028_DEFAULT_FIRMWARE,
- .max_len = 64,
- .scode_table = XC3028_FE_OREN538,
- };
-
- fe = dvb_attach(xc2028_attach,
- fe0->dvb.frontend, &cfg);
- if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
- fe->ops.tuner_ops.set_config(fe, &ctl);
- }
- break;
- case CX88_BOARD_PINNACLE_HYBRID_PCTV:
- case CX88_BOARD_WINFAST_DTV1800H:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &cx88_pinnacle_hybrid_pctv,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
- if (attach_xc3028(0x61, dev) < 0)
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_WINFAST_DTV1800H_XC4000:
- case CX88_BOARD_WINFAST_DTV2000H_PLUS:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &cx88_pinnacle_hybrid_pctv,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- struct xc4000_config cfg = {
- .i2c_address = 0x61,
- .default_pm = 0,
- .dvb_amplitude = 134,
- .set_smoothedcvbs = 1,
- .if_khz = 4560
- };
- fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
- if (attach_xc4000(dev, &cfg) < 0)
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_GENIATECH_X8000_MT:
- dev->ts_gen_cntrl = 0x00;
-
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &cx88_geniatech_x8000_mt,
- &core->i2c_adap);
- if (attach_xc3028(0x61, dev) < 0)
- goto frontend_detach;
- break;
- case CX88_BOARD_KWORLD_ATSC_120:
- fe0->dvb.frontend = dvb_attach(s5h1409_attach,
- &kworld_atsc_120_config,
- &core->i2c_adap);
- if (attach_xc3028(0x61, dev) < 0)
- goto frontend_detach;
- break;
- case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
- fe0->dvb.frontend = dvb_attach(s5h1411_attach,
- &dvico_fusionhdtv7_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &core->i2c_adap,
- &dvico_fusionhdtv7_tuner_config))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_HAUPPAUGE_HVR4000:
- /* MFE frontend 1 */
- mfe_shared = 1;
- dev->frontends.gate = 2;
- /* DVB-S/S2 Init */
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &hauppauge_hvr4000_config,
- &dev->core->i2c_adap);
- if (fe0->dvb.frontend) {
- if (!dvb_attach(isl6421_attach,
- fe0->dvb.frontend,
- &dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
- goto frontend_detach;
- }
- /* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
- if (!fe1)
- goto frontend_detach;
- /* DVB-T Init */
- fe1->dvb.frontend = dvb_attach(cx22702_attach,
- &hauppauge_hvr_config,
- &dev->core->i2c_adap);
- if (fe1->dvb.frontend) {
- fe1->dvb.frontend->id = 1;
- if (!dvb_attach(simple_tuner_attach,
- fe1->dvb.frontend,
- &dev->core->i2c_adap,
- 0x61, TUNER_PHILIPS_FMD1216ME_MK3))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &hauppauge_hvr4000_config,
- &dev->core->i2c_adap);
- if (fe0->dvb.frontend) {
- if (!dvb_attach(isl6421_attach,
- fe0->dvb.frontend,
- &dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_PROF_6200:
- case CX88_BOARD_TBS_8910:
- case CX88_BOARD_TEVII_S420:
- fe0->dvb.frontend = dvb_attach(stv0299_attach,
- &tevii_tuner_sharp_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
- &core->i2c_adap, DVB_PLL_OPERA1))
- goto frontend_detach;
- core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
-
- } else {
- fe0->dvb.frontend = dvb_attach(stv0288_attach,
- &tevii_tuner_earda_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
- &core->i2c_adap))
- goto frontend_detach;
- core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
- }
- }
- break;
- case CX88_BOARD_TEVII_S460:
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &tevii_s460_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
- break;
- case CX88_BOARD_TEVII_S464:
- fe0->dvb.frontend = dvb_attach(ds3000_attach,
- &tevii_ds3000_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- fe0->dvb.frontend->ops.set_voltage =
- tevii_dvbs_set_voltage;
- break;
- case CX88_BOARD_OMICOM_SS4_PCI:
- case CX88_BOARD_TBS_8920:
- case CX88_BOARD_PROF_7300:
- case CX88_BOARD_SATTRADE_ST4200:
- fe0->dvb.frontend = dvb_attach(cx24116_attach,
- &hauppauge_hvr4000_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
- break;
- case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &cx88_terratec_cinergy_ht_pci_mkii_config,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
- if (attach_xc3028(0x61, dev) < 0)
- goto frontend_detach;
- }
- break;
- case CX88_BOARD_PROF_7301:{
- struct dvb_tuner_ops *tuner_ops = NULL;
-
- fe0->dvb.frontend = dvb_attach(stv0900_attach,
- &prof_7301_stv0900_config,
- &core->i2c_adap, 0);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(stb6100_attach, fe0->dvb.frontend,
- &prof_7301_stb6100_config,
- &core->i2c_adap))
- goto frontend_detach;
-
- tuner_ops = &fe0->dvb.frontend->ops.tuner_ops;
- tuner_ops->set_frequency = stb6100_set_freq;
- tuner_ops->get_frequency = stb6100_get_freq;
- tuner_ops->set_bandwidth = stb6100_set_bandw;
- tuner_ops->get_bandwidth = stb6100_get_bandw;
-
- core->prev_set_voltage =
- fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage =
- tevii_dvbs_set_voltage;
- }
- break;
- }
- case CX88_BOARD_SAMSUNG_SMT_7020:
- dev->ts_gen_cntrl = 0x08;
-
- cx_set(MO_GP0_IO, 0x0101);
-
- cx_clear(MO_GP0_IO, 0x01);
- mdelay(100);
- cx_set(MO_GP0_IO, 0x01);
- mdelay(200);
-
- fe0->dvb.frontend = dvb_attach(stv0299_attach,
- &samsung_stv0299_config,
- &dev->core->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.tuner_ops.set_params =
- samsung_smt_7020_tuner_set_params;
- fe0->dvb.frontend->tuner_priv =
- &dev->core->i2c_adap;
- fe0->dvb.frontend->ops.set_voltage =
- samsung_smt_7020_set_voltage;
- fe0->dvb.frontend->ops.set_tone =
- samsung_smt_7020_set_tone;
- }
-
- break;
- case CX88_BOARD_TWINHAN_VP1027_DVBS:
- dev->ts_gen_cntrl = 0x00;
- fe0->dvb.frontend = dvb_attach(mb86a16_attach,
- &twinhan_vp1027,
- &core->i2c_adap);
- if (fe0->dvb.frontend) {
- core->prev_set_voltage =
- fe0->dvb.frontend->ops.set_voltage;
- fe0->dvb.frontend->ops.set_voltage =
- vp1027_set_voltage;
- }
- break;
-
- default:
- printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
- core->name);
- break;
- }
-
- if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
- printk(KERN_ERR
- "%s/2: frontend initialization failed\n",
- core->name);
- goto frontend_detach;
- }
- /* define general-purpose callback pointer */
- fe0->dvb.frontend->callback = cx88_tuner_callback;
-
- /* Ensure all frontends negotiate bus access */
- fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
- if (fe1)
- fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
-
- /* Put the analog decoder in standby to keep it quiet */
- call_all(core, core, s_power, 0);
-
- /* register everything */
- 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 res;
-}
-
-/* ----------------------------------------------------------- */
-
-/* CX8802 MPEG -> mini driver - We have been given the hardware */
-static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
-{
- struct cx88_core *core = drv->core;
- int err = 0;
- dprintk( 1, "%s\n", __func__);
-
- switch (core->boardnr) {
- case CX88_BOARD_HAUPPAUGE_HVR1300:
- /* We arrive here with either the cx23416 or the cx22702
- * on the bus. Take the bus from the cx23416 and enable the
- * cx22702 demod
- */
- /* Toggle reset on cx22702 leaving i2c active */
- cx_set(MO_GP0_IO, 0x00000080);
- udelay(1000);
- cx_clear(MO_GP0_IO, 0x00000080);
- udelay(50);
- cx_set(MO_GP0_IO, 0x00000080);
- udelay(1000);
- /* enable the cx22702 pins */
- cx_clear(MO_GP0_IO, 0x00000004);
- udelay(1000);
- break;
-
- case CX88_BOARD_HAUPPAUGE_HVR3000:
- case CX88_BOARD_HAUPPAUGE_HVR4000:
- /* Toggle reset on cx22702 leaving i2c active */
- cx_set(MO_GP0_IO, 0x00000080);
- udelay(1000);
- cx_clear(MO_GP0_IO, 0x00000080);
- udelay(50);
- cx_set(MO_GP0_IO, 0x00000080);
- udelay(1000);
- switch (core->dvbdev->frontends.active_fe_id) {
- case 1: /* DVB-S/S2 Enabled */
- /* tri-state the cx22702 pins */
- cx_set(MO_GP0_IO, 0x00000004);
- /* Take the cx24116/cx24123 out of reset */
- cx_write(MO_SRST_IO, 1);
- core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
- break;
- case 2: /* DVB-T Enabled */
- /* Put the cx24116/cx24123 into reset */
- cx_write(MO_SRST_IO, 0);
- /* enable the cx22702 pins */
- cx_clear(MO_GP0_IO, 0x00000004);
- core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
- break;
- }
- udelay(1000);
- break;
-
- case CX88_BOARD_WINFAST_DTV2000H_PLUS:
- /* set RF input to AIR for DVB-T (GPIO 16) */
- cx_write(MO_GP2_IO, 0x0101);
- break;
-
- default:
- err = -ENODEV;
- }
- return err;
-}
-
-/* CX8802 MPEG -> mini driver - We no longer have the hardware */
-static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
-{
- struct cx88_core *core = drv->core;
- int err = 0;
- dprintk( 1, "%s\n", __func__);
-
- switch (core->boardnr) {
- case CX88_BOARD_HAUPPAUGE_HVR1300:
- /* Do Nothing, leave the cx22702 on the bus. */
- break;
- case CX88_BOARD_HAUPPAUGE_HVR3000:
- case CX88_BOARD_HAUPPAUGE_HVR4000:
- break;
- default:
- err = -ENODEV;
- }
- return err;
-}
-
-static int cx8802_dvb_probe(struct cx8802_driver *drv)
-{
- struct cx88_core *core = drv->core;
- struct cx8802_dev *dev = drv->core->dvbdev;
- int err;
- struct videobuf_dvb_frontend *fe;
- int i;
-
- dprintk( 1, "%s\n", __func__);
- dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- core->boardnr,
- core->name,
- core->pci_bus,
- core->pci_slot);
-
- err = -ENODEV;
- if (!(core->board.mpeg & CX88_MPEG_DVB))
- goto fail_core;
-
- /* If vp3054 isn't enabled, a stub will just return 0 */
- err = vp3054_i2c_probe(dev);
- if (0 != err)
- goto fail_core;
-
- /* dvb stuff */
- printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
- dev->ts_gen_cntrl = 0x0c;
-
- err = cx8802_alloc_frontends(dev);
- if (err)
- goto fail_core;
-
- err = -ENODEV;
- for (i = 1; i <= core->board.num_frontends; i++) {
- fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
- if (fe == NULL) {
- printk(KERN_ERR "%s() failed to get frontend(%d)\n",
- __func__, i);
- goto fail_probe;
- }
- videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_TOP,
- sizeof(struct cx88_buffer),
- dev, NULL);
- /* init struct videobuf_dvb */
- fe->dvb.name = dev->core->name;
- }
-
- err = dvb_register(dev);
- if (err)
- /* frontends/adapter de-allocated in dvb_register */
- printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
- core->name, err);
- return err;
-fail_probe:
- videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends);
-fail_core:
- return err;
-}
-
-static int cx8802_dvb_remove(struct cx8802_driver *drv)
-{
- struct cx88_core *core = drv->core;
- struct cx8802_dev *dev = drv->core->dvbdev;
-
- dprintk( 1, "%s\n", __func__);
-
- videobuf_dvb_unregister_bus(&dev->frontends);
-
- vp3054_i2c_remove(dev);
-
- core->gate_ctrl = NULL;
-
- return 0;
-}
-
-static struct cx8802_driver cx8802_dvb_driver = {
- .type_id = CX88_MPEG_DVB,
- .hw_access = CX8802_DRVCTL_SHARED,
- .probe = cx8802_dvb_probe,
- .remove = cx8802_dvb_remove,
- .advise_acquire = cx8802_dvb_advise_acquire,
- .advise_release = cx8802_dvb_advise_release,
-};
-
-static int __init dvb_init(void)
-{
- printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n",
- CX88_VERSION);
- return cx8802_register_driver(&cx8802_dvb_driver);
-}
-
-static void __exit dvb_fini(void)
-{
- cx8802_unregister_driver(&cx8802_dvb_driver);
-}
-
-module_init(dvb_init);
-module_exit(dvb_fini);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
deleted file mode 100644
index 0cae0fd9e164..000000000000
--- a/drivers/media/video/cx88/cx88.h
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- *
- * v4l2 device driver for cx2388x based TV cards
- *
- * (c) 2003,04 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
- *
- * 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/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev2.h>
-#include <linux/kdev_t.h>
-
-#include <media/v4l2-device.h>
-#include <media/v4l2-fh.h>
-#include <media/tuner.h>
-#include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/cx2341x.h>
-#include <media/videobuf-dvb.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/wm8775.h>
-
-#include "btcx-risc.h"
-#include "cx88-reg.h"
-#include "tuner-xc2028.h"
-
-#include <linux/mutex.h>
-
-#define CX88_VERSION "0.0.9"
-
-#define UNSET (-1U)
-
-#define CX88_MAXBOARDS 8
-
-/* Max number of inputs by card */
-#define MAX_CX88_INPUT 8
-
-/* ----------------------------------------------------------- */
-/* defines and enums */
-
-/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */
-#define CX88_NORMS (V4L2_STD_ALL \
- & ~V4L2_STD_PAL_H \
- & ~V4L2_STD_NTSC_M_KR \
- & ~V4L2_STD_SECAM_LC)
-
-#define FORMAT_FLAGS_PACKED 0x01
-#define FORMAT_FLAGS_PLANAR 0x02
-
-#define VBI_LINE_COUNT 17
-#define VBI_LINE_LENGTH 2048
-
-#define AUD_RDS_LINES 4
-
-/* need "shadow" registers for some write-only ones ... */
-#define SHADOW_AUD_VOL_CTL 1
-#define SHADOW_AUD_BAL_CTL 2
-#define SHADOW_MAX 3
-
-/* FM Radio deemphasis type */
-enum cx88_deemph_type {
- FM_NO_DEEMPH = 0,
- FM_DEEMPH_50,
- FM_DEEMPH_75
-};
-
-enum cx88_board_type {
- CX88_BOARD_NONE = 0,
- CX88_MPEG_DVB,
- CX88_MPEG_BLACKBIRD
-};
-
-enum cx8802_board_access {
- CX8802_DRVCTL_SHARED = 1,
- CX8802_DRVCTL_EXCLUSIVE = 2,
-};
-
-/* ----------------------------------------------------------- */
-/* tv norms */
-
-static unsigned int inline norm_maxw(v4l2_std_id norm)
-{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
-}
-
-
-static unsigned int inline norm_maxh(v4l2_std_id norm)
-{
- return (norm & V4L2_STD_625_50) ? 576 : 480;
-}
-
-/* ----------------------------------------------------------- */
-/* static data */
-
-struct cx8800_fmt {
- const char *name;
- u32 fourcc; /* v4l2 format id */
- int depth;
- int flags;
- u32 cxformat;
-};
-
-/* ----------------------------------------------------------- */
-/* SRAM memory management data (see cx88-core.c) */
-
-#define SRAM_CH21 0 /* video */
-#define SRAM_CH22 1
-#define SRAM_CH23 2
-#define SRAM_CH24 3 /* vbi */
-#define SRAM_CH25 4 /* audio */
-#define SRAM_CH26 5
-#define SRAM_CH28 6 /* mpeg */
-#define SRAM_CH27 7 /* audio rds */
-/* more */
-
-struct sram_channel {
- const char *name;
- u32 cmds_start;
- u32 ctrl_start;
- u32 cdt;
- u32 fifo_start;
- u32 fifo_size;
- u32 ptr1_reg;
- u32 ptr2_reg;
- u32 cnt1_reg;
- u32 cnt2_reg;
-};
-extern const struct sram_channel const cx88_sram_channels[];
-
-/* ----------------------------------------------------------- */
-/* card configuration */
-
-#define CX88_BOARD_NOAUTO UNSET
-#define CX88_BOARD_UNKNOWN 0
-#define CX88_BOARD_HAUPPAUGE 1
-#define CX88_BOARD_GDI 2
-#define CX88_BOARD_PIXELVIEW 3
-#define CX88_BOARD_ATI_WONDER_PRO 4
-#define CX88_BOARD_WINFAST2000XP_EXPERT 5
-#define CX88_BOARD_AVERTV_STUDIO_303 6
-#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
-#define CX88_BOARD_WINFAST_DV2000 8
-#define CX88_BOARD_LEADTEK_PVR2000 9
-#define CX88_BOARD_IODATA_GVVCP3PCI 10
-#define CX88_BOARD_PROLINK_PLAYTVPVR 11
-#define CX88_BOARD_ASUS_PVR_416 12
-#define CX88_BOARD_MSI_TVANYWHERE 13
-#define CX88_BOARD_KWORLD_DVB_T 14
-#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
-#define CX88_BOARD_KWORLD_LTV883 16
-#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17
-#define CX88_BOARD_HAUPPAUGE_DVB_T1 18
-#define CX88_BOARD_CONEXANT_DVB_T1 19
-#define CX88_BOARD_PROVIDEO_PV259 20
-#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
-#define CX88_BOARD_PCHDTV_HD3000 22
-#define CX88_BOARD_DNTV_LIVE_DVB_T 23
-#define CX88_BOARD_HAUPPAUGE_ROSLYN 24
-#define CX88_BOARD_DIGITALLOGIC_MEC 25
-#define CX88_BOARD_IODATA_GVBCTV7E 26
-#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
-#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28
-#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
-#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
-#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
-#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
-#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
-#define CX88_BOARD_ATI_HDTVWONDER 34
-#define CX88_BOARD_WINFAST_DTV1000 35
-#define CX88_BOARD_AVERTV_303 36
-#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37
-#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38
-#define CX88_BOARD_KWORLD_DVBS_100 39
-#define CX88_BOARD_HAUPPAUGE_HVR1100 40
-#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41
-#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42
-#define CX88_BOARD_KWORLD_DVB_T_CX22702 43
-#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
-#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
-#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
-#define CX88_BOARD_PCHDTV_HD5500 47
-#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
-#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
-#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
-#define CX88_BOARD_WINFAST_DTV2000H 51
-#define CX88_BOARD_GENIATECH_DVBS 52
-#define CX88_BOARD_HAUPPAUGE_HVR3000 53
-#define CX88_BOARD_NORWOOD_MICRO 54
-#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
-#define CX88_BOARD_HAUPPAUGE_HVR1300 56
-#define CX88_BOARD_ADSTECH_PTV_390 57
-#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58
-#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
-#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60
-#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
-#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62
-#define CX88_BOARD_GENIATECH_X8000_MT 63
-#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
-#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
-#define CX88_BOARD_PROLINK_PV_8000GT 66
-#define CX88_BOARD_KWORLD_ATSC_120 67
-#define CX88_BOARD_HAUPPAUGE_HVR4000 68
-#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69
-#define CX88_BOARD_TEVII_S460 70
-#define CX88_BOARD_OMICOM_SS4_PCI 71
-#define CX88_BOARD_TBS_8920 72
-#define CX88_BOARD_TEVII_S420 73
-#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
-#define CX88_BOARD_PROF_7300 75
-#define CX88_BOARD_SATTRADE_ST4200 76
-#define CX88_BOARD_TBS_8910 77
-#define CX88_BOARD_PROF_6200 78
-#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
-#define CX88_BOARD_HAUPPAUGE_IRONLY 80
-#define CX88_BOARD_WINFAST_DTV1800H 81
-#define CX88_BOARD_WINFAST_DTV2000H_J 82
-#define CX88_BOARD_PROF_7301 83
-#define CX88_BOARD_SAMSUNG_SMT_7020 84
-#define CX88_BOARD_TWINHAN_VP1027_DVBS 85
-#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,
- CX88_VMUX_COMPOSITE2,
- CX88_VMUX_COMPOSITE3,
- CX88_VMUX_COMPOSITE4,
- CX88_VMUX_SVIDEO,
- CX88_VMUX_TELEVISION,
- CX88_VMUX_CABLE,
- CX88_VMUX_DVB,
- CX88_VMUX_DEBUG,
- CX88_RADIO,
-};
-
-struct cx88_input {
- enum cx88_itype type;
- u32 gpio0, gpio1, gpio2, gpio3;
- unsigned int vmux:2;
- unsigned int audioroute:4;
-};
-
-struct cx88_board {
- const char *name;
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
- int tda9887_conf;
- struct cx88_input input[MAX_CX88_INPUT];
- struct cx88_input radio;
- enum cx88_board_type mpeg;
- unsigned int audio_chip;
- int num_frontends;
-
- /* Used for I2S devices */
- int i2sinputcntl;
-};
-
-struct cx88_subid {
- u16 subvendor;
- u16 subdevice;
- u32 card;
-};
-
-enum cx88_tvaudio {
- WW_NONE = 1,
- WW_BTSC,
- WW_BG,
- WW_DK,
- WW_I,
- WW_L,
- WW_EIAJ,
- WW_I2SPT,
- WW_FM,
- WW_I2SADC,
- WW_M
-};
-
-#define INPUT(nr) (core->board.input[nr])
-
-/* ----------------------------------------------------------- */
-/* device / file handle status */
-
-#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
-#define RESOURCE_VBI 4
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(2000)
-
-/* buffer for one video frame */
-struct cx88_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
-
- /* cx88 specific */
- unsigned int bpl;
- struct btcx_riscmem risc;
- const struct cx8800_fmt *fmt;
- u32 count;
-};
-
-struct cx88_dmaqueue {
- struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
- struct btcx_riscmem stopper;
- u32 count;
-};
-
-struct cx88_core {
- struct list_head devlist;
- atomic_t refcount;
-
- /* board name */
- int nr;
- char name[32];
-
- /* pci stuff */
- int pci_bus;
- int pci_slot;
- u32 __iomem *lmmio;
- u8 __iomem *bmmio;
- u32 shadow[SHADOW_MAX];
- int pci_irqmask;
-
- /* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
- struct i2c_client i2c_client;
- u32 i2c_state, i2c_rc;
-
- /* config info -- analog */
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler video_hdl;
- struct v4l2_ctrl *chroma_agc;
- struct v4l2_ctrl_handler audio_hdl;
- struct v4l2_subdev *sd_wm8775;
- struct i2c_client *i2c_rtc;
- unsigned int boardnr;
- struct cx88_board board;
-
- /* Supported V4L _STD_ tuner formats */
- unsigned int tuner_formats;
-
- /* config info -- dvb */
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
-#endif
- void (*gate_ctrl)(struct cx88_core *core, int open);
-
- /* state info */
- struct task_struct *kthread;
- v4l2_std_id tvnorm;
- enum cx88_tvaudio tvaudio;
- u32 audiomode_manual;
- u32 audiomode_current;
- u32 input;
- u32 last_analog_input;
- u32 astat;
- u32 use_nicam;
- unsigned long last_change;
-
- /* IR remote control state */
- struct cx88_IR *ir;
-
- /* I2C remote data */
- struct IR_i2c_init_data init_data;
- struct wm8775_platform_data wm8775_data;
-
- struct mutex lock;
- /* various v4l controls */
- u32 freq;
- int users;
- int mpeg_users;
-
- /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
- struct cx8802_dev *dvbdev;
- enum cx88_board_type active_type_id;
- int active_ref;
- int active_fe_id;
-};
-
-static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
-}
-
-#define call_hw(core, grpid, o, f, args...) \
- do { \
- if (!core->i2c_rc) { \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 1); \
- v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 0); \
- } \
- } while (0)
-
-#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
-
-#define WM8775_GID (1 << 0)
-
-#define wm8775_s_ctrl(core, id, val) \
- do { \
- struct v4l2_ctrl *ctrl_ = \
- v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
- if (ctrl_ && !core->i2c_rc) { \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 1); \
- v4l2_ctrl_s_ctrl(ctrl_, val); \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 0); \
- } \
- } while (0)
-
-#define wm8775_g_ctrl(core, id) \
- ({ \
- struct v4l2_ctrl *ctrl_ = \
- v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
- s32 val = 0; \
- if (ctrl_ && !core->i2c_rc) { \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 1); \
- val = v4l2_ctrl_g_ctrl(ctrl_); \
- if (core->gate_ctrl) \
- core->gate_ctrl(core, 0); \
- } \
- val; \
- })
-
-struct cx8800_dev;
-struct cx8802_dev;
-
-/* ----------------------------------------------------------- */
-/* function 0: video stuff */
-
-struct cx8800_fh {
- struct v4l2_fh fh;
- struct cx8800_dev *dev;
- unsigned int resources;
-
- /* video capture */
- struct videobuf_queue vidq;
-
- /* vbi capture */
- struct videobuf_queue vbiq;
-};
-
-struct cx8800_suspend_state {
- int disabled;
-};
-
-struct cx8800_dev {
- struct cx88_core *core;
- spinlock_t slock;
-
- /* various device info */
- unsigned int resources;
- struct video_device *video_dev;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
-
- /* pci i/o */
- struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
-
- const struct cx8800_fmt *fmt;
- unsigned int width, height;
-
- /* capture queues */
- struct cx88_dmaqueue vidq;
- struct cx88_dmaqueue vbiq;
-
- /* various v4l controls */
-
- /* other global state info */
- struct cx8800_suspend_state state;
-};
-
-/* ----------------------------------------------------------- */
-/* function 1: audio/alsa stuff */
-/* =============> moved to cx88-alsa.c <====================== */
-
-
-/* ----------------------------------------------------------- */
-/* function 2: mpeg stuff */
-
-struct cx8802_fh {
- struct v4l2_fh fh;
- struct cx8802_dev *dev;
- struct videobuf_queue mpegq;
-};
-
-struct cx8802_suspend_state {
- int disabled;
-};
-
-struct cx8802_driver {
- struct cx88_core *core;
-
- /* List of drivers attached to device */
- struct list_head drvlist;
-
- /* Type of driver and access required */
- enum cx88_board_type type_id;
- enum cx8802_board_access hw_access;
-
- /* MPEG 8802 internal only */
- int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
- int (*resume)(struct pci_dev *pci_dev);
-
- /* Callers to the following functions must hold core->lock */
-
- /* MPEG 8802 -> mini driver - Driver probe and configuration */
- int (*probe)(struct cx8802_driver *drv);
- int (*remove)(struct cx8802_driver *drv);
-
- /* MPEG 8802 -> mini driver - Access for hardware control */
- int (*advise_acquire)(struct cx8802_driver *drv);
- int (*advise_release)(struct cx8802_driver *drv);
-
- /* MPEG 8802 <- mini driver - Access for hardware control */
- int (*request_acquire)(struct cx8802_driver *drv);
- int (*request_release)(struct cx8802_driver *drv);
-};
-
-struct cx8802_dev {
- struct cx88_core *core;
- spinlock_t slock;
-
- /* pci i/o */
- struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
-
- /* dma queues */
- struct cx88_dmaqueue mpegq;
- u32 ts_packet_size;
- u32 ts_packet_count;
-
- /* other global state info */
- struct cx8802_suspend_state state;
-
- /* for blackbird only */
- struct list_head devlist;
-#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
- defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
- struct video_device *mpeg_dev;
- u32 mailbox;
- int width;
- int height;
- unsigned char mpeg_active; /* nonzero if mpeg encoder is active */
-
- /* mpeg params */
- struct cx2341x_handler cxhdl;
-#endif
-
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- /* for dvb only */
- struct videobuf_dvb_frontends frontends;
-#endif
-
-#if defined(CONFIG_VIDEO_CX88_VP3054) || \
- defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
- /* For VP3045 secondary I2C bus support */
- struct vp3054_i2c_state *vp3054;
-#endif
- /* for switching modulation types */
- unsigned char ts_gen_cntrl;
-
- /* List of attached drivers; must hold core->lock to access */
- struct list_head drvlist;
-
- struct work_struct request_module_wk;
-};
-
-/* ----------------------------------------------------------- */
-
-#define cx_read(reg) readl(core->lmmio + ((reg)>>2))
-#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2))
-#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg))
-
-#define cx_andor(reg,mask,value) \
- writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
- ((value) & (mask)), core->lmmio+((reg)>>2))
-#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
-#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
-
-#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
-
-/* shadow registers */
-#define cx_sread(sreg) (core->shadow[sreg])
-#define cx_swrite(sreg,reg,value) \
- (core->shadow[sreg] = value, \
- writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
-#define cx_sandor(sreg,reg,mask,value) \
- (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
- writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
-
-/* ----------------------------------------------------------- */
-/* cx88-core.c */
-
-extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
- int len, u32 bits, u32 mask);
-
-extern int cx88_core_irq(struct cx88_core *core, u32 status);
-extern void cx88_wakeup(struct cx88_core *core,
- struct cx88_dmaqueue *q, u32 count);
-extern void cx88_shutdown(struct cx88_core *core);
-extern int cx88_reset(struct cx88_core *core);
-
-extern int
-cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- struct scatterlist *sglist,
- unsigned int top_offset, unsigned int bottom_offset,
- unsigned int bpl, unsigned int padding, unsigned int lines);
-extern int
-cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines, unsigned int lpi);
-extern int
-cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value);
-extern void
-cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
-
-extern void cx88_risc_disasm(struct cx88_core *core,
- struct btcx_riscmem *risc);
-extern int cx88_sram_channel_setup(struct cx88_core *core,
- const struct sram_channel *ch,
- unsigned int bpl, u32 risc);
-extern void cx88_sram_channel_dump(struct cx88_core *core,
- const struct sram_channel *ch);
-
-extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
- unsigned int height, enum v4l2_field field);
-extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
-
-extern struct video_device *cx88_vdev_init(struct cx88_core *core,
- struct pci_dev *pci,
- const struct video_device *template_,
- const char *type);
-extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
-extern void cx88_core_put(struct cx88_core *core,
- struct pci_dev *pci);
-
-extern int cx88_start_audio_dma(struct cx88_core *core);
-extern int cx88_stop_audio_dma(struct cx88_core *core);
-
-
-/* ----------------------------------------------------------- */
-/* cx88-vbi.c */
-
-/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
-int cx8800_vbi_fmt (struct file *file, void *priv,
- struct v4l2_format *f);
-
-/*
-int cx8800_start_vbi_dma(struct cx8800_dev *dev,
- struct cx88_dmaqueue *q,
- struct cx88_buffer *buf);
-*/
-int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
-int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
- struct cx88_dmaqueue *q);
-void cx8800_vbi_timeout(unsigned long data);
-
-extern const struct videobuf_queue_ops cx8800_vbi_qops;
-
-/* ----------------------------------------------------------- */
-/* cx88-i2c.c */
-
-extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
-
-
-/* ----------------------------------------------------------- */
-/* cx88-cards.c */
-
-extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
-extern int cx88_get_resources(const struct cx88_core *core,
- struct pci_dev *pci);
-extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
-extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
-
-/* ----------------------------------------------------------- */
-/* cx88-tvaudio.c */
-
-void cx88_set_tvaudio(struct cx88_core *core);
-void cx88_newstation(struct cx88_core *core);
-void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
-void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
-int cx88_audio_thread(void *data);
-
-int cx8802_register_driver(struct cx8802_driver *drv);
-int cx8802_unregister_driver(struct cx8802_driver *drv);
-
-/* Caller must hold core->lock */
-struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
-
-/* ----------------------------------------------------------- */
-/* cx88-dsp.c */
-
-s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
-
-/* ----------------------------------------------------------- */
-/* cx88-input.c */
-
-int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
-int cx88_ir_fini(struct cx88_core *core);
-void cx88_ir_irq(struct cx88_core *core);
-int cx88_ir_start(struct cx88_core *core);
-void cx88_ir_stop(struct cx88_core *core);
-extern void cx88_i2c_init_ir(struct cx88_core *core);
-
-/* ----------------------------------------------------------- */
-/* cx88-mpeg.c */
-
-int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
- struct cx88_buffer *buf, enum v4l2_field field);
-void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
-void cx8802_cancel_buffers(struct cx8802_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* cx88-video.c*/
-int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
-int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
-int cx88_video_mux(struct cx88_core *core, unsigned int input);
-void cx88_querycap(struct file *file, struct cx88_core *core,
- struct v4l2_capability *cap);
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
deleted file mode 100644
index 52c5ca68cb3d..000000000000
--- a/drivers/media/video/davinci/Kconfig
+++ /dev/null
@@ -1,121 +0,0 @@
-config VIDEO_DAVINCI_VPIF_DISPLAY
- tristate "DM646x/DA850/OMAPL138 EVM Video Display"
- depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
- select VIDEOBUF2_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- select VIDEO_ADV7343 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_THS7303 if VIDEO_HELPER_CHIPS_AUTO
- help
- Enables Davinci VPIF module used for display devices.
- This module is common for following DM6467/DA850/OMAPL138
- based display devices.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_display.
-
-config VIDEO_DAVINCI_VPIF_CAPTURE
- tristate "DM646x/DA850/OMAPL138 EVM Video Capture"
- depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
- select VIDEOBUF2_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- help
- Enables Davinci VPIF module used for captur devices.
- This module is common for following DM6467/DA850/OMAPL138
- based capture devices.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_capture.
-
-config VIDEO_DAVINCI_VPIF
- tristate "DaVinci VPIF Driver"
- depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE
- help
- Support for DaVinci VPIF Driver.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif.
-
-config VIDEO_VPSS_SYSTEM
- tristate "VPSS System module driver"
- depends on ARCH_DAVINCI
- help
- Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
- tristate "VPFE Video Capture Driver"
- depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
- depends on I2C
- select VIDEOBUF_DMA_CONTIG
- help
- Support for DMx/AMx VPFE based frame grabber. This is the
- common V4L2 module for following DMx/AMx SoCs from Texas
- Instruments:- DM6446, DM365, DM355 & AM3517/05.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
- tristate "DM6446 CCDC HW module"
- depends on VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from slave decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_DM355_CCDC
- tristate "DM355 CCDC HW module"
- depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DM355 CCD hw module. DM355 CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from a slave decoders
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_ISIF
- tristate "ISIF HW module"
- depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables ISIF hw module. This is the hardware module for
- configuring ISIF in VPFE to capture Raw Bayer RGB data from
- a image sensor or YUV data from a YUV source.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_DM644X_VPBE
- tristate "DM644X VPBE HW module"
- depends on ARCH_DAVINCI_DM644x
- select VIDEO_VPSS_SYSTEM
- select VIDEOBUF_DMA_CONTIG
- help
- Enables VPBE modules used for display on a DM644x
- SoC.
-
- To compile this driver as a module, choose M here: the
- module will be called vpbe.
-
-
-config VIDEO_VPBE_DISPLAY
- tristate "VPBE V4L2 Display driver"
- depends on ARCH_DAVINCI_DM644x
- select VIDEO_DM644X_VPBE
- help
- Enables VPBE V4L2 Display driver on a DM644x device
-
- To compile this driver as a module, choose M here: the
- module will be called vpbe_display.
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
deleted file mode 100644
index 5b68847d4017..000000000000
--- a/drivers/media/video/davinci/dm355_ccdc.c
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Texas Instruments Inc
- *
- * 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
- *
- * CCDC hardware module for DM355
- * ------------------------------
- *
- * This module is for configuring DM355 CCD controller of VPFE to capture
- * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
- * such as Defect Pixel Correction, Color Space Conversion etc to
- * pre-process the Bayer RGB data, before writing it to SDRAM. This
- * module also allows application to configure individual
- * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
- * To do so, application include dm355_ccdc.h and vpfe_capture.h header
- * files. The setparams() API is called by vpfe_capture driver
- * to configure module parameters
- *
- * TODO: 1) Raw bayer parameter settings and bayer capture
- * 2) Split module parameter structure to module specific ioctl structs
- * 3) add support for lense shading correction
- * 4) investigate if enum used for user space type definition
- * to be replaced by #defines or integer
- */
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/videodev2.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-#include <media/davinci/dm355_ccdc.h>
-#include <media/davinci/vpss.h>
-
-#include "dm355_ccdc_regs.h"
-#include "ccdc_hw_device.h"
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("CCDC Driver for DM355");
-MODULE_AUTHOR("Texas Instruments");
-
-static struct ccdc_oper_config {
- struct device *dev;
- /* CCDC interface type */
- enum vpfe_hw_if_type if_type;
- /* Raw Bayer configuration */
- struct ccdc_params_raw bayer;
- /* YCbCr configuration */
- struct ccdc_params_ycbcr ycbcr;
- /* Master clock */
- struct clk *mclk;
- /* slave clock */
- struct clk *sclk;
- /* ccdc base address */
- void __iomem *base_addr;
-} ccdc_cfg = {
- /* Raw configurations */
- .bayer = {
- .pix_fmt = CCDC_PIXFMT_RAW,
- .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
- .win = CCDC_WIN_VGA,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .gain = {
- .r_ye = 256,
- .gb_g = 256,
- .gr_cy = 256,
- .b_mg = 256
- },
- .config_params = {
- .datasft = 2,
- .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
- .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
- .alaw = {
- .gama_wd = 2,
- },
- .blk_clamp = {
- .sample_pixel = 1,
- .dc_sub = 25
- },
- .col_pat_field0 = {
- .olop = CCDC_GREEN_BLUE,
- .olep = CCDC_BLUE,
- .elop = CCDC_RED,
- .elep = CCDC_GREEN_RED
- },
- .col_pat_field1 = {
- .olop = CCDC_GREEN_BLUE,
- .olep = CCDC_BLUE,
- .elop = CCDC_RED,
- .elep = CCDC_GREEN_RED
- },
- },
- },
- /* YCbCr configuration */
- .ycbcr = {
- .win = CCDC_WIN_PAL,
- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
- .frm_fmt = CCDC_FRMFMT_INTERLACED,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .bt656_enable = 1,
- .pix_order = CCDC_PIXORDER_CBYCRY,
- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
- },
-};
-
-
-/* Raw Bayer formats */
-static u32 ccdc_raw_bayer_pix_formats[] =
- {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
-
-/* Raw YUV formats */
-static u32 ccdc_raw_yuv_pix_formats[] =
- {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
-
-/* register access routines */
-static inline u32 regr(u32 offset)
-{
- return __raw_readl(ccdc_cfg.base_addr + offset);
-}
-
-static inline void regw(u32 val, u32 offset)
-{
- __raw_writel(val, ccdc_cfg.base_addr + offset);
-}
-
-static void ccdc_enable(int en)
-{
- unsigned int temp;
- temp = regr(SYNCEN);
- temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
- temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
- regw(temp, SYNCEN);
-}
-
-static void ccdc_enable_output_to_sdram(int en)
-{
- unsigned int temp;
- temp = regr(SYNCEN);
- temp &= (~(CCDC_SYNCEN_WEN_MASK));
- temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
- regw(temp, SYNCEN);
-}
-
-static void ccdc_config_gain_offset(void)
-{
- /* configure gain */
- regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
- regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
- regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
- regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
- /* configure offset */
- regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
-}
-
-/*
- * ccdc_restore_defaults()
- * This function restore power on defaults in the ccdc registers
- */
-static int ccdc_restore_defaults(void)
-{
- int i;
-
- dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
- /* set all registers to zero */
- for (i = 0; i <= CCDC_REG_LAST; i += 4)
- regw(0, i);
-
- /* now override the values with power on defaults in registers */
- regw(MODESET_DEFAULT, MODESET);
- /* no culling support */
- regw(CULH_DEFAULT, CULH);
- regw(CULV_DEFAULT, CULV);
- /* Set default Gain and Offset */
- ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
- ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
- ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
- ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
- ccdc_config_gain_offset();
- regw(OUTCLIP_DEFAULT, OUTCLIP);
- regw(LSCCFG2_DEFAULT, LSCCFG2);
- /* select ccdc input */
- if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
- dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
- return -EFAULT;
- }
- /* select ccdc clock */
- if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
- dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
- return -EFAULT;
- }
- dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
- return 0;
-}
-
-static int ccdc_open(struct device *device)
-{
- return ccdc_restore_defaults();
-}
-
-static int ccdc_close(struct device *device)
-{
- /* disable clock */
- vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
- /* do nothing for now */
- return 0;
-}
-/*
- * ccdc_setwin()
- * This function will configure the window size to
- * be capture in CCDC reg.
- */
-static void ccdc_setwin(struct v4l2_rect *image_win,
- enum ccdc_frmfmt frm_fmt, int ppc)
-{
- int horz_start, horz_nr_pixels;
- int vert_start, vert_nr_lines;
- int mid_img = 0;
-
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
-
- /*
- * ppc - per pixel count. indicates how many pixels per cell
- * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
- * raw capture this is 1
- */
- horz_start = image_win->left << (ppc - 1);
- horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
-
- /* Writing the horizontal info into the registers */
- regw(horz_start, SPH);
- regw(horz_nr_pixels, NPH);
- vert_start = image_win->top;
-
- if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
- vert_nr_lines = (image_win->height >> 1) - 1;
- vert_start >>= 1;
- /* Since first line doesn't have any data */
- vert_start += 1;
- /* configure VDINT0 and VDINT1 */
- regw(vert_start, VDINT0);
- } else {
- /* Since first line doesn't have any data */
- vert_start += 1;
- vert_nr_lines = image_win->height - 1;
- /* configure VDINT0 and VDINT1 */
- mid_img = vert_start + (image_win->height / 2);
- regw(vert_start, VDINT0);
- regw(mid_img, VDINT1);
- }
- regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
- regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
- regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
- dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
-}
-
-static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
-{
- if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
- ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
- dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n");
- return -EINVAL;
- }
-
- if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
- ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
- dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n");
- return -EINVAL;
- }
-
- if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
- ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
- dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n");
- return -EINVAL;
- }
-
- if ((ccdcparam->med_filt_thres < 0) ||
- (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
- dev_dbg(ccdc_cfg.dev,
- "Invalid value of median filter threshold\n");
- return -EINVAL;
- }
-
- if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
- ccdcparam->data_sz > CCDC_DATA_8BITS) {
- dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n");
- return -EINVAL;
- }
-
- if (ccdcparam->alaw.enable) {
- if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
- ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
- dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
- return -EINVAL;
- }
- }
-
- if (ccdcparam->blk_clamp.b_clamp_enable) {
- if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
- ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
- dev_dbg(ccdc_cfg.dev,
- "Invalid value of sample pixel\n");
- return -EINVAL;
- }
- if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
- ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
- dev_dbg(ccdc_cfg.dev,
- "Invalid value of sample lines\n");
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/* Parameter operations */
-static int ccdc_set_params(void __user *params)
-{
- struct ccdc_config_params_raw ccdc_raw_params;
- int x;
-
- /* only raw module parameters can be set through the IOCTL */
- if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
- return -EINVAL;
-
- x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
- if (x) {
- dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc"
- "params, %d\n", x);
- return -EFAULT;
- }
-
- if (!validate_ccdc_param(&ccdc_raw_params)) {
- memcpy(&ccdc_cfg.bayer.config_params,
- &ccdc_raw_params,
- sizeof(ccdc_raw_params));
- return 0;
- }
- return -EINVAL;
-}
-
-/* This function will configure CCDC for YCbCr video capture */
-static void ccdc_config_ycbcr(void)
-{
- struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
- u32 temp;
-
- /* first set the CCDC power on defaults values in all registers */
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
- ccdc_restore_defaults();
-
- /* configure pixel format & video frame format */
- temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
- CCDC_INPUT_MODE_SHIFT) |
- ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
- CCDC_FRM_FMT_SHIFT));
-
- /* setup BT.656 sync mode */
- if (params->bt656_enable) {
- regw(CCDC_REC656IF_BT656_EN, REC656IF);
- /*
- * configure the FID, VD, HD pin polarity fld,hd pol positive,
- * vd negative, 8-bit pack mode
- */
- temp |= CCDC_VD_POL_NEGATIVE;
- } else { /* y/c external sync mode */
- temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
- CCDC_FID_POL_SHIFT) |
- ((params->hd_pol & CCDC_HD_POL_MASK) <<
- CCDC_HD_POL_SHIFT) |
- ((params->vd_pol & CCDC_VD_POL_MASK) <<
- CCDC_VD_POL_SHIFT));
- }
-
- /* pack the data to 8-bit */
- temp |= CCDC_DATA_PACK_ENABLE;
-
- regw(temp, MODESET);
-
- /* configure video window */
- ccdc_setwin(&params->win, params->frm_fmt, 2);
-
- /* configure the order of y cb cr in SD-RAM */
- temp = (params->pix_order << CCDC_Y8POS_SHIFT);
- temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
- regw(temp, CCDCFG);
-
- /*
- * configure the horizontal line offset. This is done by rounding up
- * width to a multiple of 16 pixels and multiply by two to account for
- * y:cb:cr 4:2:2 data
- */
- regw(((params->win.width * 2 + 31) >> 5), HSIZE);
-
- /* configure the memory line offset */
- if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
- /* two fields are interleaved in memory */
- regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
- }
-
- dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
-}
-
-/*
- * ccdc_config_black_clamp()
- * configure parameters for Optical Black Clamp
- */
-static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
-{
- u32 val;
-
- if (!bclamp->b_clamp_enable) {
- /* configure DCSub */
- regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
- regw(0x0000, CLAMP);
- return;
- }
- /* Enable the Black clamping, set sample lines and pixels */
- val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
- ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
- CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
- regw(val, CLAMP);
-
- /* If Black clamping is enable then make dcsub 0 */
- val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
- << CCDC_NUM_LINE_CALC_SHIFT;
- regw(val, DCSUB);
-}
-
-/*
- * ccdc_config_black_compense()
- * configure parameters for Black Compensation
- */
-static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
-{
- u32 val;
-
- val = (bcomp->b & CCDC_BLK_COMP_MASK) |
- ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_GB_COMP_SHIFT);
- regw(val, BLKCMP1);
-
- val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_GR_COMP_SHIFT) |
- ((bcomp->r & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_R_COMP_SHIFT);
- regw(val, BLKCMP0);
-}
-
-/*
- * ccdc_write_dfc_entry()
- * write an entry in the dfc table.
- */
-int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
-{
-/* TODO This is to be re-visited and adjusted */
-#define DFC_WRITE_WAIT_COUNT 1000
- u32 val, count = DFC_WRITE_WAIT_COUNT;
-
- regw(dfc->dft_corr_vert[index], DFCMEM0);
- regw(dfc->dft_corr_horz[index], DFCMEM1);
- regw(dfc->dft_corr_sub1[index], DFCMEM2);
- regw(dfc->dft_corr_sub2[index], DFCMEM3);
- regw(dfc->dft_corr_sub3[index], DFCMEM4);
- /* set WR bit to write */
- val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
- regw(val, DFCMEMCTL);
-
- /*
- * Assume, it is very short. If we get an error, we need to
- * adjust this value
- */
- while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
- count--;
- /*
- * TODO We expect the count to be non-zero to be successful. Adjust
- * the count if write requires more time
- */
-
- if (count) {
- dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
- return -1;
- }
- return 0;
-}
-
-/*
- * ccdc_config_vdfc()
- * configure parameters for Vertical Defect Correction
- */
-static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
-{
- u32 val;
- int i;
-
- /* Configure General Defect Correction. The table used is from IPIPE */
- val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
-
- /* Configure Vertical Defect Correction if needed */
- if (!dfc->ver_dft_en) {
- /* Enable only General Defect Correction */
- regw(val, DFCCTL);
- return 0;
- }
-
- if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
- return -EINVAL;
-
- val |= CCDC_DFCCTL_VDFC_DISABLE;
- val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
- CCDC_DFCCTL_VDFCSL_SHIFT;
- val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
- CCDC_DFCCTL_VDFCUDA_SHIFT;
- val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
- CCDC_DFCCTL_VDFLSFT_SHIFT;
- regw(val , DFCCTL);
-
- /* clear address ptr to offset 0 */
- val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
-
- /* write defect table entries */
- for (i = 0; i < dfc->table_size; i++) {
- /* increment address for non zero index */
- if (i != 0)
- val = CCDC_DFCMEMCTL_INC_ADDR;
- regw(val, DFCMEMCTL);
- if (ccdc_write_dfc_entry(i, dfc) < 0)
- return -EFAULT;
- }
-
- /* update saturation level and enable dfc */
- regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
- val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
- CCDC_DFCCTL_VDFCEN_SHIFT);
- regw(val, DFCCTL);
- return 0;
-}
-
-/*
- * ccdc_config_csc()
- * configure parameters for color space conversion
- * Each register CSCM0-7 has two values in S8Q5 format.
- */
-static void ccdc_config_csc(struct ccdc_csc *csc)
-{
- u32 val1, val2;
- int i;
-
- if (!csc->enable)
- return;
-
- /* Enable the CSC sub-module */
- regw(CCDC_CSC_ENABLE, CSCCTL);
-
- /* Converting the co-eff as per the format of the register */
- for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
- if ((i % 2) == 0) {
- /* CSCM - LSB */
- val1 = (csc->coeff[i].integer &
- CCDC_CSC_COEF_INTEG_MASK)
- << CCDC_CSC_COEF_INTEG_SHIFT;
- /*
- * convert decimal part to binary. Use 2 decimal
- * precision, user values range from .00 - 0.99
- */
- val1 |= (((csc->coeff[i].decimal &
- CCDC_CSC_COEF_DECIMAL_MASK) *
- CCDC_CSC_DEC_MAX) / 100);
- } else {
-
- /* CSCM - MSB */
- val2 = (csc->coeff[i].integer &
- CCDC_CSC_COEF_INTEG_MASK)
- << CCDC_CSC_COEF_INTEG_SHIFT;
- val2 |= (((csc->coeff[i].decimal &
- CCDC_CSC_COEF_DECIMAL_MASK) *
- CCDC_CSC_DEC_MAX) / 100);
- val2 <<= CCDC_CSCM_MSB_SHIFT;
- val2 |= val1;
- regw(val2, (CSCM0 + ((i - 1) << 1)));
- }
- }
-}
-
-/*
- * ccdc_config_color_patterns()
- * configure parameters for color patterns
- */
-static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
- struct ccdc_col_pat *pat1)
-{
- u32 val;
-
- val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
- (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
- (pat1->elop << 12) | (pat1->elep << 14));
- regw(val, COLPTN);
-}
-
-/* This function will configure CCDC for Raw mode image capture */
-static int ccdc_config_raw(void)
-{
- struct ccdc_params_raw *params = &ccdc_cfg.bayer;
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int val;
-
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
-
- /* restore power on defaults to register */
- ccdc_restore_defaults();
-
- /* CCDCFG register:
- * set CCD Not to swap input since input is RAW data
- * set FID detection function to Latch at V-Sync
- * set WENLOG - ccdc valid area to AND
- * set TRGSEL to WENBIT
- * set EXTRG to DISABLE
- * disable latching function on VSYNC - shadowed registers
- */
- regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
- CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
- CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
-
- /*
- * Set VDHD direction to input, input type to raw input
- * normal data polarity, do not use external WEN
- */
- val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
- CCDC_EXWEN_DISABLE);
-
- /*
- * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
- * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
- * frame format(progressive or interlace), & pixel format (Input mode)
- */
- val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
- ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
- ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
- ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
- ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
-
- /* set pack for alaw compression */
- if ((config_params->data_sz == CCDC_DATA_8BITS) ||
- config_params->alaw.enable)
- val |= CCDC_DATA_PACK_ENABLE;
-
- /* Configure for LPF */
- if (config_params->lpf_enable)
- val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
- CCDC_LPF_SHIFT;
-
- /* Configure the data shift */
- val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
- CCDC_DATASFT_SHIFT;
- regw(val , MODESET);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
-
- /* Configure the Median Filter threshold */
- regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
-
- /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
- val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
- CCDC_CFA_MOSAIC;
-
- /* Enable and configure aLaw register if needed */
- if (config_params->alaw.enable) {
- val |= (CCDC_ALAW_ENABLE |
- ((config_params->alaw.gama_wd &
- CCDC_ALAW_GAMA_WD_MASK) <<
- CCDC_GAMMAWD_INPUT_SHIFT));
- }
-
- /* Configure Median filter1 & filter2 */
- val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
- (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
-
- regw(val, GAMMAWD);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
-
- /* configure video window */
- ccdc_setwin(&params->win, params->frm_fmt, 1);
-
- /* Optical Clamp Averaging */
- ccdc_config_black_clamp(&config_params->blk_clamp);
-
- /* Black level compensation */
- ccdc_config_black_compense(&config_params->blk_comp);
-
- /* Vertical Defect Correction if needed */
- if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
- return -EFAULT;
-
- /* color space conversion */
- ccdc_config_csc(&config_params->csc);
-
- /* color pattern */
- ccdc_config_color_patterns(&config_params->col_pat_field0,
- &config_params->col_pat_field1);
-
- /* Configure the Gain & offset control */
- ccdc_config_gain_offset();
-
- dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
-
- /* Configure DATAOFST register */
- val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
- CCDC_DATAOFST_H_SHIFT;
- val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
- CCDC_DATAOFST_V_SHIFT;
- regw(val, DATAOFST);
-
- /* configuring HSIZE register */
- val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
- CCDC_HSIZE_FLIP_SHIFT;
-
- /* If pack 8 is enable then 1 pixel will take 1 byte */
- if ((config_params->data_sz == CCDC_DATA_8BITS) ||
- config_params->alaw.enable) {
- val |= (((params->win.width) + 31) >> 5) &
- CCDC_HSIZE_VAL_MASK;
-
- /* adjust to multiple of 32 */
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
- (((params->win.width) + 31) >> 5) &
- CCDC_HSIZE_VAL_MASK);
- } else {
- /* else one pixel will take 2 byte */
- val |= (((params->win.width * 2) + 31) >> 5) &
- CCDC_HSIZE_VAL_MASK;
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
- (((params->win.width * 2) + 31) >> 5) &
- CCDC_HSIZE_VAL_MASK);
- }
- regw(val, HSIZE);
-
- /* Configure SDOFST register */
- if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
- if (params->image_invert_enable) {
- /* For interlace inverse mode */
- regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
- CCDC_SDOFST_INTERLACE_INVERSE);
- } else {
- /* For interlace non inverse mode */
- regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
- CCDC_SDOFST_INTERLACE_NORMAL);
- }
- } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
- if (params->image_invert_enable) {
- /* For progessive inverse mode */
- regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
- CCDC_SDOFST_PROGRESSIVE_INVERSE);
- } else {
- /* For progessive non inverse mode */
- regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
- CCDC_SDOFST_PROGRESSIVE_NORMAL);
- }
- }
- dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
- return 0;
-}
-
-static int ccdc_configure(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- return ccdc_config_raw();
- else
- ccdc_config_ycbcr();
- return 0;
-}
-
-static int ccdc_set_buftype(enum ccdc_buftype buf_type)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.buf_type = buf_type;
- else
- ccdc_cfg.ycbcr.buf_type = buf_type;
- return 0;
-}
-static enum ccdc_buftype ccdc_get_buftype(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- return ccdc_cfg.bayer.buf_type;
- return ccdc_cfg.ycbcr.buf_type;
-}
-
-static int ccdc_enum_pix(u32 *pix, int i)
-{
- int ret = -EINVAL;
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
- *pix = ccdc_raw_bayer_pix_formats[i];
- ret = 0;
- }
- } else {
- if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
- *pix = ccdc_raw_yuv_pix_formats[i];
- ret = 0;
- }
- }
- return ret;
-}
-
-static int ccdc_set_pixel_format(u32 pixfmt)
-{
- struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
-
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
- if (pixfmt == V4L2_PIX_FMT_SBGGR8)
- alaw->enable = 1;
- else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
- return -EINVAL;
- } else {
- if (pixfmt == V4L2_PIX_FMT_YUYV)
- ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
- else if (pixfmt == V4L2_PIX_FMT_UYVY)
- ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
- else
- return -EINVAL;
- }
- return 0;
-}
-static u32 ccdc_get_pixel_format(void)
-{
- struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
- u32 pixfmt;
-
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- if (alaw->enable)
- pixfmt = V4L2_PIX_FMT_SBGGR8;
- else
- pixfmt = V4L2_PIX_FMT_SBGGR16;
- else {
- if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
- pixfmt = V4L2_PIX_FMT_YUYV;
- else
- pixfmt = V4L2_PIX_FMT_UYVY;
- }
- return pixfmt;
-}
-static int ccdc_set_image_window(struct v4l2_rect *win)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.win = *win;
- else
- ccdc_cfg.ycbcr.win = *win;
- return 0;
-}
-
-static void ccdc_get_image_window(struct v4l2_rect *win)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- *win = ccdc_cfg.bayer.win;
- else
- *win = ccdc_cfg.ycbcr.win;
-}
-
-static unsigned int ccdc_get_line_length(void)
-{
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int len;
-
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- if ((config_params->alaw.enable) ||
- (config_params->data_sz == CCDC_DATA_8BITS))
- len = ccdc_cfg.bayer.win.width;
- else
- len = ccdc_cfg.bayer.win.width * 2;
- } else
- len = ccdc_cfg.ycbcr.win.width * 2;
- return ALIGN(len, 32);
-}
-
-static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.frm_fmt = frm_fmt;
- else
- ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
- return 0;
-}
-
-static enum ccdc_frmfmt ccdc_get_frame_format(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- return ccdc_cfg.bayer.frm_fmt;
- else
- return ccdc_cfg.ycbcr.frm_fmt;
-}
-
-static int ccdc_getfid(void)
-{
- return (regr(MODESET) >> 15) & 1;
-}
-
-/* misc operations */
-static inline void ccdc_setfbaddr(unsigned long addr)
-{
- regw((addr >> 21) & 0x007f, STADRH);
- regw((addr >> 5) & 0x0ffff, STADRL);
-}
-
-static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
-{
- ccdc_cfg.if_type = params->if_type;
-
- switch (params->if_type) {
- case VPFE_BT656:
- case VPFE_YCBCR_SYNC_16:
- case VPFE_YCBCR_SYNC_8:
- ccdc_cfg.ycbcr.vd_pol = params->vdpol;
- ccdc_cfg.ycbcr.hd_pol = params->hdpol;
- break;
- default:
- /* TODO add support for raw bayer here */
- return -EINVAL;
- }
- return 0;
-}
-
-static struct ccdc_hw_device ccdc_hw_dev = {
- .name = "DM355 CCDC",
- .owner = THIS_MODULE,
- .hw_ops = {
- .open = ccdc_open,
- .close = ccdc_close,
- .enable = ccdc_enable,
- .enable_out_to_sdram = ccdc_enable_output_to_sdram,
- .set_hw_if_params = ccdc_set_hw_if_params,
- .set_params = ccdc_set_params,
- .configure = ccdc_configure,
- .set_buftype = ccdc_set_buftype,
- .get_buftype = ccdc_get_buftype,
- .enum_pix = ccdc_enum_pix,
- .set_pixel_format = ccdc_set_pixel_format,
- .get_pixel_format = ccdc_get_pixel_format,
- .set_frame_format = ccdc_set_frame_format,
- .get_frame_format = ccdc_get_frame_format,
- .set_image_window = ccdc_set_image_window,
- .get_image_window = ccdc_get_image_window,
- .get_line_length = ccdc_get_line_length,
- .setfbaddr = ccdc_setfbaddr,
- .getfid = ccdc_getfid,
- },
-};
-
-static int __init dm355_ccdc_probe(struct platform_device *pdev)
-{
- void (*setup_pinmux)(void);
- struct resource *res;
- int status = 0;
-
- /*
- * first try to register with vpfe. If not correct platform, then we
- * don't have to iomap
- */
- status = vpfe_register_ccdc_device(&ccdc_hw_dev);
- if (status < 0)
- return status;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- status = -ENODEV;
- goto fail_nores;
- }
-
- res = request_mem_region(res->start, resource_size(res), res->name);
- if (!res) {
- status = -EBUSY;
- goto fail_nores;
- }
-
- ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
- if (!ccdc_cfg.base_addr) {
- status = -ENOMEM;
- goto fail_nomem;
- }
-
- /* Get and enable Master clock */
- ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(ccdc_cfg.mclk)) {
- status = PTR_ERR(ccdc_cfg.mclk);
- goto fail_nomap;
- }
- if (clk_enable(ccdc_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Get and enable Slave clock */
- ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
- if (IS_ERR(ccdc_cfg.sclk)) {
- status = PTR_ERR(ccdc_cfg.sclk);
- goto fail_mclk;
- }
- if (clk_enable(ccdc_cfg.sclk)) {
- status = -ENODEV;
- goto fail_sclk;
- }
-
- /* Platform data holds setup_pinmux function ptr */
- if (NULL == pdev->dev.platform_data) {
- status = -ENODEV;
- goto fail_sclk;
- }
- setup_pinmux = pdev->dev.platform_data;
- /*
- * setup Mux configuration for ccdc which may be different for
- * different SoCs using this CCDC
- */
- setup_pinmux();
- ccdc_cfg.dev = &pdev->dev;
- printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
- return 0;
-fail_sclk:
- clk_put(ccdc_cfg.sclk);
-fail_mclk:
- clk_put(ccdc_cfg.mclk);
-fail_nomap:
- iounmap(ccdc_cfg.base_addr);
-fail_nomem:
- release_mem_region(res->start, resource_size(res));
-fail_nores:
- vpfe_unregister_ccdc_device(&ccdc_hw_dev);
- return status;
-}
-
-static int dm355_ccdc_remove(struct platform_device *pdev)
-{
- struct resource *res;
-
- clk_put(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.sclk);
- iounmap(ccdc_cfg.base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
- vpfe_unregister_ccdc_device(&ccdc_hw_dev);
- return 0;
-}
-
-static struct platform_driver dm355_ccdc_driver = {
- .driver = {
- .name = "dm355_ccdc",
- .owner = THIS_MODULE,
- },
- .remove = __devexit_p(dm355_ccdc_remove),
- .probe = dm355_ccdc_probe,
-};
-
-module_platform_driver(dm355_ccdc_driver);
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
deleted file mode 100644
index 9303fe553b07..000000000000
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ /dev/null
@@ -1,1081 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Texas Instruments Inc
- *
- * 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
- *
- * CCDC hardware module for DM6446
- * ------------------------------
- *
- * This module is for configuring CCD controller of DM6446 VPFE to capture
- * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
- * such as Defect Pixel Correction, Color Space Conversion etc to
- * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
- * module also allows application to configure individual
- * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
- * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
- * files. The setparams() API is called by vpfe_capture driver
- * to configure module parameters. This file is named DM644x so that other
- * variants such DM6443 may be supported using the same module.
- *
- * TODO: Test Raw bayer parameter settings and bayer capture
- * Split module parameter structure to module specific ioctl structs
- * investigate if enum used for user space type definition
- * to be replaced by #defines or integer
- */
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/videodev2.h>
-#include <linux/gfp.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-#include <media/davinci/dm644x_ccdc.h>
-#include <media/davinci/vpss.h>
-
-#include "dm644x_ccdc_regs.h"
-#include "ccdc_hw_device.h"
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("CCDC Driver for DM6446");
-MODULE_AUTHOR("Texas Instruments");
-
-static struct ccdc_oper_config {
- struct device *dev;
- /* CCDC interface type */
- enum vpfe_hw_if_type if_type;
- /* Raw Bayer configuration */
- struct ccdc_params_raw bayer;
- /* YCbCr configuration */
- struct ccdc_params_ycbcr ycbcr;
- /* Master clock */
- struct clk *mclk;
- /* slave clock */
- struct clk *sclk;
- /* ccdc base address */
- void __iomem *base_addr;
-} ccdc_cfg = {
- /* Raw configurations */
- .bayer = {
- .pix_fmt = CCDC_PIXFMT_RAW,
- .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
- .win = CCDC_WIN_VGA,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .config_params = {
- .data_sz = CCDC_DATA_10BITS,
- },
- },
- .ycbcr = {
- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
- .frm_fmt = CCDC_FRMFMT_INTERLACED,
- .win = CCDC_WIN_PAL,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .bt656_enable = 1,
- .pix_order = CCDC_PIXORDER_CBYCRY,
- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
- },
-};
-
-#define CCDC_MAX_RAW_YUV_FORMATS 2
-
-/* Raw Bayer formats */
-static u32 ccdc_raw_bayer_pix_formats[] =
- {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
-
-/* Raw YUV formats */
-static u32 ccdc_raw_yuv_pix_formats[] =
- {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
-
-/* CCDC Save/Restore context */
-static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
-
-/* register access routines */
-static inline u32 regr(u32 offset)
-{
- return __raw_readl(ccdc_cfg.base_addr + offset);
-}
-
-static inline void regw(u32 val, u32 offset)
-{
- __raw_writel(val, ccdc_cfg.base_addr + offset);
-}
-
-static void ccdc_enable(int flag)
-{
- regw(flag, CCDC_PCR);
-}
-
-static void ccdc_enable_vport(int flag)
-{
- if (flag)
- /* enable video port */
- regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
- else
- regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
-}
-
-/*
- * ccdc_setwin()
- * This function will configure the window size
- * to be capture in CCDC reg
- */
-void ccdc_setwin(struct v4l2_rect *image_win,
- enum ccdc_frmfmt frm_fmt,
- int ppc)
-{
- int horz_start, horz_nr_pixels;
- int vert_start, vert_nr_lines;
- int val = 0, mid_img = 0;
-
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
- /*
- * ppc - per pixel count. indicates how many pixels per cell
- * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
- * raw capture this is 1
- */
- horz_start = image_win->left << (ppc - 1);
- horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
- regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
- CCDC_HORZ_INFO);
-
- vert_start = image_win->top;
-
- if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
- vert_nr_lines = (image_win->height >> 1) - 1;
- vert_start >>= 1;
- /* Since first line doesn't have any data */
- vert_start += 1;
- /* configure VDINT0 */
- val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
- regw(val, CCDC_VDINT);
-
- } else {
- /* Since first line doesn't have any data */
- vert_start += 1;
- vert_nr_lines = image_win->height - 1;
- /*
- * configure VDINT0 and VDINT1. VDINT1 will be at half
- * of image height
- */
- mid_img = vert_start + (image_win->height / 2);
- val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
- (mid_img & CCDC_VDINT_VDINT1_MASK);
- regw(val, CCDC_VDINT);
-
- }
- regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
- CCDC_VERT_START);
- regw(vert_nr_lines, CCDC_VERT_LINES);
- dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
-}
-
-static void ccdc_readregs(void)
-{
- unsigned int val = 0;
-
- val = regr(CCDC_ALAW);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
- val = regr(CCDC_CLAMP);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
- val = regr(CCDC_DCSUB);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
- val = regr(CCDC_BLKCMP);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
- val = regr(CCDC_FPC_ADDR);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
- val = regr(CCDC_FPC);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
- val = regr(CCDC_FMTCFG);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
- val = regr(CCDC_COLPTN);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
- val = regr(CCDC_FMT_HORZ);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
- val = regr(CCDC_FMT_VERT);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
- val = regr(CCDC_HSIZE_OFF);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
- val = regr(CCDC_SDOFST);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
- val = regr(CCDC_VP_OUT);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
- val = regr(CCDC_SYN_MODE);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
- val = regr(CCDC_HORZ_INFO);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
- val = regr(CCDC_VERT_START);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
- val = regr(CCDC_VERT_LINES);
- dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
-}
-
-static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
-{
- if (ccdcparam->alaw.enable) {
- if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
- (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
- (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
- dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
- return -1;
- }
- }
- return 0;
-}
-
-static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
-{
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int *fpc_virtaddr = NULL;
- unsigned int *fpc_physaddr = NULL;
-
- memcpy(config_params, raw_params, sizeof(*raw_params));
- /*
- * allocate memory for fault pixel table and copy the user
- * values to the table
- */
- if (!config_params->fault_pxl.enable)
- return 0;
-
- fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
- fpc_virtaddr = (unsigned int *)phys_to_virt(
- (unsigned long)fpc_physaddr);
- /*
- * Allocate memory for FPC table if current
- * FPC table buffer is not big enough to
- * accommodate FPC Number requested
- */
- if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
- if (fpc_physaddr != NULL) {
- free_pages((unsigned long)fpc_physaddr,
- get_order
- (config_params->fault_pxl.fp_num *
- FP_NUM_BYTES));
- }
-
- /* Allocate memory for FPC table */
- fpc_virtaddr =
- (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
- get_order(raw_params->
- fault_pxl.fp_num *
- FP_NUM_BYTES));
-
- if (fpc_virtaddr == NULL) {
- dev_dbg(ccdc_cfg.dev,
- "\nUnable to allocate memory for FPC");
- return -EFAULT;
- }
- fpc_physaddr =
- (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
- }
-
- /* Copy number of fault pixels and FPC table */
- config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
- if (copy_from_user(fpc_virtaddr,
- (void __user *)raw_params->fault_pxl.fpc_table_addr,
- config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
- dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
- return -EFAULT;
- }
- config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
- return 0;
-}
-
-static int ccdc_close(struct device *dev)
-{
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
-
- fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
-
- if (fpc_physaddr != NULL) {
- fpc_virtaddr = (unsigned int *)
- phys_to_virt((unsigned long)fpc_physaddr);
- free_pages((unsigned long)fpc_virtaddr,
- get_order(config_params->fault_pxl.fp_num *
- FP_NUM_BYTES));
- }
- return 0;
-}
-
-/*
- * ccdc_restore_defaults()
- * This function will write defaults to all CCDC registers
- */
-static void ccdc_restore_defaults(void)
-{
- int i;
-
- /* disable CCDC */
- ccdc_enable(0);
- /* set all registers to default value */
- for (i = 4; i <= 0x94; i += 4)
- regw(0, i);
- regw(CCDC_NO_CULLING, CCDC_CULLING);
- regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
-}
-
-static int ccdc_open(struct device *device)
-{
- ccdc_restore_defaults();
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_enable_vport(1);
- return 0;
-}
-
-static void ccdc_sbl_reset(void)
-{
- vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
-}
-
-/* Parameter operations */
-static int ccdc_set_params(void __user *params)
-{
- struct ccdc_config_params_raw ccdc_raw_params;
- int x;
-
- if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
- return -EINVAL;
-
- x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
- if (x) {
- dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"
- "ccdc params, %d\n", x);
- return -EFAULT;
- }
-
- if (!validate_ccdc_param(&ccdc_raw_params)) {
- if (!ccdc_update_raw_params(&ccdc_raw_params))
- return 0;
- }
- return -EINVAL;
-}
-
-/*
- * ccdc_config_ycbcr()
- * This function will configure CCDC for YCbCr video capture
- */
-void ccdc_config_ycbcr(void)
-{
- struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
- u32 syn_mode;
-
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
- /*
- * first restore the CCDC registers to default values
- * This is important since we assume default values to be set in
- * a lot of registers that we didn't touch
- */
- ccdc_restore_defaults();
-
- /*
- * configure pixel format, frame format, configure video frame
- * format, enable output to SDRAM, enable internal timing generator
- * and 8bit pack mode
- */
- syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
- CCDC_SYN_MODE_INPMOD_SHIFT) |
- ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
- CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
- CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
-
- /* setup BT.656 sync mode */
- if (params->bt656_enable) {
- regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
-
- /*
- * configure the FID, VD, HD pin polarity,
- * fld,hd pol positive, vd negative, 8-bit data
- */
- syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
- if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
- syn_mode |= CCDC_SYN_MODE_10BITS;
- else
- syn_mode |= CCDC_SYN_MODE_8BITS;
- } else {
- /* y/c external sync mode */
- syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
- CCDC_FID_POL_SHIFT) |
- ((params->hd_pol & CCDC_HD_POL_MASK) <<
- CCDC_HD_POL_SHIFT) |
- ((params->vd_pol & CCDC_VD_POL_MASK) <<
- CCDC_VD_POL_SHIFT));
- }
- regw(syn_mode, CCDC_SYN_MODE);
-
- /* configure video window */
- ccdc_setwin(&params->win, params->frm_fmt, 2);
-
- /*
- * configure the order of y cb cr in SDRAM, and disable latch
- * internal register on vsync
- */
- if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
- regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
- CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
- CCDC_CCDCFG);
- else
- regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
- CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
-
- /*
- * configure the horizontal line offset. This should be a
- * on 32 byte boundary. So clear LSB 5 bits
- */
- regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
-
- /* configure the memory line offset */
- if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
- /* two fields are interleaved in memory */
- regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
-
- ccdc_sbl_reset();
- dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
-}
-
-static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
-{
- u32 val;
-
- if (!bclamp->enable) {
- /* configure DCSub */
- val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
- regw(val, CCDC_DCSUB);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
- regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
- return;
- }
- /*
- * Configure gain, Start pixel, No of line to be avg,
- * No of pixel/line to be avg, & Enable the Black clamping
- */
- val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
- ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
- CCDC_BLK_ST_PXL_SHIFT) |
- ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
- CCDC_BLK_SAMPLE_LINE_SHIFT) |
- ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
- CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
- regw(val, CCDC_CLAMP);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
- /* If Black clamping is enable then make dcsub 0 */
- regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
-}
-
-static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
-{
- u32 val;
-
- val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
- ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_GB_COMP_SHIFT) |
- ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_GR_COMP_SHIFT) |
- ((bcomp->r & CCDC_BLK_COMP_MASK) <<
- CCDC_BLK_COMP_R_COMP_SHIFT));
- regw(val, CCDC_BLKCMP);
-}
-
-static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
-{
- u32 val;
-
- /* Initially disable FPC */
- val = CCDC_FPC_DISABLE;
- regw(val, CCDC_FPC);
-
- if (!fpc->enable)
- return;
-
- /* Configure Fault pixel if needed */
- regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
- (fpc->fpc_table_addr));
- /* Write the FPC params with FPC disable */
- val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
- regw(val, CCDC_FPC);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
- /* read the FPC register */
- val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
- regw(val, CCDC_FPC);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
-}
-
-/*
- * ccdc_config_raw()
- * This function will configure CCDC for Raw capture mode
- */
-void ccdc_config_raw(void)
-{
- struct ccdc_params_raw *params = &ccdc_cfg.bayer;
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int syn_mode = 0;
- unsigned int val;
-
- dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
-
- /* Reset CCDC */
- ccdc_restore_defaults();
-
- /* Disable latching function registers on VSYNC */
- regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
-
- /*
- * Configure the vertical sync polarity(SYN_MODE.VDPOL),
- * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
- * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
- * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
- * SDRAM, enable internal timing generator
- */
- syn_mode =
- (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
- ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
- ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
- ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
- ((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
- CCDC_DATA_SZ_SHIFT) |
- ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
- CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
-
- /* Enable and configure aLaw register if needed */
- if (config_params->alaw.enable) {
- val = ((config_params->alaw.gama_wd &
- CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
- regw(val, CCDC_ALAW);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
- }
-
- /* Configure video window */
- ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
-
- /* Configure Black Clamp */
- ccdc_config_black_clamp(&config_params->blk_clamp);
-
- /* Configure Black level compensation */
- ccdc_config_black_compense(&config_params->blk_comp);
-
- /* Configure Fault Pixel Correction */
- ccdc_config_fpc(&config_params->fault_pxl);
-
- /* If data size is 8 bit then pack the data */
- if ((config_params->data_sz == CCDC_DATA_8BITS) ||
- config_params->alaw.enable)
- syn_mode |= CCDC_DATA_PACK_ENABLE;
-
-#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
- /* enable video port */
- val = CCDC_ENABLE_VIDEO_PORT;
-#else
- /* disable video port */
- val = CCDC_DISABLE_VIDEO_PORT;
-#endif
-
- if (config_params->data_sz == CCDC_DATA_8BITS)
- val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
- << CCDC_FMTCFG_VPIN_SHIFT;
- else
- val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
- << CCDC_FMTCFG_VPIN_SHIFT;
- /* Write value in FMTCFG */
- regw(val, CCDC_FMTCFG);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
- /* Configure the color pattern according to mt9t001 sensor */
- regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
- /*
- * Configure Data formatter(Video port) pixel selection
- * (FMT_HORZ, FMT_VERT)
- */
- val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
- CCDC_FMT_HORZ_FMTSPH_SHIFT) |
- (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
- regw(val, CCDC_FMT_HORZ);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
- val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
- << CCDC_FMT_VERT_FMTSLV_SHIFT;
- if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
- val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
- else
- val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
-
- dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n",
- params->win.height);
- regw(val, CCDC_FMT_VERT);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
-
- dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
-
- /*
- * Configure Horizontal offset register. If pack 8 is enabled then
- * 1 pixel will take 1 byte
- */
- if ((config_params->data_sz == CCDC_DATA_8BITS) ||
- config_params->alaw.enable)
- regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
- CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
- else
- /* else one pixel will take 2 byte */
- regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
- CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
- CCDC_HSIZE_OFF);
-
- /* Set value for SDOFST */
- if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
- if (params->image_invert_enable) {
- /* For intelace inverse mode */
- regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
- }
-
- else {
- /* For intelace non inverse mode */
- regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
- }
- } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
- regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
- }
-
- /*
- * Configure video port pixel selection (VPOUT)
- * Here -1 is to make the height value less than FMT_VERT.FMTLNV
- */
- if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
- val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
- << CCDC_VP_OUT_VERT_NUM_SHIFT;
- else
- val =
- ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
- 1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
- CCDC_VP_OUT_VERT_NUM_SHIFT;
-
- val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
- << CCDC_VP_OUT_HORZ_NUM_SHIFT;
- val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
- regw(val, CCDC_VP_OUT);
-
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
- regw(syn_mode, CCDC_SYN_MODE);
- dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
-
- ccdc_sbl_reset();
- dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
- ccdc_readregs();
-}
-
-static int ccdc_configure(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_config_raw();
- else
- ccdc_config_ycbcr();
- return 0;
-}
-
-static int ccdc_set_buftype(enum ccdc_buftype buf_type)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.buf_type = buf_type;
- else
- ccdc_cfg.ycbcr.buf_type = buf_type;
- return 0;
-}
-
-static enum ccdc_buftype ccdc_get_buftype(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- return ccdc_cfg.bayer.buf_type;
- return ccdc_cfg.ycbcr.buf_type;
-}
-
-static int ccdc_enum_pix(u32 *pix, int i)
-{
- int ret = -EINVAL;
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
- *pix = ccdc_raw_bayer_pix_formats[i];
- ret = 0;
- }
- } else {
- if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
- *pix = ccdc_raw_yuv_pix_formats[i];
- ret = 0;
- }
- }
- return ret;
-}
-
-static int ccdc_set_pixel_format(u32 pixfmt)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
- if (pixfmt == V4L2_PIX_FMT_SBGGR8)
- ccdc_cfg.bayer.config_params.alaw.enable = 1;
- else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
- return -EINVAL;
- } else {
- if (pixfmt == V4L2_PIX_FMT_YUYV)
- ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
- else if (pixfmt == V4L2_PIX_FMT_UYVY)
- ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
- else
- return -EINVAL;
- }
- return 0;
-}
-
-static u32 ccdc_get_pixel_format(void)
-{
- struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
- u32 pixfmt;
-
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- if (alaw->enable)
- pixfmt = V4L2_PIX_FMT_SBGGR8;
- else
- pixfmt = V4L2_PIX_FMT_SBGGR16;
- else {
- if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
- pixfmt = V4L2_PIX_FMT_YUYV;
- else
- pixfmt = V4L2_PIX_FMT_UYVY;
- }
- return pixfmt;
-}
-
-static int ccdc_set_image_window(struct v4l2_rect *win)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.win = *win;
- else
- ccdc_cfg.ycbcr.win = *win;
- return 0;
-}
-
-static void ccdc_get_image_window(struct v4l2_rect *win)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- *win = ccdc_cfg.bayer.win;
- else
- *win = ccdc_cfg.ycbcr.win;
-}
-
-static unsigned int ccdc_get_line_length(void)
-{
- struct ccdc_config_params_raw *config_params =
- &ccdc_cfg.bayer.config_params;
- unsigned int len;
-
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
- if ((config_params->alaw.enable) ||
- (config_params->data_sz == CCDC_DATA_8BITS))
- len = ccdc_cfg.bayer.win.width;
- else
- len = ccdc_cfg.bayer.win.width * 2;
- } else
- len = ccdc_cfg.ycbcr.win.width * 2;
- return ALIGN(len, 32);
-}
-
-static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- ccdc_cfg.bayer.frm_fmt = frm_fmt;
- else
- ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
- return 0;
-}
-
-static enum ccdc_frmfmt ccdc_get_frame_format(void)
-{
- if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
- return ccdc_cfg.bayer.frm_fmt;
- else
- return ccdc_cfg.ycbcr.frm_fmt;
-}
-
-static int ccdc_getfid(void)
-{
- return (regr(CCDC_SYN_MODE) >> 15) & 1;
-}
-
-/* misc operations */
-static inline void ccdc_setfbaddr(unsigned long addr)
-{
- regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
-}
-
-static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
-{
- ccdc_cfg.if_type = params->if_type;
-
- switch (params->if_type) {
- case VPFE_BT656:
- case VPFE_YCBCR_SYNC_16:
- case VPFE_YCBCR_SYNC_8:
- case VPFE_BT656_10BIT:
- ccdc_cfg.ycbcr.vd_pol = params->vdpol;
- ccdc_cfg.ycbcr.hd_pol = params->hdpol;
- break;
- default:
- /* TODO add support for raw bayer here */
- return -EINVAL;
- }
- return 0;
-}
-
-static void ccdc_save_context(void)
-{
- ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
- ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
- ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
- ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
- ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
- ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
- ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
- ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
- ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
- ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
- ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
- ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
- ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
- ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
- ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
- ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
- ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
- ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
- ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
- ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
- ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
- ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
- ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
- ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
- ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
- ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
- ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
- ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
- ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
- ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
- ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
- ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
- ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
- ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
- ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
- ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
- ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
-}
-
-static void ccdc_restore_context(void)
-{
- regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
- regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
- regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
- regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
- regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
- regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
- regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
- regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
- regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
- regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
- regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
- regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
- regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
- regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
- regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
- regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
- regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
- regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
- regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
- regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
- regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
- regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
- regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
- regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
- regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
- regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
- regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
- regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
- regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
- regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
- regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
- regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
- regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
- regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
- regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
- regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
- regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
-}
-static struct ccdc_hw_device ccdc_hw_dev = {
- .name = "DM6446 CCDC",
- .owner = THIS_MODULE,
- .hw_ops = {
- .open = ccdc_open,
- .close = ccdc_close,
- .reset = ccdc_sbl_reset,
- .enable = ccdc_enable,
- .set_hw_if_params = ccdc_set_hw_if_params,
- .set_params = ccdc_set_params,
- .configure = ccdc_configure,
- .set_buftype = ccdc_set_buftype,
- .get_buftype = ccdc_get_buftype,
- .enum_pix = ccdc_enum_pix,
- .set_pixel_format = ccdc_set_pixel_format,
- .get_pixel_format = ccdc_get_pixel_format,
- .set_frame_format = ccdc_set_frame_format,
- .get_frame_format = ccdc_get_frame_format,
- .set_image_window = ccdc_set_image_window,
- .get_image_window = ccdc_get_image_window,
- .get_line_length = ccdc_get_line_length,
- .setfbaddr = ccdc_setfbaddr,
- .getfid = ccdc_getfid,
- },
-};
-
-static int __init dm644x_ccdc_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int status = 0;
-
- /*
- * first try to register with vpfe. If not correct platform, then we
- * don't have to iomap
- */
- status = vpfe_register_ccdc_device(&ccdc_hw_dev);
- if (status < 0)
- return status;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- status = -ENODEV;
- goto fail_nores;
- }
-
- res = request_mem_region(res->start, resource_size(res), res->name);
- if (!res) {
- status = -EBUSY;
- goto fail_nores;
- }
-
- ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
- if (!ccdc_cfg.base_addr) {
- status = -ENOMEM;
- goto fail_nomem;
- }
-
- /* Get and enable Master clock */
- ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(ccdc_cfg.mclk)) {
- status = PTR_ERR(ccdc_cfg.mclk);
- goto fail_nomap;
- }
- if (clk_enable(ccdc_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Get and enable Slave clock */
- ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
- if (IS_ERR(ccdc_cfg.sclk)) {
- status = PTR_ERR(ccdc_cfg.sclk);
- goto fail_mclk;
- }
- if (clk_enable(ccdc_cfg.sclk)) {
- status = -ENODEV;
- goto fail_sclk;
- }
- ccdc_cfg.dev = &pdev->dev;
- printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
- return 0;
-fail_sclk:
- clk_put(ccdc_cfg.sclk);
-fail_mclk:
- clk_put(ccdc_cfg.mclk);
-fail_nomap:
- iounmap(ccdc_cfg.base_addr);
-fail_nomem:
- release_mem_region(res->start, resource_size(res));
-fail_nores:
- vpfe_unregister_ccdc_device(&ccdc_hw_dev);
- return status;
-}
-
-static int dm644x_ccdc_remove(struct platform_device *pdev)
-{
- struct resource *res;
-
- clk_put(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.sclk);
- iounmap(ccdc_cfg.base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
- vpfe_unregister_ccdc_device(&ccdc_hw_dev);
- return 0;
-}
-
-static int dm644x_ccdc_suspend(struct device *dev)
-{
- /* Save CCDC context */
- ccdc_save_context();
- /* Disable CCDC */
- ccdc_enable(0);
- /* Disable both master and slave clock */
- clk_disable(ccdc_cfg.mclk);
- clk_disable(ccdc_cfg.sclk);
-
- return 0;
-}
-
-static int dm644x_ccdc_resume(struct device *dev)
-{
- /* Enable both master and slave clock */
- clk_enable(ccdc_cfg.mclk);
- clk_enable(ccdc_cfg.sclk);
- /* Restore CCDC context */
- ccdc_restore_context();
-
- return 0;
-}
-
-static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
- .suspend = dm644x_ccdc_suspend,
- .resume = dm644x_ccdc_resume,
-};
-
-static struct platform_driver dm644x_ccdc_driver = {
- .driver = {
- .name = "dm644x_ccdc",
- .owner = THIS_MODULE,
- .pm = &dm644x_ccdc_pm_ops,
- },
- .remove = __devexit_p(dm644x_ccdc_remove),
- .probe = dm644x_ccdc_probe,
-};
-
-module_platform_driver(dm644x_ccdc_driver);
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c
deleted file mode 100644
index 5278fe7d6d0c..000000000000
--- a/drivers/media/video/davinci/isif.c
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Texas Instruments Inc
- *
- * 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
- *
- * Image Sensor Interface (ISIF) driver
- *
- * This driver is for configuring the ISIF IP available on DM365 or any other
- * TI SoCs. This is used for capturing yuv or bayer video or image data
- * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
- * and DM6446, but with enhanced or additional ip blocks. The driver
- * configures the ISIF upon commands from the vpfe bridge driver through
- * ccdc_hw_device interface.
- *
- * TODO: 1) Raw bayer parameter settings and bayer capture
- * 2) Add support for control ioctl
- */
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/videodev2.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-#include <mach/mux.h>
-
-#include <media/davinci/isif.h>
-#include <media/davinci/vpss.h>
-
-#include "isif_regs.h"
-#include "ccdc_hw_device.h"
-
-/* Defaults for module configuration parameters */
-static struct isif_config_params_raw isif_config_defaults = {
- .linearize = {
- .en = 0,
- .corr_shft = ISIF_NO_SHIFT,
- .scale_fact = {1, 0},
- },
- .df_csc = {
- .df_or_csc = 0,
- .csc = {
- .en = 0,
- },
- },
- .dfc = {
- .en = 0,
- },
- .bclamp = {
- .en = 0,
- },
- .gain_offset = {
- .gain = {
- .r_ye = {1, 0},
- .gr_cy = {1, 0},
- .gb_g = {1, 0},
- .b_mg = {1, 0},
- },
- },
- .culling = {
- .hcpat_odd = 0xff,
- .hcpat_even = 0xff,
- .vcpat = 0xff,
- },
- .compress = {
- .alg = ISIF_ALAW,
- },
-};
-
-/* ISIF operation configuration */
-static struct isif_oper_config {
- struct device *dev;
- enum vpfe_hw_if_type if_type;
- struct isif_ycbcr_config ycbcr;
- struct isif_params_raw bayer;
- enum isif_data_pack data_pack;
- /* Master clock */
- struct clk *mclk;
- /* ISIF base address */
- void __iomem *base_addr;
- /* ISIF Linear Table 0 */
- void __iomem *linear_tbl0_addr;
- /* ISIF Linear Table 1 */
- void __iomem *linear_tbl1_addr;
-} isif_cfg = {
- .ycbcr = {
- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
- .frm_fmt = CCDC_FRMFMT_INTERLACED,
- .win = ISIF_WIN_NTSC,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .pix_order = CCDC_PIXORDER_CBYCRY,
- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
- },
- .bayer = {
- .pix_fmt = CCDC_PIXFMT_RAW,
- .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
- .win = ISIF_WIN_VGA,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .gain = {
- .r_ye = {1, 0},
- .gr_cy = {1, 0},
- .gb_g = {1, 0},
- .b_mg = {1, 0},
- },
- .cfa_pat = ISIF_CFA_PAT_MOSAIC,
- .data_msb = ISIF_BIT_MSB_11,
- .config_params = {
- .data_shift = ISIF_NO_SHIFT,
- .col_pat_field0 = {
- .olop = ISIF_GREEN_BLUE,
- .olep = ISIF_BLUE,
- .elop = ISIF_RED,
- .elep = ISIF_GREEN_RED,
- },
- .col_pat_field1 = {
- .olop = ISIF_GREEN_BLUE,
- .olep = ISIF_BLUE,
- .elop = ISIF_RED,
- .elep = ISIF_GREEN_RED,
- },
- .test_pat_gen = 0,
- },
- },
- .data_pack = ISIF_DATA_PACK8,
-};
-
-/* Raw Bayer formats */
-static const u32 isif_raw_bayer_pix_formats[] = {
- V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
-
-/* Raw YUV formats */
-static const u32 isif_raw_yuv_pix_formats[] = {
- V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
-
-/* register access routines */
-static inline u32 regr(u32 offset)
-{
- return __raw_readl(isif_cfg.base_addr + offset);
-}
-
-static inline void regw(u32 val, u32 offset)
-{
- __raw_writel(val, isif_cfg.base_addr + offset);
-}
-
-/* reg_modify() - read, modify and write register */
-static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
-{
- u32 new_val = (regr(offset) & ~mask) | (val & mask);
-
- regw(new_val, offset);
- return new_val;
-}
-
-static inline void regw_lin_tbl(u32 val, u32 offset, int i)
-{
- if (!i)
- __raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
- else
- __raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
-}
-
-static void isif_disable_all_modules(void)
-{
- /* disable BC */
- regw(0, CLAMPCFG);
- /* disable vdfc */
- regw(0, DFCCTL);
- /* disable CSC */
- regw(0, CSCCTL);
- /* disable linearization */
- regw(0, LINCFG0);
- /* disable other modules here as they are supported */
-}
-
-static void isif_enable(int en)
-{
- if (!en) {
- /* Before disable isif, disable all ISIF modules */
- isif_disable_all_modules();
- /*
- * wait for next VD. Assume lowest scan rate is 12 Hz. So
- * 100 msec delay is good enough
- */
- msleep(100);
- }
- reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
-}
-
-static void isif_enable_output_to_sdram(int en)
-{
- reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
-}
-
-static void isif_config_culling(struct isif_cul *cul)
-{
- u32 val;
-
- /* Horizontal pattern */
- val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
- regw(val, CULH);
-
- /* vertical pattern */
- regw(cul->vcpat, CULV);
-
- /* LPF */
- reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
- cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
-}
-
-static void isif_config_gain_offset(void)
-{
- struct isif_gain_offsets_adj *gain_off_p =
- &isif_cfg.bayer.config_params.gain_offset;
- u32 val;
-
- val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
- (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
- (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
- (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
- (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
- (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
-
- reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
-
- val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
- gain_off_p->gain.r_ye.decimal;
- regw(val, CRGAIN);
-
- val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
- gain_off_p->gain.gr_cy.decimal;
- regw(val, CGRGAIN);
-
- val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
- gain_off_p->gain.gb_g.decimal;
- regw(val, CGBGAIN);
-
- val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
- gain_off_p->gain.b_mg.decimal;
- regw(val, CBGAIN);
-
- regw(gain_off_p->offset, COFSTA);
-}
-
-static void isif_restore_defaults(void)
-{
- enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
-
- dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
- isif_cfg.bayer.config_params = isif_config_defaults;
- /* Enable clock to ISIF, IPIPEIF and BL */
- vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
- vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
- vpss_enable_clock(VPSS_BL_CLOCK, 1);
- /* Set default offset and gain */
- isif_config_gain_offset();
- vpss_select_ccdc_source(source);
- dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
-}
-
-static int isif_open(struct device *device)
-{
- isif_restore_defaults();
- return 0;
-}
-
-/* This function will configure the window size to be capture in ISIF reg */
-static void isif_setwin(struct v4l2_rect *image_win,
- enum ccdc_frmfmt frm_fmt, int ppc)
-{
- int horz_start, horz_nr_pixels;
- int vert_start, vert_nr_lines;
- int mid_img = 0;
-
- dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
- /*
- * ppc - per pixel count. indicates how many pixels per cell
- * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
- * raw capture this is 1
- */
- horz_start = image_win->left << (ppc - 1);
- horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
-
- /* Writing the horizontal info into the registers */
- regw(horz_start & START_PX_HOR_MASK, SPH);
- regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
- vert_start = image_win->top;
-
- if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
- vert_nr_lines = (image_win->height >> 1) - 1;
- vert_start >>= 1;
- /* To account for VD since line 0 doesn't have any data */
- vert_start += 1;
- } else {
- /* To account for VD since line 0 doesn't have any data */
- vert_start += 1;
- vert_nr_lines = image_win->height - 1;
- /* configure VDINT0 and VDINT1 */
- mid_img = vert_start + (image_win->height / 2);
- regw(mid_img, VDINT1);
- }
-
- regw(0, VDINT0);
- regw(vert_start & START_VER_ONE_MASK, SLV0);
- regw(vert_start & START_VER_TWO_MASK, SLV1);
- regw(vert_nr_lines & NUM_LINES_VER, LNV);
-}
-
-static void isif_config_bclamp(struct isif_black_clamp *bc)
-{
- u32 val;
-
- /*
- * DC Offset is always added to image data irrespective of bc enable
- * status
- */
- regw(bc->dc_offset, CLDCOFST);
-
- if (bc->en) {
- val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
-
- /* Enable BC and horizontal clamp caculation paramaters */
- val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
-
- regw(val, CLAMPCFG);
-
- if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
- /*
- * Window count for calculation
- * Base window selection
- * pixel limit
- * Horizontal size of window
- * vertical size of the window
- * Horizontal start position of the window
- * Vertical start position of the window
- */
- val = bc->horz.win_count_calc |
- ((!!bc->horz.base_win_sel_calc) <<
- ISIF_HORZ_BC_WIN_SEL_SHIFT) |
- ((!!bc->horz.clamp_pix_limit) <<
- ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
- (bc->horz.win_h_sz_calc <<
- ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
- (bc->horz.win_v_sz_calc <<
- ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
- regw(val, CLHWIN0);
-
- regw(bc->horz.win_start_h_calc, CLHWIN1);
- regw(bc->horz.win_start_v_calc, CLHWIN2);
- }
-
- /* vertical clamp caculation paramaters */
-
- /* Reset clamp value sel for previous line */
- val |=
- (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
- (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
- regw(val, CLVWIN0);
-
- /* Optical Black horizontal start position */
- regw(bc->vert.ob_start_h, CLVWIN1);
- /* Optical Black vertical start position */
- regw(bc->vert.ob_start_v, CLVWIN2);
- /* Optical Black vertical size for calculation */
- regw(bc->vert.ob_v_sz_calc, CLVWIN3);
- /* Vertical start position for BC subtraction */
- regw(bc->vert_start_sub, CLSV);
- }
-}
-
-static void isif_config_linearization(struct isif_linearize *linearize)
-{
- u32 val, i;
-
- if (!linearize->en) {
- regw(0, LINCFG0);
- return;
- }
-
- /* shift value for correction & enable linearization (set lsb) */
- val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
- regw(val, LINCFG0);
-
- /* Scale factor */
- val = ((!!linearize->scale_fact.integer) <<
- ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
- linearize->scale_fact.decimal;
- regw(val, LINCFG1);
-
- for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
- if (i % 2)
- regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
- else
- regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
- }
-}
-
-static int isif_config_dfc(struct isif_dfc *vdfc)
-{
- /* initialize retries to loop for max ~ 250 usec */
- u32 val, count, retries = loops_per_jiffy / (4000/HZ);
- int i;
-
- if (!vdfc->en)
- return 0;
-
- /* Correction mode */
- val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
-
- /* Correct whole line or partial */
- if (vdfc->corr_whole_line)
- val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
-
- /* level shift value */
- val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
-
- regw(val, DFCCTL);
-
- /* Defect saturation level */
- regw(vdfc->def_sat_level, VDFSATLV);
-
- regw(vdfc->table[0].pos_vert, DFCMEM0);
- regw(vdfc->table[0].pos_horz, DFCMEM1);
- if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
- vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
- regw(vdfc->table[0].level_at_pos, DFCMEM2);
- regw(vdfc->table[0].level_up_pixels, DFCMEM3);
- regw(vdfc->table[0].level_low_pixels, DFCMEM4);
- }
-
- /* set DFCMARST and set DFCMWR */
- val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
- regw(val, DFCMEMCTL);
-
- count = retries;
- while (count && (regr(DFCMEMCTL) & 0x1))
- count--;
-
- if (!count) {
- dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
- return -1;
- }
-
- for (i = 1; i < vdfc->num_vdefects; i++) {
- regw(vdfc->table[i].pos_vert, DFCMEM0);
- regw(vdfc->table[i].pos_horz, DFCMEM1);
- if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
- vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
- regw(vdfc->table[i].level_at_pos, DFCMEM2);
- regw(vdfc->table[i].level_up_pixels, DFCMEM3);
- regw(vdfc->table[i].level_low_pixels, DFCMEM4);
- }
- val = regr(DFCMEMCTL);
- /* clear DFCMARST and set DFCMWR */
- val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
- val |= 1;
- regw(val, DFCMEMCTL);
-
- count = retries;
- while (count && (regr(DFCMEMCTL) & 0x1))
- count--;
-
- if (!count) {
- dev_err(isif_cfg.dev,
- "defect table write timeout !!!\n");
- return -1;
- }
- }
- if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
- /* Extra cycle needed */
- regw(0, DFCMEM0);
- regw(0x1FFF, DFCMEM1);
- regw(1, DFCMEMCTL);
- }
-
- /* enable VDFC */
- reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
- DFCCTL);
- return 0;
-}
-
-static void isif_config_csc(struct isif_df_csc *df_csc)
-{
- u32 val1 = 0, val2 = 0, i;
-
- if (!df_csc->csc.en) {
- regw(0, CSCCTL);
- return;
- }
- for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
- if ((i % 2) == 0) {
- /* CSCM - LSB */
- val1 = (df_csc->csc.coeff[i].integer <<
- ISIF_CSC_COEF_INTEG_SHIFT) |
- df_csc->csc.coeff[i].decimal;
- } else {
-
- /* CSCM - MSB */
- val2 = (df_csc->csc.coeff[i].integer <<
- ISIF_CSC_COEF_INTEG_SHIFT) |
- df_csc->csc.coeff[i].decimal;
- val2 <<= ISIF_CSCM_MSB_SHIFT;
- val2 |= val1;
- regw(val2, (CSCM0 + ((i - 1) << 1)));
- }
- }
-
- /* program the active area */
- regw(df_csc->start_pix, FMTSPH);
- /*
- * one extra pixel as required for CSC. Actually number of
- * pixel - 1 should be configured in this register. So we
- * need to subtract 1 before writing to FMTSPH, but we will
- * not do this since csc requires one extra pixel
- */
- regw(df_csc->num_pixels, FMTLNH);
- regw(df_csc->start_line, FMTSLV);
- /*
- * one extra line as required for CSC. See reason documented for
- * num_pixels
- */
- regw(df_csc->num_lines, FMTLNV);
-
- /* Enable CSC */
- regw(1, CSCCTL);
-}
-
-static int isif_config_raw(void)
-{
- struct isif_params_raw *params = &isif_cfg.bayer;
- struct isif_config_params_raw *module_params =
- &isif_cfg.bayer.config_params;
- struct vpss_pg_frame_size frame_size;
- struct vpss_sync_pol sync;
- u32 val;
-
- dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
-
- /*
- * Configure CCDCFG register:-
- * Set CCD Not to swap input since input is RAW data
- * Set FID detection function to Latch at V-Sync
- * Set WENLOG - isif valid area
- * Set TRGSEL
- * Set EXTRG
- * Packed to 8 or 16 bits
- */
-
- val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
- ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
- ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
-
- dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
- regw(val, CCDCFG);
-
- /*
- * Configure the vertical sync polarity(MODESET.VDPOL)
- * Configure the horizontal sync polarity (MODESET.HDPOL)
- * Configure frame id polarity (MODESET.FLDPOL)
- * Configure data polarity
- * Configure External WEN Selection
- * Configure frame format(progressive or interlace)
- * Configure pixel format (Input mode)
- * Configure the data shift
- */
-
- val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
- (params->hd_pol << ISIF_HD_POL_SHIFT) |
- (params->fid_pol << ISIF_FID_POL_SHIFT) |
- (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
- (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
- (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
- (params->pix_fmt << ISIF_INPUT_SHIFT) |
- (params->config_params.data_shift << ISIF_DATASFT_SHIFT);
-
- regw(val, MODESET);
- dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
-
- /*
- * Configure GAMMAWD register
- * CFA pattern setting
- */
- val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
-
- /* Gamma msb */
- if (module_params->compress.alg == ISIF_ALAW)
- val |= ISIF_ALAW_ENABLE;
-
- val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
- regw(val, CGAMMAWD);
-
- /* Configure DPCM compression settings */
- if (module_params->compress.alg == ISIF_DPCM) {
- val = BIT(ISIF_DPCM_EN_SHIFT) |
- (module_params->compress.pred <<
- ISIF_DPCM_PREDICTOR_SHIFT);
- }
-
- regw(val, MISC);
-
- /* Configure Gain & Offset */
- isif_config_gain_offset();
-
- /* Configure Color pattern */
- val = (params->config_params.col_pat_field0.olop) |
- (params->config_params.col_pat_field0.olep << 2) |
- (params->config_params.col_pat_field0.elop << 4) |
- (params->config_params.col_pat_field0.elep << 6) |
- (params->config_params.col_pat_field1.olop << 8) |
- (params->config_params.col_pat_field1.olep << 10) |
- (params->config_params.col_pat_field1.elop << 12) |
- (params->config_params.col_pat_field1.elep << 14);
- regw(val, CCOLP);
- dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
-
- /* Configure HSIZE register */
- val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
-
- /* calculate line offset in 32 bytes based on pack value */
- if (isif_cfg.data_pack == ISIF_PACK_8BIT)
- val |= ((params->win.width + 31) >> 5);
- else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
- val |= (((params->win.width +
- (params->win.width >> 2)) + 31) >> 5);
- else
- val |= (((params->win.width * 2) + 31) >> 5);
- regw(val, HSIZE);
-
- /* Configure SDOFST register */
- if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
- if (params->image_invert_en) {
- /* For interlace inverse mode */
- regw(0x4B6D, SDOFST);
- dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
- } else {
- /* For interlace non inverse mode */
- regw(0x0B6D, SDOFST);
- dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
- }
- } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
- if (params->image_invert_en) {
- /* For progressive inverse mode */
- regw(0x4000, SDOFST);
- dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
- } else {
- /* For progressive non inverse mode */
- regw(0x0000, SDOFST);
- dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
- }
- }
-
- /* Configure video window */
- isif_setwin(&params->win, params->frm_fmt, 1);
-
- /* Configure Black Clamp */
- isif_config_bclamp(&module_params->bclamp);
-
- /* Configure Vertical Defection Pixel Correction */
- if (isif_config_dfc(&module_params->dfc) < 0)
- return -EFAULT;
-
- if (!module_params->df_csc.df_or_csc)
- /* Configure Color Space Conversion */
- isif_config_csc(&module_params->df_csc);
-
- isif_config_linearization(&module_params->linearize);
-
- /* Configure Culling */
- isif_config_culling(&module_params->culling);
-
- /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
- regw(module_params->horz_offset, DATAHOFST);
- regw(module_params->vert_offset, DATAVOFST);
-
- /* Setup test pattern if enabled */
- if (params->config_params.test_pat_gen) {
- /* Use the HD/VD pol settings from user */
- sync.ccdpg_hdpol = params->hd_pol;
- sync.ccdpg_vdpol = params->vd_pol;
- dm365_vpss_set_sync_pol(sync);
- frame_size.hlpfr = isif_cfg.bayer.win.width;
- frame_size.pplen = isif_cfg.bayer.win.height;
- dm365_vpss_set_pg_frame_size(frame_size);
- vpss_select_ccdc_source(VPSS_PGLPBK);
- }
-
- dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
- return 0;
-}
-
-static int isif_set_buftype(enum ccdc_buftype buf_type)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- isif_cfg.bayer.buf_type = buf_type;
- else
- isif_cfg.ycbcr.buf_type = buf_type;
-
- return 0;
-
-}
-static enum ccdc_buftype isif_get_buftype(void)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- return isif_cfg.bayer.buf_type;
-
- return isif_cfg.ycbcr.buf_type;
-}
-
-static int isif_enum_pix(u32 *pix, int i)
-{
- int ret = -EINVAL;
-
- if (isif_cfg.if_type == VPFE_RAW_BAYER) {
- if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
- *pix = isif_raw_bayer_pix_formats[i];
- ret = 0;
- }
- } else {
- if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
- *pix = isif_raw_yuv_pix_formats[i];
- ret = 0;
- }
- }
-
- return ret;
-}
-
-static int isif_set_pixel_format(unsigned int pixfmt)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER) {
- if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
- if ((isif_cfg.bayer.config_params.compress.alg !=
- ISIF_ALAW) &&
- (isif_cfg.bayer.config_params.compress.alg !=
- ISIF_DPCM)) {
- dev_dbg(isif_cfg.dev,
- "Either configure A-Law or DPCM\n");
- return -EINVAL;
- }
- isif_cfg.data_pack = ISIF_PACK_8BIT;
- } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
- isif_cfg.bayer.config_params.compress.alg =
- ISIF_NO_COMPRESSION;
- isif_cfg.data_pack = ISIF_PACK_16BIT;
- } else
- return -EINVAL;
- isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
- } else {
- if (pixfmt == V4L2_PIX_FMT_YUYV)
- isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
- else if (pixfmt == V4L2_PIX_FMT_UYVY)
- isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
- else
- return -EINVAL;
- isif_cfg.data_pack = ISIF_PACK_8BIT;
- }
- return 0;
-}
-
-static u32 isif_get_pixel_format(void)
-{
- u32 pixfmt;
-
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
- isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
- pixfmt = V4L2_PIX_FMT_SBGGR8;
- else
- pixfmt = V4L2_PIX_FMT_SBGGR16;
- else {
- if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
- pixfmt = V4L2_PIX_FMT_YUYV;
- else
- pixfmt = V4L2_PIX_FMT_UYVY;
- }
- return pixfmt;
-}
-
-static int isif_set_image_window(struct v4l2_rect *win)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER) {
- isif_cfg.bayer.win.top = win->top;
- isif_cfg.bayer.win.left = win->left;
- isif_cfg.bayer.win.width = win->width;
- isif_cfg.bayer.win.height = win->height;
- } else {
- isif_cfg.ycbcr.win.top = win->top;
- isif_cfg.ycbcr.win.left = win->left;
- isif_cfg.ycbcr.win.width = win->width;
- isif_cfg.ycbcr.win.height = win->height;
- }
- return 0;
-}
-
-static void isif_get_image_window(struct v4l2_rect *win)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- *win = isif_cfg.bayer.win;
- else
- *win = isif_cfg.ycbcr.win;
-}
-
-static unsigned int isif_get_line_length(void)
-{
- unsigned int len;
-
- if (isif_cfg.if_type == VPFE_RAW_BAYER) {
- if (isif_cfg.data_pack == ISIF_PACK_8BIT)
- len = ((isif_cfg.bayer.win.width));
- else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
- len = (((isif_cfg.bayer.win.width * 2) +
- (isif_cfg.bayer.win.width >> 2)));
- else
- len = (((isif_cfg.bayer.win.width * 2)));
- } else
- len = (((isif_cfg.ycbcr.win.width * 2)));
- return ALIGN(len, 32);
-}
-
-static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- isif_cfg.bayer.frm_fmt = frm_fmt;
- else
- isif_cfg.ycbcr.frm_fmt = frm_fmt;
- return 0;
-}
-static enum ccdc_frmfmt isif_get_frame_format(void)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- return isif_cfg.bayer.frm_fmt;
- return isif_cfg.ycbcr.frm_fmt;
-}
-
-static int isif_getfid(void)
-{
- return (regr(MODESET) >> 15) & 0x1;
-}
-
-/* misc operations */
-static void isif_setfbaddr(unsigned long addr)
-{
- regw((addr >> 21) & 0x07ff, CADU);
- regw((addr >> 5) & 0x0ffff, CADL);
-}
-
-static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
-{
- isif_cfg.if_type = params->if_type;
-
- switch (params->if_type) {
- case VPFE_BT656:
- case VPFE_BT656_10BIT:
- case VPFE_YCBCR_SYNC_8:
- isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
- isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
- break;
- case VPFE_BT1120:
- case VPFE_YCBCR_SYNC_16:
- isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
- isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
- break;
- case VPFE_RAW_BAYER:
- isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
- break;
- default:
- dev_dbg(isif_cfg.dev, "Invalid interface type\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* This function will configure ISIF for YCbCr parameters. */
-static int isif_config_ycbcr(void)
-{
- struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
- struct vpss_pg_frame_size frame_size;
- u32 modeset = 0, ccdcfg = 0;
- struct vpss_sync_pol sync;
-
- dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
-
- /* configure pixel format or input mode */
- modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
- (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
- (params->fid_pol << ISIF_FID_POL_SHIFT) |
- (params->hd_pol << ISIF_HD_POL_SHIFT) |
- (params->vd_pol << ISIF_VD_POL_SHIFT);
-
- /* pack the data to 8-bit ISIFCFG */
- switch (isif_cfg.if_type) {
- case VPFE_BT656:
- if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
- dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
- regw(3, REC656IF);
- ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
- break;
- case VPFE_BT656_10BIT:
- if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
- dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- /* setup BT.656, embedded sync */
- regw(3, REC656IF);
- /* enable 10 bit mode in ccdcfg */
- ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
- ISIF_BW656_ENABLE;
- break;
- case VPFE_BT1120:
- if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
- dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- regw(3, REC656IF);
- break;
-
- case VPFE_YCBCR_SYNC_8:
- ccdcfg |= ISIF_DATA_PACK8;
- ccdcfg |= ISIF_YCINSWP_YCBCR;
- if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
- dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- break;
- case VPFE_YCBCR_SYNC_16:
- if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
- dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
- return -EINVAL;
- }
- break;
- default:
- /* should never come here */
- dev_dbg(isif_cfg.dev, "Invalid interface type\n");
- return -EINVAL;
- }
-
- regw(modeset, MODESET);
-
- /* Set up pix order */
- ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
-
- regw(ccdcfg, CCDCFG);
-
- /* configure video window */
- if ((isif_cfg.if_type == VPFE_BT1120) ||
- (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
- isif_setwin(&params->win, params->frm_fmt, 1);
- else
- isif_setwin(&params->win, params->frm_fmt, 2);
-
- /*
- * configure the horizontal line offset
- * this is done by rounding up width to a multiple of 16 pixels
- * and multiply by two to account for y:cb:cr 4:2:2 data
- */
- regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
-
- /* configure the memory line offset */
- if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
- (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
- /* two fields are interleaved in memory */
- regw(0x00000249, SDOFST);
-
- /* Setup test pattern if enabled */
- if (isif_cfg.bayer.config_params.test_pat_gen) {
- sync.ccdpg_hdpol = params->hd_pol;
- sync.ccdpg_vdpol = params->vd_pol;
- dm365_vpss_set_sync_pol(sync);
- dm365_vpss_set_pg_frame_size(frame_size);
- }
- return 0;
-}
-
-static int isif_configure(void)
-{
- if (isif_cfg.if_type == VPFE_RAW_BAYER)
- return isif_config_raw();
- return isif_config_ycbcr();
-}
-
-static int isif_close(struct device *device)
-{
- /* copy defaults to module params */
- isif_cfg.bayer.config_params = isif_config_defaults;
- return 0;
-}
-
-static struct ccdc_hw_device isif_hw_dev = {
- .name = "ISIF",
- .owner = THIS_MODULE,
- .hw_ops = {
- .open = isif_open,
- .close = isif_close,
- .enable = isif_enable,
- .enable_out_to_sdram = isif_enable_output_to_sdram,
- .set_hw_if_params = isif_set_hw_if_params,
- .configure = isif_configure,
- .set_buftype = isif_set_buftype,
- .get_buftype = isif_get_buftype,
- .enum_pix = isif_enum_pix,
- .set_pixel_format = isif_set_pixel_format,
- .get_pixel_format = isif_get_pixel_format,
- .set_frame_format = isif_set_frame_format,
- .get_frame_format = isif_get_frame_format,
- .set_image_window = isif_set_image_window,
- .get_image_window = isif_get_image_window,
- .get_line_length = isif_get_line_length,
- .setfbaddr = isif_setfbaddr,
- .getfid = isif_getfid,
- },
-};
-
-static int __init isif_probe(struct platform_device *pdev)
-{
- void (*setup_pinmux)(void);
- struct resource *res;
- void *__iomem addr;
- int status = 0, i;
-
- /*
- * first try to register with vpfe. If not correct platform, then we
- * don't have to iomap
- */
- status = vpfe_register_ccdc_device(&isif_hw_dev);
- if (status < 0)
- return status;
-
- /* Get and enable Master clock */
- isif_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(isif_cfg.mclk)) {
- status = PTR_ERR(isif_cfg.mclk);
- goto fail_mclk;
- }
- if (clk_enable(isif_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Platform data holds setup_pinmux function ptr */
- if (NULL == pdev->dev.platform_data) {
- status = -ENODEV;
- goto fail_mclk;
- }
- setup_pinmux = pdev->dev.platform_data;
- /*
- * setup Mux configuration for ccdc which may be different for
- * different SoCs using this CCDC
- */
- setup_pinmux();
-
- i = 0;
- /* Get the ISIF base address, linearization table0 and table1 addr. */
- while (i < 3) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- status = -ENODEV;
- goto fail_nobase_res;
- }
- res = request_mem_region(res->start, resource_size(res),
- res->name);
- if (!res) {
- status = -EBUSY;
- goto fail_nobase_res;
- }
- addr = ioremap_nocache(res->start, resource_size(res));
- if (!addr) {
- status = -ENOMEM;
- goto fail_base_iomap;
- }
- switch (i) {
- case 0:
- /* ISIF base address */
- isif_cfg.base_addr = addr;
- break;
- case 1:
- /* ISIF linear tbl0 address */
- isif_cfg.linear_tbl0_addr = addr;
- break;
- default:
- /* ISIF linear tbl0 address */
- isif_cfg.linear_tbl1_addr = addr;
- break;
- }
- i++;
- }
- isif_cfg.dev = &pdev->dev;
-
- printk(KERN_NOTICE "%s is registered with vpfe.\n",
- isif_hw_dev.name);
- return 0;
-fail_base_iomap:
- release_mem_region(res->start, resource_size(res));
- i--;
-fail_nobase_res:
- if (isif_cfg.base_addr)
- iounmap(isif_cfg.base_addr);
- if (isif_cfg.linear_tbl0_addr)
- iounmap(isif_cfg.linear_tbl0_addr);
-
- while (i >= 0) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- release_mem_region(res->start, resource_size(res));
- i--;
- }
-fail_mclk:
- clk_put(isif_cfg.mclk);
- vpfe_unregister_ccdc_device(&isif_hw_dev);
- return status;
-}
-
-static int isif_remove(struct platform_device *pdev)
-{
- struct resource *res;
- int i = 0;
-
- iounmap(isif_cfg.base_addr);
- iounmap(isif_cfg.linear_tbl0_addr);
- iounmap(isif_cfg.linear_tbl1_addr);
- while (i < 3) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (res)
- release_mem_region(res->start, resource_size(res));
- i++;
- }
- vpfe_unregister_ccdc_device(&isif_hw_dev);
- return 0;
-}
-
-static struct platform_driver isif_driver = {
- .driver = {
- .name = "isif",
- .owner = THIS_MODULE,
- },
- .remove = __devexit_p(isif_remove),
- .probe = isif_probe,
-};
-
-module_platform_driver(isif_driver);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
deleted file mode 100644
index 6fe7034bea7c..000000000000
--- a/drivers/media/video/davinci/vpbe_display.c
+++ /dev/null
@@ -1,1830 +0,0 @@
-/*
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-
-#include <asm/pgtable.h>
-#include <mach/cputype.h>
-
-#include <media/v4l2-dev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <media/davinci/vpbe_display.h>
-#include <media/davinci/vpbe_types.h>
-#include <media/davinci/vpbe.h>
-#include <media/davinci/vpbe_venc.h>
-#include <media/davinci/vpbe_osd.h>
-#include "vpbe_venc_regs.h"
-
-#define VPBE_DISPLAY_DRIVER "vpbe-v4l2"
-
-static int debug;
-
-#define VPBE_DEFAULT_NUM_BUFS 3
-
-module_param(debug, int, 0644);
-
-static int venc_is_second_field(struct vpbe_display *disp_dev)
-{
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- int ret;
- int val;
-
- ret = v4l2_subdev_call(vpbe_dev->venc,
- core,
- ioctl,
- VENC_GET_FLD,
- &val);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in getting Field ID 0\n");
- }
- return val;
-}
-
-static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
- struct vpbe_layer *layer)
-{
- struct timespec timevalue;
-
- if (layer->cur_frm == layer->next_frm)
- return;
- ktime_get_ts(&timevalue);
- layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
- layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
- layer->cur_frm->state = VIDEOBUF_DONE;
- wake_up_interruptible(&layer->cur_frm->done);
- /* Make cur_frm pointing to next_frm */
- layer->cur_frm = layer->next_frm;
-}
-
-static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
- struct vpbe_layer *layer)
-{
- struct osd_state *osd_device = disp_obj->osd_device;
- unsigned long addr;
-
- spin_lock(&disp_obj->dma_queue_lock);
- if (list_empty(&layer->dma_queue) ||
- (layer->cur_frm != layer->next_frm)) {
- spin_unlock(&disp_obj->dma_queue_lock);
- return;
- }
- /*
- * one field is displayed configure
- * the next frame if it is available
- * otherwise hold on current frame
- * Get next from the buffer queue
- */
- layer->next_frm = list_entry(
- layer->dma_queue.next,
- struct videobuf_buffer,
- queue);
- /* Remove that from the buffer queue */
- list_del(&layer->next_frm->queue);
- spin_unlock(&disp_obj->dma_queue_lock);
- /* Mark state of the frame to active */
- layer->next_frm->state = VIDEOBUF_ACTIVE;
- addr = videobuf_to_dma_contig(layer->next_frm);
- osd_device->ops.start_layer(osd_device,
- layer->layer_info.id,
- addr,
- disp_obj->cbcr_ofst);
-}
-
-/* interrupt service routine */
-static irqreturn_t venc_isr(int irq, void *arg)
-{
- struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
- struct vpbe_layer *layer;
- static unsigned last_event;
- unsigned event = 0;
- int fid;
- int i;
-
- if ((NULL == arg) || (NULL == disp_dev->dev[0]))
- return IRQ_HANDLED;
-
- if (venc_is_second_field(disp_dev))
- event |= VENC_SECOND_FIELD;
- else
- event |= VENC_FIRST_FIELD;
-
- if (event == (last_event & ~VENC_END_OF_FRAME)) {
- /*
- * If the display is non-interlaced, then we need to flag the
- * end-of-frame event at every interrupt regardless of the
- * value of the FIDST bit. We can conclude that the display is
- * non-interlaced if the value of the FIDST bit is unchanged
- * from the previous interrupt.
- */
- event |= VENC_END_OF_FRAME;
- } else if (event == VENC_SECOND_FIELD) {
- /* end-of-frame for interlaced display */
- event |= VENC_END_OF_FRAME;
- }
- last_event = event;
-
- for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
- layer = disp_dev->dev[i];
- /* If streaming is started in this layer */
- if (!layer->started)
- continue;
-
- if (layer->layer_first_int) {
- layer->layer_first_int = 0;
- continue;
- }
- /* Check the field format */
- if ((V4L2_FIELD_NONE == layer->pix_fmt.field) &&
- (event & VENC_END_OF_FRAME)) {
- /* Progressive mode */
-
- vpbe_isr_even_field(disp_dev, layer);
- vpbe_isr_odd_field(disp_dev, layer);
- } else {
- /* Interlaced mode */
-
- layer->field_id ^= 1;
- if (event & VENC_FIRST_FIELD)
- fid = 0;
- else
- fid = 1;
-
- /*
- * If field id does not match with store
- * field id
- */
- if (fid != layer->field_id) {
- /* Make them in sync */
- layer->field_id = fid;
- continue;
- }
- /*
- * device field id and local field id are
- * in sync. If this is even field
- */
- if (0 == fid)
- vpbe_isr_even_field(disp_dev, layer);
- else /* odd field */
- vpbe_isr_odd_field(disp_dev, layer);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * vpbe_buffer_prepare()
- * This is the callback function called from videobuf_qbuf() function
- * the buffer is prepared and user space virtual address is converted into
- * physical address
- */
-static int vpbe_buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct vpbe_fh *fh = q->priv_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- unsigned long addr;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe_buffer_prepare\n");
-
- /* If buffer is not initialized, initialize it */
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- vb->width = layer->pix_fmt.width;
- vb->height = layer->pix_fmt.height;
- vb->size = layer->pix_fmt.sizeimage;
- vb->field = field;
-
- ret = videobuf_iolock(q, vb, NULL);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
- user address\n");
- return -EINVAL;
- }
-
- addr = videobuf_to_dma_contig(vb);
-
- if (q->streaming) {
- if (!IS_ALIGNED(addr, 8)) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "buffer_prepare:offset is \
- not aligned to 32 bytes\n");
- return -EINVAL;
- }
- }
- vb->state = VIDEOBUF_PREPARED;
- }
- return 0;
-}
-
-/*
- * vpbe_buffer_setup()
- * This function allocates memory for the buffers
- */
-static int vpbe_buffer_setup(struct videobuf_queue *q,
- unsigned int *count,
- unsigned int *size)
-{
- /* Get the file handle object and layer object */
- struct vpbe_fh *fh = q->priv_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
-
- *size = layer->pix_fmt.sizeimage;
-
- /* Store number of buffers allocated in numbuffer member */
- if (*count < VPBE_DEFAULT_NUM_BUFS)
- *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
-
- return 0;
-}
-
-/*
- * vpbe_buffer_queue()
- * This function adds the buffer to DMA queue
- */
-static void vpbe_buffer_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- /* Get the file handle object and layer object */
- struct vpbe_fh *fh = q->priv_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- unsigned long flags;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe_buffer_queue\n");
-
- /* add the buffer to the DMA queue */
- spin_lock_irqsave(&disp->dma_queue_lock, flags);
- list_add_tail(&vb->queue, &layer->dma_queue);
- spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
- /* Change state of the buffer */
- vb->state = VIDEOBUF_QUEUED;
-}
-
-/*
- * vpbe_buffer_release()
- * This function is called from the videobuf layer to free memory allocated to
- * the buffers
- */
-static void vpbe_buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- /* Get the file handle object and layer object */
- struct vpbe_fh *fh = q->priv_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe_buffer_release\n");
-
- if (V4L2_MEMORY_USERPTR != layer->memory)
- videobuf_dma_contig_free(q, vb);
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops video_qops = {
- .buf_setup = vpbe_buffer_setup,
- .buf_prepare = vpbe_buffer_prepare,
- .buf_queue = vpbe_buffer_queue,
- .buf_release = vpbe_buffer_release,
-};
-
-static
-struct vpbe_layer*
-_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev,
- struct vpbe_layer *layer)
-{
- enum vpbe_display_device_id thiswin, otherwin;
- thiswin = layer->device_id;
-
- otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ?
- VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0;
- return disp_dev->dev[otherwin];
-}
-
-static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
- struct vpbe_layer *layer)
-{
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct osd_state *osd_device = disp_dev->osd_device;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- unsigned long addr;
- int ret;
-
- addr = videobuf_to_dma_contig(layer->cur_frm);
- /* Set address in the display registers */
- osd_device->ops.start_layer(osd_device,
- layer->layer_info.id,
- addr,
- disp_dev->cbcr_ofst);
-
- ret = osd_device->ops.enable_layer(osd_device,
- layer->layer_info.id, 0);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in enabling osd window layer 0\n");
- return -1;
- }
-
- /* Enable the window */
- layer->layer_info.enable = 1;
- if (cfg->pixfmt == PIXFMT_NV12) {
- struct vpbe_layer *otherlayer =
- _vpbe_display_get_other_win_layer(disp_dev, layer);
-
- ret = osd_device->ops.enable_layer(osd_device,
- otherlayer->layer_info.id, 1);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in enabling osd window layer 1\n");
- return -1;
- }
- otherlayer->layer_info.enable = 1;
- }
- return 0;
-}
-
-static void
-vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
- struct vpbe_layer *layer,
- int expected_xsize, int expected_ysize)
-{
- struct display_layer_info *layer_info = &layer->layer_info;
- struct v4l2_pix_format *pixfmt = &layer->pix_fmt;
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- int calculated_xsize;
- int h_exp = 0;
- int v_exp = 0;
- int h_scale;
- int v_scale;
-
- v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id;
-
- /*
- * Application initially set the image format. Current display
- * size is obtained from the vpbe display controller. expected_xsize
- * and expected_ysize are set through S_CROP ioctl. Based on this,
- * driver will calculate the scale factors for vertical and
- * horizontal direction so that the image is displayed scaled
- * and expanded. Application uses expansion to display the image
- * in a square pixel. Otherwise it is displayed using displays
- * pixel aspect ratio.It is expected that application chooses
- * the crop coordinates for cropped or scaled display. if crop
- * size is less than the image size, it is displayed cropped or
- * it is displayed scaled and/or expanded.
- *
- * to begin with, set the crop window same as expected. Later we
- * will override with scaled window size
- */
-
- cfg->xsize = pixfmt->width;
- cfg->ysize = pixfmt->height;
- layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */
- layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */
- layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */
- layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */
-
- if (pixfmt->width < expected_xsize) {
- h_scale = vpbe_dev->current_timings.xres / pixfmt->width;
- if (h_scale < 2)
- h_scale = 1;
- else if (h_scale >= 4)
- h_scale = 4;
- else
- h_scale = 2;
- cfg->xsize *= h_scale;
- if (cfg->xsize < expected_xsize) {
- if ((standard_id & V4L2_STD_525_60) ||
- (standard_id & V4L2_STD_625_50)) {
- calculated_xsize = (cfg->xsize *
- VPBE_DISPLAY_H_EXP_RATIO_N) /
- VPBE_DISPLAY_H_EXP_RATIO_D;
- if (calculated_xsize <= expected_xsize) {
- h_exp = 1;
- cfg->xsize = calculated_xsize;
- }
- }
- }
- if (h_scale == 2)
- layer_info->h_zoom = ZOOM_X2;
- else if (h_scale == 4)
- layer_info->h_zoom = ZOOM_X4;
- if (h_exp)
- layer_info->h_exp = H_EXP_9_OVER_8;
- } else {
- /* no scaling, only cropping. Set display area to crop area */
- cfg->xsize = expected_xsize;
- }
-
- if (pixfmt->height < expected_ysize) {
- v_scale = expected_ysize / pixfmt->height;
- if (v_scale < 2)
- v_scale = 1;
- else if (v_scale >= 4)
- v_scale = 4;
- else
- v_scale = 2;
- cfg->ysize *= v_scale;
- if (cfg->ysize < expected_ysize) {
- if ((standard_id & V4L2_STD_625_50)) {
- calculated_xsize = (cfg->ysize *
- VPBE_DISPLAY_V_EXP_RATIO_N) /
- VPBE_DISPLAY_V_EXP_RATIO_D;
- if (calculated_xsize <= expected_ysize) {
- v_exp = 1;
- cfg->ysize = calculated_xsize;
- }
- }
- }
- if (v_scale == 2)
- layer_info->v_zoom = ZOOM_X2;
- else if (v_scale == 4)
- layer_info->v_zoom = ZOOM_X4;
- if (v_exp)
- layer_info->h_exp = V_EXP_6_OVER_5;
- } else {
- /* no scaling, only cropping. Set display area to crop area */
- cfg->ysize = expected_ysize;
- }
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "crop display xsize = %d, ysize = %d\n",
- cfg->xsize, cfg->ysize);
-}
-
-static void vpbe_disp_adj_position(struct vpbe_display *disp_dev,
- struct vpbe_layer *layer,
- int top, int left)
-{
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
-
- cfg->xpos = min((unsigned int)left,
- vpbe_dev->current_timings.xres - cfg->xsize);
- cfg->ypos = min((unsigned int)top,
- vpbe_dev->current_timings.yres - cfg->ysize);
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "new xpos = %d, ypos = %d\n",
- cfg->xpos, cfg->ypos);
-}
-
-static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev,
- struct v4l2_rect *c)
-{
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
-
- if ((c->width == 0) ||
- ((c->width + c->left) > vpbe_dev->current_timings.xres))
- c->width = vpbe_dev->current_timings.xres - c->left;
-
- if ((c->height == 0) || ((c->height + c->top) >
- vpbe_dev->current_timings.yres))
- c->height = vpbe_dev->current_timings.yres - c->top;
-
- /* window height must be even for interlaced display */
- if (vpbe_dev->current_timings.interlaced)
- c->height &= (~0x01);
-
-}
-
-/**
- * vpbe_try_format()
- * If user application provides width and height, and have bytesperline set
- * to zero, driver calculates bytesperline and sizeimage based on hardware
- * limits.
- */
-static int vpbe_try_format(struct vpbe_display *disp_dev,
- struct v4l2_pix_format *pixfmt, int check)
-{
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- int min_height = 1;
- int min_width = 32;
- int max_height;
- int max_width;
- int bpp;
-
- if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) &&
- (pixfmt->pixelformat != V4L2_PIX_FMT_NV12))
- /* choose default as V4L2_PIX_FMT_UYVY */
- pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
-
- /* Check the field format */
- if ((pixfmt->field != V4L2_FIELD_INTERLACED) &&
- (pixfmt->field != V4L2_FIELD_NONE)) {
- if (vpbe_dev->current_timings.interlaced)
- pixfmt->field = V4L2_FIELD_INTERLACED;
- else
- pixfmt->field = V4L2_FIELD_NONE;
- }
-
- if (pixfmt->field == V4L2_FIELD_INTERLACED)
- min_height = 2;
-
- if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
- bpp = 1;
- else
- bpp = 2;
-
- max_width = vpbe_dev->current_timings.xres;
- max_height = vpbe_dev->current_timings.yres;
-
- min_width /= bpp;
-
- if (!pixfmt->width || (pixfmt->width < min_width) ||
- (pixfmt->width > max_width)) {
- pixfmt->width = vpbe_dev->current_timings.xres;
- }
-
- if (!pixfmt->height || (pixfmt->height < min_height) ||
- (pixfmt->height > max_height)) {
- pixfmt->height = vpbe_dev->current_timings.yres;
- }
-
- if (pixfmt->bytesperline < (pixfmt->width * bpp))
- pixfmt->bytesperline = pixfmt->width * bpp;
-
- /* Make the bytesperline 32 byte aligned */
- pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31);
-
- if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
- pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height +
- (pixfmt->bytesperline * pixfmt->height >> 1);
- else
- pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
-
- return 0;
-}
-
-static int vpbe_display_g_priority(struct file *file, void *priv,
- enum v4l2_priority *p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
-
- *p = v4l2_prio_max(&layer->prio);
-
- return 0;
-}
-
-static int vpbe_display_s_priority(struct file *file, void *priv,
- enum v4l2_priority p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- int ret;
-
- ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
-
- return ret;
-}
-
-static int vpbe_display_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- cap->version = VPBE_DISPLAY_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver));
- strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
- strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
-
- return 0;
-}
-
-static int vpbe_display_s_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct osd_state *osd_device = disp_dev->osd_device;
- struct v4l2_rect *rect = &crop->c;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_S_CROP, layer id = %d\n", layer->device_id);
-
- if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- if (rect->top < 0)
- rect->top = 0;
- if (rect->left < 0)
- rect->left = 0;
-
- vpbe_disp_check_window_params(disp_dev, rect);
-
- osd_device->ops.get_layer_config(osd_device,
- layer->layer_info.id, cfg);
-
- vpbe_disp_calculate_scale_factor(disp_dev, layer,
- rect->width,
- rect->height);
- vpbe_disp_adj_position(disp_dev, layer, rect->top,
- rect->left);
- ret = osd_device->ops.set_layer_config(osd_device,
- layer->layer_info.id, cfg);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in set layer config:\n");
- return -EINVAL;
- }
-
- /* apply zooming and h or v expansion */
- osd_device->ops.set_zoom(osd_device,
- layer->layer_info.id,
- layer->layer_info.h_zoom,
- layer->layer_info.v_zoom);
- ret = osd_device->ops.set_vid_expansion(osd_device,
- layer->layer_info.h_exp,
- layer->layer_info.v_exp);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in set vid expansion:\n");
- return -EINVAL;
- }
-
- if ((layer->layer_info.h_zoom != ZOOM_X1) ||
- (layer->layer_info.v_zoom != ZOOM_X1) ||
- (layer->layer_info.h_exp != H_EXP_OFF) ||
- (layer->layer_info.v_exp != V_EXP_OFF))
- /* Enable expansion filter */
- osd_device->ops.set_interpolation_filter(osd_device, 1);
- else
- osd_device->ops.set_interpolation_filter(osd_device, 0);
-
- return 0;
-}
-
-static int vpbe_display_g_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = fh->disp_dev->osd_device;
- struct v4l2_rect *rect = &crop->c;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_G_CROP, layer id = %d\n",
- layer->device_id);
-
- if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
- ret = -EINVAL;
- }
- osd_device->ops.get_layer_config(osd_device,
- layer->layer_info.id, cfg);
- rect->top = cfg->ypos;
- rect->left = cfg->xpos;
- rect->width = cfg->xsize;
- rect->height = cfg->ysize;
-
- return 0;
-}
-
-static int vpbe_display_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cropcap)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
-
- cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- cropcap->bounds.left = 0;
- cropcap->bounds.top = 0;
- cropcap->bounds.width = vpbe_dev->current_timings.xres;
- cropcap->bounds.height = vpbe_dev->current_timings.yres;
- cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
- cropcap->defrect = cropcap->bounds;
- return 0;
-}
-
-static int vpbe_display_g_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_G_FMT, layer id = %d\n",
- layer->device_id);
-
- /* If buffer type is video output */
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
- return -EINVAL;
- }
- /* Fill in the information about format */
- fmt->fmt.pix = layer->pix_fmt;
-
- return 0;
-}
-
-static int vpbe_display_enum_fmt(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- unsigned int index = 0;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_ENUM_FMT, layer id = %d\n",
- layer->device_id);
- if (fmt->index > 1) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n");
- return -EINVAL;
- }
-
- /* Fill in the information about format */
- index = fmt->index;
- memset(fmt, 0, sizeof(*fmt));
- fmt->index = index;
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- if (index == 0) {
- strcpy(fmt->description, "YUV 4:2:2 - UYVY");
- fmt->pixelformat = V4L2_PIX_FMT_UYVY;
- } else {
- strcpy(fmt->description, "Y/CbCr 4:2:0");
- fmt->pixelformat = V4L2_PIX_FMT_NV12;
- }
-
- return 0;
-}
-
-static int vpbe_display_s_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- struct osd_state *osd_device = disp_dev->osd_device;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_S_FMT, layer id = %d\n",
- layer->device_id);
-
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
- return -EINVAL;
- }
- /* Check for valid pixel format */
- ret = vpbe_try_format(disp_dev, pixfmt, 1);
- if (ret)
- return ret;
-
- /* YUV420 is requested, check availability of the
- other video window */
-
- layer->pix_fmt = *pixfmt;
-
- /* Get osd layer config */
- osd_device->ops.get_layer_config(osd_device,
- layer->layer_info.id, cfg);
- /* Store the pixel format in the layer object */
- cfg->xsize = pixfmt->width;
- cfg->ysize = pixfmt->height;
- cfg->line_length = pixfmt->bytesperline;
- cfg->ypos = 0;
- cfg->xpos = 0;
- cfg->interlaced = vpbe_dev->current_timings.interlaced;
-
- if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
- cfg->pixfmt = PIXFMT_YCbCrI;
-
- /* Change of the default pixel format for both video windows */
- if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
- struct vpbe_layer *otherlayer;
- cfg->pixfmt = PIXFMT_NV12;
- otherlayer = _vpbe_display_get_other_win_layer(disp_dev,
- layer);
- otherlayer->layer_info.config.pixfmt = PIXFMT_NV12;
- }
-
- /* Set the layer config in the osd window */
- ret = osd_device->ops.set_layer_config(osd_device,
- layer->layer_info.id, cfg);
- if (ret < 0) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Error in S_FMT params:\n");
- return -EINVAL;
- }
-
- /* Readback and fill the local copy of current pix format */
- osd_device->ops.get_layer_config(osd_device,
- layer->layer_info.id, cfg);
-
- return 0;
-}
-
-static int vpbe_display_try_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
- return -EINVAL;
- }
-
- /* Check for valid field format */
- return vpbe_try_format(disp_dev, pixfmt, 0);
-
-}
-
-/**
- * vpbe_display_s_std - Set the given standard in the encoder
- *
- * Sets the standard if supported by the current encoder. Return the status.
- * 0 - success & -EINVAL on error
- */
-static int vpbe_display_s_std(struct file *file, void *priv,
- v4l2_std_id *std_id)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
-
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
- if (NULL != vpbe_dev->ops.s_std) {
- ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Failed to set standard for sub devices\n");
- return -EINVAL;
- }
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * vpbe_display_g_std - Get the standard in the current encoder
- *
- * Get the standard in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
-static int vpbe_display_g_std(struct file *file, void *priv,
- v4l2_std_id *std_id)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n");
-
- /* Get the standard from the current encoder */
- if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) {
- *std_id = vpbe_dev->current_timings.timings.std_id;
- return 0;
- }
-
- return -EINVAL;
-}
-
-/**
- * vpbe_display_enum_output - enumerate outputs
- *
- * Enumerates the outputs available at the vpbe display
- * returns the status, -EINVAL if end of output list
- */
-static int vpbe_display_enum_output(struct file *file, void *priv,
- struct v4l2_output *output)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n");
-
- /* Enumerate outputs */
-
- if (NULL == vpbe_dev->ops.enum_outputs)
- return -EINVAL;
-
- ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output);
- if (ret) {
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "Failed to enumerate outputs\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * vpbe_display_s_output - Set output to
- * the output specified by the index
- */
-static int vpbe_display_s_output(struct file *file, void *priv,
- unsigned int i)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n");
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
- if (NULL == vpbe_dev->ops.set_output)
- return -EINVAL;
-
- ret = vpbe_dev->ops.set_output(vpbe_dev, i);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Failed to set output for sub devices\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * vpbe_display_g_output - Get output from subdevice
- * for a given by the index
- */
-static int vpbe_display_g_output(struct file *file, void *priv,
- unsigned int *i)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
- /* Get the standard from the current encoder */
- *i = vpbe_dev->current_out_index;
-
- return 0;
-}
-
-/**
- * vpbe_display_enum_dv_presets - Enumerate the dv presets
- *
- * enum the preset in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
-static int
-vpbe_display_enum_dv_presets(struct file *file, void *priv,
- struct v4l2_dv_enum_preset *preset)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n");
-
- /* Enumerate outputs */
- if (NULL == vpbe_dev->ops.enum_dv_presets)
- return -EINVAL;
-
- ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Failed to enumerate dv presets info\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * vpbe_display_s_dv_preset - Set the dv presets
- *
- * Set the preset in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
-static int
-vpbe_display_s_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n");
-
-
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
-
- /* Set the given standard in the encoder */
- if (!vpbe_dev->ops.s_dv_preset)
- return -EINVAL;
-
- ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Failed to set the dv presets info\n");
- return -EINVAL;
- }
- /* set the current norm to zero to be consistent. If STD is used
- * v4l2 layer will set the norm properly on successful s_std call
- */
- layer->video_dev.current_norm = 0;
-
- return 0;
-}
-
-/**
- * vpbe_display_g_dv_preset - Set the dv presets
- *
- * Get the preset in the current encoder. Return the status. 0 - success
- * -EINVAL on error
- */
-static int
-vpbe_display_g_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *dv_preset)
-{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n");
-
- /* Get the given standard in the encoder */
-
- if (vpbe_dev->current_timings.timings_type &
- VPBE_ENC_DV_PRESET) {
- dv_preset->preset =
- vpbe_dev->current_timings.timings.dv_preset;
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vpbe_display_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = fh->disp_dev->osd_device;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_STREAMOFF,layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
- " id = %d\n", layer->device_id);
- return -EINVAL;
- }
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
- layer->started = 0;
- ret = videobuf_streamoff(&layer->buffer_queue);
-
- return ret;
-}
-
-static int vpbe_display_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = disp_dev->osd_device;
- int ret;
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
- /* If Streaming is already started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
- return -EBUSY;
- }
-
- /*
- * Call videobuf_streamon to start streaming
- * in videobuf
- */
- ret = videobuf_streamon(&layer->buffer_queue);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "error in videobuf_streamon\n");
- return ret;
- }
- /* If buffer queue is empty, return error */
- if (list_empty(&layer->dma_queue)) {
- v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
- goto streamoff;
- }
- /* Get the next frame from the buffer queue */
- layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
- struct videobuf_buffer, queue);
- /* Remove buffer from the buffer queue */
- list_del(&layer->cur_frm->queue);
- /* Mark state of the current frame to active */
- layer->cur_frm->state = VIDEOBUF_ACTIVE;
- /* Initialize field_id and started member */
- layer->field_id = 0;
-
- /* Set parameters in OSD and VENC */
- ret = vpbe_set_osd_display_params(disp_dev, layer);
- if (ret < 0)
- goto streamoff;
-
- /*
- * if request format is yuv420 semiplanar, need to
- * enable both video windows
- */
- layer->started = 1;
-
- layer->layer_first_int = 1;
-
- return ret;
-streamoff:
- ret = videobuf_streamoff(&layer->buffer_queue);
- return ret;
-}
-
-static int vpbe_display_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_DQBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
- /* If this file handle is not allowed to do IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
- if (file->f_flags & O_NONBLOCK)
- /* Call videobuf_dqbuf for non blocking mode */
- ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
- else
- /* Call videobuf_dqbuf for blocking mode */
- ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
-
- return ret;
-}
-
-static int vpbe_display_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_QBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If this file handle is not allowed to do IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
-
- return videobuf_qbuf(&layer->buffer_queue, p);
-}
-
-static int vpbe_display_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_QUERYBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* Call videobuf_querybuf to get information */
- ret = videobuf_querybuf(&layer->buffer_queue, buf);
-
- return ret;
-}
-
-static int vpbe_display_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req_buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If io users of the layer is not zero, return error */
- if (0 != layer->io_usrs) {
- v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
- return -EBUSY;
- }
- /* Initialize videobuf queue as per the buffer type */
- videobuf_queue_dma_contig_init(&layer->buffer_queue,
- &video_qops,
- vpbe_dev->pdev,
- &layer->irqlock,
- V4L2_BUF_TYPE_VIDEO_OUTPUT,
- layer->pix_fmt.field,
- sizeof(struct videobuf_buffer),
- fh, NULL);
-
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed = 1;
- /* Increment io usrs member of layer object to 1 */
- layer->io_usrs = 1;
- /* Store type of memory requested in layer object */
- layer->memory = req_buf->memory;
- /* Initialize buffer queue */
- INIT_LIST_HEAD(&layer->dma_queue);
- /* Allocate buffers */
- ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
-
- return ret;
-}
-
-/*
- * vpbe_display_mmap()
- * It is used to map kernel space buffers into user spaces
- */
-static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- /* Get the layer object and file handle object */
- struct vpbe_fh *fh = filep->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
-
- return videobuf_mmap_mapper(&layer->buffer_queue, vma);
-}
-
-/* vpbe_display_poll(): It is used for select/poll system call
- */
-static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
-{
- struct vpbe_fh *fh = filep->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- unsigned int err = 0;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
- if (layer->started)
- err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
- return err;
-}
-
-/*
- * vpbe_display_open()
- * It creates object of file handle structure and stores it in private_data
- * member of filepointer
- */
-static int vpbe_display_open(struct file *file)
-{
- struct vpbe_fh *fh = NULL;
- struct vpbe_layer *layer = video_drvdata(file);
- struct vpbe_display *disp_dev = layer->disp_dev;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- struct osd_state *osd_device = disp_dev->osd_device;
- int err;
-
- /* Allocate memory for the file handle object */
- fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
- if (fh == NULL) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe display open plane = %d\n",
- layer->device_id);
-
- /* store pointer to fh in private_data member of filep */
- file->private_data = fh;
- fh->layer = layer;
- fh->disp_dev = disp_dev;
-
- if (!layer->usrs) {
-
- /* First claim the layer for this device */
- err = osd_device->ops.request_layer(osd_device,
- layer->layer_info.id);
- if (err < 0) {
- /* Couldn't get layer */
- v4l2_err(&vpbe_dev->v4l2_dev,
- "Display Manager failed to allocate layer\n");
- kfree(fh);
- return -EINVAL;
- }
- }
- /* Increment layer usrs counter */
- layer->usrs++;
- /* Set io_allowed member to false */
- fh->io_allowed = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&layer->prio, &fh->prio);
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe display device opened successfully\n");
- return 0;
-}
-
-/*
- * vpbe_display_release()
- * This function deletes buffer queue, frees the buffers and the davinci
- * display file * handle
- */
-static int vpbe_display_release(struct file *file)
-{
- /* Get the layer object and file handle object */
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- struct osd_state *osd_device = disp_dev->osd_device;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
-
- /* if this instance is doing IO */
- if (fh->io_allowed) {
- /* Reset io_usrs member of layer object */
- layer->io_usrs = 0;
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
- layer->started = 0;
- /* Free buffers allocated */
- videobuf_queue_cancel(&layer->buffer_queue);
- videobuf_mmap_free(&layer->buffer_queue);
- }
-
- /* Decrement layer usrs counter */
- layer->usrs--;
- /* If this file handle has initialize encoder device, reset it */
- if (!layer->usrs) {
- if (cfg->pixfmt == PIXFMT_NV12) {
- struct vpbe_layer *otherlayer;
- otherlayer =
- _vpbe_display_get_other_win_layer(disp_dev, layer);
- osd_device->ops.disable_layer(osd_device,
- otherlayer->layer_info.id);
- osd_device->ops.release_layer(osd_device,
- otherlayer->layer_info.id);
- }
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
- osd_device->ops.release_layer(osd_device,
- layer->layer_info.id);
- }
- /* Close the priority */
- v4l2_prio_close(&layer->prio, fh->prio);
- file->private_data = NULL;
-
- /* Free memory allocated to file handle object */
- kfree(fh);
-
- disp_dev->cbcr_ofst = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vpbe_display_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct v4l2_dbg_match *match = &reg->match;
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- if (match->type >= 2) {
- v4l2_subdev_call(vpbe_dev->venc,
- core,
- g_register,
- reg);
- }
-
- return 0;
-}
-
-static int vpbe_display_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- return 0;
-}
-#endif
-
-/* vpbe capture ioctl operations */
-static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
- .vidioc_querycap = vpbe_display_querycap,
- .vidioc_g_fmt_vid_out = vpbe_display_g_fmt,
- .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
- .vidioc_s_fmt_vid_out = vpbe_display_s_fmt,
- .vidioc_try_fmt_vid_out = vpbe_display_try_fmt,
- .vidioc_reqbufs = vpbe_display_reqbufs,
- .vidioc_querybuf = vpbe_display_querybuf,
- .vidioc_qbuf = vpbe_display_qbuf,
- .vidioc_dqbuf = vpbe_display_dqbuf,
- .vidioc_streamon = vpbe_display_streamon,
- .vidioc_streamoff = vpbe_display_streamoff,
- .vidioc_cropcap = vpbe_display_cropcap,
- .vidioc_g_crop = vpbe_display_g_crop,
- .vidioc_s_crop = vpbe_display_s_crop,
- .vidioc_g_priority = vpbe_display_g_priority,
- .vidioc_s_priority = vpbe_display_s_priority,
- .vidioc_s_std = vpbe_display_s_std,
- .vidioc_g_std = vpbe_display_g_std,
- .vidioc_enum_output = vpbe_display_enum_output,
- .vidioc_s_output = vpbe_display_s_output,
- .vidioc_g_output = vpbe_display_g_output,
- .vidioc_s_dv_preset = vpbe_display_s_dv_preset,
- .vidioc_g_dv_preset = vpbe_display_g_dv_preset,
- .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vpbe_display_g_register,
- .vidioc_s_register = vpbe_display_s_register,
-#endif
-};
-
-static struct v4l2_file_operations vpbe_fops = {
- .owner = THIS_MODULE,
- .open = vpbe_display_open,
- .release = vpbe_display_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vpbe_display_mmap,
- .poll = vpbe_display_poll
-};
-
-static int vpbe_device_get(struct device *dev, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct vpbe_display *vpbe_disp = data;
-
- if (strcmp("vpbe_controller", pdev->name) == 0)
- vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
-
- if (strcmp("vpbe-osd", pdev->name) == 0)
- vpbe_disp->osd_device = platform_get_drvdata(pdev);
-
- return 0;
-}
-
-static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
- struct platform_device *pdev)
-{
- struct vpbe_layer *vpbe_display_layer = NULL;
- struct video_device *vbd = NULL;
-
- /* Allocate memory for four plane display objects */
-
- disp_dev->dev[i] =
- kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL);
-
- /* If memory allocation fails, return error */
- if (!disp_dev->dev[i]) {
- printk(KERN_ERR "ran out of memory\n");
- return -ENOMEM;
- }
- spin_lock_init(&disp_dev->dev[i]->irqlock);
- mutex_init(&disp_dev->dev[i]->opslock);
-
- /* Get the pointer to the layer object */
- vpbe_display_layer = disp_dev->dev[i];
- vbd = &vpbe_display_layer->video_dev;
- /* Initialize field of video device */
- vbd->release = video_device_release_empty;
- vbd->fops = &vpbe_fops;
- vbd->ioctl_ops = &vpbe_ioctl_ops;
- vbd->minor = -1;
- vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vbd->flags);
- vbd->lock = &vpbe_display_layer->opslock;
-
- if (disp_dev->vpbe_dev->current_timings.timings_type &
- VPBE_ENC_STD) {
- vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
- vbd->current_norm =
- disp_dev->vpbe_dev->
- current_timings.timings.std_id;
- } else
- vbd->current_norm = 0;
-
- snprintf(vbd->name, sizeof(vbd->name),
- "DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
- (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff,
- (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff,
- (VPBE_DISPLAY_VERSION_CODE) & 0xff);
-
- vpbe_display_layer->device_id = i;
-
- vpbe_display_layer->layer_info.id =
- ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
-
- /* Initialize prio member of layer object */
- v4l2_prio_init(&vpbe_display_layer->prio);
-
- return 0;
-}
-
-static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
- struct vpbe_display *disp_dev,
- struct platform_device *pdev) {
- int err;
-
- v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
- "Trying to register VPBE display device.\n");
- v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
- "layer=%x,layer->video_dev=%x\n",
- (int)vpbe_display_layer,
- (int)&vpbe_display_layer->video_dev);
-
- err = video_register_device(&vpbe_display_layer->video_dev,
- VFL_TYPE_GRABBER,
- -1);
- if (err)
- return -ENODEV;
-
- vpbe_display_layer->disp_dev = disp_dev;
- /* set the driver data in platform device */
- platform_set_drvdata(pdev, disp_dev);
- video_set_drvdata(&vpbe_display_layer->video_dev,
- vpbe_display_layer);
-
- return 0;
-}
-
-
-
-/*
- * vpbe_display_probe()
- * This function creates device entries by register itself to the V4L2 driver
- * and initializes fields of each layer objects
- */
-static __devinit int vpbe_display_probe(struct platform_device *pdev)
-{
- struct vpbe_layer *vpbe_display_layer;
- struct vpbe_display *disp_dev;
- struct resource *res = NULL;
- int k;
- int i;
- int err;
- int irq;
-
- printk(KERN_DEBUG "vpbe_display_probe\n");
- /* Allocate memory for vpbe_display */
- disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
- if (!disp_dev) {
- printk(KERN_ERR "ran out of memory\n");
- return -ENOMEM;
- }
-
- spin_lock_init(&disp_dev->dma_queue_lock);
- /*
- * Scan all the platform devices to find the vpbe
- * controller device and get the vpbe_dev object
- */
- err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev,
- vpbe_device_get);
- if (err < 0)
- return err;
- /* Initialize the vpbe display controller */
- if (NULL != disp_dev->vpbe_dev->ops.initialize) {
- err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
- disp_dev->vpbe_dev);
- if (err) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Error initing vpbe\n");
- err = -ENOMEM;
- goto probe_out;
- }
- }
-
- for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
- if (init_vpbe_layer(i, disp_dev, pdev)) {
- err = -ENODEV;
- goto probe_out;
- }
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Unable to get VENC interrupt resource\n");
- err = -ENODEV;
- goto probe_out;
- }
-
- irq = res->start;
- if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
- disp_dev)) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Unable to request interrupt\n");
- err = -ENODEV;
- goto probe_out;
- }
-
- for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
- if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
- err = -ENODEV;
- goto probe_out_irq;
- }
- }
-
- printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
- return 0;
-
-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];
- /* Unregister video device */
- if (vpbe_display_layer) {
- video_unregister_device(
- &vpbe_display_layer->video_dev);
- kfree(disp_dev->dev[k]);
- }
- }
- kfree(disp_dev);
- return err;
-}
-
-/*
- * vpbe_display_remove()
- * It un-register hardware layer from V4L2 driver
- */
-static int vpbe_display_remove(struct platform_device *pdev)
-{
- struct vpbe_layer *vpbe_display_layer;
- struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
- struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
- struct resource *res;
- int i;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
-
- /* unregister irq */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- free_irq(res->start, disp_dev);
-
- /* deinitialize the vpbe display controller */
- if (NULL != vpbe_dev->ops.deinitialize)
- vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
- /* un-register device */
- for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
- /* Get the pointer to the layer object */
- vpbe_display_layer = disp_dev->dev[i];
- /* Unregister video device */
- video_unregister_device(&vpbe_display_layer->video_dev);
-
- }
- for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
- kfree(disp_dev->dev[i]);
- disp_dev->dev[i] = NULL;
- }
-
- return 0;
-}
-
-static struct platform_driver vpbe_display_driver = {
- .driver = {
- .name = VPBE_DISPLAY_DRIVER,
- .owner = THIS_MODULE,
- .bus = &platform_bus_type,
- },
- .probe = vpbe_display_probe,
- .remove = __devexit_p(vpbe_display_remove),
-};
-
-module_platform_driver(vpbe_display_driver);
-
-MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
deleted file mode 100644
index 49a845fb804a..000000000000
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ /dev/null
@@ -1,2079 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Texas Instruments Inc
- *
- * 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
- *
- * Driver name : VPFE Capture driver
- * VPFE Capture driver allows applications to capture and stream video
- * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
- * TVP5146 or Raw Bayer RGB image data from an image sensor
- * such as Microns' MT9T001, MT9T031 etc.
- *
- * These SoCs have, in common, a Video Processing Subsystem (VPSS) that
- * consists of a Video Processing Front End (VPFE) for capturing
- * video/raw image data and Video Processing Back End (VPBE) for displaying
- * YUV data through an in-built analog encoder or Digital LCD port. This
- * driver is for capture through VPFE. A typical EVM using these SoCs have
- * following high level configuration.
- *
- *
- * decoder(TVP5146/ YUV/
- * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
- * data input | |
- * V |
- * SDRAM |
- * V
- * Image Processor
- * |
- * V
- * SDRAM
- * The data flow happens from a decoder connected to the VPFE over a
- * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
- * and to the input of VPFE through an optional MUX (if more inputs are
- * to be interfaced on the EVM). The input data is first passed through
- * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
- * does very little or no processing on YUV data and does pre-process Raw
- * Bayer RGB data through modules such as Defect Pixel Correction (DFC)
- * Color Space Conversion (CSC), data gain/offset etc. After this, data
- * can be written to SDRAM or can be connected to the image processing
- * block such as IPIPE (on DM355 only).
- *
- * Features supported
- * - MMAP IO
- * - Capture using TVP5146 over BT.656
- * - support for interfacing decoders using sub device model
- * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV
- * data capture to SDRAM.
- * TODO list
- * - Support multiple REQBUF after open
- * - Support for de-allocating buffers through REQBUF
- * - Support for Raw Bayer RGB capture
- * - Support for chaining Image Processor
- * - Support for static allocation of buffers
- * - Support for USERPTR IO
- * - Support for STREAMON before QBUF
- * - Support for control ioctls
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <media/v4l2-common.h>
-#include <linux/io.h>
-#include <media/davinci/vpfe_capture.h>
-#include "ccdc_hw_device.h"
-
-static int debug;
-static u32 numbuffers = 3;
-static u32 bufsize = (720 * 576 * 2);
-
-module_param(numbuffers, uint, S_IRUGO);
-module_param(bufsize, uint, S_IRUGO);
-module_param(debug, int, 0644);
-
-MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
-MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
-MODULE_PARM_DESC(debug, "Debug level 0-1");
-
-MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments");
-
-/* standard information */
-struct vpfe_standard {
- v4l2_std_id std_id;
- unsigned int width;
- unsigned int height;
- struct v4l2_fract pixelaspect;
- /* 0 - progressive, 1 - interlaced */
- int frame_format;
-};
-
-/* ccdc configuration */
-struct ccdc_config {
- /* This make sure vpfe is probed and ready to go */
- int vpfe_probed;
- /* name of ccdc device */
- char name[32];
-};
-
-/* data structures */
-static struct vpfe_config_params config_params = {
- .min_numbuffers = 3,
- .numbuffers = 3,
- .min_bufsize = 720 * 480 * 2,
- .device_bufsize = 720 * 576 * 2,
-};
-
-/* ccdc device registered */
-static struct ccdc_hw_device *ccdc_dev;
-/* lock for accessing ccdc information */
-static DEFINE_MUTEX(ccdc_lock);
-/* ccdc configuration */
-static struct ccdc_config *ccdc_cfg;
-
-const struct vpfe_standard vpfe_standards[] = {
- {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
- {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
-};
-
-/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
-static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
- {
- .fmtdesc = {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb 8bit A-Law compr.",
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- },
- .bpp = 1,
- },
- {
- .fmtdesc = {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb - 16bit",
- .pixelformat = V4L2_PIX_FMT_SBGGR16,
- },
- .bpp = 2,
- },
- {
- .fmtdesc = {
- .index = 2,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb 8bit DPCM compr.",
- .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
- },
- .bpp = 1,
- },
- {
- .fmtdesc = {
- .index = 3,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "YCbCr 4:2:2 Interleaved UYVY",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- },
- .bpp = 2,
- },
- {
- .fmtdesc = {
- .index = 4,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "YCbCr 4:2:2 Interleaved YUYV",
- .pixelformat = V4L2_PIX_FMT_YUYV,
- },
- .bpp = 2,
- },
- {
- .fmtdesc = {
- .index = 5,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Y/CbCr 4:2:0 - Semi planar",
- .pixelformat = V4L2_PIX_FMT_NV12,
- },
- .bpp = 1,
- },
-};
-
-/*
- * vpfe_lookup_pix_format()
- * lookup an entry in the vpfe pix format table based on pix_format
- */
-static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
- if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
- return &vpfe_pix_fmts[i];
- }
- return NULL;
-}
-
-/*
- * vpfe_register_ccdc_device. CCDC module calls this to
- * register with vpfe capture
- */
-int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
-{
- int ret = 0;
- printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
-
- BUG_ON(!dev->hw_ops.open);
- BUG_ON(!dev->hw_ops.enable);
- BUG_ON(!dev->hw_ops.set_hw_if_params);
- BUG_ON(!dev->hw_ops.configure);
- BUG_ON(!dev->hw_ops.set_buftype);
- BUG_ON(!dev->hw_ops.get_buftype);
- BUG_ON(!dev->hw_ops.enum_pix);
- BUG_ON(!dev->hw_ops.set_frame_format);
- BUG_ON(!dev->hw_ops.get_frame_format);
- BUG_ON(!dev->hw_ops.get_pixel_format);
- BUG_ON(!dev->hw_ops.set_pixel_format);
- BUG_ON(!dev->hw_ops.set_image_window);
- BUG_ON(!dev->hw_ops.get_image_window);
- BUG_ON(!dev->hw_ops.get_line_length);
- BUG_ON(!dev->hw_ops.getfid);
-
- mutex_lock(&ccdc_lock);
- if (NULL == ccdc_cfg) {
- /*
- * TODO. Will this ever happen? if so, we need to fix it.
- * Proabably we need to add the request to a linked list and
- * walk through it during vpfe probe
- */
- printk(KERN_ERR "vpfe capture not initialized\n");
- ret = -EFAULT;
- goto unlock;
- }
-
- if (strcmp(dev->name, ccdc_cfg->name)) {
- /* ignore this ccdc */
- ret = -EINVAL;
- goto unlock;
- }
-
- if (ccdc_dev) {
- printk(KERN_ERR "ccdc already registered\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- ccdc_dev = dev;
-unlock:
- mutex_unlock(&ccdc_lock);
- return ret;
-}
-EXPORT_SYMBOL(vpfe_register_ccdc_device);
-
-/*
- * vpfe_unregister_ccdc_device. CCDC module calls this to
- * unregister with vpfe capture
- */
-void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
-{
- if (NULL == dev) {
- printk(KERN_ERR "invalid ccdc device ptr\n");
- return;
- }
-
- printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n",
- dev->name);
-
- if (strcmp(dev->name, ccdc_cfg->name)) {
- /* ignore this ccdc */
- return;
- }
-
- mutex_lock(&ccdc_lock);
- ccdc_dev = NULL;
- mutex_unlock(&ccdc_lock);
- return;
-}
-EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
-
-/*
- * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
- */
-static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
- struct v4l2_format *f)
-{
- struct v4l2_rect image_win;
- enum ccdc_buftype buf_type;
- enum ccdc_frmfmt frm_fmt;
-
- memset(f, 0, sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- ccdc_dev->hw_ops.get_image_window(&image_win);
- f->fmt.pix.width = image_win.width;
- f->fmt.pix.height = image_win.height;
- f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
- f->fmt.pix.height;
- buf_type = ccdc_dev->hw_ops.get_buftype();
- f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format();
- frm_fmt = ccdc_dev->hw_ops.get_frame_format();
- if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
- f->fmt.pix.field = V4L2_FIELD_NONE;
- else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
- if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED)
- f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
- else {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n");
- return -EINVAL;
- }
- } else {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n");
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- * vpfe_config_ccdc_image_format()
- * For a pix format, configure ccdc to setup the capture
- */
-static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
-{
- enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
- int ret = 0;
-
- if (ccdc_dev->hw_ops.set_pixel_format(
- vpfe_dev->fmt.fmt.pix.pixelformat) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "couldn't set pix format in ccdc\n");
- return -EINVAL;
- }
- /* configure the image window */
- ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop);
-
- switch (vpfe_dev->fmt.fmt.pix.field) {
- case V4L2_FIELD_INTERLACED:
- /* do nothing, since it is default */
- ret = ccdc_dev->hw_ops.set_buftype(
- CCDC_BUFTYPE_FLD_INTERLEAVED);
- break;
- case V4L2_FIELD_NONE:
- frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
- /* buffer type only applicable for interlaced scan */
- break;
- case V4L2_FIELD_SEQ_TB:
- ret = ccdc_dev->hw_ops.set_buftype(
- CCDC_BUFTYPE_FLD_SEPARATED);
- break;
- default:
- return -EINVAL;
- }
-
- /* set the frame format */
- if (!ret)
- ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
- return ret;
-}
-/*
- * vpfe_config_image_format()
- * For a given standard, this functions sets up the default
- * pix format & crop values in the vpfe device and ccdc. It first
- * starts with defaults based values from the standard table.
- * It then checks if sub device support g_mbus_fmt and then override the
- * values based on that.Sets crop values to match with scan resolution
- * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
- * values in ccdc
- */
-static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
- const v4l2_std_id *std_id)
-{
- struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
- struct v4l2_mbus_framefmt mbus_fmt;
- struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix;
- int i, ret = 0;
-
- for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
- if (vpfe_standards[i].std_id & *std_id) {
- vpfe_dev->std_info.active_pixels =
- vpfe_standards[i].width;
- vpfe_dev->std_info.active_lines =
- vpfe_standards[i].height;
- vpfe_dev->std_info.frame_format =
- vpfe_standards[i].frame_format;
- vpfe_dev->std_index = i;
- break;
- }
- }
-
- if (i == ARRAY_SIZE(vpfe_standards)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n");
- return -EINVAL;
- }
-
- vpfe_dev->crop.top = 0;
- vpfe_dev->crop.left = 0;
- vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
- vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
- pix->width = vpfe_dev->crop.width;
- pix->height = vpfe_dev->crop.height;
-
- /* first field and frame format based on standard frame format */
- if (vpfe_dev->std_info.frame_format) {
- pix->field = V4L2_FIELD_INTERLACED;
- /* assume V4L2_PIX_FMT_UYVY as default */
- pix->pixelformat = V4L2_PIX_FMT_UYVY;
- v4l2_fill_mbus_format(&mbus_fmt, pix,
- V4L2_MBUS_FMT_YUYV10_2X10);
- } else {
- pix->field = V4L2_FIELD_NONE;
- /* assume V4L2_PIX_FMT_SBGGR8 */
- pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
- v4l2_fill_mbus_format(&mbus_fmt, pix,
- V4L2_MBUS_FMT_SBGGR8_1X8);
- }
-
- /* if sub device supports g_mbus_fmt, override the defaults */
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
- sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt);
-
- if (ret && ret != -ENOIOCTLCMD) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "error in getting g_mbus_fmt from sub device\n");
- return ret;
- }
- v4l2_fill_pix_format(pix, &mbus_fmt);
- pix->bytesperline = pix->width * 2;
- pix->sizeimage = pix->bytesperline * pix->height;
-
- /* Sets the values in CCDC */
- ret = vpfe_config_ccdc_image_format(vpfe_dev);
- if (ret)
- return ret;
-
- /* Update the values of sizeimage and bytesperline */
- if (!ret) {
- pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
- pix->sizeimage = pix->bytesperline * pix->height;
- }
- return ret;
-}
-
-static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
-{
- int ret = 0;
-
- /* set first input of current subdevice as the current input */
- vpfe_dev->current_input = 0;
-
- /* set default standard */
- vpfe_dev->std_index = 0;
-
- /* Configure the default format information */
- ret = vpfe_config_image_format(vpfe_dev,
- &vpfe_standards[vpfe_dev->std_index].std_id);
- if (ret)
- return ret;
-
- /* now open the ccdc device to initialize it */
- mutex_lock(&ccdc_lock);
- if (NULL == ccdc_dev) {
- v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n");
- ret = -ENODEV;
- goto unlock;
- }
-
- if (!try_module_get(ccdc_dev->owner)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n");
- ret = -ENODEV;
- goto unlock;
- }
- ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
- if (!ret)
- vpfe_dev->initialized = 1;
-
- /* Clear all VPFE/CCDC interrupts */
- if (vpfe_dev->cfg->clr_intr)
- vpfe_dev->cfg->clr_intr(-1);
-
-unlock:
- mutex_unlock(&ccdc_lock);
- return ret;
-}
-
-/*
- * vpfe_open : It creates object of file handle structure and
- * stores it in private_data member of filepointer
- */
-static int vpfe_open(struct file *file)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
-
- if (!vpfe_dev->cfg->num_subdevs) {
- v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n");
- return -ENODEV;
- }
-
- /* Allocate memory for the file handle object */
- fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
- if (NULL == fh) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
- /* store pointer to fh in private_data member of file */
- file->private_data = fh;
- fh->vpfe_dev = vpfe_dev;
- mutex_lock(&vpfe_dev->lock);
- /* If decoder is not initialized. initialize it */
- if (!vpfe_dev->initialized) {
- if (vpfe_initialize_device(vpfe_dev)) {
- mutex_unlock(&vpfe_dev->lock);
- return -ENODEV;
- }
- }
- /* Increment device usrs counter */
- vpfe_dev->usrs++;
- /* Set io_allowed member to false */
- fh->io_allowed = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
- mutex_unlock(&vpfe_dev->lock);
- return 0;
-}
-
-static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
-{
- unsigned long addr;
-
- vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
- struct videobuf_buffer, queue);
- list_del(&vpfe_dev->next_frm->queue);
- vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
- addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
-
- ccdc_dev->hw_ops.setfbaddr(addr);
-}
-
-static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
-{
- unsigned long addr;
-
- addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
- addr += vpfe_dev->field_off;
- ccdc_dev->hw_ops.setfbaddr(addr);
-}
-
-static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
-{
- struct timeval timevalue;
-
- do_gettimeofday(&timevalue);
- vpfe_dev->cur_frm->ts = timevalue;
- vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
- vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
- wake_up_interruptible(&vpfe_dev->cur_frm->done);
- vpfe_dev->cur_frm = vpfe_dev->next_frm;
-}
-
-/* ISR for VINT0*/
-static irqreturn_t vpfe_isr(int irq, void *dev_id)
-{
- struct vpfe_device *vpfe_dev = dev_id;
- enum v4l2_field field;
- int fid;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
- field = vpfe_dev->fmt.fmt.pix.field;
-
- /* if streaming not started, don't do anything */
- if (!vpfe_dev->started)
- goto clear_intr;
-
- /* only for 6446 this will be applicable */
- if (NULL != ccdc_dev->hw_ops.reset)
- ccdc_dev->hw_ops.reset();
-
- if (field == V4L2_FIELD_NONE) {
- /* handle progressive frame capture */
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "frame format is progressive...\n");
- if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
- vpfe_process_buffer_complete(vpfe_dev);
- goto clear_intr;
- }
-
- /* interlaced or TB capture check which field we are in hardware */
- fid = ccdc_dev->hw_ops.getfid();
-
- /* switch the software maintained field id */
- vpfe_dev->field_id ^= 1;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n",
- fid, vpfe_dev->field_id);
- if (fid == vpfe_dev->field_id) {
- /* we are in-sync here,continue */
- if (fid == 0) {
- /*
- * One frame is just being captured. If the next frame
- * is available, release the current frame and move on
- */
- if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
- vpfe_process_buffer_complete(vpfe_dev);
- /*
- * based on whether the two fields are stored
- * interleavely or separately in memory, reconfigure
- * the CCDC memory address
- */
- if (field == V4L2_FIELD_SEQ_TB) {
- vpfe_schedule_bottom_field(vpfe_dev);
- }
- goto clear_intr;
- }
- /*
- * if one field is just being captured configure
- * the next frame get the next frame from the empty
- * queue if no frame is available hold on to the
- * current buffer
- */
- spin_lock(&vpfe_dev->dma_queue_lock);
- if (!list_empty(&vpfe_dev->dma_queue) &&
- vpfe_dev->cur_frm == vpfe_dev->next_frm)
- vpfe_schedule_next_buffer(vpfe_dev);
- spin_unlock(&vpfe_dev->dma_queue_lock);
- } else if (fid == 0) {
- /*
- * out of sync. Recover from any hardware out-of-sync.
- * May loose one frame
- */
- vpfe_dev->field_id = fid;
- }
-clear_intr:
- if (vpfe_dev->cfg->clr_intr)
- vpfe_dev->cfg->clr_intr(irq);
-
- return IRQ_HANDLED;
-}
-
-/* vdint1_isr - isr handler for VINT1 interrupt */
-static irqreturn_t vdint1_isr(int irq, void *dev_id)
-{
- struct vpfe_device *vpfe_dev = dev_id;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
-
- /* if streaming not started, don't do anything */
- if (!vpfe_dev->started) {
- if (vpfe_dev->cfg->clr_intr)
- vpfe_dev->cfg->clr_intr(irq);
- return IRQ_HANDLED;
- }
-
- spin_lock(&vpfe_dev->dma_queue_lock);
- if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
- !list_empty(&vpfe_dev->dma_queue) &&
- vpfe_dev->cur_frm == vpfe_dev->next_frm)
- vpfe_schedule_next_buffer(vpfe_dev);
- spin_unlock(&vpfe_dev->dma_queue_lock);
-
- if (vpfe_dev->cfg->clr_intr)
- vpfe_dev->cfg->clr_intr(irq);
-
- return IRQ_HANDLED;
-}
-
-static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
-{
- enum ccdc_frmfmt frame_format;
-
- frame_format = ccdc_dev->hw_ops.get_frame_format();
- if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
- free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
-}
-
-static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
-{
- enum ccdc_frmfmt frame_format;
-
- frame_format = ccdc_dev->hw_ops.get_frame_format();
- if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
- return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
- IRQF_DISABLED, "vpfe_capture1",
- vpfe_dev);
- }
- return 0;
-}
-
-/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */
-static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev)
-{
- vpfe_dev->started = 0;
- ccdc_dev->hw_ops.enable(0);
- if (ccdc_dev->hw_ops.enable_out_to_sdram)
- ccdc_dev->hw_ops.enable_out_to_sdram(0);
-}
-
-/*
- * vpfe_release : This function deletes buffer queue, frees the
- * buffers and the vpfe file handle
- */
-static int vpfe_release(struct file *file)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh = file->private_data;
- struct vpfe_subdev_info *sdinfo;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
-
- /* Get the device lock */
- mutex_lock(&vpfe_dev->lock);
- /* if this instance is doing IO */
- if (fh->io_allowed) {
- if (vpfe_dev->started) {
- sdinfo = vpfe_dev->current_subdev;
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
- sdinfo->grp_id,
- video, s_stream, 0);
- if (ret && (ret != -ENOIOCTLCMD))
- v4l2_err(&vpfe_dev->v4l2_dev,
- "stream off failed in subdev\n");
- vpfe_stop_ccdc_capture(vpfe_dev);
- vpfe_detach_irq(vpfe_dev);
- videobuf_streamoff(&vpfe_dev->buffer_queue);
- }
- vpfe_dev->io_usrs = 0;
- vpfe_dev->numbuffers = config_params.numbuffers;
- }
-
- /* Decrement device usrs counter */
- vpfe_dev->usrs--;
- /* Close the priority */
- v4l2_prio_close(&vpfe_dev->prio, fh->prio);
- /* If this is the last file handle */
- if (!vpfe_dev->usrs) {
- vpfe_dev->initialized = 0;
- if (ccdc_dev->hw_ops.close)
- ccdc_dev->hw_ops.close(vpfe_dev->pdev);
- module_put(ccdc_dev->owner);
- }
- mutex_unlock(&vpfe_dev->lock);
- file->private_data = NULL;
- /* Free memory allocated to file handle object */
- kfree(fh);
- return 0;
-}
-
-/*
- * vpfe_mmap : It is used to map kernel space buffers
- * into user spaces
- */
-static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
-{
- /* Get the device object and file handle object */
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
-
- return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma);
-}
-
-/*
- * vpfe_poll: It is used for select/poll system call
- */
-static unsigned int vpfe_poll(struct file *file, poll_table *wait)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
-
- if (vpfe_dev->started)
- return videobuf_poll_stream(file,
- &vpfe_dev->buffer_queue, wait);
- return 0;
-}
-
-/* vpfe capture driver file operations */
-static const struct v4l2_file_operations vpfe_fops = {
- .owner = THIS_MODULE,
- .open = vpfe_open,
- .release = vpfe_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vpfe_mmap,
- .poll = vpfe_poll
-};
-
-/*
- * vpfe_check_format()
- * This function adjust the input pixel format as per hardware
- * capabilities and update the same in pixfmt.
- * Following algorithm used :-
- *
- * If given pixformat is not in the vpfe list of pix formats or not
- * supported by the hardware, current value of pixformat in the device
- * is used
- * If given field is not supported, then current field is used. If field
- * is different from current, then it is matched with that from sub device.
- * Minimum height is 2 lines for interlaced or tb field and 1 line for
- * progressive. Maximum height is clamped to active active lines of scan
- * Minimum width is 32 bytes in memory and width is clamped to active
- * pixels of scan.
- * bytesperline is a multiple of 32.
- */
-static const struct vpfe_pixel_format *
- vpfe_check_format(struct vpfe_device *vpfe_dev,
- struct v4l2_pix_format *pixfmt)
-{
- u32 min_height = 1, min_width = 32, max_width, max_height;
- const struct vpfe_pixel_format *vpfe_pix_fmt;
- u32 pix;
- int temp, found;
-
- vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
- if (NULL == vpfe_pix_fmt) {
- /*
- * use current pixel format in the vpfe device. We
- * will find this pix format in the table
- */
- pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
- vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
- }
-
- /* check if hw supports it */
- temp = 0;
- found = 0;
- while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
- if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
- found = 1;
- break;
- }
- temp++;
- }
-
- if (!found) {
- /* use current pixel format */
- pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
- /*
- * Since this is currently used in the vpfe device, we
- * will find this pix format in the table
- */
- vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
- }
-
- /* check what field format is supported */
- if (pixfmt->field == V4L2_FIELD_ANY) {
- /* if field is any, use current value as default */
- pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
- }
-
- /*
- * if field is not same as current field in the vpfe device
- * try matching the field with the sub device field
- */
- if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) {
- /*
- * If field value is not in the supported fields, use current
- * field used in the device as default
- */
- switch (pixfmt->field) {
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_SEQ_TB:
- /* if sub device is supporting progressive, use that */
- if (!vpfe_dev->std_info.frame_format)
- pixfmt->field = V4L2_FIELD_NONE;
- break;
- case V4L2_FIELD_NONE:
- if (vpfe_dev->std_info.frame_format)
- pixfmt->field = V4L2_FIELD_INTERLACED;
- break;
-
- default:
- /* use current field as default */
- pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
- break;
- }
- }
-
- /* Now adjust image resolutions supported */
- if (pixfmt->field == V4L2_FIELD_INTERLACED ||
- pixfmt->field == V4L2_FIELD_SEQ_TB)
- min_height = 2;
-
- max_width = vpfe_dev->std_info.active_pixels;
- max_height = vpfe_dev->std_info.active_lines;
- min_width /= vpfe_pix_fmt->bpp;
-
- v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n",
- pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp);
-
- pixfmt->width = clamp((pixfmt->width), min_width, max_width);
- pixfmt->height = clamp((pixfmt->height), min_height, max_height);
-
- /* If interlaced, adjust height to be a multiple of 2 */
- if (pixfmt->field == V4L2_FIELD_INTERLACED)
- pixfmt->height &= (~1);
- /*
- * recalculate bytesperline and sizeimage since width
- * and height might have changed
- */
- pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31)
- & ~31);
- if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
- pixfmt->sizeimage =
- pixfmt->bytesperline * pixfmt->height +
- ((pixfmt->bytesperline * pixfmt->height) >> 1);
- else
- pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
-
- v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height ="
- " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n",
- pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp,
- pixfmt->bytesperline, pixfmt->sizeimage);
- return vpfe_pix_fmt;
-}
-
-static int vpfe_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
-
- cap->version = VPFE_CAPTURE_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
- strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
- return 0;
-}
-
-static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
- /* Fill in the information about format */
- *fmt = vpfe_dev->fmt;
- return ret;
-}
-
-static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- const struct vpfe_pixel_format *pix_fmt;
- int temp_index;
- u32 pix;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
-
- if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0)
- return -EINVAL;
-
- /* Fill in the information about format */
- pix_fmt = vpfe_lookup_pix_format(pix);
- if (NULL != pix_fmt) {
- temp_index = fmt->index;
- *fmt = pix_fmt->fmtdesc;
- fmt->index = temp_index;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- const struct vpfe_pixel_format *pix_fmts;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
-
- /* If streaming is started, return error */
- if (vpfe_dev->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
- return -EBUSY;
- }
-
- /* Check for valid frame format */
- pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix);
-
- if (NULL == pix_fmts)
- return -EINVAL;
-
- /* store the pixel format in the device object */
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- /* First detach any IRQ if currently attached */
- vpfe_detach_irq(vpfe_dev);
- vpfe_dev->fmt = *fmt;
- /* set image capture parameters in the ccdc */
- ret = vpfe_config_ccdc_image_format(vpfe_dev);
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- const struct vpfe_pixel_format *pix_fmts;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n");
-
- pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix);
- if (NULL == pix_fmts)
- return -EINVAL;
- return 0;
-}
-
-/*
- * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
- * given app input index
- */
-static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev,
- int *subdev_index,
- int *subdev_input_index,
- int app_input_index)
-{
- struct vpfe_config *cfg = vpfe_dev->cfg;
- struct vpfe_subdev_info *sdinfo;
- int i, j = 0;
-
- for (i = 0; i < cfg->num_subdevs; i++) {
- sdinfo = &cfg->sub_devs[i];
- if (app_input_index < (j + sdinfo->num_inputs)) {
- *subdev_index = i;
- *subdev_input_index = app_input_index - j;
- return 0;
- }
- j += sdinfo->num_inputs;
- }
- return -EINVAL;
-}
-
-/*
- * vpfe_get_app_input - Get app input index for a given subdev input index
- * driver stores the input index of the current sub device and translate it
- * when application request the current input
- */
-static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
- int *app_input_index)
-{
- struct vpfe_config *cfg = vpfe_dev->cfg;
- struct vpfe_subdev_info *sdinfo;
- int i, j = 0;
-
- for (i = 0; i < cfg->num_subdevs; i++) {
- sdinfo = &cfg->sub_devs[i];
- if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
- if (vpfe_dev->current_input >= sdinfo->num_inputs)
- return -1;
- *app_input_index = j + vpfe_dev->current_input;
- return 0;
- }
- j += sdinfo->num_inputs;
- }
- return -EINVAL;
-}
-
-static int vpfe_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
- int subdev, index ;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
-
- if (vpfe_get_subdev_input_index(vpfe_dev,
- &subdev,
- &index,
- inp->index) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "input information not found"
- " for the subdev\n");
- return -EINVAL;
- }
- sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
- memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
- return 0;
-}
-
-static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
-
- return vpfe_get_app_input_index(vpfe_dev, index);
-}
-
-
-static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
- int subdev_index, inp_index;
- struct vpfe_route *route;
- u32 input = 0, output = 0;
- int ret = -EINVAL;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- /*
- * If streaming is started return device busy
- * error
- */
- if (vpfe_dev->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
- ret = -EBUSY;
- goto unlock_out;
- }
-
- if (vpfe_get_subdev_input_index(vpfe_dev,
- &subdev_index,
- &inp_index,
- index) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
- goto unlock_out;
- }
-
- sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
- route = &sdinfo->routes[inp_index];
- if (route && sdinfo->can_route) {
- input = route->input;
- output = route->output;
- }
-
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, s_routing, input, output, 0);
-
- if (ret) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "vpfe_doioctl:error in setting input in decoder\n");
- ret = -EINVAL;
- goto unlock_out;
- }
- vpfe_dev->current_subdev = sdinfo;
- vpfe_dev->current_input = index;
- vpfe_dev->std_index = 0;
-
- /* set the bus/interface parameter for the sub device in ccdc */
- ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
- if (ret)
- goto unlock_out;
-
- /* set the default image parameters in the device */
- ret = vpfe_config_image_format(vpfe_dev,
- &vpfe_standards[vpfe_dev->std_index].std_id);
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- sdinfo = vpfe_dev->current_subdev;
- if (ret)
- return ret;
- /* Call querystd function of decoder device */
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, querystd, std_id);
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
-
- /* Call decoder driver function to set the standard */
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- sdinfo = vpfe_dev->current_subdev;
- /* If streaming is started, return device busy error */
- if (vpfe_dev->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
- ret = -EBUSY;
- goto unlock_out;
- }
-
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_std, *std_id);
- if (ret < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
- goto unlock_out;
- }
- ret = vpfe_config_image_format(vpfe_dev, std_id);
-
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
-
- *std_id = vpfe_standards[vpfe_dev->std_index].std_id;
- return 0;
-}
-/*
- * Videobuf operations
- */
-static int vpfe_videobuf_setup(struct videobuf_queue *vq,
- unsigned int *count,
- unsigned int *size)
-{
- struct vpfe_fh *fh = vq->priv_data;
- struct vpfe_device *vpfe_dev = fh->vpfe_dev;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
- *size = vpfe_dev->fmt.fmt.pix.sizeimage;
- if (vpfe_dev->memory == V4L2_MEMORY_MMAP &&
- vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize)
- *size = config_params.device_bufsize;
-
- if (*count < config_params.min_numbuffers)
- *count = config_params.min_numbuffers;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "count=%d, size=%d\n", *count, *size);
- return 0;
-}
-
-static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct vpfe_fh *fh = vq->priv_data;
- struct vpfe_device *vpfe_dev = fh->vpfe_dev;
- unsigned long addr;
- int ret;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
-
- /* If buffer is not initialized, initialize it */
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- vb->width = vpfe_dev->fmt.fmt.pix.width;
- vb->height = vpfe_dev->fmt.fmt.pix.height;
- vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
- vb->field = field;
-
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret < 0)
- return ret;
-
- addr = videobuf_to_dma_contig(vb);
- /* Make sure user addresses are aligned to 32 bytes */
- if (!ALIGN(addr, 32))
- return -EINVAL;
-
- vb->state = VIDEOBUF_PREPARED;
- }
- return 0;
-}
-
-static void vpfe_videobuf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- /* Get the file handle object and device object */
- struct vpfe_fh *fh = vq->priv_data;
- struct vpfe_device *vpfe_dev = fh->vpfe_dev;
- unsigned long flags;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n");
-
- /* add the buffer to the DMA queue */
- spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
- list_add_tail(&vb->queue, &vpfe_dev->dma_queue);
- spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
-
- /* Change state of the buffer */
- vb->state = VIDEOBUF_QUEUED;
-}
-
-static void vpfe_videobuf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct vpfe_fh *fh = vq->priv_data;
- struct vpfe_device *vpfe_dev = fh->vpfe_dev;
- unsigned long flags;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
-
- /*
- * We need to flush the buffer from the dma queue since
- * they are de-allocated
- */
- spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
- INIT_LIST_HEAD(&vpfe_dev->dma_queue);
- spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops vpfe_videobuf_qops = {
- .buf_setup = vpfe_videobuf_setup,
- .buf_prepare = vpfe_videobuf_prepare,
- .buf_queue = vpfe_videobuf_queue,
- .buf_release = vpfe_videobuf_release,
-};
-
-/*
- * vpfe_reqbufs. currently support REQBUF only once opening
- * the device.
- */
-static int vpfe_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req_buf)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh = file->private_data;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- if (vpfe_dev->io_usrs != 0) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
- ret = -EBUSY;
- goto unlock_out;
- }
-
- vpfe_dev->memory = req_buf->memory;
- videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
- &vpfe_videobuf_qops,
- vpfe_dev->pdev,
- &vpfe_dev->irqlock,
- req_buf->type,
- vpfe_dev->fmt.fmt.pix.field,
- sizeof(struct videobuf_buffer),
- fh, NULL);
-
- fh->io_allowed = 1;
- vpfe_dev->io_usrs = 1;
- INIT_LIST_HEAD(&vpfe_dev->dma_queue);
- ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf);
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- if (vpfe_dev->memory != V4L2_MEMORY_MMAP) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
- return -EINVAL;
- }
- /* Call videobuf_querybuf to get information */
- return videobuf_querybuf(&vpfe_dev->buffer_queue, buf);
-}
-
-static int vpfe_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh = file->private_data;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- /*
- * If this file handle is not allowed to do IO,
- * return error
- */
- if (!fh->io_allowed) {
- v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
- return videobuf_qbuf(&vpfe_dev->buffer_queue, p);
-}
-
-static int vpfe_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
- return videobuf_dqbuf(&vpfe_dev->buffer_queue,
- buf, file->f_flags & O_NONBLOCK);
-}
-
-static int vpfe_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, queryctrl, qctrl);
-
-}
-
-static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, g_ctrl, ctrl);
-}
-
-static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_ctrl, ctrl);
-}
-
-/*
- * vpfe_calculate_offsets : This function calculates buffers offset
- * for top and bottom field
- */
-static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev)
-{
- struct v4l2_rect image_win;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n");
-
- ccdc_dev->hw_ops.get_image_window(&image_win);
- vpfe_dev->field_off = image_win.height * image_win.width;
-}
-
-/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */
-static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev)
-{
- ccdc_dev->hw_ops.enable(1);
- if (ccdc_dev->hw_ops.enable_out_to_sdram)
- ccdc_dev->hw_ops.enable_out_to_sdram(1);
- vpfe_dev->started = 1;
-}
-
-/*
- * vpfe_streamon. Assume the DMA queue is not empty.
- * application is expected to call QBUF before calling
- * this ioctl. If not, driver returns error
- */
-static int vpfe_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh = file->private_data;
- struct vpfe_subdev_info *sdinfo;
- unsigned long addr;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
-
- sdinfo = vpfe_dev->current_subdev;
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, s_stream, 1);
-
- if (ret && (ret != -ENOIOCTLCMD)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n");
- return -EINVAL;
- }
-
- /* If buffer queue is empty, return error */
- if (list_empty(&vpfe_dev->buffer_queue.stream)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
- return -EIO;
- }
-
- /* Call videobuf_streamon to start streaming * in videobuf */
- ret = videobuf_streamon(&vpfe_dev->buffer_queue);
- if (ret)
- return ret;
-
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- goto streamoff;
- /* Get the next frame from the buffer queue */
- vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
- struct videobuf_buffer, queue);
- vpfe_dev->cur_frm = vpfe_dev->next_frm;
- /* Remove buffer from the buffer queue */
- list_del(&vpfe_dev->cur_frm->queue);
- /* Mark state of the current frame to active */
- vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
- /* Initialize field_id and started member */
- vpfe_dev->field_id = 0;
- addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
-
- /* Calculate field offset */
- vpfe_calculate_offsets(vpfe_dev);
-
- if (vpfe_attach_irq(vpfe_dev) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error in attaching interrupt handle\n");
- ret = -EFAULT;
- goto unlock_out;
- }
- if (ccdc_dev->hw_ops.configure() < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error in configuring ccdc\n");
- ret = -EINVAL;
- goto unlock_out;
- }
- ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr));
- vpfe_start_ccdc_capture(vpfe_dev);
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
-streamoff:
- ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
- return ret;
-}
-
-static int vpfe_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_fh *fh = file->private_data;
- struct vpfe_subdev_info *sdinfo;
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!vpfe_dev->started) {
- v4l2_err(&vpfe_dev->v4l2_dev, "device started\n");
- return -EINVAL;
- }
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- vpfe_stop_ccdc_capture(vpfe_dev);
- vpfe_detach_irq(vpfe_dev);
-
- sdinfo = vpfe_dev->current_subdev;
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, s_stream, 0);
-
- if (ret && (ret != -ENOIOCTLCMD))
- v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n");
- ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-static int vpfe_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *crop)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
-
- if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
- return -EINVAL;
-
- memset(crop, 0, sizeof(struct v4l2_cropcap));
- crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- crop->bounds.width = crop->defrect.width =
- vpfe_standards[vpfe_dev->std_index].width;
- crop->bounds.height = crop->defrect.height =
- vpfe_standards[vpfe_dev->std_index].height;
- crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
- return 0;
-}
-
-static int vpfe_g_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n");
-
- crop->c = vpfe_dev->crop;
- return 0;
-}
-
-static int vpfe_s_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- int ret = 0;
-
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n");
-
- if (vpfe_dev->started) {
- /* make sure streaming is not started */
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Cannot change crop when streaming is ON\n");
- return -EBUSY;
- }
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- if (crop->c.top < 0 || crop->c.left < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "doesn't support negative values for top & left\n");
- ret = -EINVAL;
- goto unlock_out;
- }
-
- /* adjust the width to 16 pixel boundary */
- crop->c.width = ((crop->c.width + 15) & ~0xf);
-
- /* make sure parameters are valid */
- if ((crop->c.left + crop->c.width >
- vpfe_dev->std_info.active_pixels) ||
- (crop->c.top + crop->c.height >
- vpfe_dev->std_info.active_lines)) {
- v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n");
- ret = -EINVAL;
- goto unlock_out;
- }
- ccdc_dev->hw_ops.set_image_window(&crop->c);
- vpfe_dev->fmt.fmt.pix.width = crop->c.width;
- vpfe_dev->fmt.fmt.pix.height = crop->c.height;
- vpfe_dev->fmt.fmt.pix.bytesperline =
- ccdc_dev->hw_ops.get_line_length();
- vpfe_dev->fmt.fmt.pix.sizeimage =
- vpfe_dev->fmt.fmt.pix.bytesperline *
- vpfe_dev->fmt.fmt.pix.height;
- vpfe_dev->crop = crop->c;
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-
-static long vpfe_param_handler(struct file *file, void *priv,
- bool valid_prio, int cmd, void *param)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- int ret = 0;
-
- v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
-
- if (vpfe_dev->started) {
- /* only allowed if streaming is not started */
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "device already started\n");
- return -EBUSY;
- }
-
- ret = mutex_lock_interruptible(&vpfe_dev->lock);
- if (ret)
- return ret;
-
- switch (cmd) {
- case VPFE_CMD_S_CCDC_RAW_PARAMS:
- v4l2_warn(&vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
- if (ccdc_dev->hw_ops.set_params) {
- ret = ccdc_dev->hw_ops.set_params(param);
- if (ret) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Error setting parameters in CCDC\n");
- goto unlock_out;
- }
- if (vpfe_get_ccdc_image_format(vpfe_dev,
- &vpfe_dev->fmt) < 0) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Invalid image format at CCDC\n");
- goto unlock_out;
- }
- } else {
- ret = -EINVAL;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
- }
- break;
- default:
- ret = -ENOTTY;
- }
-unlock_out:
- mutex_unlock(&vpfe_dev->lock);
- return ret;
-}
-
-
-/* vpfe capture ioctl operations */
-static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
- .vidioc_querycap = vpfe_querycap,
- .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap,
- .vidioc_enum_input = vpfe_enum_input,
- .vidioc_g_input = vpfe_g_input,
- .vidioc_s_input = vpfe_s_input,
- .vidioc_querystd = vpfe_querystd,
- .vidioc_s_std = vpfe_s_std,
- .vidioc_g_std = vpfe_g_std,
- .vidioc_queryctrl = vpfe_queryctrl,
- .vidioc_g_ctrl = vpfe_g_ctrl,
- .vidioc_s_ctrl = vpfe_s_ctrl,
- .vidioc_reqbufs = vpfe_reqbufs,
- .vidioc_querybuf = vpfe_querybuf,
- .vidioc_qbuf = vpfe_qbuf,
- .vidioc_dqbuf = vpfe_dqbuf,
- .vidioc_streamon = vpfe_streamon,
- .vidioc_streamoff = vpfe_streamoff,
- .vidioc_cropcap = vpfe_cropcap,
- .vidioc_g_crop = vpfe_g_crop,
- .vidioc_s_crop = vpfe_s_crop,
- .vidioc_default = vpfe_param_handler,
-};
-
-static struct vpfe_device *vpfe_initialize(void)
-{
- struct vpfe_device *vpfe_dev;
-
- /* Default number of buffers should be 3 */
- if ((numbuffers > 0) &&
- (numbuffers < config_params.min_numbuffers))
- numbuffers = config_params.min_numbuffers;
-
- /*
- * Set buffer size to min buffers size if invalid buffer size is
- * given
- */
- if (bufsize < config_params.min_bufsize)
- bufsize = config_params.min_bufsize;
-
- config_params.numbuffers = numbuffers;
-
- if (numbuffers)
- config_params.device_bufsize = bufsize;
-
- /* Allocate memory for device objects */
- vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
-
- return vpfe_dev;
-}
-
-/*
- * vpfe_probe : This function creates device entries by register
- * itself to the V4L2 driver and initializes fields of each
- * device objects
- */
-static __init int vpfe_probe(struct platform_device *pdev)
-{
- struct vpfe_subdev_info *sdinfo;
- struct vpfe_config *vpfe_cfg;
- struct resource *res1;
- struct vpfe_device *vpfe_dev;
- struct i2c_adapter *i2c_adap;
- struct video_device *vfd;
- int ret = -ENOMEM, i, j;
- int num_subdevs = 0;
-
- /* Get the pointer to the device object */
- vpfe_dev = vpfe_initialize();
-
- if (!vpfe_dev) {
- v4l2_err(pdev->dev.driver,
- "Failed to allocate memory for vpfe_dev\n");
- return ret;
- }
-
- vpfe_dev->pdev = &pdev->dev;
-
- if (NULL == pdev->dev.platform_data) {
- v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
- ret = -ENODEV;
- goto probe_free_dev_mem;
- }
-
- vpfe_cfg = pdev->dev.platform_data;
- vpfe_dev->cfg = vpfe_cfg;
- if (NULL == vpfe_cfg->ccdc ||
- NULL == vpfe_cfg->card_name ||
- NULL == vpfe_cfg->sub_devs) {
- v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
- ret = -ENOENT;
- goto probe_free_dev_mem;
- }
-
- /* Allocate memory for ccdc configuration */
- ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
- if (NULL == ccdc_cfg) {
- v4l2_err(pdev->dev.driver,
- "Memory allocation failed for ccdc_cfg\n");
- goto probe_free_lock;
- }
-
- mutex_lock(&ccdc_lock);
-
- strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
- /* Get VINT0 irq resource */
- res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get interrupt for VINT0\n");
- ret = -ENODEV;
- goto probe_free_ccdc_cfg_mem;
- }
- vpfe_dev->ccdc_irq0 = res1->start;
-
- /* Get VINT1 irq resource */
- res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get interrupt for VINT1\n");
- ret = -ENODEV;
- goto probe_free_ccdc_cfg_mem;
- }
- vpfe_dev->ccdc_irq1 = res1->start;
-
- ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
- "vpfe_capture0", vpfe_dev);
-
- if (0 != ret) {
- v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
- goto probe_free_ccdc_cfg_mem;
- }
-
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (NULL == vfd) {
- ret = -ENOMEM;
- v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
- goto probe_out_release_irq;
- }
-
- /* Initialize field of video device */
- vfd->release = video_device_release;
- vfd->fops = &vpfe_fops;
- vfd->ioctl_ops = &vpfe_ioctl_ops;
- vfd->tvnorms = 0;
- vfd->current_norm = V4L2_STD_PAL;
- vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
- snprintf(vfd->name, sizeof(vfd->name),
- "%s_V%d.%d.%d",
- CAPTURE_DRV_NAME,
- (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
- (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
- (VPFE_CAPTURE_VERSION_CODE) & 0xff);
- /* Set video_dev to the video device */
- vpfe_dev->video_dev = vfd;
-
- ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
- if (ret) {
- v4l2_err(pdev->dev.driver,
- "Unable to register v4l2 device.\n");
- goto probe_out_video_release;
- }
- v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
- spin_lock_init(&vpfe_dev->irqlock);
- spin_lock_init(&vpfe_dev->dma_queue_lock);
- mutex_init(&vpfe_dev->lock);
-
- /* Initialize field of the device objects */
- vpfe_dev->numbuffers = config_params.numbuffers;
-
- /* Initialize prio member of device object */
- v4l2_prio_init(&vpfe_dev->prio);
- /* register video device */
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "trying to register vpfe device.\n");
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "video_dev=%x\n", (int)&vpfe_dev->video_dev);
- vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = video_register_device(vpfe_dev->video_dev,
- VFL_TYPE_GRABBER, -1);
-
- if (ret) {
- v4l2_err(pdev->dev.driver,
- "Unable to register video device.\n");
- goto probe_out_v4l2_unregister;
- }
-
- v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n");
- /* set the driver data in platform device */
- platform_set_drvdata(pdev, vpfe_dev);
- /* set driver private data */
- video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
- i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id);
- num_subdevs = vpfe_cfg->num_subdevs;
- vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
- GFP_KERNEL);
- if (NULL == vpfe_dev->sd) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "unable to allocate memory for subdevice pointers\n");
- ret = -ENOMEM;
- goto probe_out_video_unregister;
- }
-
- for (i = 0; i < num_subdevs; i++) {
- struct v4l2_input *inps;
-
- sdinfo = &vpfe_cfg->sub_devs[i];
-
- /* Load up the subdevice */
- vpfe_dev->sd[i] =
- v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
- i2c_adap,
- &sdinfo->board_info,
- NULL);
- if (vpfe_dev->sd[i]) {
- v4l2_info(&vpfe_dev->v4l2_dev,
- "v4l2 sub device %s registered\n",
- sdinfo->name);
- vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
- /* update tvnorms from the sub devices */
- for (j = 0; j < sdinfo->num_inputs; j++) {
- inps = &sdinfo->inputs[j];
- vfd->tvnorms |= inps->std;
- }
- } else {
- v4l2_info(&vpfe_dev->v4l2_dev,
- "v4l2 sub device %s register fails\n",
- sdinfo->name);
- goto probe_sd_out;
- }
- }
-
- /* set first sub device as current one */
- vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
-
- /* We have at least one sub device to work with */
- mutex_unlock(&ccdc_lock);
- return 0;
-
-probe_sd_out:
- kfree(vpfe_dev->sd);
-probe_out_video_unregister:
- video_unregister_device(vpfe_dev->video_dev);
-probe_out_v4l2_unregister:
- v4l2_device_unregister(&vpfe_dev->v4l2_dev);
-probe_out_video_release:
- if (!video_is_registered(vpfe_dev->video_dev))
- video_device_release(vpfe_dev->video_dev);
-probe_out_release_irq:
- free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
-probe_free_ccdc_cfg_mem:
- kfree(ccdc_cfg);
-probe_free_lock:
- mutex_unlock(&ccdc_lock);
-probe_free_dev_mem:
- kfree(vpfe_dev);
- return ret;
-}
-
-/*
- * vpfe_remove : It un-register device from V4L2 driver
- */
-static int __devexit vpfe_remove(struct platform_device *pdev)
-{
- struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
-
- v4l2_info(pdev->dev.driver, "vpfe_remove\n");
-
- free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
- kfree(vpfe_dev->sd);
- v4l2_device_unregister(&vpfe_dev->v4l2_dev);
- video_unregister_device(vpfe_dev->video_dev);
- kfree(vpfe_dev);
- kfree(ccdc_cfg);
- return 0;
-}
-
-static int vpfe_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int vpfe_resume(struct device *dev)
-{
- return 0;
-}
-
-static const struct dev_pm_ops vpfe_dev_pm_ops = {
- .suspend = vpfe_suspend,
- .resume = vpfe_resume,
-};
-
-static struct platform_driver vpfe_driver = {
- .driver = {
- .name = CAPTURE_DRV_NAME,
- .owner = THIS_MODULE,
- .pm = &vpfe_dev_pm_ops,
- },
- .probe = vpfe_probe,
- .remove = __devexit_p(vpfe_remove),
-};
-
-module_platform_driver(vpfe_driver);
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c
deleted file mode 100644
index b3637aff8fee..000000000000
--- a/drivers/media/video/davinci/vpif.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * vpif - Video Port Interface driver
- * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
- * that receiveing video byte stream and two channels(2, 3) for video output.
- * The hardware supports SDTV, HDTV formats, raw data capture.
- * Currently, the driver supports NTSC and PAL standards.
- *
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed .as is. WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <mach/hardware.h>
-
-#include "vpif.h"
-
-MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
-MODULE_LICENSE("GPL");
-
-#define VPIF_CH0_MAX_MODES (22)
-#define VPIF_CH1_MAX_MODES (02)
-#define VPIF_CH2_MAX_MODES (15)
-#define VPIF_CH3_MAX_MODES (02)
-
-static resource_size_t res_len;
-static struct resource *res;
-spinlock_t vpif_lock;
-
-void __iomem *vpif_base;
-struct clk *vpif_clk;
-
-/**
- * ch_params: video standard configuration parameters for vpif
- * The table must include all presets from supported subdevices.
- */
-const struct vpif_channel_config_params ch_params[] = {
- /* HDTV formats */
- {
- .name = "480p59_94",
- .width = 720,
- .height = 480,
- .frm_fmt = 1,
- .ycmux_mode = 0,
- .eav2sav = 138-8,
- .sav2eav = 720,
- .l1 = 1,
- .l3 = 43,
- .l5 = 523,
- .vsize = 525,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_480P59_94,
- },
- {
- .name = "576p50",
- .width = 720,
- .height = 576,
- .frm_fmt = 1,
- .ycmux_mode = 0,
- .eav2sav = 144-8,
- .sav2eav = 720,
- .l1 = 1,
- .l3 = 45,
- .l5 = 621,
- .vsize = 625,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_576P50,
- },
- {
- .name = "720p50",
- .width = 1280,
- .height = 720,
- .frm_fmt = 1,
- .ycmux_mode = 0,
- .eav2sav = 700-8,
- .sav2eav = 1280,
- .l1 = 1,
- .l3 = 26,
- .l5 = 746,
- .vsize = 750,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_720P50,
- },
- {
- .name = "720p60",
- .width = 1280,
- .height = 720,
- .frm_fmt = 1,
- .ycmux_mode = 0,
- .eav2sav = 370 - 8,
- .sav2eav = 1280,
- .l1 = 1,
- .l3 = 26,
- .l5 = 746,
- .vsize = 750,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_720P60,
- },
- {
- .name = "1080I50",
- .width = 1920,
- .height = 1080,
- .frm_fmt = 0,
- .ycmux_mode = 0,
- .eav2sav = 720 - 8,
- .sav2eav = 1920,
- .l1 = 1,
- .l3 = 21,
- .l5 = 561,
- .l7 = 563,
- .l9 = 584,
- .l11 = 1124,
- .vsize = 1125,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_1080I50,
- },
- {
- .name = "1080I60",
- .width = 1920,
- .height = 1080,
- .frm_fmt = 0,
- .ycmux_mode = 0,
- .eav2sav = 280 - 8,
- .sav2eav = 1920,
- .l1 = 1,
- .l3 = 21,
- .l5 = 561,
- .l7 = 563,
- .l9 = 584,
- .l11 = 1124,
- .vsize = 1125,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_1080I60,
- },
- {
- .name = "1080p60",
- .width = 1920,
- .height = 1080,
- .frm_fmt = 1,
- .ycmux_mode = 0,
- .eav2sav = 280 - 8,
- .sav2eav = 1920,
- .l1 = 1,
- .l3 = 42,
- .l5 = 1122,
- .vsize = 1125,
- .capture_format = 0,
- .vbi_supported = 0,
- .hd_sd = 1,
- .dv_preset = V4L2_DV_1080P60,
- },
-
- /* SDTV formats */
- {
- .name = "NTSC_M",
- .width = 720,
- .height = 480,
- .frm_fmt = 0,
- .ycmux_mode = 1,
- .eav2sav = 268,
- .sav2eav = 1440,
- .l1 = 1,
- .l3 = 23,
- .l5 = 263,
- .l7 = 266,
- .l9 = 286,
- .l11 = 525,
- .vsize = 525,
- .capture_format = 0,
- .vbi_supported = 1,
- .hd_sd = 0,
- .stdid = V4L2_STD_525_60,
- },
- {
- .name = "PAL_BDGHIK",
- .width = 720,
- .height = 576,
- .frm_fmt = 0,
- .ycmux_mode = 1,
- .eav2sav = 280,
- .sav2eav = 1440,
- .l1 = 1,
- .l3 = 23,
- .l5 = 311,
- .l7 = 313,
- .l9 = 336,
- .l11 = 624,
- .vsize = 625,
- .capture_format = 0,
- .vbi_supported = 1,
- .hd_sd = 0,
- .stdid = V4L2_STD_625_50,
- },
-};
-
-const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
-
-static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
-{
- if (val)
- vpif_set_bit(reg, bit);
- else
- vpif_clr_bit(reg, bit);
-}
-
-/* This structure is used to keep track of VPIF size register's offsets */
-struct vpif_registers {
- u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
- u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
- u32 vanc1_size, width_mask, len_mask;
- u8 max_modes;
-};
-
-static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
- /* Channel0 */
- {
- VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
- VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
- VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
- VPIF_CH0_MAX_MODES,
- },
- /* Channel1 */
- {
- VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
- VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
- VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
- VPIF_CH1_MAX_MODES,
- },
- /* Channel2 */
- {
- VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
- VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
- VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
- VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
- VPIF_CH2_MAX_MODES
- },
- /* Channel3 */
- {
- VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
- VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
- VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
- VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
- VPIF_CH3_MAX_MODES
- },
-};
-
-/* vpif_set_mode_info:
- * This function is used to set horizontal and vertical config parameters
- * As per the standard in the channel, configure the values of L1, L3,
- * L5, L7 L9, L11 in VPIF Register , also write width and height
- */
-static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
- u8 channel_id, u8 config_channel_id)
-{
- u32 value;
-
- value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
- value <<= VPIF_CH_LEN_SHIFT;
- value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
- regw(value, vpifregs[channel_id].h_cfg);
-
- value = (config->l1 & vpifregs[config_channel_id].len_mask);
- value <<= VPIF_CH_LEN_SHIFT;
- value |= (config->l3 & vpifregs[config_channel_id].len_mask);
- regw(value, vpifregs[channel_id].v_cfg_00);
-
- value = (config->l5 & vpifregs[config_channel_id].len_mask);
- value <<= VPIF_CH_LEN_SHIFT;
- value |= (config->l7 & vpifregs[config_channel_id].len_mask);
- regw(value, vpifregs[channel_id].v_cfg_01);
-
- value = (config->l9 & vpifregs[config_channel_id].len_mask);
- value <<= VPIF_CH_LEN_SHIFT;
- value |= (config->l11 & vpifregs[config_channel_id].len_mask);
- regw(value, vpifregs[channel_id].v_cfg_02);
-
- value = (config->vsize & vpifregs[config_channel_id].len_mask);
- regw(value, vpifregs[channel_id].v_cfg);
-}
-
-/* config_vpif_params
- * Function to set the parameters of a channel
- * Mainly modifies the channel ciontrol register
- * It sets frame format, yc mux mode
- */
-static void config_vpif_params(struct vpif_params *vpifparams,
- u8 channel_id, u8 found)
-{
- const struct vpif_channel_config_params *config = &vpifparams->std_info;
- u32 value, ch_nip, reg;
- u8 start, end;
- int i;
-
- start = channel_id;
- end = channel_id + found;
-
- for (i = start; i < end; i++) {
- reg = vpifregs[i].ch_ctrl;
- if (channel_id < 2)
- ch_nip = VPIF_CAPTURE_CH_NIP;
- else
- ch_nip = VPIF_DISPLAY_CH_NIP;
-
- vpif_wr_bit(reg, ch_nip, config->frm_fmt);
- vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
- vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
- vpifparams->video_params.storage_mode);
-
- /* Set raster scanning SDR Format */
- vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
- vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
-
- if (channel_id > 1) /* Set the Pixel enable bit */
- vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
- else if (config->capture_format) {
- /* Set the polarity of various pins */
- vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
- vpifparams->iface.fid_pol);
- vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
- vpifparams->iface.vd_pol);
- vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
- vpifparams->iface.hd_pol);
-
- value = regr(reg);
- /* Set data width */
- value &= ~(0x3u <<
- VPIF_CH_DATA_WIDTH_BIT);
- value |= ((vpifparams->params.data_sz) <<
- VPIF_CH_DATA_WIDTH_BIT);
- regw(value, reg);
- }
-
- /* Write the pitch in the driver */
- regw((vpifparams->video_params.hpitch),
- vpifregs[i].line_offset);
- }
-}
-
-/* vpif_set_video_params
- * This function is used to set video parameters in VPIF register
- */
-int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
-{
- const struct vpif_channel_config_params *config = &vpifparams->std_info;
- int found = 1;
-
- vpif_set_mode_info(config, channel_id, channel_id);
- if (!config->ycmux_mode) {
- /* YC are on separate channels (HDTV formats) */
- vpif_set_mode_info(config, channel_id + 1, channel_id);
- found = 2;
- }
-
- config_vpif_params(vpifparams, channel_id, found);
-
- regw(0x80, VPIF_REQ_SIZE);
- regw(0x01, VPIF_EMULATION_CTRL);
-
- return found;
-}
-EXPORT_SYMBOL(vpif_set_video_params);
-
-void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
- u8 channel_id)
-{
- u32 value;
-
- value = 0x3F8 & (vbiparams->hstart0);
- value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
- regw(value, vpifregs[channel_id].vanc0_strt);
-
- value = 0x3F8 & (vbiparams->hstart1);
- value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
- regw(value, vpifregs[channel_id].vanc1_strt);
-
- value = 0x3F8 & (vbiparams->hsize0);
- value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
- regw(value, vpifregs[channel_id].vanc0_size);
-
- value = 0x3F8 & (vbiparams->hsize1);
- value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
- regw(value, vpifregs[channel_id].vanc1_size);
-
-}
-EXPORT_SYMBOL(vpif_set_vbi_display_params);
-
-int vpif_channel_getfid(u8 channel_id)
-{
- return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
- >> VPIF_CH_FID_SHIFT;
-}
-EXPORT_SYMBOL(vpif_channel_getfid);
-
-static int __init vpif_probe(struct platform_device *pdev)
-{
- int status = 0;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
-
- res_len = resource_size(res);
-
- res = request_mem_region(res->start, res_len, res->name);
- if (!res)
- return -EBUSY;
-
- vpif_base = ioremap(res->start, res_len);
- if (!vpif_base) {
- status = -EBUSY;
- goto fail;
- }
-
- vpif_clk = clk_get(&pdev->dev, "vpif");
- if (IS_ERR(vpif_clk)) {
- status = PTR_ERR(vpif_clk);
- goto clk_fail;
- }
- clk_enable(vpif_clk);
-
- spin_lock_init(&vpif_lock);
- dev_info(&pdev->dev, "vpif probe success\n");
- return 0;
-
-clk_fail:
- iounmap(vpif_base);
-fail:
- release_mem_region(res->start, res_len);
- return status;
-}
-
-static int __devexit vpif_remove(struct platform_device *pdev)
-{
- if (vpif_clk) {
- clk_disable(vpif_clk);
- clk_put(vpif_clk);
- }
-
- iounmap(vpif_base);
- release_mem_region(res->start, res_len);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int vpif_suspend(struct device *dev)
-{
- clk_disable(vpif_clk);
- return 0;
-}
-
-static int vpif_resume(struct device *dev)
-{
- clk_enable(vpif_clk);
- return 0;
-}
-
-static const struct dev_pm_ops vpif_pm = {
- .suspend = vpif_suspend,
- .resume = vpif_resume,
-};
-
-#define vpif_pm_ops (&vpif_pm)
-#else
-#define vpif_pm_ops NULL
-#endif
-
-static struct platform_driver vpif_driver = {
- .driver = {
- .name = "vpif",
- .owner = THIS_MODULE,
- .pm = vpif_pm_ops,
- },
- .remove = __devexit_p(vpif_remove),
- .probe = vpif_probe,
-};
-
-static void vpif_exit(void)
-{
- platform_driver_unregister(&vpif_driver);
-}
-
-static int __init vpif_init(void)
-{
- return platform_driver_register(&vpif_driver);
-}
-subsys_initcall(vpif_init);
-module_exit(vpif_exit);
-
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
deleted file mode 100644
index 266025e5d81d..000000000000
--- a/drivers/media/video/davinci/vpif_capture.c
+++ /dev/null
@@ -1,2444 +0,0 @@
-/*
- * Copyright (C) 2009 Texas Instruments Inc
- *
- * 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
- *
- * TODO : add support for VBI & HBI data service
- * add static buffer allocation
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-
-#include "vpif_capture.h"
-#include "vpif.h"
-
-MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VPIF_CAPTURE_VERSION);
-
-#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
-#define vpif_dbg(level, debug, fmt, arg...) \
- v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
-
-static int debug = 1;
-static u32 ch0_numbuffers = 3;
-static u32 ch1_numbuffers = 3;
-static u32 ch0_bufsize = 1920 * 1080 * 2;
-static u32 ch1_bufsize = 720 * 576 * 2;
-
-module_param(debug, int, 0644);
-module_param(ch0_numbuffers, uint, S_IRUGO);
-module_param(ch1_numbuffers, uint, S_IRUGO);
-module_param(ch0_bufsize, uint, S_IRUGO);
-module_param(ch1_bufsize, uint, S_IRUGO);
-
-MODULE_PARM_DESC(debug, "Debug level 0-1");
-MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)");
-MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)");
-MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)");
-MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)");
-
-static struct vpif_config_params config_params = {
- .min_numbuffers = 3,
- .numbuffers[0] = 3,
- .numbuffers[1] = 3,
- .min_bufsize[0] = 720 * 480 * 2,
- .min_bufsize[1] = 720 * 480 * 2,
- .channel_bufsize[0] = 1920 * 1080 * 2,
- .channel_bufsize[1] = 720 * 576 * 2,
-};
-
-/* global variables */
-static struct vpif_device vpif_obj = { {NULL} };
-static struct device *vpif_dev;
-static void vpif_calculate_offsets(struct channel_obj *ch);
-static void vpif_config_addr(struct channel_obj *ch, int muxmode);
-
-/**
- * buffer_prepare : callback function for buffer prepare
- * @vb: ptr to vb2_buffer
- *
- * This is the callback function for buffer prepare when vb2_qbuf()
- * function is called. The buffer is prepared and user space virtual address
- * or user address is converted into physical address
- */
-static int vpif_buffer_prepare(struct vb2_buffer *vb)
-{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_queue *q = vb->vb2_queue;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long addr;
-
- vpif_dbg(2, debug, "vpif_buffer_prepare\n");
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED) {
- vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- goto exit;
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
-
- if (q->streaming) {
- if (!IS_ALIGNED((addr + common->ytop_off), 8) ||
- !IS_ALIGNED((addr + common->ybtm_off), 8) ||
- !IS_ALIGNED((addr + common->ctop_off), 8) ||
- !IS_ALIGNED((addr + common->cbtm_off), 8))
- goto exit;
- }
- }
- return 0;
-exit:
- vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n");
- return -EINVAL;
-}
-
-/**
- * vpif_buffer_queue_setup : Callback function for buffer setup.
- * @vq: vb2_queue ptr
- * @fmt: v4l2 format
- * @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
- * @sizes[]: contains the size (in bytes) of each plane.
- * @alloc_ctxs: ptr to allocation context
- *
- * This callback function is called when reqbuf() is called to adjust
- * the buffer count and buffer size
- */
-static int vpif_buffer_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long size;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_buffer_setup\n");
-
- /* If memory type is not mmap, return */
- if (V4L2_MEMORY_MMAP == common->memory) {
- /* Calculate the size of the buffer */
- size = config_params.channel_bufsize[ch->channel_id];
- /*
- * Checking if the buffer size exceeds the available buffer
- * ycmux_mode = 0 means 1 channel mode HD and
- * ycmux_mode = 1 means 2 channels mode SD
- */
- if (ch->vpifparams.std_info.ycmux_mode == 0) {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- (config_params.video_limit[0]
- + config_params.video_limit[1]))
- (*nbuffers)--;
- } else {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- config_params.video_limit[ch->channel_id])
- (*nbuffers)--;
- }
-
- } else {
- size = common->fmt.fmt.pix.sizeimage;
- }
-
- if (*nbuffers < config_params.min_numbuffers)
- *nbuffers = config_params.min_numbuffers;
-
- *nplanes = 1;
- sizes[0] = size;
- alloc_ctxs[0] = common->alloc_ctx;
-
- return 0;
-}
-
-/**
- * vpif_buffer_queue : Callback function to add buffer to DMA queue
- * @vb: ptr to vb2_buffer
- */
-static void vpif_buffer_queue(struct vb2_buffer *vb)
-{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct channel_obj *ch = fh->channel;
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_buffer_queue\n");
-
- /* add the buffer to the DMA queue */
- list_add_tail(&buf->list, &common->dma_queue);
-}
-
-/**
- * vpif_buf_cleanup : Callback function to free buffer
- * @vb: ptr to vb2_buffer
- *
- * This function is called from the videobuf2 layer to free memory
- * allocated to the buffers
- */
-static void vpif_buf_cleanup(struct vb2_buffer *vb)
-{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long flags;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- spin_lock_irqsave(&common->irqlock, flags);
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
-
-}
-
-static void vpif_wait_prepare(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_unlock(&common->lock);
-}
-
-static void vpif_wait_finish(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
-}
-
-static int vpif_buffer_init(struct vb2_buffer *vb)
-{
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
-
- return 0;
-}
-
-static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] =
- { {1, 1} };
-
-static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
-{
- struct vpif_capture_config *vpif_config_data =
- vpif_dev->platform_data;
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_params *vpif = &ch->vpifparams;
- unsigned long addr = 0;
- int ret;
-
- /* If buffer queue is empty, return error */
- if (list_empty(&common->dma_queue)) {
- vpif_dbg(1, debug, "buffer queue is empty\n");
- return -EIO;
- }
-
- /* Get the next frame from the buffer queue */
- common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_cap_buffer, list);
- /* Remove buffer from the buffer queue */
- list_del(&common->cur_frm->list);
- /* Mark state of the current frame to active */
- common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
- /* Initialize field_id and started member */
- ch->field_id = 0;
- common->started = 1;
- addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
-
- /* Calculate the offset for Y and C data in the buffer */
- vpif_calculate_offsets(ch);
-
- if ((vpif->std_info.frm_fmt &&
- ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) &&
- (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) ||
- (!vpif->std_info.frm_fmt &&
- (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
- vpif_dbg(1, debug, "conflict in field format and std format\n");
- return -EINVAL;
- }
-
- /* configure 1 or 2 channel mode */
- ret = vpif_config_data->setup_input_channel_mode
- (vpif->std_info.ycmux_mode);
-
- if (ret < 0) {
- vpif_dbg(1, debug, "can't set vpif channel mode\n");
- return ret;
- }
-
- /* Call vpif_set_params function to set the parameters and addresses */
- ret = vpif_set_video_params(vpif, ch->channel_id);
-
- if (ret < 0) {
- vpif_dbg(1, debug, "can't set video params\n");
- return ret;
- }
-
- common->started = ret;
- vpif_config_addr(ch, ret);
-
- common->set_addr(addr + common->ytop_off,
- addr + common->ybtm_off,
- addr + common->ctop_off,
- addr + common->cbtm_off);
-
- /**
- * Set interrupt for both the fields in VPIF Register enable channel in
- * VPIF register
- */
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) {
- channel0_intr_assert();
- channel0_intr_enable(1);
- enable_channel0(1);
- }
- if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
- (common->started == 2)) {
- channel1_intr_assert();
- channel1_intr_enable(1);
- enable_channel1(1);
- }
- channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
-
- return 0;
-}
-
-/* abort streaming and wait for last buffer */
-static int vpif_stop_streaming(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- if (!vb2_is_streaming(vq))
- return 0;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* release all active buffers */
- while (!list_empty(&common->dma_queue)) {
- common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_cap_buffer, list);
- list_del(&common->next_frm->list);
- vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
- }
-
- return 0;
-}
-
-static struct vb2_ops video_qops = {
- .queue_setup = vpif_buffer_queue_setup,
- .wait_prepare = vpif_wait_prepare,
- .wait_finish = vpif_wait_finish,
- .buf_init = vpif_buffer_init,
- .buf_prepare = vpif_buffer_prepare,
- .start_streaming = vpif_start_streaming,
- .stop_streaming = vpif_stop_streaming,
- .buf_cleanup = vpif_buf_cleanup,
- .buf_queue = vpif_buffer_queue,
-};
-
-/**
- * vpif_process_buffer_complete: process a completed buffer
- * @common: ptr to common channel object
- *
- * This function time stamp the buffer and mark it as DONE. It also
- * wake up any process waiting on the QUEUE and set the next buffer
- * as current
- */
-static void vpif_process_buffer_complete(struct common_obj *common)
-{
- do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
- vb2_buffer_done(&common->cur_frm->vb,
- VB2_BUF_STATE_DONE);
- /* Make curFrm pointing to nextFrm */
- common->cur_frm = common->next_frm;
-}
-
-/**
- * vpif_schedule_next_buffer: set next buffer address for capture
- * @common : ptr to common channel object
- *
- * This function will get next buffer from the dma queue and
- * set the buffer address in the vpif register for capture.
- * the buffer is marked active
- */
-static void vpif_schedule_next_buffer(struct common_obj *common)
-{
- unsigned long addr = 0;
-
- common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_cap_buffer, list);
- /* Remove that buffer from the buffer queue */
- list_del(&common->next_frm->list);
- common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
- addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
-
- /* Set top and bottom field addresses in VPIF registers */
- common->set_addr(addr + common->ytop_off,
- addr + common->ybtm_off,
- addr + common->ctop_off,
- addr + common->cbtm_off);
-}
-
-/**
- * vpif_channel_isr : ISR handler for vpif capture
- * @irq: irq number
- * @dev_id: dev_id ptr
- *
- * It changes status of the captured buffer, takes next buffer from the queue
- * and sets its address in VPIF registers
- */
-static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
-{
- struct vpif_device *dev = &vpif_obj;
- struct common_obj *common;
- struct channel_obj *ch;
- enum v4l2_field field;
- int channel_id = 0;
- int fid = -1, i;
-
- channel_id = *(int *)(dev_id);
- if (!vpif_intr_status(channel_id))
- return IRQ_NONE;
-
- ch = dev->dev[channel_id];
-
- field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
-
- for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
- common = &ch->common[i];
- /* skip If streaming is not started in this channel */
- if (0 == common->started)
- continue;
-
- /* Check the field format */
- if (1 == ch->vpifparams.std_info.frm_fmt) {
- /* Progressive mode */
- if (list_empty(&common->dma_queue))
- continue;
-
- if (!channel_first_int[i][channel_id])
- vpif_process_buffer_complete(common);
-
- channel_first_int[i][channel_id] = 0;
-
- vpif_schedule_next_buffer(common);
-
-
- channel_first_int[i][channel_id] = 0;
- } else {
- /**
- * Interlaced mode. If it is first interrupt, ignore
- * it
- */
- if (channel_first_int[i][channel_id]) {
- channel_first_int[i][channel_id] = 0;
- continue;
- }
- if (0 == i) {
- ch->field_id ^= 1;
- /* Get field id from VPIF registers */
- fid = vpif_channel_getfid(ch->channel_id);
- if (fid != ch->field_id) {
- /**
- * If field id does not match stored
- * field id, make them in sync
- */
- if (0 == fid)
- ch->field_id = fid;
- return IRQ_HANDLED;
- }
- }
- /* device field id and local field id are in sync */
- if (0 == fid) {
- /* this is even field */
- if (common->cur_frm == common->next_frm)
- continue;
-
- /* mark the current buffer as done */
- vpif_process_buffer_complete(common);
- } else if (1 == fid) {
- /* odd field */
- if (list_empty(&common->dma_queue) ||
- (common->cur_frm != common->next_frm))
- continue;
-
- vpif_schedule_next_buffer(common);
- }
- }
- }
- return IRQ_HANDLED;
-}
-
-/**
- * vpif_update_std_info() - update standard related info
- * @ch: ptr to channel object
- *
- * For a given standard selected by application, update values
- * in the device data structures
- */
-static int vpif_update_std_info(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_params *vpifparams = &ch->vpifparams;
- const struct vpif_channel_config_params *config;
- struct vpif_channel_config_params *std_info = &vpifparams->std_info;
- struct video_obj *vid_ch = &ch->video;
- int index;
-
- vpif_dbg(2, debug, "vpif_update_std_info\n");
-
- for (index = 0; index < vpif_ch_params_count; index++) {
- config = &ch_params[index];
- if (config->hd_sd == 0) {
- vpif_dbg(2, debug, "SD format\n");
- if (config->stdid & vid_ch->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
- }
- } else {
- vpif_dbg(2, debug, "HD format\n");
- if (config->dv_preset == vid_ch->dv_preset) {
- memcpy(std_info, config, sizeof(*config));
- break;
- }
- }
- }
-
- /* standard not found */
- if (index == vpif_ch_params_count)
- return -EINVAL;
-
- common->fmt.fmt.pix.width = std_info->width;
- common->width = std_info->width;
- common->fmt.fmt.pix.height = std_info->height;
- common->height = std_info->height;
- common->fmt.fmt.pix.bytesperline = std_info->width;
- vpifparams->video_params.hpitch = std_info->width;
- vpifparams->video_params.storage_mode = std_info->frm_fmt;
-
- return 0;
-}
-
-/**
- * vpif_calculate_offsets : This function calculates buffers offsets
- * @ch : ptr to channel object
- *
- * This function calculates buffer offsets for Y and C in the top and
- * bottom field
- */
-static void vpif_calculate_offsets(struct channel_obj *ch)
-{
- unsigned int hpitch, vpitch, sizeimage;
- struct video_obj *vid_ch = &(ch->video);
- struct vpif_params *vpifparams = &ch->vpifparams;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- enum v4l2_field field = common->fmt.fmt.pix.field;
-
- vpif_dbg(2, debug, "vpif_calculate_offsets\n");
-
- if (V4L2_FIELD_ANY == field) {
- if (vpifparams->std_info.frm_fmt)
- vid_ch->buf_field = V4L2_FIELD_NONE;
- else
- vid_ch->buf_field = V4L2_FIELD_INTERLACED;
- } else
- vid_ch->buf_field = common->fmt.fmt.pix.field;
-
- sizeimage = common->fmt.fmt.pix.sizeimage;
-
- hpitch = common->fmt.fmt.pix.bytesperline;
- vpitch = sizeimage / (hpitch * 2);
-
- if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
- (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
- /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
- common->ytop_off = 0;
- common->ybtm_off = hpitch;
- common->ctop_off = sizeimage / 2;
- common->cbtm_off = sizeimage / 2 + hpitch;
- } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
- /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
- common->ytop_off = 0;
- common->ybtm_off = sizeimage / 4;
- common->ctop_off = sizeimage / 2;
- common->cbtm_off = common->ctop_off + sizeimage / 4;
- } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
- /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */
- common->ybtm_off = 0;
- common->ytop_off = sizeimage / 4;
- common->cbtm_off = sizeimage / 2;
- common->ctop_off = common->cbtm_off + sizeimage / 4;
- }
- if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
- (V4L2_FIELD_INTERLACED == vid_ch->buf_field))
- vpifparams->video_params.storage_mode = 1;
- else
- vpifparams->video_params.storage_mode = 0;
-
- if (1 == vpifparams->std_info.frm_fmt)
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline;
- else {
- if ((field == V4L2_FIELD_ANY)
- || (field == V4L2_FIELD_INTERLACED))
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline * 2;
- else
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline;
- }
-
- ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid;
-}
-
-/**
- * vpif_config_format: configure default frame format in the device
- * ch : ptr to channel object
- */
-static void vpif_config_format(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_config_format\n");
-
- common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if (config_params.numbuffers[ch->channel_id] == 0)
- common->memory = V4L2_MEMORY_USERPTR;
- else
- common->memory = V4L2_MEMORY_MMAP;
-
- common->fmt.fmt.pix.sizeimage
- = config_params.channel_bufsize[ch->channel_id];
-
- if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
- else
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
- common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-}
-
-/**
- * vpif_get_default_field() - Get default field type based on interface
- * @vpif_params - ptr to vpif params
- */
-static inline enum v4l2_field vpif_get_default_field(
- struct vpif_interface *iface)
-{
- return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE :
- V4L2_FIELD_INTERLACED;
-}
-
-/**
- * vpif_check_format() - check given pixel format for compatibility
- * @ch - channel ptr
- * @pixfmt - Given pixel format
- * @update - update the values as per hardware requirement
- *
- * Check the application pixel format for S_FMT and update the input
- * values as per hardware limits for TRY_FMT. The default pixel and
- * field format is selected based on interface type.
- */
-static int vpif_check_format(struct channel_obj *ch,
- struct v4l2_pix_format *pixfmt,
- int update)
-{
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
- struct vpif_params *vpif_params = &ch->vpifparams;
- enum v4l2_field field = pixfmt->field;
- u32 sizeimage, hpitch, vpitch;
- int ret = -EINVAL;
-
- vpif_dbg(2, debug, "vpif_check_format\n");
- /**
- * first check for the pixel format. If if_type is Raw bayer,
- * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only
- * V4L2_PIX_FMT_YUV422P is supported
- */
- if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {
- if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pix format\n");
- goto exit;
- }
- pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
- }
- } else {
- if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pixel format\n");
- goto exit;
- }
- pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;
- }
- }
-
- if (!(VPIF_VALID_FIELD(field))) {
- if (!update) {
- vpif_dbg(2, debug, "invalid field format\n");
- goto exit;
- }
- /**
- * By default use FIELD_NONE for RAW Bayer capture
- * and FIELD_INTERLACED for other interfaces
- */
- field = vpif_get_default_field(&vpif_params->iface);
- } else if (field == V4L2_FIELD_ANY)
- /* unsupported field. Use default */
- field = vpif_get_default_field(&vpif_params->iface);
-
- /* validate the hpitch */
- hpitch = pixfmt->bytesperline;
- if (hpitch < vpif_params->std_info.width) {
- if (!update) {
- vpif_dbg(2, debug, "invalid hpitch\n");
- goto exit;
- }
- hpitch = vpif_params->std_info.width;
- }
-
- sizeimage = pixfmt->sizeimage;
-
- vpitch = sizeimage / (hpitch * 2);
-
- /* validate the vpitch */
- if (vpitch < vpif_params->std_info.height) {
- if (!update) {
- vpif_dbg(2, debug, "Invalid vpitch\n");
- goto exit;
- }
- vpitch = vpif_params->std_info.height;
- }
-
- /* Check for 8 byte alignment */
- if (!ALIGN(hpitch, 8)) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pitch alignment\n");
- goto exit;
- }
- /* adjust to next 8 byte boundary */
- hpitch = (((hpitch + 7) / 8) * 8);
- }
- /* if update is set, modify the bytesperline and sizeimage */
- if (update) {
- pixfmt->bytesperline = hpitch;
- pixfmt->sizeimage = hpitch * vpitch * 2;
- }
- /**
- * Image width and height is always based on current standard width and
- * height
- */
- pixfmt->width = common->fmt.fmt.pix.width;
- pixfmt->height = common->fmt.fmt.pix.height;
- return 0;
-exit:
- return ret;
-}
-
-/**
- * vpif_config_addr() - function to configure buffer address in vpif
- * @ch - channel ptr
- * @muxmode - channel mux mode
- */
-static void vpif_config_addr(struct channel_obj *ch, int muxmode)
-{
- struct common_obj *common;
-
- vpif_dbg(2, debug, "vpif_config_addr\n");
-
- common = &(ch->common[VPIF_VIDEO_INDEX]);
-
- if (VPIF_CHANNEL1_VIDEO == ch->channel_id)
- common->set_addr = ch1_set_videobuf_addr;
- else if (2 == muxmode)
- common->set_addr = ch0_set_videobuf_addr_yc_nmux;
- else
- common->set_addr = ch0_set_videobuf_addr;
-}
-
-/**
- * vpif_mmap : It is used to map kernel space buffers into user spaces
- * @filep: file pointer
- * @vma: ptr to vm_area_struct
- */
-static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- /* Get the channel object and file handle object */
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
-
- vpif_dbg(2, debug, "vpif_mmap\n");
-
- return vb2_mmap(&common->buffer_queue, vma);
-}
-
-/**
- * vpif_poll: It is used for select/poll system call
- * @filep: file pointer
- * @wait: poll table to wait
- */
-static unsigned int vpif_poll(struct file *filep, poll_table * wait)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *channel = fh->channel;
- struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
-
- vpif_dbg(2, debug, "vpif_poll\n");
-
- if (common->started)
- return vb2_poll(&common->buffer_queue, filep, wait);
- return 0;
-}
-
-/**
- * vpif_open : vpif open handler
- * @filep: file ptr
- *
- * It creates object of file handle structure and stores it in private_data
- * member of filepointer
- */
-static int vpif_open(struct file *filep)
-{
- struct vpif_capture_config *config = vpif_dev->platform_data;
- struct video_device *vdev = video_devdata(filep);
- struct common_obj *common;
- struct video_obj *vid_ch;
- struct channel_obj *ch;
- struct vpif_fh *fh;
- int i;
-
- vpif_dbg(2, debug, "vpif_open\n");
-
- ch = video_get_drvdata(vdev);
-
- vid_ch = &ch->video;
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (NULL == ch->curr_subdev_info) {
- /**
- * search through the sub device to see a registered
- * sub device and make it as current sub device
- */
- for (i = 0; i < config->subdev_count; i++) {
- if (vpif_obj.sd[i]) {
- /* the sub device is registered */
- ch->curr_subdev_info = &config->subdev_info[i];
- /* make first input as the current input */
- vid_ch->input_idx = 0;
- break;
- }
- }
- if (i == config->subdev_count) {
- vpif_err("No sub device registered\n");
- return -ENOENT;
- }
- }
-
- /* Allocate memory for the file handle object */
- fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
- if (NULL == fh) {
- vpif_err("unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
-
- /* store pointer to fh in private_data member of filep */
- filep->private_data = fh;
- fh->channel = ch;
- fh->initialized = 0;
- /* If decoder is not initialized. initialize it */
- if (!ch->initialized) {
- fh->initialized = 1;
- ch->initialized = 1;
- memset(&(ch->vpifparams), 0, sizeof(struct vpif_params));
- }
- /* Increment channel usrs counter */
- ch->usrs++;
- /* Set io_allowed member to false */
- fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&ch->prio, &fh->prio);
- return 0;
-}
-
-/**
- * vpif_release : function to clean up file close
- * @filep: file pointer
- *
- * This function deletes buffer queue, frees the buffers and the vpif file
- * handle
- */
-static int vpif_release(struct file *filep)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- vpif_dbg(2, debug, "vpif_release\n");
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* if this instance is doing IO */
- if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
- /* Reset io_usrs member of channel object */
- common->io_usrs = 0;
- /* Disable channel as per its device type and channel id */
- if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
- enable_channel0(0);
- channel0_intr_enable(0);
- }
- if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
- enable_channel1(0);
- channel1_intr_enable(0);
- }
- common->started = 0;
- /* Free buffers allocated */
- vb2_queue_release(&common->buffer_queue);
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
- }
-
- /* Decrement channel usrs counter */
- ch->usrs--;
-
- /* Close the priority */
- v4l2_prio_close(&ch->prio, fh->prio);
-
- if (fh->initialized)
- ch->initialized = 0;
-
- filep->private_data = NULL;
- kfree(fh);
- return 0;
-}
-
-/**
- * vpif_reqbufs() - request buffer handler
- * @file: file ptr
- * @priv: file handle
- * @reqbuf: request buffer structure ptr
- */
-static int vpif_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- u8 index = 0;
- struct vb2_queue *q;
-
- vpif_dbg(2, debug, "vpif_reqbufs\n");
-
- /**
- * This file handle has not initialized the channel,
- * It is not allowed to do settings
- */
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev)
- return -EINVAL;
-
- index = VPIF_VIDEO_INDEX;
-
- common = &ch->common[index];
-
- if (0 != common->io_usrs)
- return -EBUSY;
-
- /* Initialize videobuf2 queue as per the buffer type */
- common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
- if (!common->alloc_ctx) {
- vpif_err("Failed to get the context\n");
- return -EINVAL;
- }
- q = &common->buffer_queue;
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpif_cap_buffer);
-
- vb2_queue_init(q);
-
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed[index] = 1;
- /* Increment io usrs member of channel object to 1 */
- common->io_usrs = 1;
- /* Store type of memory requested in channel object */
- common->memory = reqbuf->memory;
- INIT_LIST_HEAD(&common->dma_queue);
-
- /* Allocate buffers */
- return vb2_reqbufs(&common->buffer_queue, reqbuf);
-}
-
-/**
- * vpif_querybuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_querybuf\n");
-
- if (common->fmt.type != buf->type)
- return -EINVAL;
-
- if (common->memory != V4L2_MEMORY_MMAP) {
- vpif_dbg(1, debug, "Invalid memory\n");
- return -EINVAL;
- }
-
- return vb2_querybuf(&common->buffer_queue, buf);
-}
-
-/**
- * vpif_qbuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct v4l2_buffer tbuf = *buf;
-
- vpif_dbg(2, debug, "vpif_qbuf\n");
-
- if (common->fmt.type != tbuf.type) {
- vpif_err("invalid buffer type\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh io not allowed\n");
- return -EACCES;
- }
-
- return vb2_qbuf(&common->buffer_queue, buf);
-}
-
-/**
- * vpif_dqbuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_dqbuf\n");
-
- return vb2_dqbuf(&common->buffer_queue, buf,
- (file->f_flags & O_NONBLOCK));
-}
-
-/**
- * vpif_streamon() - streamon handler
- * @file: file ptr
- * @priv: file handle
- * @buftype: v4l2 buffer type
- */
-static int vpif_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
- struct vpif_params *vpif;
- int ret = 0;
-
- vpif_dbg(2, debug, "vpif_streamon\n");
-
- vpif = &ch->vpifparams;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- vpif_dbg(1, debug, "buffer type not supported\n");
- return -EINVAL;
- }
-
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_dbg(1, debug, "io not allowed\n");
- return -EACCES;
- }
-
- /* If Streaming is already started, return error */
- if (common->started) {
- vpif_dbg(1, debug, "channel->started\n");
- return -EBUSY;
- }
-
- if ((ch->channel_id == VPIF_CHANNEL0_VIDEO &&
- oth_ch->common[VPIF_VIDEO_INDEX].started &&
- vpif->std_info.ycmux_mode == 0) ||
- ((ch->channel_id == VPIF_CHANNEL1_VIDEO) &&
- (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
- vpif_dbg(1, debug, "other channel is being used\n");
- return -EBUSY;
- }
-
- ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0);
- if (ret)
- return ret;
-
- /* Enable streamon on the sub device */
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
- s_stream, 1);
-
- if (ret && (ret != -ENOIOCTLCMD)) {
- vpif_dbg(1, debug, "stream on failed in subdev\n");
- return ret;
- }
-
- /* Call vb2_streamon to start streaming in videobuf2 */
- ret = vb2_streamon(&common->buffer_queue, buftype);
- if (ret) {
- vpif_dbg(1, debug, "vb2_streamon\n");
- return ret;
- }
-
- return ret;
-}
-
-/**
- * vpif_streamoff() - streamoff handler
- * @file: file ptr
- * @priv: file handle
- * @buftype: v4l2 buffer type
- */
-static int vpif_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret;
-
- vpif_dbg(2, debug, "vpif_streamoff\n");
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- vpif_dbg(1, debug, "buffer type not supported\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_dbg(1, debug, "io not allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!common->started) {
- vpif_dbg(1, debug, "channel->started\n");
- return -EINVAL;
- }
-
- /* disable channel */
- if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
- enable_channel0(0);
- channel0_intr_enable(0);
- } else {
- enable_channel1(0);
- channel1_intr_enable(0);
- }
-
- common->started = 0;
-
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
- s_stream, 0);
-
- if (ret && (ret != -ENOIOCTLCMD))
- vpif_dbg(1, debug, "stream off failed in subdev\n");
-
- return vb2_streamoff(&common->buffer_queue, buftype);
-}
-
-/**
- * vpif_map_sub_device_to_input() - Maps sub device to input
- * @ch - ptr to channel
- * @config - ptr to capture configuration
- * @input_index - Given input index from application
- * @sub_device_index - index into sd table
- *
- * lookup the sub device information for a given input index.
- * we report all the inputs to application. inputs table also
- * has sub device name for the each input
- */
-static struct vpif_subdev_info *vpif_map_sub_device_to_input(
- struct channel_obj *ch,
- struct vpif_capture_config *vpif_cfg,
- int input_index,
- int *sub_device_index)
-{
- struct vpif_capture_chan_config *chan_cfg;
- struct vpif_subdev_info *subdev_info = NULL;
- const char *subdev_name = NULL;
- int i;
-
- vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n");
-
- chan_cfg = &vpif_cfg->chan_config[ch->channel_id];
-
- /**
- * search through the inputs to find the sub device supporting
- * the input
- */
- for (i = 0; i < chan_cfg->input_count; i++) {
- /* For each sub device, loop through input */
- if (i == input_index) {
- subdev_name = chan_cfg->inputs[i].subdev_name;
- break;
- }
- }
-
- /* if reached maximum. return null */
- if (i == chan_cfg->input_count || (NULL == subdev_name))
- return subdev_info;
-
- /* loop through the sub device list to get the sub device info */
- for (i = 0; i < vpif_cfg->subdev_count; i++) {
- subdev_info = &vpif_cfg->subdev_info[i];
- if (!strcmp(subdev_info->name, subdev_name))
- break;
- }
-
- if (i == vpif_cfg->subdev_count)
- return subdev_info;
-
- /* check if the sub device is registered */
- if (NULL == vpif_obj.sd[i])
- return NULL;
-
- *sub_device_index = i;
- return subdev_info;
-}
-
-/**
- * vpif_querystd() - querystd handler
- * @file: file ptr
- * @priv: file handle
- * @std_id: ptr to std id
- *
- * This function is called to detect standard at the selected input
- */
-static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- int ret = 0;
-
- vpif_dbg(2, debug, "vpif_querystd\n");
-
- /* Call querystd function of decoder device */
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
- querystd, std_id);
- if (ret < 0)
- vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
-
- return ret;
-}
-
-/**
- * vpif_g_std() - get STD handler
- * @file: file ptr
- * @priv: file handle
- * @std_id: ptr to std id
- */
-static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- vpif_dbg(2, debug, "vpif_g_std\n");
-
- *std = ch->video.stdid;
- return 0;
-}
-
-/**
- * vpif_s_std() - set STD handler
- * @file: file ptr
- * @priv: file handle
- * @std_id: ptr to std id
- */
-static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- vpif_dbg(2, debug, "vpif_s_std\n");
-
- if (common->started) {
- vpif_err("streaming in progress\n");
- return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
-
- fh->initialized = 1;
-
- /* Call encoder subdevice function to set the standard */
- ch->video.stdid = *std_id;
- ch->video.dv_preset = V4L2_DV_INVALID;
- memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
-
- /* Get the information about the standard */
- if (vpif_update_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
- return -EINVAL;
- }
-
- /* Configure the default format information */
- vpif_config_format(ch);
-
- /* set standard in the sub device */
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
- s_std, *std_id);
- if (ret < 0)
- vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
- return ret;
-}
-
-/**
- * vpif_enum_input() - ENUMINPUT handler
- * @file: file ptr
- * @priv: file handle
- * @input: ptr to input structure
- */
-static int vpif_enum_input(struct file *file, void *priv,
- struct v4l2_input *input)
-{
-
- struct vpif_capture_config *config = vpif_dev->platform_data;
- struct vpif_capture_chan_config *chan_cfg;
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- chan_cfg = &config->chan_config[ch->channel_id];
-
- if (input->index >= chan_cfg->input_count) {
- vpif_dbg(1, debug, "Invalid input index\n");
- return -EINVAL;
- }
-
- memcpy(input, &chan_cfg->inputs[input->index].input,
- sizeof(*input));
- return 0;
-}
-
-/**
- * vpif_g_input() - Get INPUT handler
- * @file: file ptr
- * @priv: file handle
- * @index: ptr to input index
- */
-static int vpif_g_input(struct file *file, void *priv, unsigned int *index)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
-
- *index = vid_ch->input_idx;
-
- return 0;
-}
-
-/**
- * vpif_s_input() - Set INPUT handler
- * @file: file ptr
- * @priv: file handle
- * @index: input index
- */
-static int vpif_s_input(struct file *file, void *priv, unsigned int index)
-{
- struct vpif_capture_config *config = vpif_dev->platform_data;
- struct vpif_capture_chan_config *chan_cfg;
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct video_obj *vid_ch = &ch->video;
- struct vpif_subdev_info *subdev_info;
- int ret = 0, sd_index = 0;
- u32 input = 0, output = 0;
-
- chan_cfg = &config->chan_config[ch->channel_id];
-
- if (common->started) {
- vpif_err("Streaming in progress\n");
- return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
-
- fh->initialized = 1;
- subdev_info = vpif_map_sub_device_to_input(ch, config, index,
- &sd_index);
- if (NULL == subdev_info) {
- vpif_dbg(1, debug,
- "couldn't lookup sub device for the input index\n");
- return -EINVAL;
- }
-
- /* first setup input path from sub device to vpif */
- if (config->setup_input_path) {
- ret = config->setup_input_path(ch->channel_id,
- subdev_info->name);
- if (ret < 0) {
- vpif_dbg(1, debug, "couldn't setup input path for the"
- " sub device %s, for input index %d\n",
- subdev_info->name, index);
- return ret;
- }
- }
-
- if (subdev_info->can_route) {
- input = subdev_info->input;
- output = subdev_info->output;
- ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing,
- input, output, 0);
- if (ret < 0) {
- vpif_dbg(1, debug, "Failed to set input\n");
- return ret;
- }
- }
- vid_ch->input_idx = index;
- ch->curr_subdev_info = subdev_info;
- ch->curr_sd_index = sd_index;
- /* copy interface parameters to vpif */
- ch->vpifparams.iface = subdev_info->vpif_if;
-
- /* update tvnorms from the sub device input info */
- ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
- return ret;
-}
-
-/**
- * vpif_enum_fmt_vid_cap() - ENUM_FMT handler
- * @file: file ptr
- * @priv: file handle
- * @index: input index
- */
-static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- if (fmt->index != 0) {
- vpif_dbg(1, debug, "Invalid format index\n");
- return -EINVAL;
- }
-
- /* Fill in the information about format */
- if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb");
- fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
- } else {
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
- fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
- }
- return 0;
-}
-
-/**
- * vpif_try_fmt_vid_cap() - TRY_FMT handler
- * @file: file ptr
- * @priv: file handle
- * @fmt: ptr to v4l2 format structure
- */
-static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
-
- return vpif_check_format(ch, pixfmt, 1);
-}
-
-
-/**
- * vpif_g_fmt_vid_cap() - Set INPUT handler
- * @file: file ptr
- * @priv: file handle
- * @fmt: ptr to v4l2 format structure
- */
-static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* Check the validity of the buffer type */
- if (common->fmt.type != fmt->type)
- return -EINVAL;
-
- /* Fill in the information about format */
- *fmt = common->fmt;
- return 0;
-}
-
-/**
- * vpif_s_fmt_vid_cap() - Set FMT handler
- * @file: file ptr
- * @priv: file handle
- * @fmt: ptr to v4l2 format structure
- */
-static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct v4l2_pix_format *pixfmt;
- int ret = 0;
-
- vpif_dbg(2, debug, "%s\n", __func__);
-
- /* If streaming is started, return error */
- if (common->started) {
- vpif_dbg(1, debug, "Streaming is started\n");
- return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
-
- fh->initialized = 1;
-
- pixfmt = &fmt->fmt.pix;
- /* Check for valid field format */
- ret = vpif_check_format(ch, pixfmt, 0);
-
- if (ret)
- return ret;
- /* store the format in the channel object */
- common->fmt = *fmt;
- return 0;
-}
-
-/**
- * vpif_querycap() - QUERYCAP handler
- * @file: file ptr
- * @priv: file handle
- * @cap: ptr to v4l2_capability structure
- */
-static int vpif_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vpif_capture_config *config = vpif_dev->platform_data;
-
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));
- strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info));
- strlcpy(cap->card, config->card_name, sizeof(cap->card));
-
- return 0;
-}
-
-/**
- * vpif_g_priority() - get priority handler
- * @file: file ptr
- * @priv: file handle
- * @prio: ptr to v4l2_priority structure
- */
-static int vpif_g_priority(struct file *file, void *priv,
- enum v4l2_priority *prio)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *prio = v4l2_prio_max(&ch->prio);
-
- return 0;
-}
-
-/**
- * vpif_s_priority() - set priority handler
- * @file: file ptr
- * @priv: file handle
- * @prio: ptr to v4l2_priority structure
- */
-static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_prio_change(&ch->prio, &fh->prio, p);
-}
-
-/**
- * vpif_cropcap() - cropcap handler
- * @file: file ptr
- * @priv: file handle
- * @crop: ptr to v4l2_cropcap structure
- */
-static int vpif_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *crop)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type)
- return -EINVAL;
-
- crop->bounds.left = 0;
- crop->bounds.top = 0;
- crop->bounds.height = common->height;
- crop->bounds.width = common->width;
- crop->defrect = crop->bounds;
- return 0;
-}
-
-/**
- * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_enum_dv_presets(struct file *file, void *priv,
- struct v4l2_dv_enum_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
- video, enum_dv_presets, preset);
-}
-
-/**
- * vpif_query_dv_presets() - QUERY_DV_PRESET handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_query_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
- video, query_dv_preset, preset);
-}
-/**
- * vpif_s_dv_presets() - S_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_s_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- if (common->started) {
- vpif_dbg(1, debug, "streaming in progress\n");
- return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (ret)
- return ret;
-
- fh->initialized = 1;
-
- /* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- ch->video.dv_preset = preset->preset;
- ch->video.stdid = V4L2_STD_UNKNOWN;
- memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
-
- /* Get the information about the standard */
- if (vpif_update_std_info(ch)) {
- vpif_dbg(1, debug, "Error getting the standard info\n");
- ret = -EINVAL;
- } else {
- /* Configure the default format information */
- vpif_config_format(ch);
-
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
- video, s_dv_preset, preset);
- }
-
- mutex_unlock(&common->lock);
-
- return ret;
-}
-/**
- * vpif_g_dv_presets() - G_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_g_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- preset->preset = ch->video.dv_preset;
-
- return 0;
-}
-
-/**
- * vpif_s_dv_timings() - S_DV_TIMINGS handler
- * @file: file ptr
- * @priv: file handle
- * @timings: digital video timings
- */
-static int vpif_s_dv_timings(struct file *file, void *priv,
- struct v4l2_dv_timings *timings)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct vpif_params *vpifparams = &ch->vpifparams;
- struct vpif_channel_config_params *std_info = &vpifparams->std_info;
- struct video_obj *vid_ch = &ch->video;
- struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
- int ret;
-
- if (timings->type != V4L2_DV_BT_656_1120) {
- vpif_dbg(2, debug, "Timing type not defined\n");
- return -EINVAL;
- }
-
- /* Configure subdevice timings, if any */
- ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
- video, s_dv_timings, timings);
- if (ret == -ENOIOCTLCMD) {
- vpif_dbg(2, debug, "Custom DV timings not supported by "
- "subdevice\n");
- return -EINVAL;
- }
- if (ret < 0) {
- vpif_dbg(2, debug, "Error setting custom DV timings\n");
- return ret;
- }
-
- if (!(timings->bt.width && timings->bt.height &&
- (timings->bt.hbackporch ||
- timings->bt.hfrontporch ||
- timings->bt.hsync) &&
- timings->bt.vfrontporch &&
- (timings->bt.vbackporch ||
- timings->bt.vsync))) {
- vpif_dbg(2, debug, "Timings for width, height, "
- "horizontal back porch, horizontal sync, "
- "horizontal front porch, vertical back porch, "
- "vertical sync and vertical back porch "
- "must be defined\n");
- return -EINVAL;
- }
-
- *bt = timings->bt;
-
- /* Configure video port timings */
-
- std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
- bt->hsync - 8;
- std_info->sav2eav = bt->width;
-
- std_info->l1 = 1;
- std_info->l3 = bt->vsync + bt->vbackporch + 1;
-
- if (bt->interlaced) {
- if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
- std_info->vsize = bt->height * 2 +
- bt->vfrontporch + bt->vsync + bt->vbackporch +
- bt->il_vfrontporch + bt->il_vsync +
- bt->il_vbackporch;
- std_info->l5 = std_info->vsize/2 -
- (bt->vfrontporch - 1);
- std_info->l7 = std_info->vsize/2 + 1;
- std_info->l9 = std_info->l7 + bt->il_vsync +
- bt->il_vbackporch + 1;
- std_info->l11 = std_info->vsize -
- (bt->il_vfrontporch - 1);
- } else {
- vpif_dbg(2, debug, "Required timing values for "
- "interlaced BT format missing\n");
- return -EINVAL;
- }
- } else {
- std_info->vsize = bt->height + bt->vfrontporch +
- bt->vsync + bt->vbackporch;
- std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
- }
- strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
- std_info->width = bt->width;
- std_info->height = bt->height;
- std_info->frm_fmt = bt->interlaced ? 0 : 1;
- std_info->ycmux_mode = 0;
- std_info->capture_format = 0;
- std_info->vbi_supported = 0;
- std_info->hd_sd = 1;
- std_info->stdid = 0;
- std_info->dv_preset = V4L2_DV_INVALID;
-
- vid_ch->stdid = 0;
- vid_ch->dv_preset = V4L2_DV_INVALID;
- return 0;
-}
-
-/**
- * vpif_g_dv_timings() - G_DV_TIMINGS handler
- * @file: file ptr
- * @priv: file handle
- * @timings: digital video timings
- */
-static int vpif_g_dv_timings(struct file *file, void *priv,
- struct v4l2_dv_timings *timings)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
- struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
-
- timings->bt = *bt;
-
- return 0;
-}
-
-/*
- * vpif_g_chip_ident() - Identify the chip
- * @file: file ptr
- * @priv: file handle
- * @chip: chip identity
- *
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- 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) {
- vpif_dbg(2, debug, "match_type is invalid.\n");
- return -EINVAL;
- }
-
- return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
- g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * vpif_dbg_g_register() - Read register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be read
- *
- * Debugging only
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_dbg_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
- g_register, reg);
-}
-
-/*
- * vpif_dbg_s_register() - Write to register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be modified
- *
- * Debugging only
- * Returns zero or -EINVAL if write operations fails.
- */
-static int vpif_dbg_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
- s_register, reg);
-}
-#endif
-
-/*
- * vpif_log_status() - Status information
- * @file: file ptr
- * @priv: file handle
- *
- * Returns zero.
- */
-static int vpif_log_status(struct file *filep, void *priv)
-{
- /* status for sub devices */
- v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
-
- return 0;
-}
-
-/* vpif capture ioctl operations */
-static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
- .vidioc_querycap = vpif_querycap,
- .vidioc_g_priority = vpif_g_priority,
- .vidioc_s_priority = vpif_s_priority,
- .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap,
- .vidioc_enum_input = vpif_enum_input,
- .vidioc_s_input = vpif_s_input,
- .vidioc_g_input = vpif_g_input,
- .vidioc_reqbufs = vpif_reqbufs,
- .vidioc_querybuf = vpif_querybuf,
- .vidioc_querystd = vpif_querystd,
- .vidioc_s_std = vpif_s_std,
- .vidioc_g_std = vpif_g_std,
- .vidioc_qbuf = vpif_qbuf,
- .vidioc_dqbuf = vpif_dqbuf,
- .vidioc_streamon = vpif_streamon,
- .vidioc_streamoff = vpif_streamoff,
- .vidioc_cropcap = vpif_cropcap,
- .vidioc_enum_dv_presets = vpif_enum_dv_presets,
- .vidioc_s_dv_preset = vpif_s_dv_preset,
- .vidioc_g_dv_preset = vpif_g_dv_preset,
- .vidioc_query_dv_preset = vpif_query_dv_preset,
- .vidioc_s_dv_timings = vpif_s_dv_timings,
- .vidioc_g_dv_timings = vpif_g_dv_timings,
- .vidioc_g_chip_ident = vpif_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vpif_dbg_g_register,
- .vidioc_s_register = vpif_dbg_s_register,
-#endif
- .vidioc_log_status = vpif_log_status,
-};
-
-/* vpif file operations */
-static struct v4l2_file_operations vpif_fops = {
- .owner = THIS_MODULE,
- .open = vpif_open,
- .release = vpif_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vpif_mmap,
- .poll = vpif_poll
-};
-
-/* vpif video template */
-static struct video_device vpif_video_template = {
- .name = "vpif",
- .fops = &vpif_fops,
- .minor = -1,
- .ioctl_ops = &vpif_ioctl_ops,
-};
-
-/**
- * initialize_vpif() - Initialize vpif data structures
- *
- * Allocate memory for data structures and initialize them
- */
-static int initialize_vpif(void)
-{
- int err = 0, i, j;
- int free_channel_objects_index;
-
- /* Default number of buffers should be 3 */
- if ((ch0_numbuffers > 0) &&
- (ch0_numbuffers < config_params.min_numbuffers))
- ch0_numbuffers = config_params.min_numbuffers;
- if ((ch1_numbuffers > 0) &&
- (ch1_numbuffers < config_params.min_numbuffers))
- ch1_numbuffers = config_params.min_numbuffers;
-
- /* Set buffer size to min buffers size if it is invalid */
- if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO])
- ch0_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL0_VIDEO];
- if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO])
- ch1_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL1_VIDEO];
-
- config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers;
- config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers;
- if (ch0_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO]
- = ch0_bufsize;
- }
- if (ch1_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO]
- = ch1_bufsize;
- }
-
- /* Allocate memory for six channel objects */
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- vpif_obj.dev[i] =
- kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL);
- /* If memory allocation fails, return error */
- if (!vpif_obj.dev[i]) {
- free_channel_objects_index = i;
- err = -ENOMEM;
- goto vpif_init_free_channel_objects;
- }
- }
- return 0;
-
-vpif_init_free_channel_objects:
- for (j = 0; j < free_channel_objects_index; j++)
- kfree(vpif_obj.dev[j]);
- return err;
-}
-
-/**
- * vpif_probe : This function probes the vpif capture driver
- * @pdev: platform device pointer
- *
- * This creates device entries by register itself to the V4L2 driver and
- * initializes fields of each channel objects
- */
-static __init int vpif_probe(struct platform_device *pdev)
-{
- struct vpif_subdev_info *subdevdata;
- struct vpif_capture_config *config;
- int i, j, k, m, q, err;
- struct i2c_adapter *i2c_adap;
- struct channel_obj *ch;
- struct common_obj *common;
- struct video_device *vfd;
- struct resource *res;
- int subdev_count;
- size_t size;
-
- vpif_dev = &pdev->dev;
-
- err = initialize_vpif();
- if (err) {
- v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
- 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++) {
- if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
- "VPIF_Capture",
- (void *)(&vpif_obj.dev[k]->channel_id))) {
- err = -EBUSY;
- i--;
- goto vpif_int_err;
- }
- }
- k++;
- }
-
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (NULL == vfd) {
- for (j = 0; j < i; j++) {
- ch = vpif_obj.dev[j];
- video_device_release(ch->video_dev);
- }
- err = -ENOMEM;
- goto vpif_dev_alloc_err;
- }
-
- /* Initialize field of video device */
- *vfd = vpif_video_template;
- vfd->v4l2_dev = &vpif_obj.v4l2_dev;
- vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name),
- "VPIF_Capture_DRIVER_V%s",
- VPIF_CAPTURE_VERSION);
- /* Set video_dev to the video device */
- ch->video_dev = vfd;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- size = resource_size(res);
- /* The resources are divided into two equal memory and when we
- * have HD output we can add them together
- */
- for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- ch->channel_id = j;
- /* only enabled if second resource exists */
- config_params.video_limit[ch->channel_id] = 0;
- if (size)
- config_params.video_limit[ch->channel_id] =
- size/2;
- }
- }
-
- for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- ch->channel_id = j;
- common = &(ch->common[VPIF_VIDEO_INDEX]);
- spin_lock_init(&common->irqlock);
- mutex_init(&common->lock);
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
- ch->video_dev->lock = &common->lock;
- /* Initialize prio member of channel object */
- v4l2_prio_init(&ch->prio);
- err = video_register_device(ch->video_dev,
- VFL_TYPE_GRABBER, (j ? 1 : 0));
- if (err)
- goto probe_out;
-
- video_set_drvdata(ch->video_dev, ch);
-
- }
-
- i2c_adap = i2c_get_adapter(1);
- config = pdev->dev.platform_data;
-
- subdev_count = config->subdev_count;
- vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
- GFP_KERNEL);
- if (vpif_obj.sd == NULL) {
- vpif_err("unable to allocate memory for subdevice pointers\n");
- err = -ENOMEM;
- goto probe_out;
- }
-
- for (i = 0; i < subdev_count; i++) {
- subdevdata = &config->subdev_info[i];
- vpif_obj.sd[i] =
- v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap,
- &subdevdata->board_info,
- NULL);
-
- if (!vpif_obj.sd[i]) {
- vpif_err("Error registering v4l2 subdevice\n");
- goto probe_subdev_out;
- }
- v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
- subdevdata->name);
-
- if (vpif_obj.sd[i])
- vpif_obj.sd[i]->grp_id = 1 << i;
- }
-
- v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
- return 0;
-
-probe_subdev_out:
- /* free sub devices memory */
- kfree(vpif_obj.sd);
-
- j = VPIF_CAPTURE_MAX_DEVICES;
-probe_out:
- for (k = 0; k < j; k++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[k];
- /* Unregister video device */
- video_unregister_device(ch->video_dev);
- }
-
-vpif_dev_alloc_err:
- k = VPIF_CAPTURE_MAX_DEVICES-1;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
- i = res->end;
-
-vpif_int_err:
- for (q = k; q >= 0; q--) {
- for (m = i; m >= (int)res->start; m--)
- free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id));
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1);
- if (res)
- i = res->end;
- }
- v4l2_device_unregister(&vpif_obj.v4l2_dev);
- return err;
-}
-
-/**
- * vpif_remove() - driver remove handler
- * @device: ptr to platform device structure
- *
- * The vidoe device is unregistered
- */
-static int vpif_remove(struct platform_device *device)
-{
- int i;
- struct channel_obj *ch;
-
- v4l2_device_unregister(&vpif_obj.v4l2_dev);
-
- /* un-register device */
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- /* Unregister video device */
- video_unregister_device(ch->video_dev);
- }
- return 0;
-}
-
-#ifdef CONFIG_PM
-/**
- * vpif_suspend: vpif device suspend
- */
-static int vpif_suspend(struct device *dev)
-{
-
- struct common_obj *common;
- struct channel_obj *ch;
- int i;
-
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
- if (ch->usrs && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
- enable_channel0(0);
- channel0_intr_enable(0);
- }
- if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
- common->started == 2) {
- enable_channel1(0);
- channel1_intr_enable(0);
- }
- }
- mutex_unlock(&common->lock);
- }
-
- return 0;
-}
-
-/*
- * vpif_resume: vpif device suspend
- */
-static int vpif_resume(struct device *dev)
-{
- struct common_obj *common;
- struct channel_obj *ch;
- int i;
-
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
- if (ch->usrs && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
- enable_channel0(1);
- channel0_intr_enable(1);
- }
- if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
- common->started == 2) {
- enable_channel1(1);
- channel1_intr_enable(1);
- }
- }
- mutex_unlock(&common->lock);
- }
-
- return 0;
-}
-
-static const struct dev_pm_ops vpif_dev_pm_ops = {
- .suspend = vpif_suspend,
- .resume = vpif_resume,
-};
-
-#define vpif_pm_ops (&vpif_dev_pm_ops)
-#else
-#define vpif_pm_ops NULL
-#endif
-
-static __refdata struct platform_driver vpif_driver = {
- .driver = {
- .name = "vpif_capture",
- .owner = THIS_MODULE,
- .pm = vpif_pm_ops,
- },
- .probe = vpif_probe,
- .remove = vpif_remove,
-};
-
-/**
- * vpif_init: initialize the vpif driver
- *
- * This function registers device and driver to the kernel, requests irq
- * handler and allocates memory
- * for channel objects
- */
-static __init int vpif_init(void)
-{
- return platform_driver_register(&vpif_driver);
-}
-
-/**
- * vpif_cleanup : This function clean up the vpif capture resources
- *
- * This will un-registers device and driver to the kernel, frees
- * requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
- struct platform_device *pdev;
- struct resource *res;
- int irq_num;
- int i = 0;
-
- pdev = container_of(vpif_dev, struct platform_device, dev);
- while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
- for (irq_num = res->start; irq_num <= res->end; irq_num++)
- free_irq(irq_num,
- (void *)(&vpif_obj.dev[i]->channel_id));
- i++;
- }
-
- platform_driver_unregister(&vpif_driver);
-
- kfree(vpif_obj.sd);
- for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
- kfree(vpif_obj.dev[i]);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpif_init);
-module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
deleted file mode 100644
index e129c98921ad..000000000000
--- a/drivers/media/video/davinci/vpif_display.c
+++ /dev/null
@@ -1,1998 +0,0 @@
-/*
- * vpif-display - VPIF display driver
- * Display driver for TI DaVinci VPIF
- *
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed .as is. WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <asm/irq.h>
-#include <asm/page.h>
-
-#include <media/adv7343.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-
-#include "vpif_display.h"
-#include "vpif.h"
-
-MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VPIF_DISPLAY_VERSION);
-
-#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
-
-#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
-#define vpif_dbg(level, debug, fmt, arg...) \
- v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
-
-static int debug = 1;
-static u32 ch2_numbuffers = 3;
-static u32 ch3_numbuffers = 3;
-static u32 ch2_bufsize = 1920 * 1080 * 2;
-static u32 ch3_bufsize = 720 * 576 * 2;
-
-module_param(debug, int, 0644);
-module_param(ch2_numbuffers, uint, S_IRUGO);
-module_param(ch3_numbuffers, uint, S_IRUGO);
-module_param(ch2_bufsize, uint, S_IRUGO);
-module_param(ch3_bufsize, uint, S_IRUGO);
-
-MODULE_PARM_DESC(debug, "Debug level 0-1");
-MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
-MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
-MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
-MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
-
-static struct vpif_config_params config_params = {
- .min_numbuffers = 3,
- .numbuffers[0] = 3,
- .numbuffers[1] = 3,
- .min_bufsize[0] = 720 * 480 * 2,
- .min_bufsize[1] = 720 * 480 * 2,
- .channel_bufsize[0] = 1920 * 1080 * 2,
- .channel_bufsize[1] = 720 * 576 * 2,
-};
-
-static struct vpif_device vpif_obj = { {NULL} };
-static struct device *vpif_dev;
-static void vpif_calculate_offsets(struct channel_obj *ch);
-static void vpif_config_addr(struct channel_obj *ch, int muxmode);
-
-/*
- * buffer_prepare: This is the callback function called from vb2_qbuf()
- * function the buffer is prepared and user space virtual address is converted
- * into physical address
- */
-static int vpif_buffer_prepare(struct vb2_buffer *vb)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_queue *q = vb->vb2_queue;
- struct common_obj *common;
- unsigned long addr;
-
- common = &fh->channel->common[VPIF_VIDEO_INDEX];
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED) {
- vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- goto buf_align_exit;
-
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
- if (q->streaming &&
- (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
- if (!ISALIGNED(addr + common->ytop_off) ||
- !ISALIGNED(addr + common->ybtm_off) ||
- !ISALIGNED(addr + common->ctop_off) ||
- !ISALIGNED(addr + common->cbtm_off))
- goto buf_align_exit;
- }
- }
- return 0;
-
-buf_align_exit:
- vpif_err("buffer offset not aligned to 8 bytes\n");
- return -EINVAL;
-}
-
-/*
- * vpif_buffer_queue_setup: This function allocates memory for the buffers
- */
-static int vpif_buffer_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- unsigned long size;
-
- if (V4L2_MEMORY_MMAP == common->memory) {
- size = config_params.channel_bufsize[ch->channel_id];
- /*
- * Checking if the buffer size exceeds the available buffer
- * ycmux_mode = 0 means 1 channel mode HD and
- * ycmux_mode = 1 means 2 channels mode SD
- */
- if (ch->vpifparams.std_info.ycmux_mode == 0) {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- (config_params.video_limit[0]
- + config_params.video_limit[1]))
- (*nbuffers)--;
- } else {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- config_params.video_limit[ch->channel_id])
- (*nbuffers)--;
- }
- } else {
- size = common->fmt.fmt.pix.sizeimage;
- }
-
- if (*nbuffers < config_params.min_numbuffers)
- *nbuffers = config_params.min_numbuffers;
-
- *nplanes = 1;
- sizes[0] = size;
- alloc_ctxs[0] = common->alloc_ctx;
- return 0;
-}
-
-/*
- * vpif_buffer_queue: This function adds the buffer to DMA queue
- */
-static void vpif_buffer_queue(struct vb2_buffer *vb)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* add the buffer to the DMA queue */
- list_add_tail(&buf->list, &common->dma_queue);
-}
-
-/*
- * vpif_buf_cleanup: This function is called from the videobuf2 layer to
- * free memory allocated to the buffers
- */
-static void vpif_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long flags;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- spin_lock_irqsave(&common->irqlock, flags);
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
-}
-
-static void vpif_wait_prepare(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_unlock(&common->lock);
-}
-
-static void vpif_wait_finish(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
-}
-
-static int vpif_buffer_init(struct vb2_buffer *vb)
-{
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
-
- return 0;
-}
-
-static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
-
-static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
-{
- struct vpif_display_config *vpif_config_data =
- vpif_dev->platform_data;
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_params *vpif = &ch->vpifparams;
- unsigned long addr = 0;
- int ret;
-
- /* If buffer queue is empty, return error */
- if (list_empty(&common->dma_queue)) {
- vpif_err("buffer queue is empty\n");
- return -EIO;
- }
-
- /* Get the next frame from the buffer queue */
- common->next_frm = common->cur_frm =
- list_entry(common->dma_queue.next,
- struct vpif_disp_buffer, list);
-
- list_del(&common->cur_frm->list);
- /* Mark state of the current frame to active */
- common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
-
- /* Initialize field_id and started member */
- ch->field_id = 0;
- common->started = 1;
- addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
- /* Calculate the offset for Y and C data in the buffer */
- vpif_calculate_offsets(ch);
-
- if ((ch->vpifparams.std_info.frm_fmt &&
- ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
- && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
- || (!ch->vpifparams.std_info.frm_fmt
- && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
- vpif_err("conflict in field format and std format\n");
- return -EINVAL;
- }
-
- /* clock settings */
- ret =
- vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
- ch->vpifparams.std_info.hd_sd);
- if (ret < 0) {
- vpif_err("can't set clock\n");
- return ret;
- }
-
- /* set the parameters and addresses */
- ret = vpif_set_video_params(vpif, ch->channel_id + 2);
- if (ret < 0)
- return ret;
-
- common->started = ret;
- vpif_config_addr(ch, ret);
- common->set_addr((addr + common->ytop_off),
- (addr + common->ybtm_off),
- (addr + common->ctop_off),
- (addr + common->cbtm_off));
-
- /* Set interrupt for both the fields in VPIF
- Register enable channel in VPIF register */
- if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
- channel2_intr_assert();
- channel2_intr_enable(1);
- enable_channel2(1);
- if (vpif_config_data->ch2_clip_en)
- channel2_clipping_enable(1);
- }
-
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
- || (common->started == 2)) {
- channel3_intr_assert();
- channel3_intr_enable(1);
- enable_channel3(1);
- if (vpif_config_data->ch3_clip_en)
- channel3_clipping_enable(1);
- }
- channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
-
- return 0;
-}
-
-/* abort streaming and wait for last buffer */
-static int vpif_stop_streaming(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- if (!vb2_is_streaming(vq))
- return 0;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* release all active buffers */
- while (!list_empty(&common->dma_queue)) {
- common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_disp_buffer, list);
- list_del(&common->next_frm->list);
- vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
- }
-
- return 0;
-}
-
-static struct vb2_ops video_qops = {
- .queue_setup = vpif_buffer_queue_setup,
- .wait_prepare = vpif_wait_prepare,
- .wait_finish = vpif_wait_finish,
- .buf_init = vpif_buffer_init,
- .buf_prepare = vpif_buffer_prepare,
- .start_streaming = vpif_start_streaming,
- .stop_streaming = vpif_stop_streaming,
- .buf_cleanup = vpif_buf_cleanup,
- .buf_queue = vpif_buffer_queue,
-};
-
-static void process_progressive_mode(struct common_obj *common)
-{
- unsigned long addr = 0;
-
- /* Get the next buffer from buffer queue */
- common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_disp_buffer, list);
- /* Remove that buffer from the buffer queue */
- list_del(&common->next_frm->list);
- /* Mark status of the buffer as active */
- common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
-
- /* Set top and bottom field addrs in VPIF registers */
- addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
- common->set_addr(addr + common->ytop_off,
- addr + common->ybtm_off,
- addr + common->ctop_off,
- addr + common->cbtm_off);
-}
-
-static void process_interlaced_mode(int fid, struct common_obj *common)
-{
- /* device field id and local field id are in sync */
- /* If this is even field */
- if (0 == fid) {
- if (common->cur_frm == common->next_frm)
- return;
-
- /* one frame is displayed If next frame is
- * available, release cur_frm and move on */
- /* Copy frame display time */
- do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
- /* Change status of the cur_frm */
- vb2_buffer_done(&common->cur_frm->vb,
- VB2_BUF_STATE_DONE);
- /* Make cur_frm pointing to next_frm */
- common->cur_frm = common->next_frm;
-
- } else if (1 == fid) { /* odd field */
- if (list_empty(&common->dma_queue)
- || (common->cur_frm != common->next_frm)) {
- return;
- }
- /* one field is displayed configure the next
- * frame if it is available else hold on current
- * frame */
- /* Get next from the buffer queue */
- process_progressive_mode(common);
-
- }
-}
-
-/*
- * vpif_channel_isr: It changes status of the displayed buffer, takes next
- * buffer from the queue and sets its address in VPIF registers
- */
-static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
-{
- struct vpif_device *dev = &vpif_obj;
- struct channel_obj *ch;
- struct common_obj *common;
- enum v4l2_field field;
- int fid = -1, i;
- int channel_id = 0;
-
- channel_id = *(int *)(dev_id);
- if (!vpif_intr_status(channel_id + 2))
- return IRQ_NONE;
-
- ch = dev->dev[channel_id];
- field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
- for (i = 0; i < VPIF_NUMOBJECTS; i++) {
- common = &ch->common[i];
- /* If streaming is started in this channel */
- if (0 == common->started)
- continue;
-
- if (1 == ch->vpifparams.std_info.frm_fmt) {
- if (list_empty(&common->dma_queue))
- continue;
-
- /* Progressive mode */
- if (!channel_first_int[i][channel_id]) {
- /* Mark status of the cur_frm to
- * done and unlock semaphore on it */
- do_gettimeofday(&common->cur_frm->vb.
- v4l2_buf.timestamp);
- vb2_buffer_done(&common->cur_frm->vb,
- VB2_BUF_STATE_DONE);
- /* Make cur_frm pointing to next_frm */
- common->cur_frm = common->next_frm;
- }
-
- channel_first_int[i][channel_id] = 0;
- process_progressive_mode(common);
- } else {
- /* Interlaced mode */
- /* If it is first interrupt, ignore it */
-
- if (channel_first_int[i][channel_id]) {
- channel_first_int[i][channel_id] = 0;
- continue;
- }
-
- if (0 == i) {
- ch->field_id ^= 1;
- /* Get field id from VPIF registers */
- fid = vpif_channel_getfid(ch->channel_id + 2);
- /* If fid does not match with stored field id */
- if (fid != ch->field_id) {
- /* Make them in sync */
- if (0 == fid)
- ch->field_id = fid;
-
- return IRQ_HANDLED;
- }
- }
- process_interlaced_mode(fid, common);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-static int vpif_update_std_info(struct channel_obj *ch)
-{
- struct video_obj *vid_ch = &ch->video;
- struct vpif_params *vpifparams = &ch->vpifparams;
- struct vpif_channel_config_params *std_info = &vpifparams->std_info;
- const struct vpif_channel_config_params *config;
-
- int i;
-
- for (i = 0; i < vpif_ch_params_count; i++) {
- config = &ch_params[i];
- if (config->hd_sd == 0) {
- vpif_dbg(2, debug, "SD format\n");
- if (config->stdid & vid_ch->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
- }
- } else {
- vpif_dbg(2, debug, "HD format\n");
- if (config->dv_preset == vid_ch->dv_preset) {
- memcpy(std_info, config, sizeof(*config));
- break;
- }
- }
- }
-
- if (i == vpif_ch_params_count) {
- vpif_dbg(1, debug, "Format not found\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vpif_update_resolution(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct video_obj *vid_ch = &ch->video;
- struct vpif_params *vpifparams = &ch->vpifparams;
- struct vpif_channel_config_params *std_info = &vpifparams->std_info;
-
- if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
- return -EINVAL;
-
- if (vid_ch->stdid || vid_ch->dv_preset) {
- if (vpif_update_std_info(ch))
- return -EINVAL;
- }
-
- common->fmt.fmt.pix.width = std_info->width;
- common->fmt.fmt.pix.height = std_info->height;
- vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
- common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
-
- /* Set height and width paramateres */
- common->height = std_info->height;
- common->width = std_info->width;
-
- return 0;
-}
-
-/*
- * vpif_calculate_offsets: This function calculates buffers offset for Y and C
- * in the top and bottom field
- */
-static void vpif_calculate_offsets(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_params *vpifparams = &ch->vpifparams;
- enum v4l2_field field = common->fmt.fmt.pix.field;
- struct video_obj *vid_ch = &ch->video;
- unsigned int hpitch, vpitch, sizeimage;
-
- if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
- if (ch->vpifparams.std_info.frm_fmt)
- vid_ch->buf_field = V4L2_FIELD_NONE;
- else
- vid_ch->buf_field = V4L2_FIELD_INTERLACED;
- } else {
- vid_ch->buf_field = common->fmt.fmt.pix.field;
- }
-
- sizeimage = common->fmt.fmt.pix.sizeimage;
-
- hpitch = common->fmt.fmt.pix.bytesperline;
- vpitch = sizeimage / (hpitch * 2);
- if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
- (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
- common->ytop_off = 0;
- common->ybtm_off = hpitch;
- common->ctop_off = sizeimage / 2;
- common->cbtm_off = sizeimage / 2 + hpitch;
- } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
- common->ytop_off = 0;
- common->ybtm_off = sizeimage / 4;
- common->ctop_off = sizeimage / 2;
- common->cbtm_off = common->ctop_off + sizeimage / 4;
- } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
- common->ybtm_off = 0;
- common->ytop_off = sizeimage / 4;
- common->cbtm_off = sizeimage / 2;
- common->ctop_off = common->cbtm_off + sizeimage / 4;
- }
-
- if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
- (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
- vpifparams->video_params.storage_mode = 1;
- } else {
- vpifparams->video_params.storage_mode = 0;
- }
-
- if (ch->vpifparams.std_info.frm_fmt == 1) {
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline;
- } else {
- if ((field == V4L2_FIELD_ANY) ||
- (field == V4L2_FIELD_INTERLACED))
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline * 2;
- else
- vpifparams->video_params.hpitch =
- common->fmt.fmt.pix.bytesperline;
- }
-
- ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
-}
-
-static void vpif_config_format(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if (config_params.numbuffers[ch->channel_id] == 0)
- common->memory = V4L2_MEMORY_USERPTR;
- else
- common->memory = V4L2_MEMORY_MMAP;
-
- common->fmt.fmt.pix.sizeimage =
- config_params.channel_bufsize[ch->channel_id];
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
- common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-}
-
-static int vpif_check_format(struct channel_obj *ch,
- struct v4l2_pix_format *pixfmt)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- enum v4l2_field field = pixfmt->field;
- u32 sizeimage, hpitch, vpitch;
-
- if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
- goto invalid_fmt_exit;
-
- if (!(VPIF_VALID_FIELD(field)))
- goto invalid_fmt_exit;
-
- if (pixfmt->bytesperline <= 0)
- goto invalid_pitch_exit;
-
- sizeimage = pixfmt->sizeimage;
-
- if (vpif_update_resolution(ch))
- return -EINVAL;
-
- hpitch = pixfmt->bytesperline;
- vpitch = sizeimage / (hpitch * 2);
-
- /* Check for valid value of pitch */
- if ((hpitch < ch->vpifparams.std_info.width) ||
- (vpitch < ch->vpifparams.std_info.height))
- goto invalid_pitch_exit;
-
- /* Check for 8 byte alignment */
- if (!ISALIGNED(hpitch)) {
- vpif_err("invalid pitch alignment\n");
- return -EINVAL;
- }
- pixfmt->width = common->fmt.fmt.pix.width;
- pixfmt->height = common->fmt.fmt.pix.height;
-
- return 0;
-
-invalid_fmt_exit:
- vpif_err("invalid field format\n");
- return -EINVAL;
-
-invalid_pitch_exit:
- vpif_err("invalid pitch\n");
- return -EINVAL;
-}
-
-static void vpif_config_addr(struct channel_obj *ch, int muxmode)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {
- common->set_addr = ch3_set_videobuf_addr;
- } else {
- if (2 == muxmode)
- common->set_addr = ch2_set_videobuf_addr_yc_nmux;
- else
- common->set_addr = ch2_set_videobuf_addr;
- }
-}
-
-/*
- * vpif_mmap: It is used to map kernel space buffers into user spaces
- */
-static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
-
- vpif_dbg(2, debug, "vpif_mmap\n");
-
- return vb2_mmap(&common->buffer_queue, vma);
-}
-
-/*
- * vpif_poll: It is used for select/poll system call
- */
-static unsigned int vpif_poll(struct file *filep, poll_table *wait)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (common->started)
- return vb2_poll(&common->buffer_queue, filep, wait);
-
- return 0;
-}
-
-/*
- * vpif_open: It creates object of file handle structure and stores it in
- * private_data member of filepointer
- */
-static int vpif_open(struct file *filep)
-{
- struct video_device *vdev = video_devdata(filep);
- struct channel_obj *ch = NULL;
- struct vpif_fh *fh = NULL;
-
- ch = video_get_drvdata(vdev);
- /* Allocate memory for the file handle object */
- fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
- if (fh == NULL) {
- vpif_err("unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
-
- /* store pointer to fh in private_data member of filep */
- filep->private_data = fh;
- fh->channel = ch;
- fh->initialized = 0;
- if (!ch->initialized) {
- fh->initialized = 1;
- ch->initialized = 1;
- memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
- }
-
- /* Increment channel usrs counter */
- atomic_inc(&ch->usrs);
- /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
- fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&ch->prio, &fh->prio);
-
- return 0;
-}
-
-/*
- * vpif_release: This function deletes buffer queue, frees the buffers and
- * the vpif file handle
- */
-static int vpif_release(struct file *filep)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* if this instance is doing IO */
- if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
- /* Reset io_usrs member of channel object */
- common->io_usrs = 0;
- /* Disable channel */
- if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
- enable_channel2(0);
- channel2_intr_enable(0);
- }
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
- enable_channel3(0);
- channel3_intr_enable(0);
- }
- common->started = 0;
-
- /* Free buffers allocated */
- vb2_queue_release(&common->buffer_queue);
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
-
- common->numbuffers =
- config_params.numbuffers[ch->channel_id];
- }
-
- /* Decrement channel usrs counter */
- atomic_dec(&ch->usrs);
- /* If this file handle has initialize encoder device, reset it */
- if (fh->initialized)
- ch->initialized = 0;
-
- /* Close the priority */
- v4l2_prio_close(&ch->prio, fh->prio);
- filep->private_data = NULL;
- fh->initialized = 0;
- kfree(fh);
-
- return 0;
-}
-
-/* functions implementing ioctls */
-/**
- * vpif_querycap() - QUERYCAP handler
- * @file: file ptr
- * @priv: file handle
- * @cap: ptr to v4l2_capability structure
- */
-static int vpif_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vpif_display_config *config = vpif_dev->platform_data;
-
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
- strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
- strlcpy(cap->card, config->card_name, sizeof(cap->card));
-
- return 0;
-}
-
-static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- if (fmt->index != 0) {
- vpif_err("Invalid format index\n");
- return -EINVAL;
- }
-
- /* Fill in the information about format */
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
- fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
-
- return 0;
-}
-
-static int vpif_g_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* Check the validity of the buffer type */
- if (common->fmt.type != fmt->type)
- return -EINVAL;
-
- if (vpif_update_resolution(ch))
- return -EINVAL;
- *fmt = common->fmt;
- return 0;
-}
-
-static int vpif_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct v4l2_pix_format *pixfmt;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
-
- /* Check for the priority */
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
- fh->initialized = 1;
- }
-
- if (common->started) {
- vpif_dbg(1, debug, "Streaming in progress\n");
- return -EBUSY;
- }
-
- pixfmt = &fmt->fmt.pix;
- /* Check for valid field format */
- ret = vpif_check_format(ch, pixfmt);
- if (ret)
- return ret;
-
- /* store the pix format in the channel object */
- common->fmt.fmt.pix = *pixfmt;
- /* store the format in the channel object */
- common->fmt = *fmt;
- return 0;
-}
-
-static int vpif_try_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- int ret = 0;
-
- ret = vpif_check_format(ch, pixfmt);
- if (ret) {
- *pixfmt = common->fmt.fmt.pix;
- pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
- }
-
- return ret;
-}
-
-static int vpif_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- enum v4l2_field field;
- struct vb2_queue *q;
- u8 index = 0;
-
- /* This file handle has not initialized the channel,
- It is not allowed to do settings */
- if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_err("Channel Busy\n");
- return -EBUSY;
- }
- }
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
- return -EINVAL;
-
- index = VPIF_VIDEO_INDEX;
-
- common = &ch->common[index];
-
- if (common->fmt.type != reqbuf->type || !vpif_dev)
- return -EINVAL;
- if (0 != common->io_usrs)
- return -EBUSY;
-
- if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_INTERLACED;
- else
- field = common->fmt.fmt.pix.field;
- } else {
- field = V4L2_VBI_INTERLACED;
- }
- /* Initialize videobuf2 queue as per the buffer type */
- common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
- if (!common->alloc_ctx) {
- vpif_err("Failed to get the context\n");
- return -EINVAL;
- }
- q = &common->buffer_queue;
- q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpif_disp_buffer);
-
- vb2_queue_init(q);
-
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed[index] = 1;
- /* Increment io usrs member of channel object to 1 */
- common->io_usrs = 1;
- /* Store type of memory requested in channel object */
- common->memory = reqbuf->memory;
- INIT_LIST_HEAD(&common->dma_queue);
- /* Allocate buffers */
- return vb2_reqbufs(&common->buffer_queue, reqbuf);
-}
-
-static int vpif_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *tbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (common->fmt.type != tbuf->type)
- return -EINVAL;
-
- return vb2_querybuf(&common->buffer_queue, tbuf);
-}
-
-static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpif_fh *fh = NULL;
- struct channel_obj *ch = NULL;
- struct common_obj *common = NULL;
-
- if (!buf || !priv)
- return -EINVAL;
-
- fh = priv;
- ch = fh->channel;
- if (!ch)
- return -EINVAL;
-
- common = &(ch->common[VPIF_VIDEO_INDEX]);
- if (common->fmt.type != buf->type)
- return -EINVAL;
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
-
- return vb2_qbuf(&common->buffer_queue, buf);
-}
-
-static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- if (!(*std_id & VPIF_V4L2_STD))
- return -EINVAL;
-
- if (common->started) {
- vpif_err("streaming in progress\n");
- return -EBUSY;
- }
-
- /* Call encoder subdevice function to set the standard */
- ch->video.stdid = *std_id;
- ch->video.dv_preset = V4L2_DV_INVALID;
- memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
-
- /* Get the information about the standard */
- if (vpif_update_resolution(ch))
- return -EINVAL;
-
- if ((ch->vpifparams.std_info.width *
- ch->vpifparams.std_info.height * 2) >
- config_params.channel_bufsize[ch->channel_id]) {
- vpif_err("invalid std for this size\n");
- return -EINVAL;
- }
-
- common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
- /* Configure the default format information */
- vpif_config_format(ch);
-
- ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
- s_std_output, *std_id);
- if (ret < 0) {
- vpif_err("Failed to set output standard\n");
- return ret;
- }
-
- ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
- s_std, *std_id);
- if (ret < 0)
- vpif_err("Failed to set standard for sub devices\n");
- return ret;
-}
-
-static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *std = ch->video.stdid;
- return 0;
-}
-
-static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- return vb2_dqbuf(&common->buffer_queue, p,
- (file->f_flags & O_NONBLOCK));
-}
-
-static int vpif_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
- int ret = 0;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- vpif_err("buffer type not supported\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
-
- /* If Streaming is already started, return error */
- if (common->started) {
- vpif_err("channel->started\n");
- return -EBUSY;
- }
-
- if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
- && oth_ch->common[VPIF_VIDEO_INDEX].started &&
- ch->vpifparams.std_info.ycmux_mode == 0)
- || ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
- && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
- vpif_err("other channel is using\n");
- return -EBUSY;
- }
-
- ret = vpif_check_format(ch, &common->fmt.fmt.pix);
- if (ret < 0)
- return ret;
-
- /* Call vb2_streamon to start streaming in videobuf2 */
- ret = vb2_streamon(&common->buffer_queue, buftype);
- if (ret < 0) {
- vpif_err("vb2_streamon\n");
- return ret;
- }
-
- return ret;
-}
-
-static int vpif_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_display_config *vpif_config_data =
- vpif_dev->platform_data;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- vpif_err("buffer type not supported\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
-
- if (!common->started) {
- vpif_err("channel->started\n");
- return -EINVAL;
- }
-
- if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- /* disable channel */
- if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
- if (vpif_config_data->ch2_clip_en)
- channel2_clipping_enable(0);
- enable_channel2(0);
- channel2_intr_enable(0);
- }
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
- if (vpif_config_data->ch3_clip_en)
- channel3_clipping_enable(0);
- enable_channel3(0);
- channel3_intr_enable(0);
- }
- }
-
- common->started = 0;
- return vb2_streamoff(&common->buffer_queue, buftype);
-}
-
-static int vpif_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *crop)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
- return -EINVAL;
-
- crop->bounds.left = crop->bounds.top = 0;
- crop->defrect.left = crop->defrect.top = 0;
- crop->defrect.height = crop->bounds.height = common->height;
- crop->defrect.width = crop->bounds.width = common->width;
-
- return 0;
-}
-
-static int vpif_enum_output(struct file *file, void *fh,
- struct v4l2_output *output)
-{
-
- struct vpif_display_config *config = vpif_dev->platform_data;
-
- if (output->index >= config->output_count) {
- vpif_dbg(1, debug, "Invalid output index\n");
- return -EINVAL;
- }
-
- strcpy(output->name, config->output[output->index]);
- output->type = V4L2_OUTPUT_TYPE_ANALOG;
- output->std = VPIF_V4L2_STD;
-
- return 0;
-}
-
-static int vpif_s_output(struct file *file, void *priv, unsigned int i)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- if (common->started) {
- vpif_err("Streaming in progress\n");
- return -EBUSY;
- }
-
- ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
- s_routing, 0, i, 0);
-
- if (ret < 0)
- vpif_err("Failed to set output standard\n");
-
- vid_ch->output_id = i;
- return ret;
-}
-
-static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
-
- *i = vid_ch->output_id;
-
- return 0;
-}
-
-static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *p = v4l2_prio_max(&ch->prio);
-
- return 0;
-}
-
-static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_prio_change(&ch->prio, &fh->prio, p);
-}
-
-/**
- * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_enum_dv_presets(struct file *file, void *priv,
- struct v4l2_dv_enum_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
-
- return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
- video, enum_dv_presets, preset);
-}
-
-/**
- * vpif_s_dv_presets() - S_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_s_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct video_obj *vid_ch = &ch->video;
- int ret = 0;
-
- if (common->started) {
- vpif_dbg(1, debug, "streaming in progress\n");
- return -EBUSY;
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (ret != 0)
- return ret;
-
- fh->initialized = 1;
-
- /* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- ch->video.dv_preset = preset->preset;
- ch->video.stdid = V4L2_STD_UNKNOWN;
- memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
-
- /* Get the information about the standard */
- if (vpif_update_resolution(ch)) {
- ret = -EINVAL;
- } else {
- /* Configure the default format information */
- vpif_config_format(ch);
-
- ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
- video, s_dv_preset, preset);
- }
-
- mutex_unlock(&common->lock);
-
- return ret;
-}
-/**
- * vpif_g_dv_presets() - G_DV_PRESETS handler
- * @file: file ptr
- * @priv: file handle
- * @preset: input preset
- */
-static int vpif_g_dv_preset(struct file *file, void *priv,
- struct v4l2_dv_preset *preset)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- preset->preset = ch->video.dv_preset;
-
- return 0;
-}
-/**
- * vpif_s_dv_timings() - S_DV_TIMINGS handler
- * @file: file ptr
- * @priv: file handle
- * @timings: digital video timings
- */
-static int vpif_s_dv_timings(struct file *file, void *priv,
- struct v4l2_dv_timings *timings)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct vpif_params *vpifparams = &ch->vpifparams;
- struct vpif_channel_config_params *std_info = &vpifparams->std_info;
- struct video_obj *vid_ch = &ch->video;
- struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
- int ret;
-
- if (timings->type != V4L2_DV_BT_656_1120) {
- vpif_dbg(2, debug, "Timing type not defined\n");
- return -EINVAL;
- }
-
- /* Configure subdevice timings, if any */
- ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
- video, s_dv_timings, timings);
- if (ret == -ENOIOCTLCMD) {
- vpif_dbg(2, debug, "Custom DV timings not supported by "
- "subdevice\n");
- return -EINVAL;
- }
- if (ret < 0) {
- vpif_dbg(2, debug, "Error setting custom DV timings\n");
- return ret;
- }
-
- if (!(timings->bt.width && timings->bt.height &&
- (timings->bt.hbackporch ||
- timings->bt.hfrontporch ||
- timings->bt.hsync) &&
- timings->bt.vfrontporch &&
- (timings->bt.vbackporch ||
- timings->bt.vsync))) {
- vpif_dbg(2, debug, "Timings for width, height, "
- "horizontal back porch, horizontal sync, "
- "horizontal front porch, vertical back porch, "
- "vertical sync and vertical back porch "
- "must be defined\n");
- return -EINVAL;
- }
-
- *bt = timings->bt;
-
- /* Configure video port timings */
-
- std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
- bt->hsync - 8;
- std_info->sav2eav = bt->width;
-
- std_info->l1 = 1;
- std_info->l3 = bt->vsync + bt->vbackporch + 1;
-
- if (bt->interlaced) {
- if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
- std_info->vsize = bt->height * 2 +
- bt->vfrontporch + bt->vsync + bt->vbackporch +
- bt->il_vfrontporch + bt->il_vsync +
- bt->il_vbackporch;
- std_info->l5 = std_info->vsize/2 -
- (bt->vfrontporch - 1);
- std_info->l7 = std_info->vsize/2 + 1;
- std_info->l9 = std_info->l7 + bt->il_vsync +
- bt->il_vbackporch + 1;
- std_info->l11 = std_info->vsize -
- (bt->il_vfrontporch - 1);
- } else {
- vpif_dbg(2, debug, "Required timing values for "
- "interlaced BT format missing\n");
- return -EINVAL;
- }
- } else {
- std_info->vsize = bt->height + bt->vfrontporch +
- bt->vsync + bt->vbackporch;
- std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
- }
- strncpy(std_info->name, "Custom timings BT656/1120",
- VPIF_MAX_NAME);
- std_info->width = bt->width;
- std_info->height = bt->height;
- std_info->frm_fmt = bt->interlaced ? 0 : 1;
- std_info->ycmux_mode = 0;
- std_info->capture_format = 0;
- std_info->vbi_supported = 0;
- std_info->hd_sd = 1;
- std_info->stdid = 0;
- std_info->dv_preset = V4L2_DV_INVALID;
-
- vid_ch->stdid = 0;
- vid_ch->dv_preset = V4L2_DV_INVALID;
-
- return 0;
-}
-
-/**
- * vpif_g_dv_timings() - G_DV_TIMINGS handler
- * @file: file ptr
- * @priv: file handle
- * @timings: digital video timings
- */
-static int vpif_g_dv_timings(struct file *file, void *priv,
- struct v4l2_dv_timings *timings)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
- struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
-
- timings->bt = *bt;
-
- return 0;
-}
-
-/*
- * vpif_g_chip_ident() - Identify the chip
- * @file: file ptr
- * @priv: file handle
- * @chip: chip identity
- *
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- 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) {
- vpif_dbg(2, debug, "match_type is invalid.\n");
- return -EINVAL;
- }
-
- return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
- g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * vpif_dbg_g_register() - Read register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be read
- *
- * Debugging only
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_dbg_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
-
- return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
- g_register, reg);
-}
-
-/*
- * vpif_dbg_s_register() - Write to register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be modified
- *
- * Debugging only
- * Returns zero or -EINVAL if write operations fails.
- */
-static int vpif_dbg_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct video_obj *vid_ch = &ch->video;
-
- return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
- s_register, reg);
-}
-#endif
-
-/*
- * vpif_log_status() - Status information
- * @file: file ptr
- * @priv: file handle
- *
- * Returns zero.
- */
-static int vpif_log_status(struct file *filep, void *priv)
-{
- /* status for sub devices */
- v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
-
- return 0;
-}
-
-/* vpif display ioctl operations */
-static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
- .vidioc_querycap = vpif_querycap,
- .vidioc_g_priority = vpif_g_priority,
- .vidioc_s_priority = vpif_s_priority,
- .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
- .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
- .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
- .vidioc_reqbufs = vpif_reqbufs,
- .vidioc_querybuf = vpif_querybuf,
- .vidioc_qbuf = vpif_qbuf,
- .vidioc_dqbuf = vpif_dqbuf,
- .vidioc_streamon = vpif_streamon,
- .vidioc_streamoff = vpif_streamoff,
- .vidioc_s_std = vpif_s_std,
- .vidioc_g_std = vpif_g_std,
- .vidioc_enum_output = vpif_enum_output,
- .vidioc_s_output = vpif_s_output,
- .vidioc_g_output = vpif_g_output,
- .vidioc_cropcap = vpif_cropcap,
- .vidioc_enum_dv_presets = vpif_enum_dv_presets,
- .vidioc_s_dv_preset = vpif_s_dv_preset,
- .vidioc_g_dv_preset = vpif_g_dv_preset,
- .vidioc_s_dv_timings = vpif_s_dv_timings,
- .vidioc_g_dv_timings = vpif_g_dv_timings,
- .vidioc_g_chip_ident = vpif_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vpif_dbg_g_register,
- .vidioc_s_register = vpif_dbg_s_register,
-#endif
- .vidioc_log_status = vpif_log_status,
-};
-
-static const struct v4l2_file_operations vpif_fops = {
- .owner = THIS_MODULE,
- .open = vpif_open,
- .release = vpif_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = vpif_mmap,
- .poll = vpif_poll
-};
-
-static struct video_device vpif_video_template = {
- .name = "vpif",
- .fops = &vpif_fops,
- .ioctl_ops = &vpif_ioctl_ops,
- .tvnorms = VPIF_V4L2_STD,
- .current_norm = V4L2_STD_625_50,
-
-};
-
-/*Configure the channels, buffer sizei, request irq */
-static int initialize_vpif(void)
-{
- int free_channel_objects_index;
- int free_buffer_channel_index;
- int free_buffer_index;
- int err = 0, i, j;
-
- /* Default number of buffers should be 3 */
- if ((ch2_numbuffers > 0) &&
- (ch2_numbuffers < config_params.min_numbuffers))
- ch2_numbuffers = config_params.min_numbuffers;
- if ((ch3_numbuffers > 0) &&
- (ch3_numbuffers < config_params.min_numbuffers))
- ch3_numbuffers = config_params.min_numbuffers;
-
- /* Set buffer size to min buffers size if invalid buffer size is
- * given */
- if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
- ch2_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
- if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
- ch3_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
-
- config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
-
- if (ch2_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
- ch2_bufsize;
- }
- config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
-
- if (ch3_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
- ch3_bufsize;
- }
-
- /* Allocate memory for six channel objects */
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- vpif_obj.dev[i] =
- kzalloc(sizeof(struct channel_obj), GFP_KERNEL);
- /* If memory allocation fails, return error */
- if (!vpif_obj.dev[i]) {
- free_channel_objects_index = i;
- err = -ENOMEM;
- goto vpif_init_free_channel_objects;
- }
- }
-
- free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
- free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
- free_buffer_index = config_params.numbuffers[i - 1];
-
- return 0;
-
-vpif_init_free_channel_objects:
- for (j = 0; j < free_channel_objects_index; j++)
- kfree(vpif_obj.dev[j]);
- return err;
-}
-
-/*
- * vpif_probe: This function creates device entries by register itself to the
- * V4L2 driver and initializes fields of each channel objects
- */
-static __init int vpif_probe(struct platform_device *pdev)
-{
- struct vpif_subdev_info *subdevdata;
- struct vpif_display_config *config;
- int i, j = 0, k, q, m, err = 0;
- struct i2c_adapter *i2c_adap;
- struct common_obj *common;
- struct channel_obj *ch;
- struct video_device *vfd;
- struct resource *res;
- int subdev_count;
- size_t size;
-
- vpif_dev = &pdev->dev;
- err = initialize_vpif();
-
- if (err) {
- v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
- 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++) {
- if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
- "VPIF_Display",
- (void *)(&vpif_obj.dev[k]->channel_id))) {
- err = -EBUSY;
- goto vpif_int_err;
- }
- }
- k++;
- }
-
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
-
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
-
- /* Allocate memory for video device */
- vfd = video_device_alloc();
- if (vfd == NULL) {
- for (j = 0; j < i; j++) {
- ch = vpif_obj.dev[j];
- video_device_release(ch->video_dev);
- }
- err = -ENOMEM;
- goto vpif_int_err;
- }
-
- /* Initialize field of video device */
- *vfd = vpif_video_template;
- vfd->v4l2_dev = &vpif_obj.v4l2_dev;
- vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name),
- "VPIF_Display_DRIVER_V%s",
- VPIF_DISPLAY_VERSION);
-
- /* Set video_dev to the video device */
- ch->video_dev = vfd;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- size = resource_size(res);
- /* The resources are divided into two equal memory and when
- * we have HD output we can add them together
- */
- for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- ch->channel_id = j;
-
- /* only enabled if second resource exists */
- config_params.video_limit[ch->channel_id] = 0;
- if (size)
- config_params.video_limit[ch->channel_id] =
- size/2;
- }
- }
-
- for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- /* Initialize field of the channel objects */
- atomic_set(&ch->usrs, 0);
- for (k = 0; k < VPIF_NUMOBJECTS; k++) {
- ch->common[k].numbuffers = 0;
- common = &ch->common[k];
- common->io_usrs = 0;
- common->started = 0;
- spin_lock_init(&common->irqlock);
- mutex_init(&common->lock);
- common->numbuffers = 0;
- common->set_addr = NULL;
- common->ytop_off = common->ybtm_off = 0;
- common->ctop_off = common->cbtm_off = 0;
- common->cur_frm = common->next_frm = NULL;
- memset(&common->fmt, 0, sizeof(common->fmt));
- common->numbuffers = config_params.numbuffers[k];
-
- }
- ch->initialized = 0;
- ch->channel_id = j;
- if (j < 2)
- ch->common[VPIF_VIDEO_INDEX].numbuffers =
- config_params.numbuffers[ch->channel_id];
- else
- ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
-
- memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
-
- /* Initialize prio member of channel object */
- v4l2_prio_init(&ch->prio);
- ch->common[VPIF_VIDEO_INDEX].fmt.type =
- V4L2_BUF_TYPE_VIDEO_OUTPUT;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
- ch->video_dev->lock = &common->lock;
-
- /* register video device */
- vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
- (int)ch, (int)&ch->video_dev);
-
- err = video_register_device(ch->video_dev,
- VFL_TYPE_GRABBER, (j ? 3 : 2));
- if (err < 0)
- goto probe_out;
-
- video_set_drvdata(ch->video_dev, ch);
- }
-
- i2c_adap = i2c_get_adapter(1);
- config = pdev->dev.platform_data;
- subdev_count = config->subdev_count;
- subdevdata = config->subdevinfo;
- vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
- GFP_KERNEL);
- if (vpif_obj.sd == NULL) {
- vpif_err("unable to allocate memory for subdevice pointers\n");
- err = -ENOMEM;
- goto probe_out;
- }
-
- for (i = 0; i < subdev_count; i++) {
- vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap,
- &subdevdata[i].board_info,
- NULL);
- if (!vpif_obj.sd[i]) {
- vpif_err("Error registering v4l2 subdevice\n");
- goto probe_subdev_out;
- }
-
- if (vpif_obj.sd[i])
- vpif_obj.sd[i]->grp_id = 1 << i;
- }
-
- v4l2_info(&vpif_obj.v4l2_dev,
- " VPIF display driver initialized\n");
- return 0;
-
-probe_subdev_out:
- kfree(vpif_obj.sd);
-probe_out:
- for (k = 0; k < j; k++) {
- ch = vpif_obj.dev[k];
- video_unregister_device(ch->video_dev);
- video_device_release(ch->video_dev);
- ch->video_dev = NULL;
- }
-vpif_int_err:
- v4l2_device_unregister(&vpif_obj.v4l2_dev);
- vpif_err("VPIF IRQ request failed\n");
- for (q = k; k >= 0; k--) {
- for (m = i; m >= res->start; m--)
- free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
- res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
- m = res->end;
- }
-
- return err;
-}
-
-/*
- * vpif_remove: It un-register channels from V4L2 driver
- */
-static int vpif_remove(struct platform_device *device)
-{
- struct channel_obj *ch;
- int i;
-
- v4l2_device_unregister(&vpif_obj.v4l2_dev);
-
- /* un-register device */
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- /* Unregister video device */
- video_unregister_device(ch->video_dev);
-
- ch->video_dev = NULL;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int vpif_suspend(struct device *dev)
-{
- struct common_obj *common;
- struct channel_obj *ch;
- int i;
-
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
- if (atomic_read(&ch->usrs) && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
- enable_channel2(0);
- channel2_intr_enable(0);
- }
- if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
- common->started == 2) {
- enable_channel3(0);
- channel3_intr_enable(0);
- }
- }
- mutex_unlock(&common->lock);
- }
-
- return 0;
-}
-
-static int vpif_resume(struct device *dev)
-{
-
- struct common_obj *common;
- struct channel_obj *ch;
- int i;
-
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
- /* Get the pointer to the channel object */
- ch = vpif_obj.dev[i];
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
- if (atomic_read(&ch->usrs) && common->io_usrs) {
- /* Enable channel */
- if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
- enable_channel2(1);
- channel2_intr_enable(1);
- }
- if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
- common->started == 2) {
- enable_channel3(1);
- channel3_intr_enable(1);
- }
- }
- mutex_unlock(&common->lock);
- }
-
- return 0;
-}
-
-static const struct dev_pm_ops vpif_pm = {
- .suspend = vpif_suspend,
- .resume = vpif_resume,
-};
-
-#define vpif_pm_ops (&vpif_pm)
-#else
-#define vpif_pm_ops NULL
-#endif
-
-static __refdata struct platform_driver vpif_driver = {
- .driver = {
- .name = "vpif_display",
- .owner = THIS_MODULE,
- .pm = vpif_pm_ops,
- },
- .probe = vpif_probe,
- .remove = vpif_remove,
-};
-
-static __init int vpif_init(void)
-{
- return platform_driver_register(&vpif_driver);
-}
-
-/*
- * vpif_cleanup: This function un-registers device and driver to the kernel,
- * frees requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
- struct platform_device *pdev;
- struct resource *res;
- int irq_num;
- int i = 0;
-
- pdev = container_of(vpif_dev, struct platform_device, dev);
-
- while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
- for (irq_num = res->start; irq_num <= res->end; irq_num++)
- free_irq(irq_num,
- (void *)(&vpif_obj.dev[i]->channel_id));
- i++;
- }
-
- platform_driver_unregister(&vpif_driver);
- kfree(vpif_obj.sd);
- for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
- kfree(vpif_obj.dev[i]);
-}
-
-module_init(vpif_init);
-module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
deleted file mode 100644
index 3e5cf27ec2b2..000000000000
--- a/drivers/media/video/davinci/vpss.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2009 Texas Instruments.
- *
- * 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.
- *
- * common vpss system module platform driver for all video drivers.
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/compiler.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <media/davinci/vpss.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("VPSS Driver");
-MODULE_AUTHOR("Texas Instruments");
-
-/* DM644x defines */
-#define DM644X_SBL_PCR_VPSS (4)
-
-#define DM355_VPSSBL_INTSEL 0x10
-#define DM355_VPSSBL_EVTSEL 0x14
-/* vpss BL register offsets */
-#define DM355_VPSSBL_CCDCMUX 0x1c
-/* vpss CLK register offsets */
-#define DM355_VPSSCLK_CLKCTRL 0x04
-/* masks and shifts */
-#define VPSS_HSSISEL_SHIFT 4
-/*
- * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4,
- * IPIPE_INT1_SDR - vpss_int5
- */
-#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10
-/* VENCINT - vpss_int8 */
-#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4
-
-#define DM365_ISP5_PCCR 0x04
-#define DM365_ISP5_INTSEL1 0x10
-#define DM365_ISP5_INTSEL2 0x14
-#define DM365_ISP5_INTSEL3 0x18
-#define DM365_ISP5_CCDCMUX 0x20
-#define DM365_ISP5_PG_FRAME_SIZE 0x28
-#define DM365_VPBE_CLK_CTRL 0x00
-/*
- * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
- * AF - vpss_int3
- */
-#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100
-/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */
-#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f
-/* VENC - vpss_int8 */
-#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015
-
-/* masks and shifts for DM365*/
-#define DM365_CCDC_PG_VD_POL_SHIFT 0
-#define DM365_CCDC_PG_HD_POL_SHIFT 1
-
-#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4))
-#define CCD_SRC_SEL_SHIFT 4
-
-/* Different SoC platforms supported by this driver */
-enum vpss_platform_type {
- DM644X,
- DM355,
- DM365,
-};
-
-/*
- * vpss operations. Depends on platform. Not all functions are available
- * on all platforms. The api, first check if a functio is available before
- * invoking it. In the probe, the function ptrs are initialized based on
- * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
- */
-struct vpss_hw_ops {
- /* enable clock */
- int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
- /* select input to ccdc */
- void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
- /* clear wbl overflow bit */
- int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
-};
-
-/* vpss configuration */
-struct vpss_oper_config {
- __iomem void *vpss_regs_base0;
- __iomem void *vpss_regs_base1;
- enum vpss_platform_type platform;
- spinlock_t vpss_lock;
- struct vpss_hw_ops hw_ops;
-};
-
-static struct vpss_oper_config oper_cfg;
-
-/* register access routines */
-static inline u32 bl_regr(u32 offset)
-{
- return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
-}
-
-static inline void bl_regw(u32 val, u32 offset)
-{
- __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
-}
-
-static inline u32 vpss_regr(u32 offset)
-{
- return __raw_readl(oper_cfg.vpss_regs_base1 + offset);
-}
-
-static inline void vpss_regw(u32 val, u32 offset)
-{
- __raw_writel(val, oper_cfg.vpss_regs_base1 + offset);
-}
-
-/* For DM365 only */
-static inline u32 isp5_read(u32 offset)
-{
- return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
-}
-
-/* For DM365 only */
-static inline void isp5_write(u32 val, u32 offset)
-{
- __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
-}
-
-static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
-{
- u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK;
-
- /* if we are using pattern generator, enable it */
- if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG)
- temp |= 0x08;
-
- temp |= (src_sel << CCD_SRC_SEL_SHIFT);
- isp5_write(temp, DM365_ISP5_CCDCMUX);
-}
-
-static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
-{
- bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
-}
-
-int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
-{
- if (!oper_cfg.hw_ops.select_ccdc_source)
- return -EINVAL;
-
- oper_cfg.hw_ops.select_ccdc_source(src_sel);
- return 0;
-}
-EXPORT_SYMBOL(vpss_select_ccdc_source);
-
-static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
-{
- u32 mask = 1, val;
-
- if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
- wbl_sel > VPSS_PCR_CCDC_WBL_O)
- return -EINVAL;
-
- /* writing a 0 clear the overflow */
- mask = ~(mask << wbl_sel);
- val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
- bl_regw(val, DM644X_SBL_PCR_VPSS);
- return 0;
-}
-
-int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
-{
- if (!oper_cfg.hw_ops.clear_wbl_overflow)
- return -EINVAL;
-
- return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
-}
-EXPORT_SYMBOL(vpss_clear_wbl_overflow);
-
-/*
- * dm355_enable_clock - Enable VPSS Clock
- * @clock_sel: CLock to be enabled/disabled
- * @en: enable/disable flag
- *
- * This is called to enable or disable a vpss clock
- */
-static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
-{
- unsigned long flags;
- u32 utemp, mask = 0x1, shift = 0;
-
- switch (clock_sel) {
- case VPSS_VPBE_CLOCK:
- /* nothing since lsb */
- break;
- case VPSS_VENC_CLOCK_SEL:
- shift = 2;
- break;
- case VPSS_CFALD_CLOCK:
- shift = 3;
- break;
- case VPSS_H3A_CLOCK:
- shift = 4;
- break;
- case VPSS_IPIPE_CLOCK:
- shift = 5;
- break;
- case VPSS_CCDC_CLOCK:
- shift = 6;
- break;
- default:
- printk(KERN_ERR "dm355_enable_clock:"
- " Invalid selector: %d\n", clock_sel);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
- utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
- if (!en)
- utemp &= ~(mask << shift);
- else
- utemp |= (mask << shift);
-
- vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
- spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
- return 0;
-}
-
-static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en)
-{
- unsigned long flags;
- u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR;
- u32 (*read)(u32 offset) = isp5_read;
- void(*write)(u32 val, u32 offset) = isp5_write;
-
- switch (clock_sel) {
- case VPSS_BL_CLOCK:
- break;
- case VPSS_CCDC_CLOCK:
- shift = 1;
- break;
- case VPSS_H3A_CLOCK:
- shift = 2;
- break;
- case VPSS_RSZ_CLOCK:
- shift = 3;
- break;
- case VPSS_IPIPE_CLOCK:
- shift = 4;
- break;
- case VPSS_IPIPEIF_CLOCK:
- shift = 5;
- break;
- case VPSS_PCLK_INTERNAL:
- shift = 6;
- break;
- case VPSS_PSYNC_CLOCK_SEL:
- shift = 7;
- break;
- case VPSS_VPBE_CLOCK:
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- case VPSS_VENC_CLOCK_SEL:
- shift = 2;
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- case VPSS_LDC_CLOCK:
- shift = 3;
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- case VPSS_FDIF_CLOCK:
- shift = 4;
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- case VPSS_OSD_CLOCK_SEL:
- shift = 6;
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- case VPSS_LDC_CLOCK_SEL:
- shift = 7;
- read = vpss_regr;
- write = vpss_regw;
- offset = DM365_VPBE_CLK_CTRL;
- break;
- default:
- printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n",
- clock_sel);
- return -1;
- }
-
- spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
- utemp = read(offset);
- if (!en) {
- mask = ~mask;
- utemp &= (mask << shift);
- } else
- utemp |= (mask << shift);
-
- write(utemp, offset);
- spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
-
- return 0;
-}
-
-int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
-{
- if (!oper_cfg.hw_ops.enable_clock)
- return -EINVAL;
-
- return oper_cfg.hw_ops.enable_clock(clock_sel, en);
-}
-EXPORT_SYMBOL(vpss_enable_clock);
-
-void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
-{
- int val = 0;
- val = isp5_read(DM365_ISP5_CCDCMUX);
-
- val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT);
- val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT);
-
- isp5_write(val, DM365_ISP5_CCDCMUX);
-}
-EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
-
-void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
-{
- int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
-
- current_reg |= (frame_size.pplen - 1);
- isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE);
-}
-EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
-
-static int __init vpss_probe(struct platform_device *pdev)
-{
- struct resource *r1, *r2;
- char *platform_name;
- int status;
-
- if (!pdev->dev.platform_data) {
- dev_err(&pdev->dev, "no platform data\n");
- return -ENOENT;
- }
-
- platform_name = pdev->dev.platform_data;
- if (!strcmp(platform_name, "dm355_vpss"))
- oper_cfg.platform = DM355;
- else if (!strcmp(platform_name, "dm365_vpss"))
- oper_cfg.platform = DM365;
- else if (!strcmp(platform_name, "dm644x_vpss"))
- oper_cfg.platform = DM644X;
- else {
- dev_err(&pdev->dev, "vpss driver not supported on"
- " this platform\n");
- return -ENODEV;
- }
-
- dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
- r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r1)
- return -ENOENT;
-
- r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
- if (!r1)
- return -EBUSY;
-
- oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
- if (!oper_cfg.vpss_regs_base0) {
- status = -EBUSY;
- goto fail1;
- }
-
- if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
- r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!r2) {
- status = -ENOENT;
- goto fail2;
- }
- r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
- if (!r2) {
- status = -EBUSY;
- goto fail2;
- }
-
- oper_cfg.vpss_regs_base1 = ioremap(r2->start,
- resource_size(r2));
- if (!oper_cfg.vpss_regs_base1) {
- status = -EBUSY;
- goto fail3;
- }
- }
-
- if (oper_cfg.platform == DM355) {
- oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
- oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
- /* Setup vpss interrupts */
- bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL);
- bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL);
- } else if (oper_cfg.platform == DM365) {
- oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
- oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
- /* Setup vpss interrupts */
- isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
- isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
- isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
- } else
- oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
-
- spin_lock_init(&oper_cfg.vpss_lock);
- dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
- return 0;
-
-fail3:
- release_mem_region(r2->start, resource_size(r2));
-fail2:
- iounmap(oper_cfg.vpss_regs_base0);
-fail1:
- release_mem_region(r1->start, resource_size(r1));
- return status;
-}
-
-static int __devexit vpss_remove(struct platform_device *pdev)
-{
- struct resource *res;
-
- iounmap(oper_cfg.vpss_regs_base0);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
- if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
- iounmap(oper_cfg.vpss_regs_base1);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- release_mem_region(res->start, resource_size(res));
- }
- return 0;
-}
-
-static struct platform_driver vpss_driver = {
- .driver = {
- .name = "vpss",
- .owner = THIS_MODULE,
- },
- .remove = __devexit_p(vpss_remove),
- .probe = vpss_probe,
-};
-
-static void vpss_exit(void)
-{
- platform_driver_unregister(&vpss_driver);
-}
-
-static int __init vpss_init(void)
-{
- return platform_driver_register(&vpss_driver);
-}
-subsys_initcall(vpss_init);
-module_exit(vpss_exit);
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
deleted file mode 100644
index 928ef0d0429f..000000000000
--- a/drivers/media/video/em28xx/Kconfig
+++ /dev/null
@@ -1,58 +0,0 @@
-config VIDEO_EM28XX
- tristate "Empia EM28xx USB video capture support"
- depends on VIDEO_DEV && I2C
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEOBUF_VMALLOC
- select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO
-
- ---help---
- This is a video4linux driver for Empia 28xx based TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called em28xx
-
-config VIDEO_EM28XX_ALSA
- depends on VIDEO_EM28XX && SND
- select SND_PCM
- tristate "Empia EM28xx ALSA audio module"
- ---help---
- This is an ALSA driver for some Empia 28xx based TV cards.
-
- This is not required for em2800/em2820/em2821 boards. However,
- newer em28xx devices uses Vendor Class for audio, instead of
- implementing the USB Audio Class. For those chips, this module
- will enable digital audio.
-
- To compile this driver as a module, choose M here: the
- module will be called em28xx-alsa
-
-config VIDEO_EM28XX_DVB
- tristate "DVB/ATSC Support for em28xx based TV cards"
- depends on VIDEO_EM28XX && DVB_CORE
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
- select DVB_S921 if !DVB_FE_CUSTOMISE
- select DVB_DRXD if !DVB_FE_CUSTOMISE
- select DVB_CXD2820R if !DVB_FE_CUSTOMISE
- select DVB_DRXK if !DVB_FE_CUSTOMISE
- select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
- select DVB_TDA10071 if !DVB_FE_CUSTOMISE
- select DVB_A8293 if !DVB_FE_CUSTOMISE
- select VIDEOBUF_DVB
- ---help---
- This adds support for DVB cards based on the
- Empiatech em28xx chips.
-
-config VIDEO_EM28XX_RC
- tristate "EM28XX Remote Controller support"
- depends on RC_CORE
- depends on VIDEO_EM28XX
- depends on !(RC_CORE=m && VIDEO_EM28XX=y)
- default VIDEO_EM28XX
- ---help---
- Enables Remote Controller support on em28xx driver.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
deleted file mode 100644
index c8b338d4be05..000000000000
--- a/drivers/media/video/em28xx/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-em28xx-y := em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y += em28xx-core.o em28xx-vbi.o
-
-em28xx-alsa-objs := em28xx-audio.o
-em28xx-rc-objs := em28xx-input.o
-
-obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
-obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
-obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
-obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.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
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
deleted file mode 100644
index 07dc594e79f0..000000000000
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * Empiatech em28x1 audio extension
- *
- * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
- *
- * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
- * - Port to work with the in-kernel driver
- * - Cleanups, fixes, alsa-controls, etc.
- *
- * This driver is based on my previous au600 usb pstn audio driver
- * and inherits all the copyrights
- *
- * 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/kernel.h>
-#include <linux/usb.h>
-#include <linux/init.h>
-#include <linux/sound.h>
-#include <linux/spinlock.h>
-#include <linux/soundcard.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/proc_fs.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-#include <sound/ac97_codec.h>
-#include <media/v4l2-common.h>
-#include "em28xx.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-#define dprintk(fmt, arg...) do { \
- if (debug) \
- printk(KERN_INFO "em28xx-audio %s: " fmt, \
- __func__, ##arg); \
- } while (0)
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-
-static int em28xx_deinit_isoc_audio(struct em28xx *dev)
-{
- int i;
-
- dprintk("Stopping isoc\n");
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- if (!irqs_disabled())
- usb_kill_urb(dev->adev.urb[i]);
- else
- usb_unlink_urb(dev->adev.urb[i]);
-
- usb_free_urb(dev->adev.urb[i]);
- dev->adev.urb[i] = NULL;
-
- kfree(dev->adev.transfer_buffer[i]);
- dev->adev.transfer_buffer[i] = NULL;
- }
-
- return 0;
-}
-
-static void em28xx_audio_isocirq(struct urb *urb)
-{
- struct em28xx *dev = urb->context;
- int i;
- unsigned int oldptr;
- int period_elapsed = 0;
- int status;
- unsigned char *cp;
- unsigned int stride;
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
-
- switch (urb->status) {
- case 0: /* success */
- case -ETIMEDOUT: /* NAK */
- break;
- case -ECONNRESET: /* kill */
- case -ENOENT:
- case -ESHUTDOWN:
- return;
- default: /* error */
- dprintk("urb completition error %d.\n", urb->status);
- break;
- }
-
- if (atomic_read(&dev->stream_started) == 0)
- return;
-
- if (dev->adev.capture_pcm_substream) {
- substream = dev->adev.capture_pcm_substream;
- runtime = substream->runtime;
- stride = runtime->frame_bits >> 3;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int length =
- urb->iso_frame_desc[i].actual_length / stride;
- cp = (unsigned char *)urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
-
- if (!length)
- continue;
-
- oldptr = dev->adev.hwptr_done_capture;
- if (oldptr + length >= runtime->buffer_size) {
- unsigned int cnt =
- runtime->buffer_size - oldptr;
- memcpy(runtime->dma_area + oldptr * stride, cp,
- cnt * stride);
- memcpy(runtime->dma_area, cp + cnt * stride,
- length * stride - cnt * stride);
- } else {
- memcpy(runtime->dma_area + oldptr * stride, cp,
- length * stride);
- }
-
- snd_pcm_stream_lock(substream);
-
- dev->adev.hwptr_done_capture += length;
- if (dev->adev.hwptr_done_capture >=
- runtime->buffer_size)
- dev->adev.hwptr_done_capture -=
- runtime->buffer_size;
-
- dev->adev.capture_transfer_done += length;
- if (dev->adev.capture_transfer_done >=
- runtime->period_size) {
- dev->adev.capture_transfer_done -=
- runtime->period_size;
- period_elapsed = 1;
- }
-
- snd_pcm_stream_unlock(substream);
- }
- if (period_elapsed)
- snd_pcm_period_elapsed(substream);
- }
- urb->status = 0;
-
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status < 0) {
- em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
- status);
- }
- return;
-}
-
-static int em28xx_init_audio_isoc(struct em28xx *dev)
-{
- int i, errCode;
- const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
- EM28XX_AUDIO_MAX_PACKET_SIZE;
-
- dprintk("Starting isoc transfers\n");
-
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- struct urb *urb;
- int j, k;
-
- dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
- if (!dev->adev.transfer_buffer[i])
- return -ENOMEM;
-
- memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
- urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
- if (!urb) {
- em28xx_errdev("usb_alloc_urb failed!\n");
- for (j = 0; j < i; j++) {
- usb_free_urb(dev->adev.urb[j]);
- kfree(dev->adev.transfer_buffer[j]);
- }
- return -ENOMEM;
- }
-
- urb->dev = dev->udev;
- urb->context = dev;
- 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;
- urb->complete = em28xx_audio_isocirq;
- urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
- urb->transfer_buffer_length = sb_size;
-
- for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
- j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- EM28XX_AUDIO_MAX_PACKET_SIZE;
- }
- dev->adev.urb[i] = urb;
- }
-
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
- if (errCode) {
- em28xx_errdev("submit of audio urb failed\n");
- em28xx_deinit_isoc_audio(dev);
- atomic_set(&dev->stream_started, 0);
- return errCode;
- }
-
- }
-
- return 0;
-}
-
-static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
- size_t size)
-{
- struct snd_pcm_runtime *runtime = subs->runtime;
-
- dprintk("Allocating vbuffer\n");
- if (runtime->dma_area) {
- if (runtime->dma_bytes > size)
- return 0;
-
- vfree(runtime->dma_area);
- }
- runtime->dma_area = vmalloc(size);
- if (!runtime->dma_area)
- return -ENOMEM;
-
- runtime->dma_bytes = size;
-
- return 0;
-}
-
-static struct snd_pcm_hardware snd_em28xx_hw_capture = {
- .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_MMAP_VALID,
-
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
-
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
- .period_bytes_min = 64, /* 12544/2, */
- .period_bytes_max = 12544,
- .periods_min = 2,
- .periods_max = 98, /* 12544, */
-};
-
-static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
-{
- struct em28xx *dev = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret = 0;
-
- dprintk("opening device and trying to acquire exclusive lock\n");
-
- if (!dev) {
- em28xx_err("BUG: em28xx can't find device struct."
- " Can't proceed with open\n");
- return -ENODEV;
- }
-
- runtime->hw = snd_em28xx_hw_capture;
- if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
- if (dev->audio_ifnum)
- dev->alt = 1;
- else
- dev->alt = 7;
-
- dprintk("changing alternate number on interface %d to %d\n",
- dev->audio_ifnum, dev->alt);
- usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
-
- /* Sets volume, mute, etc */
- dev->mute = 0;
- mutex_lock(&dev->lock);
- ret = em28xx_audio_analog_set(dev);
- if (ret < 0)
- goto err;
-
- dev->adev.users++;
- mutex_unlock(&dev->lock);
- }
-
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- dev->adev.capture_pcm_substream = substream;
- runtime->private_data = dev;
-
- return 0;
-err:
- mutex_unlock(&dev->lock);
-
- em28xx_err("Error while configuring em28xx mixer\n");
- return ret;
-}
-
-static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
-{
- struct em28xx *dev = snd_pcm_substream_chip(substream);
-
- dprintk("closing device\n");
-
- dev->mute = 1;
- mutex_lock(&dev->lock);
- dev->adev.users--;
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
- }
-
- em28xx_audio_analog_set(dev);
- if (substream->runtime->dma_area) {
- dprintk("freeing\n");
- vfree(substream->runtime->dma_area);
- substream->runtime->dma_area = NULL;
- }
- mutex_unlock(&dev->lock);
-
- return 0;
-}
-
-static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int ret;
-
- dprintk("Setting capture parameters\n");
-
- ret = snd_pcm_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0)
- return ret;
-#if 0
- /* TODO: set up em28xx audio chip to deliver the correct audio format,
- current default is 48000hz multiplexed => 96000hz mono
- which shouldn't matter since analogue TV only supports mono */
- unsigned int channels, rate, format;
-
- format = params_format(hw_params);
- rate = params_rate(hw_params);
- channels = params_channels(hw_params);
-#endif
-
- return 0;
-}
-
-static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
-{
- struct em28xx *dev = snd_pcm_substream_chip(substream);
-
- dprintk("Stop capture, if needed\n");
-
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
- }
-
- return 0;
-}
-
-static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
-{
- struct em28xx *dev = snd_pcm_substream_chip(substream);
-
- dev->adev.hwptr_done_capture = 0;
- dev->adev.capture_transfer_done = 0;
-
- return 0;
-}
-
-static void audio_trigger(struct work_struct *work)
-{
- struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
-
- if (atomic_read(&dev->stream_started)) {
- dprintk("starting capture");
- em28xx_init_audio_isoc(dev);
- } else {
- dprintk("stopping capture");
- em28xx_deinit_isoc_audio(dev);
- }
-}
-
-static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct em28xx *dev = snd_pcm_substream_chip(substream);
- int retval = 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(&dev->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(&dev->stream_started, 0);
- break;
- default:
- retval = -EINVAL;
- }
- schedule_work(&dev->wq_trigger);
- return retval;
-}
-
-static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
- *substream)
-{
- unsigned long flags;
- struct em28xx *dev;
- snd_pcm_uframes_t hwptr_done;
-
- dev = snd_pcm_substream_chip(substream);
- spin_lock_irqsave(&dev->adev.slock, flags);
- hwptr_done = dev->adev.hwptr_done_capture;
- spin_unlock_irqrestore(&dev->adev.slock, flags);
-
- return hwptr_done;
-}
-
-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);
-}
-
-/*
- * AC97 volume control support
- */
-static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *info)
-{
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 2;
- info->value.integer.min = 0;
- info->value.integer.max = 0x1f;
-
- return 0;
-}
-
-static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- struct em28xx *dev = snd_kcontrol_chip(kcontrol);
- u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
- (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
- int rc;
-
- mutex_lock(&dev->lock);
- rc = em28xx_read_ac97(dev, kcontrol->private_value);
- if (rc < 0)
- goto err;
-
- val |= rc & 0x8000; /* Preserve the mute flag */
-
- rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
- if (rc < 0)
- goto err;
-
- dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
- (val & 0x8000) ? "muted " : "",
- 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
- val, (int)kcontrol->private_value);
-
-err:
- mutex_unlock(&dev->lock);
- return rc;
-}
-
-static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- struct em28xx *dev = snd_kcontrol_chip(kcontrol);
- int val;
-
- mutex_lock(&dev->lock);
- val = em28xx_read_ac97(dev, kcontrol->private_value);
- mutex_unlock(&dev->lock);
- if (val < 0)
- return val;
-
- dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
- (val & 0x8000) ? "muted " : "",
- 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
- val, (int)kcontrol->private_value);
-
- value->value.integer.value[0] = 0x1f - (val & 0x1f);
- value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
-
- return 0;
-}
-
-static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- struct em28xx *dev = snd_kcontrol_chip(kcontrol);
- u16 val = value->value.integer.value[0];
- int rc;
-
- mutex_lock(&dev->lock);
- rc = em28xx_read_ac97(dev, kcontrol->private_value);
- if (rc < 0)
- goto err;
-
- if (val)
- rc &= 0x1f1f;
- else
- rc |= 0x8000;
-
- rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
- if (rc < 0)
- goto err;
-
- dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
- (val & 0x8000) ? "muted " : "",
- 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
- val, (int)kcontrol->private_value);
-
-err:
- mutex_unlock(&dev->lock);
- return rc;
-}
-
-static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- struct em28xx *dev = snd_kcontrol_chip(kcontrol);
- int val;
-
- mutex_lock(&dev->lock);
- val = em28xx_read_ac97(dev, kcontrol->private_value);
- mutex_unlock(&dev->lock);
- if (val < 0)
- return val;
-
- if (val & 0x8000)
- value->value.integer.value[0] = 0;
- else
- value->value.integer.value[0] = 1;
-
- dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
- (val & 0x8000) ? "muted " : "",
- 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
- val, (int)kcontrol->private_value);
-
- return 0;
-}
-
-static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
-
-static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
- char *name, int id)
-{
- int err;
- char ctl_name[44];
- struct snd_kcontrol *kctl;
- struct snd_kcontrol_new tmp;
-
- memset (&tmp, 0, sizeof(tmp));
- tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- tmp.private_value = id,
- tmp.name = ctl_name,
-
- /* Add Mute Control */
- sprintf(ctl_name, "%s Switch", name);
- tmp.get = em28xx_vol_get_mute;
- tmp.put = em28xx_vol_put_mute;
- tmp.info = snd_ctl_boolean_mono_info;
- kctl = snd_ctl_new1(&tmp, dev);
- err = snd_ctl_add(card, kctl);
- if (err < 0)
- return err;
- dprintk("Added control %s for ac97 volume control 0x%04x\n",
- ctl_name, id);
-
- memset (&tmp, 0, sizeof(tmp));
- tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- tmp.private_value = id,
- tmp.name = ctl_name,
-
- /* Add Volume Control */
- sprintf(ctl_name, "%s Volume", name);
- tmp.get = em28xx_vol_get;
- tmp.put = em28xx_vol_put;
- tmp.info = em28xx_vol_info;
- tmp.tlv.p = em28xx_db_scale,
- kctl = snd_ctl_new1(&tmp, dev);
- err = snd_ctl_add(card, kctl);
- if (err < 0)
- return err;
- dprintk("Added control %s for ac97 volume control 0x%04x\n",
- ctl_name, id);
-
- return 0;
-}
-
-/*
- * register/unregister code and data
- */
-static struct snd_pcm_ops snd_em28xx_pcm_capture = {
- .open = snd_em28xx_capture_open,
- .close = snd_em28xx_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_em28xx_hw_capture_params,
- .hw_free = snd_em28xx_hw_capture_free,
- .prepare = snd_em28xx_prepare,
- .trigger = snd_em28xx_capture_trigger,
- .pointer = snd_em28xx_capture_pointer,
- .page = snd_pcm_get_vmalloc_page,
-};
-
-static int em28xx_audio_init(struct em28xx *dev)
-{
- struct em28xx_audio *adev = &dev->adev;
- struct snd_pcm *pcm;
- struct snd_card *card;
- static int devnr;
- int err;
-
- if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
- /* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module or
- doesn't have analog audio support at all) */
- return 0;
- }
-
- printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
- printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
- "Rechberger\n");
- printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
-
- err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
- &card);
- if (err < 0)
- return err;
-
- spin_lock_init(&adev->slock);
- err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
- pcm->info_flags = 0;
- pcm->private_data = dev;
- strcpy(pcm->name, "Empia 28xx Capture");
-
- snd_card_set_dev(card, &dev->udev->dev);
- strcpy(card->driver, "Em28xx-Audio");
- strcpy(card->shortname, "Em28xx Audio");
- strcpy(card->longname, "Empia Em28xx Audio");
-
- INIT_WORK(&dev->wq_trigger, audio_trigger);
-
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
- em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
- em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
- em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
- em28xx_cvol_new(card, dev, "CD", AC97_CD);
- em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
- em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
-
- em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
- em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
- em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
- em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
- em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
- }
-
- err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
- adev->sndcard = card;
- adev->udev = dev->udev;
-
- return 0;
-}
-
-static int em28xx_audio_fini(struct em28xx *dev)
-{
- if (dev == NULL)
- return 0;
-
- if (dev->has_alsa_audio != 1) {
- /* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module or
- doesn't have analog audio support at all) */
- return 0;
- }
-
- if (dev->adev.sndcard) {
- snd_card_free(dev->adev.sndcard);
- dev->adev.sndcard = NULL;
- }
-
- return 0;
-}
-
-static struct em28xx_ops audio_ops = {
- .id = EM28XX_AUDIO,
- .name = "Em28xx Audio Extension",
- .init = em28xx_audio_init,
- .fini = em28xx_audio_fini,
-};
-
-static int __init em28xx_alsa_register(void)
-{
- return em28xx_register_extension(&audio_ops);
-}
-
-static void __exit em28xx_alsa_unregister(void)
-{
- em28xx_unregister_extension(&audio_ops);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Audio driver");
-
-module_init(em28xx_alsa_register);
-module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
deleted file mode 100644
index de2cb20ad2cc..000000000000
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ /dev/null
@@ -1,1264 +0,0 @@
-/*
- em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
-
- 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/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <sound/ac97_codec.h>
-#include <media/v4l2-common.h>
-
-#include "em28xx.h"
-
-/* #define ENABLE_DEBUG_ISOC_FRAMES */
-
-static unsigned int core_debug;
-module_param(core_debug, int, 0644);
-MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
-
-#define em28xx_coredbg(fmt, arg...) do {\
- if (core_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-static unsigned int reg_debug;
-module_param(reg_debug, int, 0644);
-MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
-
-#define em28xx_regdbg(fmt, arg...) do {\
- if (reg_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-static int alt;
-module_param(alt, int, 0644);
-MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-static unsigned int disable_vbi;
-module_param(disable_vbi, int, 0644);
-MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-
-/* FIXME */
-#define em28xx_isocdbg(fmt, arg...) do {\
- if (core_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-/*
- * em28xx_read_reg_req()
- * reads data from the usb device specifying bRequest
- */
-int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
- char *buf, int len)
-{
- int ret;
- int pipe = usb_rcvctrlpipe(dev->udev, 0);
-
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
-
- if (len > URB_MAX_CTRL_SIZE)
- return -EINVAL;
-
- if (reg_debug) {
- printk(KERN_DEBUG "(pipe 0x%08x): "
- "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
- pipe,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8);
- }
-
- mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, pipe, req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, dev->urb_buf, len, HZ);
- if (ret < 0) {
- if (reg_debug)
- printk(" failed!\n");
- mutex_unlock(&dev->ctrl_urb_lock);
- return ret;
- }
-
- if (len)
- memcpy(buf, dev->urb_buf, len);
-
- mutex_unlock(&dev->ctrl_urb_lock);
-
- if (reg_debug) {
- int byte;
-
- printk("<<<");
- for (byte = 0; byte < len; byte++)
- printk(" %02x", (unsigned char)buf[byte]);
- printk("\n");
- }
-
- return ret;
-}
-
-/*
- * em28xx_read_reg_req()
- * reads data from the usb device specifying bRequest
- */
-int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
-{
- int ret;
- u8 val;
-
- ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
- if (ret < 0)
- return ret;
-
- return val;
-}
-
-int em28xx_read_reg(struct em28xx *dev, u16 reg)
-{
- return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
-}
-EXPORT_SYMBOL_GPL(em28xx_read_reg);
-
-/*
- * em28xx_write_regs_req()
- * sends data to the usb device, specifying bRequest
- */
-int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
- int len)
-{
- int ret;
- int pipe = usb_sndctrlpipe(dev->udev, 0);
-
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
-
- if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
- return -EINVAL;
-
- if (reg_debug) {
- int byte;
-
- printk(KERN_DEBUG "(pipe 0x%08x): "
- "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
- pipe,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8);
-
- for (byte = 0; byte < len; byte++)
- printk(" %02x", (unsigned char)buf[byte]);
- printk("\n");
- }
-
- mutex_lock(&dev->ctrl_urb_lock);
- memcpy(dev->urb_buf, buf, len);
- ret = usb_control_msg(dev->udev, pipe, req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, dev->urb_buf, len, HZ);
- mutex_unlock(&dev->ctrl_urb_lock);
-
- if (dev->wait_after_write)
- msleep(dev->wait_after_write);
-
- return ret;
-}
-
-int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
-{
- int rc;
-
- rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
-
- /* Stores GPO/GPIO values at the cache, if changed
- Only write values should be stored, since input on a GPIO
- register will return the input bits.
- Not sure what happens on reading GPO register.
- */
- if (rc >= 0) {
- if (reg == dev->reg_gpo_num)
- dev->reg_gpo = buf[0];
- else if (reg == dev->reg_gpio_num)
- dev->reg_gpio = buf[0];
- }
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(em28xx_write_regs);
-
-/* Write a single register */
-int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
-{
- return em28xx_write_regs(dev, reg, &val, 1);
-}
-EXPORT_SYMBOL_GPL(em28xx_write_reg);
-
-/*
- * em28xx_write_reg_bits()
- * sets only some bits (specified by bitmask) of a register, by first reading
- * the actual value
- */
-int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- u8 bitmask)
-{
- int oldval;
- u8 newval;
-
- /* Uses cache for gpo/gpio registers */
- if (reg == dev->reg_gpo_num)
- oldval = dev->reg_gpo;
- else if (reg == dev->reg_gpio_num)
- oldval = dev->reg_gpio;
- else
- oldval = em28xx_read_reg(dev, reg);
-
- if (oldval < 0)
- return oldval;
-
- newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
-
- return em28xx_write_regs(dev, reg, &newval, 1);
-}
-EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
-
-/*
- * em28xx_is_ac97_ready()
- * Checks if ac97 is ready
- */
-static int em28xx_is_ac97_ready(struct em28xx *dev)
-{
- int ret, i;
-
- /* Wait up to 50 ms for AC97 command to complete */
- for (i = 0; i < 10; i++, msleep(5)) {
- ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
- if (ret < 0)
- return ret;
-
- if (!(ret & 0x01))
- return 0;
- }
-
- em28xx_warn("AC97 command still being executed: not handled properly!\n");
- return -EBUSY;
-}
-
-/*
- * em28xx_read_ac97()
- * write a 16 bit value to the specified AC97 address (LSB first!)
- */
-int em28xx_read_ac97(struct em28xx *dev, u8 reg)
-{
- int ret;
- u8 addr = (reg & 0x7f) | 0x80;
- u16 val;
-
- ret = em28xx_is_ac97_ready(dev);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
- if (ret < 0)
- return ret;
-
- ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
- (u8 *)&val, sizeof(val));
-
- if (ret < 0)
- return ret;
- return le16_to_cpu(val);
-}
-EXPORT_SYMBOL_GPL(em28xx_read_ac97);
-
-/*
- * em28xx_write_ac97()
- * write a 16 bit value to the specified AC97 address (LSB first!)
- */
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
-{
- int ret;
- u8 addr = reg & 0x7f;
- __le16 value;
-
- value = cpu_to_le16(val);
-
- ret = em28xx_is_ac97_ready(dev);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(em28xx_write_ac97);
-
-struct em28xx_vol_itable {
- enum em28xx_amux mux;
- u8 reg;
-};
-
-static struct em28xx_vol_itable inputs[] = {
- { EM28XX_AMUX_VIDEO, AC97_VIDEO },
- { EM28XX_AMUX_LINE_IN, AC97_LINE },
- { EM28XX_AMUX_PHONE, AC97_PHONE },
- { EM28XX_AMUX_MIC, AC97_MIC },
- { EM28XX_AMUX_CD, AC97_CD },
- { EM28XX_AMUX_AUX, AC97_AUX },
- { EM28XX_AMUX_PCM_OUT, AC97_PCM },
-};
-
-static int set_ac97_input(struct em28xx *dev)
-{
- int ret, i;
- enum em28xx_amux amux = dev->ctl_ainput;
-
- /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
- em28xx should point to LINE IN, while AC97 should use VIDEO
- */
- if (amux == EM28XX_AMUX_VIDEO2)
- amux = EM28XX_AMUX_VIDEO;
-
- /* Mute all entres but the one that were selected */
- for (i = 0; i < ARRAY_SIZE(inputs); i++) {
- if (amux == inputs[i].mux)
- ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
- else
- ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
-
- if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- inputs[i].reg);
- }
- return 0;
-}
-
-static int em28xx_set_audio_source(struct em28xx *dev)
-{
- int ret;
- u8 input;
-
- if (dev->board.is_em2800) {
- if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
- input = EM2800_AUDIO_SRC_TUNER;
- else
- input = EM2800_AUDIO_SRC_LINE;
-
- ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
- if (ret < 0)
- return ret;
- }
-
- if (dev->board.has_msp34xx)
- input = EM28XX_AUDIO_SRC_TUNER;
- else {
- switch (dev->ctl_ainput) {
- case EM28XX_AMUX_VIDEO:
- input = EM28XX_AUDIO_SRC_TUNER;
- break;
- default:
- input = EM28XX_AUDIO_SRC_LINE;
- break;
- }
- }
-
- if (dev->board.mute_gpio && dev->mute)
- em28xx_gpio_set(dev, dev->board.mute_gpio);
- else
- em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
-
- ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
- if (ret < 0)
- return ret;
- msleep(5);
-
- switch (dev->audio_mode.ac97) {
- case EM28XX_NO_AC97:
- break;
- default:
- ret = set_ac97_input(dev);
- }
-
- return ret;
-}
-
-struct em28xx_vol_otable {
- enum em28xx_aout mux;
- u8 reg;
-};
-
-static const struct em28xx_vol_otable outputs[] = {
- { EM28XX_AOUT_MASTER, AC97_MASTER },
- { EM28XX_AOUT_LINE, AC97_HEADPHONE },
- { EM28XX_AOUT_MONO, AC97_MASTER_MONO },
- { EM28XX_AOUT_LFE, AC97_CENTER_LFE_MASTER },
- { EM28XX_AOUT_SURR, AC97_SURROUND_MASTER },
-};
-
-int em28xx_audio_analog_set(struct em28xx *dev)
-{
- int ret, i;
- u8 xclk;
-
- if (!dev->audio_mode.has_audio)
- return 0;
-
- /* It is assumed that all devices use master volume for output.
- It would be possible to use also line output.
- */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- /* Mute all outputs */
- for (i = 0; i < ARRAY_SIZE(outputs); i++) {
- ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
- if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
- }
- }
-
- xclk = dev->board.xclk & 0x7f;
- if (!dev->mute)
- xclk |= EM28XX_XCLK_AUDIO_UNMUTE;
-
- ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
- if (ret < 0)
- return ret;
- msleep(10);
-
- /* Selects the proper audio input */
- ret = em28xx_set_audio_source(dev);
-
- /* Sets volume */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- int vol;
-
- em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200);
- em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031);
- em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80);
-
- /* LSB: left channel - both channels with the same level */
- vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
-
- /* Mute device, if needed */
- if (dev->mute)
- vol |= 0x8000;
-
- /* Sets volume */
- for (i = 0; i < ARRAY_SIZE(outputs); i++) {
- if (dev->ctl_aoutput & outputs[i].mux)
- ret = em28xx_write_ac97(dev, outputs[i].reg,
- vol);
- if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
- }
-
- if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
- int sel = ac97_return_record_select(dev->ctl_aoutput);
-
- /* Use the same input for both left and right
- channels */
- sel |= (sel << 8);
-
- em28xx_write_ac97(dev, AC97_REC_SEL, sel);
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
-
-int em28xx_audio_setup(struct em28xx *dev)
-{
- int vid1, vid2, feat, cfg;
- u32 vid;
-
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
- || dev->chip_id == CHIP_ID_EM28174) {
- /* Digital only device - don't load any alsa module */
- dev->audio_mode.has_audio = false;
- dev->has_audio_class = false;
- dev->has_alsa_audio = false;
- return 0;
- }
-
- dev->audio_mode.has_audio = true;
-
- /* See how this device is configured */
- cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
- em28xx_info("Config register raw data: 0x%02x\n", cfg);
- if (cfg < 0) {
- /* Register read error? */
- cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
- /* The device doesn't have vendor audio at all */
- dev->has_alsa_audio = false;
- dev->audio_mode.has_audio = false;
- return 0;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
- em28xx_info("I2S Audio (3 sample rates)\n");
- dev->audio_mode.i2s_3rates = 1;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
- em28xx_info("I2S Audio (5 sample rates)\n");
- dev->audio_mode.i2s_5rates = 1;
- }
-
- if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
- /* Skip the code that does AC97 vendor detection */
- dev->audio_mode.ac97 = EM28XX_NO_AC97;
- goto init_audio;
- }
-
- dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
-
- vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
- if (vid1 < 0) {
- /*
- * Device likely doesn't support AC97
- * Note: (some) em2800 devices without eeprom reports 0x91 on
- * CHIPCFG register, even not having an AC97 chip
- */
- em28xx_warn("AC97 chip type couldn't be determined\n");
- dev->audio_mode.ac97 = EM28XX_NO_AC97;
- dev->has_alsa_audio = false;
- dev->audio_mode.has_audio = false;
- goto init_audio;
- }
-
- vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
- if (vid2 < 0)
- goto init_audio;
-
- vid = vid1 << 16 | vid2;
-
- dev->audio_mode.ac97_vendor_id = vid;
- em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
-
- feat = em28xx_read_ac97(dev, AC97_RESET);
- if (feat < 0)
- goto init_audio;
-
- dev->audio_mode.ac97_feat = feat;
- em28xx_warn("AC97 features = 0x%04x\n", feat);
-
- /* Try to identify what audio processor we have */
- 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;
-
-init_audio:
- /* Reports detected AC97 processor */
- switch (dev->audio_mode.ac97) {
- case EM28XX_NO_AC97:
- em28xx_info("No AC97 audio processor\n");
- break;
- case EM28XX_AC97_EM202:
- em28xx_info("Empia 202 AC97 audio processor detected\n");
- break;
- case EM28XX_AC97_SIGMATEL:
- em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
- dev->audio_mode.ac97_vendor_id & 0xff);
- break;
- case EM28XX_AC97_OTHER:
- em28xx_warn("Unknown AC97 audio processor detected!\n");
- break;
- default:
- break;
- }
-
- return em28xx_audio_analog_set(dev);
-}
-EXPORT_SYMBOL_GPL(em28xx_audio_setup);
-
-int em28xx_colorlevels_set_default(struct em28xx *dev)
-{
- em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */
- em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */
- em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
- em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
-
- em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
- em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
- return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
-}
-
-int em28xx_capture_start(struct em28xx *dev, int start)
-{
- int rc;
-
- if (dev->chip_id == CHIP_ID_EM2874 ||
- dev->chip_id == CHIP_ID_EM2884 ||
- dev->chip_id == CHIP_ID_EM28174) {
- /* The Transport Stream Enable Register moved in em2874 */
- if (!start) {
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- 0x00,
- EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
- /* Enable Transport Stream */
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
-
- /* FIXME: which is the best order? */
- /* video registers are sampled by VREF */
- rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
- start ? 0x10 : 0x00, 0x10);
- if (rc < 0)
- return rc;
-
- if (!start) {
- /* disable video capture */
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
- return rc;
- }
-
- if (dev->board.is_webcam)
- rc = em28xx_write_reg(dev, 0x13, 0x0c);
-
- /* enable video capture */
- rc = em28xx_write_reg(dev, 0x48, 0x00);
-
- if (dev->mode == EM28XX_ANALOG_MODE)
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
- else
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
-
- msleep(6);
-
- return rc;
-}
-
-int em28xx_vbi_supported(struct em28xx *dev)
-{
- /* Modprobe option to manually disable */
- if (disable_vbi == 1)
- return 0;
-
- if (dev->chip_id == CHIP_ID_EM2860 ||
- dev->chip_id == CHIP_ID_EM2883)
- return 1;
-
- /* Version of em28xx that does not support VBI */
- return 0;
-}
-
-int em28xx_set_outfmt(struct em28xx *dev)
-{
- int ret;
- u8 vinctrl;
-
- ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
- dev->format->reg | 0x20, 0xff);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
- if (ret < 0)
- return ret;
-
- vinctrl = dev->vinctl;
- if (em28xx_vbi_supported(dev) == 1) {
- vinctrl |= EM28XX_VINCTRL_VBI_RAW;
- em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
- em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
- }
- }
-
- return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
-}
-
-static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
- u8 ymin, u8 ymax)
-{
- em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
- xmin, ymin, xmax, ymax);
-
- em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
- em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
- em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
- return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
-}
-
-static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height)
-{
- u8 cwidth = width;
- u8 cheight = height;
- u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
-
- em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
- (width | (overflow & 2) << 7),
- (height | (overflow & 1) << 8));
-
- em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
- em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
- em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
- em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
- return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
-}
-
-static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
-{
- u8 mode;
- /* the em2800 scaler only supports scaling down to 50% */
-
- if (dev->board.is_em2800) {
- mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
- } else {
- u8 buf[2];
-
- buf[0] = h;
- buf[1] = h >> 8;
- em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
-
- buf[0] = v;
- buf[1] = v >> 8;
- em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
- /* it seems that both H and V scalers must be active
- to work correctly */
- mode = (h || v) ? 0x30 : 0x00;
- }
- return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
-}
-
-/* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
-{
- int width, height;
- width = norm_maxw(dev);
- height = norm_maxh(dev);
-
- /* Properly setup VBI */
- dev->vbi_width = 720;
- if (dev->norm & V4L2_STD_525_60)
- dev->vbi_height = 12;
- else
- dev->vbi_height = 18;
-
- if (!dev->progressive)
- height >>= norm_maxh(dev);
-
- em28xx_set_outfmt(dev);
-
-
- em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
-
- /* If we don't set the start position to 2 in VBI mode, we end up
- with line 20/21 being YUYV encoded instead of being in 8-bit
- greyscale. The core of the issue is that line 21 (and line 23 for
- PAL WSS) are inside of active video region, and as a result they
- get the pixelformatting associated with that area. So by cropping
- it out, we end up with the same format as the rest of the VBI
- region */
- if (em28xx_vbi_supported(dev) == 1)
- em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2);
- else
- em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
-
- return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
-}
-
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode, prev_alt = dev->alt;
- int i;
- unsigned int min_pkt_size = dev->width * 2 + 4;
-
- /*
- * alt = 0 is used only for control messages, so, only values
- * greater than 0 can be used for streaming.
- */
- if (alt && alt < dev->num_alt) {
- em28xx_coredbg("alternate forced to %d\n", dev->alt);
- dev->alt = alt;
- goto set_alt;
- }
-
- /* When image size is bigger than a certain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
- */
- if (dev->width * 2 * dev->height > 720 * 240 * 2)
- min_pkt_size *= 2;
-
- for (i = 0; i < dev->num_alt; i++) {
- /* stop when the selected alt setting offers enough bandwidth */
- if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
- dev->alt = i;
- break;
- /* otherwise make sure that we end up with the maximum bandwidth
- because the min_pkt_size equation might be wrong...
- */
- } else if (dev->alt_max_pkt_size[i] >
- dev->alt_max_pkt_size[dev->alt])
- dev->alt = i;
- }
-
-set_alt:
- if (dev->alt != prev_alt) {
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
- }
- }
- return 0;
-}
-
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
-{
- int rc = 0;
-
- if (!gpio)
- return rc;
-
- if (dev->mode != EM28XX_SUSPEND) {
- em28xx_write_reg(dev, 0x48, 0x00);
- if (dev->mode == EM28XX_ANALOG_MODE)
- em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
- else
- em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
- msleep(6);
- }
-
- /* Send GPIO reset sequences specified at board entry */
- while (gpio->sleep >= 0) {
- if (gpio->reg >= 0) {
- rc = em28xx_write_reg_bits(dev,
- gpio->reg,
- gpio->val,
- gpio->mask);
- if (rc < 0)
- return rc;
- }
- if (gpio->sleep > 0)
- msleep(gpio->sleep);
-
- gpio++;
- }
- return rc;
-}
-EXPORT_SYMBOL_GPL(em28xx_gpio_set);
-
-int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
-{
- if (dev->mode == set_mode)
- return 0;
-
- if (set_mode == EM28XX_SUSPEND) {
- dev->mode = set_mode;
-
- /* FIXME: add suspend support for ac97 */
-
- return em28xx_gpio_set(dev, dev->board.suspend_gpio);
- }
-
- dev->mode = set_mode;
-
- if (dev->mode == EM28XX_DIGITAL_MODE)
- return em28xx_gpio_set(dev, dev->board.dvb_gpio);
- else
- return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
-}
-EXPORT_SYMBOL_GPL(em28xx_set_mode);
-
-/* ------------------------------------------------------------------
- URB control
- ------------------------------------------------------------------*/
-
-/*
- * IRQ callback, called by URB callback
- */
-static void em28xx_irq_callback(struct urb *urb)
-{
- struct em28xx *dev = urb->context;
- int i;
-
- switch (urb->status) {
- case 0: /* success */
- case -ETIMEDOUT: /* NAK */
- break;
- case -ECONNRESET: /* kill */
- case -ENOENT:
- case -ESHUTDOWN:
- return;
- default: /* error */
- em28xx_isocdbg("urb completition error %d.\n", urb->status);
- break;
- }
-
- /* Copy data from URB */
- spin_lock(&dev->slock);
- dev->isoc_ctl.isoc_copy(dev, urb);
- spin_unlock(&dev->slock);
-
- /* Reset urb buffers */
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
- urb->status = 0;
-
- urb->status = usb_submit_urb(urb, GFP_ATOMIC);
- if (urb->status) {
- em28xx_isocdbg("urb resubmit failed (error=%i)\n",
- urb->status);
- }
-}
-
-/*
- * Stop and Deallocate URBs
- */
-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 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;
-
- 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 (isoc_bufs->transfer_buffer[i]) {
- usb_free_coherent(dev->udev,
- urb->transfer_buffer_length,
- isoc_bufs->transfer_buffer[i],
- urb->transfer_dma);
- }
- usb_free_urb(urb);
- isoc_bufs->urb[i] = NULL;
- }
- isoc_bufs->transfer_buffer[i] = NULL;
- }
-
- kfree(isoc_bufs->urb);
- kfree(isoc_bufs->transfer_buffer);
-
- 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);
-
-/*
- * Stop URBs
- */
-void em28xx_stop_urbs(struct em28xx *dev)
-{
- int i;
- struct urb *urb;
- struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
-
- em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
-
- 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);
- }
- }
-
- em28xx_capture_start(dev, 0);
-}
-EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
-
-/*
- * Allocate URBs
- */
-int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
- int max_packets, int num_bufs, int max_pkt_size)
-{
- struct em28xx_usb_isoc_bufs *isoc_bufs;
- int i;
- int sb_size, pipe;
- struct urb *urb;
- int j, k;
-
- 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, mode);
-
- isoc_bufs->num_bufs = num_bufs;
-
- 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;
- }
-
- 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(isoc_bufs->urb);
- return -ENOMEM;
- }
-
- 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 = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
-
- /* allocate urbs and transfer buffers */
- 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, mode);
- return -ENOMEM;
- }
- isoc_bufs->urb[i] = urb;
-
- isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- 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, mode);
- return -ENOMEM;
- }
- 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,
- mode == EM28XX_ANALOG_MODE ?
- EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
-
- usb_fill_int_urb(urb, dev->udev, pipe,
- isoc_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev, 1);
-
- 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 < isoc_bufs->num_packets; j++) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- 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 < 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, mode);
- return rc;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(em28xx_init_isoc);
-
-/*
- * em28xx_wake_i2c()
- * configure i2c attached devices
- */
-void em28xx_wake_i2c(struct em28xx *dev)
-{
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
- INPUT(dev->ctl_input)->vmux, 0, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-}
-
-/*
- * Device control list
- */
-
-static LIST_HEAD(em28xx_devlist);
-static DEFINE_MUTEX(em28xx_devlist_mutex);
-
-/*
- * Extension interface
- */
-
-static LIST_HEAD(em28xx_extension_devlist);
-
-int em28xx_register_extension(struct em28xx_ops *ops)
-{
- struct em28xx *dev = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- list_add_tail(&ops->next, &em28xx_extension_devlist);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->init(dev);
- }
- mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
- return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
-
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
- struct em28xx *dev = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->fini(dev);
- }
- list_del(&ops->next);
- mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
-
-void em28xx_init_extension(struct em28xx *dev)
-{
- const struct em28xx_ops *ops = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- list_add_tail(&dev->devlist, &em28xx_devlist);
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->init)
- ops->init(dev);
- }
- mutex_unlock(&em28xx_devlist_mutex);
-}
-
-void em28xx_close_extension(struct em28xx *dev)
-{
- const struct em28xx_ops *ops = NULL;
-
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->fini)
- ops->fini(dev);
- }
- list_del(&dev->devlist);
- mutex_unlock(&em28xx_devlist_mutex);
-}
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
deleted file mode 100644
index 50f5f4fc2148..000000000000
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ /dev/null
@@ -1,2606 +0,0 @@
-/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
- video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
-
- Some parts based on SN9C10x PC Camera Controllers GPL driver made
- by Luca Risolia <luca.risolia@studio.unibo.it>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the 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/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitmap.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include "em28xx.h"
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/msp3400.h>
-#include <media/tuner.h>
-
-#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
- "Markus Rechberger <mrechberger@gmail.com>, " \
- "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
- "Sascha Sommer <saschasommer@freenet.de>"
-
-#define DRIVER_DESC "Empia em28xx based USB video device driver"
-
-#define EM28XX_VERSION "0.1.3"
-
-#define em28xx_videodbg(fmt, arg...) do {\
- if (video_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
-#define em28xx_isocdbg(fmt, arg...) \
-do {\
- if (isoc_debug) { \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); \
- } \
- } while (0)
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(EM28XX_VERSION);
-
-static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(video_nr, int, NULL, 0444);
-module_param_array(vbi_nr, int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
-MODULE_PARM_DESC(video_nr, "video device numbers");
-MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
-
-static unsigned int video_debug;
-module_param(video_debug, int, 0644);
-MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
-
-/* supported video standards */
-static struct em28xx_fmt format[] = {
- {
- .name = "16 bpp YUY2, 4:2:2, packed",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- .reg = EM28XX_OUTFMT_YUV422_Y0UY1V,
- }, {
- .name = "16 bpp RGB 565, LE",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .depth = 16,
- .reg = EM28XX_OUTFMT_RGB_16_656,
- }, {
- .name = "8 bpp Bayer BGBG..GRGR",
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .depth = 8,
- .reg = EM28XX_OUTFMT_RGB_8_BGBG,
- }, {
- .name = "8 bpp Bayer GRGR..BGBG",
- .fourcc = V4L2_PIX_FMT_SGRBG8,
- .depth = 8,
- .reg = EM28XX_OUTFMT_RGB_8_GRGR,
- }, {
- .name = "8 bpp Bayer GBGB..RGRG",
- .fourcc = V4L2_PIX_FMT_SGBRG8,
- .depth = 8,
- .reg = EM28XX_OUTFMT_RGB_8_GBGB,
- }, {
- .name = "12 bpp YUV411",
- .fourcc = V4L2_PIX_FMT_YUV411P,
- .depth = 12,
- .reg = EM28XX_OUTFMT_YUV411,
- },
-};
-
-/* supported controls */
-/* Common to all boards */
-static struct v4l2_queryctrl ac97_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0x0,
- .maximum = 0x1f,
- .step = 0x1,
- .default_value = 0x1f,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- }
-};
-
-/* ------------------------------------------------------------------
- DMA and thread functions
- ------------------------------------------------------------------*/
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf)
-{
- /* Advice that buffer was filled */
- em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- dev->isoc_ctl.vid_buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-static inline void vbi_buffer_filled(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf)
-{
- /* Advice that buffer was filled */
- em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- dev->isoc_ctl.vbi_buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-/*
- * Identify the buffer header type and properly handles
- */
-static void em28xx_copy_video(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
-{
- void *fieldstart, *startwrite, *startread;
- int linesdone, currlinedone, offset, lencopy, remain;
- int bytesperline = dev->width << 1;
-
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
-
- startread = p;
- remain = len;
-
- if (dev->progressive)
- fieldstart = outp;
- else {
- /* Interlaces two half frames */
- if (buf->top_field)
- fieldstart = outp;
- else
- fieldstart = outp + bytesperline;
- }
-
- linesdone = dma_q->pos / bytesperline;
- currlinedone = dma_q->pos % bytesperline;
-
- if (dev->progressive)
- offset = linesdone * bytesperline + currlinedone;
- else
- offset = linesdone * bytesperline * 2 + currlinedone;
-
- startwrite = fieldstart + offset;
- lencopy = bytesperline - currlinedone;
- lencopy = lencopy > remain ? remain : lencopy;
-
- if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
- em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
- ((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- remain = (char *)outp + buf->vb.size - (char *)startwrite;
- lencopy = remain;
- }
- if (lencopy <= 0)
- return;
- memcpy(startwrite, startread, lencopy);
-
- remain -= lencopy;
-
- while (remain > 0) {
- startwrite += lencopy + bytesperline;
- startread += lencopy;
- if (bytesperline > remain)
- lencopy = remain;
- else
- lencopy = bytesperline;
-
- if ((char *)startwrite + lencopy > (char *)outp +
- buf->vb.size) {
- em28xx_isocdbg("Overflow of %zi bytes past buffer end"
- "(2)\n",
- ((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- lencopy = remain = (char *)outp + buf->vb.size -
- (char *)startwrite;
- }
- if (lencopy <= 0)
- break;
-
- memcpy(startwrite, startread, lencopy);
-
- remain -= lencopy;
- }
-
- dma_q->pos += len;
-}
-
-static void em28xx_copy_vbi(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
-{
- void *startwrite, *startread;
- int offset;
- int bytesperline;
-
- if (dev == NULL) {
- em28xx_isocdbg("dev is null\n");
- return;
- }
- bytesperline = dev->vbi_width;
-
- if (dma_q == NULL) {
- em28xx_isocdbg("dma_q is null\n");
- return;
- }
- if (buf == NULL) {
- return;
- }
- if (p == NULL) {
- em28xx_isocdbg("p is null\n");
- return;
- }
- if (outp == NULL) {
- em28xx_isocdbg("outp is null\n");
- return;
- }
-
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
-
- startread = p;
-
- startwrite = outp + dma_q->pos;
- offset = dma_q->pos;
-
- /* Make sure the bottom field populates the second half of the frame */
- if (buf->top_field == 0) {
- startwrite += bytesperline * dev->vbi_height;
- offset += bytesperline * dev->vbi_height;
- }
-
- memcpy(startwrite, startread, len);
- dma_q->pos += len;
-}
-
-static inline void print_err_status(struct em28xx *dev,
- int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronuously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronuously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
- } else {
- em28xx_isocdbg("URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer **buf)
-{
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
- char *outp;
-
- if (list_empty(&dma_q->active)) {
- em28xx_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.vid_buf = NULL;
- *buf = NULL;
- return;
- }
-
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
-
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0, (*buf)->vb.size);
-
- dev->isoc_ctl.vid_buf = *buf;
-
- return;
-}
-
-/*
- * video-buf generic routine to get the next available VBI buffer
- */
-static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer **buf)
-{
- struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
- char *outp;
-
- if (list_empty(&dma_q->active)) {
- em28xx_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.vbi_buf = NULL;
- *buf = NULL;
- return;
- }
-
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0x00, (*buf)->vb.size);
-
- dev->isoc_ctl.vbi_buf = *buf;
-
- return;
-}
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
-{
- struct em28xx_buffer *buf;
- struct em28xx_dmaqueue *dma_q = &dev->vidq;
- unsigned char *outp = NULL;
- int i, len = 0, rc = 1;
- unsigned char *p;
-
- if (!dev)
- return 0;
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- buf = dev->isoc_ctl.vid_buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
-
- len = urb->iso_frame_desc[i].actual_length - 4;
-
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- /* em28xx_isocdbg("packet %d is empty",i); - spammy */
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
-
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- /* FIXME: incomplete buffer checks where removed to make
- logic simpler. Impacts of those changes should be evaluated
- */
- if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
- em28xx_isocdbg("VBI HEADER!!!\n");
- /* FIXME: Should add vbi copy */
- continue;
- }
- if (p[0] == 0x22 && p[1] == 0x5a) {
- em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
- len, (p[2] & 1) ? "odd" : "even");
-
- if (dev->progressive || !(p[2] & 1)) {
- if (buf != NULL)
- buffer_filled(dev, dma_q, buf);
- get_next_buf(dma_q, &buf);
- if (buf == NULL)
- outp = NULL;
- else
- outp = videobuf_to_vmalloc(&buf->vb);
- }
-
- if (buf != NULL) {
- if (p[2] & 1)
- buf->top_field = 0;
- else
- buf->top_field = 1;
- }
-
- dma_q->pos = 0;
- }
- if (buf != NULL) {
- if (p[0] != 0x88 && p[0] != 0x22) {
- em28xx_isocdbg("frame is not complete\n");
- len += 4;
- } else {
- p += 4;
- }
- em28xx_copy_video(dev, dma_q, buf, p, outp, len);
- }
- }
- return rc;
-}
-
-/* Version of isoc handler that takes into account a mixture of video and
- VBI data */
-static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
-{
- struct em28xx_buffer *buf, *vbi_buf;
- struct em28xx_dmaqueue *dma_q = &dev->vidq;
- struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
- unsigned char *outp = NULL;
- unsigned char *vbioutp = NULL;
- int i, len = 0, rc = 1;
- unsigned char *p;
- int vbi_size;
-
- if (!dev)
- return 0;
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- buf = dev->isoc_ctl.vid_buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- vbi_buf = dev->isoc_ctl.vbi_buf;
- if (vbi_buf != NULL)
- vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
-
- len = urb->iso_frame_desc[i].actual_length;
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- /* em28xx_isocdbg("packet %d is empty",i); - spammy */
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
-
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- /* capture type 0 = vbi start
- capture type 1 = video start
- capture type 2 = video in progress */
- if (p[0] == 0x33 && p[1] == 0x95) {
- dev->capture_type = 0;
- dev->vbi_read = 0;
- em28xx_isocdbg("VBI START HEADER!!!\n");
- dev->cur_field = p[2];
- p += 4;
- len -= 4;
- } else if (p[0] == 0x88 && p[1] == 0x88 &&
- p[2] == 0x88 && p[3] == 0x88) {
- /* continuation */
- p += 4;
- len -= 4;
- } else if (p[0] == 0x22 && p[1] == 0x5a) {
- /* start video */
- p += 4;
- len -= 4;
- }
-
- vbi_size = dev->vbi_width * dev->vbi_height;
-
- if (dev->capture_type == 0) {
- if (dev->vbi_read >= vbi_size) {
- /* We've already read all the VBI data, so
- treat the rest as video */
- em28xx_isocdbg("dev->vbi_read > vbi_size\n");
- } else if ((dev->vbi_read + len) < vbi_size) {
- /* This entire frame is VBI data */
- if (dev->vbi_read == 0 &&
- (!(dev->cur_field & 1))) {
- /* Brand new frame */
- if (vbi_buf != NULL)
- vbi_buffer_filled(dev,
- vbi_dma_q,
- vbi_buf);
- vbi_get_next_buf(vbi_dma_q, &vbi_buf);
- if (vbi_buf == NULL)
- vbioutp = NULL;
- else
- vbioutp = videobuf_to_vmalloc(
- &vbi_buf->vb);
- }
-
- if (dev->vbi_read == 0) {
- vbi_dma_q->pos = 0;
- if (vbi_buf != NULL) {
- if (dev->cur_field & 1)
- vbi_buf->top_field = 0;
- else
- vbi_buf->top_field = 1;
- }
- }
-
- dev->vbi_read += len;
- em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
- vbioutp, len);
- } else {
- /* Some of this frame is VBI data and some is
- video data */
- int vbi_data_len = vbi_size - dev->vbi_read;
- dev->vbi_read += vbi_data_len;
- em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
- vbioutp, vbi_data_len);
- dev->capture_type = 1;
- p += vbi_data_len;
- len -= vbi_data_len;
- }
- }
-
- if (dev->capture_type == 1) {
- dev->capture_type = 2;
- if (dev->progressive || !(dev->cur_field & 1)) {
- if (buf != NULL)
- buffer_filled(dev, dma_q, buf);
- get_next_buf(dma_q, &buf);
- if (buf == NULL)
- outp = NULL;
- else
- outp = videobuf_to_vmalloc(&buf->vb);
- }
- if (buf != NULL) {
- if (dev->cur_field & 1)
- buf->top_field = 0;
- else
- buf->top_field = 1;
- }
-
- dma_q->pos = 0;
- }
-
- if (buf != NULL && dev->capture_type == 2) {
- if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
- p[2] == 0x88 && p[3] == 0x88) {
- p += 4;
- len -= 4;
- }
- if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
- em28xx_isocdbg("Video frame %d, len=%i, %s\n",
- p[2], len, (p[2] & 1) ?
- "odd" : "even");
- p += 4;
- len -= 4;
- }
-
- if (len > 0)
- em28xx_copy_video(dev, dma_q, buf, p, outp,
- len);
- }
- }
- return rc;
-}
-
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
-{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- struct v4l2_frequency f;
-
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
- >> 3;
-
- if (0 == *count)
- *count = EM28XX_DEF_BUF;
-
- if (*count < EM28XX_MIN_BUF)
- *count = EM28XX_MIN_BUF;
-
- /* Ask tuner to go to analog or radio mode */
- memset(&f, 0, sizeof(f));
- f.frequency = dev->ctl_freq;
- f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-
- return 0;
-}
-
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
-{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.vid_buf == buf)
- dev->isoc_ctl.vid_buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
- struct em28xx *dev = fh->dev;
- int rc = 0, urb_init = 0;
-
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
- + 7) >> 3;
-
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- 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_ANALOG_MODE,
- EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS,
- dev->max_pkt_size,
- em28xx_isoc_copy_vbi);
- else
- rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
- EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS,
- dev->max_pkt_size,
- em28xx_isoc_copy);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct em28xx_buffer *buf = container_of(vb,
- struct em28xx_buffer,
- vb);
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- struct em28xx_dmaqueue *vidq = &dev->vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct em28xx_buffer *buf = container_of(vb,
- struct em28xx_buffer,
- vb);
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = (struct em28xx *)fh->dev;
-
- em28xx_isocdbg("em28xx: called buffer_release\n");
-
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops em28xx_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/********************* v4l2 interface **************************************/
-
-static void video_mux(struct em28xx *dev, int index)
-{
- dev->ctl_input = index;
- dev->ctl_ainput = INPUT(index)->amux;
- dev->ctl_aoutput = INPUT(index)->aout;
-
- if (!dev->ctl_aoutput)
- dev->ctl_aoutput = EM28XX_AOUT_MASTER;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
- INPUT(index)->vmux, 0, 0);
-
- if (dev->board.has_msp34xx) {
- if (dev->i2s_speed) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
- s_i2s_clock_freq, dev->i2s_speed);
- }
- /* Note: this is msp3400 specific */
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
- dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
- }
-
- if (dev->board.adecoder != EM28XX_NOADECODER) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
- dev->ctl_ainput, dev->ctl_aoutput, 0);
- }
-
- em28xx_audio_analog_set(dev);
-}
-
-/* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh, unsigned int bit)
-{
- struct em28xx *dev = fh->dev;
-
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- if (dev->resources & bit) {
- /* no, someone else uses it */
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- em28xx_videodbg("res: get %d\n", bit);
- return 1;
-}
-
-static int res_check(struct em28xx_fh *fh, unsigned int bit)
-{
- return fh->resources & bit;
-}
-
-static int res_locked(struct em28xx *dev, unsigned int bit)
-{
- return dev->resources & bit;
-}
-
-static void res_free(struct em28xx_fh *fh, unsigned int bits)
-{
- struct em28xx *dev = fh->dev;
-
- BUG_ON((fh->resources & bits) != bits);
-
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- em28xx_videodbg("res: put %d\n", bits);
-}
-
-static int get_ressource(struct em28xx_fh *fh)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return EM28XX_RESOURCE_VIDEO;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return EM28XX_RESOURCE_VBI;
- default:
- BUG();
- return 0;
- }
-}
-
-/*
- * ac97_queryctrl()
- * return the ac97 supported controls
- */
-static int ac97_queryctrl(struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
- if (qc->id && qc->id == ac97_qctrl[i].id) {
- memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
-
- /* Control is not ac97 related */
- return 1;
-}
-
-/*
- * ac97_get_ctrl()
- * return the current values for ac97 mute and volume
- */
-static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->mute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = dev->volume;
- return 0;
- default:
- /* Control is not ac97 related */
- return 1;
- }
-}
-
-/*
- * ac97_set_ctrl()
- * set values for ac97 mute and volume
- */
-static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
- if (ctrl->id == ac97_qctrl[i].id)
- goto handle;
-
- /* Announce that hasn't handle it */
- return 1;
-
-handle:
- if (ctrl->value < ac97_qctrl[i].minimum ||
- ctrl->value > ac97_qctrl[i].maximum)
- return -ERANGE;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- dev->mute = ctrl->value;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- dev->volume = ctrl->value;
- break;
- }
-
- return em28xx_audio_analog_set(dev);
-}
-
-static int check_dev(struct em28xx *dev)
-{
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_errdev("v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_errdev("v4l2 ioctl: device is misconfigured; "
- "close and open it again\n");
- return -EIO;
- }
- return 0;
-}
-
-static void get_scale(struct em28xx *dev,
- unsigned int width, unsigned int height,
- unsigned int *hscale, unsigned int *vscale)
-{
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
-
- *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
- if (*hscale >= 0x4000)
- *hscale = 0x3fff;
-
- *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
- if (*vscale >= 0x4000)
- *vscale = 0x3fff;
-}
-
-/* ------------------------------------------------------------------
- IOCTL vidioc handling
- ------------------------------------------------------------------*/
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
- if (dev->progressive)
- f->fmt.pix.field = V4L2_FIELD_NONE;
- else
- f->fmt.pix.field = dev->interlaced ?
- V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
- return 0;
-}
-
-static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(format); i++)
- if (format[i].fourcc == fourcc)
- return &format[i];
-
- return NULL;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- unsigned int width = f->fmt.pix.width;
- unsigned int height = f->fmt.pix.height;
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
- unsigned int hscale, vscale;
- struct em28xx_fmt *fmt;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt) {
- em28xx_videodbg("Fourcc format (%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- if (dev->board.is_em2800) {
- /* 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 */
- v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
- 1, 0);
- }
-
- get_scale(dev, width, height, &hscale, &vscale);
-
- width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
- height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
- f->fmt.pix.width = width;
- f->fmt.pix.height = height;
- f->fmt.pix.pixelformat = fmt->fourcc;
- f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- if (dev->progressive)
- f->fmt.pix.field = V4L2_FIELD_NONE;
- else
- f->fmt.pix.field = dev->interlaced ?
- V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
-
- return 0;
-}
-
-static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
- unsigned width, unsigned height)
-{
- struct em28xx_fmt *fmt;
-
- fmt = format_by_fourcc(fourcc);
- if (!fmt)
- return -EINVAL;
-
- dev->format = fmt;
- dev->width = width;
- dev->height = height;
-
- /* set new image size */
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
- em28xx_set_alternate(dev);
- em28xx_resolution_set(dev);
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- em28xx_errdev("%s queue busy\n", __func__);
- return -EBUSY;
- }
-
- return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
- f->fmt.pix.width, f->fmt.pix.height);
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- *norm = dev->norm;
-
- return 0;
-}
-
-static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
-
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- struct v4l2_format f;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- dev->norm = *norm;
-
- /* Adjusts width/height, if needed */
- f.fmt.pix.width = dev->width;
- f.fmt.pix.height = dev->height;
- vidioc_try_fmt_vid_cap(file, priv, &f);
-
- /* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
- em28xx_resolution_set(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
-
- return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
- struct v4l2_streamparm *p)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc = 0;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (dev->board.is_webcam)
- rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
- video, g_parm, p);
- else
- v4l2_video_std_frame_period(dev->norm,
- &p->parm.capture.timeperframe);
-
- return rc;
-}
-
-static int vidioc_s_parm(struct file *file, void *priv,
- struct v4l2_streamparm *p)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- if (!dev->board.is_webcam)
- return -EINVAL;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
-}
-
-static const char *iname[] = {
- [EM28XX_VMUX_COMPOSITE1] = "Composite1",
- [EM28XX_VMUX_COMPOSITE2] = "Composite2",
- [EM28XX_VMUX_COMPOSITE3] = "Composite3",
- [EM28XX_VMUX_COMPOSITE4] = "Composite4",
- [EM28XX_VMUX_SVIDEO] = "S-Video",
- [EM28XX_VMUX_TELEVISION] = "Television",
- [EM28XX_VMUX_CABLE] = "Cable TV",
- [EM28XX_VMUX_DVB] = "DVB",
- [EM28XX_VMUX_DEBUG] = "for debug only",
-};
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- unsigned int n;
-
- n = i->index;
- if (n >= MAX_EM28XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
-
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- strcpy(i->name, iname[INPUT(n)->type]);
-
- if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
- (EM28XX_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- i->std = dev->vdev->tvnorms;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- *i = dev->ctl_input;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (i >= MAX_EM28XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(i)->type)
- return -EINVAL;
-
- video_mux(dev, i);
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
- switch (a->index) {
- case EM28XX_AMUX_VIDEO:
- strcpy(a->name, "Television");
- break;
- case EM28XX_AMUX_LINE_IN:
- strcpy(a->name, "Line In");
- break;
- case EM28XX_AMUX_VIDEO2:
- strcpy(a->name, "Television alt");
- break;
- case EM28XX_AMUX_PHONE:
- strcpy(a->name, "Phone");
- break;
- case EM28XX_AMUX_MIC:
- strcpy(a->name, "Mic");
- break;
- case EM28XX_AMUX_CD:
- strcpy(a->name, "CD");
- break;
- case EM28XX_AMUX_AUX:
- strcpy(a->name, "Aux");
- break;
- case EM28XX_AMUX_PCM_OUT:
- strcpy(a->name, "PCM");
- break;
- default:
- return -EINVAL;
- }
-
- a->index = dev->ctl_ainput;
- a->capability = V4L2_AUDCAP_STEREO;
-
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
-
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
- if (a->index >= MAX_EM28XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(a->index)->type)
- return -EINVAL;
-
- dev->ctl_ainput = INPUT(a->index)->amux;
- dev->ctl_aoutput = INPUT(a->index)->aout;
-
- if (!dev->ctl_aoutput)
- dev->ctl_aoutput = EM28XX_AOUT_MASTER;
-
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int id = qc->id;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- memset(qc, 0, sizeof(*qc));
-
- qc->id = id;
-
- /* enumerate AC97 controls */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- rc = ac97_queryctrl(qc);
- if (!rc)
- return 0;
- }
-
- /* enumerate V4L2 device controls */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
-
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-/*
- * FIXME: This is an indirect way to check if a control exists at a
- * subdev. Instead of that hack, maybe the better would be to change all
- * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
- */
-static int check_subdev_ctrl(struct em28xx *dev, int id)
-{
- struct v4l2_queryctrl qc;
-
- memset(&qc, 0, sizeof(qc));
- qc.id = id;
-
- /* enumerate V4L2 device controls */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
-
- if (qc.type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
- rc = 0;
-
- /* Set an AC97 control */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
- rc = ac97_get_ctrl(dev, ctrl);
- else
- rc = 1;
-
- /* It were not an AC97 control. Sends it to the v4l2 dev interface */
- if (rc == 1) {
- if (check_subdev_ctrl(dev, ctrl->id))
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- rc = 0;
- }
-
- return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- /* Set an AC97 control */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
- rc = ac97_set_ctrl(dev, ctrl);
- else
- rc = 1;
-
- /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
- if (rc == 1) {
- rc = check_subdev_ctrl(dev, ctrl->id);
- if (!rc)
- v4l2_device_call_all(&dev->v4l2_dev, 0,
- core, s_ctrl, ctrl);
- /*
- * In the case of non-AC97 volume controls, we still need
- * to do some setups at em28xx, in order to mute/unmute
- * and to adjust audio volume. However, the value ranges
- * should be checked by the corresponding V4L subdriver.
- */
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- dev->mute = ctrl->value;
- rc = em28xx_audio_analog_set(dev);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- dev->volume = ctrl->value;
- rc = em28xx_audio_analog_set(dev);
- }
- }
- return (rc < 0) ? rc : 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != t->index)
- return -EINVAL;
-
- strcpy(t->name, "Tuner");
- t->type = V4L2_TUNER_ANALOG_TV;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != t->index)
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (0 != f->tuner)
- return -EINVAL;
-
- 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;
-
- dev->ctl_freq = f->frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int em28xx_reg_len(int reg)
-{
- switch (reg) {
- case EM28XX_R40_AC97LSB:
- case EM28XX_R30_HSCALELOW:
- case EM28XX_R32_VSCALELOW:
- return 2;
- default:
- return 1;
- }
-}
-
-static int vidioc_g_chip_ident(struct file *file, void *priv,
- struct v4l2_dbg_chip_ident *chip)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
-
- return 0;
-}
-
-
-static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int ret;
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_AC97:
- ret = em28xx_read_ac97(dev, reg->reg);
- if (ret < 0)
- return ret;
-
- reg->val = ret;
- reg->size = 1;
- return 0;
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
- /* Match host */
- reg->size = em28xx_reg_len(reg->reg);
- if (reg->size == 1) {
- ret = em28xx_read_reg(dev, reg->reg);
-
- if (ret < 0)
- return ret;
-
- reg->val = ret;
- } else {
- __le16 val = 0;
- ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
- reg->reg, (char *)&val, 2);
- if (ret < 0)
- return ret;
-
- reg->val = le16_to_cpu(val);
- }
-
- return 0;
-}
-
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- __le16 buf;
-
- switch (reg->match.type) {
- case V4L2_CHIP_MATCH_AC97:
- return em28xx_write_ac97(dev, reg->reg, reg->val);
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* TODO: is this correct? */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
- return 0;
- default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- }
-
- /* Match host */
- buf = cpu_to_le16(reg->val);
-
- return em28xx_write_regs(dev, reg->reg, (char *)&buf,
- em28xx_reg_len(reg->reg));
-}
-#endif
-
-
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc = -EINVAL;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (unlikely(type != fh->type))
- return -EINVAL;
-
- em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (unlikely(!res_get(fh, get_ressource(fh))))
- return -EBUSY;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vidq);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vbiq);
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
- return -EINVAL;
- if (type != fh->type)
- return -EINVAL;
-
- em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
- }
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (res_check(fh, EM28XX_RESOURCE_VBI)) {
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
- }
- }
-
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
- strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities =
- V4L2_CAP_SLICED_VBI_CAPTURE |
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-
- if (dev->vbi_dev)
- cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
-
- if (dev->audio_mode.has_audio)
- cap->capabilities |= V4L2_CAP_AUDIO;
-
- if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (unlikely(f->index >= ARRAY_SIZE(format)))
- return -EINVAL;
-
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
- f->pixelformat = format[f->index].fourcc;
-
- return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *priv,
- struct v4l2_frmsizeenum *fsize)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- struct em28xx_fmt *fmt;
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
-
- fmt = format_by_fourcc(fsize->pixel_format);
- if (!fmt) {
- em28xx_videodbg("Fourcc format (%08x) invalid.\n",
- fsize->pixel_format);
- return -EINVAL;
- }
-
- if (dev->board.is_em2800) {
- if (fsize->index > 1)
- return -EINVAL;
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = maxw / (1 + fsize->index);
- fsize->discrete.height = maxh / (1 + fsize->index);
- return 0;
- }
-
- if (fsize->index != 0)
- return -EINVAL;
-
- /* Report a continuous range */
- fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise.min_width = 48;
- fsize->stepwise.min_height = 32;
- fsize->stepwise.max_width = maxw;
- fsize->stepwise.max_height = maxh;
- fsize->stepwise.step_width = 1;
- fsize->stepwise.step_height = 1;
- return 0;
-}
-
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- f->fmt.sliced.service_set = 0;
- v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- rc = -EINVAL;
-
- return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- return -EINVAL;
-
- return 0;
-}
-
-/* RAW VBI ioctls */
-
-static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *format)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- format->fmt.vbi.samples_per_line = dev->vbi_width;
- format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 0;
- format->fmt.vbi.flags = 0;
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
-
- /* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- format->fmt.vbi.start[0] = 6;
- format->fmt.vbi.start[1] = 318;
- }
-
- return 0;
-}
-
-static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *format)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- format->fmt.vbi.samples_per_line = dev->vbi_width;
- format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 0;
- format->fmt.vbi.flags = 0;
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
-
- /* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- format->fmt.vbi.start[0] = 6;
- format->fmt.vbi.start[1] = 318;
- }
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_reqbufs(&fh->vb_vidq, rb);
- else
- return videobuf_reqbufs(&fh->vb_vbiq, rb);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_querybuf(&fh->vb_vidq, b);
- else {
- /* FIXME: I'm not sure yet whether this is a bug in zvbi or
- the videobuf framework, but we probably shouldn't be
- returning a buffer larger than that which was asked for.
- At a minimum, it causes a crash in zvbi since it does
- a memcpy based on the source buffer length */
- int result = videobuf_querybuf(&fh->vb_vbiq, b);
- b->length = dev->vbi_width * dev->vbi_height * 2;
-
- return result;
- }
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_qbuf(&fh->vb_vidq, b);
- else
- return videobuf_qbuf(&fh->vb_vbiq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
- O_NONBLOCK);
- else
- return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
- O_NONBLOCK);
-}
-
-/* ----------------------------------------------------------- */
-/* RADIO ESPECIFIC IOCTLS */
-/* ----------------------------------------------------------- */
-
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-
- strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
- strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
-static int radio_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-
- if (unlikely(t->index > 0))
- return -EINVAL;
-
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
- return 0;
-}
-
-static int radio_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-
- if (0 != t->index)
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int radio_s_audio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- if (qc->id < V4L2_CID_BASE ||
- qc->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
- if (qc->id && qc->id == ac97_qctrl[i].id) {
- memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-/*
- * em28xx_v4l2_open()
- * inits the device and starts isoc transfer
- */
-static int em28xx_v4l2_open(struct file *filp)
-{
- int errCode = 0, radio = 0;
- struct video_device *vdev = video_devdata(filp);
- struct em28xx *dev = video_drvdata(filp);
- enum v4l2_buf_type fh_type = 0;
- struct em28xx_fh *fh;
- enum v4l2_field field;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- em28xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- dev->users);
-
-
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
- if (!fh) {
- em28xx_errdev("em28xx-video.c: Out of memory?!\n");
- return -ENOMEM;
- }
- fh->dev = dev;
- fh->radio = radio;
- fh->type = fh_type;
- filp->private_data = fh;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
- em28xx_set_alternate(dev);
- em28xx_resolution_set(dev);
-
- /* Needed, since GPIO might have disabled power of
- some i2c device
- */
- em28xx_wake_i2c(dev);
-
- }
- if (fh->radio) {
- em28xx_videodbg("video_open: setting radio device\n");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
- }
-
- dev->users++;
-
- if (dev->progressive)
- field = V4L2_FIELD_NONE;
- else
- field = V4L2_FIELD_INTERLACED;
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
- sizeof(struct em28xx_buffer), fh, &dev->lock);
-
- videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct em28xx_buffer), fh, &dev->lock);
-
- return errCode;
-}
-
-/*
- * em28xx_realease_resources()
- * unregisters the v4l2,i2c and usb devices
- * called when the device gets disconected or at module unload
-*/
-void em28xx_release_analog_resources(struct em28xx *dev)
-{
-
- /*FIXME: I2C IR should be disconnected */
-
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
- if (dev->vbi_dev) {
- em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
- }
- if (dev->vdev) {
- em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
- }
-}
-
-/*
- * em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2
- * calls and ioctls
- */
-static int em28xx_v4l2_close(struct file *filp)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int errCode;
-
- em28xx_videodbg("users=%d\n", dev->users);
-
- if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
- videobuf_stop(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
- }
-
- if (res_check(fh, EM28XX_RESOURCE_VBI)) {
- videobuf_stop(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
- }
-
- if (dev->users == 1) {
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_release_resources(dev);
- kfree(dev->alt_max_pkt_size);
- kfree(dev);
- kfree(fh);
- return 0;
- }
-
- /* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
-
- /* do this before setting alternate! */
- em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
- em28xx_set_mode(dev, EM28XX_SUSPEND);
-
- /* set alternate 0 */
- dev->alt = 0;
- em28xx_videodbg("setting alternate 0\n");
- errCode = usb_set_interface(dev->udev, 0, 0);
- if (errCode < 0) {
- em28xx_errdev("cannot change alternate number to "
- "0 (error=%i)\n", errCode);
- }
- }
-
- videobuf_mmap_free(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vbiq);
- kfree(fh);
- dev->users--;
- return 0;
-}
-
-/*
- * em28xx_v4l2_read()
- * will allocate buffers when called for the first time
- */
-static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- /* FIXME: read() is not prepared to allow changing the video
- resolution while streaming. Seems a bug at em28xx_set_fmt
- */
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
- return -EBUSY;
-
- return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
-
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VBI))
- return -EBUSY;
-
- return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
- return 0;
-}
-
-/*
- * em28xx_v4l2_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VBI))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
- }
-}
-
-/*
- * em28xx_v4l2_mmap()
- */
-static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
-
- em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- rc);
-
- return rc;
-}
-
-static const struct v4l2_file_operations em28xx_v4l_fops = {
- .owner = THIS_MODULE,
- .open = em28xx_v4l2_open,
- .release = em28xx_v4l2_close,
- .read = em28xx_v4l2_read,
- .poll = em28xx_v4l2_poll,
- .mmap = em28xx_v4l2_mmap,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_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_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
- .vidioc_enum_framesizes = vidioc_enum_framesizes,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
- .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_querystd = vidioc_querystd,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_parm = vidioc_g_parm,
- .vidioc_s_parm = vidioc_s_parm,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
-#endif
-};
-
-static const struct video_device em28xx_video_template = {
- .fops = &em28xx_v4l_fops,
- .release = video_device_release,
- .ioctl_ops = &video_ioctl_ops,
-
- .tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_PAL,
-};
-
-static const struct v4l2_file_operations radio_fops = {
- .owner = THIS_MODULE,
- .open = em28xx_v4l2_open,
- .release = em28xx_v4l2_close,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
- .vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
- .vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
-#endif
-};
-
-static struct video_device em28xx_radio_template = {
- .name = "em28xx-radio",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
-};
-
-/******************************** usb interface ******************************/
-
-
-
-static struct video_device *em28xx_vdev_init(struct em28xx *dev,
- const struct video_device *template,
- const char *type_name)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
- *vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
- vfd->debug = video_debug;
- vfd->lock = &dev->lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
-
- snprintf(vfd->name, sizeof(vfd->name), "%s %s",
- dev->name, type_name);
-
- video_set_drvdata(vfd, dev);
- return vfd;
-}
-
-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);
-
- /* set default norm */
- dev->norm = em28xx_video_template.current_norm;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
- dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-
- /* 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,
- maxw, norm_maxh(dev));
-
- video_mux(dev, 0);
-
- /* Audio defaults */
- dev->mute = 1;
- dev->volume = 0x1f;
-
-/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
- val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
- em28xx_write_reg(dev, EM28XX_R0F_XCLK,
- (EM28XX_XCLK_AUDIO_UNMUTE | val));
-
- em28xx_set_outfmt(dev);
- em28xx_colorlevels_set_default(dev);
- em28xx_compression_disable(dev);
-
- /* allocate and fill video video_device struct */
- dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
- if (!dev->vdev) {
- em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
- }
-
- /* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
- video_nr[dev->devno]);
- if (ret) {
- em28xx_errdev("unable to register video device (error=%i).\n",
- ret);
- return ret;
- }
-
- /* Allocate and fill vbi video_device struct */
- if (em28xx_vbi_supported(dev) == 1) {
- dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
- "vbi");
-
- /* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
- vbi_nr[dev->devno]);
- if (ret < 0) {
- em28xx_errdev("unable to register vbi device\n");
- return ret;
- }
- }
-
- if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
- dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
- em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
- }
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
- radio_nr[dev->devno]);
- if (ret < 0) {
- em28xx_errdev("can't register radio device\n");
- return ret;
- }
- em28xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
- }
-
- em28xx_info("V4L2 video device registered as %s\n",
- video_device_node_name(dev->vdev));
-
- if (dev->vbi_dev)
- em28xx_info("V4L2 VBI device registered as %s\n",
- video_device_node_name(dev->vbi_dev));
-
- return 0;
-}
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
deleted file mode 100644
index 777486f7cadb..000000000000
--- a/drivers/media/video/fsl-viu.c
+++ /dev/null
@@ -1,1673 +0,0 @@
-/*
- * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * Freescale VIU video driver
- *
- * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
- * Porting to 2.6.35 by DENX Software Engineering,
- * Anatolij Gustschin <agust@denx.de>
- *
- * 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/kernel.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/of_platform.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/videobuf-dma-contig.h>
-
-#define DRV_NAME "fsl_viu"
-#define VIU_VERSION "0.5.1"
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
-
-#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
-
-/* I2C address of video decoder chip is 0x4A */
-#define VIU_VIDEO_DECODER_ADDR 0x25
-
-/* supported controls */
-static struct v4l2_queryctrl viu_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 127,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 0x10,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 127,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 0x1,
- .default_value = 0,
- .flags = 0,
- }
-};
-
-static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
-
-static int info_level;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (level <= info_level) \
- printk(KERN_DEBUG "viu: " fmt , ## arg); \
- } while (0)
-
-/*
- * Basic structures
- */
-struct viu_fmt {
- char name[32];
- u32 fourcc; /* v4l2 format id */
- u32 pixelformat;
- int depth;
-};
-
-static struct viu_fmt formats[] = {
- {
- .name = "RGB-16 (5/B-6/G-5/R)",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .pixelformat = V4L2_PIX_FMT_RGB565,
- .depth = 16,
- }, {
- .name = "RGB-32 (A-R-G-B)",
- .fourcc = V4L2_PIX_FMT_RGB32,
- .pixelformat = V4L2_PIX_FMT_RGB32,
- .depth = 32,
- }
-};
-
-struct viu_dev;
-struct viu_buf;
-
-/* buffer for one video frame */
-struct viu_buf {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- struct viu_fmt *fmt;
-};
-
-struct viu_dmaqueue {
- struct viu_dev *dev;
- struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
-};
-
-struct viu_status {
- u32 field_irq;
- u32 vsync_irq;
- u32 hsync_irq;
- u32 vstart_irq;
- u32 dma_end_irq;
- u32 error_irq;
-};
-
-struct viu_reg {
- u32 status_cfg;
- u32 luminance;
- u32 chroma_r;
- u32 chroma_g;
- u32 chroma_b;
- u32 field_base_addr;
- u32 dma_inc;
- u32 picture_count;
- u32 req_alarm;
- u32 alpha;
-} __attribute__ ((packed));
-
-struct viu_dev {
- struct v4l2_device v4l2_dev;
- struct mutex lock;
- spinlock_t slock;
- int users;
-
- struct device *dev;
- /* various device info */
- struct video_device *vdev;
- struct viu_dmaqueue vidq;
- enum v4l2_field capfield;
- int field;
- int first;
- int dma_done;
-
- /* Hardware register area */
- struct viu_reg *vr;
-
- /* Interrupt vector */
- int irq;
- struct viu_status irqs;
-
- /* video overlay */
- struct v4l2_framebuffer ovbuf;
- struct viu_fmt *ovfmt;
- unsigned int ovenable;
- enum v4l2_field ovfield;
-
- /* crop */
- struct v4l2_rect crop_current;
-
- /* clock pointer */
- struct clk *clk;
-
- /* decoder */
- struct v4l2_subdev *decoder;
-
- v4l2_std_id std;
-};
-
-struct viu_fh {
- struct viu_dev *dev;
-
- /* video capture */
- struct videobuf_queue vb_vidq;
- spinlock_t vbq_lock; /* spinlock for the videobuf queue */
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip clips[1];
-
- /* video capture */
- struct viu_fmt *fmt;
- int width, height, sizeimage;
- enum v4l2_buf_type type;
-};
-
-static struct viu_reg reg_val;
-
-/*
- * Macro definitions of VIU registers
- */
-
-/* STATUS_CONFIG register */
-enum status_config {
- SOFT_RST = 1 << 0,
-
- ERR_MASK = 0x0f << 4, /* Error code mask */
- ERR_NO = 0x00, /* No error */
- ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
- ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
- ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
- ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
- ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
- ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
- ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
- ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
- ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
- ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
-
- INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
- INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
- INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
- INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
- INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
- INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
- INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
-
- INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */
- INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */
- INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */
- INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */
- INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */
- INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */
-
- DMA_ACT = 0x01 << 27, /* Enable DMA transfer */
- FIELD_NO = 0x01 << 28, /* Field number */
- DITHER_ON = 0x01 << 29, /* Dithering is on */
- ROUND_ON = 0x01 << 30, /* Round is on */
- MODE_32BIT = 0x01 << 31, /* Data in RGBa888,
- * 0 in RGB565
- */
-};
-
-#define norm_maxw() 720
-#define norm_maxh() 576
-
-#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
- INT_HSYNC_STATUS | INT_VSTART_STATUS | \
- INT_DMA_END_STATUS | INT_ERROR_STATUS)
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-static irqreturn_t viu_intr(int irq, void *dev_id);
-
-struct viu_fmt *format_by_fourcc(int fourcc)
-{
- int i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].pixelformat == fourcc)
- return formats + i;
- }
-
- dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
- return NULL;
-}
-
-void viu_start_dma(struct viu_dev *dev)
-{
- struct viu_reg *vr = dev->vr;
-
- dev->field = 0;
-
- /* Enable DMA operation */
- out_be32(&vr->status_cfg, SOFT_RST);
- out_be32(&vr->status_cfg, INT_FIELD_EN);
-}
-
-void viu_stop_dma(struct viu_dev *dev)
-{
- struct viu_reg *vr = dev->vr;
- int cnt = 100;
- u32 status_cfg;
-
- out_be32(&vr->status_cfg, 0);
-
- /* Clear pending interrupts */
- status_cfg = in_be32(&vr->status_cfg);
- if (status_cfg & 0x3f0000)
- out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
-
- if (status_cfg & DMA_ACT) {
- do {
- status_cfg = in_be32(&vr->status_cfg);
- if (status_cfg & INT_DMA_END_STATUS)
- break;
- } while (cnt--);
-
- if (cnt < 0) {
- /* timed out, issue soft reset */
- out_be32(&vr->status_cfg, SOFT_RST);
- out_be32(&vr->status_cfg, 0);
- } else {
- /* clear DMA_END and other pending irqs */
- out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
- }
- }
-
- dev->field = 0;
-}
-
-static int restart_video_queue(struct viu_dmaqueue *vidq)
-{
- struct viu_buf *buf, *prev;
-
- dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
- if (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
- dprintk(2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
-
- viu_stop_dma(vidq->dev);
-
- /* cancel all outstanding capture requests */
- list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- }
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- return 0;
- }
-
- prev = NULL;
- for (;;) {
- if (list_empty(&vidq->queued))
- return 0;
- buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
- if (prev == NULL) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue, &vidq->active);
-
- dprintk(1, "Restarting video dma\n");
- viu_stop_dma(vidq->dev);
- viu_start_dma(vidq->dev);
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2, "[%p/%d] restart_queue - first active\n",
- buf, buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(2, "[%p/%d] restart_queue - move to active\n",
- buf, buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
-}
-
-static void viu_vid_timeout(unsigned long data)
-{
- struct viu_dev *dev = (struct viu_dev *)data;
- struct viu_buf *buf;
- struct viu_dmaqueue *vidq = &dev->vidq;
-
- while (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
- }
-
- restart_video_queue(vidq);
-}
-
-/*
- * Videobuf operations
- */
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct viu_fh *fh = vq->priv_data;
-
- *size = fh->width * fh->height * fh->fmt->depth >> 3;
- if (*count == 0)
- *count = 32;
-
- while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
- (*count)--;
-
- dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
-{
- struct videobuf_buffer *vb = &buf->vb;
- void *vaddr = NULL;
-
- BUG_ON(in_interrupt());
-
- videobuf_waiton(vq, &buf->vb, 0, 0);
-
- if (vq->int_ops && vq->int_ops->vaddr)
- vaddr = vq->int_ops->vaddr(vb);
-
- if (vaddr)
- videobuf_dma_contig_free(vq, &buf->vb);
-
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
-{
- struct viu_reg *vr = dev->vr;
- int bpp;
-
- /* setup the DMA base address */
- reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
-
- dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
- buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
-
- /* interlace is on by default, set horizontal DMA increment */
- reg_val.status_cfg = 0;
- bpp = buf->fmt->depth >> 3;
- switch (bpp) {
- case 2:
- reg_val.status_cfg &= ~MODE_32BIT;
- reg_val.dma_inc = buf->vb.width * 2;
- break;
- case 4:
- reg_val.status_cfg |= MODE_32BIT;
- reg_val.dma_inc = buf->vb.width * 4;
- break;
- default:
- dprintk(0, "doesn't support color depth(%d)\n",
- bpp * 8);
- return -EINVAL;
- }
-
- /* setup picture_count register */
- reg_val.picture_count = (buf->vb.height / 2) << 16 |
- buf->vb.width;
-
- reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- dev->capfield = buf->vb.field;
-
- /* reset dma increment if needed */
- if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
- reg_val.dma_inc = 0;
-
- out_be32(&vr->dma_inc, reg_val.dma_inc);
- out_be32(&vr->picture_count, reg_val.picture_count);
- out_be32(&vr->field_base_addr, reg_val.field_base_addr);
- mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
- return 0;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct viu_fh *fh = vq->priv_data;
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- int rc;
-
- BUG_ON(fh->fmt == NULL);
-
- if (fh->width < 48 || fh->width > norm_maxw() ||
- fh->height < 32 || fh->height > norm_maxh())
- return -EINVAL;
- buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
- if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- }
-
- if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc != 0)
- goto fail;
-
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- buf->fmt = fh->fmt;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- struct viu_fh *fh = vq->priv_data;
- struct viu_dev *dev = fh->dev;
- struct viu_dmaqueue *vidq = &dev->vidq;
- struct viu_buf *prev;
-
- if (!list_empty(&vidq->queued)) {
- dprintk(1, "adding vb queue=0x%08lx\n",
- (unsigned long)&buf->vb.queue);
- dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
- vidq, &vidq->queued);
- dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
- dev, &vidq->queued, vidq->queued.next,
- vidq->queued.prev);
- list_add_tail(&buf->vb.queue, &vidq->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
- buf, buf->vb.i);
- } else if (list_empty(&vidq->active)) {
- dprintk(1, "adding vb active=0x%08lx\n",
- (unsigned long)&buf->vb.queue);
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2, "[%p/%d] buffer_queue - first active\n",
- buf, buf->vb.i);
-
- buffer_activate(dev, buf);
- } else {
- dprintk(1, "adding vb queue2=0x%08lx\n",
- (unsigned long)&buf->vb.queue);
- prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
- if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(2, "[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
- } else {
- list_add_tail(&buf->vb.queue, &vidq->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n",
- buf, buf->vb.i);
- }
- }
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- struct viu_fh *fh = vq->priv_data;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
-
- viu_stop_dma(dev);
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops viu_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/*
- * IOCTL vidioc handling
- */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- strcpy(cap->driver, "viu");
- strcpy(cap->card, "viu");
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_READWRITE;
- return 0;
-}
-
-static int vidioc_enum_fmt(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- int index = f->index;
-
- if (f->index > NUM_FORMATS)
- return -EINVAL;
-
- strlcpy(f->description, formats[index].name, sizeof(f->description));
- f->pixelformat = formats[index].fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
-
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->pixelformat;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage = fh->sizeimage;
- return 0;
-}
-
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fmt *fmt;
- enum v4l2_field field;
- unsigned int maxw, maxh;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt) {
- dprintk(1, "Fourcc format (0x%08x) invalid.",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- field = f->fmt.pix.field;
-
- if (field == V4L2_FIELD_ANY) {
- field = V4L2_FIELD_INTERLACED;
- } else if (field != V4L2_FIELD_INTERLACED) {
- dprintk(1, "Field type invalid.\n");
- return -EINVAL;
- }
-
- maxw = norm_maxw();
- maxh = norm_maxh();
-
- f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
-
- return 0;
-}
-
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
- int ret;
-
- ret = vidioc_try_fmt_cap(file, fh, f);
- if (ret < 0)
- return ret;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->sizeimage = f->fmt.pix.sizeimage;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
- dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
- return 0;
-}
-
-static int vidioc_g_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
-
- f->fmt.win = fh->win;
- return 0;
-}
-
-static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
-{
- enum v4l2_field field;
- int maxw, maxh;
-
- if (dev->ovbuf.base == NULL)
- return -EINVAL;
- if (dev->ovfmt == NULL)
- return -EINVAL;
- if (win->w.width < 48 || win->w.height < 32)
- return -EINVAL;
-
- field = win->field;
- maxw = dev->crop_current.width;
- maxh = dev->crop_current.height;
-
- if (field == V4L2_FIELD_ANY) {
- field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
- return 0;
-}
-
-inline void viu_activate_overlay(struct viu_reg *viu_reg)
-{
- struct viu_reg *vr = viu_reg;
-
- out_be32(&vr->field_base_addr, reg_val.field_base_addr);
- out_be32(&vr->dma_inc, reg_val.dma_inc);
- out_be32(&vr->picture_count, reg_val.picture_count);
-}
-
-static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
-{
- int bpp;
-
- dprintk(1, "%s %dx%d %s\n", __func__,
- fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
-
- reg_val.status_cfg = 0;
-
- /* setup window */
- reg_val.picture_count = (fh->win.w.height / 2) << 16 |
- fh->win.w.width;
-
- /* setup color depth and dma increment */
- bpp = dev->ovfmt->depth / 8;
- switch (bpp) {
- case 2:
- reg_val.status_cfg &= ~MODE_32BIT;
- reg_val.dma_inc = fh->win.w.width * 2;
- break;
- case 4:
- reg_val.status_cfg |= MODE_32BIT;
- reg_val.dma_inc = fh->win.w.width * 4;
- break;
- default:
- dprintk(0, "device doesn't support color depth(%d)\n",
- bpp * 8);
- return -EINVAL;
- }
-
- dev->ovfield = fh->win.field;
- if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
- reg_val.dma_inc = 0;
-
- reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
-
- /* setup the base address of the overlay buffer */
- reg_val.field_base_addr = (u32)dev->ovbuf.base;
-
- return 0;
-}
-
-static int vidioc_s_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
- unsigned long flags;
- int err;
-
- err = verify_preview(dev, &f->fmt.win);
- if (err)
- return err;
-
- fh->win = f->fmt.win;
-
- spin_lock_irqsave(&dev->slock, flags);
- viu_setup_preview(dev, fh);
- spin_unlock_irqrestore(&dev->slock, flags);
- return 0;
-}
-
-static int vidioc_try_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- return 0;
-}
-
-static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
- unsigned long flags;
-
- if (on) {
- spin_lock_irqsave(&dev->slock, flags);
- viu_activate_overlay(dev->vr);
- dev->ovenable = 1;
-
- /* start dma */
- viu_start_dma(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- } else {
- viu_stop_dma(dev);
- dev->ovenable = 0;
- }
-
- return 0;
-}
-
-int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
- struct v4l2_framebuffer *fb = arg;
-
- *fb = dev->ovbuf;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- return 0;
-}
-
-int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
- struct v4l2_framebuffer *fb = arg;
- struct viu_fmt *fmt;
-
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = format_by_fourcc(fb->fmt.pixelformat);
- if (fmt == NULL)
- return -EINVAL;
-
- /* ok, accept it */
- dev->ovbuf = *fb;
- dev->ovfmt = fmt;
- if (dev->ovbuf.fmt.bytesperline == 0) {
- dev->ovbuf.fmt.bytesperline =
- dev->ovbuf.fmt.width * fmt->depth / 8;
- }
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_reqbufs(&fh->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_querybuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_qbuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->vb_vidq, p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (fh->type != i)
- return -EINVAL;
-
- if (dev->ovenable)
- dev->ovenable = 0;
-
- viu_start_dma(fh->dev);
-
- return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct viu_fh *fh = priv;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (fh->type != i)
- return -EINVAL;
-
- viu_stop_dma(fh->dev);
-
- return videobuf_streamoff(&fh->vb_vidq);
-}
-
-#define decoder_call(viu, o, f, args...) \
- v4l2_subdev_call(viu->decoder, o, f, ##args)
-
-static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct viu_fh *fh = priv;
-
- decoder_call(fh->dev, video, querystd, std_id);
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
-{
- struct viu_fh *fh = priv;
-
- fh->dev->std = *id;
- decoder_call(fh->dev, core, s_std, *id);
- return 0;
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct viu_fh *fh = priv;
-
- *std_id = fh->dev->std;
- return 0;
-}
-
-/* only one input in this driver */
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- struct viu_fh *fh = priv;
-
- if (inp->index != 0)
- return -EINVAL;
-
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = fh->dev->vdev->tvnorms;
- strcpy(inp->name, "Camera");
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct viu_fh *fh = priv;
-
- if (i > 1)
- return -EINVAL;
-
- decoder_call(fh->dev, video, s_routing, i, 0, 0);
- return 0;
-}
-
-/* Controls */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
- if (qc->id && qc->id == viu_qctrl[i].id) {
- memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
- if (ctrl->id == viu_qctrl[i].id) {
- ctrl->value = qctl_regs[i];
- return 0;
- }
- }
- return -EINVAL;
-}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
- if (ctrl->id == viu_qctrl[i].id) {
- if (ctrl->value < viu_qctrl[i].minimum
- || ctrl->value > viu_qctrl[i].maximum)
- return -ERANGE;
- qctl_regs[i] = ctrl->value;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-inline void viu_activate_next_buf(struct viu_dev *dev,
- struct viu_dmaqueue *viuq)
-{
- struct viu_dmaqueue *vidq = viuq;
- struct viu_buf *buf;
-
- /* launch another DMA operation for an active/queued buffer */
- if (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf,
- vb.queue);
- dprintk(1, "start another queued buffer: 0x%p\n", buf);
- buffer_activate(dev, buf);
- } else if (!list_empty(&vidq->queued)) {
- buf = list_entry(vidq->queued.next, struct viu_buf,
- vb.queue);
- list_del(&buf->vb.queue);
-
- dprintk(1, "start another queued buffer: 0x%p\n", buf);
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buffer_activate(dev, buf);
- }
-}
-
-inline void viu_default_settings(struct viu_reg *viu_reg)
-{
- struct viu_reg *vr = viu_reg;
-
- out_be32(&vr->luminance, 0x9512A254);
- out_be32(&vr->chroma_r, 0x03310000);
- out_be32(&vr->chroma_g, 0x06600F38);
- out_be32(&vr->chroma_b, 0x00000409);
- out_be32(&vr->alpha, 0x000000ff);
- out_be32(&vr->req_alarm, 0x00000090);
- dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
- in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
-}
-
-static void viu_overlay_intr(struct viu_dev *dev, u32 status)
-{
- struct viu_reg *vr = dev->vr;
-
- if (status & INT_DMA_END_STATUS)
- dev->dma_done = 1;
-
- if (status & INT_FIELD_STATUS) {
- if (dev->dma_done) {
- u32 addr = reg_val.field_base_addr;
-
- dev->dma_done = 0;
- if (status & FIELD_NO)
- addr += reg_val.dma_inc;
-
- out_be32(&vr->field_base_addr, addr);
- out_be32(&vr->dma_inc, reg_val.dma_inc);
- out_be32(&vr->status_cfg,
- (status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg);
- } else if (status & INT_VSYNC_STATUS) {
- out_be32(&vr->status_cfg,
- (status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg);
- }
- }
-}
-
-static void viu_capture_intr(struct viu_dev *dev, u32 status)
-{
- struct viu_dmaqueue *vidq = &dev->vidq;
- struct viu_reg *vr = dev->vr;
- struct viu_buf *buf;
- int field_num;
- int need_two;
- int dma_done = 0;
-
- field_num = status & FIELD_NO;
- need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
-
- if (status & INT_DMA_END_STATUS) {
- dma_done = 1;
- if (((field_num == 0) && (dev->field == 0)) ||
- (field_num && (dev->field == 1)))
- dev->field++;
- }
-
- if (status & INT_FIELD_STATUS) {
- dprintk(1, "irq: field %d, done %d\n",
- !!field_num, dma_done);
- if (unlikely(dev->first)) {
- if (field_num == 0) {
- dev->first = 0;
- dprintk(1, "activate first buf\n");
- viu_activate_next_buf(dev, vidq);
- } else
- dprintk(1, "wait field 0\n");
- return;
- }
-
- /* setup buffer address for next dma operation */
- if (!list_empty(&vidq->active)) {
- u32 addr = reg_val.field_base_addr;
-
- if (field_num && need_two) {
- addr += reg_val.dma_inc;
- dprintk(1, "field 1, 0x%lx, dev field %d\n",
- (unsigned long)addr, dev->field);
- }
- out_be32(&vr->field_base_addr, addr);
- out_be32(&vr->dma_inc, reg_val.dma_inc);
- out_be32(&vr->status_cfg,
- (status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg);
- return;
- }
- }
-
- if (dma_done && field_num && (dev->field == 2)) {
- dev->field = 0;
- buf = list_entry(vidq->active.next,
- struct viu_buf, vb.queue);
- dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
- buf, buf->vb.i,
- (unsigned long)videobuf_to_dma_contig(&buf->vb),
- (unsigned long)in_be32(&vr->field_base_addr));
-
- if (waitqueue_active(&buf->vb.done)) {
- list_del(&buf->vb.queue);
- do_gettimeofday(&buf->vb.ts);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- wake_up(&buf->vb.done);
- }
- /* activate next dma buffer */
- viu_activate_next_buf(dev, vidq);
- }
-}
-
-static irqreturn_t viu_intr(int irq, void *dev_id)
-{
- struct viu_dev *dev = (struct viu_dev *)dev_id;
- struct viu_reg *vr = dev->vr;
- u32 status;
- u32 error;
-
- status = in_be32(&vr->status_cfg);
-
- if (status & INT_ERROR_STATUS) {
- dev->irqs.error_irq++;
- error = status & ERR_MASK;
- if (error)
- dprintk(1, "Err: error(%d), times:%d!\n",
- error >> 4, dev->irqs.error_irq);
- /* Clear interrupt error bit and error flags */
- out_be32(&vr->status_cfg,
- (status & 0xffc0ffff) | INT_ERROR_STATUS);
- }
-
- if (status & INT_DMA_END_STATUS) {
- dev->irqs.dma_end_irq++;
- dev->dma_done = 1;
- dprintk(2, "VIU DMA end interrupt times: %d\n",
- dev->irqs.dma_end_irq);
- }
-
- if (status & INT_HSYNC_STATUS)
- dev->irqs.hsync_irq++;
-
- if (status & INT_FIELD_STATUS) {
- dev->irqs.field_irq++;
- dprintk(2, "VIU field interrupt times: %d\n",
- dev->irqs.field_irq);
- }
-
- if (status & INT_VSTART_STATUS)
- dev->irqs.vstart_irq++;
-
- if (status & INT_VSYNC_STATUS) {
- dev->irqs.vsync_irq++;
- dprintk(2, "VIU vsync interrupt times: %d\n",
- dev->irqs.vsync_irq);
- }
-
- /* clear all pending irqs */
- status = in_be32(&vr->status_cfg);
- out_be32(&vr->status_cfg,
- (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
-
- if (dev->ovenable) {
- viu_overlay_intr(dev, status);
- return IRQ_HANDLED;
- }
-
- /* Capture mode */
- viu_capture_intr(dev, status);
- return IRQ_HANDLED;
-}
-
-/*
- * File operations for the device
- */
-static int viu_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct viu_dev *dev = video_get_drvdata(vdev);
- struct viu_fh *fh;
- struct viu_reg *vr;
- int minor = vdev->minor;
- u32 status_cfg;
- int i;
-
- dprintk(1, "viu: open (minor=%d)\n", minor);
-
- dev->users++;
- if (dev->users > 1) {
- dev->users--;
- return -EBUSY;
- }
-
- vr = dev->vr;
-
- dprintk(1, "open minor=%d type=%s users=%d\n", minor,
- v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
-
- /* allocate and initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (!fh) {
- dev->users--;
- return -ENOMEM;
- }
-
- file->private_data = fh;
- fh->dev = dev;
-
- fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32);
- fh->width = norm_maxw();
- fh->height = norm_maxh();
- dev->crop_current.width = fh->width;
- dev->crop_current.height = fh->height;
-
- /* Put all controls at a sane state */
- for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
- qctl_regs[i] = viu_qctrl[i].default_value;
-
- dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&dev->vidq);
- dprintk(1, "Open: list_empty queued=%d\n",
- list_empty(&dev->vidq.queued));
- dprintk(1, "Open: list_empty active=%d\n",
- list_empty(&dev->vidq.active));
-
- viu_default_settings(vr);
-
- status_cfg = in_be32(&vr->status_cfg);
- out_be32(&vr->status_cfg,
- status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
- INT_FIELD_EN | INT_VSTART_EN |
- INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
-
- status_cfg = in_be32(&vr->status_cfg);
- out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
-
- spin_lock_init(&fh->vbq_lock);
- videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
- dev->dev, &fh->vbq_lock,
- fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct viu_buf), fh,
- &fh->dev->lock);
- return 0;
-}
-
-static ssize_t viu_read(struct file *file, char __user *data, size_t count,
- loff_t *ppos)
-{
- struct viu_fh *fh = file->private_data;
- struct viu_dev *dev = fh->dev;
- int ret = 0;
-
- dprintk(2, "%s\n", __func__);
- if (dev->ovenable)
- dev->ovenable = 0;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- viu_start_dma(dev);
- ret = videobuf_read_stream(&fh->vb_vidq, data, count,
- ppos, 0, file->f_flags & O_NONBLOCK);
- return ret;
- }
- return 0;
-}
-
-static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct viu_fh *fh = file->private_data;
- struct videobuf_queue *q = &fh->vb_vidq;
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
-
- return videobuf_poll_stream(file, q, wait);
-}
-
-static int viu_release(struct file *file)
-{
- struct viu_fh *fh = file->private_data;
- struct viu_dev *dev = fh->dev;
- int minor = video_devdata(file)->minor;
-
- viu_stop_dma(dev);
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- kfree(fh);
-
- dev->users--;
- dprintk(1, "close (minor=%d, users=%d)\n",
- minor, dev->users);
- return 0;
-}
-
-void viu_reset(struct viu_reg *reg)
-{
- out_be32(&reg->status_cfg, 0);
- out_be32(&reg->luminance, 0x9512a254);
- out_be32(&reg->chroma_r, 0x03310000);
- out_be32(&reg->chroma_g, 0x06600f38);
- out_be32(&reg->chroma_b, 0x00000409);
- out_be32(&reg->field_base_addr, 0);
- out_be32(&reg->dma_inc, 0);
- out_be32(&reg->picture_count, 0x01e002d0);
- out_be32(&reg->req_alarm, 0x00000090);
- out_be32(&reg->alpha, 0x000000ff);
-}
-
-static int viu_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct viu_fh *fh = file->private_data;
- int ret;
-
- dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
-
- ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-
- dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- ret);
-
- return ret;
-}
-
-static struct v4l2_file_operations viu_fops = {
- .owner = THIS_MODULE,
- .open = viu_open,
- .release = viu_release,
- .read = viu_read,
- .poll = viu_poll,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = viu_mmap,
-};
-
-static const struct v4l2_ioctl_ops viu_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap,
- .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
- .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
- .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
- .vidioc_overlay = vidioc_overlay,
- .vidioc_g_fbuf = vidioc_g_fbuf,
- .vidioc_s_fbuf = vidioc_s_fbuf,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_querystd = vidioc_querystd,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
-};
-
-static struct video_device viu_template = {
- .name = "FSL viu",
- .fops = &viu_fops,
- .minor = -1,
- .ioctl_ops = &viu_ioctl_ops,
- .release = video_device_release,
-
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-static int __devinit viu_of_probe(struct platform_device *op)
-{
- struct viu_dev *viu_dev;
- struct video_device *vdev;
- struct resource r;
- struct viu_reg __iomem *viu_regs;
- struct i2c_adapter *ad;
- int ret, viu_irq;
-
- ret = of_address_to_resource(op->dev.of_node, 0, &r);
- if (ret) {
- dev_err(&op->dev, "Can't parse device node resource\n");
- return -ENODEV;
- }
-
- viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
- if (viu_irq == NO_IRQ) {
- dev_err(&op->dev, "Error while mapping the irq\n");
- return -EINVAL;
- }
-
- /* request mem region */
- if (!devm_request_mem_region(&op->dev, r.start,
- sizeof(struct viu_reg), DRV_NAME)) {
- dev_err(&op->dev, "Error while requesting mem region\n");
- ret = -EBUSY;
- goto err;
- }
-
- /* remap registers */
- viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
- if (!viu_regs) {
- dev_err(&op->dev, "Can't map register set\n");
- ret = -ENOMEM;
- goto err;
- }
-
- /* Prepare our private structure */
- viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
- if (!viu_dev) {
- dev_err(&op->dev, "Can't allocate private structure\n");
- ret = -ENOMEM;
- goto err;
- }
-
- viu_dev->vr = viu_regs;
- viu_dev->irq = viu_irq;
- viu_dev->dev = &op->dev;
-
- /* init video dma queues */
- INIT_LIST_HEAD(&viu_dev->vidq.active);
- INIT_LIST_HEAD(&viu_dev->vidq.queued);
-
- snprintf(viu_dev->v4l2_dev.name,
- sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
- ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
- if (ret < 0) {
- dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
- goto err;
- }
-
- ad = i2c_get_adapter(0);
- viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
- "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
-
- viu_dev->vidq.timeout.function = viu_vid_timeout;
- viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
- init_timer(&viu_dev->vidq.timeout);
- viu_dev->first = 1;
-
- /* Allocate memory for video device */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- ret = -ENOMEM;
- goto err_vdev;
- }
-
- memcpy(vdev, &viu_template, sizeof(viu_template));
-
- vdev->v4l2_dev = &viu_dev->v4l2_dev;
-
- viu_dev->vdev = vdev;
-
- /* initialize locks */
- mutex_init(&viu_dev->lock);
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &viu_dev->vdev->flags);
- viu_dev->vdev->lock = &viu_dev->lock;
- spin_lock_init(&viu_dev->slock);
-
- video_set_drvdata(viu_dev->vdev, viu_dev);
-
- mutex_lock(&viu_dev->lock);
-
- ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- video_device_release(viu_dev->vdev);
- goto err_vdev;
- }
-
- /* enable VIU clock */
- viu_dev->clk = clk_get(&op->dev, "viu_clk");
- if (IS_ERR(viu_dev->clk)) {
- dev_err(&op->dev, "failed to find the clock module!\n");
- ret = -ENODEV;
- goto err_clk;
- } else {
- clk_enable(viu_dev->clk);
- }
-
- /* reset VIU module */
- viu_reset(viu_dev->vr);
-
- /* install interrupt handler */
- if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
- dev_err(&op->dev, "Request VIU IRQ failed.\n");
- ret = -ENODEV;
- goto err_irq;
- }
-
- mutex_unlock(&viu_dev->lock);
-
- dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
- return ret;
-
-err_irq:
- clk_disable(viu_dev->clk);
- clk_put(viu_dev->clk);
-err_clk:
- video_unregister_device(viu_dev->vdev);
-err_vdev:
- mutex_unlock(&viu_dev->lock);
- i2c_put_adapter(ad);
- v4l2_device_unregister(&viu_dev->v4l2_dev);
-err:
- irq_dispose_mapping(viu_irq);
- return ret;
-}
-
-static int __devexit viu_of_remove(struct platform_device *op)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
- struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
- struct v4l2_subdev, list);
- struct i2c_client *client = v4l2_get_subdevdata(sdev);
-
- free_irq(dev->irq, (void *)dev);
- irq_dispose_mapping(dev->irq);
-
- clk_disable(dev->clk);
- clk_put(dev->clk);
-
- video_unregister_device(dev->vdev);
- i2c_put_adapter(client->adapter);
- v4l2_device_unregister(&dev->v4l2_dev);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int viu_suspend(struct platform_device *op, pm_message_t state)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
-
- clk_disable(dev->clk);
- return 0;
-}
-
-static int viu_resume(struct platform_device *op)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
-
- clk_enable(dev->clk);
- return 0;
-}
-#endif
-
-/*
- * Initialization and module stuff
- */
-static struct of_device_id mpc512x_viu_of_match[] = {
- {
- .compatible = "fsl,mpc5121-viu",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
-
-static struct platform_driver viu_of_platform_driver = {
- .probe = viu_of_probe,
- .remove = __devexit_p(viu_of_remove),
-#ifdef CONFIG_PM
- .suspend = viu_suspend,
- .resume = viu_resume,
-#endif
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = mpc512x_viu_of_match,
- },
-};
-
-module_platform_driver(viu_of_platform_driver);
-
-MODULE_DESCRIPTION("Freescale Video-In(VIU)");
-MODULE_AUTHOR("Hongjun Chen");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VIU_VERSION);
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
deleted file mode 100644
index dfe268bfa4f8..000000000000
--- a/drivers/media/video/gspca/Kconfig
+++ /dev/null
@@ -1,425 +0,0 @@
-menuconfig USB_GSPCA
- tristate "GSPCA based webcams"
- depends on VIDEO_V4L2
- default m
- ---help---
- Say Y here if you want to enable selecting webcams based
- on the GSPCA framework.
-
- See <file:Documentation/video4linux/gspca.txt> for more info.
-
- This driver uses the Video For Linux API. You must say Y or M to
- "Video For Linux" to use this driver.
-
- To compile this driver as modules, choose M here: the
- module will be called gspca_main.
-
-
-if USB_GSPCA && VIDEO_V4L2
-
-source "drivers/media/video/gspca/m5602/Kconfig"
-source "drivers/media/video/gspca/stv06xx/Kconfig"
-source "drivers/media/video/gspca/gl860/Kconfig"
-
-config USB_GSPCA_BENQ
- tristate "Benq USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for the Benq DC E300 camera.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_benq.
-
-config USB_GSPCA_CONEX
- tristate "Conexant Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Conexant chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_conex.
-
-config USB_GSPCA_CPIA1
- tristate "cpia CPiA (version 1) Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for USB cameras based on the cpia
- CPiA chip. Note that you need atleast version 0.6.4 of libv4l for
- applications to understand the videoformat generated by this driver.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_cpia1.
-
-config USB_GSPCA_ETOMS
- tristate "Etoms USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Etoms chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_etoms.
-
-config USB_GSPCA_FINEPIX
- tristate "Fujifilm FinePix USB V4L2 driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the FinePix chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_finepix.
-
-config USB_GSPCA_JEILINJ
- tristate "Jeilin JPEG USB V4L2 driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on this Jeilin chip.
-
- 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
- help
- Say Y here if you want support for the Microsoft Kinect sensor device.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_kinect.
-
-config USB_GSPCA_KONICA
- tristate "Konica USB Camera V4L2 driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Konica chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_konica.
-
-config USB_GSPCA_MARS
- tristate "Mars USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Mars chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_mars.
-
-config USB_GSPCA_MR97310A
- tristate "Mars-Semi MR97310A USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the MR97310A chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_mr97310a.
-
-config USB_GSPCA_NW80X
- tristate "Divio based (NW80x) USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the NW80x chips.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_nw80x.
-
-config USB_GSPCA_OV519
- tristate "OV51x / OVFX2 / W996xCF USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on one of these:
- OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_ov519.
-
-config USB_GSPCA_OV534
- tristate "OV534 OV772x USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the OV534 chip
- and sensor OV772x (e.g. Sony Playstation EYE)
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_ov534.
-
-config USB_GSPCA_OV534_9
- tristate "OV534 OV965x USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the OV534 chip
- and sensor OV965x (e.g. Hercules Dualpix)
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_ov534_9.
-
-config USB_GSPCA_PAC207
- tristate "Pixart PAC207 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the PAC207 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_pac207.
-
-config USB_GSPCA_PAC7302
- tristate "Pixart PAC7302 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the PAC7302 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_pac7302.
-
-config USB_GSPCA_PAC7311
- tristate "Pixart PAC7311 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the PAC7311 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_pac7311.
-
-config USB_GSPCA_SE401
- tristate "SE401 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the
- Endpoints (formerly known as AOX) se401 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_se401.
-
-config USB_GSPCA_SN9C2028
- tristate "SONIX Dual-Mode USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want streaming support for Sonix SN9C2028 cameras.
- These are supported as stillcams in libgphoto2/camlibs/sonix.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sn9c2028.
-
-config USB_GSPCA_SN9C20X
- tristate "SN9C20X USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the
- sn9c20x chips (SN9C201 and SN9C202).
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sn9c20x.
-
-config USB_GSPCA_SONIXB
- tristate "SONIX Bayer USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Sonix
- chips with Bayer format (SN9C101, SN9C102 and SN9C103).
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sonixb.
-
-config USB_GSPCA_SONIXJ
- tristate "SONIX JPEG USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Sonix
- chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110).
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sonixj
-
-config USB_GSPCA_SPCA500
- tristate "SPCA500 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA500 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca500.
-
-config USB_GSPCA_SPCA501
- tristate "SPCA501 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA501 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca501.
-
-config USB_GSPCA_SPCA505
- tristate "SPCA505 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA505 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca505.
-
-config USB_GSPCA_SPCA506
- tristate "SPCA506 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA506 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca506.
-
-config USB_GSPCA_SPCA508
- tristate "SPCA508 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA508 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca508.
-
-config USB_GSPCA_SPCA561
- tristate "SPCA561 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA561 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca561.
-
-config USB_GSPCA_SPCA1528
- tristate "SPCA1528 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SPCA1528 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_spca1528.
-
-config USB_GSPCA_SQ905
- tristate "SQ Technologies SQ905 based USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SQ905 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sq905.
-
-config USB_GSPCA_SQ905C
- tristate "SQ Technologies SQ905C based USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SQ905C chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sq905c.
-
-config USB_GSPCA_SQ930X
- tristate "SQ Technologies SQ930X based USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the SQ930X chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sq930x.
-
-config USB_GSPCA_STK014
- tristate "Syntek DV4000 (STK014) USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the STK014 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_stk014.
-
-config USB_GSPCA_STV0680
- tristate "STV0680 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the STV0680 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_stv0680.
-
-config USB_GSPCA_SUNPLUS
- tristate "SUNPLUS USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the Sunplus
- SPCA504(abc) SPCA533 SPCA536 chips.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_sunplus.
-
-config USB_GSPCA_T613
- tristate "T613 (JPEG Compliance) USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the T613 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_t613.
-
-config USB_GSPCA_TOPRO
- tristate "TOPRO USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the
- TP6800 and TP6810 Topro chips.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_topro.
-
-config USB_GSPCA_TV8532
- tristate "TV8532 USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the TV8531 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_tv8532.
-
-config USB_GSPCA_VC032X
- tristate "VC032X USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the VC032X chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_vc032x.
-
-config USB_GSPCA_VICAM
- tristate "ViCam USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for the 3com homeconnect camera
- (vicam).
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_vicam.
-
-config USB_GSPCA_XIRLINK_CIT
- tristate "Xirlink C-It USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for Xirlink C-It bases cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_xirlink_cit.
-
-config USB_GSPCA_ZC3XX
- tristate "ZC3XX USB Camera Driver"
- depends on VIDEO_V4L2 && USB_GSPCA
- help
- Say Y here if you want support for cameras based on the ZC3XX chip.
-
- To compile this driver as a module, choose M here: the
- module will be called gspca_zc3xx.
-
-endif
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile
deleted file mode 100644
index 773ea3426561..000000000000
--- a/drivers/media/video/gspca/gl860/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-$(CONFIG_USB_GL860) += gspca_gl860.o
-
-gspca_gl860-objs := gl860.o \
- gl860-mi1320.o \
- gl860-ov2640.o \
- gl860-ov9655.o \
- gl860-mi2020.o
-
-ccflags-y += -I$(srctree)/drivers/media/video/gspca
-
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
deleted file mode 100644
index 575b75bacb62..000000000000
--- a/drivers/media/video/gspca/m5602/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-obj-$(CONFIG_USB_M5602) += gspca_m5602.o
-
-gspca_m5602-objs := m5602_core.o \
- m5602_ov9650.o \
- m5602_ov7660.o \
- m5602_mt9m111.o \
- m5602_po1030.o \
- m5602_s5k83a.o \
- m5602_s5k4aa.o
-
-ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
deleted file mode 100644
index 2c2f3d2f357f..000000000000
--- a/drivers/media/video/gspca/sq905c.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * SQ905C subdriver
- *
- * Copyright (C) 2009 Theodore Kilgore
- *
- * 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
- */
-
-/*
- *
- * This driver uses work done in
- * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
- *
- * This driver has also used as a base the sq905c driver
- * and may contain code fragments from it.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define MODULE_NAME "sq905c"
-
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-#include "gspca.h"
-
-MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
-MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
-MODULE_LICENSE("GPL");
-
-/* Default timeouts, in ms */
-#define SQ905C_CMD_TIMEOUT 500
-#define SQ905C_DATA_TIMEOUT 1000
-
-/* Maximum transfer size to use. */
-#define SQ905C_MAX_TRANSFER 0x8000
-
-#define FRAME_HEADER_LEN 0x50
-
-/* Commands. These go in the "value" slot. */
-#define SQ905C_CLEAR 0xa0 /* clear everything */
-#define SQ905C_GET_ID 0x14f4 /* Read version number */
-#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
-#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
-#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
-
-/* For capture, this must go in the "index" slot. */
-#define SQ905C_CAPTURE_INDEX 0x110f
-
-/* Structure to hold all of our device specific stuff */
-struct sd {
- struct gspca_dev gspca_dev; /* !! must be the first item */
- const struct v4l2_pix_format *cap_mode;
- /* Driver stuff */
- struct work_struct work_struct;
- struct workqueue_struct *work_thread;
-};
-
-/*
- * Most of these cameras will do 640x480 and 320x240. 160x120 works
- * in theory but gives very poor output. Therefore, not supported.
- * The 0x2770:0x9050 cameras have max resolution of 320x240.
- */
-static struct v4l2_pix_format sq905c_mode[] = {
- { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
- { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0}
-};
-
-/* Send a command to the camera. */
-static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
-{
- int ret;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- USB_REQ_SYNCH_FRAME, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- command, index, NULL, 0,
- SQ905C_CMD_TIMEOUT);
- if (ret < 0) {
- pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
- int size)
-{
- int ret;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- USB_REQ_SYNCH_FRAME, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- command, index, gspca_dev->usb_buf, size,
- SQ905C_CMD_TIMEOUT);
- if (ret < 0) {
- pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-/* 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 sq905c_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; /* bytes remaining in current frame. */
- int data_len; /* size to use for the next read. */
- int act_len;
- int packet_type;
- int ret;
- u8 *buffer;
-
- buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
- if (!buffer) {
- pr_err("Couldn't allocate USB buffer\n");
- goto quit_stream;
- }
-
- while (gspca_dev->dev && gspca_dev->streaming) {
-#ifdef CONFIG_PM
- if (gspca_dev->frozen)
- break;
-#endif
- /* Request the header, which tells the size to download */
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x81),
- buffer, FRAME_HEADER_LEN, &act_len,
- SQ905C_DATA_TIMEOUT);
- PDEBUG(D_STREAM,
- "Got %d bytes out of %d for header",
- act_len, FRAME_HEADER_LEN);
- if (ret < 0 || act_len < FRAME_HEADER_LEN)
- goto quit_stream;
- /* size is read from 4 bytes starting 0x40, little endian */
- bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
- |(buffer[0x43]<<24);
- PDEBUG(D_STREAM, "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, FRAME_HEADER_LEN);
- while (bytes_left > 0 && gspca_dev->dev) {
- data_len = bytes_left > SQ905C_MAX_TRANSFER ?
- SQ905C_MAX_TRANSFER : bytes_left;
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x81),
- buffer, data_len, &act_len,
- SQ905C_DATA_TIMEOUT);
- if (ret < 0 || act_len < data_len)
- goto quit_stream;
- PDEBUG(D_STREAM,
- "Got %d bytes out of %d for frame",
- data_len, bytes_left);
- bytes_left -= data_len;
- if (bytes_left == 0)
- packet_type = LAST_PACKET;
- else
- packet_type = INTER_PACKET;
- gspca_frame_add(gspca_dev, packet_type,
- buffer, data_len);
- }
- }
-quit_stream:
- if (gspca_dev->dev) {
- mutex_lock(&gspca_dev->usb_lock);
- sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
- mutex_unlock(&gspca_dev->usb_lock);
- }
- kfree(buffer);
-}
-
-/* This function is called at probe time just before sd_init */
-static int sd_config(struct gspca_dev *gspca_dev,
- const struct usb_device_id *id)
-{
- struct cam *cam = &gspca_dev->cam;
- struct sd *dev = (struct sd *) gspca_dev;
- int ret;
-
- PDEBUG(D_PROBE,
- "SQ9050 camera detected"
- " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
-
- ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0);
- if (ret < 0) {
- PDEBUG(D_ERR, "Get version command failed");
- return ret;
- }
-
- ret = sq905c_read(gspca_dev, 0xf5, 0, 20);
- if (ret < 0) {
- PDEBUG(D_ERR, "Reading version command failed");
- return ret;
- }
- /* Note we leave out the usb id and the manufacturing date */
- PDEBUG(D_PROBE,
- "SQ9050 ID string: %02x - %02x %02x %02x %02x %02x %02x",
- gspca_dev->usb_buf[3],
- gspca_dev->usb_buf[14], gspca_dev->usb_buf[15],
- gspca_dev->usb_buf[16], gspca_dev->usb_buf[17],
- gspca_dev->usb_buf[18], gspca_dev->usb_buf[19]);
-
- cam->cam_mode = sq905c_mode;
- cam->nmodes = 2;
- if (gspca_dev->usb_buf[15] == 0)
- cam->nmodes = 1;
- /* We don't use the buffer gspca allocates so make it small. */
- cam->bulk_size = 32;
- cam->bulk = 1;
- INIT_WORK(&dev->work_struct, sq905c_dostream);
- 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);
-}
-
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
- int ret;
-
- /* connect to the camera and reset it. */
- ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
- return ret;
-}
-
-/* Set up for getting frames. */
-static int sd_start(struct gspca_dev *gspca_dev)
-{
- struct sd *dev = (struct sd *) gspca_dev;
- int ret;
-
- dev->cap_mode = gspca_dev->cam.cam_mode;
- /* "Open the shutter" and set size, to start capture */
- switch (gspca_dev->width) {
- case 640:
- PDEBUG(D_STREAM, "Start streaming at high resolution");
- dev->cap_mode++;
- ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
- SQ905C_CAPTURE_INDEX);
- break;
- default: /* 320 */
- PDEBUG(D_STREAM, "Start streaming at medium resolution");
- ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
- SQ905C_CAPTURE_INDEX);
- }
-
- if (ret < 0) {
- PDEBUG(D_ERR, "Start streaming command failed");
- return ret;
- }
- /* Start the workqueue function to do the streaming */
- dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
- queue_work(dev->work_thread, &dev->work_struct);
-
- return 0;
-}
-
-/* Table of supported USB devices */
-static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x2770, 0x905c)},
- {USB_DEVICE(0x2770, 0x9050)},
- {USB_DEVICE(0x2770, 0x9051)},
- {USB_DEVICE(0x2770, 0x9052)},
- {USB_DEVICE(0x2770, 0x913d)},
- {}
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-/* sub-driver description */
-static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
- .config = sd_config,
- .init = sd_init,
- .start = sd_start,
- .stop0 = sd_stop0,
-};
-
-/* -- 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,
- .reset_resume = gspca_resume,
-#endif
-};
-
-module_usb_driver(sd_driver);
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
deleted file mode 100644
index 3e1e486af883..000000000000
--- a/drivers/media/video/gspca/sq930x.c
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * SQ930x subdriver
- *
- * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
- * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
- * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define MODULE_NAME "sq930x"
-
-#include "gspca.h"
-
-MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
- "Gerard Klaver <gerard at gkall dot hobby dot nl\n"
- "Sam Revitch <samr7@cs.washington.edu>");
-MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
-MODULE_LICENSE("GPL");
-
-/* Structure to hold all of our device specific stuff */
-struct sd {
- struct gspca_dev gspca_dev; /* !! must be the first item */
-
- struct { /* exposure/gain control cluster */
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *gain;
- };
-
- u8 do_ctrl;
- u8 gpio[2];
- u8 sensor;
- u8 type;
-#define Generic 0
-#define Creative_live_motion 1
-};
-enum sensors {
- SENSOR_ICX098BQ,
- SENSOR_LZ24BP,
- SENSOR_MI0360,
- SENSOR_MT9V111, /* = MI360SOC */
- SENSOR_OV7660,
- SENSOR_OV9630,
-};
-
-static struct v4l2_pix_format vga_mode[] = {
- {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
- {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
-};
-
-/* sq930x registers */
-#define SQ930_CTRL_UCBUS_IO 0x0001
-#define SQ930_CTRL_I2C_IO 0x0002
-#define SQ930_CTRL_GPIO 0x0005
-#define SQ930_CTRL_CAP_START 0x0010
-#define SQ930_CTRL_CAP_STOP 0x0011
-#define SQ930_CTRL_SET_EXPOSURE 0x001d
-#define SQ930_CTRL_RESET 0x001e
-#define SQ930_CTRL_GET_DEV_INFO 0x001f
-
-/* gpio 1 (8..15) */
-#define SQ930_GPIO_DFL_I2C_SDA 0x0001
-#define SQ930_GPIO_DFL_I2C_SCL 0x0002
-#define SQ930_GPIO_RSTBAR 0x0004
-#define SQ930_GPIO_EXTRA1 0x0040
-#define SQ930_GPIO_EXTRA2 0x0080
-/* gpio 3 (24..31) */
-#define SQ930_GPIO_POWER 0x0200
-#define SQ930_GPIO_DFL_LED 0x1000
-
-struct ucbus_write_cmd {
- u16 bw_addr;
- u8 bw_data;
-};
-struct i2c_write_cmd {
- u8 reg;
- u16 val;
-};
-
-static const struct ucbus_write_cmd icx098bq_start_0[] = {
- {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
- {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
- {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
- {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
- {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
- {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
- {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
- {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
- {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
- {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
- {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
- {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
- {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
- {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
- {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
- {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
- {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
- {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
- {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
- {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
- {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
- {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
- {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
- {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
- {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
- {0xf800, 0x03}
-};
-static const struct ucbus_write_cmd icx098bq_start_1[] = {
- {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xc0},
- {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xc0},
- {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
- {0xf5f9, 0x00}
-};
-
-static const struct ucbus_write_cmd icx098bq_start_2[] = {
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03}
-};
-
-static const struct ucbus_write_cmd lz24bp_start_0[] = {
- {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
- {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
- {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
- {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
- {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
- {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
- {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
- {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
- {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
- {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
- {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
- {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
- {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
- {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
- {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
- {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
- {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
- {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
- {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
- {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
- {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
- {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
- {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
- {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
- {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
- {0xf800, 0x03}
-};
-static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
- {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xb3},
- {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xb3},
- {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
- {0xf5f9, 0x00}
-};
-
-static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
- {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
- {0xf5f4, 0xc0},
- {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
- {0xf5f4, 0xc0},
- {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
- {0xf5f9, 0x00}
-};
-
-static const struct ucbus_write_cmd lz24bp_start_2[] = {
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
- {0xf807, 0x7f}, {0xf800, 0x03},
- {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
- {0xf807, 0x7f}, {0xf800, 0x03}
-};
-
-static const struct ucbus_write_cmd mi0360_start_0[] = {
- {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
- {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
-};
-static const struct i2c_write_cmd mi0360_init_23[] = {
- {0x30, 0x0040}, /* reserved - def 0x0005 */
- {0x31, 0x0000}, /* reserved - def 0x002a */
- {0x34, 0x0100}, /* reserved - def 0x0100 */
- {0x3d, 0x068f}, /* reserved - def 0x068f */
-};
-static const struct i2c_write_cmd mi0360_init_24[] = {
- {0x03, 0x01e5}, /* window height */
- {0x04, 0x0285}, /* window width */
-};
-static const struct i2c_write_cmd mi0360_init_25[] = {
- {0x35, 0x0020}, /* global gain */
- {0x2b, 0x0020}, /* green1 gain */
- {0x2c, 0x002a}, /* blue gain */
- {0x2d, 0x0028}, /* red gain */
- {0x2e, 0x0020}, /* green2 gain */
-};
-static const struct ucbus_write_cmd mi0360_start_1[] = {
- {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xa6},
- {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xa6},
- {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
- {0xf5f9, 0x00}
-};
-static const struct i2c_write_cmd mi0360_start_2[] = {
- {0x62, 0x041d}, /* reserved - def 0x0418 */
-};
-static const struct i2c_write_cmd mi0360_start_3[] = {
- {0x05, 0x007b}, /* horiz blanking */
-};
-static const struct i2c_write_cmd mi0360_start_4[] = {
- {0x05, 0x03f5}, /* horiz blanking */
-};
-
-static const struct i2c_write_cmd mt9v111_init_0[] = {
- {0x01, 0x0001}, /* select IFP/SOC registers */
- {0x06, 0x300c}, /* operating mode control */
- {0x08, 0xcc00}, /* output format control (RGB) */
- {0x01, 0x0004}, /* select sensor core registers */
-};
-static const struct i2c_write_cmd mt9v111_init_1[] = {
- {0x03, 0x01e5}, /* window height */
- {0x04, 0x0285}, /* window width */
-};
-static const struct i2c_write_cmd mt9v111_init_2[] = {
- {0x30, 0x7800},
- {0x31, 0x0000},
- {0x07, 0x3002}, /* output control */
- {0x35, 0x0020}, /* global gain */
- {0x2b, 0x0020}, /* green1 gain */
- {0x2c, 0x0020}, /* blue gain */
- {0x2d, 0x0020}, /* red gain */
- {0x2e, 0x0020}, /* green2 gain */
-};
-static const struct ucbus_write_cmd mt9v111_start_1[] = {
- {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xaa},
- {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
- {0xf5f4, 0xaa},
- {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
- {0xf5f9, 0x0a}
-};
-static const struct i2c_write_cmd mt9v111_init_3[] = {
- {0x62, 0x0405},
-};
-static const struct i2c_write_cmd mt9v111_init_4[] = {
-/* {0x05, 0x00ce}, */
- {0x05, 0x005d}, /* horizontal blanking */
-};
-
-static const struct ucbus_write_cmd ov7660_start_0[] = {
- {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
- {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
-};
-
-static const struct ucbus_write_cmd ov9630_start_0[] = {
- {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
- {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
-};
-
-/* start parameters indexed by [sensor][mode] */
-static const struct cap_s {
- u8 cc_sizeid;
- u8 cc_bytes[32];
-} capconfig[4][2] = {
- [SENSOR_ICX098BQ] = {
- {2, /* Bayer 320x240 */
- {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
- 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- {4, /* Bayer 640x480 */
- {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
- 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- },
- [SENSOR_LZ24BP] = {
- {2, /* Bayer 320x240 */
- {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
- 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- {4, /* Bayer 640x480 */
- {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
- 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- },
- [SENSOR_MI0360] = {
- {2, /* Bayer 320x240 */
- {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
- 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- {4, /* Bayer 640x480 */
- {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
- 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- },
- [SENSOR_MT9V111] = {
- {2, /* Bayer 320x240 */
- {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
- 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- {4, /* Bayer 640x480 */
- {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
- 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
- },
-};
-
-struct sensor_s {
- const char *name;
- u8 i2c_addr;
- u8 i2c_dum;
- u8 gpio[5];
- u8 cmd_len;
- const struct ucbus_write_cmd *cmd;
-};
-
-static const struct sensor_s sensor_tb[] = {
- [SENSOR_ICX098BQ] = {
- "icx098bp",
- 0x00, 0x00,
- {0,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- SQ930_GPIO_RSTBAR
- },
- 8, icx098bq_start_0
- },
- [SENSOR_LZ24BP] = {
- "lz24bp",
- 0x00, 0x00,
- {0,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- SQ930_GPIO_RSTBAR
- },
- 8, lz24bp_start_0
- },
- [SENSOR_MI0360] = {
- "mi0360",
- 0x5d, 0x80,
- {SQ930_GPIO_RSTBAR,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- 0
- },
- 7, mi0360_start_0
- },
- [SENSOR_MT9V111] = {
- "mt9v111",
- 0x5c, 0x7f,
- {SQ930_GPIO_RSTBAR,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- 0
- },
- 7, mi0360_start_0
- },
- [SENSOR_OV7660] = {
- "ov7660",
- 0x21, 0x00,
- {0,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- SQ930_GPIO_RSTBAR
- },
- 7, ov7660_start_0
- },
- [SENSOR_OV9630] = {
- "ov9630",
- 0x30, 0x00,
- {0,
- SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
- SQ930_GPIO_DFL_I2C_SDA,
- 0,
- SQ930_GPIO_RSTBAR
- },
- 7, ov9630_start_0
- },
-};
-
-static void reg_r(struct gspca_dev *gspca_dev,
- u16 value, int len)
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0x0c,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, 0, gspca_dev->usb_buf, len,
- 500);
- if (ret < 0) {
- pr_err("reg_r %04x failed %d\n", value, ret);
- gspca_dev->usb_err = ret;
- }
-}
-
-static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
- PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x0c, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, NULL, 0,
- 500);
- msleep(30);
- if (ret < 0) {
- pr_err("reg_w %04x %04x failed %d\n", value, index, ret);
- gspca_dev->usb_err = ret;
- }
-}
-
-static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
- const u8 *data, int len)
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
- PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
- value, index, *data, data[len - 1]);
- memcpy(gspca_dev->usb_buf, data, len);
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x0c, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, gspca_dev->usb_buf, len,
- 1000);
- msleep(30);
- if (ret < 0) {
- pr_err("reg_wb %04x %04x failed %d\n", value, index, ret);
- gspca_dev->usb_err = ret;
- }
-}
-
-static void i2c_write(struct sd *sd,
- const struct i2c_write_cmd *cmd,
- int ncmds)
-{
- struct gspca_dev *gspca_dev = &sd->gspca_dev;
- const struct sensor_s *sensor;
- u16 val, idx;
- u8 *buf;
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
-
- sensor = &sensor_tb[sd->sensor];
-
- val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
- idx = (cmd->val & 0xff00) | cmd->reg;
-
- buf = gspca_dev->usb_buf;
- *buf++ = sensor->i2c_dum;
- *buf++ = cmd->val;
-
- while (--ncmds > 0) {
- cmd++;
- *buf++ = cmd->reg;
- *buf++ = cmd->val >> 8;
- *buf++ = sensor->i2c_dum;
- *buf++ = cmd->val;
- }
-
- PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
- val, idx, gspca_dev->usb_buf[0], buf[-1]);
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x0c, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- val, idx,
- gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
- 500);
- if (ret < 0) {
- pr_err("i2c_write failed %d\n", ret);
- gspca_dev->usb_err = ret;
- }
-}
-
-static void ucbus_write(struct gspca_dev *gspca_dev,
- const struct ucbus_write_cmd *cmd,
- int ncmds,
- int batchsize)
-{
- u8 *buf;
- u16 val, idx;
- int len, ret;
-
- if (gspca_dev->usb_err < 0)
- return;
-
-#ifdef GSPCA_DEBUG
- if ((batchsize - 1) * 3 > USB_BUF_SZ) {
- pr_err("Bug: usb_buf overflow\n");
- gspca_dev->usb_err = -ENOMEM;
- return;
- }
-#endif
-
- for (;;) {
- len = ncmds;
- if (len > batchsize)
- len = batchsize;
- ncmds -= len;
-
- val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
- idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
-
- buf = gspca_dev->usb_buf;
- while (--len > 0) {
- cmd++;
- *buf++ = cmd->bw_addr;
- *buf++ = cmd->bw_addr >> 8;
- *buf++ = cmd->bw_data;
- }
- if (buf != gspca_dev->usb_buf)
- PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
- val, idx,
- gspca_dev->usb_buf[0], buf[-1]);
- else
- PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
- val, idx);
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x0c, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- val, idx,
- gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
- 500);
- if (ret < 0) {
- pr_err("ucbus_write failed %d\n", ret);
- gspca_dev->usb_err = ret;
- return;
- }
- msleep(30);
- if (ncmds <= 0)
- break;
- cmd++;
- }
-}
-
-static void gpio_set(struct sd *sd, u16 val, u16 mask)
-{
- struct gspca_dev *gspca_dev = &sd->gspca_dev;
-
- if (mask & 0x00ff) {
- sd->gpio[0] &= ~mask;
- sd->gpio[0] |= val;
- reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
- ~sd->gpio[0] << 8);
- }
- mask >>= 8;
- val >>= 8;
- if (mask) {
- sd->gpio[1] &= ~mask;
- sd->gpio[1] |= val;
- reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
- ~sd->gpio[1] << 8);
- }
-}
-
-static void gpio_init(struct sd *sd,
- const u8 *gpio)
-{
- gpio_set(sd, *gpio++, 0x000f);
- gpio_set(sd, *gpio++, 0x000f);
- gpio_set(sd, *gpio++, 0x000f);
- gpio_set(sd, *gpio++, 0x000f);
- gpio_set(sd, *gpio, 0x000f);
-}
-
-static void bridge_init(struct sd *sd)
-{
- static const struct ucbus_write_cmd clkfreq_cmd = {
- 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */
- };
-
- ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
-
- gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
-}
-
-static void cmos_probe(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
- const struct sensor_s *sensor;
- static const u8 probe_order[] = {
-/* SENSOR_LZ24BP, (tested as ccd) */
- SENSOR_OV9630,
- SENSOR_MI0360,
- SENSOR_OV7660,
- SENSOR_MT9V111,
- };
-
- for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
- sensor = &sensor_tb[probe_order[i]];
- ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
- gpio_init(sd, sensor->gpio);
- msleep(100);
- reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
- msleep(100);
- if (gspca_dev->usb_buf[0] != 0)
- break;
- }
- if (i >= ARRAY_SIZE(probe_order)) {
- pr_err("Unknown sensor\n");
- gspca_dev->usb_err = -EINVAL;
- return;
- }
- sd->sensor = probe_order[i];
- switch (sd->sensor) {
- case SENSOR_OV7660:
- case SENSOR_OV9630:
- pr_err("Sensor %s not yet treated\n",
- sensor_tb[sd->sensor].name);
- gspca_dev->usb_err = -EINVAL;
- break;
- }
-}
-
-static void mt9v111_init(struct gspca_dev *gspca_dev)
-{
- int i, nwait;
- static const u8 cmd_001b[] = {
- 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
- 0x00, 0x00, 0x00
- };
- static const u8 cmd_011b[][7] = {
- {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
- {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
- {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
- {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
- };
-
- reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
- for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
- reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
- ARRAY_SIZE(cmd_011b[0]));
- msleep(400);
- nwait = 20;
- for (;;) {
- reg_r(gspca_dev, 0x031b, 1);
- if (gspca_dev->usb_buf[0] == 0
- || gspca_dev->usb_err != 0)
- break;
- if (--nwait < 0) {
- PDEBUG(D_PROBE, "mt9v111_init timeout");
- gspca_dev->usb_err = -ETIME;
- return;
- }
- msleep(50);
- }
- }
-}
-
-static void global_init(struct sd *sd, int first_time)
-{
- switch (sd->sensor) {
- case SENSOR_ICX098BQ:
- if (first_time)
- ucbus_write(&sd->gspca_dev,
- icx098bq_start_0,
- 8, 8);
- gpio_init(sd, sensor_tb[sd->sensor].gpio);
- break;
- case SENSOR_LZ24BP:
- if (sd->type != Creative_live_motion)
- gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
- else
- gpio_set(sd, 0, 0x00ff);
- msleep(50);
- if (first_time)
- ucbus_write(&sd->gspca_dev,
- lz24bp_start_0,
- 8, 8);
- gpio_init(sd, sensor_tb[sd->sensor].gpio);
- break;
- case SENSOR_MI0360:
- if (first_time)
- ucbus_write(&sd->gspca_dev,
- mi0360_start_0,
- ARRAY_SIZE(mi0360_start_0),
- 8);
- gpio_init(sd, sensor_tb[sd->sensor].gpio);
- gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
- break;
- default:
-/* case SENSOR_MT9V111: */
- if (first_time)
- mt9v111_init(&sd->gspca_dev);
- else
- gpio_init(sd, sensor_tb[sd->sensor].gpio);
- break;
- }
-}
-
-static void lz24bp_ppl(struct sd *sd, u16 ppl)
-{
- struct ucbus_write_cmd cmds[2] = {
- {0xf810, ppl >> 8},
- {0xf811, ppl}
- };
-
- ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
-}
-
-static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i, integclks, intstartclk, frameclks, min_frclk;
- const struct sensor_s *sensor;
- u16 cmd;
- u8 buf[15];
-
- integclks = expo;
- i = 0;
- cmd = SQ930_CTRL_SET_EXPOSURE;
-
- switch (sd->sensor) {
- case SENSOR_ICX098BQ: /* ccd */
- case SENSOR_LZ24BP:
- min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
- if (integclks >= min_frclk) {
- intstartclk = 0;
- frameclks = integclks;
- } else {
- intstartclk = min_frclk - integclks;
- frameclks = min_frclk;
- }
- buf[i++] = intstartclk >> 8;
- buf[i++] = intstartclk;
- buf[i++] = frameclks >> 8;
- buf[i++] = frameclks;
- buf[i++] = gain;
- break;
- default: /* cmos */
-/* case SENSOR_MI0360: */
-/* case SENSOR_MT9V111: */
- cmd |= 0x0100;
- sensor = &sensor_tb[sd->sensor];
- buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */
- buf[i++] = 0x08; /* 2 * ni2c */
- buf[i++] = 0x09; /* reg = shutter width */
- buf[i++] = integclks >> 8; /* val H */
- buf[i++] = sensor->i2c_dum;
- buf[i++] = integclks; /* val L */
- buf[i++] = 0x35; /* reg = global gain */
- buf[i++] = 0x00; /* val H */
- buf[i++] = sensor->i2c_dum;
- buf[i++] = 0x80 + gain / 2; /* val L */
- buf[i++] = 0x00;
- buf[i++] = 0x00;
- buf[i++] = 0x00;
- buf[i++] = 0x00;
- buf[i++] = 0x83;
- break;
- }
- reg_wb(gspca_dev, cmd, 0, buf, i);
-}
-
-/* This function is called at probe time just before sd_init */
-static int sd_config(struct gspca_dev *gspca_dev,
- const struct usb_device_id *id)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam = &gspca_dev->cam;
-
- sd->sensor = id->driver_info >> 8;
- sd->type = id->driver_info;
-
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
-
- cam->bulk = 1;
-
- 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;
-
- sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */
-
-/*fixme: is this needed for icx098bp and mi0360?
- if (sd->sensor != SENSOR_LZ24BP)
- reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
- */
-
- reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
- if (gspca_dev->usb_err < 0)
- return gspca_dev->usb_err;
-
-/* it returns:
- * 03 00 12 93 0b f6 c9 00 live! ultra
- * 03 00 07 93 0b f6 ca 00 live! ultra for notebook
- * 03 00 12 93 0b fe c8 00 Trust WB-3500T
- * 02 00 06 93 0b fe c8 00 Joy-IT 318S
- * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq
- * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam
- *
- * byte
- * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
- * 1: 00
- * 2: 06 / 07 / 12 = mode webcam? firmware??
- * 3: 93 chip = 930b (930b or 930c)
- * 4: 0b
- * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
- * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
- * 7: 00
- */
- PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x",
- gspca_dev->usb_buf[0],
- gspca_dev->usb_buf[1],
- gspca_dev->usb_buf[2],
- gspca_dev->usb_buf[3],
- gspca_dev->usb_buf[4],
- gspca_dev->usb_buf[5],
- gspca_dev->usb_buf[6],
- gspca_dev->usb_buf[7]);
-
- bridge_init(sd);
-
- if (sd->sensor == SENSOR_MI0360) {
-
- /* no sensor probe for icam tracer */
- if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */
- sd->sensor = SENSOR_ICX098BQ;
- else
- cmos_probe(gspca_dev);
- }
- if (gspca_dev->usb_err >= 0) {
- PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
- global_init(sd, 1);
- }
- return gspca_dev->usb_err;
-}
-
-/* send the start/stop commands to the webcam */
-static void send_start(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- const struct cap_s *cap;
- int mode;
-
- mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- cap = &capconfig[sd->sensor][mode];
- reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START,
- 0x0a00 | cap->cc_sizeid,
- cap->cc_bytes, 32);
-}
-
-static void send_stop(struct gspca_dev *gspca_dev)
-{
- reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
-}
-
-/* function called at start time before URB creation */
-static int sd_isoc_init(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */
- sd->do_ctrl = 0;
- gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8;
- return 0;
-}
-
-/* start the capture */
-static int sd_start(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int mode;
-
- bridge_init(sd);
- global_init(sd, 0);
- msleep(100);
-
- switch (sd->sensor) {
- case SENSOR_ICX098BQ:
- ucbus_write(gspca_dev, icx098bq_start_0,
- ARRAY_SIZE(icx098bq_start_0),
- 8);
- ucbus_write(gspca_dev, icx098bq_start_1,
- ARRAY_SIZE(icx098bq_start_1),
- 5);
- ucbus_write(gspca_dev, icx098bq_start_2,
- ARRAY_SIZE(icx098bq_start_2),
- 6);
- msleep(50);
-
- /* 1st start */
- send_start(gspca_dev);
- gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
- msleep(70);
- reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
- gpio_set(sd, 0x7f, 0x00ff);
-
- /* 2nd start */
- send_start(gspca_dev);
- gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
- goto out;
- case SENSOR_LZ24BP:
- ucbus_write(gspca_dev, lz24bp_start_0,
- ARRAY_SIZE(lz24bp_start_0),
- 8);
- if (sd->type != Creative_live_motion)
- ucbus_write(gspca_dev, lz24bp_start_1_gen,
- ARRAY_SIZE(lz24bp_start_1_gen),
- 5);
- else
- ucbus_write(gspca_dev, lz24bp_start_1_clm,
- ARRAY_SIZE(lz24bp_start_1_clm),
- 5);
- ucbus_write(gspca_dev, lz24bp_start_2,
- ARRAY_SIZE(lz24bp_start_2),
- 6);
- mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310);
- msleep(10);
- break;
- case SENSOR_MI0360:
- ucbus_write(gspca_dev, mi0360_start_0,
- ARRAY_SIZE(mi0360_start_0),
- 8);
- i2c_write(sd, mi0360_init_23,
- ARRAY_SIZE(mi0360_init_23));
- i2c_write(sd, mi0360_init_24,
- ARRAY_SIZE(mi0360_init_24));
- i2c_write(sd, mi0360_init_25,
- ARRAY_SIZE(mi0360_init_25));
- ucbus_write(gspca_dev, mi0360_start_1,
- ARRAY_SIZE(mi0360_start_1),
- 5);
- i2c_write(sd, mi0360_start_2,
- ARRAY_SIZE(mi0360_start_2));
- i2c_write(sd, mi0360_start_3,
- ARRAY_SIZE(mi0360_start_3));
-
- /* 1st start */
- send_start(gspca_dev);
- msleep(60);
- send_stop(gspca_dev);
-
- i2c_write(sd,
- mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
- break;
- default:
-/* case SENSOR_MT9V111: */
- ucbus_write(gspca_dev, mi0360_start_0,
- ARRAY_SIZE(mi0360_start_0),
- 8);
- i2c_write(sd, mt9v111_init_0,
- ARRAY_SIZE(mt9v111_init_0));
- i2c_write(sd, mt9v111_init_1,
- ARRAY_SIZE(mt9v111_init_1));
- i2c_write(sd, mt9v111_init_2,
- ARRAY_SIZE(mt9v111_init_2));
- ucbus_write(gspca_dev, mt9v111_start_1,
- ARRAY_SIZE(mt9v111_start_1),
- 5);
- i2c_write(sd, mt9v111_init_3,
- ARRAY_SIZE(mt9v111_init_3));
- i2c_write(sd, mt9v111_init_4,
- ARRAY_SIZE(mt9v111_init_4));
- break;
- }
-
- send_start(gspca_dev);
-out:
- msleep(1000);
-
- if (sd->sensor == SENSOR_MT9V111)
- gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
-
- sd->do_ctrl = 1; /* set the exposure */
-
- return gspca_dev->usb_err;
-}
-
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- if (sd->sensor == SENSOR_MT9V111)
- gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
- send_stop(gspca_dev);
-}
-
-/* function called when the application gets a new frame */
-/* It sets the exposure if required and restart the bulk transfer. */
-static void sd_dq_callback(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int ret;
-
- if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
- return;
- sd->do_ctrl = 0;
-
- setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure),
- v4l2_ctrl_g_ctrl(sd->gain));
-
- gspca_dev->cam.bulk_nurbs = 1;
- ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
- if (ret < 0)
- pr_err("sd_dq_callback() err %d\n", ret);
-
- /* wait a little time, otherwise the webcam crashes */
- msleep(100);
-}
-
-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;
-
- if (sd->do_ctrl)
- gspca_dev->cam.bulk_nurbs = 0;
- gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8);
- gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
-}
-
-static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct gspca_dev *gspca_dev =
- container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
- struct sd *sd = (struct sd *) gspca_dev;
-
- gspca_dev->usb_err = 0;
-
- if (!gspca_dev->streaming)
- return 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- setexposure(gspca_dev, ctrl->val, sd->gain->val);
- break;
- }
- return gspca_dev->usb_err;
-}
-
-static const struct v4l2_ctrl_ops sd_ctrl_ops = {
- .s_ctrl = sd_s_ctrl,
-};
-
-static int sd_init_controls(struct gspca_dev *gspca_dev)
-{
- struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
- struct sd *sd = (struct sd *) gspca_dev;
-
- gspca_dev->vdev.ctrl_handler = hdl;
- v4l2_ctrl_handler_init(hdl, 2);
- sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356);
- sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_GAIN, 1, 255, 1, 0x8d);
-
- if (hdl->error) {
- pr_err("Could not initialize controls\n");
- return hdl->error;
- }
- v4l2_ctrl_cluster(2, &sd->exposure);
- return 0;
-}
-
-/* sub-driver description */
-static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
- .config = sd_config,
- .init = sd_init,
- .init_controls = sd_init_controls,
- .isoc_init = sd_isoc_init,
- .start = sd_start,
- .stopN = sd_stopN,
- .pkt_scan = sd_pkt_scan,
- .dq_callback = sd_dq_callback,
-};
-
-/* Table of supported USB devices */
-#define ST(sensor, type) \
- .driver_info = (SENSOR_ ## sensor << 8) \
- | (type)
-static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
- {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
- {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
- {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
- {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
- {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
- {}
-};
-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,
- .reset_resume = gspca_resume,
-#endif
-};
-
-module_usb_driver(sd_driver);
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
deleted file mode 100644
index 38bc41061d83..000000000000
--- a/drivers/media/video/gspca/stv06xx/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
-
-gspca_stv06xx-objs := stv06xx.o \
- stv06xx_vv6410.o \
- stv06xx_hdcs.o \
- stv06xx_pb0100.o \
- stv06xx_st6422.o
-
-ccflags-y += -I$(srctree)/drivers/media/video/gspca
-
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
deleted file mode 100644
index f21fd1677c38..000000000000
--- a/drivers/media/video/gspca/vc032x.c
+++ /dev/null
@@ -1,3853 +0,0 @@
-/*
- * Z-star vc0321 library
- *
- * Copyright (C) 2009-2010 Jean-François Moine <http://moinejf.free.fr>
- * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
- * Copyright (C) 2006 Michel Xhaard
- *
- * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define MODULE_NAME "vc032x"
-
-#include "gspca.h"
-
-MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
-MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
-MODULE_LICENSE("GPL");
-
-/* specific webcam descriptor */
-struct sd {
- struct gspca_dev gspca_dev; /* !! must be the first item */
- struct { /* hvflip cluster */
- struct v4l2_ctrl *hflip;
- struct v4l2_ctrl *vflip;
- };
-
- u8 image_offset;
-
- u8 bridge;
- u8 sensor;
- u8 flags;
-#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
-#define FL_HFLIP 0x02 /* mirrored by default */
-#define FL_VFLIP 0x04 /* vertical flipped by default */
-};
-enum bridges {
- BRIDGE_VC0321,
- BRIDGE_VC0323,
-};
-enum sensors {
- SENSOR_HV7131R,
- SENSOR_MI0360,
- SENSOR_MI1310_SOC,
- SENSOR_MI1320,
- SENSOR_MI1320_SOC,
- SENSOR_OV7660,
- SENSOR_OV7670,
- SENSOR_PO1200,
- SENSOR_PO3130NC,
- SENSOR_POxxxx,
- NSENSORS
-};
-
-
-static const struct v4l2_pix_format vc0321_mode[] = {
- {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240 * 2,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
- {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480 * 2,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
-};
-static const struct v4l2_pix_format vc0323_mode[] = {
- {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1},
- {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0},
- {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
- .bytesperline = 1280,
- .sizeimage = 1280 * 960 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2},
-};
-static const struct v4l2_pix_format bi_mode[] = {
- {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240 * 2,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
- {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480 * 2,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
- {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 1280,
- .sizeimage = 1280 * 1024 * 2,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
-};
-static const struct v4l2_pix_format svga_mode[] = {
- {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 800,
- .sizeimage = 800 * 600 * 1 / 4 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0},
-};
-
-/* OV7660/7670 registers */
-#define OV7660_REG_MVFP 0x1e
-#define OV7660_MVFP_MIRROR 0x20
-#define OV7660_MVFP_VFLIP 0x10
-
-static const u8 mi0360_matrix[9] = {
- 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
-};
-
-static const u8 mi0360_initVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc},
- {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc},
- {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc},
- {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x50, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc},
- {0xb8, 0x08, 0xe0, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc},
- {0xb8, 0x14, 0x18, 0xcc},
- {0xb8, 0xb2, 0x0a, 0xcc},
- {0xb8, 0xb4, 0x0a, 0xcc},
- {0xb8, 0xb5, 0x0a, 0xcc},
- {0xb8, 0xfe, 0x00, 0xcc},
- {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc},
- {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc},
- {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc},
- {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc},
- {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0x31, 0x00, 0x00, 0xbb},
- {0x09, 0x01, 0xc7, 0xbb},
- {0x34, 0x01, 0x00, 0xbb},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x62, 0x04, 0x11, 0xbb},
- {0x03, 0x01, 0xe0, 0xbb},
- {0x2c, 0x00, 0x2c, 0xbb},
- {0x20, 0xd0, 0x00, 0xbb},
- {0x01, 0x00, 0x08, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0x05, 0x00, 0x20, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x02, 0xcc},
- {0xb6, 0x02, 0x80, 0xcc},
- {0xb6, 0x05, 0x01, 0xcc},
- {0xb6, 0x04, 0xe0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x02, 0xcc},
- {0xb6, 0x17, 0x58, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x35, 0x00, 0x60, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-static const u8 mi0360_initQVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc},
- {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc},
- {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc},
- {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x50, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc},
- {0xb8, 0x08, 0xe0, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc},
- {0xb8, 0x14, 0x18, 0xcc},
- {0xb8, 0xb2, 0x0a, 0xcc},
- {0xb8, 0xb4, 0x0a, 0xcc},
- {0xb8, 0xb5, 0x0a, 0xcc},
- {0xb8, 0xfe, 0x00, 0xcc},
- {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc},
- {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc},
- {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc},
- {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc},
- {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0x31, 0x00, 0x00, 0xbb},
- {0x09, 0x01, 0xc7, 0xbb},
- {0x34, 0x01, 0x00, 0xbb},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x62, 0x04, 0x11, 0xbb},
- {0x03, 0x01, 0xe0, 0xbb},
- {0x2c, 0x00, 0x2c, 0xbb},
- {0x20, 0xd0, 0x00, 0xbb},
- {0x01, 0x00, 0x08, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0x05, 0x00, 0x20, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x01, 0xcc},
- {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc},
- {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc},
- {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
- {0x35, 0x00, 0xef, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-
-static const u8 mi1310_socinitVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x03, 0xcc},
- {0xb3, 0x23, 0xc0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc},
- {0xb3, 0x17, 0xff, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc},
- {0xb8, 0x00, 0x00, 0xcc},
- {0xbc, 0x00, 0xd0, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0xc8, 0x9f, 0x0b, 0xbb},
- {0x5b, 0x00, 0x01, 0xbb},
- {0x2f, 0xde, 0x20, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
- {0xf0, 0x00, 0x01, 0xbb},
- {0x05, 0x00, 0x07, 0xbb},
- {0x34, 0x00, 0x00, 0xbb},
- {0x35, 0xff, 0x00, 0xbb},
- {0xdc, 0x07, 0x02, 0xbb},
- {0xdd, 0x3c, 0x18, 0xbb},
- {0xde, 0x92, 0x6d, 0xbb},
- {0xdf, 0xcd, 0xb1, 0xbb},
- {0xe0, 0xff, 0xe7, 0xbb},
- {0x06, 0xf0, 0x0d, 0xbb},
- {0x06, 0x70, 0x0e, 0xbb},
- {0x4c, 0x00, 0x01, 0xbb},
- {0x4d, 0x00, 0x01, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x2e, 0x0c, 0x55, 0xbb},
- {0x21, 0xb6, 0x6e, 0xbb},
- {0x36, 0x30, 0x10, 0xbb},
- {0x37, 0x00, 0xc1, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x07, 0x00, 0x84, 0xbb},
- {0x08, 0x02, 0x4a, 0xbb},
- {0x05, 0x01, 0x10, 0xbb},
- {0x06, 0x00, 0x39, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x58, 0x02, 0x67, 0xbb},
- {0x57, 0x02, 0x00, 0xbb},
- {0x5a, 0x02, 0x67, 0xbb},
- {0x59, 0x02, 0x00, 0xbb},
- {0x5c, 0x12, 0x0d, 0xbb},
- {0x5d, 0x16, 0x11, 0xbb},
- {0x39, 0x06, 0x18, 0xbb},
- {0x3a, 0x06, 0x18, 0xbb},
- {0x3b, 0x06, 0x18, 0xbb},
- {0x3c, 0x06, 0x18, 0xbb},
- {0x64, 0x7b, 0x5b, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x36, 0x30, 0x10, 0xbb},
- {0x37, 0x00, 0xc0, 0xbb},
- {0xbc, 0x0e, 0x00, 0xcc},
- {0xbc, 0x0f, 0x05, 0xcc},
- {0xbc, 0x10, 0xc0, 0xcc},
- {0xbc, 0x11, 0x03, 0xcc},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x02, 0xcc},
- {0xb6, 0x02, 0x80, 0xcc},
- {0xb6, 0x05, 0x01, 0xcc},
- {0xb6, 0x04, 0xe0, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x25, 0xcc},
- {0xb6, 0x18, 0x02, 0xcc},
- {0xb6, 0x17, 0x58, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x00, 0xcc},
- {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x80, 0x00, 0x03, 0xbb},
- {0x81, 0xc7, 0x14, 0xbb},
- {0x82, 0xeb, 0xe8, 0xbb},
- {0x83, 0xfe, 0xf4, 0xbb},
- {0x84, 0xcd, 0x10, 0xbb},
- {0x85, 0xf3, 0xee, 0xbb},
- {0x86, 0xff, 0xf1, 0xbb},
- {0x87, 0xcd, 0x10, 0xbb},
- {0x88, 0xf3, 0xee, 0xbb},
- {0x89, 0x01, 0xf1, 0xbb},
- {0x8a, 0xe5, 0x17, 0xbb},
- {0x8b, 0xe8, 0xe2, 0xbb},
- {0x8c, 0xf7, 0xed, 0xbb},
- {0x8d, 0x00, 0xff, 0xbb},
- {0x8e, 0xec, 0x10, 0xbb},
- {0x8f, 0xf0, 0xed, 0xbb},
- {0x90, 0xf9, 0xf2, 0xbb},
- {0x91, 0x00, 0x00, 0xbb},
- {0x92, 0xe9, 0x0d, 0xbb},
- {0x93, 0xf4, 0xf2, 0xbb},
- {0x94, 0xfb, 0xf5, 0xbb},
- {0x95, 0x00, 0xff, 0xbb},
- {0xb6, 0x0f, 0x08, 0xbb},
- {0xb7, 0x3d, 0x16, 0xbb},
- {0xb8, 0x0c, 0x04, 0xbb},
- {0xb9, 0x1c, 0x07, 0xbb},
- {0xba, 0x0a, 0x03, 0xbb},
- {0xbb, 0x1b, 0x09, 0xbb},
- {0xbc, 0x17, 0x0d, 0xbb},
- {0xbd, 0x23, 0x1d, 0xbb},
- {0xbe, 0x00, 0x28, 0xbb},
- {0xbf, 0x11, 0x09, 0xbb},
- {0xc0, 0x16, 0x15, 0xbb},
- {0xc1, 0x00, 0x1b, 0xbb},
- {0xc2, 0x0e, 0x07, 0xbb},
- {0xc3, 0x14, 0x10, 0xbb},
- {0xc4, 0x00, 0x17, 0xbb},
- {0x06, 0x74, 0x8e, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0xf4, 0x8e, 0xbb},
- {0x00, 0x00, 0x50, 0xdd},
- {0x06, 0x74, 0x8e, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x24, 0x50, 0x20, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x34, 0x0c, 0x50, 0xbb},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x03, 0x03, 0xc0, 0xbb},
- {},
-};
-static const u8 mi1310_socinitQVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
- {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
- {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
- {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
- {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
- {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
- {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
- {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
- {0xf0, 0x00, 0x01, 0xbb},
- {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
- {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
- {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
- {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
- {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
- {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
- {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
- {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
- {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
- {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
- {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
- {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
- {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
- {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
- {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
- {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
- {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
- {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
- {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
- {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
- {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
- {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
- {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
- {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
- {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
- {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
- {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
- {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
- {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
- {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
- {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
- {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
- {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
- {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
- {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
- {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
- {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
- {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
- {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
- {0x03, 0x03, 0xc0, 0xbb},
- {},
-};
-static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x0d, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x03, 0xcc},
- {0xb3, 0x23, 0xc0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc},
- {0xb3, 0x17, 0xff, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc},
- {0xb8, 0x00, 0x00, 0xcc},
- {0xbc, 0x00, 0x70, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0xc8, 0x9f, 0x0b, 0xbb},
- {0x5b, 0x00, 0x01, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
- {0xf0, 0x00, 0x01, 0xbb},
- {0x05, 0x00, 0x07, 0xbb},
- {0x34, 0x00, 0x00, 0xbb},
- {0x35, 0xff, 0x00, 0xbb},
- {0xdc, 0x07, 0x02, 0xbb},
- {0xdd, 0x3c, 0x18, 0xbb},
- {0xde, 0x92, 0x6d, 0xbb},
- {0xdf, 0xcd, 0xb1, 0xbb},
- {0xe0, 0xff, 0xe7, 0xbb},
- {0x06, 0xf0, 0x0d, 0xbb},
- {0x06, 0x70, 0x0e, 0xbb},
- {0x4c, 0x00, 0x01, 0xbb},
- {0x4d, 0x00, 0x01, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x2e, 0x0c, 0x60, 0xbb},
- {0x21, 0xb6, 0x6e, 0xbb},
- {0x37, 0x01, 0x40, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x07, 0x00, 0x84, 0xbb},
- {0x08, 0x02, 0x4a, 0xbb},
- {0x05, 0x01, 0x10, 0xbb},
- {0x06, 0x00, 0x39, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x58, 0x02, 0x67, 0xbb},
- {0x57, 0x02, 0x00, 0xbb},
- {0x5a, 0x02, 0x67, 0xbb},
- {0x59, 0x02, 0x00, 0xbb},
- {0x5c, 0x12, 0x0d, 0xbb},
- {0x5d, 0x16, 0x11, 0xbb},
- {0x39, 0x06, 0x18, 0xbb},
- {0x3a, 0x06, 0x18, 0xbb},
- {0x3b, 0x06, 0x18, 0xbb},
- {0x3c, 0x06, 0x18, 0xbb},
- {0x64, 0x7b, 0x5b, 0xbb},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x05, 0xcc},
- {0xb6, 0x02, 0x00, 0xcc},
- {0xb6, 0x05, 0x03, 0xcc},
- {0xb6, 0x04, 0xc0, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x29, 0xcc},
- {0xb6, 0x18, 0x09, 0xcc},
- {0xb6, 0x17, 0x60, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x00, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0x00, 0x00, 0x80, 0xdd},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x22, 0xa0, 0x78, 0xbb},
- {0x23, 0xa0, 0x78, 0xbb},
- {0x24, 0x7f, 0x00, 0xbb},
- {0x28, 0xea, 0x02, 0xbb},
- {0x29, 0x86, 0x7a, 0xbb},
- {0x5e, 0x52, 0x4c, 0xbb},
- {0x5f, 0x20, 0x24, 0xbb},
- {0x60, 0x00, 0x02, 0xbb},
- {0x02, 0x00, 0xee, 0xbb},
- {0x03, 0x39, 0x23, 0xbb},
- {0x04, 0x07, 0x24, 0xbb},
- {0x09, 0x00, 0xc0, 0xbb},
- {0x0a, 0x00, 0x79, 0xbb},
- {0x0b, 0x00, 0x04, 0xbb},
- {0x0c, 0x00, 0x5c, 0xbb},
- {0x0d, 0x00, 0xd9, 0xbb},
- {0x0e, 0x00, 0x53, 0xbb},
- {0x0f, 0x00, 0x21, 0xbb},
- {0x10, 0x00, 0xa4, 0xbb},
- {0x11, 0x00, 0xe5, 0xbb},
- {0x15, 0x00, 0x00, 0xbb},
- {0x16, 0x00, 0x00, 0xbb},
- {0x17, 0x00, 0x00, 0xbb},
- {0x18, 0x00, 0x00, 0xbb},
- {0x19, 0x00, 0x00, 0xbb},
- {0x1a, 0x00, 0x00, 0xbb},
- {0x1b, 0x00, 0x00, 0xbb},
- {0x1c, 0x00, 0x00, 0xbb},
- {0x1d, 0x00, 0x00, 0xbb},
- {0x1e, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x00, 0x20, 0xdd},
- {0x06, 0xf0, 0x8e, 0xbb},
- {0x00, 0x00, 0x80, 0xdd},
- {0x06, 0x70, 0x8e, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x00, 0x00, 0x20, 0xdd},
- {0x5e, 0x6a, 0x53, 0xbb},
- {0x5f, 0x40, 0x2c, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x00, 0x20, 0xdd},
- {0x58, 0x00, 0x00, 0xbb},
- {0x53, 0x09, 0x03, 0xbb},
- {0x54, 0x31, 0x18, 0xbb},
- {0x55, 0x8b, 0x5f, 0xbb},
- {0x56, 0xc0, 0xa9, 0xbb},
- {0x57, 0xe0, 0xd2, 0xbb},
- {0xe1, 0x00, 0x00, 0xbb},
- {0xdc, 0x09, 0x03, 0xbb},
- {0xdd, 0x31, 0x18, 0xbb},
- {0xde, 0x8b, 0x5f, 0xbb},
- {0xdf, 0xc0, 0xa9, 0xbb},
- {0xe0, 0xe0, 0xd2, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0xf0, 0x8e, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x2f, 0xde, 0x20, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x24, 0x50, 0x20, 0xbb},
- {0xbc, 0x0e, 0x00, 0xcc},
- {0xbc, 0x0f, 0x05, 0xcc},
- {0xbc, 0x10, 0xc0, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x34, 0x0c, 0x50, 0xbb},
- {0xbc, 0x11, 0x03, 0xcc},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x80, 0x00, 0x03, 0xbb},
- {0x81, 0xc7, 0x14, 0xbb},
- {0x82, 0xeb, 0xe8, 0xbb},
- {0x83, 0xfe, 0xf4, 0xbb},
- {0x84, 0xcd, 0x10, 0xbb},
- {0x85, 0xf3, 0xee, 0xbb},
- {0x86, 0xff, 0xf1, 0xbb},
- {0x87, 0xcd, 0x10, 0xbb},
- {0x88, 0xf3, 0xee, 0xbb},
- {0x89, 0x01, 0xf1, 0xbb},
- {0x8a, 0xe5, 0x17, 0xbb},
- {0x8b, 0xe8, 0xe2, 0xbb},
- {0x8c, 0xf7, 0xed, 0xbb},
- {0x8d, 0x00, 0xff, 0xbb},
- {0x8e, 0xec, 0x10, 0xbb},
- {0x8f, 0xf0, 0xed, 0xbb},
- {0x90, 0xf9, 0xf2, 0xbb},
- {0x91, 0x00, 0x00, 0xbb},
- {0x92, 0xe9, 0x0d, 0xbb},
- {0x93, 0xf4, 0xf2, 0xbb},
- {0x94, 0xfb, 0xf5, 0xbb},
- {0x95, 0x00, 0xff, 0xbb},
- {0xb6, 0x0f, 0x08, 0xbb},
- {0xb7, 0x3d, 0x16, 0xbb},
- {0xb8, 0x0c, 0x04, 0xbb},
- {0xb9, 0x1c, 0x07, 0xbb},
- {0xba, 0x0a, 0x03, 0xbb},
- {0xbb, 0x1b, 0x09, 0xbb},
- {0xbc, 0x17, 0x0d, 0xbb},
- {0xbd, 0x23, 0x1d, 0xbb},
- {0xbe, 0x00, 0x28, 0xbb},
- {0xbf, 0x11, 0x09, 0xbb},
- {0xc0, 0x16, 0x15, 0xbb},
- {0xc1, 0x00, 0x1b, 0xbb},
- {0xc2, 0x0e, 0x07, 0xbb},
- {0xc3, 0x14, 0x10, 0xbb},
- {0xc4, 0x00, 0x17, 0xbb},
- {0x06, 0x74, 0x8e, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x03, 0x03, 0xc0, 0xbb},
- {}
-};
-
-static const u8 mi1320_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
-};
-static const u8 mi1320_matrix[9] = {
- 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
-};
-static const u8 mi1320_initVGA_data[][4] = {
- {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
- {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
- {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
- {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
- {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
- {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
- {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb},
- {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
- {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb},
- {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb},
- {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb},
- {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb},
- {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb},
- {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb},
- {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb},
- {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb},
- {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb},
- {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb},
- {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb},
- {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb},
- {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb},
- {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb},
- {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb},
- {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb},
- {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb},
- {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb},
- {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb},
- {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb},
- {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb},
- {0x08, 0x00, 0x27, 0xbb},
- {0x20, 0x01, 0x00, 0xbb}, /* h/v flips - was 03 */
- {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb},
- {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb},
- {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb},
- {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb},
- {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
- {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
- {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
- {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
- {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd},
- {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
- {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
- {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc},
- {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc},
- {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc},
- {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
- {}
-};
-static const u8 mi1320_initQVGA_data[][4] = {
- {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
- {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc},
- {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb},
- {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb},
- {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb},
- {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb},
- {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb},
- {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
- {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb},
- {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb},
- {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
- {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb},
- {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb},
- {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb},
- {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb},
- {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb},
- {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb},
- {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb},
- {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb},
- {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb},
- {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
- {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb},
- {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb},
- {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb},
- {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb},
- {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb},
- {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb},
- {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb},
- {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb},
- {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb},
- {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
- {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb},
- {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
- {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb},
- {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb},
- {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb},
- {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb},
- {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb},
- {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb},
- {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb},
- {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
- {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {}
-};
-
-static const u8 mi1320_soc_InitVGA[][4] = {
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x30, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb8, 0x00, 0x00, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0xc8, 0x00, 0x00, 0xbb},
- {0x00, 0x00, 0x30, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x07, 0x00, 0xe0, 0xbb},
- {0x08, 0x00, 0x0b, 0xbb},
- {0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x05, 0x01, 0x78, 0xbb},
- {0x06, 0x00, 0x11, 0xbb},
- {0x07, 0x01, 0x42, 0xbb},
- {0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0x21, 0x80, 0x00, 0xbb},
- {0x22, 0x0d, 0x0f, 0xbb},
- {0x24, 0x80, 0x00, 0xbb},
- {0x59, 0x00, 0xff, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x39, 0x03, 0xca, 0xbb},
- {0x3a, 0x06, 0x80, 0xbb},
- {0x3b, 0x01, 0x52, 0xbb},
- {0x3c, 0x05, 0x40, 0xbb},
- {0x57, 0x01, 0x9c, 0xbb},
- {0x58, 0x01, 0xee, 0xbb},
- {0x59, 0x00, 0xf0, 0xbb},
- {0x5a, 0x01, 0x20, 0xbb},
- {0x5c, 0x1d, 0x17, 0xbb},
- {0x5d, 0x22, 0x1c, 0xbb},
- {0x64, 0x1e, 0x1c, 0xbb},
- {0x5b, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x22, 0xa0, 0x78, 0xbb},
- {0x23, 0xa0, 0x78, 0xbb},
- {0x24, 0x7f, 0x00, 0xbb},
- {0x28, 0xea, 0x02, 0xbb},
- {0x29, 0x86, 0x7a, 0xbb},
- {0x5e, 0x52, 0x4c, 0xbb},
- {0x5f, 0x20, 0x24, 0xbb},
- {0x60, 0x00, 0x02, 0xbb},
- {0x02, 0x00, 0xee, 0xbb},
- {0x03, 0x39, 0x23, 0xbb},
- {0x04, 0x07, 0x24, 0xbb},
- {0x09, 0x00, 0xc0, 0xbb},
- {0x0a, 0x00, 0x79, 0xbb},
- {0x0b, 0x00, 0x04, 0xbb},
- {0x0c, 0x00, 0x5c, 0xbb},
- {0x0d, 0x00, 0xd9, 0xbb},
- {0x0e, 0x00, 0x53, 0xbb},
- {0x0f, 0x00, 0x21, 0xbb},
- {0x10, 0x00, 0xa4, 0xbb},
- {0x11, 0x00, 0xe5, 0xbb},
- {0x15, 0x00, 0x00, 0xbb},
- {0x16, 0x00, 0x00, 0xbb},
- {0x17, 0x00, 0x00, 0xbb},
- {0x18, 0x00, 0x00, 0xbb},
- {0x19, 0x00, 0x00, 0xbb},
- {0x1a, 0x00, 0x00, 0xbb},
- {0x1b, 0x00, 0x00, 0xbb},
- {0x1c, 0x00, 0x00, 0xbb},
- {0x1d, 0x00, 0x00, 0xbb},
- {0x1e, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0xe0, 0x0e, 0xbb},
- {0x06, 0x60, 0x0e, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-static const u8 mi1320_soc_InitQVGA[][4] = {
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x30, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc},
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb8, 0x00, 0x00, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0xc8, 0x00, 0x00, 0xbb},
- {0x00, 0x00, 0x30, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x07, 0x00, 0xe0, 0xbb},
- {0x08, 0x00, 0x0b, 0xbb},
- {0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc},
- {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x05, 0x01, 0x78, 0xbb},
- {0x06, 0x00, 0x11, 0xbb},
- {0x07, 0x01, 0x42, 0xbb},
- {0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0x21, 0x80, 0x00, 0xbb},
- {0x22, 0x0d, 0x0f, 0xbb},
- {0x24, 0x80, 0x00, 0xbb},
- {0x59, 0x00, 0xff, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x39, 0x03, 0xca, 0xbb},
- {0x3a, 0x06, 0x80, 0xbb},
- {0x3b, 0x01, 0x52, 0xbb},
- {0x3c, 0x05, 0x40, 0xbb},
- {0x57, 0x01, 0x9c, 0xbb},
- {0x58, 0x01, 0xee, 0xbb},
- {0x59, 0x00, 0xf0, 0xbb},
- {0x5a, 0x01, 0x20, 0xbb},
- {0x5c, 0x1d, 0x17, 0xbb},
- {0x5d, 0x22, 0x1c, 0xbb},
- {0x64, 0x1e, 0x1c, 0xbb},
- {0x5b, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x22, 0xa0, 0x78, 0xbb},
- {0x23, 0xa0, 0x78, 0xbb},
- {0x24, 0x7f, 0x00, 0xbb},
- {0x28, 0xea, 0x02, 0xbb},
- {0x29, 0x86, 0x7a, 0xbb},
- {0x5e, 0x52, 0x4c, 0xbb},
- {0x5f, 0x20, 0x24, 0xbb},
- {0x60, 0x00, 0x02, 0xbb},
- {0x02, 0x00, 0xee, 0xbb},
- {0x03, 0x39, 0x23, 0xbb},
- {0x04, 0x07, 0x24, 0xbb},
- {0x09, 0x00, 0xc0, 0xbb},
- {0x0a, 0x00, 0x79, 0xbb},
- {0x0b, 0x00, 0x04, 0xbb},
- {0x0c, 0x00, 0x5c, 0xbb},
- {0x0d, 0x00, 0xd9, 0xbb},
- {0x0e, 0x00, 0x53, 0xbb},
- {0x0f, 0x00, 0x21, 0xbb},
- {0x10, 0x00, 0xa4, 0xbb},
- {0x11, 0x00, 0xe5, 0xbb},
- {0x15, 0x00, 0x00, 0xbb},
- {0x16, 0x00, 0x00, 0xbb},
- {0x17, 0x00, 0x00, 0xbb},
- {0x18, 0x00, 0x00, 0xbb},
- {0x19, 0x00, 0x00, 0xbb},
- {0x1a, 0x00, 0x00, 0xbb},
- {0x1b, 0x00, 0x00, 0xbb},
- {0x1c, 0x00, 0x00, 0xbb},
- {0x1d, 0x00, 0x00, 0xbb},
- {0x1e, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0xe0, 0x0e, 0xbb},
- {0x06, 0x60, 0x0e, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-static const u8 mi1320_soc_InitSXGA[][4] = {
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb0, 0x03, 0x19, 0xcc},
- {0x00, 0x00, 0x30, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc},
- {0xb3, 0x02, 0x00, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc},
- {0xb3, 0x23, 0x00, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc},
- {0xb3, 0x17, 0xff, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x00, 0x00, 0x30, 0xdd},
- {0xc8, 0x9f, 0x0b, 0xbb},
- {0x00, 0x00, 0x20, 0xdd},
- {0x5b, 0x00, 0x01, 0xbb},
- {0x00, 0x00, 0x20, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x00, 0x30, 0xdd},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0x00, 0x00, 0x20, 0xdd},
- {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x05, 0x01, 0x78, 0xbb},
- {0x06, 0x00, 0x11, 0xbb},
- {0x07, 0x01, 0x42, 0xbb},
- {0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0x21, 0x80, 0x00, 0xbb},
- {0x22, 0x0d, 0x0f, 0xbb},
- {0x24, 0x80, 0x00, 0xbb},
- {0x59, 0x00, 0xff, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x39, 0x03, 0xca, 0xbb},
- {0x3a, 0x06, 0x80, 0xbb},
- {0x3b, 0x01, 0x52, 0xbb},
- {0x3c, 0x05, 0x40, 0xbb},
- {0x57, 0x01, 0x9c, 0xbb},
- {0x58, 0x01, 0xee, 0xbb},
- {0x59, 0x00, 0xf0, 0xbb},
- {0x5a, 0x01, 0x20, 0xbb},
- {0x5c, 0x1d, 0x17, 0xbb},
- {0x5d, 0x22, 0x1c, 0xbb},
- {0x64, 0x1e, 0x1c, 0xbb},
- {0x5b, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x22, 0xa0, 0x78, 0xbb},
- {0x23, 0xa0, 0x78, 0xbb},
- {0x24, 0x7f, 0x00, 0xbb},
- {0x28, 0xea, 0x02, 0xbb},
- {0x29, 0x86, 0x7a, 0xbb},
- {0x5e, 0x52, 0x4c, 0xbb},
- {0x5f, 0x20, 0x24, 0xbb},
- {0x60, 0x00, 0x02, 0xbb},
- {0x02, 0x00, 0xee, 0xbb},
- {0x03, 0x39, 0x23, 0xbb},
- {0x04, 0x07, 0x24, 0xbb},
- {0x09, 0x00, 0xc0, 0xbb},
- {0x0a, 0x00, 0x79, 0xbb},
- {0x0b, 0x00, 0x04, 0xbb},
- {0x0c, 0x00, 0x5c, 0xbb},
- {0x0d, 0x00, 0xd9, 0xbb},
- {0x0e, 0x00, 0x53, 0xbb},
- {0x0f, 0x00, 0x21, 0xbb},
- {0x10, 0x00, 0xa4, 0xbb},
- {0x11, 0x00, 0xe5, 0xbb},
- {0x15, 0x00, 0x00, 0xbb},
- {0x16, 0x00, 0x00, 0xbb},
- {0x17, 0x00, 0x00, 0xbb},
- {0x18, 0x00, 0x00, 0xbb},
- {0x19, 0x00, 0x00, 0xbb},
- {0x1a, 0x00, 0x00, 0xbb},
- {0x1b, 0x00, 0x00, 0xbb},
- {0x1c, 0x00, 0x00, 0xbb},
- {0x1d, 0x00, 0x00, 0xbb},
- {0x1e, 0x00, 0x00, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x06, 0xe0, 0x0e, 0xbb},
- {0x06, 0x60, 0x0e, 0xbb},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x05, 0x01, 0x13, 0xbb},
- {0x06, 0x00, 0x11, 0xbb},
- {0x07, 0x00, 0x85, 0xbb},
- {0x08, 0x00, 0x27, 0xbb},
- {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
- {0x21, 0x80, 0x00, 0xbb},
- {0x22, 0x0d, 0x0f, 0xbb},
- {0x24, 0x80, 0x00, 0xbb},
- {0x59, 0x00, 0xff, 0xbb},
- {0xf0, 0x00, 0x02, 0xbb},
- {0x39, 0x03, 0x0d, 0xbb},
- {0x3a, 0x06, 0x1b, 0xbb},
- {0x3b, 0x00, 0x95, 0xbb},
- {0x3c, 0x04, 0xdb, 0xbb},
- {0x57, 0x02, 0x00, 0xbb},
- {0x58, 0x02, 0x66, 0xbb},
- {0x59, 0x00, 0xff, 0xbb},
- {0x5a, 0x01, 0x33, 0xbb},
- {0x5c, 0x12, 0x0d, 0xbb},
- {0x5d, 0x16, 0x11, 0xbb},
- {0x64, 0x5e, 0x1c, 0xbb},
- {}
-};
-static const u8 po3130_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
-};
-static const u8 po3130_matrix[9] = {
- 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
-};
-
-static const u8 po3130_initVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
- {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
- {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
- {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
- {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
- {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
- {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
- {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
- {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
- {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
- {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
- {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
- {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
- {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
- {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
- {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
- {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
- {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
- {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
- {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
- {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
- {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
- {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
- {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
- {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
- {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
- {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
- {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
- {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
- {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
- {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
- {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
- {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
- {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
- {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
- {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
- {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
- {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
- {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
- {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
- {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa},
- {0x00, 0x4c, 0x07, 0xaa},
- {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
- {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
-/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
- {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */
- {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
- {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
- {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
- {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
- {}
-};
-static const u8 po3130_rundata[][4] = {
- {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
- {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
- {0x00, 0x44, 0x40, 0xaa},
-/* {0x00, 0xd5, 0x7c, 0xaa}, */
- {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa},
- {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa},
- {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa},
- {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa},
- {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa},
- {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa},
- {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
- {}
-};
-
-static const u8 po3130_initQVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
- {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
- {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
- {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
- {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
- {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
- {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
- {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
- {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
- {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
- {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
- {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
- {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
- {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
- {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
- {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
- {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
- {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
- {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
- {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
- {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
- {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
- {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
- {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
- {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
- {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
- {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
- {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
- {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
- {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
- {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
- {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
- {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
- {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
- {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
- {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
- {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
- {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
- {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
- {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
- {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
- {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa},
- {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
- {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
- {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
- {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
- {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
- {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
- {}
-};
-
-static const u8 hv7131r_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
-};
-static const u8 hv7131r_matrix[9] = {
- 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
-};
-static const u8 hv7131r_initVGA_data[][4] = {
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x20, 0xdd},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x01, 0x45, 0xcc},
- {0xb3, 0x03, 0x0b, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x02, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0x91, 0xcc}, /* i2c add: 11 */
- {0xb3, 0x00, 0x27, 0xcc},
- {0xbc, 0x00, 0x73, 0xcc},
- {0xb8, 0x00, 0x23, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc},
- {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc},
- {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc},
- {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x58, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0x00, 0x01, 0x0c, 0xaa},
- {0x00, 0x14, 0x01, 0xaa},
- {0x00, 0x15, 0xe6, 0xaa},
- {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x17, 0x86, 0xaa},
- {0x00, 0x23, 0x00, 0xaa},
- {0x00, 0x25, 0x03, 0xaa},
- {0x00, 0x26, 0xa9, 0xaa},
- {0x00, 0x27, 0x80, 0xaa},
- {0x00, 0x30, 0x18, 0xaa},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x02, 0xcc},
- {0xb6, 0x02, 0x80, 0xcc},
- {0xb6, 0x05, 0x01, 0xcc},
- {0xb6, 0x04, 0xe0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x02, 0xcc},
- {0xb6, 0x17, 0x58, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-
-static const u8 hv7131r_initQVGA_data[][4] = {
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x20, 0xdd},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x01, 0x45, 0xcc},
- {0xb3, 0x03, 0x0b, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x02, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0x91, 0xcc},
- {0xb3, 0x00, 0x27, 0xcc},
- {0xbc, 0x00, 0xd3, 0xcc},
- {0xb8, 0x00, 0x23, 0xcc},
- {0xb8, 0x2c, 0x50, 0xcc},
- {0xb8, 0x2d, 0xf8, 0xcc},
- {0xb8, 0x2e, 0xf8, 0xcc},
- {0xb8, 0x2f, 0xf8, 0xcc},
- {0xb8, 0x30, 0x50, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf8, 0xcc},
- {0xb8, 0x33, 0xf8, 0xcc},
- {0xb8, 0x34, 0x58, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0x00, 0x01, 0x0c, 0xaa},
- {0x00, 0x14, 0x01, 0xaa},
- {0x00, 0x15, 0xe6, 0xaa},
- {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x17, 0x86, 0xaa},
- {0x00, 0x23, 0x00, 0xaa},
- {0x00, 0x25, 0x03, 0xaa},
- {0x00, 0x26, 0xa9, 0xaa},
- {0x00, 0x27, 0x80, 0xaa},
- {0x00, 0x30, 0x18, 0xaa},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x01, 0xcc},
- {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc},
- {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc},
- {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {}
-};
-
-static const u8 ov7660_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
-};
-static const u8 ov7660_matrix[9] = {
- 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
-};
-static const u8 ov7660_initVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd},
- {0xb0, 0x03, 0x01, 0xcc},
- {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
- {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
- {0xb3, 0x1f, 0x02, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
- {0xb3, 0x00, 0x26, 0xcc},
- {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x8f, 0x50, 0xcc},
- {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
- {0x00, 0x12, 0x80, 0xaa},
- {0x00, 0x12, 0x05, 0xaa},
- {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
- {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
- {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
- {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
- {0x00, 0x13, 0xa7, 0xaa},
- {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
- {0x00, 0x36, 0x00, 0xaa},
- {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
- {0x00, 0x39, 0x43, 0xaa},
- {0x00, 0x8d, 0xcf, 0xaa},
- {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
- {0x00, 0x0f, 0x62, 0xaa},
- {0x00, 0x35, 0x84, 0xaa},
- {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
- {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
- {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
- {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
- {0x00, 0x01, 0x80, 0xaa},
- {0x00, 0x02, 0x80, 0xaa},
- {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
- {0xb9, 0x00, 0x28, 0xcc},
- {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc},
- {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc},
- {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
- {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc},
-
- {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
-
- {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
- {}
-};
-static const u8 ov7660_initQVGA_data[][4] = {
- {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
- {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
- {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
- {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
- {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
- {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
- {0xb8, 0x01, 0x7d, 0xcc},
-/* sizer */
- {0xbc, 0x00, 0xd3, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc},
- {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
- {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa},
- {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */
- {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
- {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
- {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
- {0x00, 0x13, 0xa7, 0xaa},
- {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
- {0x00, 0x36, 0x00, 0xaa},
- {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
- {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa},
- {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
- {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa},
- {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
- {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
- {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
- {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
- {0x00, 0x01, 0x80, 0xaa},
- {0x00, 0x02, 0x80, 0xaa},
-/* sizer filters */
- {0xbc, 0x02, 0x08, 0xcc},
- {0xbc, 0x03, 0x70, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xbc, 0x04, 0x08, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x3c, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x04, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
-/* */
- {0xb8, 0xfe, 0x00, 0xcc},
- {0xb8, 0xff, 0x28, 0xcc},
-/* */
- {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
- {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
- {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
- {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
- {0xb9, 0x08, 0x3c, 0xcc},
-/* */
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc}, /* ff */
- {0x00, 0x29, 0x3c, 0xaa},
- {0xb3, 0x01, 0x45, 0xcc}, /* 45 */
- {}
-};
-
-static const u8 ov7660_50HZ[][4] = {
- {0x00, 0x3b, 0x08, 0xaa},
- {0x00, 0x9d, 0x40, 0xaa},
- {0x00, 0x13, 0xa7, 0xaa},
- {}
-};
-
-static const u8 ov7660_60HZ[][4] = {
- {0x00, 0x3b, 0x00, 0xaa},
- {0x00, 0x9e, 0x40, 0xaa},
- {0x00, 0x13, 0xa7, 0xaa},
- {}
-};
-
-static const u8 ov7660_NoFliker[][4] = {
- {0x00, 0x13, 0x87, 0xaa},
- {}
-};
-
-static const u8 ov7670_InitVGA[][4] = {
- {0xb3, 0x01, 0x05, 0xcc},
- {0x00, 0x00, 0x30, 0xdd},
- {0xb0, 0x03, 0x19, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb3, 0x00, 0x66, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb0, 0x16, 0x01, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xb3, 0x03, 0x1f, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xbc, 0x00, 0x41, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0x00, 0x12, 0x80, 0xaa},
- {0x00, 0x00, 0x20, 0xdd},
- {0x00, 0x12, 0x00, 0xaa},
- {0x00, 0x11, 0x40, 0xaa},
- {0x00, 0x6b, 0x0a, 0xaa},
- {0x00, 0x3a, 0x04, 0xaa},
- {0x00, 0x40, 0xc0, 0xaa},
- {0x00, 0x8c, 0x00, 0xaa},
- {0x00, 0x7a, 0x29, 0xaa},
- {0x00, 0x7b, 0x0e, 0xaa},
- {0x00, 0x7c, 0x1a, 0xaa},
- {0x00, 0x7d, 0x31, 0xaa},
- {0x00, 0x7e, 0x53, 0xaa},
- {0x00, 0x7f, 0x60, 0xaa},
- {0x00, 0x80, 0x6b, 0xaa},
- {0x00, 0x81, 0x73, 0xaa},
- {0x00, 0x82, 0x7b, 0xaa},
- {0x00, 0x83, 0x82, 0xaa},
- {0x00, 0x84, 0x89, 0xaa},
- {0x00, 0x85, 0x96, 0xaa},
- {0x00, 0x86, 0xa1, 0xaa},
- {0x00, 0x87, 0xb7, 0xaa},
- {0x00, 0x88, 0xcc, 0xaa},
- {0x00, 0x89, 0xe1, 0xaa},
- {0x00, 0x13, 0xe0, 0xaa},
- {0x00, 0x00, 0x00, 0xaa},
- {0x00, 0x10, 0x00, 0xaa},
- {0x00, 0x0d, 0x40, 0xaa},
- {0x00, 0x14, 0x28, 0xaa},
- {0x00, 0xa5, 0x05, 0xaa},
- {0x00, 0xab, 0x07, 0xaa},
- {0x00, 0x24, 0x95, 0xaa},
- {0x00, 0x25, 0x33, 0xaa},
- {0x00, 0x26, 0xe3, 0xaa},
- {0x00, 0x9f, 0x88, 0xaa},
- {0x00, 0xa0, 0x78, 0xaa},
- {0x00, 0x55, 0x90, 0xaa},
- {0x00, 0xa1, 0x03, 0xaa},
- {0x00, 0xa6, 0xe0, 0xaa},
- {0x00, 0xa7, 0xd8, 0xaa},
- {0x00, 0xa8, 0xf0, 0xaa},
- {0x00, 0xa9, 0x90, 0xaa},
- {0x00, 0xaa, 0x14, 0xaa},
- {0x00, 0x13, 0xe5, 0xaa},
- {0x00, 0x0e, 0x61, 0xaa},
- {0x00, 0x0f, 0x4b, 0xaa},
- {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
- {0x00, 0x21, 0x02, 0xaa},
- {0x00, 0x22, 0x91, 0xaa},
- {0x00, 0x29, 0x07, 0xaa},
- {0x00, 0x33, 0x0b, 0xaa},
- {0x00, 0x35, 0x0b, 0xaa},
- {0x00, 0x37, 0x1d, 0xaa},
- {0x00, 0x38, 0x71, 0xaa},
- {0x00, 0x39, 0x2a, 0xaa},
- {0x00, 0x3c, 0x78, 0xaa},
- {0x00, 0x4d, 0x40, 0xaa},
- {0x00, 0x4e, 0x20, 0xaa},
- {0x00, 0x74, 0x19, 0xaa},
- {0x00, 0x8d, 0x4f, 0xaa},
- {0x00, 0x8e, 0x00, 0xaa},
- {0x00, 0x8f, 0x00, 0xaa},
- {0x00, 0x90, 0x00, 0xaa},
- {0x00, 0x91, 0x00, 0xaa},
- {0x00, 0x96, 0x00, 0xaa},
- {0x00, 0x9a, 0x80, 0xaa},
- {0x00, 0xb0, 0x84, 0xaa},
- {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0xb2, 0x0e, 0xaa},
- {0x00, 0xb3, 0x82, 0xaa},
- {0x00, 0xb8, 0x0a, 0xaa},
- {0x00, 0x43, 0x14, 0xaa},
- {0x00, 0x44, 0xf0, 0xaa},
- {0x00, 0x45, 0x45, 0xaa},
- {0x00, 0x46, 0x63, 0xaa},
- {0x00, 0x47, 0x2d, 0xaa},
- {0x00, 0x48, 0x46, 0xaa},
- {0x00, 0x59, 0x88, 0xaa},
- {0x00, 0x5a, 0xa0, 0xaa},
- {0x00, 0x5b, 0xc6, 0xaa},
- {0x00, 0x5c, 0x7d, 0xaa},
- {0x00, 0x5d, 0x5f, 0xaa},
- {0x00, 0x5e, 0x19, 0xaa},
- {0x00, 0x6c, 0x0a, 0xaa},
- {0x00, 0x6d, 0x55, 0xaa},
- {0x00, 0x6e, 0x11, 0xaa},
- {0x00, 0x6f, 0x9e, 0xaa},
- {0x00, 0x69, 0x00, 0xaa},
- {0x00, 0x6a, 0x40, 0xaa},
- {0x00, 0x01, 0x40, 0xaa},
- {0x00, 0x02, 0x40, 0xaa},
- {0x00, 0x13, 0xe7, 0xaa},
- {0x00, 0x5f, 0xf0, 0xaa},
- {0x00, 0x60, 0xf0, 0xaa},
- {0x00, 0x61, 0xf0, 0xaa},
- {0x00, 0x27, 0xa0, 0xaa},
- {0x00, 0x28, 0x80, 0xaa},
- {0x00, 0x2c, 0x90, 0xaa},
- {0x00, 0x4f, 0x66, 0xaa},
- {0x00, 0x50, 0x66, 0xaa},
- {0x00, 0x51, 0x00, 0xaa},
- {0x00, 0x52, 0x22, 0xaa},
- {0x00, 0x53, 0x5e, 0xaa},
- {0x00, 0x54, 0x80, 0xaa},
- {0x00, 0x58, 0x9e, 0xaa},
- {0x00, 0x41, 0x08, 0xaa},
- {0x00, 0x3f, 0x00, 0xaa},
- {0x00, 0x75, 0x85, 0xaa},
- {0x00, 0x76, 0xe1, 0xaa},
- {0x00, 0x4c, 0x00, 0xaa},
- {0x00, 0x77, 0x0a, 0xaa},
- {0x00, 0x3d, 0x88, 0xaa},
- {0x00, 0x4b, 0x09, 0xaa},
- {0x00, 0xc9, 0x60, 0xaa},
- {0x00, 0x41, 0x38, 0xaa},
- {0x00, 0x62, 0x30, 0xaa},
- {0x00, 0x63, 0x30, 0xaa},
- {0x00, 0x64, 0x08, 0xaa},
- {0x00, 0x94, 0x07, 0xaa},
- {0x00, 0x95, 0x0b, 0xaa},
- {0x00, 0x65, 0x00, 0xaa},
- {0x00, 0x66, 0x05, 0xaa},
- {0x00, 0x56, 0x50, 0xaa},
- {0x00, 0x34, 0x11, 0xaa},
- {0x00, 0xa4, 0x88, 0xaa},
- {0x00, 0x96, 0x00, 0xaa},
- {0x00, 0x97, 0x30, 0xaa},
- {0x00, 0x98, 0x20, 0xaa},
- {0x00, 0x99, 0x30, 0xaa},
- {0x00, 0x9a, 0x84, 0xaa},
- {0x00, 0x9b, 0x29, 0xaa},
- {0x00, 0x9c, 0x03, 0xaa},
- {0x00, 0x78, 0x04, 0xaa},
- {0x00, 0x79, 0x01, 0xaa},
- {0x00, 0xc8, 0xf0, 0xaa},
- {0x00, 0x79, 0x0f, 0xaa},
- {0x00, 0xc8, 0x00, 0xaa},
- {0x00, 0x79, 0x10, 0xaa},
- {0x00, 0xc8, 0x7e, 0xaa},
- {0x00, 0x79, 0x0a, 0xaa},
- {0x00, 0xc8, 0x80, 0xaa},
- {0x00, 0x79, 0x0b, 0xaa},
- {0x00, 0xc8, 0x01, 0xaa},
- {0x00, 0x79, 0x0c, 0xaa},
- {0x00, 0xc8, 0x0f, 0xaa},
- {0x00, 0x79, 0x0d, 0xaa},
- {0x00, 0xc8, 0x20, 0xaa},
- {0x00, 0x79, 0x09, 0xaa},
- {0x00, 0xc8, 0x80, 0xaa},
- {0x00, 0x79, 0x02, 0xaa},
- {0x00, 0xc8, 0xc0, 0xaa},
- {0x00, 0x79, 0x03, 0xaa},
- {0x00, 0xc8, 0x40, 0xaa},
- {0x00, 0x79, 0x05, 0xaa},
- {0x00, 0xc8, 0x30, 0xaa},
- {0x00, 0x79, 0x26, 0xaa},
- {0x00, 0x11, 0x40, 0xaa},
- {0x00, 0x3a, 0x04, 0xaa},
- {0x00, 0x12, 0x00, 0xaa},
- {0x00, 0x40, 0xc0, 0xaa},
- {0x00, 0x8c, 0x00, 0xaa},
- {0x00, 0x17, 0x14, 0xaa},
- {0x00, 0x18, 0x02, 0xaa},
- {0x00, 0x32, 0x92, 0xaa},
- {0x00, 0x19, 0x02, 0xaa},
- {0x00, 0x1a, 0x7a, 0xaa},
- {0x00, 0x03, 0x0a, 0xaa},
- {0x00, 0x0c, 0x00, 0xaa},
- {0x00, 0x3e, 0x00, 0xaa},
- {0x00, 0x70, 0x3a, 0xaa},
- {0x00, 0x71, 0x35, 0xaa},
- {0x00, 0x72, 0x11, 0xaa},
- {0x00, 0x73, 0xf0, 0xaa},
- {0x00, 0xa2, 0x02, 0xaa},
- {0x00, 0xb1, 0x00, 0xaa},
- {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
- {0x00, 0xaa, 0x14, 0xaa},
- {0x00, 0x24, 0x80, 0xaa},
- {0x00, 0x25, 0x74, 0xaa},
- {0x00, 0x26, 0xd3, 0xaa},
- {0x00, 0x0d, 0x00, 0xaa},
- {0x00, 0x14, 0x18, 0xaa},
- {0x00, 0x9d, 0x99, 0xaa},
- {0x00, 0x9e, 0x7f, 0xaa},
- {0x00, 0x64, 0x08, 0xaa},
- {0x00, 0x94, 0x07, 0xaa},
- {0x00, 0x95, 0x06, 0xaa},
- {0x00, 0x66, 0x05, 0xaa},
- {0x00, 0x41, 0x08, 0xaa},
- {0x00, 0x3f, 0x00, 0xaa},
- {0x00, 0x75, 0x07, 0xaa},
- {0x00, 0x76, 0xe1, 0xaa},
- {0x00, 0x4c, 0x00, 0xaa},
- {0x00, 0x77, 0x00, 0xaa},
- {0x00, 0x3d, 0xc2, 0xaa},
- {0x00, 0x4b, 0x09, 0xaa},
- {0x00, 0xc9, 0x60, 0xaa},
- {0x00, 0x41, 0x38, 0xaa},
- {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x01, 0x45, 0xcc},
- {0x00, 0x77, 0x05, 0xaa},
- {},
-};
-
-static const u8 ov7670_InitQVGA[][4] = {
- {0xb3, 0x01, 0x05, 0xcc},
- {0x00, 0x00, 0x30, 0xdd},
- {0xb0, 0x03, 0x19, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb0, 0x04, 0x02, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb3, 0x00, 0x66, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb0, 0x16, 0x01, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xb3, 0x03, 0x1f, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x04, 0x05, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0x00, 0x12, 0x80, 0xaa},
- {0x00, 0x00, 0x20, 0xdd},
- {0x00, 0x12, 0x00, 0xaa},
- {0x00, 0x11, 0x40, 0xaa},
- {0x00, 0x6b, 0x0a, 0xaa},
- {0x00, 0x3a, 0x04, 0xaa},
- {0x00, 0x40, 0xc0, 0xaa},
- {0x00, 0x8c, 0x00, 0xaa},
- {0x00, 0x7a, 0x29, 0xaa},
- {0x00, 0x7b, 0x0e, 0xaa},
- {0x00, 0x7c, 0x1a, 0xaa},
- {0x00, 0x7d, 0x31, 0xaa},
- {0x00, 0x7e, 0x53, 0xaa},
- {0x00, 0x7f, 0x60, 0xaa},
- {0x00, 0x80, 0x6b, 0xaa},
- {0x00, 0x81, 0x73, 0xaa},
- {0x00, 0x82, 0x7b, 0xaa},
- {0x00, 0x83, 0x82, 0xaa},
- {0x00, 0x84, 0x89, 0xaa},
- {0x00, 0x85, 0x96, 0xaa},
- {0x00, 0x86, 0xa1, 0xaa},
- {0x00, 0x87, 0xb7, 0xaa},
- {0x00, 0x88, 0xcc, 0xaa},
- {0x00, 0x89, 0xe1, 0xaa},
- {0x00, 0x13, 0xe0, 0xaa},
- {0x00, 0x00, 0x00, 0xaa},
- {0x00, 0x10, 0x00, 0xaa},
- {0x00, 0x0d, 0x40, 0xaa},
- {0x00, 0x14, 0x28, 0xaa},
- {0x00, 0xa5, 0x05, 0xaa},
- {0x00, 0xab, 0x07, 0xaa},
- {0x00, 0x24, 0x95, 0xaa},
- {0x00, 0x25, 0x33, 0xaa},
- {0x00, 0x26, 0xe3, 0xaa},
- {0x00, 0x9f, 0x88, 0xaa},
- {0x00, 0xa0, 0x78, 0xaa},
- {0x00, 0x55, 0x90, 0xaa},
- {0x00, 0xa1, 0x03, 0xaa},
- {0x00, 0xa6, 0xe0, 0xaa},
- {0x00, 0xa7, 0xd8, 0xaa},
- {0x00, 0xa8, 0xf0, 0xaa},
- {0x00, 0xa9, 0x90, 0xaa},
- {0x00, 0xaa, 0x14, 0xaa},
- {0x00, 0x13, 0xe5, 0xaa},
- {0x00, 0x0e, 0x61, 0xaa},
- {0x00, 0x0f, 0x4b, 0xaa},
- {0x00, 0x16, 0x02, 0xaa},
- {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */
- {0x00, 0x21, 0x02, 0xaa},
- {0x00, 0x22, 0x91, 0xaa},
- {0x00, 0x29, 0x07, 0xaa},
- {0x00, 0x33, 0x0b, 0xaa},
- {0x00, 0x35, 0x0b, 0xaa},
- {0x00, 0x37, 0x1d, 0xaa},
- {0x00, 0x38, 0x71, 0xaa},
- {0x00, 0x39, 0x2a, 0xaa},
- {0x00, 0x3c, 0x78, 0xaa},
- {0x00, 0x4d, 0x40, 0xaa},
- {0x00, 0x4e, 0x20, 0xaa},
- {0x00, 0x74, 0x19, 0xaa},
- {0x00, 0x8d, 0x4f, 0xaa},
- {0x00, 0x8e, 0x00, 0xaa},
- {0x00, 0x8f, 0x00, 0xaa},
- {0x00, 0x90, 0x00, 0xaa},
- {0x00, 0x91, 0x00, 0xaa},
- {0x00, 0x96, 0x00, 0xaa},
- {0x00, 0x9a, 0x80, 0xaa},
- {0x00, 0xb0, 0x84, 0xaa},
- {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0xb2, 0x0e, 0xaa},
- {0x00, 0xb3, 0x82, 0xaa},
- {0x00, 0xb8, 0x0a, 0xaa},
- {0x00, 0x43, 0x14, 0xaa},
- {0x00, 0x44, 0xf0, 0xaa},
- {0x00, 0x45, 0x45, 0xaa},
- {0x00, 0x46, 0x63, 0xaa},
- {0x00, 0x47, 0x2d, 0xaa},
- {0x00, 0x48, 0x46, 0xaa},
- {0x00, 0x59, 0x88, 0xaa},
- {0x00, 0x5a, 0xa0, 0xaa},
- {0x00, 0x5b, 0xc6, 0xaa},
- {0x00, 0x5c, 0x7d, 0xaa},
- {0x00, 0x5d, 0x5f, 0xaa},
- {0x00, 0x5e, 0x19, 0xaa},
- {0x00, 0x6c, 0x0a, 0xaa},
- {0x00, 0x6d, 0x55, 0xaa},
- {0x00, 0x6e, 0x11, 0xaa},
- {0x00, 0x6f, 0x9e, 0xaa},
- {0x00, 0x69, 0x00, 0xaa},
- {0x00, 0x6a, 0x40, 0xaa},
- {0x00, 0x01, 0x40, 0xaa},
- {0x00, 0x02, 0x40, 0xaa},
- {0x00, 0x13, 0xe7, 0xaa},
- {0x00, 0x5f, 0xf0, 0xaa},
- {0x00, 0x60, 0xf0, 0xaa},
- {0x00, 0x61, 0xf0, 0xaa},
- {0x00, 0x27, 0xa0, 0xaa},
- {0x00, 0x28, 0x80, 0xaa},
- {0x00, 0x2c, 0x90, 0xaa},
- {0x00, 0x4f, 0x66, 0xaa},
- {0x00, 0x50, 0x66, 0xaa},
- {0x00, 0x51, 0x00, 0xaa},
- {0x00, 0x52, 0x22, 0xaa},
- {0x00, 0x53, 0x5e, 0xaa},
- {0x00, 0x54, 0x80, 0xaa},
- {0x00, 0x58, 0x9e, 0xaa},
- {0x00, 0x41, 0x08, 0xaa},
- {0x00, 0x3f, 0x00, 0xaa},
- {0x00, 0x75, 0x85, 0xaa},
- {0x00, 0x76, 0xe1, 0xaa},
- {0x00, 0x4c, 0x00, 0xaa},
- {0x00, 0x77, 0x0a, 0xaa},
- {0x00, 0x3d, 0x88, 0xaa},
- {0x00, 0x4b, 0x09, 0xaa},
- {0x00, 0xc9, 0x60, 0xaa},
- {0x00, 0x41, 0x38, 0xaa},
- {0x00, 0x62, 0x30, 0xaa},
- {0x00, 0x63, 0x30, 0xaa},
- {0x00, 0x64, 0x08, 0xaa},
- {0x00, 0x94, 0x07, 0xaa},
- {0x00, 0x95, 0x0b, 0xaa},
- {0x00, 0x65, 0x00, 0xaa},
- {0x00, 0x66, 0x05, 0xaa},
- {0x00, 0x56, 0x50, 0xaa},
- {0x00, 0x34, 0x11, 0xaa},
- {0x00, 0xa4, 0x88, 0xaa},
- {0x00, 0x96, 0x00, 0xaa},
- {0x00, 0x97, 0x30, 0xaa},
- {0x00, 0x98, 0x20, 0xaa},
- {0x00, 0x99, 0x30, 0xaa},
- {0x00, 0x9a, 0x84, 0xaa},
- {0x00, 0x9b, 0x29, 0xaa},
- {0x00, 0x9c, 0x03, 0xaa},
- {0x00, 0x78, 0x04, 0xaa},
- {0x00, 0x79, 0x01, 0xaa},
- {0x00, 0xc8, 0xf0, 0xaa},
- {0x00, 0x79, 0x0f, 0xaa},
- {0x00, 0xc8, 0x00, 0xaa},
- {0x00, 0x79, 0x10, 0xaa},
- {0x00, 0xc8, 0x7e, 0xaa},
- {0x00, 0x79, 0x0a, 0xaa},
- {0x00, 0xc8, 0x80, 0xaa},
- {0x00, 0x79, 0x0b, 0xaa},
- {0x00, 0xc8, 0x01, 0xaa},
- {0x00, 0x79, 0x0c, 0xaa},
- {0x00, 0xc8, 0x0f, 0xaa},
- {0x00, 0x79, 0x0d, 0xaa},
- {0x00, 0xc8, 0x20, 0xaa},
- {0x00, 0x79, 0x09, 0xaa},
- {0x00, 0xc8, 0x80, 0xaa},
- {0x00, 0x79, 0x02, 0xaa},
- {0x00, 0xc8, 0xc0, 0xaa},
- {0x00, 0x79, 0x03, 0xaa},
- {0x00, 0xc8, 0x40, 0xaa},
- {0x00, 0x79, 0x05, 0xaa},
- {0x00, 0xc8, 0x30, 0xaa},
- {0x00, 0x79, 0x26, 0xaa},
- {0x00, 0x11, 0x40, 0xaa},
- {0x00, 0x3a, 0x04, 0xaa},
- {0x00, 0x12, 0x00, 0xaa},
- {0x00, 0x40, 0xc0, 0xaa},
- {0x00, 0x8c, 0x00, 0xaa},
- {0x00, 0x17, 0x14, 0xaa},
- {0x00, 0x18, 0x02, 0xaa},
- {0x00, 0x32, 0x92, 0xaa},
- {0x00, 0x19, 0x02, 0xaa},
- {0x00, 0x1a, 0x7a, 0xaa},
- {0x00, 0x03, 0x0a, 0xaa},
- {0x00, 0x0c, 0x00, 0xaa},
- {0x00, 0x3e, 0x00, 0xaa},
- {0x00, 0x70, 0x3a, 0xaa},
- {0x00, 0x71, 0x35, 0xaa},
- {0x00, 0x72, 0x11, 0xaa},
- {0x00, 0x73, 0xf0, 0xaa},
- {0x00, 0xa2, 0x02, 0xaa},
- {0x00, 0xb1, 0x00, 0xaa},
- {0x00, 0xb1, 0x0c, 0xaa},
- {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */
- {0x00, 0xaa, 0x14, 0xaa},
- {0x00, 0x24, 0x80, 0xaa},
- {0x00, 0x25, 0x74, 0xaa},
- {0x00, 0x26, 0xd3, 0xaa},
- {0x00, 0x0d, 0x00, 0xaa},
- {0x00, 0x14, 0x18, 0xaa},
- {0x00, 0x9d, 0x99, 0xaa},
- {0x00, 0x9e, 0x7f, 0xaa},
- {0x00, 0x64, 0x08, 0xaa},
- {0x00, 0x94, 0x07, 0xaa},
- {0x00, 0x95, 0x06, 0xaa},
- {0x00, 0x66, 0x05, 0xaa},
- {0x00, 0x41, 0x08, 0xaa},
- {0x00, 0x3f, 0x00, 0xaa},
- {0x00, 0x75, 0x07, 0xaa},
- {0x00, 0x76, 0xe1, 0xaa},
- {0x00, 0x4c, 0x00, 0xaa},
- {0x00, 0x77, 0x00, 0xaa},
- {0x00, 0x3d, 0xc2, 0xaa},
- {0x00, 0x4b, 0x09, 0xaa},
- {0x00, 0xc9, 0x60, 0xaa},
- {0x00, 0x41, 0x38, 0xaa},
- {0xbc, 0x02, 0x18, 0xcc},
- {0xbc, 0x03, 0x50, 0xcc},
- {0xbc, 0x04, 0x18, 0xcc},
- {0xbc, 0x05, 0x00, 0xcc},
- {0xbc, 0x06, 0x00, 0xcc},
- {0xbc, 0x08, 0x30, 0xcc},
- {0xbc, 0x09, 0x40, 0xcc},
- {0xbc, 0x0a, 0x10, 0xcc},
- {0xbc, 0x0b, 0x00, 0xcc},
- {0xbc, 0x0c, 0x00, 0xcc},
- {0xbf, 0xc0, 0x26, 0xcc},
- {0xbf, 0xc1, 0x02, 0xcc},
- {0xbf, 0xcc, 0x04, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x01, 0x45, 0xcc},
- {0x00, 0x77, 0x05, 0xaa},
- {},
-};
-
-/* PO1200 - values from usbvm326.inf and ms-win trace */
-static const u8 po1200_gamma[17] = {
- 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
-};
-static const u8 po1200_matrix[9] = {
- 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
-};
-static const u8 po1200_initVGA_data[][4] = {
- {0xb0, 0x03, 0x19, 0xcc}, /* reset? */
- {0xb0, 0x03, 0x19, 0xcc},
-/* {0x00, 0x00, 0x33, 0xdd}, */
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb0, 0x02, 0x02, 0xcc},
- {0xb3, 0x5d, 0x00, 0xcc},
- {0xb3, 0x01, 0x01, 0xcc},
- {0xb3, 0x00, 0x64, 0xcc},
- {0xb3, 0x00, 0x65, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x02, 0xb2, 0xcc},
- {0xb3, 0x03, 0x18, 0xcc},
- {0xb3, 0x04, 0x15, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x02, 0xcc},
- {0xb3, 0x23, 0x58, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x03, 0xcc},
- {0xb3, 0x17, 0x1f, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xb0, 0x54, 0x13, 0xcc},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xdc, 0xcc}, /* i2c add: 5c */
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x12, 0x05, 0xaa},
- {0x00, 0x13, 0x02, 0xaa},
- {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */
- {0x00, 0x21, 0x00, 0xaa},
- {0x00, 0x25, 0x02, 0xaa},
- {0x00, 0x3c, 0x4f, 0xaa},
- {0x00, 0x3f, 0xe0, 0xaa},
- {0x00, 0x42, 0xff, 0xaa},
- {0x00, 0x45, 0x34, 0xaa},
- {0x00, 0x55, 0xfe, 0xaa},
- {0x00, 0x59, 0xd3, 0xaa},
- {0x00, 0x5e, 0x04, 0xaa},
- {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */
- {0x00, 0x62, 0x02, 0xaa},
- {0x00, 0xa7, 0x31, 0xaa},
- {0x00, 0xa9, 0x66, 0xaa},
- {0x00, 0xb0, 0x00, 0xaa},
- {0x00, 0xb1, 0x00, 0xaa},
- {0x00, 0xb3, 0x11, 0xaa},
- {0x00, 0xb6, 0x26, 0xaa},
- {0x00, 0xb7, 0x20, 0xaa},
- {0x00, 0xba, 0x04, 0xaa},
- {0x00, 0x88, 0x42, 0xaa},
- {0x00, 0x89, 0x9a, 0xaa},
- {0x00, 0x8a, 0x88, 0xaa},
- {0x00, 0x8b, 0x8e, 0xaa},
- {0x00, 0x8c, 0x3e, 0xaa},
- {0x00, 0x8d, 0x90, 0xaa},
- {0x00, 0x8e, 0x87, 0xaa},
- {0x00, 0x8f, 0x96, 0xaa},
- {0x00, 0x90, 0x3d, 0xaa},
- {0x00, 0x64, 0x00, 0xaa},
- {0x00, 0x65, 0x10, 0xaa},
- {0x00, 0x66, 0x20, 0xaa},
- {0x00, 0x67, 0x2b, 0xaa},
- {0x00, 0x68, 0x36, 0xaa},
- {0x00, 0x69, 0x49, 0xaa},
- {0x00, 0x6a, 0x5a, 0xaa},
- {0x00, 0x6b, 0x7f, 0xaa},
- {0x00, 0x6c, 0x9b, 0xaa},
- {0x00, 0x6d, 0xba, 0xaa},
- {0x00, 0x6e, 0xd4, 0xaa},
- {0x00, 0x6f, 0xea, 0xaa},
- {0x00, 0x70, 0x00, 0xaa},
- {0x00, 0x71, 0x10, 0xaa},
- {0x00, 0x72, 0x20, 0xaa},
- {0x00, 0x73, 0x2b, 0xaa},
- {0x00, 0x74, 0x36, 0xaa},
- {0x00, 0x75, 0x49, 0xaa},
- {0x00, 0x76, 0x5a, 0xaa},
- {0x00, 0x77, 0x7f, 0xaa},
- {0x00, 0x78, 0x9b, 0xaa},
- {0x00, 0x79, 0xba, 0xaa},
- {0x00, 0x7a, 0xd4, 0xaa},
- {0x00, 0x7b, 0xea, 0xaa},
- {0x00, 0x7c, 0x00, 0xaa},
- {0x00, 0x7d, 0x10, 0xaa},
- {0x00, 0x7e, 0x20, 0xaa},
- {0x00, 0x7f, 0x2b, 0xaa},
- {0x00, 0x80, 0x36, 0xaa},
- {0x00, 0x81, 0x49, 0xaa},
- {0x00, 0x82, 0x5a, 0xaa},
- {0x00, 0x83, 0x7f, 0xaa},
- {0x00, 0x84, 0x9b, 0xaa},
- {0x00, 0x85, 0xba, 0xaa},
- {0x00, 0x86, 0xd4, 0xaa},
- {0x00, 0x87, 0xea, 0xaa},
- {0x00, 0x57, 0x2a, 0xaa},
- {0x00, 0x03, 0x01, 0xaa},
- {0x00, 0x04, 0x10, 0xaa},
- {0x00, 0x05, 0x10, 0xaa},
- {0x00, 0x06, 0x10, 0xaa},
- {0x00, 0x07, 0x10, 0xaa},
- {0x00, 0x08, 0x13, 0xaa},
- {0x00, 0x0a, 0x00, 0xaa},
- {0x00, 0x0b, 0x10, 0xaa},
- {0x00, 0x0c, 0x20, 0xaa},
- {0x00, 0x0d, 0x18, 0xaa},
- {0x00, 0x22, 0x01, 0xaa},
- {0x00, 0x23, 0x60, 0xaa},
- {0x00, 0x25, 0x08, 0xaa},
- {0x00, 0x26, 0x82, 0xaa},
- {0x00, 0x2e, 0x0f, 0xaa},
- {0x00, 0x2f, 0x1e, 0xaa},
- {0x00, 0x30, 0x2d, 0xaa},
- {0x00, 0x31, 0x3c, 0xaa},
- {0x00, 0x32, 0x4b, 0xaa},
- {0x00, 0x33, 0x5a, 0xaa},
- {0x00, 0x34, 0x69, 0xaa},
- {0x00, 0x35, 0x78, 0xaa},
- {0x00, 0x36, 0x87, 0xaa},
- {0x00, 0x37, 0x96, 0xaa},
- {0x00, 0x38, 0xa5, 0xaa},
- {0x00, 0x39, 0xb4, 0xaa},
- {0x00, 0x3a, 0xc3, 0xaa},
- {0x00, 0x3b, 0xd2, 0xaa},
- {0x00, 0x3c, 0xe1, 0xaa},
- {0x00, 0x3e, 0xff, 0xaa},
- {0x00, 0x3f, 0xff, 0xaa},
- {0x00, 0x40, 0xff, 0xaa},
- {0x00, 0x41, 0xff, 0xaa},
- {0x00, 0x42, 0xff, 0xaa},
- {0x00, 0x43, 0xff, 0xaa},
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x20, 0xc4, 0xaa},
- {0x00, 0x13, 0x03, 0xaa},
- {0x00, 0x3c, 0x50, 0xaa},
- {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */
- {0x00, 0x51, 0x5b, 0xaa},
- {0x00, 0x52, 0x91, 0xaa},
- {0x00, 0x53, 0x4c, 0xaa},
- {0x00, 0x54, 0x50, 0xaa},
- {0x00, 0x56, 0x02, 0xaa},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x03, 0xcc},
- {0xb6, 0x02, 0x20, 0xcc},
- {0xb6, 0x05, 0x02, 0xcc},
- {0xb6, 0x04, 0x58, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x21, 0xcc},
- {0xb6, 0x18, 0x03, 0xcc},
- {0xb6, 0x17, 0xa9, 0xcc},
- {0xb6, 0x16, 0x80, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x00, 0xcc},
- {0xb8, 0x06, 0x20, 0xcc},
- {0xb8, 0x07, 0x03, 0xcc},
- {0xb8, 0x08, 0x58, 0xcc},
- {0xb8, 0x09, 0x02, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0xd9, 0x0f, 0xaa},
- {0x00, 0xda, 0xaa, 0xaa},
- {0x00, 0xd9, 0x10, 0xaa},
- {0x00, 0xda, 0xaa, 0xaa},
- {0x00, 0xd9, 0x11, 0xaa},
- {0x00, 0xda, 0x00, 0xaa},
- {0x00, 0xd9, 0x12, 0xaa},
- {0x00, 0xda, 0xff, 0xaa},
- {0x00, 0xd9, 0x13, 0xaa},
- {0x00, 0xda, 0xff, 0xaa},
- {0x00, 0xe8, 0x11, 0xaa},
- {0x00, 0xe9, 0x12, 0xaa},
- {0x00, 0xea, 0x5c, 0xaa},
- {0x00, 0xeb, 0xff, 0xaa},
- {0x00, 0xd8, 0x80, 0xaa},
- {0x00, 0xe6, 0x02, 0xaa},
- {0x00, 0xd6, 0x40, 0xaa},
- {0x00, 0xe3, 0x05, 0xaa},
- {0x00, 0xe0, 0x40, 0xaa},
- {0x00, 0xde, 0x03, 0xaa},
- {0x00, 0xdf, 0x03, 0xaa},
- {0x00, 0xdb, 0x02, 0xaa},
- {0x00, 0xdc, 0x00, 0xaa},
- {0x00, 0xdd, 0x03, 0xaa},
- {0x00, 0xe1, 0x08, 0xaa},
- {0x00, 0xe2, 0x01, 0xaa},
- {0x00, 0xd6, 0x40, 0xaa},
- {0x00, 0xe4, 0x40, 0xaa},
- {0x00, 0xa8, 0x8f, 0xaa},
- {0x00, 0xb4, 0x16, 0xaa},
- {0xb0, 0x02, 0x06, 0xcc},
- {0xb0, 0x18, 0x06, 0xcc},
- {0xb0, 0x19, 0x06, 0xcc},
- {0xb3, 0x5d, 0x18, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0x00, 0xb4, 0x0e, 0xaa},
- {0x00, 0xb5, 0x49, 0xaa},
- {0x00, 0xb6, 0x1c, 0xaa},
- {0x00, 0xb7, 0x96, 0xaa},
-/* end of usbvm326.inf - start of ms-win trace */
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x13, 0x3d, 0xcc},
-/*read b306*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x1a, 0x09, 0xaa},
- {0x00, 0x1b, 0x8a, 0xaa},
-/*read b827*/
- {0xb8, 0x27, 0x00, 0xcc},
- {0xb8, 0x26, 0x60, 0xcc},
- {0xb8, 0x26, 0x60, 0xcc},
-/*gamma - to do?*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0xae, 0x84, 0xaa},
-/*gamma again*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x96, 0xa0, 0xaa},
-/*matrix*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x91, 0x35, 0xaa},
- {0x00, 0x92, 0x22, 0xaa},
-/*gamma*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x95, 0x85, 0xaa},
-/*matrix*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x4d, 0x20, 0xaa},
- {0xb8, 0x22, 0x40, 0xcc},
- {0xb8, 0x23, 0x40, 0xcc},
- {0xb8, 0x24, 0x40, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0x00, 0x00, 0x64, 0xdd},
- {0x00, 0x03, 0x01, 0xaa},
-/*read 46*/
- {0x00, 0x46, 0x3c, 0xaa},
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0x16, 0x40, 0xaa},
- {0x00, 0x17, 0x40, 0xaa},
- {0x00, 0x18, 0x40, 0xaa},
- {0x00, 0x19, 0x41, 0xaa},
- {0x00, 0x03, 0x01, 0xaa},
- {0x00, 0x46, 0x3c, 0xaa},
- {0x00, 0x00, 0x18, 0xdd},
-/*read bfff*/
- {0x00, 0x03, 0x00, 0xaa},
- {0x00, 0xb4, 0x1c, 0xaa},
- {0x00, 0xb5, 0x92, 0xaa},
- {0x00, 0xb6, 0x39, 0xaa},
- {0x00, 0xb7, 0x24, 0xaa},
-/*write 89 0400 1415*/
- {}
-};
-
-static const u8 poxxxx_init_common[][4] = {
- {0xb3, 0x00, 0x04, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb3, 0x00, 0x64, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb3, 0x00, 0x65, 0xcc},
- {0x00, 0x00, 0x10, 0xdd},
- {0xb3, 0x00, 0x67, 0xcc},
- {0xb0, 0x03, 0x09, 0xcc},
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
- {0xb3, 0x02, 0xb0, 0xcc},
- {0xb3, 0x03, 0x18, 0xcc},
- {0xb3, 0x04, 0x15, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */
- {0xb3, 0x23, 0x00, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */
- {0xb3, 0x17, 0xff, 0xcc},
- {0xb3, 0x2c, 0x03, 0xcc},
- {0xb3, 0x2d, 0x56, 0xcc},
- {0xb3, 0x2e, 0x02, 0xcc},
- {0xb3, 0x2f, 0x0a, 0xcc},
- {0xb3, 0x40, 0x00, 0xcc},
- {0xb3, 0x41, 0x34, 0xcc},
- {0xb3, 0x42, 0x01, 0xcc},
- {0xb3, 0x43, 0xe0, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xbc, 0x01, 0x01, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0xb3, 0x4d, 0x00, 0xcc},
- {0x00, 0x0b, 0x2a, 0xaa},
- {0x00, 0x0e, 0x03, 0xaa},
- {0x00, 0x0f, 0xea, 0xaa},
- {0x00, 0x12, 0x08, 0xaa},
- {0x00, 0x1e, 0x06, 0xaa},
- {0x00, 0x21, 0x00, 0xaa},
- {0x00, 0x31, 0x1f, 0xaa},
- {0x00, 0x33, 0x38, 0xaa},
- {0x00, 0x36, 0xc0, 0xaa},
- {0x00, 0x37, 0xc8, 0xaa},
- {0x00, 0x3b, 0x36, 0xaa},
- {0x00, 0x4b, 0xfe, 0xaa},
- {0x00, 0x4d, 0x2e, 0xaa},
- {0x00, 0x51, 0x1c, 0xaa},
- {0x00, 0x52, 0x01, 0xaa},
- {0x00, 0x55, 0x0a, 0xaa},
- {0x00, 0x56, 0x0a, 0xaa},
- {0x00, 0x57, 0x07, 0xaa},
- {0x00, 0x58, 0x07, 0xaa},
- {0x00, 0x59, 0x04, 0xaa},
- {0x00, 0x70, 0x68, 0xaa},
- {0x00, 0x71, 0x04, 0xaa},
- {0x00, 0x72, 0x10, 0xaa},
- {0x00, 0x80, 0x71, 0xaa},
- {0x00, 0x81, 0x08, 0xaa},
- {0x00, 0x82, 0x00, 0xaa},
- {0x00, 0x83, 0x55, 0xaa},
- {0x00, 0x84, 0x06, 0xaa},
- {0x00, 0x85, 0x06, 0xaa},
- {0x00, 0x8b, 0x25, 0xaa},
- {0x00, 0x8c, 0x00, 0xaa},
- {0x00, 0x8d, 0x86, 0xaa},
- {0x00, 0x8e, 0x82, 0xaa},
- {0x00, 0x8f, 0x2d, 0xaa},
- {0x00, 0x90, 0x8b, 0xaa},
- {0x00, 0x91, 0x81, 0xaa},
- {0x00, 0x92, 0x81, 0xaa},
- {0x00, 0x93, 0x23, 0xaa},
- {0x00, 0xa3, 0x2a, 0xaa},
- {0x00, 0xa4, 0x03, 0xaa},
- {0x00, 0xa5, 0xea, 0xaa},
- {0x00, 0xb0, 0x68, 0xaa},
- {0x00, 0xbc, 0x04, 0xaa},
- {0x00, 0xbe, 0x3b, 0xaa},
- {0x00, 0x4e, 0x40, 0xaa},
- {0x00, 0x06, 0x04, 0xaa},
- {0x00, 0x07, 0x03, 0xaa},
- {0x00, 0xcd, 0x18, 0xaa},
- {0x00, 0x28, 0x03, 0xaa},
- {0x00, 0x29, 0xef, 0xaa},
-/* reinit on alt 2 (qvga) or alt7 (vga) */
- {0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0xb8, 0x00, 0x01, 0xcc},
-
- {0x00, 0x1d, 0x85, 0xaa},
- {0x00, 0x1e, 0xc6, 0xaa},
- {0x00, 0x00, 0x40, 0xdd},
- {0x00, 0x1d, 0x05, 0xaa},
- {}
-};
-static const u8 poxxxx_gamma[][4] = {
- {0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */
- {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x0a, 0xaa},
- {0x00, 0x75, 0x16, 0xaa},
- {0x00, 0x76, 0x25, 0xaa},
- {0x00, 0x77, 0x34, 0xaa},
- {0x00, 0x78, 0x49, 0xaa},
- {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa},
- {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa},
- {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa},
-
- {0x00, 0xd6, 0x62, 0xaa}, /* gamma 1 */
- {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x0a, 0xaa},
- {0x00, 0x75, 0x16, 0xaa},
- {0x00, 0x76, 0x25, 0xaa},
- {0x00, 0x77, 0x34, 0xaa},
- {0x00, 0x78, 0x49, 0xaa},
- {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa},
- {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa},
- {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa},
-
- {0x00, 0xd6, 0xa2, 0xaa}, /* gamma 2 */
- {0x00, 0x73, 0x00, 0xaa},
- {0x00, 0x74, 0x0a, 0xaa},
- {0x00, 0x75, 0x16, 0xaa},
- {0x00, 0x76, 0x25, 0xaa},
- {0x00, 0x77, 0x34, 0xaa},
- {0x00, 0x78, 0x49, 0xaa},
- {0x00, 0x79, 0x5a, 0xaa},
- {0x00, 0x7a, 0x7f, 0xaa},
- {0x00, 0x7b, 0x9b, 0xaa},
- {0x00, 0x7c, 0xba, 0xaa},
- {0x00, 0x7d, 0xd4, 0xaa},
- {0x00, 0x7e, 0xea, 0xaa},
- {}
-};
-static const u8 poxxxx_init_start_3[][4] = {
- {0x00, 0xb8, 0x28, 0xaa},
- {0x00, 0xb9, 0x1e, 0xaa},
- {0x00, 0xb6, 0x14, 0xaa},
- {0x00, 0xb7, 0x0f, 0xaa},
- {0x00, 0x5c, 0x10, 0xaa},
- {0x00, 0x5d, 0x18, 0xaa},
- {0x00, 0x5e, 0x24, 0xaa},
- {0x00, 0x5f, 0x24, 0xaa},
- {0x00, 0x86, 0x1a, 0xaa},
- {0x00, 0x60, 0x00, 0xaa},
- {0x00, 0x61, 0x1b, 0xaa},
- {0x00, 0x62, 0x30, 0xaa},
- {0x00, 0x63, 0x40, 0xaa},
- {0x00, 0x87, 0x1a, 0xaa},
- {0x00, 0x64, 0x00, 0xaa},
- {0x00, 0x65, 0x08, 0xaa},
- {0x00, 0x66, 0x10, 0xaa},
- {0x00, 0x67, 0x20, 0xaa},
- {0x00, 0x88, 0x10, 0xaa},
- {0x00, 0x68, 0x00, 0xaa},
- {0x00, 0x69, 0x08, 0xaa},
- {0x00, 0x6a, 0x0f, 0xaa},
- {0x00, 0x6b, 0x0f, 0xaa},
- {0x00, 0x89, 0x07, 0xaa},
- {0x00, 0xd5, 0x4c, 0xaa},
- {0x00, 0x0a, 0x00, 0xaa},
- {0x00, 0x0b, 0x2a, 0xaa},
- {0x00, 0x0e, 0x03, 0xaa},
- {0x00, 0x0f, 0xea, 0xaa},
- {0x00, 0xa2, 0x00, 0xaa},
- {0x00, 0xa3, 0x2a, 0xaa},
- {0x00, 0xa4, 0x03, 0xaa},
- {0x00, 0xa5, 0xea, 0xaa},
- {}
-};
-static const u8 poxxxx_initVGA[][4] = {
- {0x00, 0x20, 0x11, 0xaa},
- {0x00, 0x33, 0x38, 0xaa},
- {0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x02, 0xb0, 0xcc},
- {0xb3, 0x06, 0x00, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0x00, 0x04, 0x06, 0xaa},
- {0x00, 0x05, 0x3f, 0xaa},
- {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
- {}
-};
-static const u8 poxxxx_initQVGA[][4] = {
- {0x00, 0x20, 0x33, 0xaa},
- {0x00, 0x33, 0x38, 0xaa},
- {0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */
- {0xb3, 0x23, 0xf0, 0xcc},
- {0xb3, 0x16, 0x01, 0xcc},
- {0xb3, 0x17, 0x3f, 0xcc},
- {0xb3, 0x02, 0xb0, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x5c, 0x00, 0xcc},
- {0x00, 0x04, 0x06, 0xaa},
- {0x00, 0x05, 0x3f, 0xaa},
- {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
- {}
-};
-static const u8 poxxxx_init_end_1[][4] = {
- {0x00, 0x47, 0x25, 0xaa},
- {0x00, 0x48, 0x80, 0xaa},
- {0x00, 0x49, 0x1f, 0xaa},
- {0x00, 0x4a, 0x40, 0xaa},
- {0x00, 0x44, 0x40, 0xaa},
- {0x00, 0xab, 0x4a, 0xaa},
- {0x00, 0xb1, 0x00, 0xaa},
- {0x00, 0xb2, 0x04, 0xaa},
- {0x00, 0xb3, 0x08, 0xaa},
- {0x00, 0xb4, 0x0b, 0xaa},
- {0x00, 0xb5, 0x0d, 0xaa},
- {}
-};
-static const u8 poxxxx_init_end_2[][4] = {
- {0x00, 0x1d, 0x85, 0xaa},
- {0x00, 0x1e, 0x06, 0xaa},
- {0x00, 0x1d, 0x05, 0xaa},
- {}
-};
-
-struct sensor_info {
- s8 sensorId;
- u8 I2cAdd;
- u8 IdAdd;
- u16 VpId;
- u8 m1;
- u8 m2;
- u8 op;
-};
-
-/* probe values */
-static const struct sensor_info vc0321_probe_data[] = {
-/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
-/* 0 OV9640 */
- {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
-/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
- {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
-/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
- {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 3 MI1310 */
- {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 4 MI360 - tested in vc032x_probe_sensor */
-/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
-/* 5 7131R */
- {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
-/* 6 OV7649 */
- {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
-/* 7 PAS302BCW */
- {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
-/* 8 OV7660 */
- {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
-/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
-/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
-/* 10 PO1030KC */
- {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 11 MI1310_SOC */
- {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
-/* 12 OV9650 */
- {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
-/* 13 S5K532 */
- {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
-/* 14 MI360_SOC - ??? */
-/* 15 PO1200N */
- {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
-/* 16 PO3030K */
- {-1, 0x80 | 0x18, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 17 PO2030 */
- {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* ?? */
- {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
- {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
-};
-static const struct sensor_info vc0323_probe_data[] = {
-/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
-/* 0 OV9640 */
- {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
-/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
- {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
-/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
- {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 3 MI1310 */
- {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 4 MI360 - tested in vc032x_probe_sensor */
-/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
-/* 5 7131R */
- {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
-/* 6 OV7649 */
- {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
-/* 7 PAS302BCW */
- {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
-/* 8 OV7660 */
- {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
-/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
-/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
-/* 10 PO1030KC */
- {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* 11 MI1310_SOC */
- {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
-/* 12 OV9650 */
- {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
-/* 13 S5K532 */
- {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
-/* 14 MI360_SOC - ??? */
-/* 15 PO1200N */
- {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
-/* 16 ?? */
- {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
-/* 17 PO2030 */
- {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* ?? */
- {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
- {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
-/*fixme: not in the ms-win probe - may be found before? */
- {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
-};
-
-/* read 'len' bytes in gspca_dev->usb_buf */
-static void reg_r_i(struct gspca_dev *gspca_dev,
- u16 req,
- u16 index,
- u16 len)
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1, /* value */
- index, gspca_dev->usb_buf, len,
- 500);
- if (ret < 0) {
- pr_err("reg_r err %d\n", ret);
- gspca_dev->usb_err = ret;
- }
-}
-static void reg_r(struct gspca_dev *gspca_dev,
- u16 req,
- u16 index,
- u16 len)
-{
- reg_r_i(gspca_dev, req, index, len);
-#ifdef GSPCA_DEBUG
- if (gspca_dev->usb_err < 0)
- return;
- if (len == 1)
- PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
- gspca_dev->usb_buf[0]);
- else
- PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x",
- req, index,
- gspca_dev->usb_buf[0],
- gspca_dev->usb_buf[1],
- gspca_dev->usb_buf[2]);
-#endif
-}
-
-static void reg_w_i(struct gspca_dev *gspca_dev,
- u16 req,
- u16 value,
- u16 index)
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return;
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, NULL, 0,
- 500);
- if (ret < 0) {
- pr_err("reg_w err %d\n", ret);
- gspca_dev->usb_err = ret;
- }
-}
-static void reg_w(struct gspca_dev *gspca_dev,
- u16 req,
- u16 value,
- u16 index)
-{
-#ifdef GSPCA_DEBUG
- if (gspca_dev->usb_err < 0)
- return;
- PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
-#endif
- reg_w_i(gspca_dev, req, value, index);
-}
-
-static u16 read_sensor_register(struct gspca_dev *gspca_dev,
- u16 address)
-{
- u8 ldata, mdata, hdata;
- int retry = 50;
-
- reg_r(gspca_dev, 0xa1, 0xb33f, 1);
- if (!(gspca_dev->usb_buf[0] & 0x02)) {
- pr_err("I2c Bus Busy Wait %02x\n", gspca_dev->usb_buf[0]);
- return 0;
- }
- reg_w(gspca_dev, 0xa0, address, 0xb33a);
- reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
-
- do {
- reg_r(gspca_dev, 0xa1, 0xb33b, 1);
- if (gspca_dev->usb_buf[0] == 0x00)
- break;
- msleep(40);
- } while (--retry >= 0);
-
- reg_r(gspca_dev, 0xa1, 0xb33e, 1);
- ldata = gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0xa1, 0xb33d, 1);
- mdata = gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0xa1, 0xb33c, 1);
- hdata = gspca_dev->usb_buf[0];
- if (hdata != 0 && mdata != 0 && ldata != 0)
- PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
- hdata, mdata, ldata);
- reg_r(gspca_dev, 0xa1, 0xb334, 1);
- if (gspca_dev->usb_buf[0] == 0x02)
- return (hdata << 8) + mdata;
- return hdata;
-}
-
-static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i, n;
- u16 value;
- const struct sensor_info *ptsensor_info;
-
-/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
- if (sd->flags & FL_SAMSUNG) {
- reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
- reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
- /* select the back sensor */
- }
-
- reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
- PDEBUG(D_PROBE, "vc032%d check sensor header %02x",
- sd->bridge == BRIDGE_VC0321 ? 1 : 3, gspca_dev->usb_buf[0]);
- if (sd->bridge == BRIDGE_VC0321) {
- ptsensor_info = vc0321_probe_data;
- n = ARRAY_SIZE(vc0321_probe_data);
- } else {
- ptsensor_info = vc0323_probe_data;
- n = ARRAY_SIZE(vc0323_probe_data);
- }
- for (i = 0; i < n; i++) {
- reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
- reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
- reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
- reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
- reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
- reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
- reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
- value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
- if (value == 0 && ptsensor_info->IdAdd == 0x82)
- value = read_sensor_register(gspca_dev, 0x83);
- if (value != 0) {
- PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
- value, i);
- if (value == ptsensor_info->VpId)
- return ptsensor_info->sensorId;
-
- switch (value) {
- case 0x3130:
- return SENSOR_PO3130NC;
- case 0x7673:
- return SENSOR_OV7670;
- case 0x8243:
- return SENSOR_MI0360;
- }
- }
- ptsensor_info++;
- }
- return -1;
-}
-
-static void i2c_write(struct gspca_dev *gspca_dev,
- u8 reg, const u8 *val,
- u8 size) /* 1 or 2 */
-{
- int retry;
-
-#ifdef GSPCA_DEBUG
- if (gspca_dev->usb_err < 0)
- return;
- if (size == 1)
- PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
- else
- PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
-#endif
- reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
-/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
- reg_w_i(gspca_dev, 0xa0, size, 0xb334);
- reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
- reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
- if (size > 1)
- reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
- reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
- retry = 4;
- do {
- reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
- if (gspca_dev->usb_buf[0] == 0)
- break;
- msleep(20);
- } while (--retry > 0);
- if (retry <= 0)
- pr_err("i2c_write timeout\n");
-}
-
-static void put_tab_to_reg(struct gspca_dev *gspca_dev,
- const u8 *tab, u8 tabsize, u16 addr)
-{
- int j;
- u16 ad = addr;
-
- for (j = 0; j < tabsize; j++)
- reg_w(gspca_dev, 0xa0, tab[j], ad++);
-}
-
-static void usb_exchange(struct gspca_dev *gspca_dev,
- const u8 data[][4])
-{
- int i = 0;
-
- for (;;) {
- switch (data[i][3]) {
- default:
- return;
- case 0xcc: /* normal write */
- reg_w(gspca_dev, 0xa0, data[i][2],
- (data[i][0]) << 8 | data[i][1]);
- break;
- case 0xaa: /* i2c op */
- i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
- break;
- case 0xbb: /* i2c op */
- i2c_write(gspca_dev, data[i][0], &data[i][1], 2);
- break;
- case 0xdd:
- msleep(data[i][1] * 256 + data[i][2] + 10);
- break;
- }
- i++;
- }
- /*not reached*/
-}
-
-
-/* this function is called at probe time */
-static int sd_config(struct gspca_dev *gspca_dev,
- const struct usb_device_id *id)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->bridge = id->driver_info >> 8;
- sd->flags = id->driver_info & 0xff;
-
- if (id->idVendor == 0x046d &&
- (id->idProduct == 0x0892 || id->idProduct == 0x0896))
- sd->sensor = SENSOR_POxxxx; /* no probe */
-
- 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;
- struct cam *cam;
- int sensor;
- /* number of packets per ISOC message */
- static u8 npkt[NSENSORS] = {
- [SENSOR_HV7131R] = 64,
- [SENSOR_MI0360] = 32,
- [SENSOR_MI1310_SOC] = 32,
- [SENSOR_MI1320] = 64,
- [SENSOR_MI1320_SOC] = 128,
- [SENSOR_OV7660] = 32,
- [SENSOR_OV7670] = 64,
- [SENSOR_PO1200] = 128,
- [SENSOR_PO3130NC] = 128,
- [SENSOR_POxxxx] = 128,
- };
-
- if (sd->sensor != SENSOR_POxxxx)
- sensor = vc032x_probe_sensor(gspca_dev);
- else
- sensor = sd->sensor;
-
- switch (sensor) {
- case -1:
- pr_err("Unknown sensor...\n");
- return -EINVAL;
- case SENSOR_HV7131R:
- PDEBUG(D_PROBE, "Find Sensor HV7131R");
- break;
- case SENSOR_MI0360:
- PDEBUG(D_PROBE, "Find Sensor MI0360");
- sd->bridge = BRIDGE_VC0323;
- break;
- case SENSOR_MI1310_SOC:
- PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
- break;
- case SENSOR_MI1320:
- PDEBUG(D_PROBE, "Find Sensor MI1320");
- break;
- case SENSOR_MI1320_SOC:
- PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
- break;
- case SENSOR_OV7660:
- PDEBUG(D_PROBE, "Find Sensor OV7660");
- break;
- case SENSOR_OV7670:
- PDEBUG(D_PROBE, "Find Sensor OV7670");
- break;
- case SENSOR_PO1200:
- PDEBUG(D_PROBE, "Find Sensor PO1200");
- break;
- case SENSOR_PO3130NC:
- PDEBUG(D_PROBE, "Find Sensor PO3130NC");
- break;
- case SENSOR_POxxxx:
- PDEBUG(D_PROBE, "Sensor POxxxx");
- break;
- }
- sd->sensor = sensor;
-
- cam = &gspca_dev->cam;
- if (sd->bridge == BRIDGE_VC0321) {
- cam->cam_mode = vc0321_mode;
- cam->nmodes = ARRAY_SIZE(vc0321_mode);
- } else {
- switch (sensor) {
- case SENSOR_PO1200:
- cam->cam_mode = svga_mode;
- cam->nmodes = ARRAY_SIZE(svga_mode);
- break;
- case SENSOR_MI1310_SOC:
- cam->cam_mode = vc0323_mode;
- cam->nmodes = ARRAY_SIZE(vc0323_mode);
- break;
- case SENSOR_MI1320_SOC:
- cam->cam_mode = bi_mode;
- cam->nmodes = ARRAY_SIZE(bi_mode);
- break;
- case SENSOR_OV7670:
- cam->cam_mode = bi_mode;
- cam->nmodes = ARRAY_SIZE(bi_mode) - 1;
- break;
- default:
- cam->cam_mode = vc0323_mode;
- cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
- break;
- }
- }
- cam->npkt = npkt[sd->sensor];
-
- if (sd->sensor == SENSOR_OV7670)
- sd->flags |= FL_HFLIP | FL_VFLIP;
-
- if (sd->bridge == BRIDGE_VC0321) {
- reg_r(gspca_dev, 0x8a, 0, 3);
- reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
- reg_r(gspca_dev, 0x8b, 0, 3);
- reg_w(gspca_dev, 0x88, 0x00, 0x0202);
- if (sd->sensor == SENSOR_POxxxx) {
- reg_r(gspca_dev, 0xa1, 0xb300, 1);
- if (gspca_dev->usb_buf[0] != 0) {
- reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
- reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
- }
- reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
- }
- }
- return gspca_dev->usb_err;
-}
-
-static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
-{
- u8 data;
-
- data = val;
- if (data >= 0x80)
- data &= 0x7f;
- else
- data = 0xff ^ data;
- i2c_write(gspca_dev, 0x98, &data, 1);
-}
-
-static void setcontrast(struct gspca_dev *gspca_dev, u8 val)
-{
- i2c_write(gspca_dev, 0x99, &val, 1);
-}
-
-static void setcolors(struct gspca_dev *gspca_dev, u8 val)
-{
- u8 data;
-
- data = val - (val >> 3) - 1;
- i2c_write(gspca_dev, 0x94, &data, 1);
- i2c_write(gspca_dev, 0x95, &val, 1);
-}
-
-static void sethvflip(struct gspca_dev *gspca_dev, bool hflip, bool vflip)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 data[2];
-
- if (sd->flags & FL_HFLIP)
- hflip = !hflip;
- if (sd->flags & FL_VFLIP)
- vflip = !vflip;
- switch (sd->sensor) {
- case SENSOR_MI1310_SOC:
- case SENSOR_MI1320:
- case SENSOR_MI1320_SOC:
- data[0] = data[1] = 0; /* select page 0 */
- i2c_write(gspca_dev, 0xf0, data, 2);
- data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
- data[1] = 0x02 * hflip
- | 0x01 * vflip;
- i2c_write(gspca_dev, 0x20, data, 2);
- break;
- case SENSOR_OV7660:
- case SENSOR_OV7670:
- data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
- data[0] |= OV7660_MVFP_MIRROR * hflip
- | OV7660_MVFP_VFLIP * vflip;
- i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
- break;
- case SENSOR_PO1200:
- data[0] = 0;
- i2c_write(gspca_dev, 0x03, data, 1);
- data[0] = 0x80 * hflip
- | 0x40 * vflip
- | 0x06;
- i2c_write(gspca_dev, 0x1e, data, 1);
- break;
- }
-}
-
-static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- static const u8 (*ov7660_freq_tb[3])[4] =
- {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
-
- if (sd->sensor != SENSOR_OV7660)
- return;
- usb_exchange(gspca_dev, ov7660_freq_tb[val]);
-}
-
-static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 data;
-
- switch (sd->sensor) {
- case SENSOR_PO1200:
- data = 0;
- i2c_write(gspca_dev, 0x03, &data, 1);
- if (val < 0)
- data = 0x6a;
- else
- data = 0xb5 + val * 3;
- i2c_write(gspca_dev, 0x61, &data, 1);
- break;
- case SENSOR_POxxxx:
- if (val < 0)
- data = 0x7e; /* def = max */
- else
- data = 0x60 + val * 0x0f;
- i2c_write(gspca_dev, 0x59, &data, 1);
- break;
- }
-}
-static void setgain(struct gspca_dev *gspca_dev, u8 val)
-{
- i2c_write(gspca_dev, 0x15, &val, 1);
-}
-
-static void setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- u8 data;
-
- data = val >> 8;
- i2c_write(gspca_dev, 0x1a, &data, 1);
- data = val;
- i2c_write(gspca_dev, 0x1b, &data, 1);
-}
-
-static void setautogain(struct gspca_dev *gspca_dev, s32 val)
-{
- static const u8 data[2] = {0x28, 0x3c};
-
- i2c_write(gspca_dev, 0xd1, &data[val], 1);
-}
-
-static void setgamma(struct gspca_dev *gspca_dev)
-{
-/*fixme:to do */
- usb_exchange(gspca_dev, poxxxx_gamma);
-}
-
-static void setbacklight(struct gspca_dev *gspca_dev, s32 val)
-{
- u16 v;
- u8 data;
-
- data = (val << 4) | 0x0f;
- i2c_write(gspca_dev, 0xaa, &data, 1);
- v = 613 + 12 * val;
- data = v >> 8;
- i2c_write(gspca_dev, 0xc4, &data, 1);
- data = v;
- i2c_write(gspca_dev, 0xc5, &data, 1);
- v = 1093 - 12 * val;
- data = v >> 8;
- i2c_write(gspca_dev, 0xc6, &data, 1);
- data = v;
- i2c_write(gspca_dev, 0xc7, &data, 1);
- v = 342 + 9 * val;
- data = v >> 8;
- i2c_write(gspca_dev, 0xc8, &data, 1);
- data = v;
- i2c_write(gspca_dev, 0xc9, &data, 1);
- v = 702 - 9 * val;
- data = v >> 8;
- i2c_write(gspca_dev, 0xca, &data, 1);
- data = v;
- i2c_write(gspca_dev, 0xcb, &data, 1);
-}
-
-static void setwb(struct gspca_dev *gspca_dev)
-{
-/*fixme:to do - valid when reg d1 = 0x1c - (reg16 + reg15 = 0xa3)*/
- static const u8 data[2] = {0x00, 0x00};
-
- i2c_write(gspca_dev, 0x16, &data[0], 1);
- i2c_write(gspca_dev, 0x18, &data[1], 1);
-}
-
-static int sd_start(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- const u8 (*init)[4];
- const u8 *GammaT = NULL;
- const u8 *MatrixT = NULL;
- int mode;
- static const u8 (*mi1320_soc_init[])[4] = {
- mi1320_soc_InitSXGA,
- mi1320_soc_InitVGA,
- mi1320_soc_InitQVGA,
- };
-
-/*fixme: back sensor only*/
- if (sd->flags & FL_SAMSUNG) {
- reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
- reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
- reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
- }
-
- /* Assume start use the good resolution from gspca_dev->mode */
- if (sd->bridge == BRIDGE_VC0321) {
- reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
- reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
- reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
- reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
- sd->image_offset = 46;
- } else {
- if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
- == V4L2_PIX_FMT_JPEG)
- sd->image_offset = 0;
- else
- sd->image_offset = 32;
- }
-
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- GammaT = hv7131r_gamma;
- MatrixT = hv7131r_matrix;
- if (mode)
- init = hv7131r_initQVGA_data; /* 320x240 */
- else
- init = hv7131r_initVGA_data; /* 640x480 */
- break;
- case SENSOR_OV7660:
- GammaT = ov7660_gamma;
- MatrixT = ov7660_matrix;
- if (mode)
- init = ov7660_initQVGA_data; /* 320x240 */
- else
- init = ov7660_initVGA_data; /* 640x480 */
- break;
- case SENSOR_MI0360:
- GammaT = mi1320_gamma;
- MatrixT = mi0360_matrix;
- if (mode)
- init = mi0360_initQVGA_JPG; /* 320x240 */
- else
- init = mi0360_initVGA_JPG; /* 640x480 */
- break;
- case SENSOR_MI1310_SOC:
- GammaT = mi1320_gamma;
- MatrixT = mi1320_matrix;
- switch (mode) {
- case 1:
- init = mi1310_socinitQVGA_JPG; /* 320x240 */
- break;
- case 0:
- init = mi1310_socinitVGA_JPG; /* 640x480 */
- break;
- default:
- init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
- break;
- }
- break;
- case SENSOR_MI1320:
- GammaT = mi1320_gamma;
- MatrixT = mi1320_matrix;
- if (mode)
- init = mi1320_initQVGA_data; /* 320x240 */
- else
- init = mi1320_initVGA_data; /* 640x480 */
- break;
- case SENSOR_MI1320_SOC:
- GammaT = mi1320_gamma;
- MatrixT = mi1320_matrix;
- init = mi1320_soc_init[mode];
- break;
- case SENSOR_OV7670:
- init = mode == 1 ? ov7670_InitVGA : ov7670_InitQVGA;
- break;
- case SENSOR_PO3130NC:
- GammaT = po3130_gamma;
- MatrixT = po3130_matrix;
- if (mode)
- init = po3130_initQVGA_data; /* 320x240 */
- else
- init = po3130_initVGA_data; /* 640x480 */
- usb_exchange(gspca_dev, init);
- init = po3130_rundata;
- break;
- case SENSOR_PO1200:
- GammaT = po1200_gamma;
- MatrixT = po1200_matrix;
- init = po1200_initVGA_data;
- break;
- default:
-/* case SENSOR_POxxxx: */
- usb_exchange(gspca_dev, poxxxx_init_common);
- setgamma(gspca_dev);
- usb_exchange(gspca_dev, poxxxx_init_start_3);
- if (mode)
- init = poxxxx_initQVGA;
- else
- init = poxxxx_initVGA;
- usb_exchange(gspca_dev, init);
- reg_r(gspca_dev, 0x8c, 0x0000, 3);
- reg_w(gspca_dev, 0xa0,
- gspca_dev->usb_buf[2] & 1 ? 0 : 1,
- 0xb35c);
- msleep(300);
-/*fixme: i2c read 04 and 05*/
- init = poxxxx_init_end_1;
- break;
- }
- usb_exchange(gspca_dev, init);
- if (GammaT && MatrixT) {
- put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
- put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
- put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
- put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
-
- switch (sd->sensor) {
- case SENSOR_PO1200:
- case SENSOR_HV7131R:
- reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
- break;
- case SENSOR_MI1310_SOC:
- reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
- break;
- }
- msleep(100);
- }
- switch (sd->sensor) {
- case SENSOR_OV7670:
- reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
- reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
- reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
- break;
- case SENSOR_POxxxx:
- usb_exchange(gspca_dev, poxxxx_init_end_2);
- setwb(gspca_dev);
- msleep(80); /* led on */
- reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
- break;
- }
- return gspca_dev->usb_err;
-}
-
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- switch (sd->sensor) {
- case SENSOR_MI1310_SOC:
- reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
- break;
- case SENSOR_POxxxx:
- return;
- default:
- if (!(sd->flags & FL_SAMSUNG))
- reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
- break;
- }
- reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
- reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
-}
-
-/* called on streamoff with alt 0 and on disconnect */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- if (!gspca_dev->present)
- return;
-/*fixme: is this useful?*/
- if (sd->sensor == SENSOR_MI1310_SOC)
- reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
- else if (!(sd->flags & FL_SAMSUNG))
- reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
-
- if (sd->sensor == SENSOR_POxxxx) {
- reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
- reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
- reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
- }
-}
-
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
- u8 *data, /* isoc packet */
- int len) /* iso pkt length */
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- if (data[0] == 0xff && data[1] == 0xd8) {
- PDEBUG(D_PACK,
- "vc032x header packet found len %d", len);
- gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
- data += sd->image_offset;
- len -= sd->image_offset;
- gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
- return;
- }
-
- /* The vc0321 sends some additional data after sending the complete
- * frame, we ignore this. */
- if (sd->bridge == BRIDGE_VC0321) {
- int size, l;
-
- l = gspca_dev->image_len;
- size = gspca_dev->frsz;
- if (len > size - l)
- len = size - l;
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
-}
-
-static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct gspca_dev *gspca_dev =
- container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
- struct sd *sd = (struct sd *)gspca_dev;
-
- gspca_dev->usb_err = 0;
-
- if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY)
- return 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- setbrightness(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_CONTRAST:
- setcontrast(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_SATURATION:
- setcolors(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_HFLIP:
- sethvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
- break;
- case V4L2_CID_SHARPNESS:
- setsharpness(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_AUTOGAIN:
- setautogain(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_GAIN:
- setgain(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_EXPOSURE:
- setexposure(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_BACKLIGHT_COMPENSATION:
- setbacklight(gspca_dev, ctrl->val);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- setlightfreq(gspca_dev, ctrl->val);
- break;
- }
- return gspca_dev->usb_err;
-}
-
-static const struct v4l2_ctrl_ops sd_ctrl_ops = {
- .s_ctrl = sd_s_ctrl,
-};
-
-static int sd_init_controls(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *)gspca_dev;
- struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
- bool has_brightness = false;
- bool has_contrast = false;
- bool has_sat = false;
- bool has_hvflip = false;
- bool has_freq = false;
- bool has_backlight = false;
- bool has_exposure = false;
- bool has_autogain = false;
- bool has_gain = false;
- bool has_sharpness = false;
-
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- case SENSOR_MI0360:
- case SENSOR_PO3130NC:
- break;
- case SENSOR_MI1310_SOC:
- case SENSOR_MI1320:
- case SENSOR_MI1320_SOC:
- case SENSOR_OV7660:
- has_hvflip = true;
- break;
- case SENSOR_OV7670:
- has_hvflip = has_freq = true;
- break;
- case SENSOR_PO1200:
- has_hvflip = has_sharpness = true;
- break;
- case SENSOR_POxxxx:
- has_brightness = has_contrast = has_sat = has_backlight =
- has_exposure = has_autogain = has_gain =
- has_sharpness = true;
- break;
- }
-
- gspca_dev->vdev.ctrl_handler = hdl;
- v4l2_ctrl_handler_init(hdl, 8);
- if (has_brightness)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
- if (has_contrast)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 127);
- if (has_sat)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_SATURATION, 1, 127, 1, 63);
- if (has_hvflip) {
- sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- }
- if (has_sharpness)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_SHARPNESS, -1, 2, 1, -1);
- if (has_freq)
- v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
- V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
- V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
- if (has_autogain)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- if (has_gain)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_GAIN, 0, 78, 1, 0);
- if (has_exposure)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_EXPOSURE, 0, 4095, 1, 450);
- if (has_backlight)
- v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
- V4L2_CID_BACKLIGHT_COMPENSATION, 0, 15, 1, 15);
-
- if (hdl->error) {
- pr_err("Could not initialize controls\n");
- return hdl->error;
- }
- if (sd->hflip)
- v4l2_ctrl_cluster(2, &sd->hflip);
- return 0;
-}
-
-/* sub-driver description */
-static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
- .init_controls = sd_init_controls,
- .config = sd_config,
- .init = sd_init,
- .start = sd_start,
- .stopN = sd_stopN,
- .stop0 = sd_stop0,
- .pkt_scan = sd_pkt_scan,
-};
-
-/* -- module initialisation -- */
-#define BF(bridge, flags) \
- .driver_info = (BRIDGE_ ## bridge << 8) \
- | (flags)
-static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
- {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
- {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
- {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
- {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)},
- {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)},
- {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
- {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
- {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
- {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
- {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
- {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
- {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},
- {}
-};
-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,
- .reset_resume = gspca_resume,
-#endif
-};
-
-module_usb_driver(sd_driver);
diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile
deleted file mode 100644
index 52f057f24e39..000000000000
--- a/drivers/media/video/hdpvr/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
-
-obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
-
-ccflags-y += -Idrivers/media/video
-
-ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
deleted file mode 100644
index 351e9bafe8fe..000000000000
--- a/drivers/media/video/imx074.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Driver for IMX074 CMOS Image Sensor from Sony
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * Partially inspired by the IMX074 driver from the Android / MSM tree
- *
- * 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/delay.h>
-#include <linux/i2c.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
-
-/* IMX074 registers */
-
-#define MODE_SELECT 0x0100
-#define IMAGE_ORIENTATION 0x0101
-#define GROUPED_PARAMETER_HOLD 0x0104
-
-/* Integration Time */
-#define COARSE_INTEGRATION_TIME_HI 0x0202
-#define COARSE_INTEGRATION_TIME_LO 0x0203
-/* Gain */
-#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204
-#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205
-
-/* PLL registers */
-#define PRE_PLL_CLK_DIV 0x0305
-#define PLL_MULTIPLIER 0x0307
-#define PLSTATIM 0x302b
-#define VNDMY_ABLMGSHLMT 0x300a
-#define Y_OPBADDR_START_DI 0x3014
-/* mode setting */
-#define FRAME_LENGTH_LINES_HI 0x0340
-#define FRAME_LENGTH_LINES_LO 0x0341
-#define LINE_LENGTH_PCK_HI 0x0342
-#define LINE_LENGTH_PCK_LO 0x0343
-#define YADDR_START 0x0347
-#define YADDR_END 0x034b
-#define X_OUTPUT_SIZE_MSB 0x034c
-#define X_OUTPUT_SIZE_LSB 0x034d
-#define Y_OUTPUT_SIZE_MSB 0x034e
-#define Y_OUTPUT_SIZE_LSB 0x034f
-#define X_EVEN_INC 0x0381
-#define X_ODD_INC 0x0383
-#define Y_EVEN_INC 0x0385
-#define Y_ODD_INC 0x0387
-
-#define HMODEADD 0x3001
-#define VMODEADD 0x3016
-#define VAPPLINE_START 0x3069
-#define VAPPLINE_END 0x306b
-#define SHUTTER 0x3086
-#define HADDAVE 0x30e8
-#define LANESEL 0x3301
-
-/* IMX074 supported geometry */
-#define IMX074_WIDTH 1052
-#define IMX074_HEIGHT 780
-
-/* IMX074 has only one fixed colorspace per pixelcode */
-struct imx074_datafmt {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-struct imx074 {
- struct v4l2_subdev subdev;
- const struct imx074_datafmt *fmt;
-};
-
-static const struct imx074_datafmt imx074_colour_fmts[] = {
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
-};
-
-static struct imx074 *to_imx074(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct imx074, subdev);
-}
-
-/* Find a data format by a pixel code in an array */
-static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++)
- if (imx074_colour_fmts[i].code == code)
- return imx074_colour_fmts + i;
-
- return NULL;
-}
-
-static int reg_write(struct i2c_client *client, const u16 addr, const u8 data)
-{
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg;
- unsigned char tx[3];
- int ret;
-
- msg.addr = client->addr;
- msg.buf = tx;
- msg.len = 3;
- msg.flags = 0;
-
- tx[0] = addr >> 8;
- tx[1] = addr & 0xff;
- tx[2] = data;
-
- ret = i2c_transfer(adap, &msg, 1);
-
- mdelay(2);
-
- return ret == 1 ? 0 : -EIO;
-}
-
-static int reg_read(struct i2c_client *client, const u16 addr)
-{
- u8 buf[2] = {addr >> 8, addr & 0xff};
- int ret;
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 2,
- .buf = buf,
- }, {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 2,
- .buf = buf,
- },
- };
-
- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (ret < 0) {
- dev_warn(&client->dev, "Reading register %x from %x failed\n",
- addr, client->addr);
- return ret;
- }
-
- return buf[0] & 0xff; /* no sign-extension */
-}
-
-static int imx074_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code);
-
- dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
-
- if (!fmt) {
- mf->code = imx074_colour_fmts[0].code;
- mf->colorspace = imx074_colour_fmts[0].colorspace;
- }
-
- mf->width = IMX074_WIDTH;
- mf->height = IMX074_HEIGHT;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int imx074_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct imx074 *priv = to_imx074(client);
-
- dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
-
- /* MIPI CSI could have changed the format, double-check */
- if (!imx074_find_datafmt(mf->code))
- return -EINVAL;
-
- imx074_try_fmt(sd, mf);
-
- priv->fmt = imx074_find_datafmt(mf->code);
-
- return 0;
-}
-
-static int imx074_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct imx074 *priv = to_imx074(client);
-
- const struct imx074_datafmt *fmt = priv->fmt;
-
- mf->code = fmt->code;
- mf->colorspace = fmt->colorspace;
- mf->width = IMX074_WIDTH;
- mf->height = IMX074_HEIGHT;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct v4l2_rect *rect = &a->c;
-
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rect->top = 0;
- rect->left = 0;
- rect->width = IMX074_WIDTH;
- rect->height = IMX074_HEIGHT;
-
- return 0;
-}
-
-static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = IMX074_WIDTH;
- a->bounds.height = IMX074_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
- return -EINVAL;
-
- *code = imx074_colour_fmts[index].code;
- return 0;
-}
-
-static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- /* MODE_SELECT: stream or standby */
- return reg_write(client, MODE_SELECT, !!enable);
-}
-
-static int imx074_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_IMX074;
- id->revision = 0;
-
- return 0;
-}
-
-static int imx074_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- cfg->type = V4L2_MBUS_CSI2;
- cfg->flags = V4L2_MBUS_CSI2_2_LANE |
- V4L2_MBUS_CSI2_CHANNEL_0 |
- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
- .s_stream = imx074_s_stream,
- .s_mbus_fmt = imx074_s_fmt,
- .g_mbus_fmt = imx074_g_fmt,
- .try_mbus_fmt = imx074_try_fmt,
- .enum_mbus_fmt = imx074_enum_fmt,
- .g_crop = imx074_g_crop,
- .cropcap = imx074_cropcap,
- .g_mbus_config = imx074_g_mbus_config,
-};
-
-static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
- .g_chip_ident = imx074_g_chip_ident,
-};
-
-static struct v4l2_subdev_ops imx074_subdev_ops = {
- .core = &imx074_subdev_core_ops,
- .video = &imx074_subdev_video_ops,
-};
-
-static int imx074_video_probe(struct i2c_client *client)
-{
- int ret;
- u16 id;
-
- /* Read sensor Model ID */
- ret = reg_read(client, 0);
- if (ret < 0)
- return ret;
-
- id = ret << 8;
-
- ret = reg_read(client, 1);
- if (ret < 0)
- return ret;
-
- id |= ret;
-
- dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
-
- if (id != 0x74)
- return -ENODEV;
-
- /* PLL Setting EXTCLK=24MHz, 22.5times */
- reg_write(client, PLL_MULTIPLIER, 0x2D);
- reg_write(client, PRE_PLL_CLK_DIV, 0x02);
- reg_write(client, PLSTATIM, 0x4B);
-
- /* 2-lane mode */
- reg_write(client, 0x3024, 0x00);
-
- reg_write(client, IMAGE_ORIENTATION, 0x00);
-
- /* select RAW mode:
- * 0x08+0x08 = top 8 bits
- * 0x0a+0x08 = compressed 8-bits
- * 0x0a+0x0a = 10 bits
- */
- reg_write(client, 0x0112, 0x08);
- reg_write(client, 0x0113, 0x08);
-
- /* Base setting for High frame mode */
- reg_write(client, VNDMY_ABLMGSHLMT, 0x80);
- reg_write(client, Y_OPBADDR_START_DI, 0x08);
- reg_write(client, 0x3015, 0x37);
- reg_write(client, 0x301C, 0x01);
- reg_write(client, 0x302C, 0x05);
- reg_write(client, 0x3031, 0x26);
- reg_write(client, 0x3041, 0x60);
- reg_write(client, 0x3051, 0x24);
- reg_write(client, 0x3053, 0x34);
- reg_write(client, 0x3057, 0xC0);
- reg_write(client, 0x305C, 0x09);
- reg_write(client, 0x305D, 0x07);
- reg_write(client, 0x3060, 0x30);
- reg_write(client, 0x3065, 0x00);
- reg_write(client, 0x30AA, 0x08);
- reg_write(client, 0x30AB, 0x1C);
- reg_write(client, 0x30B0, 0x32);
- reg_write(client, 0x30B2, 0x83);
- reg_write(client, 0x30D3, 0x04);
- reg_write(client, 0x3106, 0x78);
- reg_write(client, 0x310C, 0x82);
- reg_write(client, 0x3304, 0x05);
- reg_write(client, 0x3305, 0x04);
- reg_write(client, 0x3306, 0x11);
- reg_write(client, 0x3307, 0x02);
- reg_write(client, 0x3308, 0x0C);
- reg_write(client, 0x3309, 0x06);
- reg_write(client, 0x330A, 0x08);
- reg_write(client, 0x330B, 0x04);
- reg_write(client, 0x330C, 0x08);
- reg_write(client, 0x330D, 0x06);
- reg_write(client, 0x330E, 0x01);
- reg_write(client, 0x3381, 0x00);
-
- /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */
- /* 1608 = 1560 + 48 (black lines) */
- reg_write(client, FRAME_LENGTH_LINES_HI, 0x06);
- reg_write(client, FRAME_LENGTH_LINES_LO, 0x48);
- reg_write(client, YADDR_START, 0x00);
- reg_write(client, YADDR_END, 0x2F);
- /* 0x838 == 2104 */
- reg_write(client, X_OUTPUT_SIZE_MSB, 0x08);
- reg_write(client, X_OUTPUT_SIZE_LSB, 0x38);
- /* 0x618 == 1560 */
- reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06);
- reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18);
- reg_write(client, X_EVEN_INC, 0x01);
- reg_write(client, X_ODD_INC, 0x03);
- reg_write(client, Y_EVEN_INC, 0x01);
- reg_write(client, Y_ODD_INC, 0x03);
- reg_write(client, HMODEADD, 0x00);
- reg_write(client, VMODEADD, 0x16);
- reg_write(client, VAPPLINE_START, 0x24);
- reg_write(client, VAPPLINE_END, 0x53);
- reg_write(client, SHUTTER, 0x00);
- reg_write(client, HADDAVE, 0x80);
-
- reg_write(client, LANESEL, 0x00);
-
- reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */
-
- return 0;
-}
-
-static int imx074_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct imx074 *priv;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "IMX074: missing platform data!\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
- return -EIO;
- }
-
- priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
-
- priv->fmt = &imx074_colour_fmts[0];
-
- ret = imx074_video_probe(client);
- if (ret < 0) {
- kfree(priv);
- return ret;
- }
-
- return ret;
-}
-
-static int imx074_remove(struct i2c_client *client)
-{
- struct imx074 *priv = to_imx074(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- if (icl->free_bus)
- icl->free_bus(icl);
- kfree(priv);
-
- return 0;
-}
-
-static const struct i2c_device_id imx074_id[] = {
- { "imx074", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, imx074_id);
-
-static struct i2c_driver imx074_i2c_driver = {
- .driver = {
- .name = "imx074",
- },
- .probe = imx074_probe,
- .remove = imx074_remove,
- .id_table = imx074_id,
-};
-
-module_i2c_driver(imx074_i2c_driver);
-
-MODULE_DESCRIPTION("Sony IMX074 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
deleted file mode 100644
index 77de8a45b46f..000000000000
--- a/drivers/media/video/ivtv/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
- ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
- ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
- ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
- ivtv-vbi.o ivtv-yuv.o
-
-obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
-obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
-
-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-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
deleted file mode 100644
index 9ff69b5a87e2..000000000000
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ /dev/null
@@ -1,1038 +0,0 @@
-/*
- file operation functions
- Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
- Copyright (C) 2004 Chris Kennedy <c@groovy.org>
- Copyright (C) 2005-2007 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
- */
-
-#include "ivtv-driver.h"
-#include "ivtv-fileops.h"
-#include "ivtv-i2c.h"
-#include "ivtv-queue.h"
-#include "ivtv-udma.h"
-#include "ivtv-irq.h"
-#include "ivtv-vbi.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-routing.h"
-#include "ivtv-streams.h"
-#include "ivtv-yuv.h"
-#include "ivtv-ioctl.h"
-#include "ivtv-cards.h"
-#include "ivtv-firmware.h"
-#include <media/v4l2-event.h>
-#include <media/saa7115.h>
-
-/* This function tries to claim the stream for a specific file descriptor.
- If no one else is using this stream then the stream is claimed and
- associated VBI streams are also automatically claimed.
- Possible error returns: -EBUSY if someone else has claimed
- the stream or 0 on success. */
-static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
-{
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[type];
- struct ivtv_stream *s_vbi;
- int vbi_type;
-
- if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
- /* someone already claimed this stream */
- if (s->fh == &id->fh) {
- /* yes, this file descriptor did. So that's OK. */
- return 0;
- }
- 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->fh = &id->fh;
- IVTV_DEBUG_INFO("Start Read VBI\n");
- return 0;
- }
- /* someone else is using this stream already */
- IVTV_DEBUG_INFO("Stream %d is busy\n", type);
- return -EBUSY;
- }
- 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);
- }
-
- /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI,
- IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI
- (provided VBI insertion is on and sliced VBI is selected), for all
- other streams we're done */
- if (type == IVTV_DEC_STREAM_TYPE_MPG) {
- vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
- } else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
- itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
- vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
- } else {
- return 0;
- }
- s_vbi = &itv->streams[vbi_type];
-
- if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) {
- /* Enable reinsertion interrupt */
- if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI)
- ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
- }
- /* mark that it is used internally */
- set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags);
- return 0;
-}
-
-/* This function releases a previously claimed stream. It will take into
- account associated VBI streams. */
-void ivtv_release_stream(struct ivtv_stream *s)
-{
- struct ivtv *itv = s->itv;
- struct ivtv_stream *s_vbi;
-
- 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 */
- return;
- }
- if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
- IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name);
- return;
- }
-
- ivtv_flush_queues(s);
-
- /* disable reinsertion interrupt */
- if (s->type == IVTV_DEC_STREAM_TYPE_VBI)
- ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
-
- /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI,
- IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI,
- for all other streams we're done */
- if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
- s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
- else if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
- s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- else
- return;
-
- /* clear internal use flag */
- if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
- /* was already cleared */
- return;
- }
- if (s_vbi->fh) {
- /* VBI stream still claimed by a file descriptor */
- return;
- }
- /* disable reinsertion interrupt */
- if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI)
- ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
- clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags);
- ivtv_flush_queues(s_vbi);
-}
-
-static void ivtv_dualwatch(struct ivtv *itv)
-{
- struct v4l2_tuner vt;
- u32 new_stereo_mode;
- const u32 dual = 0x02;
-
- new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
- memset(&vt, 0, sizeof(vt));
- ivtv_call_all(itv, tuner, g_tuner, &vt);
- if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
- new_stereo_mode = dual;
-
- if (new_stereo_mode == itv->dualwatch_stereo_mode)
- return;
-
- IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
- itv->dualwatch_stereo_mode, new_stereo_mode);
- if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode))
- IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
-}
-
-static void ivtv_update_pgm_info(struct ivtv *itv)
-{
- u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24;
- int cnt;
- int i = 0;
-
- if (wr_idx >= itv->pgm_info_num) {
- IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num);
- return;
- }
- cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num;
- while (i < cnt) {
- int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
- struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
- u32 addr = itv->pgm_info_offset + 4 + idx * 24;
- const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
- V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
- // 1=I, 2=P, 4=B
-
- e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
- if (e->offset > itv->mpg_data_received) {
- break;
- }
- e->offset += itv->vbi_data_inserted;
- e->length = read_enc(addr);
- e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
- e->flags = mapping[read_enc(addr + 12) & 7];
- i++;
- }
- itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
-}
-
-static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
-{
- struct ivtv *itv = s->itv;
- struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- struct ivtv_buffer *buf;
- DEFINE_WAIT(wait);
-
- *err = 0;
- while (1) {
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG) {
- /* Process pending program info updates and pending VBI data */
- ivtv_update_pgm_info(itv);
-
- if (time_after(jiffies,
- itv->dualwatch_jiffies +
- msecs_to_jiffies(1000))) {
- itv->dualwatch_jiffies = jiffies;
- ivtv_dualwatch(itv);
- }
-
- if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
- !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
- while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) {
- /* byteswap and process VBI data */
- ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type);
- ivtv_enqueue(s_vbi, buf, &s_vbi->q_free);
- }
- }
- buf = &itv->vbi.sliced_mpeg_buf;
- if (buf->readpos != buf->bytesused) {
- return buf;
- }
- }
-
- /* do we have leftover data? */
- buf = ivtv_dequeue(s, &s->q_io);
- if (buf)
- return buf;
-
- /* do we have new data? */
- buf = ivtv_dequeue(s, &s->q_full);
- if (buf) {
- if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
- return buf;
- buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
- /* byteswap MPG data */
- ivtv_buf_swap(buf);
- else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) {
- /* byteswap and process VBI data */
- ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type);
- }
- return buf;
- }
-
- /* return if end of stream */
- if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- IVTV_DEBUG_INFO("EOS %s\n", s->name);
- return NULL;
- }
-
- /* return if file was opened with O_NONBLOCK */
- if (non_block) {
- *err = -EAGAIN;
- return NULL;
- }
-
- /* 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);
- *err = -EINTR;
- return NULL;
- }
- }
-}
-
-static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv)
-{
- int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
-
- itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx];
- itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx];
- itv->vbi.sliced_mpeg_buf.readpos = 0;
-}
-
-static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf,
- char __user *ubuf, size_t ucount)
-{
- struct ivtv *itv = s->itv;
- size_t len = buf->bytesused - buf->readpos;
-
- if (len > ucount) len = ucount;
- if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
- !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
- const char *start = buf->buf + buf->readpos;
- const char *p = start + 1;
- const u8 *q;
- u8 ch = itv->search_pack_header ? 0xba : 0xe0;
- int stuffing, i;
-
- while (start + len > p && (q = memchr(p, 0, start + len - p))) {
- p = q + 1;
- if ((char *)q + 15 >= buf->buf + buf->bytesused ||
- q[1] != 0 || q[2] != 1 || q[3] != ch) {
- continue;
- }
- if (!itv->search_pack_header) {
- if ((q[6] & 0xc0) != 0x80)
- continue;
- if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) ||
- ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) {
- ch = 0xba;
- itv->search_pack_header = 1;
- p = q + 9;
- }
- continue;
- }
- stuffing = q[13] & 7;
- /* all stuffing bytes must be 0xff */
- for (i = 0; i < stuffing; i++)
- if (q[14 + i] != 0xff)
- break;
- if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 &&
- q[14 + stuffing] == 0 && q[15 + stuffing] == 0 &&
- q[16 + stuffing] == 1) {
- itv->search_pack_header = 0;
- len = (char *)q - start;
- ivtv_setup_sliced_vbi_buf(itv);
- break;
- }
- }
- }
- if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
- IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name);
- return -EFAULT;
- }
- /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount,
- buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len,
- buf == &itv->vbi.sliced_mpeg_buf); */
- buf->readpos += len;
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf)
- itv->mpg_data_received += len;
- return len;
-}
-
-static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block)
-{
- struct ivtv *itv = s->itv;
- size_t tot_written = 0;
- int single_frame = 0;
-
- 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;
- }
-
- /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
- arrive one-by-one, so make sure we never output more than one VBI frame at a time */
- if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
- (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
- single_frame = 1;
-
- for (;;) {
- struct ivtv_buffer *buf;
- int rc;
-
- buf = ivtv_get_buffer(s, non_block, &rc);
- /* if there is no data available... */
- if (buf == NULL) {
- /* if we got data, then return that regardless */
- if (tot_written)
- break;
- /* EOS condition */
- if (rc == 0) {
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- ivtv_release_stream(s);
- }
- /* set errno */
- return rc;
- }
- rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
- if (buf != &itv->vbi.sliced_mpeg_buf) {
- ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
- }
- else if (buf->readpos == buf->bytesused) {
- int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
- itv->vbi.sliced_mpeg_size[idx] = 0;
- itv->vbi.inserted_frame++;
- itv->vbi_data_inserted += buf->bytesused;
- }
- if (rc < 0)
- return rc;
- tot_written += rc;
-
- if (tot_written == tot_count || single_frame)
- break;
- }
- return tot_written;
-}
-
-static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count,
- loff_t *pos, int non_block)
-{
- ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
- struct ivtv *itv = s->itv;
-
- IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
- if (rc > 0)
- pos += rc;
- return rc;
-}
-
-int ivtv_start_capture(struct ivtv_open_id *id)
-{
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- struct ivtv_stream *s_vbi;
-
- if (s->type == IVTV_ENC_STREAM_TYPE_RAD ||
- s->type == IVTV_DEC_STREAM_TYPE_MPG ||
- s->type == IVTV_DEC_STREAM_TYPE_YUV ||
- s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
- /* you cannot read from these stream types. */
- return -EPERM;
- }
-
- /* Try to claim this stream. */
- if (ivtv_claim_stream(id, s->type))
- return -EBUSY;
-
- /* This stream does not need to start capturing */
- if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return 0;
- }
-
- /* If capture is already in progress, then we also have to
- do nothing extra. */
- if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return 0;
- }
-
- /* Start VBI capture if required */
- s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
- test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
- !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
- /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed
- automatically when the MPG stream is claimed.
- We only need to start the VBI capturing. */
- if (ivtv_start_v4l2_encode_stream(s_vbi)) {
- IVTV_DEBUG_WARN("VBI capture start failed\n");
-
- /* Failure, clean up and return an error */
- clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- /* also releases the associated VBI stream */
- ivtv_release_stream(s);
- return -EIO;
- }
- IVTV_DEBUG_INFO("VBI insertion started\n");
- }
-
- /* Tell the card to start capturing */
- if (!ivtv_start_v4l2_encode_stream(s)) {
- /* We're done */
- set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- /* Resume a possibly paused encoder */
- if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
- ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
- return 0;
- }
-
- /* failure, clean up */
- IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
-
- /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released
- automatically when the MPG stream is released.
- We only need to stop the VBI capturing. */
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
- test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
- ivtv_stop_v4l2_encode_stream(s_vbi, 0);
- clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
- }
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- ivtv_release_stream(s);
- return -EIO;
-}
-
-ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos)
-{
- struct ivtv_open_id *id = fh2id(filp->private_data);
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- int rc;
-
- IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
-
- rc = ivtv_start_capture(id);
- if (rc)
- return rc;
- return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
-}
-
-int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
-{
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- int rc;
-
- if (atomic_read(&itv->decoding) == 0) {
- if (ivtv_claim_stream(id, s->type)) {
- /* someone else is using this stream already */
- IVTV_DEBUG_WARN("start decode, stream already claimed\n");
- return -EBUSY;
- }
- rc = ivtv_start_v4l2_decode_stream(s, 0);
- if (rc < 0) {
- if (rc == -EAGAIN)
- rc = ivtv_start_v4l2_decode_stream(s, 0);
- if (rc < 0)
- return rc;
- }
- }
- if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
- return ivtv_set_speed(itv, speed);
- return 0;
-}
-
-ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
-{
- struct ivtv_open_id *id = fh2id(filp->private_data);
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- struct yuv_playback_info *yi = &itv->yuv_info;
- struct ivtv_buffer *buf;
- struct ivtv_queue q;
- int bytes_written = 0;
- int mode;
- int rc;
- DEFINE_WAIT(wait);
-
- IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
-
- if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
- s->type != IVTV_DEC_STREAM_TYPE_YUV &&
- s->type != IVTV_DEC_STREAM_TYPE_VOUT)
- /* not decoder streams */
- return -EPERM;
-
- /* Try to claim this stream */
- if (ivtv_claim_stream(id, s->type))
- return -EBUSY;
-
- /* This stream does not need to start any decoding */
- if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
- int elems = count / sizeof(struct v4l2_sliced_vbi_data);
-
- set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return ivtv_write_vbi_from_user(itv,
- (const struct v4l2_sliced_vbi_data __user *)user_buf, elems);
- }
-
- mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
-
- if (ivtv_set_output_mode(itv, mode) != mode) {
- ivtv_release_stream(s);
- return -EBUSY;
- }
- ivtv_queue_init(&q);
- set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
-
- /* Start decoder (returns 0 if already started) */
- rc = ivtv_start_decoding(id, itv->speed);
- if (rc) {
- IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
-
- /* failure, clean up */
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return rc;
- }
-
-retry:
- /* If possible, just DMA the entire frame - Check the data transfer size
- since we may get here before the stream has been fully set-up */
- if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
- while (count >= itv->dma_data_req_size) {
- rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
-
- if (rc < 0)
- return rc;
-
- bytes_written += itv->dma_data_req_size;
- user_buf += itv->dma_data_req_size;
- count -= itv->dma_data_req_size;
- }
- if (count == 0) {
- IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
- return bytes_written;
- }
- }
-
- for (;;) {
- /* Gather buffers */
- while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
- ivtv_enqueue(s, buf, &q);
- while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) {
- ivtv_enqueue(s, buf, &q);
- }
- if (q.buffers)
- 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;
- }
- }
-
- /* copy user data into buffers */
- while ((buf = ivtv_dequeue(s, &q))) {
- /* yuv is a pain. Don't copy more data than needed for a single
- frame, otherwise we lose sync with the incoming stream */
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
- yi->stream_size + count > itv->dma_data_req_size)
- rc = ivtv_buf_copy_from_user(s, buf, user_buf,
- itv->dma_data_req_size - yi->stream_size);
- else
- rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
-
- /* Make sure we really got all the user data */
- if (rc < 0) {
- ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
- return rc;
- }
- user_buf += rc;
- count -= rc;
- bytes_written += rc;
-
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
- yi->stream_size += rc;
- /* If we have a complete yuv frame, break loop now */
- if (yi->stream_size == itv->dma_data_req_size) {
- ivtv_enqueue(s, buf, &s->q_full);
- yi->stream_size = 0;
- break;
- }
- }
-
- if (buf->bytesused != s->buf_size) {
- /* incomplete, leave in q_io for next time */
- ivtv_enqueue(s, buf, &s->q_io);
- break;
- }
- /* Byteswap MPEG buffer */
- if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
- ivtv_buf_swap(buf);
- ivtv_enqueue(s, buf, &s->q_full);
- }
-
- if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
- if (s->q_full.length >= itv->dma_data_req_size) {
- int got_sig;
-
- 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;
- }
-
- clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
- ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
- ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1);
- }
- }
- /* more user data is available, wait until buffers become free
- to transfer the rest. */
- if (count && !(filp->f_flags & O_NONBLOCK))
- goto retry;
- IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
- return bytes_written;
-}
-
-unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
-{
- struct ivtv_open_id *id = fh2id(filp->private_data);
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- int res = 0;
-
- /* add stream's waitq to the poll list */
- IVTV_DEBUG_HI_FILE("Decoder poll\n");
-
- /* If there are subscribed events, then only use the new event
- API instead of the old video.h based API. */
- if (!list_empty(&id->fh.subscribed)) {
- poll_wait(filp, &id->fh.wait, wait);
- /* Turn off the old-style vsync events */
- clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
- if (v4l2_event_pending(&id->fh))
- res = POLLPRI;
- } else {
- /* This is the old-style API which is here only for backwards
- compatibility. */
- poll_wait(filp, &s->waitq, wait);
- set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
- if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
- test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
- res = POLLPRI;
- }
-
- /* Allow write if buffers are available for writing */
- if (s->q_free.buffers)
- res |= POLLOUT | POLLWRNORM;
- return res;
-}
-
-unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
-{
- unsigned long req_events = poll_requested_events(wait);
- struct ivtv_open_id *id = fh2id(filp->private_data);
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
- int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- unsigned res = 0;
-
- /* Start a capture if there is none */
- if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) &&
- (req_events & (POLLIN | POLLRDNORM))) {
- int rc;
-
- rc = ivtv_start_capture(id);
- if (rc) {
- IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
- s->name, rc);
- return POLLERR;
- }
- IVTV_DEBUG_FILE("Encoder poll started capture\n");
- }
-
- /* add stream's waitq to the poll list */
- IVTV_DEBUG_HI_FILE("Encoder poll\n");
- poll_wait(filp, &s->waitq, wait);
- if (v4l2_event_pending(&id->fh))
- res |= POLLPRI;
- else
- poll_wait(filp, &id->fh.wait, wait);
-
- if (s->q_full.length || s->q_io.length)
- return res | POLLIN | POLLRDNORM;
- if (eof)
- return res | POLLHUP;
- return res;
-}
-
-void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
-{
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
-
- IVTV_DEBUG_FILE("close() of %s\n", s->name);
-
- /* 'Unclaim' this stream */
-
- /* Stop capturing */
- if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
-
- IVTV_DEBUG_INFO("close stopping capture\n");
- /* Special case: a running VBI capture for VBI insertion
- in the mpeg stream. Need to stop that too. */
- if (id->type == IVTV_ENC_STREAM_TYPE_MPG &&
- test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) &&
- !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
- IVTV_DEBUG_INFO("close stopping embedded VBI capture\n");
- ivtv_stop_v4l2_encode_stream(s_vbi, 0);
- }
- if ((id->type == IVTV_DEC_STREAM_TYPE_VBI ||
- 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->fh = NULL;
- }
- else {
- ivtv_stop_v4l2_encode_stream(s, gop_end);
- }
- }
- if (!gop_end) {
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- ivtv_release_stream(s);
- }
-}
-
-static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
-{
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
-
- IVTV_DEBUG_FILE("close() of %s\n", s->name);
-
- if (id->type == IVTV_DEC_STREAM_TYPE_YUV &&
- test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
- /* Restore registers we've changed & clean up any mess */
- ivtv_yuv_close(itv);
- }
-
- /* Stop decoding */
- if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- IVTV_DEBUG_INFO("close stopping decode\n");
-
- ivtv_stop_v4l2_decode_stream(s, flags, pts);
- itv->output_mode = OUT_NONE;
- }
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
- if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
- itv->output_mode = OUT_NONE;
-
- itv->speed = 0;
- clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
- ivtv_release_stream(s);
-}
-
-int ivtv_v4l2_close(struct file *filp)
-{
- struct v4l2_fh *fh = filp->private_data;
- struct ivtv_open_id *id = fh2id(fh);
- struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
-
- IVTV_DEBUG_FILE("close %s\n", s->name);
-
- /* Stop radio */
- 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 */
- clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
- /* Switch tuner to TV */
- ivtv_call_all(itv, core, s_std, itv->std);
- /* Select correct audio input (i.e. TV tuner or Line in) */
- ivtv_audio_set_io(itv);
- if (itv->hw_flags & IVTV_HW_SAA711X) {
- ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
- SAA7115_FREQ_32_11_MHZ, 0);
- }
- 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));
- }
- /* Done! Unmute and continue. */
- ivtv_unmute(itv);
- }
-
- 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, 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. */
- if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
- /* disable CC on TV-out */
- ivtv_disable_cc(itv);
- }
- } else {
- ivtv_stop_capture(id, 0);
- }
- kfree(id);
- return 0;
-}
-
-int ivtv_v4l2_open(struct file *filp)
-{
- struct video_device *vdev = video_devdata(filp);
- 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) {
- IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
- video_device_node_name(vdev));
- IVTV_WARN("Selected firmware errors will be ignored\n");
- } else {
-#else
- if (1) {
-#endif
- res = ivtv_firmware_check(itv, "ivtv_serialized_open");
- if (res == -EAGAIN)
- res = ivtv_firmware_check(itv, "ivtv_serialized_open");
- if (res < 0)
- return -EIO;
- }
-
- if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
- test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
- return -EBUSY;
-
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
- test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
- return -EBUSY;
-
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
- if (read_reg(0x82c) == 0) {
- IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
- /* return -ENODEV; */
- }
- ivtv_udma_alloc(itv);
- }
-
- /* Allocate memory */
- item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
- if (NULL == item) {
- IVTV_DEBUG_WARN("nomem on v4l2 open\n");
- return -ENOMEM;
- }
- v4l2_fh_init(&item->fh, s->vdev);
- item->itv = itv;
- item->type = s->type;
-
- filp->private_data = &item->fh;
- v4l2_fh_add(&item->fh);
-
- 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 */
- v4l2_fh_del(&item->fh);
- v4l2_fh_exit(&item->fh);
- kfree(item);
- return -EBUSY;
- }
- }
- /* Mark that the radio is being used. */
- set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
- /* We have the radio */
- ivtv_mute(itv);
- /* Switch tuner to radio */
- ivtv_call_all(itv, tuner, s_radio);
- /* Select the correct audio input (i.e. radio tuner) */
- ivtv_audio_set_io(itv);
- if (itv->hw_flags & IVTV_HW_SAA711X) {
- ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq,
- SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL);
- }
- /* Done! Unmute and continue. */
- ivtv_unmute(itv);
- }
-
- /* YUV or MPG Decoding Mode? */
- if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
- clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
- set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- /* For yuv, we need to know the dma size before we start */
- itv->dma_data_req_size =
- 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
- itv->yuv_info.stream_size = 0;
- }
- return 0;
-}
-
-void ivtv_mute(struct ivtv *itv)
-{
- if (atomic_read(&itv->capturing))
- ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
- IVTV_DEBUG_INFO("Mute\n");
-}
-
-void ivtv_unmute(struct ivtv *itv)
-{
- if (atomic_read(&itv->capturing)) {
- ivtv_msleep_timeout(100, 0);
- ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
- ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
- }
- IVTV_DEBUG_INFO("Unmute\n");
-}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
deleted file mode 100644
index 02c5adebf517..000000000000
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- ivtv firmware functions.
- Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
- Copyright (C) 2004 Chris Kennedy <c@groovy.org>
- Copyright (C) 2005-2007 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
- */
-
-#include "ivtv-driver.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-firmware.h"
-#include "ivtv-yuv.h"
-#include "ivtv-ioctl.h"
-#include "ivtv-cards.h"
-#include <linux/firmware.h>
-#include <media/saa7127.h>
-
-#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
-#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
-#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB
-#define IVTV_CMD_VDM_STOP 0x00000000
-#define IVTV_CMD_AO_STOP 0x00000005
-#define IVTV_CMD_APU_PING 0x00000000
-#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE
-#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE
-#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
-#define IVTV_CMD_SPU_STOP 0x00000001
-#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
-#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
-#define IVTV_SDRAM_SLEEPTIME 600
-
-#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg"
-#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024)
-
-/* Encoder/decoder firmware sizes */
-#define IVTV_FW_ENC_SIZE (376836)
-#define IVTV_FW_DEC_SIZE (256*1024)
-
-static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size)
-{
- const struct firmware *fw = NULL;
- int retries = 3;
-
-retry:
- if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
- int i;
- volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
- const u32 *src = (const u32 *)fw->data;
-
- if (fw->size != size) {
- /* Due to race conditions in firmware loading (esp. with udev <0.95)
- the wrong file was sometimes loaded. So we check filesizes to
- see if at least the right-sized file was loaded. If not, then we
- retry. */
- IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
- release_firmware(fw);
- retries--;
- goto retry;
- }
- for (i = 0; i < fw->size; i += 4) {
- /* no need for endianness conversion on the ppc */
- __raw_writel(*src, dst);
- dst++;
- src++;
- }
- IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
- release_firmware(fw);
- return size;
- }
- IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
- IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
- return -ENOMEM;
-}
-
-void ivtv_halt_firmware(struct ivtv *itv)
-{
- IVTV_DEBUG_INFO("Preparing for firmware halt.\n");
- if (itv->has_cx23415 && itv->dec_mbox.mbox)
- ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0);
- if (itv->enc_mbox.mbox)
- ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
-
- ivtv_msleep_timeout(10, 0);
- itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
-
- IVTV_DEBUG_INFO("Stopping VDM\n");
- write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM);
-
- IVTV_DEBUG_INFO("Stopping AO\n");
- write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO);
-
- IVTV_DEBUG_INFO("pinging (?) APU\n");
- write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU);
-
- IVTV_DEBUG_INFO("Stopping VPU\n");
- if (!itv->has_cx23415)
- write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU);
- else
- write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU);
-
- IVTV_DEBUG_INFO("Resetting Hw Blocks\n");
- write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS);
-
- IVTV_DEBUG_INFO("Stopping SPU\n");
- write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
-
- ivtv_msleep_timeout(10, 0);
-
- IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
- write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
-
- IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n");
- write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH);
-
- if (itv->has_cx23415) {
- IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n");
- write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE);
-
- IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n");
- write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
- }
-
- IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
- ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
-}
-
-void ivtv_firmware_versions(struct ivtv *itv)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
-
- /* Encoder */
- ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0);
- IVTV_INFO("Encoder revision: 0x%08x\n", data[0]);
-
- if (data[0] != 0x02060039)
- IVTV_WARN("Recommended firmware version is 0x02060039.\n");
-
- if (itv->has_cx23415) {
- /* Decoder */
- ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0);
- IVTV_INFO("Decoder revision: 0x%08x\n", data[0]);
- }
-}
-
-static int ivtv_firmware_copy(struct ivtv *itv)
-{
- IVTV_DEBUG_INFO("Loading encoder image\n");
- if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME,
- itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) {
- IVTV_DEBUG_WARN("failed loading encoder firmware\n");
- return -3;
- }
- if (!itv->has_cx23415)
- return 0;
-
- IVTV_DEBUG_INFO("Loading decoder image\n");
- if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME,
- itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) {
- IVTV_DEBUG_WARN("failed loading decoder firmware\n");
- return -1;
- }
- return 0;
-}
-
-static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size)
-{
- int i;
-
- /* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte
- address boundary */
- for (i = 0; i < size; i += 0x100) {
- if (readl(mem + i) == 0x12345678 &&
- readl(mem + i + 4) == 0x34567812 &&
- readl(mem + i + 8) == 0x56781234 &&
- readl(mem + i + 12) == 0x78123456) {
- return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16);
- }
- }
- return NULL;
-}
-
-int ivtv_firmware_init(struct ivtv *itv)
-{
- int err;
-
- ivtv_halt_firmware(itv);
-
- /* load firmware */
- err = ivtv_firmware_copy(itv);
- if (err) {
- IVTV_DEBUG_WARN("Error %d loading firmware\n", err);
- return err;
- }
-
- /* start firmware */
- write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
- ivtv_msleep_timeout(100, 0);
- if (itv->has_cx23415)
- write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
- else
- write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
- ivtv_msleep_timeout(100, 0);
-
- /* find mailboxes and ping firmware */
- itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
- if (itv->enc_mbox.mbox == NULL)
- IVTV_ERR("Encoder mailbox not found\n");
- else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) {
- IVTV_ERR("Encoder firmware dead!\n");
- itv->enc_mbox.mbox = NULL;
- }
- if (itv->enc_mbox.mbox == NULL)
- return -ENODEV;
-
- if (!itv->has_cx23415)
- return 0;
-
- itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE);
- if (itv->dec_mbox.mbox == NULL) {
- IVTV_ERR("Decoder mailbox not found\n");
- } else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) {
- IVTV_ERR("Decoder firmware dead!\n");
- itv->dec_mbox.mbox = NULL;
- } else {
- /* Firmware okay, so check yuv output filter table */
- ivtv_yuv_filter_check(itv);
- }
- return itv->dec_mbox.mbox ? 0 : -ENODEV;
-}
-
-void ivtv_init_mpeg_decoder(struct ivtv *itv)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
- long readbytes;
- volatile u8 __iomem *mem_offset;
-
- data[0] = 0;
- data[1] = itv->cxhdl.width; /* YUV source width */
- data[2] = itv->cxhdl.height;
- data[3] = itv->cxhdl.audio_properties; /* Audio settings to use,
- bitmap. see docs. */
- if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) {
- IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n");
- return;
- }
-
- if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) {
- IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n");
- return;
- }
- ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
- mem_offset = itv->dec_mem + data[1];
-
- if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME,
- mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) {
- IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n",
- IVTV_DECODE_INIT_MPEG_FILENAME);
- } else {
- ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
- ivtv_msleep_timeout(100, 0);
- }
- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
-}
-
-/* Try to restart the card & restore previous settings */
-int ivtv_firmware_restart(struct ivtv *itv)
-{
- int rc = 0;
- v4l2_std_id std;
-
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
- /* Display test image during restart */
- ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
- SAA7127_INPUT_TYPE_TEST_IMAGE,
- itv->card->video_outputs[itv->active_output].video_output,
- 0);
-
- mutex_lock(&itv->udma.lock);
-
- rc = ivtv_firmware_init(itv);
- if (rc) {
- mutex_unlock(&itv->udma.lock);
- return rc;
- }
-
- /* Allow settings to reload */
- ivtv_mailbox_cache_invalidate(itv);
-
- /* Restore encoder video standard */
- std = itv->std;
- itv->std = 0;
- ivtv_s_std_enc(itv, &std);
-
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
- ivtv_init_mpeg_decoder(itv);
-
- /* Restore decoder video standard */
- std = itv->std_out;
- itv->std_out = 0;
- ivtv_s_std_dec(itv, &std);
-
- /* Restore framebuffer if active */
- if (itv->ivtvfb_restore)
- itv->ivtvfb_restore(itv);
-
- /* Restore alpha settings */
- ivtv_set_osd_alpha(itv);
-
- /* Restore normal output */
- ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
- SAA7127_INPUT_TYPE_NORMAL,
- itv->card->video_outputs[itv->active_output].video_output,
- 0);
- }
-
- mutex_unlock(&itv->udma.lock);
- return rc;
-}
-
-/* Check firmware running state. The checks fall through
- allowing multiple failures to be logged. */
-int ivtv_firmware_check(struct ivtv *itv, char *where)
-{
- int res = 0;
-
- /* Check encoder is still running */
- if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
- IVTV_WARN("Encoder has died : %s\n", where);
- res = -1;
- }
-
- /* Also check audio. Only check if not in use & encoder is okay */
- if (!res && !atomic_read(&itv->capturing) &&
- (!atomic_read(&itv->decoding) ||
- (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
- &itv->i_flags)))) {
-
- if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
- IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
- res = -2;
- }
- }
-
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
- /* Second audio check. Skip if audio already failed */
- if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
- /* Wait & try again to be certain. */
- ivtv_msleep_timeout(14, 0);
- if (read_dec(0x100) != read_dec(0x104)) {
- IVTV_WARN("Audio has died (Decoder) : %s\n",
- where);
- res = -1;
- }
- }
-
- /* Check decoder is still running */
- if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
- IVTV_WARN("Decoder has died : %s\n", where);
- res = -1;
- }
- }
-
- /* If something failed & currently idle, try to reload */
- if (res && !atomic_read(&itv->capturing) &&
- !atomic_read(&itv->decoding)) {
- IVTV_INFO("Detected in %s that firmware had failed - "
- "Reloading\n", where);
- res = ivtv_firmware_restart(itv);
- /*
- * Even if restarted ok, still signal a problem had occurred.
- * The caller can come through this function again to check
- * if things are really ok after the restart.
- */
- if (!res) {
- IVTV_INFO("Firmware restart okay\n");
- res = -EAGAIN;
- } else {
- IVTV_INFO("Firmware restart failed\n");
- }
- } else if (res) {
- res = -EIO;
- }
-
- return res;
-}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
deleted file mode 100644
index 87990c5f0910..000000000000
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- init/start/stop/exit stream functions
- Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
- Copyright (C) 2004 Chris Kennedy <c@groovy.org>
- Copyright (C) 2005-2007 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
- */
-
-/* License: GPL
- * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
- *
- * This file will hold API related functions, both internal (firmware api)
- * and external (v4l2, etc)
- *
- * -----
- * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com>
- * and Takeru KOMORIYA<komoriya@paken.org>
- *
- * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
- * using information provided by Jiun-Kuei Jung @ AVerMedia.
- */
-
-#include "ivtv-driver.h"
-#include "ivtv-fileops.h"
-#include "ivtv-queue.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-ioctl.h"
-#include "ivtv-irq.h"
-#include "ivtv-yuv.h"
-#include "ivtv-cards.h"
-#include "ivtv-streams.h"
-#include "ivtv-firmware.h"
-#include <media/v4l2-event.h>
-
-static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .unlocked_ioctl = video_ioctl2,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_enc_poll,
-};
-
-static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .unlocked_ioctl = video_ioctl2,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_dec_poll,
-};
-
-#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
-#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
-#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
-#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
-
-static struct {
- const char *name;
- int vfl_type;
- 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
- }
-};
-
-static void ivtv_stream_init(struct ivtv *itv, int type)
-{
- struct ivtv_stream *s = &itv->streams[type];
- struct video_device *vdev = s->vdev;
-
- /* we need to keep vdev, so restore it afterwards */
- memset(s, 0, sizeof(*s));
- s->vdev = vdev;
-
- /* initialize ivtv_stream fields */
- 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;
- else
- s->dma = ivtv_stream_info[type].dma;
- s->buf_size = itv->stream_buf_size[type];
- if (s->buf_size)
- 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->sg_handle = IVTV_DMA_UNMAPPED;
- ivtv_queue_init(&s->q_free);
- ivtv_queue_init(&s->q_full);
- ivtv_queue_init(&s->q_dma);
- ivtv_queue_init(&s->q_predma);
- ivtv_queue_init(&s->q_io);
-}
-
-static int ivtv_prep_dev(struct ivtv *itv, int type)
-{
- struct ivtv_stream *s = &itv->streams[type];
- int num_offset = ivtv_stream_info[type].num_offset;
- int num = itv->instance + ivtv_first_minor + num_offset;
-
- /* These four fields are always initialized. If vdev == NULL, then
- this stream is not in use. In that case no other fields but these
- four can be used. */
- s->vdev = NULL;
- s->itv = itv;
- s->type = type;
- s->name = ivtv_stream_info[type].name;
-
- /* Check whether the radio is supported */
- if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))
- return 0;
- if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return 0;
-
- /* User explicitly selected 0 buffers for these streams, so don't
- create them. */
- if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
- itv->options.kilobytes[type] == 0) {
- IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
- return 0;
- }
-
- ivtv_stream_init(itv, type);
-
- /* allocate and initialize the v4l2 video device structure */
- s->vdev = video_device_alloc();
- if (s->vdev == NULL) {
- IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
- return -ENOMEM;
- }
-
- snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
- itv->v4l2_dev.name, s->name);
-
- s->vdev->num = num;
- s->vdev->v4l2_dev = &itv->v4l2_dev;
- 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;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &s->vdev->flags);
- set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
- ivtv_set_funcs(s->vdev);
- return 0;
-}
-
-/* Initialize v4l2 variables and prepare v4l2 devices */
-int ivtv_streams_setup(struct ivtv *itv)
-{
- int type;
-
- /* Setup V4L2 Devices */
- for (type = 0; type < IVTV_MAX_STREAMS; type++) {
- /* Prepare device */
- if (ivtv_prep_dev(itv, type))
- break;
-
- if (itv->streams[type].vdev == NULL)
- continue;
-
- /* Allocate Stream */
- if (ivtv_stream_alloc(&itv->streams[type]))
- break;
- }
- if (type == IVTV_MAX_STREAMS)
- return 0;
-
- /* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv, 0);
- return -ENOMEM;
-}
-
-static int ivtv_reg_dev(struct ivtv *itv, int type)
-{
- struct ivtv_stream *s = &itv->streams[type];
- int vfl_type = ivtv_stream_info[type].vfl_type;
- const char *name;
- int num;
-
- if (s->vdev == NULL)
- return 0;
-
- num = s->vdev->num;
- /* card number + user defined offset + device offset */
- if (type != IVTV_ENC_STREAM_TYPE_MPG) {
- struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
-
- if (s_mpg->vdev)
- num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
- }
- video_set_drvdata(s->vdev, s);
-
- /* Register device. First try the desired minor, then any free one. */
- if (video_register_device_no_warn(s->vdev, vfl_type, num)) {
- IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
- s->name, num);
- video_device_release(s->vdev);
- s->vdev = NULL;
- return -ENOMEM;
- }
- name = video_device_node_name(s->vdev);
-
- switch (vfl_type) {
- case VFL_TYPE_GRABBER:
- IVTV_INFO("Registered device %s for %s (%d kB)\n",
- name, s->name, itv->options.kilobytes[type]);
- break;
- case VFL_TYPE_RADIO:
- IVTV_INFO("Registered device %s for %s\n",
- name, s->name);
- break;
- case VFL_TYPE_VBI:
- if (itv->options.kilobytes[type])
- IVTV_INFO("Registered device %s for %s (%d kB)\n",
- name, s->name, itv->options.kilobytes[type]);
- else
- IVTV_INFO("Registered device %s for %s\n",
- name, s->name);
- break;
- }
- return 0;
-}
-
-/* Register v4l2 devices */
-int ivtv_streams_register(struct ivtv *itv)
-{
- int type;
- int err = 0;
-
- /* Register V4L2 devices */
- for (type = 0; type < IVTV_MAX_STREAMS; type++)
- err |= ivtv_reg_dev(itv, type);
-
- if (err == 0)
- return 0;
-
- /* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv, 1);
- return -ENOMEM;
-}
-
-/* Unregister v4l2 devices */
-void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
-{
- int type;
-
- /* Teardown all streams */
- for (type = 0; type < IVTV_MAX_STREAMS; type++) {
- struct video_device *vdev = itv->streams[type].vdev;
-
- itv->streams[type].vdev = NULL;
- if (vdev == NULL)
- continue;
-
- ivtv_stream_free(&itv->streams[type]);
- /* Unregister or release device */
- if (unregister)
- video_unregister_device(vdev);
- else
- video_device_release(vdev);
- }
-}
-
-static void ivtv_vbi_setup(struct ivtv *itv)
-{
- int raw = ivtv_raw_vbi(itv);
- u32 data[CX2341X_MBOX_MAX_DATA];
- int lines;
- int i;
-
- /* Reset VBI */
- ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
-
- /* setup VBI registers */
- if (raw)
- v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi);
- else
- v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced);
-
- /* determine number of lines and total number of VBI bytes.
- A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
- The '- 1' byte is probably an unused U or V byte. Or something...
- A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
- header, 42 data bytes + checksum (to be confirmed) */
- if (raw) {
- lines = itv->vbi.count * 2;
- } else {
- lines = itv->is_60hz ? 24 : 38;
- if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))
- lines += 2;
- }
-
- itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
-
- /* Note: sliced vs raw flag doesn't seem to have any effect
- TODO: check mode (0x02) value with older ivtv versions. */
- data[0] = raw | 0x02 | (0xbd << 8);
-
- /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
- data[1] = 1;
- /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
- data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
- /* The start/stop codes determine which VBI lines end up in the raw VBI data area.
- The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
- is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
- code. These values for raw VBI are obtained from a driver disassembly. The sliced
- start/stop codes was deduced from this, but they do not appear in the driver.
- Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.
- However, I have no idea what these values are for. */
- if (itv->hw_flags & IVTV_HW_CX25840) {
- /* Setup VBI for the cx25840 digitizer */
- if (raw) {
- data[3] = 0x20602060;
- data[4] = 0x30703070;
- } else {
- data[3] = 0xB0F0B0F0;
- data[4] = 0xA0E0A0E0;
- }
- /* Lines per frame */
- data[5] = lines;
- /* bytes per line */
- data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
- } else {
- /* Setup VBI for the saa7115 digitizer */
- if (raw) {
- data[3] = 0x25256262;
- data[4] = 0x387F7F7F;
- } else {
- data[3] = 0xABABECEC;
- data[4] = 0xB6F1F1F1;
- }
- /* Lines per frame */
- data[5] = lines;
- /* bytes per line */
- data[6] = itv->vbi.enc_size / lines;
- }
-
- IVTV_DEBUG_INFO(
- "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",
- data[0], data[1], data[2], data[5], data[6]);
-
- ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);
-
- /* returns the VBI encoder memory area. */
- itv->vbi.enc_start = data[2];
- itv->vbi.fpi = data[0];
- if (!itv->vbi.fpi)
- itv->vbi.fpi = 1;
-
- IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
- itv->vbi.enc_start, data[1], itv->vbi.fpi);
-
- /* select VBI lines.
- Note that the sliced argument seems to have no effect. */
- for (i = 2; i <= 24; i++) {
- int valid;
-
- if (itv->is_60hz) {
- valid = i >= 10 && i < 22;
- } else {
- valid = i >= 6 && i < 24;
- }
- ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,
- valid, 0 , 0, 0);
- ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,
- valid, 0, 0, 0);
- }
-
- /* Remaining VBI questions:
- - Is it possible to select particular VBI lines only for inclusion in the MPEG
- stream? Currently you can only get the first X lines.
- - Is mixed raw and sliced VBI possible?
- - What's the meaning of the raw/sliced flag?
- - What's the meaning of params 2, 3 & 4 of the Select VBI command? */
-}
-
-int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
- struct ivtv *itv = s->itv;
- int captype = 0, subtype = 0;
- int enable_passthrough = 0;
-
- if (s->vdev == NULL)
- return -EINVAL;
-
- IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
-
- switch (s->type) {
- case IVTV_ENC_STREAM_TYPE_MPG:
- captype = 0;
- subtype = 3;
-
- /* Stop Passthrough */
- if (itv->output_mode == OUT_PASSTHROUGH) {
- ivtv_passthrough_mode(itv, 0);
- enable_passthrough = 1;
- }
- itv->mpg_data_received = itv->vbi_data_inserted = 0;
- itv->dualwatch_jiffies = jiffies;
- itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
- itv->search_pack_header = 0;
- break;
-
- case IVTV_ENC_STREAM_TYPE_YUV:
- if (itv->output_mode == OUT_PASSTHROUGH) {
- captype = 2;
- subtype = 11; /* video+audio+decoder */
- break;
- }
- captype = 1;
- subtype = 1;
- break;
- case IVTV_ENC_STREAM_TYPE_PCM:
- captype = 1;
- subtype = 2;
- break;
- case IVTV_ENC_STREAM_TYPE_VBI:
- captype = 1;
- subtype = 4;
-
- itv->vbi.frame = 0;
- itv->vbi.inserted_frame = 0;
- memset(itv->vbi.sliced_mpeg_size,
- 0, sizeof(itv->vbi.sliced_mpeg_size));
- break;
- default:
- return -EINVAL;
- }
- s->subtype = subtype;
- s->buffers_stolen = 0;
-
- /* Clear Streamoff flags in case left from last capture */
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
- if (atomic_read(&itv->capturing) == 0) {
- int digitizer;
-
- /* Always use frame based mode. Experiments have demonstrated that byte
- stream based mode results in dropped frames and corruption. Not often,
- but occasionally. Many thanks go to Leonard Orb who spent a lot of
- effort and time trying to trace the cause of the drop outs. */
- /* 1 frame per DMA */
- /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
- ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
-
- /* Stuff from Windows, we don't know what it is */
- ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0);
- /* According to the docs, this should be correct. However, this is
- untested. I don't dare enable this without having tested it.
- Only very few old cards actually have this hardware combination.
- ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1,
- ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0);
- */
- ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
- ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
- ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
- ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
-
- /* assign placeholder */
- ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-
- if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
- digitizer = 0xF1;
- else if (itv->card->hw_all & IVTV_HW_SAA7114)
- digitizer = 0xEF;
- else /* cx25840 */
- digitizer = 0x140;
-
- ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
-
- /* Setup VBI */
- if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
- ivtv_vbi_setup(itv);
- }
-
- /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */
- ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400);
- itv->pgm_info_offset = data[0];
- itv->pgm_info_num = data[1];
- itv->pgm_info_write_idx = 0;
- itv->pgm_info_read_idx = 0;
-
- IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n",
- itv->pgm_info_offset, itv->pgm_info_num);
-
- /* Setup API for Stream */
- cx2341x_handler_setup(&itv->cxhdl);
-
- /* mute if capturing radio */
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
- ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
- 1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
- }
-
- /* Vsync Setup */
- if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
- /* event notification (on) */
- ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1);
- ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
- }
-
- if (atomic_read(&itv->capturing) == 0) {
- /* Clear all Pending Interrupts */
- ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
-
- clear_bit(IVTV_F_I_EOS, &itv->i_flags);
-
- cx2341x_handler_set_busy(&itv->cxhdl, 1);
-
- /* Initialize Digitizer for Capture */
- /* Avoid tinny audio problem - ensure audio clocks are going */
- v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
- /* Avoid unpredictable PCI bus hang - disable video clocks */
- v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
- ivtv_msleep_timeout(300, 0);
- ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
- }
-
- /* begin_capture */
- if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
- {
- IVTV_DEBUG_WARN( "Error starting capture!\n");
- return -EINVAL;
- }
-
- /* Start Passthrough */
- if (enable_passthrough) {
- ivtv_passthrough_mode(itv, 1);
- }
-
- if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
- ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
- else
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
-
- /* you're live! sit back and await interrupts :) */
- atomic_inc(&itv->capturing);
- return 0;
-}
-
-static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
-{
- u32 data[CX2341X_MBOX_MAX_DATA];
- struct ivtv *itv = s->itv;
- int datatype;
- u16 width;
- u16 height;
-
- if (s->vdev == NULL)
- return -EINVAL;
-
- IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
-
- width = itv->cxhdl.width;
- height = itv->cxhdl.height;
-
- /* set audio mode to left/stereo for dual/stereo mode. */
- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-
- /* set number of internal decoder buffers */
- ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
-
- /* prebuffering */
- ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1);
-
- /* extract from user packets */
- ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1);
- itv->vbi.dec_start = data[0];
-
- IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n",
- itv->vbi.dec_start, data[1]);
-
- /* set decoder source settings */
- /* Data type: 0 = mpeg from host,
- 1 = yuv from encoder,
- 2 = yuv_from_host */
- switch (s->type) {
- case IVTV_DEC_STREAM_TYPE_YUV:
- if (itv->output_mode == OUT_PASSTHROUGH) {
- datatype = 1;
- } else {
- /* Fake size to avoid switching video standard */
- datatype = 2;
- width = 720;
- height = itv->is_out_50hz ? 576 : 480;
- }
- IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
- break;
- case IVTV_DEC_STREAM_TYPE_MPG:
- default:
- datatype = 0;
- break;
- }
- if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
- width, height, itv->cxhdl.audio_properties)) {
- IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
- }
-
- /* Decoder sometimes dies here, so wait a moment */
- ivtv_msleep_timeout(10, 0);
-
- /* Known failure point for firmware, so check */
- return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
-}
-
-int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
-{
- struct ivtv *itv = s->itv;
- int rc;
-
- if (s->vdev == NULL)
- return -EINVAL;
-
- if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
- return 0; /* already started */
-
- IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
-
- rc = ivtv_setup_v4l2_decode_stream(s);
- if (rc < 0) {
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- return rc;
- }
-
- /* set dma size to 65536 bytes */
- ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
-
- /* Clear Streamoff */
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
- /* Zero out decoder counters */
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]);
-
- /* turn on notification of dual/stereo mode change */
- ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
-
- /* start playback */
- ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
-
- /* Let things settle before we actually start */
- ivtv_msleep_timeout(10, 0);
-
- /* Clear the following Interrupt mask bits for decoding */
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
- IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
-
- /* you're live! sit back and await interrupts :) */
- atomic_inc(&itv->decoding);
- return 0;
-}
-
-void ivtv_stop_all_captures(struct ivtv *itv)
-{
- int i;
-
- for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
- struct ivtv_stream *s = &itv->streams[i];
-
- if (s->vdev == NULL)
- continue;
- if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- ivtv_stop_v4l2_encode_stream(s, 0);
- }
- }
-}
-
-int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
-{
- struct ivtv *itv = s->itv;
- DECLARE_WAITQUEUE(wait, current);
- int cap_type;
- int stopmode;
-
- if (s->vdev == NULL)
- return -EINVAL;
-
- /* This function assumes that you are allowed to stop the capture
- and that we are actually capturing */
-
- IVTV_DEBUG_INFO("Stop Capture\n");
-
- if (s->type == IVTV_DEC_STREAM_TYPE_VOUT)
- return 0;
- if (atomic_read(&itv->capturing) == 0)
- return 0;
-
- switch (s->type) {
- case IVTV_ENC_STREAM_TYPE_YUV:
- cap_type = 1;
- break;
- case IVTV_ENC_STREAM_TYPE_PCM:
- cap_type = 1;
- break;
- case IVTV_ENC_STREAM_TYPE_VBI:
- cap_type = 1;
- break;
- case IVTV_ENC_STREAM_TYPE_MPG:
- default:
- cap_type = 0;
- break;
- }
-
- /* Stop Capture Mode */
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
- stopmode = 0;
- } else {
- stopmode = 1;
- }
-
- /* end_capture */
- /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
- ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
-
- if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
- /* only run these if we're shutting down the last cap */
- unsigned long duration;
- unsigned long then = jiffies;
-
- add_wait_queue(&itv->eos_waitq, &wait);
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* wait 2s for EOS interrupt */
- while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
- time_before(jiffies,
- then + msecs_to_jiffies(2000))) {
- schedule_timeout(msecs_to_jiffies(10));
- }
-
- /* To convert jiffies to ms, we must multiply by 1000
- * and divide by HZ. To avoid runtime division, we
- * convert this to multiplication by 1000/HZ.
- * Since integer division truncates, we get the best
- * accuracy if we do a rounding calculation of the constant.
- * Think of the case where HZ is 1024.
- */
- duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
-
- if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
- IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
- IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
- } else {
- IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&itv->eos_waitq, &wait);
- set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- }
-
- /* Handle any pending interrupts */
- ivtv_msleep_timeout(100, 0);
- }
-
- atomic_dec(&itv->capturing);
-
- /* Clear capture and no-read bits */
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
-
- if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
- ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
-
- if (atomic_read(&itv->capturing) > 0) {
- return 0;
- }
-
- cx2341x_handler_set_busy(&itv->cxhdl, 0);
-
- /* Set the following Interrupt mask bits for capture */
- ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
- del_timer(&itv->dma_timer);
-
- /* event notification (off) */
- if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
- /* type: 0 = refresh */
- /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
- ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
- ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
- }
-
- /* Raw-passthrough is implied on start. Make sure it's stopped so
- the encoder will re-initialize when next started */
- ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
-
- wake_up(&s->waitq);
-
- return 0;
-}
-
-int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
-{
- static const struct v4l2_event ev = {
- .type = V4L2_EVENT_EOS,
- };
- struct ivtv *itv = s->itv;
-
- if (s->vdev == NULL)
- return -EINVAL;
-
- if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
- return -EINVAL;
-
- if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags))
- return 0;
-
- IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
-
- /* Stop Decoder */
- if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
- u32 tmp = 0;
-
- /* Wait until the decoder is no longer running */
- if (pts) {
- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3,
- 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32));
- }
- while (1) {
- u32 data[CX2341X_MBOX_MAX_DATA];
- ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0);
- if (s->q_full.buffers + s->q_dma.buffers == 0) {
- if (tmp == data[3])
- break;
- tmp = data[3];
- }
- if (ivtv_msleep_timeout(100, 1))
- break;
- }
- }
- 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);
-
- ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
- del_timer(&itv->dma_timer);
-
- clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- ivtv_flush_queues(s);
-
- /* decoder needs time to settle */
- ivtv_msleep_timeout(40, 0);
-
- /* decrement decoding */
- atomic_dec(&itv->decoding);
-
- set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
- wake_up(&itv->event_waitq);
- v4l2_event_queue(s->vdev, &ev);
-
- /* wake up wait queues */
- wake_up(&s->waitq);
-
- return 0;
-}
-
-int ivtv_passthrough_mode(struct ivtv *itv, int enable)
-{
- struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
- struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
-
- if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
- return -EINVAL;
-
- IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
-
- /* Prevent others from starting/stopping streams while we
- initiate/terminate passthrough mode */
- if (enable) {
- if (itv->output_mode == OUT_PASSTHROUGH) {
- return 0;
- }
- if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH)
- return -EBUSY;
-
- /* Fully initialize stream, and then unflag init */
- set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
- set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
-
- /* Setup YUV Decoder */
- ivtv_setup_v4l2_decode_stream(dec_stream);
-
- /* Start Decoder */
- ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1);
- atomic_inc(&itv->decoding);
-
- /* Setup capture if not already done */
- if (atomic_read(&itv->capturing) == 0) {
- cx2341x_handler_setup(&itv->cxhdl);
- cx2341x_handler_set_busy(&itv->cxhdl, 1);
- }
-
- /* Start Passthrough Mode */
- ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11);
- atomic_inc(&itv->capturing);
- return 0;
- }
-
- if (itv->output_mode != OUT_PASSTHROUGH)
- return 0;
-
- /* Stop Passthrough Mode */
- ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11);
- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0);
-
- atomic_dec(&itv->capturing);
- atomic_dec(&itv->decoding);
- clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
- clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
- itv->output_mode = OUT_NONE;
- if (atomic_read(&itv->capturing) == 0)
- cx2341x_handler_set_busy(&itv->cxhdl, 0);
-
- return 0;
-}
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
deleted file mode 100644
index 0b91a5cd38eb..000000000000
--- a/drivers/media/video/mem2mem_testdev.c
+++ /dev/null
@@ -1,1120 +0,0 @@
-/*
- * A virtual v4l2-mem2mem example device.
- *
- * This is a virtual device driver for testing mem-to-mem videobuf framework.
- * It simulates a device that uses memory buffers for both source and
- * destination, processes the data and issues an "irq" (simulated by a timer).
- * The device is capable of multi-instance, multi-buffer-per-transaction
- * operation (via the mem2mem framework).
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * Pawel Osciak, <pawel@osciak.com>
- * Marek Szyprowski, <m.szyprowski@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/delay.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <linux/platform_device.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-vmalloc.h>
-
-#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
-
-MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
-MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1.1");
-
-#define MIN_W 32
-#define MIN_H 32
-#define MAX_W 640
-#define MAX_H 480
-#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
-
-/* 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-testdev"
-
-/* Per queue */
-#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
-/* In bytes, per queue */
-#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
-
-/* Default transaction time in msec */
-#define MEM2MEM_DEF_TRANSTIME 1000
-/* Default number of buffers per transaction */
-#define MEM2MEM_DEF_TRANSLEN 1
-#define MEM2MEM_COLOR_STEP (0xff >> 4)
-#define MEM2MEM_NUM_TILES 8
-
-/* Flags that indicate processing mode */
-#define MEM2MEM_HFLIP (1 << 0)
-#define MEM2MEM_VFLIP (1 << 1)
-
-#define dprintk(dev, fmt, arg...) \
- v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
-
-
-void m2mtest_dev_release(struct device *dev)
-{}
-
-static struct platform_device m2mtest_pdev = {
- .name = MEM2MEM_NAME,
- .dev.release = m2mtest_dev_release,
-};
-
-struct m2mtest_fmt {
- char *name;
- u32 fourcc;
- int depth;
- /* Types the format can be used for */
- u32 types;
-};
-
-static struct m2mtest_fmt formats[] = {
- {
- .name = "RGB565 (BE)",
- .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
- .depth = 16,
- /* Both capture and output format */
- .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
- },
- {
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- /* Output-only format */
- .types = MEM2MEM_OUTPUT,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-/* Per-queue, driver-specific private data */
-struct m2mtest_q_data {
- unsigned int width;
- unsigned int height;
- unsigned int sizeimage;
- struct m2mtest_fmt *fmt;
-};
-
-enum {
- V4L2_M2M_SRC = 0,
- V4L2_M2M_DST = 1,
-};
-
-#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000)
-#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001)
-
-static struct m2mtest_fmt *find_format(struct v4l2_format *f)
-{
- struct m2mtest_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 m2mtest_dev {
- struct v4l2_device v4l2_dev;
- struct video_device *vfd;
-
- atomic_t num_inst;
- struct mutex dev_mutex;
- spinlock_t irqlock;
-
- struct timer_list timer;
-
- struct v4l2_m2m_dev *m2m_dev;
-};
-
-struct m2mtest_ctx {
- struct v4l2_fh fh;
- struct m2mtest_dev *dev;
-
- struct v4l2_ctrl_handler hdl;
-
- /* Processed buffers in this transaction */
- u8 num_processed;
-
- /* Transaction length (i.e. how many buffers per transaction) */
- u32 translen;
- /* Transaction time (i.e. simulated processing time) in milliseconds */
- u32 transtime;
-
- /* Abort requested by m2m */
- int aborting;
-
- /* Processing mode */
- int mode;
-
- enum v4l2_colorspace colorspace;
-
- struct v4l2_m2m_ctx *m2m_ctx;
-
- /* Source and destination queue data */
- struct m2mtest_q_data q_data[2];
-};
-
-static inline struct m2mtest_ctx *file2ctx(struct file *file)
-{
- return container_of(file->private_data, struct m2mtest_ctx, fh);
-}
-
-static struct m2mtest_q_data *get_q_data(struct m2mtest_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;
-}
-
-
-static int device_process(struct m2mtest_ctx *ctx,
- struct vb2_buffer *in_vb,
- struct vb2_buffer *out_vb)
-{
- struct m2mtest_dev *dev = ctx->dev;
- struct m2mtest_q_data *q_data;
- u8 *p_in, *p_out;
- int x, y, t, w;
- int tile_w, bytes_left;
- int width, height, bytesperline;
-
- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
- width = q_data->width;
- height = q_data->height;
- bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
-
- p_in = vb2_plane_vaddr(in_vb, 0);
- p_out = vb2_plane_vaddr(out_vb, 0);
- if (!p_in || !p_out) {
- v4l2_err(&dev->v4l2_dev,
- "Acquiring kernel pointers to buffers failed\n");
- return -EFAULT;
- }
-
- if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
- v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
- return -EINVAL;
- }
-
- tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
- / MEM2MEM_NUM_TILES;
- bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
- w = 0;
-
- switch (ctx->mode) {
- case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
- p_out += bytesperline * height - bytes_left;
- for (y = 0; y < height; ++y) {
- for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
- if (w & 0x1) {
- for (x = 0; x < tile_w; ++x)
- *--p_out = *p_in++ +
- MEM2MEM_COLOR_STEP;
- } else {
- for (x = 0; x < tile_w; ++x)
- *--p_out = *p_in++ -
- MEM2MEM_COLOR_STEP;
- }
- ++w;
- }
- p_in += bytes_left;
- p_out -= bytes_left;
- }
- break;
-
- case MEM2MEM_HFLIP:
- for (y = 0; y < height; ++y) {
- p_out += MEM2MEM_NUM_TILES * tile_w;
- for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
- if (w & 0x01) {
- for (x = 0; x < tile_w; ++x)
- *--p_out = *p_in++ +
- MEM2MEM_COLOR_STEP;
- } else {
- for (x = 0; x < tile_w; ++x)
- *--p_out = *p_in++ -
- MEM2MEM_COLOR_STEP;
- }
- ++w;
- }
- p_in += bytes_left;
- p_out += bytesperline;
- }
- break;
-
- case MEM2MEM_VFLIP:
- p_out += bytesperline * (height - 1);
- for (y = 0; y < height; ++y) {
- for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
- if (w & 0x1) {
- for (x = 0; x < tile_w; ++x)
- *p_out++ = *p_in++ +
- MEM2MEM_COLOR_STEP;
- } else {
- for (x = 0; x < tile_w; ++x)
- *p_out++ = *p_in++ -
- MEM2MEM_COLOR_STEP;
- }
- ++w;
- }
- p_in += bytes_left;
- p_out += bytes_left - 2 * bytesperline;
- }
- break;
-
- default:
- for (y = 0; y < height; ++y) {
- for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
- if (w & 0x1) {
- for (x = 0; x < tile_w; ++x)
- *p_out++ = *p_in++ +
- MEM2MEM_COLOR_STEP;
- } else {
- for (x = 0; x < tile_w; ++x)
- *p_out++ = *p_in++ -
- MEM2MEM_COLOR_STEP;
- }
- ++w;
- }
- p_in += bytes_left;
- p_out += bytes_left;
- }
- }
-
- return 0;
-}
-
-static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
-{
- dprintk(dev, "Scheduling a simulated irq\n");
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
-}
-
-/*
- * mem2mem callbacks
- */
-
-/**
- * job_ready() - check whether an instance is ready to be scheduled to run
- */
-static int job_ready(void *priv)
-{
- struct m2mtest_ctx *ctx = priv;
-
- if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
- || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
- dprintk(ctx->dev, "Not enough buffers available\n");
- return 0;
- }
-
- return 1;
-}
-
-static void job_abort(void *priv)
-{
- struct m2mtest_ctx *ctx = priv;
-
- /* Will cancel the transaction in the next interrupt handler */
- ctx->aborting = 1;
-}
-
-static void m2mtest_lock(void *priv)
-{
- struct m2mtest_ctx *ctx = priv;
- struct m2mtest_dev *dev = ctx->dev;
- mutex_lock(&dev->dev_mutex);
-}
-
-static void m2mtest_unlock(void *priv)
-{
- struct m2mtest_ctx *ctx = priv;
- struct m2mtest_dev *dev = ctx->dev;
- mutex_unlock(&dev->dev_mutex);
-}
-
-
-/* device_run() - prepares and starts the device
- *
- * This simulates all the immediate preparations required before starting
- * a device. This will be called by the framework when it decides to schedule
- * a particular instance.
- */
-static void device_run(void *priv)
-{
- struct m2mtest_ctx *ctx = priv;
- struct m2mtest_dev *dev = ctx->dev;
- struct vb2_buffer *src_buf, *dst_buf;
-
- src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-
- device_process(ctx, src_buf, dst_buf);
-
- /* Run a timer, which simulates a hardware irq */
- schedule_irq(dev, ctx->transtime);
-}
-
-static void device_isr(unsigned long priv)
-{
- struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
- struct m2mtest_ctx *curr_ctx;
- struct vb2_buffer *src_vb, *dst_vb;
- unsigned long flags;
-
- curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
-
- if (NULL == curr_ctx) {
- printk(KERN_ERR
- "Instance released before the end of transaction\n");
- return;
- }
-
- src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
- dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
-
- curr_ctx->num_processed++;
-
- spin_lock_irqsave(&m2mtest_dev->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(&m2mtest_dev->irqlock, flags);
-
- if (curr_ctx->num_processed == curr_ctx->translen
- || curr_ctx->aborting) {
- dprintk(curr_ctx->dev, "Finishing transaction\n");
- curr_ctx->num_processed = 0;
- v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
- } else {
- device_run(curr_ctx);
- }
-}
-
-/*
- * 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);
- strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
-{
- int i, num;
- struct m2mtest_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];
- strncpy(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 m2mtest_ctx *ctx, struct v4l2_format *f)
-{
- struct vb2_queue *vq;
- struct m2mtest_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;
- f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
- f->fmt.pix.sizeimage = q_data->sizeimage;
- f->fmt.pix.colorspace = ctx->colorspace;
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- return vidioc_g_fmt(file2ctx(file), f);
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- return vidioc_g_fmt(file2ctx(file), f);
-}
-
-static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
-{
- enum v4l2_field field;
-
- 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.height < MIN_H)
- f->fmt.pix.height = MIN_H;
- else if (f->fmt.pix.height > MAX_H)
- f->fmt.pix.height = MAX_H;
-
- if (f->fmt.pix.width < MIN_W)
- f->fmt.pix.width = MIN_W;
- else if (f->fmt.pix.width > MAX_W)
- f->fmt.pix.width = MAX_W;
-
- f->fmt.pix.width &= ~DIM_ALIGN_MASK;
- 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_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct m2mtest_fmt *fmt;
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- 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;
- }
- f->fmt.pix.colorspace = ctx->colorspace;
-
- return vidioc_try_fmt(f, fmt);
-}
-
-static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct m2mtest_fmt *fmt;
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- 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;
- }
- if (!f->fmt.pix.colorspace)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
-
- return vidioc_try_fmt(f, fmt);
-}
-
-static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
-{
- struct m2mtest_q_data *q_data;
- struct vb2_queue *vq;
-
- 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;
- }
-
- q_data->fmt = find_format(f);
- q_data->width = f->fmt.pix.width;
- q_data->height = f->fmt.pix.height;
- q_data->sizeimage = q_data->width * q_data->height
- * q_data->fmt->depth >> 3;
-
- 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(file2ctx(file), f);
-}
-
-static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
- int ret;
-
- ret = vidioc_try_fmt_vid_out(file, priv, f);
- if (ret)
- return ret;
-
- ret = vidioc_s_fmt(file2ctx(file), f);
- if (!ret)
- ctx->colorspace = f->fmt.pix.colorspace;
- return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
-static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct m2mtest_ctx *ctx =
- container_of(ctrl->handler, struct m2mtest_ctx, hdl);
-
- switch (ctrl->id) {
- case V4L2_CID_HFLIP:
- if (ctrl->val)
- ctx->mode |= MEM2MEM_HFLIP;
- else
- ctx->mode &= ~MEM2MEM_HFLIP;
- break;
-
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- ctx->mode |= MEM2MEM_VFLIP;
- else
- ctx->mode &= ~MEM2MEM_VFLIP;
- break;
-
- case V4L2_CID_TRANS_TIME_MSEC:
- ctx->transtime = ctrl->val;
- break;
-
- case V4L2_CID_TRANS_NUM_BUFS:
- ctx->translen = ctrl->val;
- break;
-
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = {
- .s_ctrl = m2mtest_s_ctrl,
-};
-
-
-static const struct v4l2_ioctl_ops m2mtest_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,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-
-/*
- * Queue operations
- */
-
-static int m2mtest_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
- struct m2mtest_q_data *q_data;
- unsigned int size, count = *nbuffers;
-
- q_data = get_q_data(ctx, vq->type);
-
- size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
-
- while (size * count > MEM2MEM_VID_MEM_LIMIT)
- (count)--;
-
- *nplanes = 1;
- *nbuffers = count;
- sizes[0] = size;
-
- /*
- * videobuf2-vmalloc allocator is context-less so no need to set
- * alloc_ctxs array.
- */
-
- dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
-
- return 0;
-}
-
-static int m2mtest_buf_prepare(struct vb2_buffer *vb)
-{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct m2mtest_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 m2mtest_buf_queue(struct vb2_buffer *vb)
-{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void m2mtest_wait_prepare(struct vb2_queue *q)
-{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
- m2mtest_unlock(ctx);
-}
-
-static void m2mtest_wait_finish(struct vb2_queue *q)
-{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
- m2mtest_lock(ctx);
-}
-
-static struct vb2_ops m2mtest_qops = {
- .queue_setup = m2mtest_queue_setup,
- .buf_prepare = m2mtest_buf_prepare,
- .buf_queue = m2mtest_buf_queue,
- .wait_prepare = m2mtest_wait_prepare,
- .wait_finish = m2mtest_wait_finish,
-};
-
-static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
-{
- struct m2mtest_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 = &m2mtest_qops;
- src_vq->mem_ops = &vb2_vmalloc_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 = &m2mtest_qops;
- dst_vq->mem_ops = &vb2_vmalloc_memops;
-
- return vb2_queue_init(dst_vq);
-}
-
-static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
- .ops = &m2mtest_ctrl_ops,
- .id = V4L2_CID_TRANS_TIME_MSEC,
- .name = "Transaction Time (msec)",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .def = 1001,
- .min = 1,
- .max = 10001,
- .step = 100,
-};
-
-static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
- .ops = &m2mtest_ctrl_ops,
- .id = V4L2_CID_TRANS_NUM_BUFS,
- .name = "Buffers Per Transaction",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .def = 1,
- .min = 1,
- .max = MEM2MEM_DEF_NUM_BUFS,
- .step = 1,
-};
-
-/*
- * File operations
- */
-static int m2mtest_open(struct file *file)
-{
- struct m2mtest_dev *dev = video_drvdata(file);
- struct m2mtest_ctx *ctx = NULL;
- struct v4l2_ctrl_handler *hdl;
-
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
- ctx->dev = dev;
- hdl = &ctx->hdl;
- v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL);
- v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL);
- if (hdl->error) {
- int err = hdl->error;
-
- v4l2_ctrl_handler_free(hdl);
- return err;
- }
- ctx->fh.ctrl_handler = hdl;
- v4l2_ctrl_handler_setup(hdl);
-
- ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
- ctx->q_data[V4L2_M2M_SRC].width = 640;
- ctx->q_data[V4L2_M2M_SRC].height = 480;
- ctx->q_data[V4L2_M2M_SRC].sizeimage =
- ctx->q_data[V4L2_M2M_SRC].width *
- ctx->q_data[V4L2_M2M_SRC].height *
- (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
- ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
- ctx->colorspace = V4L2_COLORSPACE_REC709;
-
- ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
-
- if (IS_ERR(ctx->m2m_ctx)) {
- int ret = PTR_ERR(ctx->m2m_ctx);
-
- v4l2_ctrl_handler_free(hdl);
- kfree(ctx);
- return ret;
- }
-
- v4l2_fh_add(&ctx->fh);
- atomic_inc(&dev->num_inst);
-
- dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
-
- return 0;
-}
-
-static int m2mtest_release(struct file *file)
-{
- struct m2mtest_dev *dev = video_drvdata(file);
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- dprintk(dev, "Releasing instance %p\n", ctx);
-
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- v4l2_ctrl_handler_free(&ctx->hdl);
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
- kfree(ctx);
-
- atomic_dec(&dev->num_inst);
-
- return 0;
-}
-
-static unsigned int m2mtest_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-}
-
-static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct m2mtest_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-}
-
-static const struct v4l2_file_operations m2mtest_fops = {
- .owner = THIS_MODULE,
- .open = m2mtest_open,
- .release = m2mtest_release,
- .poll = m2mtest_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = m2mtest_mmap,
-};
-
-static struct video_device m2mtest_videodev = {
- .name = MEM2MEM_NAME,
- .fops = &m2mtest_fops,
- .ioctl_ops = &m2mtest_ioctl_ops,
- .minor = -1,
- .release = video_device_release,
-};
-
-static struct v4l2_m2m_ops m2m_ops = {
- .device_run = device_run,
- .job_ready = job_ready,
- .job_abort = job_abort,
- .lock = m2mtest_lock,
- .unlock = m2mtest_unlock,
-};
-
-static int m2mtest_probe(struct platform_device *pdev)
-{
- struct m2mtest_dev *dev;
- struct video_device *vfd;
- int ret;
-
- dev = kzalloc(sizeof *dev, GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- spin_lock_init(&dev->irqlock);
-
- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
- if (ret)
- goto free_dev;
-
- atomic_set(&dev->num_inst, 0);
- mutex_init(&dev->dev_mutex);
-
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
- ret = -ENOMEM;
- goto unreg_dev;
- }
-
- *vfd = m2mtest_videodev;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- vfd->lock = &dev->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", m2mtest_videodev.name);
- dev->vfd = vfd;
- v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
- "Device registered as /dev/video%d\n", vfd->num);
-
- setup_timer(&dev->timer, device_isr, (long)dev);
- platform_set_drvdata(pdev, dev);
-
- dev->m2m_dev = v4l2_m2m_init(&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 err_m2m;
- }
-
- return 0;
-
- v4l2_m2m_release(dev->m2m_dev);
-err_m2m:
- video_unregister_device(dev->vfd);
-rel_vdev:
- video_device_release(vfd);
-unreg_dev:
- v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
- kfree(dev);
-
- return ret;
-}
-
-static int m2mtest_remove(struct platform_device *pdev)
-{
- struct m2mtest_dev *dev =
- (struct m2mtest_dev *)platform_get_drvdata(pdev);
-
- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
- v4l2_m2m_release(dev->m2m_dev);
- del_timer_sync(&dev->timer);
- video_unregister_device(dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
-
- return 0;
-}
-
-static struct platform_driver m2mtest_pdrv = {
- .probe = m2mtest_probe,
- .remove = m2mtest_remove,
- .driver = {
- .name = MEM2MEM_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static void __exit m2mtest_exit(void)
-{
- platform_driver_unregister(&m2mtest_pdrv);
- platform_device_unregister(&m2mtest_pdev);
-}
-
-static int __init m2mtest_init(void)
-{
- int ret;
-
- ret = platform_device_register(&m2mtest_pdev);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&m2mtest_pdrv);
- if (ret)
- platform_device_unregister(&m2mtest_pdev);
-
- return 0;
-}
-
-module_init(m2mtest_init);
-module_exit(m2mtest_exit);
-
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
deleted file mode 100644
index 00583f5fd26b..000000000000
--- a/drivers/media/video/mt9m001.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * Driver for MT9M001 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/videodev2.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-
-/*
- * mt9m001 i2c address 0x5d
- * The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_link
- */
-
-/* mt9m001 selected register addresses */
-#define MT9M001_CHIP_VERSION 0x00
-#define MT9M001_ROW_START 0x01
-#define MT9M001_COLUMN_START 0x02
-#define MT9M001_WINDOW_HEIGHT 0x03
-#define MT9M001_WINDOW_WIDTH 0x04
-#define MT9M001_HORIZONTAL_BLANKING 0x05
-#define MT9M001_VERTICAL_BLANKING 0x06
-#define MT9M001_OUTPUT_CONTROL 0x07
-#define MT9M001_SHUTTER_WIDTH 0x09
-#define MT9M001_FRAME_RESTART 0x0b
-#define MT9M001_SHUTTER_DELAY 0x0c
-#define MT9M001_RESET 0x0d
-#define MT9M001_READ_OPTIONS1 0x1e
-#define MT9M001_READ_OPTIONS2 0x20
-#define MT9M001_GLOBAL_GAIN 0x35
-#define MT9M001_CHIP_ENABLE 0xF1
-
-#define MT9M001_MAX_WIDTH 1280
-#define MT9M001_MAX_HEIGHT 1024
-#define MT9M001_MIN_WIDTH 48
-#define MT9M001_MIN_HEIGHT 32
-#define MT9M001_COLUMN_SKIP 20
-#define MT9M001_ROW_SKIP 12
-
-/* MT9M001 has only one fixed colorspace per pixelcode */
-struct mt9m001_datafmt {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct mt9m001_datafmt *mt9m001_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct mt9m001_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 mt9m001_datafmt mt9m001_colour_fmts[] = {
- /*
- * Order important: first natively supported,
- * second supported with a GPIO extender
- */
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
-};
-
-static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
- /* Order important - see above */
- {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
-};
-
-struct mt9m001 {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct {
- /* exposure/auto-exposure cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
- };
- struct v4l2_rect rect; /* Sensor window */
- const struct mt9m001_datafmt *fmt;
- const struct mt9m001_datafmt *fmts;
- int num_fmts;
- int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
- unsigned int total_h;
- unsigned short y_skip_top; /* Lines to skip at the top */
-};
-
-static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u8 reg)
-{
- 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_swapped(client, reg, data);
-}
-
-static int reg_set(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret | data);
-}
-
-static int reg_clear(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret & ~data);
-}
-
-static int mt9m001_init(struct i2c_client *client)
-{
- int ret;
-
- dev_dbg(&client->dev, "%s\n", __func__);
-
- /*
- * We don't know, whether platform provides reset, issue a soft reset
- * too. This returns all registers to their default values.
- */
- ret = reg_write(client, MT9M001_RESET, 1);
- if (!ret)
- ret = reg_write(client, MT9M001_RESET, 0);
-
- /* Disable chip, synchronous option update */
- if (!ret)
- ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
-
- return ret;
-}
-
-static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- /* Switch to master "normal" mode or stop sensor readout */
- if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
- return -EIO;
- return 0;
-}
-
-static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- struct v4l2_rect rect = a->c;
- int ret;
- const u16 hblank = 9, vblank = 25;
-
- if (mt9m001->fmts == mt9m001_colour_fmts)
- /*
- * Bayer format - even number of rows for simplicity,
- * but let the user play with the top row.
- */
- rect.height = ALIGN(rect.height, 2);
-
- /* Datasheet requirement: see register description */
- rect.width = ALIGN(rect.width, 2);
- rect.left = ALIGN(rect.left, 2);
-
- soc_camera_limit_side(&rect.left, &rect.width,
- MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
-
- soc_camera_limit_side(&rect.top, &rect.height,
- MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
-
- mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
-
- /* Blanking and start values - default... */
- ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
- if (!ret)
- ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
-
- /*
- * The caller provides a supported format, as verified per
- * call to .try_mbus_fmt()
- */
- if (!ret)
- ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
- if (!ret)
- ret = reg_write(client, MT9M001_ROW_START, rect.top);
- if (!ret)
- ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
- if (!ret)
- ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
- rect.height + mt9m001->y_skip_top - 1);
- if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
- ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
-
- if (!ret)
- mt9m001->rect = rect;
-
- return ret;
-}
-
-static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- a->c = mt9m001->rect;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = MT9M001_COLUMN_SKIP;
- a->bounds.top = MT9M001_ROW_SKIP;
- a->bounds.width = MT9M001_MAX_WIDTH;
- a->bounds.height = MT9M001_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int mt9m001_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- mf->width = mt9m001->rect.width;
- mf->height = mt9m001->rect.height;
- mf->code = mt9m001->fmt->code;
- mf->colorspace = mt9m001->fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9m001_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- struct v4l2_crop a = {
- .c = {
- .left = mt9m001->rect.left,
- .top = mt9m001->rect.top,
- .width = mf->width,
- .height = mf->height,
- },
- };
- int ret;
-
- /* No support for scaling so far, just crop. TODO: use skipping */
- ret = mt9m001_s_crop(sd, &a);
- if (!ret) {
- mf->width = mt9m001->rect.width;
- mf->height = mt9m001->rect.height;
- mt9m001->fmt = mt9m001_find_datafmt(mf->code,
- mt9m001->fmts, mt9m001->num_fmts);
- mf->colorspace = mt9m001->fmt->colorspace;
- }
-
- return ret;
-}
-
-static int mt9m001_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- const struct mt9m001_datafmt *fmt;
-
- v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
- MT9M001_MAX_WIDTH, 1,
- &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
- MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
-
- if (mt9m001->fmts == mt9m001_colour_fmts)
- mf->height = ALIGN(mf->height - 1, 2);
-
- fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
- mt9m001->num_fmts);
- if (!fmt) {
- fmt = mt9m001->fmt;
- mf->code = fmt->code;
- }
-
- mf->colorspace = fmt->colorspace;
-
- return 0;
-}
-
-static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9m001->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m001_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- reg->size = 2;
- reg->val = reg_read(client, reg->reg);
-
- if (reg->val > 0xffff)
- return -EIO;
-
- return 0;
-}
-
-static int mt9m001_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- if (reg_write(client, reg->reg, reg->val) < 0)
- return -EIO;
-
- return 0;
-}
-#endif
-
-static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9m001 *mt9m001 = container_of(ctrl->handler,
- struct mt9m001, hdl);
- s32 min, max;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE_AUTO:
- min = mt9m001->exposure->minimum;
- max = mt9m001->exposure->maximum;
- mt9m001->exposure->val =
- (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
- break;
- }
- return 0;
-}
-
-static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9m001 *mt9m001 = container_of(ctrl->handler,
- struct mt9m001, hdl);
- struct v4l2_subdev *sd = &mt9m001->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct v4l2_ctrl *exp = mt9m001->exposure;
- int data;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
- else
- data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
- if (data < 0)
- return -EIO;
- return 0;
-
- case V4L2_CID_GAIN:
- /* See Datasheet Table 7, Gain settings. */
- if (ctrl->val <= ctrl->default_value) {
- /* Pack it into 0..1 step 0.125, register values 0..8 */
- unsigned long range = ctrl->default_value - ctrl->minimum;
- data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
-
- dev_dbg(&client->dev, "Setting gain %d\n", data);
- data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
- if (data < 0)
- return -EIO;
- } else {
- /* Pack it into 1.125..15 variable step, register values 9..67 */
- /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
- unsigned long range = ctrl->maximum - ctrl->default_value - 1;
- unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
- 111 + range / 2) / range + 9;
-
- if (gain <= 32)
- data = gain;
- else if (gain <= 64)
- data = ((gain - 32) * 16 + 16) / 32 + 80;
- else
- data = ((gain - 64) * 7 + 28) / 56 + 96;
-
- dev_dbg(&client->dev, "Setting gain from %d to %d\n",
- reg_read(client, MT9M001_GLOBAL_GAIN), data);
- data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
- if (data < 0)
- return -EIO;
- }
- return 0;
-
- case V4L2_CID_EXPOSURE_AUTO:
- if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
- unsigned long range = exp->maximum - exp->minimum;
- unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
- range / 2) / range + 1;
-
- dev_dbg(&client->dev,
- "Setting shutter width from %d to %lu\n",
- reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
- if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
- return -EIO;
- } else {
- const u16 vblank = 25;
-
- mt9m001->total_h = mt9m001->rect.height +
- mt9m001->y_skip_top + vblank;
- if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
- return -EIO;
- }
- return 0;
- }
- return -EINVAL;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9m001_video_probe(struct soc_camera_link *icl,
- struct i2c_client *client)
-{
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- s32 data;
- unsigned long flags;
- int ret;
-
- /* Enable the chip */
- data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
- dev_dbg(&client->dev, "write: %d\n", data);
-
- /* Read out the chip version register */
- data = reg_read(client, MT9M001_CHIP_VERSION);
-
- /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
- switch (data) {
- case 0x8411:
- case 0x8421:
- mt9m001->model = V4L2_IDENT_MT9M001C12ST;
- mt9m001->fmts = mt9m001_colour_fmts;
- break;
- case 0x8431:
- mt9m001->model = V4L2_IDENT_MT9M001C12STM;
- mt9m001->fmts = mt9m001_monochrome_fmts;
- break;
- default:
- dev_err(&client->dev,
- "No MT9M001 chip detected, register read %x\n", data);
- return -ENODEV;
- }
-
- mt9m001->num_fmts = 0;
-
- /*
- * This is a 10bit sensor, so by default we only allow 10bit.
- * The platform may support different bus widths due to
- * different routing of the data lines.
- */
- if (icl->query_bus_param)
- flags = icl->query_bus_param(icl);
- else
- flags = SOCAM_DATAWIDTH_10;
-
- if (flags & SOCAM_DATAWIDTH_10)
- mt9m001->num_fmts++;
- else
- mt9m001->fmts++;
-
- if (flags & SOCAM_DATAWIDTH_8)
- mt9m001->num_fmts++;
-
- mt9m001->fmt = &mt9m001->fmts[0];
-
- dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
- data == 0x8431 ? "C12STM" : "C12ST");
-
- ret = mt9m001_init(client);
- if (ret < 0)
- dev_err(&client->dev, "Failed to initialise the camera\n");
-
- /* mt9m001_init() has reset the chip, returning registers to defaults */
- return v4l2_ctrl_handler_setup(&mt9m001->hdl);
-}
-
-static void mt9m001_video_remove(struct soc_camera_link *icl)
-{
- if (icl->free_bus)
- icl->free_bus(icl);
-}
-
-static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- *lines = mt9m001->y_skip_top;
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
- .g_volatile_ctrl = mt9m001_g_volatile_ctrl,
- .s_ctrl = mt9m001_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
- .g_chip_ident = mt9m001_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9m001_g_register,
- .s_register = mt9m001_s_register,
-#endif
-};
-
-static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
-
- if (index >= mt9m001->num_fmts)
- return -EINVAL;
-
- *code = mt9m001->fmts[index].code;
- return 0;
-}
-
-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- /* MT9M001 has all capture_format parameters fixed */
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- const struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
-
- if (icl->set_bus_param)
- return icl->set_bus_param(icl, 1 << (bps - 1));
-
- /*
- * Without board specific bus width settings we only support the
- * sensors native bus width
- */
- return bps == 10 ? 0 : -EINVAL;
-}
-
-static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
- .s_stream = mt9m001_s_stream,
- .s_mbus_fmt = mt9m001_s_fmt,
- .g_mbus_fmt = mt9m001_g_fmt,
- .try_mbus_fmt = mt9m001_try_fmt,
- .s_crop = mt9m001_s_crop,
- .g_crop = mt9m001_g_crop,
- .cropcap = mt9m001_cropcap,
- .enum_mbus_fmt = mt9m001_enum_fmt,
- .g_mbus_config = mt9m001_g_mbus_config,
- .s_mbus_config = mt9m001_s_mbus_config,
-};
-
-static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
- .g_skip_top_lines = mt9m001_g_skip_top_lines,
-};
-
-static struct v4l2_subdev_ops mt9m001_subdev_ops = {
- .core = &mt9m001_subdev_core_ops,
- .video = &mt9m001_subdev_video_ops,
- .sensor = &mt9m001_subdev_sensor_ops,
-};
-
-static int mt9m001_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct mt9m001 *mt9m001;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "MT9M001 driver needs platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
- if (!mt9m001)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
- v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
- v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
- V4L2_CID_GAIN, 0, 127, 1, 64);
- mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, 255, 1, 255);
- /*
- * Simulated autoexposure. If enabled, we calculate shutter width
- * ourselves in the driver based on vertical blanking and frame width
- */
- mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
- &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
- V4L2_EXPOSURE_AUTO);
- mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
- if (mt9m001->hdl.error) {
- int err = mt9m001->hdl.error;
-
- kfree(mt9m001);
- return err;
- }
- v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
- V4L2_EXPOSURE_MANUAL, true);
-
- /* Second stage probe - when a capture adapter is there */
- mt9m001->y_skip_top = 0;
- mt9m001->rect.left = MT9M001_COLUMN_SKIP;
- mt9m001->rect.top = MT9M001_ROW_SKIP;
- mt9m001->rect.width = MT9M001_MAX_WIDTH;
- mt9m001->rect.height = MT9M001_MAX_HEIGHT;
-
- ret = mt9m001_video_probe(icl, client);
- if (ret) {
- v4l2_ctrl_handler_free(&mt9m001->hdl);
- kfree(mt9m001);
- }
-
- return ret;
-}
-
-static int mt9m001_remove(struct i2c_client *client)
-{
- struct mt9m001 *mt9m001 = to_mt9m001(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- v4l2_device_unregister_subdev(&mt9m001->subdev);
- v4l2_ctrl_handler_free(&mt9m001->hdl);
- mt9m001_video_remove(icl);
- kfree(mt9m001);
-
- return 0;
-}
-
-static const struct i2c_device_id mt9m001_id[] = {
- { "mt9m001", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9m001_id);
-
-static struct i2c_driver mt9m001_i2c_driver = {
- .driver = {
- .name = "mt9m001",
- },
- .probe = mt9m001_probe,
- .remove = mt9m001_remove,
- .id_table = mt9m001_id,
-};
-
-module_i2c_driver(mt9m001_i2c_driver);
-
-MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
deleted file mode 100644
index 863d722dda06..000000000000
--- a/drivers/media/video/mt9m111.c
+++ /dev/null
@@ -1,1014 +0,0 @@
-/*
- * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
- *
- * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
- *
- * 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/videodev2.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/log2.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
-
-/*
- * MT9M111, MT9M112 and MT9M131:
- * i2c address is 0x48 or 0x5d (depending on SADDR pin)
- * The platform has to define i2c_board_info and call i2c_register_board_info()
- */
-
-/*
- * Sensor core register addresses (0x000..0x0ff)
- */
-#define MT9M111_CHIP_VERSION 0x000
-#define MT9M111_ROW_START 0x001
-#define MT9M111_COLUMN_START 0x002
-#define MT9M111_WINDOW_HEIGHT 0x003
-#define MT9M111_WINDOW_WIDTH 0x004
-#define MT9M111_HORIZONTAL_BLANKING_B 0x005
-#define MT9M111_VERTICAL_BLANKING_B 0x006
-#define MT9M111_HORIZONTAL_BLANKING_A 0x007
-#define MT9M111_VERTICAL_BLANKING_A 0x008
-#define MT9M111_SHUTTER_WIDTH 0x009
-#define MT9M111_ROW_SPEED 0x00a
-#define MT9M111_EXTRA_DELAY 0x00b
-#define MT9M111_SHUTTER_DELAY 0x00c
-#define MT9M111_RESET 0x00d
-#define MT9M111_READ_MODE_B 0x020
-#define MT9M111_READ_MODE_A 0x021
-#define MT9M111_FLASH_CONTROL 0x023
-#define MT9M111_GREEN1_GAIN 0x02b
-#define MT9M111_BLUE_GAIN 0x02c
-#define MT9M111_RED_GAIN 0x02d
-#define MT9M111_GREEN2_GAIN 0x02e
-#define MT9M111_GLOBAL_GAIN 0x02f
-#define MT9M111_CONTEXT_CONTROL 0x0c8
-#define MT9M111_PAGE_MAP 0x0f0
-#define MT9M111_BYTE_WISE_ADDR 0x0f1
-
-#define MT9M111_RESET_SYNC_CHANGES (1 << 15)
-#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9)
-#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8)
-#define MT9M111_RESET_RESET_SOC (1 << 5)
-#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4)
-#define MT9M111_RESET_CHIP_ENABLE (1 << 3)
-#define MT9M111_RESET_ANALOG_STANDBY (1 << 2)
-#define MT9M111_RESET_RESTART_FRAME (1 << 1)
-#define MT9M111_RESET_RESET_MODE (1 << 0)
-
-#define MT9M111_RM_FULL_POWER_RD (0 << 10)
-#define MT9M111_RM_LOW_POWER_RD (1 << 10)
-#define MT9M111_RM_COL_SKIP_4X (1 << 5)
-#define MT9M111_RM_ROW_SKIP_4X (1 << 4)
-#define MT9M111_RM_COL_SKIP_2X (1 << 3)
-#define MT9M111_RM_ROW_SKIP_2X (1 << 2)
-#define MT9M111_RMB_MIRROR_COLS (1 << 1)
-#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
-#define MT9M111_CTXT_CTRL_RESTART (1 << 15)
-#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12)
-#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10)
-#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9)
-#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8)
-#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7)
-#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3)
-#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
-#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
-#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
-
-/*
- * Colorpipe register addresses (0x100..0x1ff)
- */
-#define MT9M111_OPER_MODE_CTRL 0x106
-#define MT9M111_OUTPUT_FORMAT_CTRL 0x108
-#define MT9M111_REDUCER_XZOOM_B 0x1a0
-#define MT9M111_REDUCER_XSIZE_B 0x1a1
-#define MT9M111_REDUCER_YZOOM_B 0x1a3
-#define MT9M111_REDUCER_YSIZE_B 0x1a4
-#define MT9M111_REDUCER_XZOOM_A 0x1a6
-#define MT9M111_REDUCER_XSIZE_A 0x1a7
-#define MT9M111_REDUCER_YZOOM_A 0x1a9
-#define MT9M111_REDUCER_YSIZE_A 0x1aa
-
-#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
-#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
-
-#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
-#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
-#define MT9M111_OUTFMT_FLIP_BAYER_COL (1 << 9)
-#define MT9M111_OUTFMT_FLIP_BAYER_ROW (1 << 8)
-#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
-#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
-#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
-#define MT9M111_OUTFMT_RGB (1 << 8)
-#define MT9M111_OUTFMT_RGB565 (0 << 6)
-#define MT9M111_OUTFMT_RGB555 (1 << 6)
-#define MT9M111_OUTFMT_RGB444x (2 << 6)
-#define MT9M111_OUTFMT_RGBx444 (3 << 6)
-#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4)
-#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
-#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
-#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
-#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0)
-
-/*
- * Camera control register addresses (0x200..0x2ff not implemented)
- */
-
-#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
-#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
-#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
-#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
-#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
- (val), (mask))
-
-#define MT9M111_MIN_DARK_ROWS 8
-#define MT9M111_MIN_DARK_COLS 26
-#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;
-};
-
-static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
-};
-
-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 */
- 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 */
-};
-
-/* 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);
-}
-
-static int reg_page_map_set(struct i2c_client *client, const u16 reg)
-{
- int ret;
- u16 page;
- struct mt9m111 *mt9m111 = to_mt9m111(client);
-
- page = (reg >> 8);
- if (page == mt9m111->lastpage)
- return 0;
- if (page > 2)
- return -EINVAL;
-
- ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
- if (!ret)
- mt9m111->lastpage = page;
- return ret;
-}
-
-static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
-{
- int ret;
-
- ret = reg_page_map_set(client, reg);
- if (!ret)
- ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
-
- dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
- return ret;
-}
-
-static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_page_map_set(client, reg);
- if (!ret)
- 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;
-}
-
-static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
- const u16 data)
-{
- int ret;
-
- ret = mt9m111_reg_read(client, reg);
- if (ret >= 0)
- ret = mt9m111_reg_write(client, reg, ret | data);
- return ret;
-}
-
-static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
- const u16 data)
-{
- int ret;
-
- ret = mt9m111_reg_read(client, reg);
- if (ret >= 0)
- ret = mt9m111_reg_write(client, reg, ret & ~data);
- return ret;
-}
-
-static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
- const u16 data, const u16 mask)
-{
- int ret;
-
- ret = mt9m111_reg_read(client, reg);
- if (ret >= 0)
- ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
- return ret;
-}
-
-static int mt9m111_set_context(struct mt9m111 *mt9m111,
- struct mt9m111_context *ctx)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- return reg_write(CONTEXT_CONTROL, ctx->control);
-}
-
-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 = 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;
-}
-
-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 (!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 = mt9m111_setup_rect_ctx(mt9m111, &context_b,
- rect, width, height);
- if (!ret)
- 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);
- return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
-}
-
-static int mt9m111_reset(struct mt9m111 *mt9m111)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int ret;
-
- ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
- if (!ret)
- ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
- if (!ret)
- ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
- | MT9M111_RESET_RESET_SOC);
-
- return ret;
-}
-
-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);
- /* Let the user play with the starting pixel */
- }
-
- /* FIXME: the datasheet doesn't specify minimum sizes */
- soc_camera_limit_side(&rect.left, &rect.width,
- MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
-
- soc_camera_limit_side(&rect.top, &rect.height,
- MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
-
- width = min(mt9m111->width, rect.width);
- height = min(mt9m111->height, rect.height);
-
- ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
- if (!ret) {
- mt9m111->rect = rect;
- mt9m111->width = width;
- mt9m111->height = height;
- }
-
- return ret;
-}
-
-static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
- a->c = mt9m111->rect;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- a->bounds.left = MT9M111_MIN_DARK_COLS;
- a->bounds.top = MT9M111_MIN_DARK_ROWS;
- a->bounds.width = MT9M111_MAX_WIDTH;
- a->bounds.height = MT9M111_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int mt9m111_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
- mf->width = mt9m111->width;
- mf->height = mt9m111->height;
- mf->code = mt9m111->fmt->code;
- mf->colorspace = mt9m111->fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
- enum v4l2_mbus_pixelcode code)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
- MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
- MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
- MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
- MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
- MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
- int ret;
-
- switch (code) {
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
- MT9M111_OUTFMT_RGB;
- break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
- data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
- break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
- MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
- break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
- break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
- MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
- break;
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
- break;
- case V4L2_MBUS_FMT_BGR565_2X8_BE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
- MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
- break;
- case V4L2_MBUS_FMT_BGR565_2X8_LE:
- data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
- MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
- MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
- break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- data_outfmt2 = 0;
- break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
- data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
- break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
- break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
- data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
- MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
- break;
- default:
- dev_err(&client->dev, "Pixel format not handled: %x\n", code);
- return -EINVAL;
- }
-
- ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
- data_outfmt2, mask_outfmt2);
- if (!ret)
- ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
- data_outfmt2, mask_outfmt2);
-
- return ret;
-}
-
-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;
- 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 (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;
- }
-
- 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)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9m111->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m111_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int val;
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
- return -EINVAL;
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- val = mt9m111_reg_read(client, reg->reg);
- reg->size = 2;
- reg->val = (u64)val;
-
- if (reg->val > 0xffff)
- return -EIO;
-
- return 0;
-}
-
-static int mt9m111_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
- return -EIO;
-
- return 0;
-}
-#endif
-
-static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int ret;
-
- 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;
-}
-
-static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int data;
-
- data = reg_read(GLOBAL_GAIN);
- if (data >= 0)
- return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
- (1 << ((data >> 9) & 1));
- return data;
-}
-
-static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- u16 val;
-
- if (gain > 63 * 2 * 2)
- return -EINVAL;
-
- if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
- val = (1 << 10) | (1 << 9) | (gain / 4);
- else if ((gain >= 64) && (gain < 64 * 2))
- val = (1 << 9) | (gain / 2);
- else
- val = gain;
-
- return reg_write(GLOBAL_GAIN, val);
-}
-
-static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-
- if (on)
- return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
- return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
-}
-
-static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-
- if (on)
- return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
- return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
-}
-
-static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9m111 *mt9m111 = container_of(ctrl->handler,
- struct mt9m111, hdl);
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- return mt9m111_set_flip(mt9m111, ctrl->val,
- MT9M111_RMB_MIRROR_ROWS);
- case V4L2_CID_HFLIP:
- return mt9m111_set_flip(mt9m111, ctrl->val,
- MT9M111_RMB_MIRROR_COLS);
- case V4L2_CID_GAIN:
- return mt9m111_set_global_gain(mt9m111, ctrl->val);
- case V4L2_CID_EXPOSURE_AUTO:
- return mt9m111_set_autoexposure(mt9m111, ctrl->val);
- case V4L2_CID_AUTO_WHITE_BALANCE:
- return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
- }
-
- return -EINVAL;
-}
-
-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));
-
- 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->ctx);
- mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
- 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 = mt9m111_enable(mt9m111);
- if (!ret)
- ret = mt9m111_reset(mt9m111);
- if (!ret)
- mt9m111_restore_state(mt9m111);
-
- return ret;
-}
-
-static int mt9m111_init(struct mt9m111 *mt9m111)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int ret;
-
- /* 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->ctx);
- if (ret)
- dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
- return ret;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9m111_video_probe(struct i2c_client *client)
-{
- struct mt9m111 *mt9m111 = to_mt9m111(client);
- s32 data;
- int ret;
-
- data = reg_read(CHIP_VERSION);
-
- switch (data) {
- case 0x143a: /* MT9M111 or MT9M131 */
- mt9m111->model = V4L2_IDENT_MT9M111;
- dev_info(&client->dev,
- "Detected a MT9M111/MT9M131 chip ID %x\n", data);
- break;
- case 0x148c: /* MT9M112 */
- mt9m111->model = V4L2_IDENT_MT9M112;
- dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
- break;
- default:
- dev_err(&client->dev,
- "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
- data);
- return -ENODEV;
- }
-
- ret = mt9m111_init(mt9m111);
- if (ret)
- return ret;
- return v4l2_ctrl_handler_setup(&mt9m111->hdl);
-}
-
-static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
-{
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
-
- mutex_lock(&mt9m111->power_lock);
-
- /*
- * If the power count is modified from 0 to != 0 or from != 0 to 0,
- * update the power state.
- */
- if (mt9m111->power_count == !on) {
- if (on) {
- ret = mt9m111_resume(mt9m111);
- if (ret) {
- dev_err(&client->dev,
- "Failed to resume the sensor: %d\n", ret);
- goto out;
- }
- } else {
- mt9m111_suspend(mt9m111);
- }
- }
-
- /* Update the power count. */
- mt9m111->power_count += on ? 1 : -1;
- WARN_ON(mt9m111->power_count < 0);
-
-out:
- mutex_unlock(&mt9m111->power_lock);
- return ret;
-}
-
-static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
- .s_ctrl = mt9m111_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
- .g_chip_ident = mt9m111_g_chip_ident,
- .s_power = mt9m111_s_power,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9m111_g_register,
- .s_register = mt9m111_s_register,
-#endif
-};
-
-static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
- return -EINVAL;
-
- *code = mt9m111_colour_fmts[index].code;
- return 0;
-}
-
-static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
- .s_mbus_fmt = mt9m111_s_fmt,
- .g_mbus_fmt = mt9m111_g_fmt,
- .try_mbus_fmt = mt9m111_try_fmt,
- .s_crop = mt9m111_s_crop,
- .g_crop = mt9m111_g_crop,
- .cropcap = mt9m111_cropcap,
- .enum_mbus_fmt = mt9m111_enum_fmt,
- .g_mbus_config = mt9m111_g_mbus_config,
-};
-
-static struct v4l2_subdev_ops mt9m111_subdev_ops = {
- .core = &mt9m111_subdev_core_ops,
- .video = &mt9m111_subdev_video_ops,
-};
-
-static int mt9m111_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct mt9m111 *mt9m111;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "mt9m111: driver needs platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
- if (!mt9m111)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
- v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
- v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
- V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
- V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
- v4l2_ctrl_new_std_menu(&mt9m111->hdl,
- &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
- V4L2_EXPOSURE_AUTO);
- mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
- if (mt9m111->hdl.error) {
- int err = mt9m111->hdl.error;
-
- kfree(mt9m111);
- return err;
- }
-
- /* Second stage probe - when a capture adapter is there */
- mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
- mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
- mt9m111->rect.width = MT9M111_MAX_WIDTH;
- mt9m111->rect.height = MT9M111_MAX_HEIGHT;
- mt9m111->fmt = &mt9m111_colour_fmts[0];
- mt9m111->lastpage = -1;
- mutex_init(&mt9m111->power_lock);
-
- ret = mt9m111_video_probe(client);
- if (ret) {
- v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
- }
-
- return ret;
-}
-
-static int mt9m111_remove(struct i2c_client *client)
-{
- struct mt9m111 *mt9m111 = to_mt9m111(client);
-
- v4l2_device_unregister_subdev(&mt9m111->subdev);
- v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
-
- return 0;
-}
-
-static const struct i2c_device_id mt9m111_id[] = {
- { "mt9m111", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9m111_id);
-
-static struct i2c_driver mt9m111_i2c_driver = {
- .driver = {
- .name = "mt9m111",
- },
- .probe = mt9m111_probe,
- .remove = mt9m111_remove,
- .id_table = mt9m111_id,
-};
-
-module_i2c_driver(mt9m111_i2c_driver);
-
-MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
-MODULE_AUTHOR("Robert Jarzmik");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
deleted file mode 100644
index 1415074138a5..000000000000
--- a/drivers/media/video/mt9t031.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- * Driver for MT9T031 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
- *
- * 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/device.h>
-#include <linux/i2c.h>
-#include <linux/log2.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-ctrls.h>
-
-/*
- * ATTENTION: this driver still cannot be used outside of the soc-camera
- * framework because of its PM implementation, using the video_device node.
- * If hardware becomes available for testing, alternative PM approaches shall
- * be considered and tested.
- */
-
-/*
- * mt9t031 i2c address 0x5d
- * The platform has to define i2c_board_info and link to it from
- * struct soc_camera_link
- */
-
-/* mt9t031 selected register addresses */
-#define MT9T031_CHIP_VERSION 0x00
-#define MT9T031_ROW_START 0x01
-#define MT9T031_COLUMN_START 0x02
-#define MT9T031_WINDOW_HEIGHT 0x03
-#define MT9T031_WINDOW_WIDTH 0x04
-#define MT9T031_HORIZONTAL_BLANKING 0x05
-#define MT9T031_VERTICAL_BLANKING 0x06
-#define MT9T031_OUTPUT_CONTROL 0x07
-#define MT9T031_SHUTTER_WIDTH_UPPER 0x08
-#define MT9T031_SHUTTER_WIDTH 0x09
-#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a
-#define MT9T031_FRAME_RESTART 0x0b
-#define MT9T031_SHUTTER_DELAY 0x0c
-#define MT9T031_RESET 0x0d
-#define MT9T031_READ_MODE_1 0x1e
-#define MT9T031_READ_MODE_2 0x20
-#define MT9T031_READ_MODE_3 0x21
-#define MT9T031_ROW_ADDRESS_MODE 0x22
-#define MT9T031_COLUMN_ADDRESS_MODE 0x23
-#define MT9T031_GLOBAL_GAIN 0x35
-#define MT9T031_CHIP_ENABLE 0xF8
-
-#define MT9T031_MAX_HEIGHT 1536
-#define MT9T031_MAX_WIDTH 2048
-#define MT9T031_MIN_HEIGHT 2
-#define MT9T031_MIN_WIDTH 18
-#define MT9T031_HORIZONTAL_BLANK 142
-#define MT9T031_VERTICAL_BLANK 25
-#define MT9T031_COLUMN_SKIP 32
-#define MT9T031_ROW_SKIP 20
-
-struct mt9t031 {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct {
- /* exposure/auto-exposure cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
- };
- struct v4l2_rect rect; /* Sensor window */
- int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
- u16 xskip;
- u16 yskip;
- unsigned int total_h;
- unsigned short y_skip_top; /* Lines to skip at the top */
-};
-
-static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct mt9t031, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u8 reg)
-{
- 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_swapped(client, reg, data);
-}
-
-static int reg_set(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret | data);
-}
-
-static int reg_clear(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret & ~data);
-}
-
-static int set_shutter(struct i2c_client *client, const u32 data)
-{
- int ret;
-
- ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
-
- if (ret >= 0)
- ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff);
-
- return ret;
-}
-
-static int get_shutter(struct i2c_client *client, u32 *data)
-{
- int ret;
-
- ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
- *data = ret << 16;
-
- if (ret >= 0)
- ret = reg_read(client, MT9T031_SHUTTER_WIDTH);
- *data |= ret & 0xffff;
-
- return ret < 0 ? ret : 0;
-}
-
-static int mt9t031_idle(struct i2c_client *client)
-{
- int ret;
-
- /* Disable chip output, synchronous option update */
- ret = reg_write(client, MT9T031_RESET, 1);
- if (ret >= 0)
- ret = reg_write(client, MT9T031_RESET, 0);
- if (ret >= 0)
- ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
-
- return ret >= 0 ? 0 : -EIO;
-}
-
-static int mt9t031_disable(struct i2c_client *client)
-{
- /* Disable the chip */
- reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
-
- return 0;
-}
-
-static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- if (enable)
- /* Switch to master "normal" mode */
- ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2);
- else
- /* Stop sensor readout */
- ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
-
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-/* target must be _even_ */
-static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
-{
- unsigned int skip;
-
- if (*source < target + target / 2) {
- *source = target;
- return 1;
- }
-
- skip = min(max, *source + target / 2) / target;
- if (skip > 8)
- skip = 8;
- *source = target * skip;
-
- return skip;
-}
-
-/* rect is the sensor rectangle, the caller guarantees parameter validity */
-static int mt9t031_set_params(struct i2c_client *client,
- struct v4l2_rect *rect, u16 xskip, u16 yskip)
-{
- struct mt9t031 *mt9t031 = to_mt9t031(client);
- int ret;
- u16 xbin, ybin;
- const u16 hblank = MT9T031_HORIZONTAL_BLANK,
- vblank = MT9T031_VERTICAL_BLANK;
-
- xbin = min(xskip, (u16)3);
- ybin = min(yskip, (u16)3);
-
- /*
- * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper.
- * There is always a valid suitably aligned value. The worst case is
- * xbin = 3, width = 2048. Then we will start at 36, the last read out
- * pixel will be 2083, which is < 2085 - first black pixel.
- *
- * MT9T031 datasheet imposes window left border alignment, depending on
- * the selected xskip. Failing to conform to this requirement produces
- * dark horizontal stripes in the image. However, even obeying to this
- * requirement doesn't eliminate the stripes in all configurations. They
- * appear "locally reproducibly," but can differ between tests under
- * different lighting conditions.
- */
- switch (xbin) {
- case 1:
- rect->left &= ~1;
- break;
- case 2:
- rect->left &= ~3;
- break;
- case 3:
- rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ?
- (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6);
- }
-
- rect->top &= ~1;
-
- dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
- xskip, yskip, rect->width, rect->height, rect->left, rect->top);
-
- /* Disable register update, reconfigure atomically */
- ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
- if (ret < 0)
- return ret;
-
- /* Blanking and start values - default... */
- ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank);
- if (ret >= 0)
- ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank);
-
- if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
- /* Binning, skipping */
- if (ret >= 0)
- ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
- ((xbin - 1) << 4) | (xskip - 1));
- if (ret >= 0)
- ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
- ((ybin - 1) << 4) | (yskip - 1));
- }
- dev_dbg(&client->dev, "new physical left %u, top %u\n",
- rect->left, rect->top);
-
- /*
- * The caller provides a supported format, as guaranteed by
- * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap()
- */
- if (ret >= 0)
- ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
- if (ret >= 0)
- ret = reg_write(client, MT9T031_ROW_START, rect->top);
- if (ret >= 0)
- ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1);
- if (ret >= 0)
- ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
- rect->height + mt9t031->y_skip_top - 1);
- if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) {
- mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank;
-
- ret = set_shutter(client, mt9t031->total_h);
- }
-
- /* Re-enable register update, commit all changes */
- if (ret >= 0)
- ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
-
- if (ret >= 0) {
- mt9t031->rect = *rect;
- mt9t031->xskip = xskip;
- mt9t031->yskip = yskip;
- }
-
- return ret < 0 ? ret : 0;
-}
-
-static int mt9t031_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 mt9t031 *mt9t031 = to_mt9t031(client);
-
- rect.width = ALIGN(rect.width, 2);
- rect.height = ALIGN(rect.height, 2);
-
- soc_camera_limit_side(&rect.left, &rect.width,
- MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH);
-
- soc_camera_limit_side(&rect.top, &rect.height,
- MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT);
-
- return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip);
-}
-
-static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- a->c = mt9t031->rect;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = MT9T031_COLUMN_SKIP;
- a->bounds.top = MT9T031_ROW_SKIP;
- a->bounds.width = MT9T031_MAX_WIDTH;
- a->bounds.height = MT9T031_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int mt9t031_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- mf->width = mt9t031->rect.width / mt9t031->xskip;
- mf->height = mt9t031->rect.height / mt9t031->yskip;
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9t031_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
- u16 xskip, yskip;
- struct v4l2_rect rect = mt9t031->rect;
-
- /*
- * try_fmt has put width and height within limits.
- * S_FMT: use binning and skipping for scaling
- */
- xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
- yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
-
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
- mf->colorspace = V4L2_COLORSPACE_SRGB;
-
- /* mt9t031_set_params() doesn't change width and height */
- return mt9t031_set_params(client, &rect, xskip, yskip);
-}
-
-/*
- * If a user window larger than sensor window is requested, we'll increase the
- * sensor window.
- */
-static int mt9t031_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- v4l_bound_align_image(
- &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
- &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
-
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
- mf->colorspace = V4L2_COLORSPACE_SRGB;
-
- return 0;
-}
-
-static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9t031->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t031_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- reg->val = reg_read(client, reg->reg);
-
- if (reg->val > 0xffff)
- return -EIO;
-
- return 0;
-}
-
-static int mt9t031_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- if (reg_write(client, reg->reg, reg->val) < 0)
- return -EIO;
-
- return 0;
-}
-#endif
-
-static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9t031 *mt9t031 = container_of(ctrl->handler,
- struct mt9t031, hdl);
- const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK;
- s32 min, max;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE_AUTO:
- min = mt9t031->exposure->minimum;
- max = mt9t031->exposure->maximum;
- mt9t031->exposure->val =
- (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min))
- / shutter_max + min;
- break;
- }
- return 0;
-}
-
-static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9t031 *mt9t031 = container_of(ctrl->handler,
- struct mt9t031, hdl);
- struct v4l2_subdev *sd = &mt9t031->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct v4l2_ctrl *exp = mt9t031->exposure;
- int data;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
- else
- data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_HFLIP:
- if (ctrl->val)
- data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
- else
- data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_GAIN:
- /* See Datasheet Table 7, Gain settings. */
- if (ctrl->val <= ctrl->default_value) {
- /* Pack it into 0..1 step 0.125, register values 0..8 */
- unsigned long range = ctrl->default_value - ctrl->minimum;
- data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
-
- dev_dbg(&client->dev, "Setting gain %d\n", data);
- data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
- if (data < 0)
- return -EIO;
- } else {
- /* Pack it into 1.125..128 variable step, register values 9..0x7860 */
- /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
- unsigned long range = ctrl->maximum - ctrl->default_value - 1;
- /* calculated gain: map 65..127 to 9..1024 step 0.125 */
- unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
- 1015 + range / 2) / range + 9;
-
- if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
- data = gain;
- else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */
- data = ((gain - 32) * 16 + 16) / 32 + 80;
- else
- /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
- data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
-
- dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n",
- reg_read(client, MT9T031_GLOBAL_GAIN), data);
- data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
- if (data < 0)
- return -EIO;
- }
- return 0;
-
- case V4L2_CID_EXPOSURE_AUTO:
- if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
- unsigned int range = exp->maximum - exp->minimum;
- unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
- range / 2) / range + 1;
- u32 old;
-
- get_shutter(client, &old);
- dev_dbg(&client->dev, "Set shutter from %u to %u\n",
- old, shutter);
- if (set_shutter(client, shutter) < 0)
- return -EIO;
- } else {
- const u16 vblank = MT9T031_VERTICAL_BLANK;
- mt9t031->total_h = mt9t031->rect.height +
- mt9t031->y_skip_top + vblank;
-
- if (set_shutter(client, mt9t031->total_h) < 0)
- return -EIO;
- }
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- * Power Management:
- * This function does nothing for now but must be present for pm to work
- */
-static int mt9t031_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-/*
- * Power Management:
- * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
- * they are however changed at reset if the platform hook is present
- * thus we rewrite them with the values stored by the driver
- */
-static int mt9t031_runtime_resume(struct device *dev)
-{
- struct video_device *vdev = to_video_device(dev);
- struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- int ret;
- u16 xbin, ybin;
-
- xbin = min(mt9t031->xskip, (u16)3);
- ybin = min(mt9t031->yskip, (u16)3);
-
- ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
- ((xbin - 1) << 4) | (mt9t031->xskip - 1));
- if (ret < 0)
- return ret;
-
- ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
- ((ybin - 1) << 4) | (mt9t031->yskip - 1));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct dev_pm_ops mt9t031_dev_pm_ops = {
- .runtime_suspend = mt9t031_runtime_suspend,
- .runtime_resume = mt9t031_runtime_resume,
-};
-
-static struct device_type mt9t031_dev_type = {
- .name = "MT9T031",
- .pm = &mt9t031_dev_pm_ops,
-};
-
-static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct video_device *vdev = soc_camera_i2c_to_vdev(client);
-
- if (on)
- vdev->dev.type = &mt9t031_dev_type;
- else
- vdev->dev.type = NULL;
-
- return 0;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9t031_video_probe(struct i2c_client *client)
-{
- struct mt9t031 *mt9t031 = to_mt9t031(client);
- s32 data;
- int ret;
-
- /* Enable the chip */
- data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
- dev_dbg(&client->dev, "write: %d\n", data);
-
- /* Read out the chip version register */
- data = reg_read(client, MT9T031_CHIP_VERSION);
-
- switch (data) {
- case 0x1621:
- mt9t031->model = V4L2_IDENT_MT9T031;
- break;
- default:
- dev_err(&client->dev,
- "No MT9T031 chip detected, register read %x\n", data);
- return -ENODEV;
- }
-
- dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
-
- ret = mt9t031_idle(client);
- if (ret < 0)
- dev_err(&client->dev, "Failed to initialise the camera\n");
- else
- v4l2_ctrl_handler_setup(&mt9t031->hdl);
-
- return ret;
-}
-
-static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- *lines = mt9t031->y_skip_top;
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
- .g_volatile_ctrl = mt9t031_g_volatile_ctrl,
- .s_ctrl = mt9t031_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
- .g_chip_ident = mt9t031_g_chip_ident,
- .s_power = mt9t031_s_power,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9t031_g_register,
- .s_register = mt9t031_s_register,
-#endif
-};
-
-static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index)
- return -EINVAL;
-
- *code = V4L2_MBUS_FMT_SBGGR10_1X10;
- return 0;
-}
-
-static int mt9t031_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int mt9t031_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- if (soc_camera_apply_board_flags(icl, cfg) &
- V4L2_MBUS_PCLK_SAMPLE_FALLING)
- return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
- else
- return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
-}
-
-static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
- .s_stream = mt9t031_s_stream,
- .s_mbus_fmt = mt9t031_s_fmt,
- .g_mbus_fmt = mt9t031_g_fmt,
- .try_mbus_fmt = mt9t031_try_fmt,
- .s_crop = mt9t031_s_crop,
- .g_crop = mt9t031_g_crop,
- .cropcap = mt9t031_cropcap,
- .enum_mbus_fmt = mt9t031_enum_fmt,
- .g_mbus_config = mt9t031_g_mbus_config,
- .s_mbus_config = mt9t031_s_mbus_config,
-};
-
-static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
- .g_skip_top_lines = mt9t031_g_skip_top_lines,
-};
-
-static struct v4l2_subdev_ops mt9t031_subdev_ops = {
- .core = &mt9t031_subdev_core_ops,
- .video = &mt9t031_subdev_video_ops,
- .sensor = &mt9t031_subdev_sensor_ops,
-};
-
-static int mt9t031_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct mt9t031 *mt9t031;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "MT9T031 driver needs platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
- if (!mt9t031)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
- v4l2_ctrl_handler_init(&mt9t031->hdl, 5);
- v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
- V4L2_CID_GAIN, 0, 127, 1, 64);
-
- /*
- * Simulated autoexposure. If enabled, we calculate shutter width
- * ourselves in the driver based on vertical blanking and frame width
- */
- mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl,
- &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
- V4L2_EXPOSURE_AUTO);
- mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, 255, 1, 255);
-
- mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
- if (mt9t031->hdl.error) {
- int err = mt9t031->hdl.error;
-
- kfree(mt9t031);
- return err;
- }
- v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure,
- V4L2_EXPOSURE_MANUAL, true);
-
- mt9t031->y_skip_top = 0;
- mt9t031->rect.left = MT9T031_COLUMN_SKIP;
- mt9t031->rect.top = MT9T031_ROW_SKIP;
- mt9t031->rect.width = MT9T031_MAX_WIDTH;
- mt9t031->rect.height = MT9T031_MAX_HEIGHT;
-
- mt9t031->xskip = 1;
- mt9t031->yskip = 1;
-
- mt9t031_idle(client);
-
- ret = mt9t031_video_probe(client);
-
- mt9t031_disable(client);
-
- if (ret) {
- v4l2_ctrl_handler_free(&mt9t031->hdl);
- kfree(mt9t031);
- }
-
- return ret;
-}
-
-static int mt9t031_remove(struct i2c_client *client)
-{
- struct mt9t031 *mt9t031 = to_mt9t031(client);
-
- v4l2_device_unregister_subdev(&mt9t031->subdev);
- v4l2_ctrl_handler_free(&mt9t031->hdl);
- kfree(mt9t031);
-
- return 0;
-}
-
-static const struct i2c_device_id mt9t031_id[] = {
- { "mt9t031", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9t031_id);
-
-static struct i2c_driver mt9t031_i2c_driver = {
- .driver = {
- .name = "mt9t031",
- },
- .probe = mt9t031_probe,
- .remove = mt9t031_remove,
- .id_table = mt9t031_id,
-};
-
-module_i2c_driver(mt9t031_i2c_driver);
-
-MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
deleted file mode 100644
index e1ae46a7ee96..000000000000
--- a/drivers/media/video/mt9t112.c
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- * mt9t112 Camera Driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov772x driver, mt9m111 driver,
- *
- * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
- * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/mt9t112.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
-
-/* you can check PLL/clock info */
-/* #define EXT_CLOCK 24000000 */
-
-/************************************************************************
- macro
-************************************************************************/
-/*
- * frame size
- */
-#define MAX_WIDTH 2048
-#define MAX_HEIGHT 1536
-
-#define VGA_WIDTH 640
-#define VGA_HEIGHT 480
-
-/*
- * macro of read/write
- */
-#define ECHECKER(ret, x) \
- do { \
- (ret) = (x); \
- if ((ret) < 0) \
- return (ret); \
- } while (0)
-
-#define mt9t112_reg_write(ret, client, a, b) \
- ECHECKER(ret, __mt9t112_reg_write(client, a, b))
-#define mt9t112_mcu_write(ret, client, a, b) \
- ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
-
-#define mt9t112_reg_mask_set(ret, client, a, b, c) \
- ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
-#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
- ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
-
-#define mt9t112_reg_read(ret, client, a) \
- ECHECKER(ret, __mt9t112_reg_read(client, a))
-
-/*
- * Logical address
- */
-#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff))
-#define VAR(id, offset) _VAR(id, offset, 0x0000)
-#define VAR8(id, offset) _VAR(id, offset, 0x8000)
-
-/************************************************************************
- struct
-************************************************************************/
-struct mt9t112_format {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
- u16 fmt;
- u16 order;
-};
-
-struct mt9t112_priv {
- struct v4l2_subdev subdev;
- struct mt9t112_camera_info *info;
- struct i2c_client *client;
- struct v4l2_rect frame;
- const struct mt9t112_format *format;
- int model;
- u32 flags;
-/* for flags */
-#define INIT_DONE (1 << 0)
-#define PCLK_RISING (1 << 1)
-};
-
-/************************************************************************
- supported format
-************************************************************************/
-
-static const struct mt9t112_format mt9t112_cfmts[] = {
- {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 0,
- }, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 1,
- }, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 2,
- }, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 3,
- }, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .fmt = 8,
- .order = 2,
- }, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .fmt = 4,
- .order = 2,
- },
-};
-
-/************************************************************************
- general function
-************************************************************************/
-static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client),
- struct mt9t112_priv,
- subdev);
-}
-
-static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
-{
- struct i2c_msg msg[2];
- u8 buf[2];
- int ret;
-
- command = swab16(command);
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 2;
- msg[0].buf = (u8 *)&command;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 2;
- msg[1].buf = buf;
-
- /*
- * if return value of this function is < 0,
- * it mean error.
- * else, under 16bit is valid data.
- */
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0)
- return ret;
-
- memcpy(&ret, buf, 2);
- return swab16(ret);
-}
-
-static int __mt9t112_reg_write(const struct i2c_client *client,
- u16 command, u16 data)
-{
- struct i2c_msg msg;
- u8 buf[4];
- int ret;
-
- command = swab16(command);
- data = swab16(data);
-
- memcpy(buf + 0, &command, 2);
- memcpy(buf + 2, &data, 2);
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = 4;
- msg.buf = buf;
-
- /*
- * i2c_transfer return message length,
- * but this function should return 0 if correct case
- */
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret >= 0)
- ret = 0;
-
- return ret;
-}
-
-static int __mt9t112_reg_mask_set(const struct i2c_client *client,
- u16 command,
- u16 mask,
- u16 set)
-{
- int val = __mt9t112_reg_read(client, command);
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- return __mt9t112_reg_write(client, command, val);
-}
-
-/* mcu access */
-static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
-{
- int ret;
-
- ret = __mt9t112_reg_write(client, 0x098E, command);
- if (ret < 0)
- return ret;
-
- return __mt9t112_reg_read(client, 0x0990);
-}
-
-static int __mt9t112_mcu_write(const struct i2c_client *client,
- u16 command, u16 data)
-{
- int ret;
-
- ret = __mt9t112_reg_write(client, 0x098E, command);
- if (ret < 0)
- return ret;
-
- return __mt9t112_reg_write(client, 0x0990, data);
-}
-
-static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
- u16 command,
- u16 mask,
- u16 set)
-{
- int val = __mt9t112_mcu_read(client, command);
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- return __mt9t112_mcu_write(client, command, val);
-}
-
-static int mt9t112_reset(const struct i2c_client *client)
-{
- int ret;
-
- mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
- msleep(1);
- mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
-
- return ret;
-}
-
-#ifndef EXT_CLOCK
-#define CLOCK_INFO(a, b)
-#else
-#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
-static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
-{
- int m, n, p1, p2, p3, p4, p5, p6, p7;
- u32 vco, clk;
- char *enable;
-
- ext /= 1000; /* kbyte order */
-
- mt9t112_reg_read(n, client, 0x0012);
- p1 = n & 0x000f;
- n = n >> 4;
- p2 = n & 0x000f;
- n = n >> 4;
- p3 = n & 0x000f;
-
- mt9t112_reg_read(n, client, 0x002a);
- p4 = n & 0x000f;
- n = n >> 4;
- p5 = n & 0x000f;
- n = n >> 4;
- p6 = n & 0x000f;
-
- mt9t112_reg_read(n, client, 0x002c);
- p7 = n & 0x000f;
-
- mt9t112_reg_read(n, client, 0x0010);
- m = n & 0x00ff;
- n = (n >> 8) & 0x003f;
-
- enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
- dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable);
-
- vco = 2 * m * ext / (n+1);
- enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
- dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable);
-
- clk = vco / (p1+1) / (p2+1);
- enable = (96000 < clk) ? "X" : "";
- dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable);
-
- clk = vco / (p3+1);
- enable = (768000 < clk) ? "X" : "";
- dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable);
-
- clk = vco / (p6+1);
- enable = (96000 < clk) ? "X" : "";
- dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable);
-
- clk = vco / (p5+1);
- enable = (54000 < clk) ? "X" : "";
- dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable);
-
- clk = vco / (p4+1);
- enable = (70000 < clk) ? "X" : "";
- dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable);
-
- clk = vco / (p7+1);
- dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
-
- clk = ext / (n+1);
- enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
- dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable);
-
- return 0;
-}
-#endif
-
-static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
-{
- soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
- soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
-}
-
-static int mt9t112_set_a_frame_size(const struct i2c_client *client,
- u16 width,
- u16 height)
-{
- int ret;
- u16 wstart = (MAX_WIDTH - width) / 2;
- u16 hstart = (MAX_HEIGHT - height) / 2;
-
- /* (Context A) Image Width/Height */
- mt9t112_mcu_write(ret, client, VAR(26, 0), width);
- mt9t112_mcu_write(ret, client, VAR(26, 2), height);
-
- /* (Context A) Output Width/Height */
- mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
- mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
-
- /* (Context A) Start Row/Column */
- mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
- mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
-
- /* (Context A) End Row/Column */
- mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
- mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart);
-
- mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
-
- return ret;
-}
-
-static int mt9t112_set_pll_dividers(const struct i2c_client *client,
- u8 m, u8 n,
- u8 p1, u8 p2, u8 p3,
- u8 p4, u8 p5, u8 p6,
- u8 p7)
-{
- int ret;
- u16 val;
-
- /* N/M */
- val = (n << 8) |
- (m << 0);
- mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
-
- /* P1/P2/P3 */
- val = ((p3 & 0x0F) << 8) |
- ((p2 & 0x0F) << 4) |
- ((p1 & 0x0F) << 0);
- mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
-
- /* P4/P5/P6 */
- val = (0x7 << 12) |
- ((p6 & 0x0F) << 8) |
- ((p5 & 0x0F) << 4) |
- ((p4 & 0x0F) << 0);
- mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
-
- /* P7 */
- val = (0x1 << 12) |
- ((p7 & 0x0F) << 0);
- mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
-
- return ret;
-}
-
-static int mt9t112_init_pll(const struct i2c_client *client)
-{
- struct mt9t112_priv *priv = to_mt9t112(client);
- int data, i, ret;
-
- mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
-
- /* PLL control: BYPASS PLL = 8517 */
- mt9t112_reg_write(ret, client, 0x0014, 0x2145);
-
- /* Replace these registers when new timing parameters are generated */
- mt9t112_set_pll_dividers(client,
- priv->info->divider.m,
- priv->info->divider.n,
- priv->info->divider.p1,
- priv->info->divider.p2,
- priv->info->divider.p3,
- priv->info->divider.p4,
- priv->info->divider.p5,
- priv->info->divider.p6,
- priv->info->divider.p7);
-
- /*
- * TEST_BYPASS on
- * PLL_ENABLE on
- * SEL_LOCK_DET on
- * TEST_BYPASS off
- */
- mt9t112_reg_write(ret, client, 0x0014, 0x2525);
- mt9t112_reg_write(ret, client, 0x0014, 0x2527);
- mt9t112_reg_write(ret, client, 0x0014, 0x3427);
- mt9t112_reg_write(ret, client, 0x0014, 0x3027);
-
- mdelay(10);
-
- /*
- * PLL_BYPASS off
- * Reference clock count
- * I2C Master Clock Divider
- */
- mt9t112_reg_write(ret, client, 0x0014, 0x3046);
- mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
- mt9t112_reg_write(ret, client, 0x0022, 0x0190);
- mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
-
- /* External sensor clock is PLL bypass */
- mt9t112_reg_write(ret, client, 0x002E, 0x0500);
-
- mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
- mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
-
- /* MCU disabled */
- mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
-
- /* out of standby */
- mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
-
- mdelay(50);
-
- /*
- * Standby Workaround
- * Disable Secondary I2C Pads
- */
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
- mt9t112_reg_write(ret, client, 0x0614, 0x0001);
- mdelay(1);
-
- /* poll to verify out of standby. Must Poll this bit */
- for (i = 0; i < 100; i++) {
- mt9t112_reg_read(data, client, 0x0018);
- if (!(0x4000 & data))
- break;
-
- mdelay(10);
- }
-
- return ret;
-}
-
-static int mt9t112_init_setting(const struct i2c_client *client)
-{
-
- int ret;
-
- /* Adaptive Output Clock (A) */
- mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
-
- /* Read Mode (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
-
- /* Fine Correction (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
-
- /* Fine IT Min (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
-
- /* Fine IT Max Margin (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
-
- /* Base Frame Lines (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
-
- /* Min Line Length (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
-
- /* Line Length (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
-
- /* Adaptive Output Clock (B) */
- mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
-
- /* Row Start (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
-
- /* Column Start (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
-
- /* Row End (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
-
- /* Column End (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
-
- /* Fine Correction (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
-
- /* Fine IT Min (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
-
- /* Fine IT Max Margin (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
-
- /* Base Frame Lines (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
-
- /* Min Line Length (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
-
- /* Line Length (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
-
- /*
- * Flicker Dectection registers
- * This section should be replaced whenever new Timing file is generated
- * All the following registers need to be replaced
- * Following registers are generated from Register Wizard but user can
- * modify them. For detail see auto flicker detection tuning
- */
-
- /* FD_FDPERIOD_SELECT */
- mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
-
- /* PRI_B_CONFIG_FD_ALGO_RUN */
- mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
-
- /* PRI_A_CONFIG_FD_ALGO_RUN */
- mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
-
- /*
- * AFD range detection tuning registers
- */
-
- /* search_f1_50 */
- mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
-
- /* search_f2_50 */
- mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
-
- /* search_f1_60 */
- mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
-
- /* search_f2_60 */
- mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
-
- /* period_50Hz (A) */
- mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
-
- /* secret register by aptina */
- /* period_50Hz (A MSB) */
- mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
-
- /* period_60Hz (A) */
- mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
-
- /* secret register by aptina */
- /* period_60Hz (A MSB) */
- mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
-
- /* period_50Hz (B) */
- mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
-
- /* secret register by aptina */
- /* period_50Hz (B) MSB */
- mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
-
- /* period_60Hz (B) */
- mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
-
- /* secret register by aptina */
- /* period_60Hz (B) MSB */
- mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
-
- /* FD Mode */
- mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
-
- /* Stat_min */
- mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
-
- /* Stat_max */
- mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
-
- /* Min_amplitude */
- mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
-
- /* RX FIFO Watermark (A) */
- mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
-
- /* RX FIFO Watermark (B) */
- mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
-
- /* MCLK: 16MHz
- * PCLK: 73MHz
- * CorePixCLK: 36.5 MHz
- */
- mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
-
- mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
- mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
-
- return ret;
-}
-
-static int mt9t112_auto_focus_setting(const struct i2c_client *client)
-{
- int ret;
-
- mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F);
- mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F);
- mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
-
- mt9t112_reg_write(ret, client, 0x0614, 0x0000);
-
- mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
- mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02);
- mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002);
- mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001);
- mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025);
- mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193);
- mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18);
- mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
-
- return ret;
-}
-
-static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
-{
- int ret;
-
- mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
-
- return ret;
-}
-
-static int mt9t112_init_camera(const struct i2c_client *client)
-{
- int ret;
-
- ECHECKER(ret, mt9t112_reset(client));
-
- ECHECKER(ret, mt9t112_init_pll(client));
-
- ECHECKER(ret, mt9t112_init_setting(client));
-
- ECHECKER(ret, mt9t112_auto_focus_setting(client));
-
- mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
-
- /* Analog setting B */
- mt9t112_reg_write(ret, client, 0x3084, 0x2409);
- mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
- mt9t112_reg_write(ret, client, 0x3094, 0x4949);
- mt9t112_reg_write(ret, client, 0x3096, 0x4950);
-
- /*
- * Disable adaptive clock
- * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
- * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
- */
- mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
- mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
-
- /* Configure STatus in Status_before_length Format and enable header */
- /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
- mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
-
- /* Enable JPEG in context B */
- /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
- mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
-
- /* Disable Dac_TXLO */
- mt9t112_reg_write(ret, client, 0x316C, 0x350F);
-
- /* Set max slew rates */
- mt9t112_reg_write(ret, client, 0x1E, 0x777);
-
- return ret;
-}
-
-/************************************************************************
- v4l2_subdev_core_ops
-************************************************************************/
-static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t112_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- reg->size = 2;
- mt9t112_reg_read(ret, client, reg->reg);
-
- reg->val = (__u64)ret;
-
- return 0;
-}
-
-static int mt9t112_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- mt9t112_reg_write(ret, client, reg->reg, reg->val);
-
- return ret;
-}
-#endif
-
-static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
- .g_chip_ident = mt9t112_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9t112_g_register,
- .s_register = mt9t112_s_register,
-#endif
-};
-
-
-/************************************************************************
- v4l2_subdev_video_ops
-************************************************************************/
-static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
- int ret = 0;
-
- if (!enable) {
- /* FIXME
- *
- * If user selected large output size,
- * and used it long time,
- * mt9t112 camera will be very warm.
- *
- * But current driver can not stop mt9t112 camera.
- * So, set small size here to solve this problem.
- */
- mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
- return ret;
- }
-
- if (!(priv->flags & INIT_DONE)) {
- u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000;
-
- ECHECKER(ret, mt9t112_init_camera(client));
-
- /* Invert PCLK (Data sampled on falling edge of pixclk) */
- mt9t112_reg_write(ret, client, 0x3C20, param);
-
- mdelay(5);
-
- priv->flags |= INIT_DONE;
- }
-
- mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt);
- mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order);
- mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
-
- mt9t112_set_a_frame_size(client,
- priv->frame.width,
- priv->frame.height);
-
- ECHECKER(ret, mt9t112_auto_focus_trigger(client));
-
- dev_dbg(&client->dev, "format : %d\n", priv->format->code);
- dev_dbg(&client->dev, "size : %d x %d\n",
- priv->frame.width,
- priv->frame.height);
-
- CLOCK_INFO(client, EXT_CLOCK);
-
- return ret;
-}
-
-static int mt9t112_set_params(struct mt9t112_priv *priv,
- const struct v4l2_rect *rect,
- enum v4l2_mbus_pixelcode code)
-{
- int i;
-
- /*
- * get color format
- */
- for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
- if (mt9t112_cfmts[i].code == code)
- break;
-
- if (i == ARRAY_SIZE(mt9t112_cfmts))
- return -EINVAL;
-
- priv->frame = *rect;
-
- /*
- * frame size check
- */
- mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
- &priv->frame.left, &priv->frame.top);
-
- priv->format = mt9t112_cfmts + i;
-
- return 0;
-}
-
-static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = MAX_WIDTH;
- a->bounds.height = MAX_HEIGHT;
- a->defrect.left = 0;
- a->defrect.top = 0;
- a->defrect.width = VGA_WIDTH;
- a->defrect.height = VGA_HEIGHT;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- a->c = priv->frame;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
- struct v4l2_rect *rect = &a->c;
-
- return mt9t112_set_params(priv, rect, priv->format->code);
-}
-
-static int mt9t112_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- mf->width = priv->frame.width;
- mf->height = priv->frame.height;
- mf->colorspace = priv->format->colorspace;
- mf->code = priv->format->code;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9t112_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9t112_priv *priv = to_mt9t112(client);
- struct v4l2_rect rect = {
- .width = mf->width,
- .height = mf->height,
- .left = priv->frame.left,
- .top = priv->frame.top,
- };
- int ret;
-
- ret = mt9t112_set_params(priv, &rect, mf->code);
-
- if (!ret)
- mf->colorspace = priv->format->colorspace;
-
- return ret;
-}
-
-static int mt9t112_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- unsigned int top, left;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
- if (mt9t112_cfmts[i].code == mf->code)
- break;
-
- if (i == ARRAY_SIZE(mt9t112_cfmts)) {
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- } else {
- mf->colorspace = mt9t112_cfmts[i].colorspace;
- }
-
- mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
-
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(mt9t112_cfmts))
- return -EINVAL;
-
- *code = mt9t112_cfmts[index].code;
-
- return 0;
-}
-
-static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
- priv->flags |= PCLK_RISING;
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
- .s_stream = mt9t112_s_stream,
- .g_mbus_fmt = mt9t112_g_fmt,
- .s_mbus_fmt = mt9t112_s_fmt,
- .try_mbus_fmt = mt9t112_try_fmt,
- .cropcap = mt9t112_cropcap,
- .g_crop = mt9t112_g_crop,
- .s_crop = mt9t112_s_crop,
- .enum_mbus_fmt = mt9t112_enum_fmt,
- .g_mbus_config = mt9t112_g_mbus_config,
- .s_mbus_config = mt9t112_s_mbus_config,
-};
-
-/************************************************************************
- i2c driver
-************************************************************************/
-static struct v4l2_subdev_ops mt9t112_subdev_ops = {
- .core = &mt9t112_subdev_core_ops,
- .video = &mt9t112_subdev_video_ops,
-};
-
-static int mt9t112_camera_probe(struct i2c_client *client)
-{
- struct mt9t112_priv *priv = to_mt9t112(client);
- const char *devname;
- int chipid;
-
- /*
- * check and show chip ID
- */
- mt9t112_reg_read(chipid, client, 0x0000);
-
- switch (chipid) {
- case 0x2680:
- devname = "mt9t111";
- priv->model = V4L2_IDENT_MT9T111;
- break;
- case 0x2682:
- devname = "mt9t112";
- priv->model = V4L2_IDENT_MT9T112;
- break;
- default:
- dev_err(&client->dev, "Product ID error %04x\n", chipid);
- return -ENODEV;
- }
-
- dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
-
- return 0;
-}
-
-static int mt9t112_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct mt9t112_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct v4l2_rect rect = {
- .width = VGA_WIDTH,
- .height = VGA_HEIGHT,
- .left = (MAX_WIDTH - VGA_WIDTH) / 2,
- .top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
- };
- int ret;
-
- if (!icl || !icl->priv) {
- dev_err(&client->dev, "mt9t112: missing platform data!\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->info = icl->priv;
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
-
- ret = mt9t112_camera_probe(client);
- if (ret) {
- kfree(priv);
- return ret;
- }
-
- /* Cannot fail: using the default supported pixel code */
- mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
-
- return ret;
-}
-
-static int mt9t112_remove(struct i2c_client *client)
-{
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id mt9t112_id[] = {
- { "mt9t112", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9t112_id);
-
-static struct i2c_driver mt9t112_i2c_driver = {
- .driver = {
- .name = "mt9t112",
- },
- .probe = mt9t112_probe,
- .remove = mt9t112_remove,
- .id_table = mt9t112_id,
-};
-
-module_i2c_driver(mt9t112_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
deleted file mode 100644
index 72479247522a..000000000000
--- a/drivers/media/video/mt9v022.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * Driver for MT9V022 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/videodev2.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-
-/*
- * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_link
- */
-
-static char *sensor_type;
-module_param(sensor_type, charp, S_IRUGO);
-MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
-
-/* mt9v022 selected register addresses */
-#define MT9V022_CHIP_VERSION 0x00
-#define MT9V022_COLUMN_START 0x01
-#define MT9V022_ROW_START 0x02
-#define MT9V022_WINDOW_HEIGHT 0x03
-#define MT9V022_WINDOW_WIDTH 0x04
-#define MT9V022_HORIZONTAL_BLANKING 0x05
-#define MT9V022_VERTICAL_BLANKING 0x06
-#define MT9V022_CHIP_CONTROL 0x07
-#define MT9V022_SHUTTER_WIDTH1 0x08
-#define MT9V022_SHUTTER_WIDTH2 0x09
-#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a
-#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b
-#define MT9V022_RESET 0x0c
-#define MT9V022_READ_MODE 0x0d
-#define MT9V022_MONITOR_MODE 0x0e
-#define MT9V022_PIXEL_OPERATION_MODE 0x0f
-#define MT9V022_LED_OUT_CONTROL 0x1b
-#define MT9V022_ADC_MODE_CONTROL 0x1c
-#define MT9V022_ANALOG_GAIN 0x35
-#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
-#define MT9V022_PIXCLK_FV_LV 0x74
-#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
-#define MT9V022_AEC_AGC_ENABLE 0xAF
-#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
-
-/* Progressive scan, master, defaults */
-#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
-
-#define MT9V022_MAX_WIDTH 752
-#define MT9V022_MAX_HEIGHT 480
-#define MT9V022_MIN_WIDTH 48
-#define MT9V022_MIN_HEIGHT 32
-#define MT9V022_COLUMN_SKIP 1
-#define MT9V022_ROW_SKIP 4
-
-/* MT9V022 has only one fixed colorspace per pixelcode */
-struct mt9v022_datafmt {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct mt9v022_datafmt *mt9v022_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct mt9v022_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 mt9v022_datafmt mt9v022_colour_fmts[] = {
- /*
- * Order important: first natively supported,
- * second supported with a GPIO extender
- */
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
-};
-
-static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
- /* Order important - see above */
- {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
-};
-
-struct mt9v022 {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct {
- /* exposure/auto-exposure cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
- };
- struct {
- /* gain/auto-gain cluster */
- struct v4l2_ctrl *autogain;
- struct v4l2_ctrl *gain;
- };
- struct v4l2_rect rect; /* Sensor window */
- const struct mt9v022_datafmt *fmt;
- const struct mt9v022_datafmt *fmts;
- int num_fmts;
- int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
- u16 chip_control;
- unsigned short y_skip_top; /* Lines to skip at the top */
-};
-
-static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u8 reg)
-{
- 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_swapped(client, reg, data);
-}
-
-static int reg_set(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret | data);
-}
-
-static int reg_clear(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, ret & ~data);
-}
-
-static int mt9v022_init(struct i2c_client *client)
-{
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- int ret;
-
- /*
- * Almost the default mode: master, parallel, simultaneous, and an
- * undocumented bit 0x200, which is present in table 7, but not in 8,
- * plus snapshot mode to disable scan for now
- */
- mt9v022->chip_control |= 0x10;
- ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
- if (!ret)
- ret = reg_write(client, MT9V022_READ_MODE, 0x300);
-
- /* All defaults */
- if (!ret)
- /* AEC, AGC on */
- ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
- if (!ret)
- ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
- if (!ret)
- ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
- if (!ret)
- ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
- if (!ret)
- /* default - auto */
- ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
- if (!ret)
- ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
- if (!ret)
- return v4l2_ctrl_handler_setup(&mt9v022->hdl);
-
- return ret;
-}
-
-static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- if (enable)
- /* Switch to master "normal" mode */
- mt9v022->chip_control &= ~0x10;
- else
- /* Switch to snapshot mode */
- mt9v022->chip_control |= 0x10;
-
- if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
- return -EIO;
- return 0;
-}
-
-static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct v4l2_rect rect = a->c;
- int ret;
-
- /* Bayer format - even size lengths */
- if (mt9v022->fmts == mt9v022_colour_fmts) {
- rect.width = ALIGN(rect.width, 2);
- rect.height = ALIGN(rect.height, 2);
- /* Let the user play with the starting pixel */
- }
-
- soc_camera_limit_side(&rect.left, &rect.width,
- MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
-
- soc_camera_limit_side(&rect.top, &rect.height,
- MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
-
- /* Like in example app. Contradicts the datasheet though */
- ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
- if (ret >= 0) {
- if (ret & 1) /* Autoexposure */
- ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
- rect.height + mt9v022->y_skip_top + 43);
- else
- ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- rect.height + mt9v022->y_skip_top + 43);
- }
- /* Setup frame format: defaults apart from width and height */
- if (!ret)
- ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
- if (!ret)
- ret = reg_write(client, MT9V022_ROW_START, rect.top);
- if (!ret)
- /*
- * Default 94, Phytec driver says:
- * "width + horizontal blank >= 660"
- */
- ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
- rect.width > 660 - 43 ? 43 :
- 660 - rect.width);
- if (!ret)
- ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
- if (!ret)
- ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
- if (!ret)
- ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
- rect.height + mt9v022->y_skip_top);
-
- if (ret < 0)
- return ret;
-
- dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
-
- mt9v022->rect = rect;
-
- return 0;
-}
-
-static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- a->c = mt9v022->rect;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = MT9V022_COLUMN_SKIP;
- a->bounds.top = MT9V022_ROW_SKIP;
- a->bounds.width = MT9V022_MAX_WIDTH;
- a->bounds.height = MT9V022_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int mt9v022_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- mf->width = mt9v022->rect.width;
- mf->height = mt9v022->rect.height;
- mf->code = mt9v022->fmt->code;
- mf->colorspace = mt9v022->fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int mt9v022_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct v4l2_crop a = {
- .c = {
- .left = mt9v022->rect.left,
- .top = mt9v022->rect.top,
- .width = mf->width,
- .height = mf->height,
- },
- };
- int ret;
-
- /*
- * The caller provides a supported format, as verified per call to
- * .try_mbus_fmt(), datawidth is from our supported format list
- */
- switch (mf->code) {
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_Y10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
- return -EINVAL;
- break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- /* No support for scaling on this camera, just crop. */
- ret = mt9v022_s_crop(sd, &a);
- if (!ret) {
- mf->width = mt9v022->rect.width;
- mf->height = mt9v022->rect.height;
- mt9v022->fmt = mt9v022_find_datafmt(mf->code,
- mt9v022->fmts, mt9v022->num_fmts);
- mf->colorspace = mt9v022->fmt->colorspace;
- }
-
- return ret;
-}
-
-static int mt9v022_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- const struct mt9v022_datafmt *fmt;
- int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
-
- v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
- MT9V022_MAX_WIDTH, align,
- &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
- MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
-
- fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
- mt9v022->num_fmts);
- if (!fmt) {
- fmt = mt9v022->fmt;
- mf->code = fmt->code;
- }
-
- mf->colorspace = fmt->colorspace;
-
- return 0;
-}
-
-static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = mt9v022->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9v022_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- reg->size = 2;
- reg->val = reg_read(client, reg->reg);
-
- if (reg->val > 0xffff)
- return -EIO;
-
- return 0;
-}
-
-static int mt9v022_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- if (reg_write(client, reg->reg, reg->val) < 0)
- return -EIO;
-
- return 0;
-}
-#endif
-
-static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9v022 *mt9v022 = container_of(ctrl->handler,
- struct mt9v022, hdl);
- struct v4l2_subdev *sd = &mt9v022->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct v4l2_ctrl *gain = mt9v022->gain;
- struct v4l2_ctrl *exp = mt9v022->exposure;
- unsigned long range;
- int data;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTOGAIN:
- data = reg_read(client, MT9V022_ANALOG_GAIN);
- if (data < 0)
- return -EIO;
-
- range = gain->maximum - gain->minimum;
- gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
- return 0;
- case V4L2_CID_EXPOSURE_AUTO:
- data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
- if (data < 0)
- return -EIO;
-
- range = exp->maximum - exp->minimum;
- exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
- return 0;
- }
- return -EINVAL;
-}
-
-static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct mt9v022 *mt9v022 = container_of(ctrl->handler,
- struct mt9v022, hdl);
- struct v4l2_subdev *sd = &mt9v022->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int data;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- data = reg_set(client, MT9V022_READ_MODE, 0x10);
- else
- data = reg_clear(client, MT9V022_READ_MODE, 0x10);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_HFLIP:
- if (ctrl->val)
- data = reg_set(client, MT9V022_READ_MODE, 0x20);
- else
- data = reg_clear(client, MT9V022_READ_MODE, 0x20);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_AUTOGAIN:
- if (ctrl->val) {
- if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
- return -EIO;
- } else {
- struct v4l2_ctrl *gain = mt9v022->gain;
- /* mt9v022 has minimum == default */
- unsigned long range = gain->maximum - gain->minimum;
- /* Valid values 16 to 64, 32 to 64 must be even. */
- unsigned long gain_val = ((gain->val - gain->minimum) *
- 48 + range / 2) / range + 16;
-
- if (gain_val >= 32)
- gain_val &= ~1;
-
- /*
- * The user wants to set gain manually, hope, she
- * knows, what she's doing... Switch AGC off.
- */
- if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
- return -EIO;
-
- dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
- reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
- if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
- return -EIO;
- }
- return 0;
- case V4L2_CID_EXPOSURE_AUTO:
- if (ctrl->val == V4L2_EXPOSURE_AUTO) {
- data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
- } else {
- struct v4l2_ctrl *exp = mt9v022->exposure;
- unsigned long range = exp->maximum - exp->minimum;
- unsigned long shutter = ((exp->val - exp->minimum) *
- 479 + range / 2) / range + 1;
-
- /*
- * The user wants to set shutter width manually, hope,
- * she knows, what she's doing... Switch AEC off.
- */
- data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
- if (data < 0)
- return -EIO;
- dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
- reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
- shutter);
- if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- shutter) < 0)
- return -EIO;
- }
- return 0;
- }
- return -EINVAL;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9v022_video_probe(struct i2c_client *client)
-{
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- s32 data;
- int ret;
- unsigned long flags;
-
- /* Read out the chip version register */
- data = reg_read(client, MT9V022_CHIP_VERSION);
-
- /* must be 0x1311 or 0x1313 */
- if (data != 0x1311 && data != 0x1313) {
- ret = -ENODEV;
- dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
- data);
- goto ei2c;
- }
-
- /* Soft reset */
- ret = reg_write(client, MT9V022_RESET, 1);
- if (ret < 0)
- goto ei2c;
- /* 15 clock cycles */
- udelay(200);
- if (reg_read(client, MT9V022_RESET)) {
- dev_err(&client->dev, "Resetting MT9V022 failed!\n");
- if (ret > 0)
- ret = -EIO;
- goto ei2c;
- }
-
- /* Set monochrome or colour sensor type */
- if (sensor_type && (!strcmp("colour", sensor_type) ||
- !strcmp("color", sensor_type))) {
- ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
- mt9v022->fmts = mt9v022_colour_fmts;
- } else {
- ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
- mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
- mt9v022->fmts = mt9v022_monochrome_fmts;
- }
-
- if (ret < 0)
- goto ei2c;
-
- mt9v022->num_fmts = 0;
-
- /*
- * This is a 10bit sensor, so by default we only allow 10bit.
- * The platform may support different bus widths due to
- * different routing of the data lines.
- */
- if (icl->query_bus_param)
- flags = icl->query_bus_param(icl);
- else
- flags = SOCAM_DATAWIDTH_10;
-
- if (flags & SOCAM_DATAWIDTH_10)
- mt9v022->num_fmts++;
- else
- mt9v022->fmts++;
-
- if (flags & SOCAM_DATAWIDTH_8)
- mt9v022->num_fmts++;
-
- mt9v022->fmt = &mt9v022->fmts[0];
-
- dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
- data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
- "monochrome" : "colour");
-
- ret = mt9v022_init(client);
- if (ret < 0)
- dev_err(&client->dev, "Failed to initialise the camera\n");
-
-ei2c:
- return ret;
-}
-
-static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- *lines = mt9v022->y_skip_top;
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
- .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
- .s_ctrl = mt9v022_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
- .g_chip_ident = mt9v022_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = mt9v022_g_register,
- .s_register = mt9v022_s_register,
-#endif
-};
-
-static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
-
- if (index >= mt9v022->num_fmts)
- return -EINVAL;
-
- *code = mt9v022->fmts[index].code;
- return 0;
-}
-
-static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
- unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
- int ret;
- u16 pixclk = 0;
-
- if (icl->set_bus_param) {
- ret = icl->set_bus_param(icl, 1 << (bps - 1));
- if (ret)
- return ret;
- } else if (bps != 10) {
- /*
- * Without board specific bus width settings we only support the
- * sensors native bus width
- */
- return -EINVAL;
- }
-
- if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- pixclk |= 0x10;
-
- if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
- pixclk |= 0x1;
-
- if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
- pixclk |= 0x2;
-
- ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
- if (ret < 0)
- return ret;
-
- if (!(flags & V4L2_MBUS_MASTER))
- mt9v022->chip_control &= ~0x8;
-
- ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
- if (ret < 0)
- return ret;
-
- dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
- pixclk, mt9v022->chip_control);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
- .s_stream = mt9v022_s_stream,
- .s_mbus_fmt = mt9v022_s_fmt,
- .g_mbus_fmt = mt9v022_g_fmt,
- .try_mbus_fmt = mt9v022_try_fmt,
- .s_crop = mt9v022_s_crop,
- .g_crop = mt9v022_g_crop,
- .cropcap = mt9v022_cropcap,
- .enum_mbus_fmt = mt9v022_enum_fmt,
- .g_mbus_config = mt9v022_g_mbus_config,
- .s_mbus_config = mt9v022_s_mbus_config,
-};
-
-static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
- .g_skip_top_lines = mt9v022_g_skip_top_lines,
-};
-
-static struct v4l2_subdev_ops mt9v022_subdev_ops = {
- .core = &mt9v022_subdev_core_ops,
- .video = &mt9v022_subdev_video_ops,
- .sensor = &mt9v022_subdev_sensor_ops,
-};
-
-static int mt9v022_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct mt9v022 *mt9v022;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "MT9V022 driver needs platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
- return -EIO;
- }
-
- mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
- if (!mt9v022)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
- v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
- v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
- V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
- V4L2_CID_GAIN, 0, 127, 1, 64);
-
- /*
- * Simulated autoexposure. If enabled, we calculate shutter width
- * ourselves in the driver based on vertical blanking and frame width
- */
- mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
- &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
- V4L2_EXPOSURE_AUTO);
- mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, 255, 1, 255);
-
- mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
- if (mt9v022->hdl.error) {
- int err = mt9v022->hdl.error;
-
- kfree(mt9v022);
- return err;
- }
- v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
- V4L2_EXPOSURE_MANUAL, true);
- v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
-
- mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
-
- /*
- * MT9V022 _really_ corrupts the first read out line.
- * TODO: verify on i.MX31
- */
- mt9v022->y_skip_top = 1;
- mt9v022->rect.left = MT9V022_COLUMN_SKIP;
- mt9v022->rect.top = MT9V022_ROW_SKIP;
- mt9v022->rect.width = MT9V022_MAX_WIDTH;
- mt9v022->rect.height = MT9V022_MAX_HEIGHT;
-
- ret = mt9v022_video_probe(client);
- if (ret) {
- v4l2_ctrl_handler_free(&mt9v022->hdl);
- kfree(mt9v022);
- }
-
- return ret;
-}
-
-static int mt9v022_remove(struct i2c_client *client)
-{
- struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- v4l2_device_unregister_subdev(&mt9v022->subdev);
- if (icl->free_bus)
- icl->free_bus(icl);
- v4l2_ctrl_handler_free(&mt9v022->hdl);
- kfree(mt9v022);
-
- return 0;
-}
-static const struct i2c_device_id mt9v022_id[] = {
- { "mt9v022", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9v022_id);
-
-static struct i2c_driver mt9v022_i2c_driver = {
- .driver = {
- .name = "mt9v022",
- },
- .probe = mt9v022_probe,
- .remove = mt9v022_remove,
- .id_table = mt9v022_id,
-};
-
-module_i2c_driver(mt9v022_i2c_driver);
-
-MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
deleted file mode 100644
index ac175406e582..000000000000
--- a/drivers/media/video/mx2_camera.c
+++ /dev/null
@@ -1,1884 +0,0 @@
-/*
- * V4L2 Driver for i.MX27/i.MX25 camera host
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#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/math64.h>
-#include <linux/mm.h>
-#include <linux/moduleparam.h>
-#include <linux/time.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/clk.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-dev.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>
-#include <mach/hardware.h>
-
-#include <asm/dma.h>
-
-#define MX2_CAM_DRV_NAME "mx2-camera"
-#define MX2_CAM_VERSION "0.0.6"
-#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
-
-/* reset values */
-#define CSICR1_RESET_VAL 0x40000800
-#define CSICR2_RESET_VAL 0x0
-#define CSICR3_RESET_VAL 0x0
-
-/* csi control reg 1 */
-#define CSICR1_SWAP16_EN (1 << 31)
-#define CSICR1_EXT_VSYNC (1 << 30)
-#define CSICR1_EOF_INTEN (1 << 29)
-#define CSICR1_PRP_IF_EN (1 << 28)
-#define CSICR1_CCIR_MODE (1 << 27)
-#define CSICR1_COF_INTEN (1 << 26)
-#define CSICR1_SF_OR_INTEN (1 << 25)
-#define CSICR1_RF_OR_INTEN (1 << 24)
-#define CSICR1_STATFF_LEVEL (3 << 22)
-#define CSICR1_STATFF_INTEN (1 << 21)
-#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */
-#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */
-#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */
-#define CSICR1_RXFF_INTEN (1 << 18)
-#define CSICR1_SOF_POL (1 << 17)
-#define CSICR1_SOF_INTEN (1 << 16)
-#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12)
-#define CSICR1_HSYNC_POL (1 << 11)
-#define CSICR1_CCIR_EN (1 << 10)
-#define CSICR1_MCLKEN (1 << 9)
-#define CSICR1_FCC (1 << 8)
-#define CSICR1_PACK_DIR (1 << 7)
-#define CSICR1_CLR_STATFIFO (1 << 6)
-#define CSICR1_CLR_RXFIFO (1 << 5)
-#define CSICR1_GCLK_MODE (1 << 4)
-#define CSICR1_INV_DATA (1 << 3)
-#define CSICR1_INV_PCLK (1 << 2)
-#define CSICR1_REDGE (1 << 1)
-#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN)
-
-#define SHIFT_STATFF_LEVEL 22
-#define SHIFT_RXFF_LEVEL 19
-#define SHIFT_MCLKDIV 12
-
-/* control reg 3 */
-#define CSICR3_FRMCNT (0xFFFF << 16)
-#define CSICR3_FRMCNT_RST (1 << 15)
-#define CSICR3_DMA_REFLASH_RFF (1 << 14)
-#define CSICR3_DMA_REFLASH_SFF (1 << 13)
-#define CSICR3_DMA_REQ_EN_RFF (1 << 12)
-#define CSICR3_DMA_REQ_EN_SFF (1 << 11)
-#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */
-#define CSICR3_CSI_SUP (1 << 3)
-#define CSICR3_ZERO_PACK_EN (1 << 2)
-#define CSICR3_ECC_INT_EN (1 << 1)
-#define CSICR3_ECC_AUTO_EN (1 << 0)
-
-#define SHIFT_FRMCNT 16
-
-/* csi status reg */
-#define CSISR_SFF_OR_INT (1 << 25)
-#define CSISR_RFF_OR_INT (1 << 24)
-#define CSISR_STATFF_INT (1 << 21)
-#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */
-#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */
-#define CSISR_RXFF_INT (1 << 18)
-#define CSISR_EOF_INT (1 << 17)
-#define CSISR_SOF_INT (1 << 16)
-#define CSISR_F2_INT (1 << 15)
-#define CSISR_F1_INT (1 << 14)
-#define CSISR_COF_INT (1 << 13)
-#define CSISR_ECC_INT (1 << 1)
-#define CSISR_DRDY (1 << 0)
-
-#define CSICR1 0x00
-#define CSICR2 0x04
-#define CSISR (cpu_is_mx27() ? 0x08 : 0x18)
-#define CSISTATFIFO 0x0c
-#define CSIRFIFO 0x10
-#define CSIRXCNT 0x14
-#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08)
-#define CSIDMASA_STATFIFO 0x20
-#define CSIDMATA_STATFIFO 0x24
-#define CSIDMASA_FB1 0x28
-#define CSIDMASA_FB2 0x2c
-#define CSIFBUF_PARA 0x30
-#define CSIIMAG_PARA 0x34
-
-/* 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)
-
-/* 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)
-
-/* 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;
- u32 csicr1;
-};
-
-/* 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;
- struct soc_camera_device *icd;
- struct clk *clk_csi, *clk_emma_ahb, *clk_emma_ipg;
-
- unsigned int irq_csi, irq_emma;
- void __iomem *base_csi, *base_emma;
- unsigned long base_dma;
-
- struct mx2_camera_platform_data *pdata;
- struct resource *res_csi, *res_emma;
- unsigned long platform_flags;
-
- struct list_head capture;
- struct list_head active_bufs;
- struct list_head discard;
-
- spinlock_t lock;
-
- int dma;
- struct mx2_buffer *active;
- struct mx2_buffer *fb1_active;
- struct mx2_buffer *fb2_active;
-
- 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;
-};
-
-static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
-{
- return container_of(int_buf, struct mx2_buffer, internal);
-}
-
-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,
- .csicr1 = 0,
- }
- },
- {
- .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,
- .csicr1 = CSICR1_PACK_DIR,
- }
- },
- {
- .in_fmt = V4L2_MBUS_FMT_UYVY8_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,
- .csicr1 = CSICR1_SWAP16_EN,
- }
- },
-};
-
-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_unprepare(pcdev->clk_csi);
- writel(0, pcdev->base_csi + CSICR1);
- if (cpu_is_mx27()) {
- writel(0, pcdev->base_emma + PRP_CNTL);
- } else if (cpu_is_mx25()) {
- spin_lock_irqsave(&pcdev->lock, flags);
- pcdev->fb1_active = NULL;
- pcdev->fb2_active = NULL;
- writel(0, pcdev->base_csi + CSIDMASA_FB1);
- writel(0, pcdev->base_csi + CSIDMASA_FB2);
- spin_unlock_irqrestore(&pcdev->lock, flags);
- }
-}
-
-/*
- * The following two functions absolutely depend on the fact, that
- * there can be only one camera on mx2 camera sensor interface
- */
-static int mx2_camera_add_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx2_camera_dev *pcdev = ici->priv;
- int ret;
- u32 csicr1;
-
- if (pcdev->icd)
- return -EBUSY;
-
- ret = clk_prepare_enable(pcdev->clk_csi);
- if (ret < 0)
- return ret;
-
- csicr1 = CSICR1_MCLKEN;
-
- if (cpu_is_mx27()) {
- csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
- CSICR1_RXFF_LEVEL(0);
- } else if (cpu_is_mx27())
- csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
-
- pcdev->csicr1 = csicr1;
- 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);
-
- return 0;
-}
-
-static void mx2_camera_remove_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx2_camera_dev *pcdev = ici->priv;
-
- BUG_ON(icd != pcdev->icd);
-
- dev_info(icd->parent, "Camera driver detached from camera %d\n",
- icd->devnum);
-
- mx2_camera_deactivate(pcdev);
-
- pcdev->icd = NULL;
-}
-
-static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
- int state)
-{
- struct vb2_buffer *vb;
- struct mx2_buffer *buf;
- struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
- &pcdev->fb2_active;
- u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
- unsigned long flags;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- if (*fb_active == NULL)
- goto out;
-
- vb = &(*fb_active)->vb;
- 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));
-
- 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_first_entry(&pcdev->capture, struct mx2_buffer,
- internal.queue);
- vb = &buf->vb;
- 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;
-
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
-{
- struct mx2_camera_dev *pcdev = data;
- u32 status = readl(pcdev->base_csi + CSISR);
-
- if (status & CSISR_DMA_TSF_FB1_INT)
- mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
- else if (status & CSISR_DMA_TSF_FB2_INT)
- mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
-
- /* FIXME: handle CSISR_RFF_OR_INT */
-
- writel(status, pcdev->base_csi + CSISR);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Videobuf operations
- */
-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 = soc_camera_from_vb2q(vq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx2_camera_dev *pcdev = ici->priv;
-
- 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;
-
- alloc_ctxs[0] = pcdev->alloc_ctx;
-
- sizes[0] = icd->sizeimage;
-
- if (0 == *count)
- *count = 32;
- if (!*num_planes &&
- sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
- *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
-
- *num_planes = 1;
-
- return 0;
-}
-
-static int mx2_videobuf_prepare(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- int ret = 0;
-
- 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));
-
-#ifdef DEBUG
- /*
- * This can be useful if you want to see if we actually fill
- * the buffer with something
- */
- memset((void *)vb2_plane_vaddr(vb, 0),
- 0xaa, vb2_get_plane_payload(vb, 0));
-#endif
-
- vb2_set_plane_payload(vb, 0, icd->sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
- ret = -EINVAL;
- goto out;
- }
-
- return 0;
-
-out:
- return ret;
-}
-
-static void mx2_videobuf_queue(struct vb2_buffer *vb)
-{
- 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%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- buf->state = MX2_STATE_QUEUED;
- list_add_tail(&buf->internal.queue, &pcdev->capture);
-
- if (cpu_is_mx25()) {
- u32 csicr3, dma_inten = 0;
-
- if (pcdev->fb1_active == NULL) {
- 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(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(&buf->internal.queue);
- buf->state = MX2_STATE_ACTIVE;
-
- csicr3 = readl(pcdev->base_csi + CSICR3);
-
- /* Reflash DMA */
- writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
- pcdev->base_csi + CSICR3);
-
- /* clear & enable interrupts */
- writel(dma_inten, pcdev->base_csi + CSISR);
- pcdev->csicr1 |= dma_inten;
- writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
-
- /* enable DMA */
- csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
- writel(csicr3, pcdev->base_csi + CSICR3);
- }
- }
-
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static void mx2_videobuf_release(struct vb2_buffer *vb)
-{
- 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%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
-
- switch (buf->state) {
- case MX2_STATE_ACTIVE:
- dev_info(icd->parent, "%s (active)\n", __func__);
- break;
- case MX2_STATE_QUEUED:
- dev_info(icd->parent, "%s (queued)\n", __func__);
- break;
- default:
- dev_info(icd->parent, "%s (unknown) %d\n", __func__,
- buf->state);
- break;
- }
-#endif
-
- /*
- * Terminate only queued but inactive buffers. Active buffers are
- * released when they become inactive after videobuf_waiton().
- *
- * FIXME: implement forced termination of active buffers for mx27 and
- * mx27 eMMA, so that the user won't get stuck in an uninterruptible
- * state. This requires a specific handling for each of the these DMA
- * types.
- */
-
- spin_lock_irqsave(&pcdev->lock, flags);
- 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);
- pcdev->fb1_active = NULL;
- } else if (pcdev->fb2_active == buf) {
- pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
- writel(0, pcdev->base_csi + CSIDMASA_FB2);
- pcdev->fb2_active = NULL;
- }
- writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
- }
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-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 void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
-{
- int dir;
-
- 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_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);
-
- 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 | \
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
- V4L2_MBUS_VSYNC_ACTIVE_LOW | \
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
- V4L2_MBUS_HSYNC_ACTIVE_LOW | \
- V4L2_MBUS_PCLK_SAMPLE_RISING | \
- V4L2_MBUS_PCLK_SAMPLE_FALLING | \
- V4L2_MBUS_DATA_ACTIVE_HIGH | \
- V4L2_MBUS_DATA_ACTIVE_LOW)
-
-static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
-{
- u32 cntl;
- int count = 0;
-
- cntl = readl(pcdev->base_emma + PRP_CNTL);
- writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
- while (count++ < 100) {
- if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
- return 0;
- barrier();
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
-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);
- struct mx2_camera_dev *pcdev = ici->priv;
- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
- unsigned long common_flags;
- int ret;
- int bytesperline;
- u32 csicr1 = pcdev->csicr1;
-
- ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS);
- if (!common_flags) {
- dev_warn(icd->parent,
- "Flags incompatible: camera 0x%x, host 0x%x\n",
- cfg.flags, MX2_BUS_FLAGS);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = MX2_BUS_FLAGS;
- }
-
- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
- else
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
- }
-
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- }
-
- cfg.flags = common_flags;
- ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
- if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
- return ret;
- }
-
- csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1;
-
- if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- csicr1 |= CSICR1_REDGE;
- if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
- csicr1 |= CSICR1_SOF_POL;
- if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
- csicr1 |= CSICR1_HSYNC_POL;
- if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
- csicr1 |= CSICR1_EXT_VSYNC;
- if (pcdev->platform_flags & MX2_CAMERA_CCIR)
- csicr1 |= CSICR1_CCIR_EN;
- if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
- csicr1 |= CSICR1_CCIR_MODE;
- if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
- csicr1 |= CSICR1_GCLK_MODE;
- if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
- csicr1 |= CSICR1_INV_DATA;
-
- pcdev->csicr1 = csicr1;
-
- bytesperline = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- if (bytesperline < 0)
- return bytesperline;
-
- if (cpu_is_mx27()) {
- ret = mx27_camera_emma_prp_reset(pcdev);
- if (ret)
- return ret;
- } else if (cpu_is_mx25()) {
- writel((bytesperline * icd->user_height) >> 2,
- pcdev->base_csi + CSIRXCNT);
- writel((bytesperline << 16) | icd->user_height,
- pcdev->base_csi + CSIIMAG_PARA);
- }
-
- writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
-
- return 0;
-}
-
-static int mx2_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
-{
- struct v4l2_rect *rect = &a->c;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
- soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
-
- ret = v4l2_subdev_call(sd, video, s_crop, a);
- if (ret < 0)
- return ret;
-
- /* The capture device might have changed its output */
- ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
- mf.width, mf.height);
-
- icd->user_width = mf.width;
- icd->user_height = mf.height;
-
- 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 ||
- code == V4L2_MBUS_FMT_UYVY8_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",
- pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
- 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;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- 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;
-}
-
-static int mx2_camera_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- 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;
- __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);
- return -EINVAL;
- }
-
- /* FIXME: implement MX27 limits */
-
- /* limit to MX25 hardware capabilities */
- if (cpu_is_mx25()) {
- if (xlate->host_fmt->bits_per_sample <= 8)
- width_limit = 0xffff * 4;
- else
- width_limit = 0xffff * 2;
- /* CSIIMAG_PARA limit */
- if (pix->width > width_limit)
- pix->width = width_limit;
- if (pix->height > 0xffff)
- pix->height = 0xffff;
-
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- if (pix->bytesperline < 0)
- return pix->bytesperline;
- pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
- pix->bytesperline, pix->height);
- /* Check against the CSIRXCNT limit */
- if (pix->sizeimage > 4 * 0x3ffff) {
- /* Adjust geometry, preserve aspect ratio */
- unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
- 4 * pix->height, pix->bytesperline));
- pix->width = new_height * pix->width / pix->height;
- pix->height = new_height;
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- BUG_ON(pix->bytesperline < 0);
- pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
- pix->bytesperline, pix->height);
- }
- }
-
- /* limit to sensor capabilities */
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
- 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;
- /*
- * 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;
- }
-
- pix->width = mf.width;
- pix->height = mf.height;
- 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;
-}
-
-static int mx2_camera_querycap(struct soc_camera_host *ici,
- struct v4l2_capability *cap)
-{
- /* cap->name is set by the friendly caller:-> */
- strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
-
- return vb2_poll(&icd->vb2_vidq, file, pt);
-}
-
-static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
- .owner = THIS_MODULE,
- .add = mx2_camera_add_device,
- .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_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, bool err)
-{
-#ifdef DEBUG
- struct mx2_fmt_cfg *prp = pcdev->emma_prp;
-#endif
- struct mx2_buf_internal *ibuf;
- struct mx2_buffer *buf;
- struct vb2_buffer *vb;
- unsigned long phys;
-
- ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
- queue);
-
- 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 = 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_Y_PTR - 0x14 * bufnum));
- }
- }
-#endif
- 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));
-
- 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)) {
- 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_first_entry(&pcdev->capture, struct mx2_buffer,
- internal.queue);
-
- buf->internal.bufnum = bufnum;
-
- list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
-
- vb = &buf->vb;
- buf->state = MX2_STATE_ACTIVE;
-
- 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_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 = 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);
-
- 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
- */
- 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);
- }
-
- spin_unlock(&pcdev->lock);
- writel(status, pcdev->base_emma + PRP_INTRSTATUS);
-
- return IRQ_HANDLED;
-}
-
-static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
-{
- struct resource *res_emma = pcdev->res_emma;
- int err = 0;
-
- if (!request_mem_region(res_emma->start, resource_size(res_emma),
- MX2_CAM_DRV_NAME)) {
- err = -EBUSY;
- goto out;
- }
-
- pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
- if (!pcdev->base_emma) {
- err = -ENOMEM;
- goto exit_release;
- }
-
- err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
- MX2_CAM_DRV_NAME, pcdev);
- if (err) {
- dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
- goto exit_iounmap;
- }
-
- pcdev->clk_emma_ipg = clk_get(pcdev->dev, "emma-ipg");
- if (IS_ERR(pcdev->clk_emma_ipg)) {
- err = PTR_ERR(pcdev->clk_emma_ipg);
- goto exit_free_irq;
- }
-
- clk_prepare_enable(pcdev->clk_emma_ipg);
-
- pcdev->clk_emma_ahb = clk_get(pcdev->dev, "emma-ahb");
- if (IS_ERR(pcdev->clk_emma_ahb)) {
- err = PTR_ERR(pcdev->clk_emma_ahb);
- goto exit_clk_emma_ipg_put;
- }
-
- clk_prepare_enable(pcdev->clk_emma_ahb);
-
- err = mx27_camera_emma_prp_reset(pcdev);
- if (err)
- goto exit_clk_emma_ahb_put;
-
- return err;
-
-exit_clk_emma_ahb_put:
- clk_disable_unprepare(pcdev->clk_emma_ahb);
- clk_put(pcdev->clk_emma_ahb);
-exit_clk_emma_ipg_put:
- clk_disable_unprepare(pcdev->clk_emma_ipg);
- clk_put(pcdev->clk_emma_ipg);
-exit_free_irq:
- free_irq(pcdev->irq_emma, pcdev);
-exit_iounmap:
- iounmap(pcdev->base_emma);
-exit_release:
- release_mem_region(res_emma->start, resource_size(res_emma));
-out:
- return err;
-}
-
-static int __devinit mx2_camera_probe(struct platform_device *pdev)
-{
- struct mx2_camera_dev *pcdev;
- struct resource *res_csi, *res_emma;
- void __iomem *base_csi;
- int irq_csi, irq_emma;
- int err = 0;
-
- dev_dbg(&pdev->dev, "initialising\n");
-
- res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq_csi = platform_get_irq(pdev, 0);
- if (res_csi == NULL || irq_csi < 0) {
- dev_err(&pdev->dev, "Missing platform resources data\n");
- err = -ENODEV;
- goto exit;
- }
-
- pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
- if (!pcdev) {
- dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit;
- }
-
- pcdev->clk_csi = clk_get(&pdev->dev, "ahb");
- 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;
- }
-
- pcdev->res_csi = res_csi;
- pcdev->pdata = pdev->dev.platform_data;
- if (pcdev->pdata) {
- long rate;
-
- pcdev->platform_flags = pcdev->pdata->flags;
-
- rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
- if (rate <= 0) {
- err = -ENODEV;
- goto exit_dma_free;
- }
- err = clk_set_rate(pcdev->clk_csi, rate);
- if (err < 0)
- goto exit_dma_free;
- }
-
- INIT_LIST_HEAD(&pcdev->capture);
- INIT_LIST_HEAD(&pcdev->active_bufs);
- INIT_LIST_HEAD(&pcdev->discard);
- spin_lock_init(&pcdev->lock);
-
- /*
- * Request the regions.
- */
- if (!request_mem_region(res_csi->start, resource_size(res_csi),
- MX2_CAM_DRV_NAME)) {
- err = -EBUSY;
- goto exit_dma_free;
- }
-
- base_csi = ioremap(res_csi->start, resource_size(res_csi));
- if (!base_csi) {
- err = -ENOMEM;
- goto exit_release;
- }
- pcdev->irq_csi = irq_csi;
- pcdev->base_csi = base_csi;
- pcdev->base_dma = res_csi->start;
- pcdev->dev = &pdev->dev;
-
- 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()) {
- /* EMMA support */
- res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- irq_emma = platform_get_irq(pdev, 1);
-
- 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,
- pcdev->soc_host.ops = &mx2_soc_camera_host_ops,
- pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
- pcdev->soc_host.nr = pdev->id;
- if (cpu_is_mx25())
- pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
-
- 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;
-
- dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
- clk_get_rate(pcdev->clk_csi));
-
- return 0;
-
-exit_free_emma:
- vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-eallocctx:
- if (cpu_is_mx27()) {
- free_irq(pcdev->irq_emma, pcdev);
- clk_disable_unprepare(pcdev->clk_emma_ipg);
- clk_put(pcdev->clk_emma_ipg);
- clk_disable_unprepare(pcdev->clk_emma_ahb);
- clk_put(pcdev->clk_emma_ahb);
- iounmap(pcdev->base_emma);
- release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
- }
-exit_free_irq:
- 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:
- clk_put(pcdev->clk_csi);
-exit_kfree:
- kfree(pcdev);
-exit:
- return err;
-}
-
-static int __devexit mx2_camera_remove(struct platform_device *pdev)
-{
- struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
- struct mx2_camera_dev *pcdev = container_of(soc_host,
- struct mx2_camera_dev, soc_host);
- struct resource *res;
-
- clk_put(pcdev->clk_csi);
- if (cpu_is_mx25())
- free_irq(pcdev->irq_csi, pcdev);
- if (cpu_is_mx27())
- 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 (cpu_is_mx27()) {
- clk_disable_unprepare(pcdev->clk_emma_ipg);
- clk_put(pcdev->clk_emma_ipg);
- clk_disable_unprepare(pcdev->clk_emma_ahb);
- clk_put(pcdev->clk_emma_ahb);
- iounmap(pcdev->base_emma);
- res = pcdev->res_emma;
- release_mem_region(res->start, resource_size(res));
- }
-
- res = pcdev->res_csi;
- release_mem_region(res->start, resource_size(res));
-
- kfree(pcdev);
-
- dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
-
- return 0;
-}
-
-static struct platform_driver mx2_camera_driver = {
- .driver = {
- .name = MX2_CAM_DRV_NAME,
- },
- .remove = __devexit_p(mx2_camera_remove),
-};
-
-
-static int __init mx2_camera_init(void)
-{
- return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
-}
-
-static void __exit mx2_camera_exit(void)
-{
- return platform_driver_unregister(&mx2_camera_driver);
-}
-
-module_init(mx2_camera_init);
-module_exit(mx2_camera_exit);
-
-MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
-MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MX2_CAM_VERSION);
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
deleted file mode 100644
index 5f8a6f5b98f9..000000000000
--- a/drivers/media/video/mx2_emmaprp.c
+++ /dev/null
@@ -1,1016 +0,0 @@
-/*
- * 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);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_M2M | 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 | VB2_USERPTR;
- 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 | VB2_USERPTR;
- 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;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- 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
deleted file mode 100644
index af2297dd49c8..000000000000
--- a/drivers/media/video/mx3_camera.c
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- * V4L2 Driver for i.MX3x camera host
- *
- * Copyright (C) 2008
- * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/videodev2.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-dev.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
-
-#include <mach/ipu.h>
-#include <mach/mx3_camera.h>
-#include <mach/dma.h>
-
-#define MX3_CAM_DRV_NAME "mx3-camera"
-
-/* CMOS Sensor Interface Registers */
-#define CSI_REG_START 0x60
-
-#define CSI_SENS_CONF (0x60 - CSI_REG_START)
-#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START)
-#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START)
-#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START)
-#define CSI_TST_CTRL (0x70 - CSI_REG_START)
-#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START)
-#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START)
-#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START)
-#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START)
-#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START)
-
-#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
-#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
-#define CSI_SENS_CONF_DATA_POL_SHIFT 2
-#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
-#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
-#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7
-#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
-#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10
-#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
-#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
-
-#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
-#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
-#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
-
-#define MAX_VIDEO_MEM 16
-
-struct mx3_camera_buffer {
- /* common v4l buffer stuff -- must be first */
- struct vb2_buffer vb;
- struct list_head queue;
-
- /* One descriptot per scatterlist (per frame) */
- struct dma_async_tx_descriptor *txd;
-
- /* We have to "build" a scatterlist ourselves - one element per frame */
- struct scatterlist sg;
-};
-
-/**
- * struct mx3_camera_dev - i.MX3x camera (CSI) object
- * @dev: camera device, to which the coherent buffer is attached
- * @icd: currently attached camera sensor
- * @clk: pointer to clock
- * @base: remapped register base address
- * @pdata: platform data
- * @platform_flags: platform flags
- * @mclk: master clock frequency in Hz
- * @capture: list of capture videobuffers
- * @lock: protects video buffer lists
- * @active: active video buffer
- * @idmac_channel: array of pointers to IPU DMAC DMA channels
- * @soc_host: embedded soc_host object
- */
-struct mx3_camera_dev {
- /*
- * i.MX3x is only supposed to handle one camera on its Camera Sensor
- * Interface. If anyone ever builds hardware to enable more than one
- * camera _simultaneously_, they will have to modify this driver too
- */
- struct soc_camera_device *icd;
- struct clk *clk;
-
- void __iomem *base;
-
- struct mx3_camera_pdata *pdata;
-
- unsigned long platform_flags;
- unsigned long mclk;
- u16 width_flags; /* max 15 bits */
-
- struct list_head capture;
- spinlock_t lock; /* Protects video buffer lists */
- struct mx3_camera_buffer *active;
- size_t buf_total;
- struct vb2_alloc_ctx *alloc_ctx;
- enum v4l2_field field;
- int sequence;
-
- /* IDMAC / dmaengine interface */
- struct idmac_channel *idmac_channel[1]; /* We need one channel */
-
- struct soc_camera_host soc_host;
-};
-
-struct dma_chan_request {
- struct mx3_camera_dev *mx3_cam;
- enum ipu_channel id;
-};
-
-static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
-{
- return __raw_readl(mx3->base + reg);
-}
-
-static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
-{
- __raw_writel(value, mx3->base + reg);
-}
-
-static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb)
-{
- return container_of(vb, struct mx3_camera_buffer, vb);
-}
-
-/* Called from the IPU IDMAC ISR */
-static void mx3_cam_dma_done(void *arg)
-{
- struct idmac_tx_desc *desc = to_tx_desc(arg);
- struct dma_chan *chan = desc->txd.chan;
- struct idmac_channel *ichannel = to_idmac_chan(chan);
- struct mx3_camera_dev *mx3_cam = ichannel->client;
-
- dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
- desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
-
- spin_lock(&mx3_cam->lock);
- if (mx3_cam->active) {
- struct vb2_buffer *vb = &mx3_cam->active->vb;
- struct mx3_camera_buffer *buf = to_mx3_vb(vb);
-
- list_del_init(&buf->queue);
- do_gettimeofday(&vb->v4l2_buf.timestamp);
- vb->v4l2_buf.field = mx3_cam->field;
- vb->v4l2_buf.sequence = mx3_cam->sequence++;
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
- }
-
- if (list_empty(&mx3_cam->capture)) {
- mx3_cam->active = NULL;
- spin_unlock(&mx3_cam->lock);
-
- /*
- * stop capture - without further buffers IPU_CHA_BUF0_RDY will
- * not get updated
- */
- return;
- }
-
- mx3_cam->active = list_entry(mx3_cam->capture.next,
- struct mx3_camera_buffer, queue);
- spin_unlock(&mx3_cam->lock);
-}
-
-/*
- * Videobuf operations
- */
-
-/*
- * Calculate the __buffer__ (not data) size and number of buffers.
- */
-static int mx3_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 = soc_camera_from_vb2q(vq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
-
- if (!mx3_cam->idmac_channel[0])
- return -EINVAL;
-
- if (fmt) {
- const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
- fmt->fmt.pix.pixelformat);
- unsigned int bytes_per_line;
- int ret;
-
- if (!xlate)
- return -EINVAL;
-
- ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- if (ret < 0)
- return ret;
-
- bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
- ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
- fmt->fmt.pix.height);
- if (ret < 0)
- return ret;
-
- sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
- } else {
- /* Called from VIDIOC_REQBUFS or in compatibility mode */
- sizes[0] = icd->sizeimage;
- }
-
- alloc_ctxs[0] = mx3_cam->alloc_ctx;
-
- if (!vq->num_buffers)
- mx3_cam->sequence = 0;
-
- if (!*count)
- *count = 2;
-
- /* If *num_planes != 0, we have already verified *count. */
- if (!*num_planes &&
- sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
- *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
- sizes[0];
-
- *num_planes = 1;
-
- return 0;
-}
-
-static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
-{
- /* Add more formats as need arises and test possibilities appear... */
- switch (fourcc) {
- case V4L2_PIX_FMT_RGB24:
- return IPU_PIX_FMT_RGB24;
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_RGB565:
- default:
- return IPU_PIX_FMT_GENERIC;
- }
-}
-
-static void mx3_videobuf_queue(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- struct mx3_camera_buffer *buf = to_mx3_vb(vb);
- struct scatterlist *sg = &buf->sg;
- struct dma_async_tx_descriptor *txd;
- struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
- struct idmac_video_param *video = &ichan->params.video;
- const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
- unsigned long flags;
- dma_cookie_t cookie;
- size_t new_size;
-
- new_size = icd->sizeimage;
-
- if (vb2_plane_size(vb, 0) < new_size) {
- dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
- vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size);
- goto error;
- }
-
- if (!buf->txd) {
- sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
- sg_dma_len(sg) = new_size;
-
- txd = dmaengine_prep_slave_sg(
- &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT);
- if (!txd)
- goto error;
-
- txd->callback_param = txd;
- txd->callback = mx3_cam_dma_done;
-
- buf->txd = txd;
- } else {
- txd = buf->txd;
- }
-
- vb2_set_plane_payload(vb, 0, new_size);
-
- /* This is the configuration of one sg-element */
- video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
-
- if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
- /*
- * If the IPU DMA channel is configured to transfer generic
- * 8-bit data, we have to set up the geometry parameters
- * correctly, according to the current pixel format. The DMA
- * horizontal parameters in this case are expressed in bytes,
- * not in pixels.
- */
- video->out_width = icd->bytesperline;
- video->out_height = icd->user_height;
- video->out_stride = icd->bytesperline;
- } else {
- /*
- * For IPU known formats the pixel unit will be managed
- * successfully by the IPU code
- */
- video->out_width = icd->user_width;
- video->out_height = icd->user_height;
- video->out_stride = icd->user_width;
- }
-
-#ifdef DEBUG
- /* helps to see what DMA actually has written */
- if (vb2_plane_vaddr(vb, 0))
- memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
-#endif
-
- spin_lock_irqsave(&mx3_cam->lock, flags);
- list_add_tail(&buf->queue, &mx3_cam->capture);
-
- if (!mx3_cam->active)
- mx3_cam->active = buf;
-
- spin_unlock_irq(&mx3_cam->lock);
-
- cookie = txd->tx_submit(txd);
- dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
- cookie, sg_dma_address(&buf->sg));
-
- if (cookie >= 0)
- return;
-
- spin_lock_irq(&mx3_cam->lock);
-
- /* Submit error */
- list_del_init(&buf->queue);
-
- if (mx3_cam->active == buf)
- mx3_cam->active = NULL;
-
- spin_unlock_irqrestore(&mx3_cam->lock, flags);
-error:
- vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
-}
-
-static void mx3_videobuf_release(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- struct mx3_camera_buffer *buf = to_mx3_vb(vb);
- struct dma_async_tx_descriptor *txd = buf->txd;
- unsigned long flags;
-
- dev_dbg(icd->parent,
- "Release%s DMA 0x%08x, queue %sempty\n",
- mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
- list_empty(&buf->queue) ? "" : "not ");
-
- spin_lock_irqsave(&mx3_cam->lock, flags);
-
- if (mx3_cam->active == buf)
- mx3_cam->active = NULL;
-
- /* Doesn't hurt also if the list is empty */
- list_del_init(&buf->queue);
-
- if (txd) {
- buf->txd = NULL;
- if (mx3_cam->idmac_channel[0])
- async_tx_ack(txd);
- }
-
- spin_unlock_irqrestore(&mx3_cam->lock, flags);
-
- mx3_cam->buf_total -= vb2_plane_size(vb, 0);
-}
-
-static int mx3_videobuf_init(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- struct mx3_camera_buffer *buf = to_mx3_vb(vb);
-
- if (!buf->txd) {
- /* This is for locking debugging only */
- INIT_LIST_HEAD(&buf->queue);
- sg_init_table(&buf->sg, 1);
-
- mx3_cam->buf_total += vb2_plane_size(vb, 0);
- }
-
- return 0;
-}
-
-static int mx3_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 mx3_camera_dev *mx3_cam = ici->priv;
- struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
- struct mx3_camera_buffer *buf, *tmp;
- unsigned long flags;
-
- if (ichan) {
- struct dma_chan *chan = &ichan->dma_chan;
- chan->device->device_control(chan, DMA_PAUSE, 0);
- }
-
- spin_lock_irqsave(&mx3_cam->lock, flags);
-
- mx3_cam->active = NULL;
-
- list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
- list_del_init(&buf->queue);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
- }
-
- spin_unlock_irqrestore(&mx3_cam->lock, flags);
-
- return 0;
-}
-
-static struct vb2_ops mx3_videobuf_ops = {
- .queue_setup = mx3_videobuf_setup,
- .buf_queue = mx3_videobuf_queue,
- .buf_cleanup = mx3_videobuf_release,
- .buf_init = mx3_videobuf_init,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
- .stop_streaming = mx3_stop_streaming,
-};
-
-static int mx3_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 = &mx3_videobuf_ops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct mx3_camera_buffer);
-
- return vb2_queue_init(q);
-}
-
-/* First part of ipu_csi_init_interface() */
-static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
- struct soc_camera_device *icd)
-{
- u32 conf;
- long rate;
-
- /* Set default size: ipu_csi_set_window_size() */
- csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
- /* ...and position to 0:0: ipu_csi_set_window_pos() */
- conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
- csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
-
- /* We use only gated clock synchronisation mode so far */
- conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
-
- /* Set generic data, platform-biggest bus-width */
- conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
-
- if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
- conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
- conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
- conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
- conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
-
- if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
- conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
- if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
- conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
- if (mx3_cam->platform_flags & MX3_CAMERA_DP)
- conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
- if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
- conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
- if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
- conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
- if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
- conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
-
- /* ipu_csi_init_interface() */
- csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
-
- clk_prepare_enable(mx3_cam->clk);
- rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
- dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
- if (rate)
- clk_set_rate(mx3_cam->clk, rate);
-}
-
-/* Called with .video_lock held */
-static int mx3_camera_add_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
-
- if (mx3_cam->icd)
- return -EBUSY;
-
- mx3_camera_activate(mx3_cam, icd);
-
- mx3_cam->buf_total = 0;
- mx3_cam->icd = icd;
-
- dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
- icd->devnum);
-
- return 0;
-}
-
-/* Called with .video_lock held */
-static void mx3_camera_remove_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
-
- BUG_ON(icd != mx3_cam->icd);
-
- if (*ichan) {
- dma_release_channel(&(*ichan)->dma_chan);
- *ichan = NULL;
- }
-
- clk_disable_unprepare(mx3_cam->clk);
-
- mx3_cam->icd = NULL;
-
- dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
- icd->devnum);
-}
-
-static int test_platform_param(struct mx3_camera_dev *mx3_cam,
- unsigned char buswidth, unsigned long *flags)
-{
- /*
- * If requested data width is supported by the platform, use it or any
- * possible lower value - i.MX31 is smart enough to shift bits
- */
- if (buswidth > fls(mx3_cam->width_flags))
- return -EINVAL;
-
- /*
- * Platform specified synchronization and pixel clock polarities are
- * only a recommendation and are only used during probing. MX3x
- * camera interface only works in master mode, i.e., uses HSYNC and
- * VSYNC signals from the sensor
- */
- *flags = V4L2_MBUS_MASTER |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_LOW;
-
- return 0;
-}
-
-static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
- const unsigned int depth)
-{
- 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,};
- unsigned long bus_flags, common_flags;
- int ret = test_platform_param(mx3_cam, depth, &bus_flags);
-
- dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
-
- if (ret < 0)
- return ret;
-
- ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = soc_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(icd->parent,
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- }
-
- return 0;
-}
-
-static bool chan_filter(struct dma_chan *chan, void *arg)
-{
- struct dma_chan_request *rq = arg;
- struct mx3_camera_pdata *pdata;
-
- if (!imx_dma_is_ipu(chan))
- return false;
-
- if (!rq)
- return false;
-
- pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data;
-
- return rq->id == chan->chan_id &&
- pdata->dma_dev == chan->device->dev;
-}
-
-static const struct soc_mbus_pixelfmt mx3_camera_formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .name = "Bayer BGGR (sRGB) 8 bit",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- }, {
- .fourcc = V4L2_PIX_FMT_GREY,
- .name = "Monochrome 8 bit",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-};
-
-/* This will be corrected as we get more formats */
-static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
-{
- return fmt->packing == SOC_MBUS_PACKING_NONE ||
- (fmt->bits_per_sample == 8 &&
- fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
- (fmt->bits_per_sample > 8 &&
- fmt->packing == SOC_MBUS_PACKING_EXTEND16);
-}
-
-static int mx3_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);
- struct device *dev = icd->parent;
- int formats = 0, ret;
- enum v4l2_mbus_pixelcode code;
- const struct soc_mbus_pixelfmt *fmt;
-
- 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_warn(icd->parent,
- "Unsupported format code #%u: %d\n", idx, code);
- return 0;
- }
-
- /* This also checks support for the requested bits-per-sample */
- ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample);
- if (ret < 0)
- return 0;
-
- switch (code) {
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- formats++;
- if (xlate) {
- xlate->host_fmt = &mx3_camera_formats[0];
- xlate->code = code;
- xlate++;
- dev_dbg(dev, "Providing format %s using code %d\n",
- mx3_camera_formats[0].name, code);
- }
- break;
- case V4L2_MBUS_FMT_Y10_1X10:
- formats++;
- if (xlate) {
- xlate->host_fmt = &mx3_camera_formats[1];
- xlate->code = code;
- xlate++;
- dev_dbg(dev, "Providing format %s using code %d\n",
- mx3_camera_formats[1].name, code);
- }
- break;
- default:
- if (!mx3_camera_packing_supported(fmt))
- return 0;
- }
-
- /* Generic pass-through */
- formats++;
- if (xlate) {
- xlate->host_fmt = fmt;
- xlate->code = code;
- dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n",
- (fmt->fourcc >> (0*8)) & 0xFF,
- (fmt->fourcc >> (1*8)) & 0xFF,
- (fmt->fourcc >> (2*8)) & 0xFF,
- (fmt->fourcc >> (3*8)) & 0xFF);
- xlate++;
- }
-
- return formats;
-}
-
-static void configure_geometry(struct mx3_camera_dev *mx3_cam,
- unsigned int width, unsigned int height,
- const struct soc_mbus_pixelfmt *fmt)
-{
- u32 ctrl, width_field, height_field;
-
- if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
- /*
- * As the CSI will be configured to output BAYER, here
- * the width parameter count the number of samples to
- * capture to complete the whole image width.
- */
- unsigned int num, den;
- int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
- BUG_ON(ret < 0);
- width = width * num / den;
- }
-
- /* Setup frame size - this cannot be changed on-the-fly... */
- width_field = width - 1;
- height_field = height - 1;
- csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
-
- csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
- csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
-
- csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
-
- /* ...and position */
- ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
- /* Sensor does the cropping */
- csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
-}
-
-static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
-{
- dma_cap_mask_t mask;
- struct dma_chan *chan;
- struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
- /* We have to use IDMAC_IC_7 for Bayer / generic data */
- struct dma_chan_request rq = {.mx3_cam = mx3_cam,
- .id = IDMAC_IC_7};
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- dma_cap_set(DMA_PRIVATE, mask);
- chan = dma_request_channel(mask, chan_filter, &rq);
- if (!chan)
- return -EBUSY;
-
- *ichan = to_idmac_chan(chan);
- (*ichan)->client = mx3_cam;
-
- return 0;
-}
-
-/*
- * FIXME: learn to use stride != width, then we can keep stride properly aligned
- * and support arbitrary (even) widths.
- */
-static inline void stride_align(__u32 *width)
-{
- if (ALIGN(*width, 8) < 4096)
- *width = ALIGN(*width, 8);
- else
- *width = *width & ~7;
-}
-
-/*
- * As long as we don't implement host-side cropping and scaling, we can use
- * default g_crop and cropcap from soc_camera.c
- */
-static int mx3_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
-{
- struct v4l2_rect *rect = &a->c;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = ici->priv;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
- soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
-
- ret = v4l2_subdev_call(sd, video, s_crop, a);
- if (ret < 0)
- return ret;
-
- /* The capture device might have changed its output sizes */
- ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- if (mf.code != icd->current_fmt->code)
- return -EINVAL;
-
- if (mf.width & 7) {
- /* Ouch! We can only handle 8-byte aligned width... */
- stride_align(&mf.width);
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
- }
-
- if (mf.width != icd->user_width || mf.height != icd->user_height)
- configure_geometry(mx3_cam, mf.width, mf.height,
- icd->current_fmt->host_fmt);
-
- dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
- mf.width, mf.height);
-
- icd->user_width = mf.width;
- icd->user_height = mf.height;
-
- return ret;
-}
-
-static int mx3_camera_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx3_camera_dev *mx3_cam = 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;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(icd->parent, "Format %x not found\n",
- pix->pixelformat);
- return -EINVAL;
- }
-
- stride_align(&pix->width);
- dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height);
-
- /*
- * Might have to perform a complete interface initialisation like in
- * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
- * mxc_v4l2_s_fmt()
- */
-
- configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- if (mf.code != xlate->code)
- return -EINVAL;
-
- if (!mx3_cam->idmac_channel[0]) {
- ret = acquire_dma_channel(mx3_cam);
- if (ret < 0)
- return ret;
- }
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- mx3_cam->field = mf.field;
- pix->colorspace = mf.colorspace;
- icd->current_fmt = xlate;
-
- dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height);
-
- return ret;
-}
-
-static int mx3_camera_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- 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;
- __u32 pixfmt = pix->pixelformat;
- int ret;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (pixfmt && !xlate) {
- dev_warn(icd->parent, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
-
- /* limit to MX3 hardware capabilities */
- if (pix->height > 4096)
- pix->height = 4096;
- if (pix->width > 4096)
- pix->width = 4096;
-
- /* limit to sensor capabilities */
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->colorspace = mf.colorspace;
-
- switch (mf.field) {
- case V4L2_FIELD_ANY:
- pix->field = V4L2_FIELD_NONE;
- break;
- case V4L2_FIELD_NONE:
- break;
- default:
- dev_err(icd->parent, "Field type %d unsupported.\n",
- mf.field);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int mx3_camera_reqbufs(struct soc_camera_device *icd,
- struct v4l2_requestbuffers *p)
-{
- return 0;
-}
-
-static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
-
- return vb2_poll(&icd->vb2_vidq, file, pt);
-}
-
-static int mx3_camera_querycap(struct soc_camera_host *ici,
- struct v4l2_capability *cap)
-{
- /* cap->name is set by the firendly caller:-> */
- strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-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;
- int buswidth;
- int ret;
- const struct soc_camera_format_xlate *xlate;
- struct device *dev = icd->parent;
-
- fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
- if (!fmt)
- return -EINVAL;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (!xlate) {
- dev_warn(dev, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
-
- buswidth = fmt->bits_per_sample;
- ret = test_platform_param(mx3_cam, buswidth, &bus_flags);
-
- dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret);
-
- if (ret < 0)
- return ret;
-
- ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = soc_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(icd->parent,
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = bus_flags;
- }
-
- dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n",
- cfg.flags, bus_flags, common_flags);
-
- /* Make choices, based on platform preferences */
- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
- }
-
- if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
- if (mx3_cam->platform_flags & MX3_CAMERA_DP)
- common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
- }
-
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- }
-
- cfg.flags = common_flags;
- ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
- if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
- return ret;
- }
-
- /*
- * So far only gated clock mode is supported. Add a line
- * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
- * below and select the required mode when supporting other
- * synchronisation protocols.
- */
- sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
- ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
- (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
- (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
- (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
- (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
- (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
-
- /* TODO: Support RGB and YUV formats */
-
- /* This has been set in mx3_camera_activate(), but we clear it above */
- sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
-
- if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
- if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
- if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
- if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
- sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
-
- /* Just do what we're asked to do */
- switch (xlate->host_fmt->bits_per_sample) {
- case 4:
- dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- break;
- case 8:
- dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- break;
- case 10:
- dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- break;
- default:
- /*
- * Actually it can only be 15 now, default is just to silence
- * compiler warnings
- */
- case 15:
- dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
- }
-
- csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
-
- dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw);
-
- return 0;
-}
-
-static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
- .owner = THIS_MODULE,
- .add = mx3_camera_add_device,
- .remove = mx3_camera_remove_device,
- .set_crop = mx3_camera_set_crop,
- .set_fmt = mx3_camera_set_fmt,
- .try_fmt = mx3_camera_try_fmt,
- .get_formats = mx3_camera_get_formats,
- .init_videobuf2 = mx3_camera_init_videobuf,
- .reqbufs = mx3_camera_reqbufs,
- .poll = mx3_camera_poll,
- .querycap = mx3_camera_querycap,
- .set_bus_param = mx3_camera_set_bus_param,
-};
-
-static int __devinit mx3_camera_probe(struct platform_device *pdev)
-{
- struct mx3_camera_dev *mx3_cam;
- struct resource *res;
- void __iomem *base;
- int err = 0;
- struct soc_camera_host *soc_host;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENODEV;
- goto egetres;
- }
-
- mx3_cam = vzalloc(sizeof(*mx3_cam));
- if (!mx3_cam) {
- dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
- err = -ENOMEM;
- goto ealloc;
- }
-
- mx3_cam->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(mx3_cam->clk)) {
- err = PTR_ERR(mx3_cam->clk);
- goto eclkget;
- }
-
- mx3_cam->pdata = pdev->dev.platform_data;
- mx3_cam->platform_flags = mx3_cam->pdata->flags;
- if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
- MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 |
- MX3_CAMERA_DATAWIDTH_15))) {
- /*
- * Platform hasn't set available data widths. This is bad.
- * Warn and use a default.
- */
- dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
- "data widths, using default 8 bit\n");
- mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
- }
- if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)
- mx3_cam->width_flags = 1 << 3;
- if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
- mx3_cam->width_flags |= 1 << 7;
- if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
- mx3_cam->width_flags |= 1 << 9;
- if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
- mx3_cam->width_flags |= 1 << 14;
-
- mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
- if (!mx3_cam->mclk) {
- dev_warn(&pdev->dev,
- "mclk_10khz == 0! Please, fix your platform data. "
- "Using default 20MHz\n");
- mx3_cam->mclk = 20000000;
- }
-
- /* list of video-buffers */
- INIT_LIST_HEAD(&mx3_cam->capture);
- spin_lock_init(&mx3_cam->lock);
-
- base = ioremap(res->start, resource_size(res));
- if (!base) {
- pr_err("Couldn't map %x@%x\n", resource_size(res), res->start);
- err = -ENOMEM;
- goto eioremap;
- }
-
- mx3_cam->base = base;
-
- soc_host = &mx3_cam->soc_host;
- soc_host->drv_name = MX3_CAM_DRV_NAME;
- soc_host->ops = &mx3_soc_camera_host_ops;
- soc_host->priv = mx3_cam;
- soc_host->v4l2_dev.dev = &pdev->dev;
- soc_host->nr = pdev->id;
-
- mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
- if (IS_ERR(mx3_cam->alloc_ctx)) {
- err = PTR_ERR(mx3_cam->alloc_ctx);
- goto eallocctx;
- }
-
- err = soc_camera_host_register(soc_host);
- if (err)
- goto ecamhostreg;
-
- /* IDMAC interface */
- dmaengine_get();
-
- return 0;
-
-ecamhostreg:
- vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
-eallocctx:
- iounmap(base);
-eioremap:
- clk_put(mx3_cam->clk);
-eclkget:
- vfree(mx3_cam);
-ealloc:
-egetres:
- return err;
-}
-
-static int __devexit mx3_camera_remove(struct platform_device *pdev)
-{
- struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
- struct mx3_camera_dev *mx3_cam = container_of(soc_host,
- struct mx3_camera_dev, soc_host);
-
- clk_put(mx3_cam->clk);
-
- soc_camera_host_unregister(soc_host);
-
- iounmap(mx3_cam->base);
-
- /*
- * The channel has either not been allocated,
- * or should have been released
- */
- if (WARN_ON(mx3_cam->idmac_channel[0]))
- dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
-
- vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
-
- vfree(mx3_cam);
-
- dmaengine_put();
-
- return 0;
-}
-
-static struct platform_driver mx3_camera_driver = {
- .driver = {
- .name = MX3_CAM_DRV_NAME,
- },
- .probe = mx3_camera_probe,
- .remove = __devexit_p(mx3_camera_remove),
-};
-
-module_platform_driver(mx3_camera_driver);
-
-MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.2.3");
-MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
deleted file mode 100644
index fc410b438f7d..000000000000
--- a/drivers/media/video/omap/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the omap video device drivers.
-#
-
-# OMAP2/3 Display driver
-omap-vout-y := omap_vout.o omap_voutlib.o
-omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
-obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
deleted file mode 100644
index c7e41145041f..000000000000
--- a/drivers/media/video/omap1_camera.c
+++ /dev/null
@@ -1,1723 +0,0 @@
-/*
- * V4L2 SoC Camera driver for OMAP1 Camera Interface
- *
- * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
- *
- * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host
- * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
- *
- * Based on PXA SoC camera driver
- * Copyright (C) 2006, Sascha Hauer, Pengutronix
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * Hardware specific bits initialy based on former work by Matt Callow
- * drivers/media/video/omap/omap1510cam.c
- * Copyright (C) 2006 Matt Callow
- *
- * 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/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <media/omap1_camera.h>
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
-#include <media/videobuf-dma-contig.h>
-#include <media/videobuf-dma-sg.h>
-
-#include <plat/dma.h>
-
-
-#define DRIVER_NAME "omap1-camera"
-#define DRIVER_VERSION "0.0.2"
-
-
-/*
- * ---------------------------------------------------------------------------
- * OMAP1 Camera Interface registers
- * ---------------------------------------------------------------------------
- */
-
-#define REG_CTRLCLOCK 0x00
-#define REG_IT_STATUS 0x04
-#define REG_MODE 0x08
-#define REG_STATUS 0x0C
-#define REG_CAMDATA 0x10
-#define REG_GPIO 0x14
-#define REG_PEAK_COUNTER 0x18
-
-/* CTRLCLOCK bit shifts */
-#define LCLK_EN BIT(7)
-#define DPLL_EN BIT(6)
-#define MCLK_EN BIT(5)
-#define CAMEXCLK_EN BIT(4)
-#define POLCLK BIT(3)
-#define FOSCMOD_SHIFT 0
-#define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT)
-#define FOSCMOD_12MHz 0x0
-#define FOSCMOD_6MHz 0x2
-#define FOSCMOD_9_6MHz 0x4
-#define FOSCMOD_24MHz 0x5
-#define FOSCMOD_8MHz 0x6
-
-/* IT_STATUS bit shifts */
-#define DATA_TRANSFER BIT(5)
-#define FIFO_FULL BIT(4)
-#define H_DOWN BIT(3)
-#define H_UP BIT(2)
-#define V_DOWN BIT(1)
-#define V_UP BIT(0)
-
-/* MODE bit shifts */
-#define RAZ_FIFO BIT(18)
-#define EN_FIFO_FULL BIT(17)
-#define EN_NIRQ BIT(16)
-#define THRESHOLD_SHIFT 9
-#define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT)
-#define DMA BIT(8)
-#define EN_H_DOWN BIT(7)
-#define EN_H_UP BIT(6)
-#define EN_V_DOWN BIT(5)
-#define EN_V_UP BIT(4)
-#define ORDERCAMD BIT(3)
-
-#define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \
- EN_NIRQ | EN_FIFO_FULL)
-
-/* STATUS bit shifts */
-#define HSTATUS BIT(1)
-#define VSTATUS BIT(0)
-
-/* GPIO bit shifts */
-#define CAM_RST BIT(0)
-
-/* end of OMAP1 Camera Interface registers */
-
-
-#define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
- V4L2_MBUS_DATA_ACTIVE_HIGH)
-
-
-#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
-#define FIFO_SHIFT __fls(FIFO_SIZE)
-
-#define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4)
-#define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT)
-
-#define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32
-#define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT)
-
-#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1)
-#define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT
-
-#define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \
- DMA_FRAME_SHIFT_CONTIG : \
- DMA_FRAME_SHIFT_SG)
-#define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x))
-#define DMA_SYNC OMAP_DMA_SYNC_FRAME
-#define THRESHOLD_LEVEL DMA_FRAME_SIZE
-
-
-#define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */
-
-
-/*
- * Structures
- */
-
-/* buffer for one video frame */
-struct omap1_cam_buf {
- struct videobuf_buffer vb;
- enum v4l2_mbus_pixelcode code;
- int inwork;
- struct scatterlist *sgbuf;
- int sgcount;
- int bytes_left;
- enum videobuf_state result;
-};
-
-struct omap1_cam_dev {
- struct soc_camera_host soc_host;
- struct soc_camera_device *icd;
- struct clk *clk;
-
- unsigned int irq;
- void __iomem *base;
-
- int dma_ch;
-
- struct omap1_cam_platform_data *pdata;
- struct resource *res;
- unsigned long pflags;
- unsigned long camexclk;
-
- struct list_head capture;
-
- /* lock used to protect videobuf */
- spinlock_t lock;
-
- /* Pointers to DMA buffers */
- struct omap1_cam_buf *active;
- struct omap1_cam_buf *ready;
-
- enum omap1_cam_vb_mode vb_mode;
- int (*mmap_mapper)(struct videobuf_queue *q,
- struct videobuf_buffer *buf,
- struct vm_area_struct *vma);
-
- u32 reg_cache[0];
-};
-
-
-static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val)
-{
- pcdev->reg_cache[reg / sizeof(u32)] = val;
- __raw_writel(val, pcdev->base + reg);
-}
-
-static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache)
-{
- return !from_cache ? __raw_readl(pcdev->base + reg) :
- pcdev->reg_cache[reg / sizeof(u32)];
-}
-
-#define CAM_READ(pcdev, reg) \
- cam_read(pcdev, REG_##reg, false)
-#define CAM_WRITE(pcdev, reg, val) \
- cam_write(pcdev, REG_##reg, val)
-#define CAM_READ_CACHE(pcdev, reg) \
- cam_read(pcdev, REG_##reg, true)
-
-/*
- * Videobuf operations
- */
-static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
-
- *size = icd->sizeimage;
-
- if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
- *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
-
- if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
- *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
-
- dev_dbg(icd->parent,
- "%s: count=%d, size=%d\n", __func__, *count, *size);
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
- enum omap1_cam_vb_mode vb_mode)
-{
- struct videobuf_buffer *vb = &buf->vb;
-
- BUG_ON(in_interrupt());
-
- videobuf_waiton(vq, vb, 0, 0);
-
- if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
- videobuf_dma_contig_free(vq, vb);
- } else {
- struct soc_camera_device *icd = vq->priv_data;
- struct device *dev = icd->parent;
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- videobuf_dma_unmap(dev, dma);
- videobuf_dma_free(dma);
- }
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int omap1_videobuf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
- int ret;
-
- WARN_ON(!list_empty(&vb->queue));
-
- BUG_ON(NULL == icd->current_fmt);
-
- buf->inwork = 1;
-
- if (buf->code != icd->current_fmt->code || vb->field != field ||
- vb->width != icd->user_width ||
- vb->height != icd->user_height) {
- 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 = icd->sizeimage;
-
- if (vb->baddr && vb->bsize < vb->size) {
- ret = -EINVAL;
- goto out;
- }
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
-
- vb->state = VIDEOBUF_PREPARED;
- }
- buf->inwork = 0;
-
- return 0;
-fail:
- free_buffer(vq, buf, pcdev->vb_mode);
-out:
- buf->inwork = 0;
- return ret;
-}
-
-static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf,
- enum omap1_cam_vb_mode vb_mode)
-{
- dma_addr_t dma_addr;
- unsigned int block_size;
-
- if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
- dma_addr = videobuf_to_dma_contig(&buf->vb);
- block_size = buf->vb.size;
- } else {
- if (WARN_ON(!buf->sgbuf)) {
- buf->result = VIDEOBUF_ERROR;
- return;
- }
- dma_addr = sg_dma_address(buf->sgbuf);
- if (WARN_ON(!dma_addr)) {
- buf->sgbuf = NULL;
- buf->result = VIDEOBUF_ERROR;
- return;
- }
- block_size = sg_dma_len(buf->sgbuf);
- if (WARN_ON(!block_size)) {
- buf->sgbuf = NULL;
- buf->result = VIDEOBUF_ERROR;
- return;
- }
- if (unlikely(buf->bytes_left < block_size))
- block_size = buf->bytes_left;
- if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) *
- DMA_ELEMENT_SIZE - 1))) {
- dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) *
- DMA_ELEMENT_SIZE);
- block_size &= ~(DMA_FRAME_SIZE(vb_mode) *
- DMA_ELEMENT_SIZE - 1);
- }
- buf->bytes_left -= block_size;
- buf->sgcount++;
- }
-
- omap_set_dma_dest_params(dma_ch,
- OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0);
- omap_set_dma_transfer_params(dma_ch,
- OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode),
- block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT),
- DMA_SYNC, 0, 0);
-}
-
-static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev)
-{
- struct omap1_cam_buf *buf;
-
- /*
- * If there is already a buffer pointed out by the pcdev->ready,
- * (re)use it, otherwise try to fetch and configure a new one.
- */
- buf = pcdev->ready;
- if (!buf) {
- if (list_empty(&pcdev->capture))
- return buf;
- buf = list_entry(pcdev->capture.next,
- struct omap1_cam_buf, vb.queue);
- buf->vb.state = VIDEOBUF_ACTIVE;
- pcdev->ready = buf;
- list_del_init(&buf->vb.queue);
- }
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, we can safely enter next buffer parameters
- * into the DMA programming register set after the DMA
- * has already been activated on the previous buffer
- */
- set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode);
- } else {
- /*
- * In SG mode, the above is not safe since there are probably
- * a bunch of sgbufs from previous sglist still pending.
- * Instead, mark the sglist fresh for the upcoming
- * try_next_sgbuf().
- */
- buf->sgbuf = NULL;
- }
-
- return buf;
-}
-
-static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf)
-{
- struct scatterlist *sgbuf;
-
- if (likely(buf->sgbuf)) {
- /* current sglist is active */
- if (unlikely(!buf->bytes_left)) {
- /* indicate sglist complete */
- sgbuf = NULL;
- } else {
- /* process next sgbuf */
- sgbuf = sg_next(buf->sgbuf);
- if (WARN_ON(!sgbuf)) {
- buf->result = VIDEOBUF_ERROR;
- } else if (WARN_ON(!sg_dma_len(sgbuf))) {
- sgbuf = NULL;
- buf->result = VIDEOBUF_ERROR;
- }
- }
- buf->sgbuf = sgbuf;
- } else {
- /* sglist is fresh, initialize it before using */
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-
- sgbuf = dma->sglist;
- if (!(WARN_ON(!sgbuf))) {
- buf->sgbuf = sgbuf;
- buf->sgcount = 0;
- buf->bytes_left = buf->vb.size;
- buf->result = VIDEOBUF_DONE;
- }
- }
- if (sgbuf)
- /*
- * Put our next sgbuf parameters (address, size)
- * into the DMA programming register set.
- */
- set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG);
-
- return sgbuf;
-}
-
-static void start_capture(struct omap1_cam_dev *pcdev)
-{
- struct omap1_cam_buf *buf = pcdev->active;
- u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
- u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;
-
- if (WARN_ON(!buf))
- return;
-
- /*
- * Enable start of frame interrupt, which we will use for activating
- * our end of frame watchdog when capture actually starts.
- */
- mode |= EN_V_UP;
-
- if (unlikely(ctrlclock & LCLK_EN))
- /* stop pixel clock before FIFO reset */
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
- /* reset FIFO */
- CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);
-
- omap_start_dma(pcdev->dma_ch);
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
- /*
- * In SG mode, it's a good moment for fetching next sgbuf
- * from the current sglist and, if available, already putting
- * its parameters into the DMA programming register set.
- */
- try_next_sgbuf(pcdev->dma_ch, buf);
- }
-
- /* (re)enable pixel clock */
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
- /* release FIFO reset */
- CAM_WRITE(pcdev, MODE, mode);
-}
-
-static void suspend_capture(struct omap1_cam_dev *pcdev)
-{
- u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
-
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
- omap_stop_dma(pcdev->dma_ch);
-}
-
-static void disable_capture(struct omap1_cam_dev *pcdev)
-{
- u32 mode = CAM_READ_CACHE(pcdev, MODE);
-
- CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
-}
-
-static void omap1_videobuf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
- struct omap1_cam_buf *buf;
- u32 mode;
-
- list_add_tail(&vb->queue, &pcdev->capture);
- vb->state = VIDEOBUF_QUEUED;
-
- if (pcdev->active) {
- /*
- * Capture in progress, so don't touch pcdev->ready even if
- * empty. Since the transfer of the DMA programming register set
- * content to the DMA working register set is done automatically
- * by the DMA hardware, this can pretty well happen while we
- * are keeping the lock here. Leave fetching it from the queue
- * to be done when a next DMA interrupt occures instead.
- */
- return;
- }
-
- WARN_ON(pcdev->ready);
-
- buf = prepare_next_vb(pcdev);
- if (WARN_ON(!buf))
- return;
-
- pcdev->active = buf;
- pcdev->ready = NULL;
-
- dev_dbg(icd->parent,
- "%s: capture not active, setup FIFO, start DMA\n", __func__);
- mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
- mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
- CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
- /*
- * In SG mode, the above prepare_next_vb() didn't actually
- * put anything into the DMA programming register set,
- * so we have to do it now, before activating DMA.
- */
- try_next_sgbuf(pcdev->dma_ch, buf);
- }
-
- start_capture(pcdev);
-}
-
-static void omap1_videobuf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct omap1_cam_buf *buf =
- container_of(vb, struct omap1_cam_buf, vb);
- struct soc_camera_device *icd = vq->priv_data;
- struct device *dev = icd->parent;
- struct soc_camera_host *ici = to_soc_camera_host(dev);
- struct omap1_cam_dev *pcdev = ici->priv;
-
- switch (vb->state) {
- case VIDEOBUF_DONE:
- dev_dbg(dev, "%s (done)\n", __func__);
- break;
- case VIDEOBUF_ACTIVE:
- dev_dbg(dev, "%s (active)\n", __func__);
- break;
- case VIDEOBUF_QUEUED:
- dev_dbg(dev, "%s (queued)\n", __func__);
- break;
- case VIDEOBUF_PREPARED:
- dev_dbg(dev, "%s (prepared)\n", __func__);
- break;
- default:
- dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state);
- break;
- }
-
- free_buffer(vq, buf, pcdev->vb_mode);
-}
-
-static void videobuf_done(struct omap1_cam_dev *pcdev,
- enum videobuf_state result)
-{
- struct omap1_cam_buf *buf = pcdev->active;
- struct videobuf_buffer *vb;
- struct device *dev = pcdev->icd->parent;
-
- if (WARN_ON(!buf)) {
- suspend_capture(pcdev);
- disable_capture(pcdev);
- return;
- }
-
- if (result == VIDEOBUF_ERROR)
- suspend_capture(pcdev);
-
- vb = &buf->vb;
- if (waitqueue_active(&vb->done)) {
- if (!pcdev->ready && result != VIDEOBUF_ERROR) {
- /*
- * No next buffer has been entered into the DMA
- * programming register set on time (could be done only
- * while the previous DMA interurpt was processed, not
- * later), so the last DMA block, be it a whole buffer
- * if in CONTIG or its last sgbuf if in SG mode, is
- * about to be reused by the just autoreinitialized DMA
- * engine, and overwritten with next frame data. Best we
- * can do is stopping the capture as soon as possible,
- * hopefully before the next frame start.
- */
- suspend_capture(pcdev);
- }
- vb->state = result;
- do_gettimeofday(&vb->ts);
- if (result != VIDEOBUF_ERROR)
- vb->field_count++;
- wake_up(&vb->done);
-
- /* shift in next buffer */
- buf = pcdev->ready;
- pcdev->active = buf;
- pcdev->ready = NULL;
-
- if (!buf) {
- /*
- * No next buffer was ready on time (see above), so
- * indicate error condition to force capture restart or
- * stop, depending on next buffer already queued or not.
- */
- result = VIDEOBUF_ERROR;
- prepare_next_vb(pcdev);
-
- buf = pcdev->ready;
- pcdev->active = buf;
- pcdev->ready = NULL;
- }
- } else if (pcdev->ready) {
- /*
- * In both CONTIG and SG mode, the DMA engine has possibly
- * been already autoreinitialized with the preprogrammed
- * pcdev->ready buffer. We can either accept this fact
- * and just swap the buffers, or provoke an error condition
- * and restart capture. The former seems less intrusive.
- */
- dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
- __func__);
- pcdev->active = pcdev->ready;
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
- /*
- * In SG mode, we have to make sure that the buffer we
- * are putting back into the pcdev->ready is marked
- * fresh.
- */
- buf->sgbuf = NULL;
- }
- pcdev->ready = buf;
-
- buf = pcdev->active;
- } else {
- /*
- * No next buffer has been entered into
- * the DMA programming register set on time.
- */
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, the DMA engine has already been
- * reinitialized with the current buffer. Best we can do
- * is not touching it.
- */
- dev_dbg(dev,
- "%s: nobody waiting on videobuf, reuse it\n",
- __func__);
- } else {
- /*
- * In SG mode, the DMA engine has just been
- * autoreinitialized with the last sgbuf from the
- * current list. Restart capture in order to transfer
- * next frame start into the first sgbuf, not the last
- * one.
- */
- if (result != VIDEOBUF_ERROR) {
- suspend_capture(pcdev);
- result = VIDEOBUF_ERROR;
- }
- }
- }
-
- if (!buf) {
- dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
- disable_capture(pcdev);
- return;
- }
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, the current buffer parameters had already
- * been entered into the DMA programming register set while the
- * buffer was fetched with prepare_next_vb(), they may have also
- * been transferred into the runtime set and already active if
- * the DMA still running.
- */
- } else {
- /* In SG mode, extra steps are required */
- if (result == VIDEOBUF_ERROR)
- /* make sure we (re)use sglist from start on error */
- buf->sgbuf = NULL;
-
- /*
- * In any case, enter the next sgbuf parameters into the DMA
- * programming register set. They will be used either during
- * nearest DMA autoreinitialization or, in case of an error,
- * on DMA startup below.
- */
- try_next_sgbuf(pcdev->dma_ch, buf);
- }
-
- if (result == VIDEOBUF_ERROR) {
- dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
- __func__);
- start_capture(pcdev);
- /*
- * In SG mode, the above also resulted in the next sgbuf
- * parameters being entered into the DMA programming register
- * set, making them ready for next DMA autoreinitialization.
- */
- }
-
- /*
- * Finally, try fetching next buffer.
- * In CONTIG mode, it will also enter it into the DMA programming
- * register set, making it ready for next DMA autoreinitialization.
- */
- prepare_next_vb(pcdev);
-}
-
-static void dma_isr(int channel, unsigned short status, void *data)
-{
- struct omap1_cam_dev *pcdev = data;
- struct omap1_cam_buf *buf = pcdev->active;
- unsigned long flags;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- if (WARN_ON(!buf)) {
- suspend_capture(pcdev);
- disable_capture(pcdev);
- goto out;
- }
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, assume we have just managed to collect the
- * whole frame, hopefully before our end of frame watchdog is
- * triggered. Then, all we have to do is disabling the watchdog
- * for this frame, and calling videobuf_done() with success
- * indicated.
- */
- CAM_WRITE(pcdev, MODE,
- CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
- videobuf_done(pcdev, VIDEOBUF_DONE);
- } else {
- /*
- * In SG mode, we have to process every sgbuf from the current
- * sglist, one after another.
- */
- if (buf->sgbuf) {
- /*
- * Current sglist not completed yet, try fetching next
- * sgbuf, hopefully putting it into the DMA programming
- * register set, making it ready for next DMA
- * autoreinitialization.
- */
- try_next_sgbuf(pcdev->dma_ch, buf);
- if (buf->sgbuf)
- goto out;
-
- /*
- * No more sgbufs left in the current sglist. This
- * doesn't mean that the whole videobuffer is already
- * complete, but only that the last sgbuf from the
- * current sglist is about to be filled. It will be
- * ready on next DMA interrupt, signalled with the
- * buf->sgbuf set back to NULL.
- */
- if (buf->result != VIDEOBUF_ERROR) {
- /*
- * Video frame collected without errors so far,
- * we can prepare for collecting a next one
- * as soon as DMA gets autoreinitialized
- * after the current (last) sgbuf is completed.
- */
- buf = prepare_next_vb(pcdev);
- if (!buf)
- goto out;
-
- try_next_sgbuf(pcdev->dma_ch, buf);
- goto out;
- }
- }
- /* end of videobuf */
- videobuf_done(pcdev, buf->result);
- }
-
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static irqreturn_t cam_isr(int irq, void *data)
-{
- struct omap1_cam_dev *pcdev = data;
- struct device *dev = pcdev->icd->parent;
- struct omap1_cam_buf *buf = pcdev->active;
- u32 it_status;
- unsigned long flags;
-
- it_status = CAM_READ(pcdev, IT_STATUS);
- if (!it_status)
- return IRQ_NONE;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- if (WARN_ON(!buf)) {
- dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
- __func__, it_status);
- suspend_capture(pcdev);
- disable_capture(pcdev);
- goto out;
- }
-
- if (unlikely(it_status & FIFO_FULL)) {
- dev_warn(dev, "%s: FIFO overflow\n", __func__);
-
- } else if (it_status & V_DOWN) {
- /* end of video frame watchdog */
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, the watchdog is disabled with
- * successful DMA end of block interrupt, and reenabled
- * on next frame start. If we get here, there is nothing
- * to check, we must be out of sync.
- */
- } else {
- if (buf->sgcount == 2) {
- /*
- * If exactly 2 sgbufs from the next sglist have
- * been programmed into the DMA engine (the
- * first one already transferred into the DMA
- * runtime register set, the second one still
- * in the programming set), then we are in sync.
- */
- goto out;
- }
- }
- dev_notice(dev, "%s: unexpected end of video frame\n",
- __func__);
-
- } else if (it_status & V_UP) {
- u32 mode;
-
- if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
- /*
- * In CONTIG mode, we need this interrupt every frame
- * in oredr to reenable our end of frame watchdog.
- */
- mode = CAM_READ_CACHE(pcdev, MODE);
- } else {
- /*
- * In SG mode, the below enabled end of frame watchdog
- * is kept on permanently, so we can turn this one shot
- * setup off.
- */
- mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
- }
-
- if (!(mode & EN_V_DOWN)) {
- /* (re)enable end of frame watchdog interrupt */
- mode |= EN_V_DOWN;
- }
- CAM_WRITE(pcdev, MODE, mode);
- goto out;
-
- } else {
- dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
- __func__, it_status);
- goto out;
- }
-
- videobuf_done(pcdev, VIDEOBUF_ERROR);
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
- return IRQ_HANDLED;
-}
-
-static struct videobuf_queue_ops omap1_videobuf_ops = {
- .buf_setup = omap1_videobuf_setup,
- .buf_prepare = omap1_videobuf_prepare,
- .buf_queue = omap1_videobuf_queue,
- .buf_release = omap1_videobuf_release,
-};
-
-
-/*
- * SOC Camera host operations
- */
-
-static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
-{
- /* apply/release camera sensor reset if requested by platform data */
- if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH)
- CAM_WRITE(pcdev, GPIO, reset);
- else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW)
- CAM_WRITE(pcdev, GPIO, !reset);
-}
-
-/*
- * The following two functions absolutely depend on the fact, that
- * there can be only one camera on OMAP1 camera sensor interface
- */
-static int omap1_cam_add_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
- u32 ctrlclock;
-
- if (pcdev->icd)
- return -EBUSY;
-
- clk_enable(pcdev->clk);
-
- /* setup sensor clock */
- ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
- ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
-
- ctrlclock &= ~FOSCMOD_MASK;
- switch (pcdev->camexclk) {
- case 6000000:
- ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
- break;
- case 8000000:
- ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
- break;
- case 9600000:
- ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
- break;
- case 12000000:
- ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
- break;
- case 24000000:
- ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
- default:
- break;
- }
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);
-
- /* enable internal clock */
- ctrlclock |= MCLK_EN;
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
-
- sensor_reset(pcdev, false);
-
- pcdev->icd = icd;
-
- dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
- icd->devnum);
- return 0;
-}
-
-static void omap1_cam_remove_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
- u32 ctrlclock;
-
- BUG_ON(icd != pcdev->icd);
-
- suspend_capture(pcdev);
- disable_capture(pcdev);
-
- sensor_reset(pcdev, true);
-
- /* disable and release system clocks */
- ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
- ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
-
- ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);
-
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
-
- clk_disable(pcdev->clk);
-
- pcdev->icd = NULL;
-
- dev_dbg(icd->parent,
- "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
-}
-
-/* Duplicate standard formats based on host capability of byte swapping */
-static const struct soc_mbus_lookup omap1_cam_formats[] = {
-{
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .name = "YUYV",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_YVYU,
- .name = "YVYU",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .name = "UYVY",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_VYUY,
- .name = "VYUY",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_RGB555,
- .name = "RGB555",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_RGB555X,
- .name = "RGB555X",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_RGB565,
- .name = "RGB565",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_RGB565X,
- .name = "RGB565X",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
- .layout = SOC_MBUS_LAYOUT_PACKED,
- },
-},
-};
-
-static int omap1_cam_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);
- struct device *dev = icd->parent;
- int formats = 0, ret;
- enum v4l2_mbus_pixelcode code;
- const struct soc_mbus_pixelfmt *fmt;
-
- 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_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
- idx, code);
- return 0;
- }
-
- /* Check support for the requested bits-per-sample */
- if (fmt->bits_per_sample != 8)
- return 0;
-
- switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- formats++;
- if (xlate) {
- xlate->host_fmt = soc_mbus_find_fmtdesc(code,
- omap1_cam_formats,
- ARRAY_SIZE(omap1_cam_formats));
- xlate->code = code;
- xlate++;
- dev_dbg(dev,
- "%s: providing format %s as byte swapped code #%d\n",
- __func__, xlate->host_fmt->name, code);
- }
- default:
- if (xlate)
- dev_dbg(dev,
- "%s: providing format %s in pass-through mode\n",
- __func__, fmt->name);
- }
- formats++;
- if (xlate) {
- xlate->host_fmt = fmt;
- xlate->code = code;
- xlate++;
- }
-
- return formats;
-}
-
-static bool is_dma_aligned(s32 bytes_per_line, unsigned int height,
- enum omap1_cam_vb_mode vb_mode)
-{
- int size = bytes_per_line * height;
-
- return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) &&
- IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE);
-}
-
-static int dma_align(int *width, int *height,
- const struct soc_mbus_pixelfmt *fmt,
- enum omap1_cam_vb_mode vb_mode, bool enlarge)
-{
- s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) {
- unsigned int pxalign = __fls(bytes_per_line / *width);
- unsigned int salign = DMA_FRAME_SHIFT(vb_mode) +
- DMA_ELEMENT_SHIFT - pxalign;
- unsigned int incr = enlarge << salign;
-
- v4l_bound_align_image(width, 1, *width + incr, 0,
- height, 1, *height + incr, 0, salign);
- return 0;
- }
- return 1;
-}
-
-#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \
-({ \
- struct soc_camera_sense sense = { \
- .master_clock = pcdev->camexclk, \
- .pixel_clock_max = 0, \
- }; \
- int __ret; \
- \
- if (pcdev->pdata) \
- sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \
- icd->sense = &sense; \
- __ret = v4l2_subdev_call(sd, video, function, ##args); \
- icd->sense = NULL; \
- \
- if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \
- if (sense.pixel_clock > sense.pixel_clock_max) { \
- dev_err(dev, \
- "%s: pixel clock %lu set by the camera too high!\n", \
- __func__, sense.pixel_clock); \
- __ret = -EINVAL; \
- } \
- } \
- __ret; \
-})
-
-static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
- struct soc_camera_device *icd, struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf,
- const struct soc_camera_format_xlate *xlate)
-{
- s32 bytes_per_line;
- int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf);
-
- if (ret < 0) {
- dev_err(dev, "%s: s_mbus_fmt failed\n", __func__);
- return ret;
- }
-
- if (mf->code != xlate->code) {
- dev_err(dev, "%s: unexpected pixel code change\n", __func__);
- return -EINVAL;
- }
-
- bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt);
- if (bytes_per_line < 0) {
- dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n",
- __func__);
- return bytes_per_line;
- }
-
- if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) {
- dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n",
- __func__, mf->width, mf->height);
- return -EINVAL;
- }
- return 0;
-}
-
-static int omap1_cam_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *crop)
-{
- struct v4l2_rect *rect = &crop->c;
- const struct soc_camera_format_xlate *xlate = icd->current_fmt;
- 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;
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop);
- if (ret < 0) {
- dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__,
- rect->width, rect->height, rect->left, rect->top);
- return ret;
- }
-
- ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
- if (ret < 0) {
- dev_warn(dev, "%s: failed to fetch current format\n", __func__);
- return ret;
- }
-
- ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
- false);
- if (ret < 0) {
- dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
- __func__, mf.width, mf.height,
- xlate->host_fmt->name);
- return ret;
- }
-
- if (!ret) {
- /* sensor returned geometry not DMA aligned, trying to fix */
- ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
- if (ret < 0) {
- dev_err(dev, "%s: failed to set format\n", __func__);
- return ret;
- }
- }
-
- icd->user_width = mf.width;
- icd->user_height = mf.height;
-
- return 0;
-}
-
-static int omap1_cam_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate;
- struct device *dev = icd->parent;
- struct soc_camera_host *ici = to_soc_camera_host(dev);
- struct omap1_cam_dev *pcdev = ici->priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(dev, "%s: format %#x not found\n", __func__,
- pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
- true);
- if (ret < 0) {
- dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
- __func__, pix->width, pix->height,
- xlate->host_fmt->name);
- return ret;
- }
-
- ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
- if (ret < 0) {
- dev_err(dev, "%s: failed to set format\n", __func__);
- return ret;
- }
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- pix->colorspace = mf.colorspace;
- icd->current_fmt = xlate;
-
- return 0;
-}
-
-static int omap1_cam_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- 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;
- /* TODO: limit to mx1 hardware capabilities */
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(icd->parent, "Format %#x not found\n",
- pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- /* limit to sensor capabilities */
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- pix->colorspace = mf.colorspace;
-
- return 0;
-}
-
-static bool sg_mode;
-
-/*
- * Local mmap_mapper wrapper,
- * used for detecting videobuf-dma-contig buffer allocation failures
- * and switching to videobuf-dma-sg automatically for future attempts.
- */
-static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
- struct videobuf_buffer *buf,
- struct vm_area_struct *vma)
-{
- struct soc_camera_device *icd = q->priv_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
- int ret;
-
- ret = pcdev->mmap_mapper(q, buf, vma);
-
- if (ret == -ENOMEM)
- sg_mode = true;
-
- return ret;
-}
-
-static void omap1_cam_init_videobuf(struct videobuf_queue *q,
- struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct omap1_cam_dev *pcdev = ici->priv;
-
- if (!sg_mode)
- videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
- icd->parent, &pcdev->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
- else
- videobuf_queue_sg_init(q, &omap1_videobuf_ops,
- icd->parent, &pcdev->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
-
- /* use videobuf mode (auto)selected with the module parameter */
- pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
-
- /*
- * Ensure we substitute the videobuf-dma-contig version of the
- * mmap_mapper() callback with our own wrapper, used for switching
- * automatically to videobuf-dma-sg on buffer allocation failure.
- */
- if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) {
- pcdev->mmap_mapper = q->int_ops->mmap_mapper;
- q->int_ops->mmap_mapper = omap1_cam_mmap_mapper;
- }
-}
-
-static int omap1_cam_reqbufs(struct soc_camera_device *icd,
- struct v4l2_requestbuffers *p)
-{
- int i;
-
- /*
- * This is for locking debugging only. I removed spinlocks and now I
- * check whether .prepare is ever called on a linked buffer, or whether
- * a dma IRQ can occur for an in-work or unlinked buffer. Until now
- * it hadn't triggered
- */
- for (i = 0; i < p->count; i++) {
- struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
- struct omap1_cam_buf, vb);
- buf->inwork = 0;
- INIT_LIST_HEAD(&buf->vb.queue);
- }
-
- return 0;
-}
-
-static int omap1_cam_querycap(struct soc_camera_host *ici,
- struct v4l2_capability *cap)
-{
- /* cap->name is set by the friendly caller:-> */
- strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-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,};
- unsigned long common_flags;
- u32 ctrlclock, mode;
- int ret;
-
- ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS);
- if (!common_flags) {
- dev_warn(dev,
- "Flags incompatible: camera 0x%x, host 0x%x\n",
- cfg.flags, SOCAM_BUS_FLAGS);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = SOCAM_BUS_FLAGS;
- }
-
- /* Make choices, possibly based on platform configuration */
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (!pcdev->pdata ||
- pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- }
-
- cfg.flags = common_flags;
- ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
- if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
- return ret;
- }
-
- ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
- if (ctrlclock & LCLK_EN)
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
-
- if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) {
- dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
- ctrlclock |= POLCLK;
- } else {
- dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
- ctrlclock &= ~POLCLK;
- }
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
-
- if (ctrlclock & LCLK_EN)
- CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
-
- /* select bus endianess */
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- fmt = xlate->host_fmt;
-
- mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
- if (fmt->order == SOC_MBUS_ORDER_LE) {
- dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
- CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
- } else {
- dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
- CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
- }
-
- return 0;
-}
-
-static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
- struct omap1_cam_buf *buf;
-
- buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
- vb.stream);
-
- poll_wait(file, &buf->vb.done, pt);
-
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static struct soc_camera_host_ops omap1_host_ops = {
- .owner = THIS_MODULE,
- .add = omap1_cam_add_device,
- .remove = omap1_cam_remove_device,
- .get_formats = omap1_cam_get_formats,
- .set_crop = omap1_cam_set_crop,
- .set_fmt = omap1_cam_set_fmt,
- .try_fmt = omap1_cam_try_fmt,
- .init_videobuf = omap1_cam_init_videobuf,
- .reqbufs = omap1_cam_reqbufs,
- .querycap = omap1_cam_querycap,
- .set_bus_param = omap1_cam_set_bus_param,
- .poll = omap1_cam_poll,
-};
-
-static int __init omap1_cam_probe(struct platform_device *pdev)
-{
- struct omap1_cam_dev *pcdev;
- struct resource *res;
- struct clk *clk;
- void __iomem *base;
- unsigned int irq;
- int err = 0;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
- err = -ENODEV;
- goto exit;
- }
-
- clk = clk_get(&pdev->dev, "armper_ck");
- if (IS_ERR(clk)) {
- err = PTR_ERR(clk);
- goto exit;
- }
-
- pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL);
- if (!pcdev) {
- dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit_put_clk;
- }
-
- pcdev->res = res;
- pcdev->clk = clk;
-
- pcdev->pdata = pdev->dev.platform_data;
- if (pcdev->pdata) {
- pcdev->pflags = pcdev->pdata->flags;
- pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
- }
-
- switch (pcdev->camexclk) {
- case 6000000:
- case 8000000:
- case 9600000:
- case 12000000:
- case 24000000:
- break;
- default:
- /* pcdev->camexclk != 0 => pcdev->pdata != NULL */
- dev_warn(&pdev->dev,
- "Incorrect sensor clock frequency %ld kHz, "
- "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
- "please correct your platform data\n",
- pcdev->pdata->camexclk_khz);
- pcdev->camexclk = 0;
- case 0:
- dev_info(&pdev->dev, "Not providing sensor clock\n");
- }
-
- INIT_LIST_HEAD(&pcdev->capture);
- spin_lock_init(&pcdev->lock);
-
- /*
- * Request the region.
- */
- if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
- err = -EBUSY;
- goto exit_kfree;
- }
-
- base = ioremap(res->start, resource_size(res));
- if (!base) {
- err = -ENOMEM;
- goto exit_release;
- }
- pcdev->irq = irq;
- pcdev->base = base;
-
- sensor_reset(pcdev, true);
-
- err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME,
- dma_isr, (void *)pcdev, &pcdev->dma_ch);
- if (err < 0) {
- dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n");
- err = -EBUSY;
- goto exit_iounmap;
- }
- dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch);
-
- /* preconfigure DMA */
- omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA,
- 0, 0);
- omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4);
- /* setup DMA autoinitialization */
- omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch);
-
- err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev);
- if (err) {
- dev_err(&pdev->dev, "Camera interrupt register failed\n");
- goto exit_free_dma;
- }
-
- pcdev->soc_host.drv_name = DRIVER_NAME;
- pcdev->soc_host.ops = &omap1_host_ops;
- pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
- pcdev->soc_host.nr = pdev->id;
-
- err = soc_camera_host_register(&pcdev->soc_host);
- if (err)
- goto exit_free_irq;
-
- dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n");
-
- return 0;
-
-exit_free_irq:
- free_irq(pcdev->irq, pcdev);
-exit_free_dma:
- omap_free_dma(pcdev->dma_ch);
-exit_iounmap:
- iounmap(base);
-exit_release:
- release_mem_region(res->start, resource_size(res));
-exit_kfree:
- kfree(pcdev);
-exit_put_clk:
- clk_put(clk);
-exit:
- return err;
-}
-
-static int __exit omap1_cam_remove(struct platform_device *pdev)
-{
- struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
- struct omap1_cam_dev *pcdev = container_of(soc_host,
- struct omap1_cam_dev, soc_host);
- struct resource *res;
-
- free_irq(pcdev->irq, pcdev);
-
- omap_free_dma(pcdev->dma_ch);
-
- soc_camera_host_unregister(soc_host);
-
- iounmap(pcdev->base);
-
- res = pcdev->res;
- release_mem_region(res->start, resource_size(res));
-
- clk_put(pcdev->clk);
-
- kfree(pcdev);
-
- dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
-
- return 0;
-}
-
-static struct platform_driver omap1_cam_driver = {
- .driver = {
- .name = DRIVER_NAME,
- },
- .probe = omap1_cam_probe,
- .remove = __exit_p(omap1_cam_remove),
-};
-
-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");
-
-MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
-MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/video/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c
deleted file mode 100644
index b5ae170de4a5..000000000000
--- a/drivers/media/video/omap24xxcam-dma.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * drivers/media/video/omap24xxcam-dma.c
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.com> and
- * David Cohen <david.cohen@indt.org.br>.
- *
- * 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/kernel.h>
-#include <linux/io.h>
-#include <linux/scatterlist.h>
-
-#include "omap24xxcam.h"
-
-/*
- *
- * DMA hardware.
- *
- */
-
-/* Ack all interrupt on CSR and IRQSTATUS_L0 */
-static void omap24xxcam_dmahw_ack_all(void __iomem *base)
-{
- u32 csr;
- int i;
-
- for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
- csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
- /* ack interrupt in CSR */
- omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
- }
- omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
-}
-
-/* Ack dmach on CSR and IRQSTATUS_L0 */
-static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
-{
- u32 csr;
-
- csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
- /* ack interrupt in CSR */
- omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
- /* ack interrupt in IRQSTATUS */
- omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
-
- return csr;
-}
-
-static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
-{
- return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
-}
-
-static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
- dma_addr_t start, u32 len)
-{
- omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
- CAMDMA_CCR_SEL_SRC_DST_SYNC
- | CAMDMA_CCR_BS
- | CAMDMA_CCR_DST_AMODE_POST_INC
- | CAMDMA_CCR_SRC_AMODE_POST_INC
- | CAMDMA_CCR_FS
- | CAMDMA_CCR_WR_ACTIVE
- | CAMDMA_CCR_RD_ACTIVE
- | CAMDMA_CCR_SYNCHRO_CAMERA);
- omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
- omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
- omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
- CAMDMA_CSDP_WRITE_MODE_POSTED
- | CAMDMA_CSDP_DST_BURST_EN_32
- | CAMDMA_CSDP_DST_PACKED
- | CAMDMA_CSDP_SRC_BURST_EN_32
- | CAMDMA_CSDP_SRC_PACKED
- | CAMDMA_CSDP_DATA_TYPE_8BITS);
- omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
- omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
- omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
- CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR
- | CAMDMA_CSR_BLOCK
- | CAMDMA_CSR_DROP);
- omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
- CAMDMA_CICR_MISALIGNED_ERR_IE
- | CAMDMA_CICR_SECURE_ERR_IE
- | CAMDMA_CICR_TRANS_ERR_IE
- | CAMDMA_CICR_BLOCK_IE
- | CAMDMA_CICR_DROP_IE);
-}
-
-static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
-{
- omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
- CAMDMA_CCR_SEL_SRC_DST_SYNC
- | CAMDMA_CCR_BS
- | CAMDMA_CCR_DST_AMODE_POST_INC
- | CAMDMA_CCR_SRC_AMODE_POST_INC
- | CAMDMA_CCR_ENABLE
- | CAMDMA_CCR_FS
- | CAMDMA_CCR_SYNCHRO_CAMERA);
-}
-
-static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
- int free_dmach)
-{
- int prev_dmach, ch;
-
- if (dmach == 0)
- prev_dmach = NUM_CAMDMA_CHANNELS - 1;
- else
- prev_dmach = dmach - 1;
- omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
- CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
- /* Did we chain the DMA transfer before the previous one
- * finished?
- */
- ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
- while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
- & CAMDMA_CCR_ENABLE)) {
- if (ch == dmach) {
- /* The previous transfer has ended and this one
- * hasn't started, so we must not have chained
- * to the previous one in time. We'll have to
- * start it now.
- */
- omap24xxcam_dmahw_transfer_start(base, dmach);
- break;
- } else
- ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
- }
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. The DMA
- * controller may not be idle after this routine completes, because
- * the completion routines might start new transfers.
- */
-static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
-{
- /* mask all interrupts from this channel */
- omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
- /* unlink this channel */
- omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
- CAMDMA_CLNK_CTRL_ENABLE_LNK);
- /* disable this channel */
- omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
-}
-
-static void omap24xxcam_dmahw_init(void __iomem *base)
-{
- omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
- CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
- | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
- | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
-
- omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
- CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
-
- omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
-}
-
-/*
- *
- * Individual DMA channel handling.
- *
- */
-
-/* Start a DMA transfer from the camera to memory.
- * Returns zero if the transfer was successfully started, or non-zero if all
- * DMA channels are already in use or starting is currently inhibited.
- */
-static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
- u32 len, dma_callback_t callback, void *arg)
-{
- unsigned long flags;
- int dmach;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
- spin_unlock_irqrestore(&dma->lock, flags);
- return -EBUSY;
- }
-
- dmach = dma->next_dmach;
-
- dma->ch_state[dmach].callback = callback;
- dma->ch_state[dmach].arg = arg;
-
- omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
-
- /* We're ready to start the DMA transfer. */
-
- if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
- /* A transfer is already in progress, so try to chain to it. */
- omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
- dma->free_dmach);
- } else {
- /* No transfer is in progress, so we'll just start this one
- * now.
- */
- omap24xxcam_dmahw_transfer_start(dma->base, dmach);
- }
-
- dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
- dma->free_dmach--;
-
- spin_unlock_irqrestore(&dma->lock, flags);
-
- return 0;
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. The DMA
- * controller may not be idle after this routine completes, because
- * the completion routines might start new transfers.
- */
-static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
-{
- unsigned long flags;
- int dmach, i, free_dmach;
- dma_callback_t callback;
- void *arg;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- /* stop any DMA transfers in progress */
- dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
- for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
- omap24xxcam_dmahw_abort_ch(dma->base, dmach);
- dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
- }
-
- /* We have to be careful here because the callback routine
- * might start a new DMA transfer, and we only want to abort
- * transfers that were started before this routine was called.
- */
- free_dmach = dma->free_dmach;
- while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
- (free_dmach < NUM_CAMDMA_CHANNELS)) {
- dmach = (dma->next_dmach + dma->free_dmach)
- % NUM_CAMDMA_CHANNELS;
- callback = dma->ch_state[dmach].callback;
- arg = dma->ch_state[dmach].arg;
- dma->free_dmach++;
- free_dmach++;
- if (callback) {
- /* leave interrupts disabled during callback */
- spin_unlock(&dma->lock);
- (*callback) (dma, csr, arg);
- spin_lock(&dma->lock);
- }
- }
-
- spin_unlock_irqrestore(&dma->lock, flags);
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. If the completion
- * routines attempt to start a new DMA transfer it will fail, so the
- * DMA controller will be idle after this routine completes.
- */
-static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
-{
- atomic_inc(&dma->dma_stop);
- omap24xxcam_dma_abort(dma, csr);
- atomic_dec(&dma->dma_stop);
-}
-
-/* Camera DMA interrupt service routine. */
-void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
-{
- int dmach;
- dma_callback_t callback;
- void *arg;
- u32 csr;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock(&dma->lock);
-
- if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
- /* A camera DMA interrupt occurred while all channels
- * are idle, so we'll acknowledge the interrupt in the
- * IRQSTATUS register and exit.
- */
- omap24xxcam_dmahw_ack_all(dma->base);
- spin_unlock(&dma->lock);
- return;
- }
-
- while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
- dmach = (dma->next_dmach + dma->free_dmach)
- % NUM_CAMDMA_CHANNELS;
- if (omap24xxcam_dmahw_running(dma->base, dmach)) {
- /* This buffer hasn't finished yet, so we're done. */
- break;
- }
- csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
- if (csr & csr_error) {
- /* A DMA error occurred, so stop all DMA
- * transfers in progress.
- */
- spin_unlock(&dma->lock);
- omap24xxcam_dma_stop(dma, csr);
- return;
- } else {
- callback = dma->ch_state[dmach].callback;
- arg = dma->ch_state[dmach].arg;
- dma->free_dmach++;
- if (callback) {
- spin_unlock(&dma->lock);
- (*callback) (dma, csr, arg);
- spin_lock(&dma->lock);
- }
- }
- }
-
- spin_unlock(&dma->lock);
-
- omap24xxcam_sgdma_process(
- container_of(dma, struct omap24xxcam_sgdma, dma));
-}
-
-void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- omap24xxcam_dmahw_init(dma->base);
-
- spin_unlock_irqrestore(&dma->lock, flags);
-}
-
-static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
- void __iomem *base)
-{
- int ch;
-
- /* group all channels on DMA IRQ0 and unmask irq */
- spin_lock_init(&dma->lock);
- dma->base = base;
- dma->free_dmach = NUM_CAMDMA_CHANNELS;
- dma->next_dmach = 0;
- for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
- dma->ch_state[ch].callback = NULL;
- dma->ch_state[ch].arg = NULL;
- }
-}
-
-/*
- *
- * Scatter-gather DMA.
- *
- * High-level DMA construct for transferring whole picture frames to
- * memory that is discontinuous.
- *
- */
-
-/* DMA completion routine for the scatter-gather DMA fragments. */
-static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
- void *arg)
-{
- struct omap24xxcam_sgdma *sgdma =
- container_of(dma, struct omap24xxcam_sgdma, dma);
- int sgslot = (int)arg;
- struct sgdma_state *sg_state;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock(&sgdma->lock);
-
- /* We got an interrupt, we can remove the timer */
- del_timer(&sgdma->reset_timer);
-
- sg_state = sgdma->sg_state + sgslot;
- if (!sg_state->queued_sglist) {
- spin_unlock(&sgdma->lock);
- printk(KERN_ERR "%s: sgdma completed when none queued!\n",
- __func__);
- return;
- }
-
- sg_state->csr |= csr;
- if (!--sg_state->queued_sglist) {
- /* Queue for this sglist is empty, so check to see if we're
- * done.
- */
- if ((sg_state->next_sglist == sg_state->sglen)
- || (sg_state->csr & csr_error)) {
- sgdma_callback_t callback = sg_state->callback;
- void *arg = sg_state->arg;
- u32 sg_csr = sg_state->csr;
- /* All done with this sglist */
- sgdma->free_sgdma++;
- if (callback) {
- spin_unlock(&sgdma->lock);
- (*callback) (sgdma, sg_csr, arg);
- return;
- }
- }
- }
-
- spin_unlock(&sgdma->lock);
-}
-
-/* Start queued scatter-gather DMA transfers. */
-void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
-{
- unsigned long flags;
- int queued_sgdma, sgslot;
- struct sgdma_state *sg_state;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
- sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
- while (queued_sgdma > 0) {
- sg_state = sgdma->sg_state + sgslot;
- while ((sg_state->next_sglist < sg_state->sglen) &&
- !(sg_state->csr & csr_error)) {
- const struct scatterlist *sglist;
- unsigned int len;
-
- sglist = sg_state->sglist + sg_state->next_sglist;
- /* try to start the next DMA transfer */
- if (sg_state->next_sglist + 1 == sg_state->sglen) {
- /*
- * On the last sg, we handle the case where
- * cam->img.pix.sizeimage % PAGE_ALIGN != 0
- */
- len = sg_state->len - sg_state->bytes_read;
- } else {
- len = sg_dma_len(sglist);
- }
-
- if (omap24xxcam_dma_start(&sgdma->dma,
- sg_dma_address(sglist),
- len,
- omap24xxcam_sgdma_callback,
- (void *)sgslot)) {
- /* DMA start failed */
- spin_unlock_irqrestore(&sgdma->lock, flags);
- return;
- } else {
- unsigned long expires;
- /* DMA start was successful */
- sg_state->next_sglist++;
- sg_state->bytes_read += len;
- sg_state->queued_sglist++;
-
- /* We start the reset timer */
- expires = jiffies + HZ;
- mod_timer(&sgdma->reset_timer, expires);
- }
- }
- queued_sgdma--;
- sgslot = (sgslot + 1) % NUM_SG_DMA;
- }
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-}
-
-/*
- * Queue a scatter-gather DMA transfer from the camera to memory.
- * Returns zero if the transfer was successfully queued, or non-zero
- * if all of the scatter-gather slots are already in use.
- */
-int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
- const struct scatterlist *sglist, int sglen,
- int len, sgdma_callback_t callback, void *arg)
-{
- unsigned long flags;
- struct sgdma_state *sg_state;
-
- if ((sglen < 0) || ((sglen > 0) && !sglist))
- return -EINVAL;
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- if (!sgdma->free_sgdma) {
- spin_unlock_irqrestore(&sgdma->lock, flags);
- return -EBUSY;
- }
-
- sg_state = sgdma->sg_state + sgdma->next_sgdma;
-
- sg_state->sglist = sglist;
- sg_state->sglen = sglen;
- sg_state->next_sglist = 0;
- sg_state->bytes_read = 0;
- sg_state->len = len;
- sg_state->queued_sglist = 0;
- sg_state->csr = 0;
- sg_state->callback = callback;
- sg_state->arg = arg;
-
- sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
- sgdma->free_sgdma--;
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-
- omap24xxcam_sgdma_process(sgdma);
-
- return 0;
-}
-
-/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
- * Any queued scatter-gather DMA transactions that have not yet been started
- * will remain queued. The DMA controller will be idle after this routine
- * completes. When the scatter-gather queue is restarted, the next
- * scatter-gather DMA transfer will begin at the start of a new transaction.
- */
-void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
-{
- unsigned long flags;
- int sgslot;
- struct sgdma_state *sg_state;
- u32 csr = CAMDMA_CSR_TRANS_ERR;
-
- /* stop any DMA transfers in progress */
- omap24xxcam_dma_stop(&sgdma->dma, csr);
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- if (sgdma->free_sgdma < NUM_SG_DMA) {
- sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
- sg_state = sgdma->sg_state + sgslot;
- if (sg_state->next_sglist != 0) {
- /* This DMA transfer was in progress, so abort it. */
- sgdma_callback_t callback = sg_state->callback;
- void *arg = sg_state->arg;
- sgdma->free_sgdma++;
- if (callback) {
- /* leave interrupts masked */
- spin_unlock(&sgdma->lock);
- (*callback) (sgdma, csr, arg);
- spin_lock(&sgdma->lock);
- }
- }
- }
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-}
-
-void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- void __iomem *base,
- void (*reset_callback)(unsigned long data),
- unsigned long reset_callback_data)
-{
- int sg;
-
- spin_lock_init(&sgdma->lock);
- sgdma->free_sgdma = NUM_SG_DMA;
- sgdma->next_sgdma = 0;
- for (sg = 0; sg < NUM_SG_DMA; sg++) {
- sgdma->sg_state[sg].sglen = 0;
- sgdma->sg_state[sg].next_sglist = 0;
- sgdma->sg_state[sg].bytes_read = 0;
- sgdma->sg_state[sg].queued_sglist = 0;
- sgdma->sg_state[sg].csr = 0;
- sgdma->sg_state[sg].callback = NULL;
- sgdma->sg_state[sg].arg = NULL;
- }
-
- omap24xxcam_dma_init(&sgdma->dma, base);
- setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
-}
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
deleted file mode 100644
index e5015b0d5508..000000000000
--- a/drivers/media/video/omap24xxcam.c
+++ /dev/null
@@ -1,1881 +0,0 @@
-/*
- * drivers/media/video/omap24xxcam.c
- *
- * OMAP 2 camera block driver.
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007-2008 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.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/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/videodev2.h>
-#include <linux/pci.h> /* needed for videobufs */
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "omap24xxcam.h"
-
-#define OMAP24XXCAM_VERSION "0.0.1"
-
-#define RESET_TIMEOUT_NS 10000
-
-static void omap24xxcam_reset(struct omap24xxcam_device *cam);
-static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
-static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
-static int omap24xxcam_remove(struct platform_device *pdev);
-
-/* module parameters */
-static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
-/*
- * Maximum amount of memory to use for capture buffers.
- * Default is 4800KB, enough to double-buffer SXGA.
- */
-static int capture_mem = 1280 * 960 * 2 * 2;
-
-static struct v4l2_int_device omap24xxcam;
-
-/*
- *
- * Clocks.
- *
- */
-
-static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
-{
- if (cam->ick != NULL && !IS_ERR(cam->ick))
- clk_put(cam->ick);
- if (cam->fck != NULL && !IS_ERR(cam->fck))
- clk_put(cam->fck);
-
- cam->ick = cam->fck = NULL;
-}
-
-static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
-{
- int rval = 0;
-
- cam->fck = clk_get(cam->dev, "fck");
- if (IS_ERR(cam->fck)) {
- dev_err(cam->dev, "can't get camera fck");
- rval = PTR_ERR(cam->fck);
- omap24xxcam_clock_put(cam);
- return rval;
- }
-
- cam->ick = clk_get(cam->dev, "ick");
- if (IS_ERR(cam->ick)) {
- dev_err(cam->dev, "can't get camera ick");
- rval = PTR_ERR(cam->ick);
- omap24xxcam_clock_put(cam);
- }
-
- return rval;
-}
-
-static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
-{
- clk_enable(cam->fck);
- clk_enable(cam->ick);
-}
-
-static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
-{
- clk_disable(cam->fck);
- clk_disable(cam->ick);
-}
-
-/*
- *
- * Camera core
- *
- */
-
-/*
- * Set xclk.
- *
- * To disable xclk, use value zero.
- */
-static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
- u32 xclk)
-{
- if (xclk) {
- u32 divisor = CAM_MCLK / xclk;
-
- if (divisor == 1)
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK,
- CC_CTRL_XCLK_DIV_BYPASS);
- else
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK, divisor);
- } else
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
-}
-
-static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
-{
- /*
- * Setting the camera core AUTOIDLE bit causes problems with frame
- * synchronization, so we will clear the AUTOIDLE bit instead.
- */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
- CC_SYSCONFIG_AUTOIDLE);
-
- /* program the camera interface DMA packet size */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
- CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
-
- /* enable camera core error interrupts */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
- CC_IRQENABLE_FW_ERR_IRQ
- | CC_IRQENABLE_FSC_ERR_IRQ
- | CC_IRQENABLE_SSC_ERR_IRQ
- | CC_IRQENABLE_FIFO_OF_IRQ);
-}
-
-/*
- * Enable the camera core.
- *
- * Data transfer to the camera DMA starts from next starting frame.
- */
-static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
-{
-
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
- cam->cc_ctrl);
-}
-
-/*
- * Disable camera core.
- *
- * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
- * core internal state machines will be reset. Use
- * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
- * frame completely.
- */
-static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
-{
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
- CC_CTRL_CC_RST);
-}
-
-/* Interrupt service routine for camera core interrupts. */
-static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
-{
- u32 cc_irqstatus;
- const u32 cc_irqstatus_err =
- CC_IRQSTATUS_FW_ERR_IRQ
- | CC_IRQSTATUS_FSC_ERR_IRQ
- | CC_IRQSTATUS_SSC_ERR_IRQ
- | CC_IRQSTATUS_FIFO_UF_IRQ
- | CC_IRQSTATUS_FIFO_OF_IRQ;
-
- cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
- CC_IRQSTATUS);
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
- cc_irqstatus);
-
- if (cc_irqstatus & cc_irqstatus_err
- && !atomic_read(&cam->in_reset)) {
- dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
- cc_irqstatus);
- omap24xxcam_reset(cam);
- }
-}
-
-/*
- *
- * videobuf_buffer handling.
- *
- * Memory for mmapped videobuf_buffers is not allocated
- * conventionally, but by several kmalloc allocations and then
- * creating the scatterlist on our own. User-space buffers are handled
- * normally.
- *
- */
-
-/*
- * Free the memory-mapped buffer memory allocated for a
- * videobuf_buffer and the associated scatterlist.
- */
-static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- size_t alloc_size;
- struct page *page;
- int i;
-
- if (dma->sglist == NULL)
- return;
-
- i = dma->sglen;
- while (i) {
- i--;
- alloc_size = sg_dma_len(&dma->sglist[i]);
- page = sg_page(&dma->sglist[i]);
- do {
- ClearPageReserved(page++);
- } while (alloc_size -= PAGE_SIZE);
- __free_pages(sg_page(&dma->sglist[i]),
- get_order(sg_dma_len(&dma->sglist[i])));
- }
-
- kfree(dma->sglist);
- dma->sglist = NULL;
-}
-
-/* Release all memory related to the videobuf_queue. */
-static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
-{
- int i;
-
- mutex_lock(&vbq->vb_lock);
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == vbq->bufs[i])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
- continue;
- vbq->ops->buf_release(vbq, vbq->bufs[i]);
- omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
- kfree(vbq->bufs[i]);
- vbq->bufs[i] = NULL;
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- videobuf_mmap_free(vbq);
-}
-
-/*
- * Allocate physically as contiguous as possible buffer for video
- * frame and allocate and build DMA scatter-gather list for it.
- */
-static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
-{
- unsigned int order;
- size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
- struct page *page;
- int max_pages, err = 0, i = 0;
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- /*
- * allocate maximum size scatter-gather list. Note this is
- * overhead. We may not use as many entries as we allocate
- */
- max_pages = vb->bsize >> PAGE_SHIFT;
- dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
- if (dma->sglist == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- while (size) {
- order = get_order(size);
- /*
- * do not over-allocate even if we would get larger
- * contiguous chunk that way
- */
- if ((PAGE_SIZE << order) > size)
- order--;
-
- /* try to allocate as many contiguous pages as possible */
- page = alloc_pages(GFP_KERNEL, order);
- /* if allocation fails, try to allocate smaller amount */
- while (page == NULL) {
- order--;
- page = alloc_pages(GFP_KERNEL, order);
- if (page == NULL && !order) {
- err = -ENOMEM;
- goto out;
- }
- }
- size -= (PAGE_SIZE << order);
-
- /* append allocated chunk of pages into scatter-gather list */
- sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
- dma->sglen++;
- i++;
-
- alloc_size = (PAGE_SIZE << order);
-
- /* clear pages before giving them to user space */
- memset(page_address(page), 0, alloc_size);
-
- /* mark allocated pages reserved */
- do {
- SetPageReserved(page++);
- } while (alloc_size -= PAGE_SIZE);
- }
- /*
- * REVISIT: not fully correct to assign nr_pages == sglen but
- * video-buf is passing nr_pages for e.g. unmap_sg calls
- */
- dma->nr_pages = dma->sglen;
- dma->direction = PCI_DMA_FROMDEVICE;
-
- return 0;
-
-out:
- omap24xxcam_vbq_free_mmap_buffer(vb);
- return err;
-}
-
-static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
- unsigned int count)
-{
- int i, err = 0;
- struct omap24xxcam_fh *fh =
- container_of(vbq, struct omap24xxcam_fh, vbq);
-
- mutex_lock(&vbq->vb_lock);
-
- for (i = 0; i < count; i++) {
- err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
- if (err)
- goto out;
- dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
- videobuf_to_dma(vbq->bufs[i])->sglen, i);
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- return 0;
-out:
- while (i) {
- i--;
- omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- return err;
-}
-
-/*
- * This routine is called from interrupt context when a scatter-gather DMA
- * transfer of a videobuf_buffer completes.
- */
-static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
- u32 csr, void *arg)
-{
- struct omap24xxcam_device *cam =
- container_of(sgdma, struct omap24xxcam_device, sgdma);
- struct omap24xxcam_fh *fh = cam->streaming->private_data;
- struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
- if (--cam->sgdma_in_queue == 0)
- omap24xxcam_core_disable(cam);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-
- do_gettimeofday(&vb->ts);
- vb->field_count = atomic_add_return(2, &fh->field_count);
- if (csr & csr_error) {
- vb->state = VIDEOBUF_ERROR;
- if (!atomic_read(&fh->cam->in_reset)) {
- dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
- omap24xxcam_reset(cam);
- }
- } else
- vb->state = VIDEOBUF_DONE;
- wake_up(&vb->done);
-}
-
-static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- /* wait for buffer, especially to get out of the sgdma queue */
- videobuf_waiton(vbq, vb, 0, 0);
- if (vb->memory == V4L2_MEMORY_MMAP) {
- dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
- dma->direction);
- dma->direction = DMA_NONE;
- } else {
- videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
- videobuf_dma_free(videobuf_to_dma(vb));
- }
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-/*
- * Limit the number of available kernel image capture buffers based on the
- * number requested, the currently selected image size, and the maximum
- * amount of memory permitted for kernel capture buffers.
- */
-static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
- unsigned int *size)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
-
- if (*cnt <= 0)
- *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
-
- if (*cnt > VIDEO_MAX_FRAME)
- *cnt = VIDEO_MAX_FRAME;
-
- *size = fh->pix.sizeimage;
-
- /* accessing fh->cam->capture_mem is ok, it's constant */
- if (*size * *cnt > fh->cam->capture_mem)
- *cnt = fh->cam->capture_mem / *size;
-
- return 0;
-}
-
-static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
- struct videobuf_dmabuf *dma)
-{
- int err = 0;
-
- dma->direction = PCI_DMA_FROMDEVICE;
- if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- err = -EIO;
- }
-
- return err;
-}
-
-static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
- int err = 0;
-
- /*
- * Accessing pix here is okay since it's constant while
- * streaming is on (and we only get called then).
- */
- if (vb->baddr) {
- /* This is a userspace buffer. */
- if (fh->pix.sizeimage > vb->bsize) {
- /* The buffer isn't big enough. */
- err = -EINVAL;
- } else
- vb->size = fh->pix.sizeimage;
- } else {
- if (vb->state != VIDEOBUF_NEEDS_INIT) {
- /*
- * We have a kernel bounce buffer that has
- * already been allocated.
- */
- if (fh->pix.sizeimage > vb->size) {
- /*
- * The image size has been changed to
- * a larger size since this buffer was
- * allocated, so we need to free and
- * reallocate it.
- */
- omap24xxcam_vbq_release(vbq, vb);
- vb->size = fh->pix.sizeimage;
- }
- } else {
- /* We need to allocate a new kernel bounce buffer. */
- vb->size = fh->pix.sizeimage;
- }
- }
-
- if (err)
- return err;
-
- vb->width = fh->pix.width;
- vb->height = fh->pix.height;
- vb->field = field;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- if (vb->memory == V4L2_MEMORY_MMAP)
- /*
- * we have built the scatter-gather list by ourself so
- * do the scatter-gather mapping as well
- */
- err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
- else
- err = videobuf_iolock(vbq, vb, NULL);
- }
-
- if (!err)
- vb->state = VIDEOBUF_PREPARED;
- else
- omap24xxcam_vbq_release(vbq, vb);
-
- return err;
-}
-
-static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
- struct omap24xxcam_device *cam = fh->cam;
- enum videobuf_state state = vb->state;
- unsigned long flags;
- int err;
-
- /*
- * FIXME: We're marking the buffer active since we have no
- * pretty way of marking it active exactly when the
- * scatter-gather transfer starts.
- */
- vb->state = VIDEOBUF_ACTIVE;
-
- err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
- videobuf_to_dma(vb)->sglist,
- videobuf_to_dma(vb)->sglen, vb->size,
- omap24xxcam_vbq_complete, vb);
-
- if (!err) {
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
- if (++cam->sgdma_in_queue == 1
- && !atomic_read(&cam->in_reset))
- omap24xxcam_core_enable(cam);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
- } else {
- /*
- * Oops. We're not supposed to get any errors here.
- * The only way we could get an error is if we ran out
- * of scatter-gather DMA slots, but we are supposed to
- * have at least as many scatter-gather DMA slots as
- * video buffers so that can't happen.
- */
- dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
- dev_err(cam->dev, "likely a bug in the driver!\n");
- vb->state = state;
- }
-}
-
-static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
- .buf_setup = omap24xxcam_vbq_setup,
- .buf_prepare = omap24xxcam_vbq_prepare,
- .buf_queue = omap24xxcam_vbq_queue,
- .buf_release = omap24xxcam_vbq_release,
-};
-
-/*
- *
- * OMAP main camera system
- *
- */
-
-/*
- * Reset camera block to power-on state.
- */
-static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam)
-{
- int max_loop = RESET_TIMEOUT_NS;
-
- /* Reset whole camera subsystem */
- omap24xxcam_reg_out(cam->mmio_base,
- CAM_SYSCONFIG,
- CAM_SYSCONFIG_SOFTRESET);
-
- /* Wait till it's finished */
- while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
- & CAM_SYSSTATUS_RESETDONE)
- && --max_loop) {
- ndelay(1);
- }
-
- if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
- & CAM_SYSSTATUS_RESETDONE))
- dev_err(cam->dev, "camera soft reset timeout\n");
-}
-
-/*
- * (Re)initialise the camera block.
- */
-static void omap24xxcam_hwinit(struct omap24xxcam_device *cam)
-{
- omap24xxcam_poweron_reset(cam);
-
- /* set the camera subsystem autoidle bit */
- omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
- CAM_SYSCONFIG_AUTOIDLE);
-
- /* set the camera MMU autoidle bit */
- omap24xxcam_reg_out(cam->mmio_base,
- CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
- CAMMMU_SYSCONFIG_AUTOIDLE);
-
- omap24xxcam_core_hwinit(cam);
-
- omap24xxcam_dma_hwinit(&cam->sgdma.dma);
-}
-
-/*
- * Callback for dma transfer stalling.
- */
-static void omap24xxcam_stalled_dma_reset(unsigned long data)
-{
- struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
-
- if (!atomic_read(&cam->in_reset)) {
- dev_dbg(cam->dev, "dma stalled, resetting camera\n");
- omap24xxcam_reset(cam);
- }
-}
-
-/*
- * Stop capture. Mark we're doing a reset, stop DMA transfers and
- * core. (No new scatter-gather transfers will be queued whilst
- * in_reset is non-zero.)
- *
- * If omap24xxcam_capture_stop is called from several places at
- * once, only the first call will have an effect. Similarly, the last
- * call omap24xxcam_streaming_cont will have effect.
- *
- * Serialisation is ensured by using cam->core_enable_disable_lock.
- */
-static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
-
- if (atomic_inc_return(&cam->in_reset) != 1) {
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
- return;
- }
-
- omap24xxcam_core_disable(cam);
-
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-
- omap24xxcam_sgdma_sync(&cam->sgdma);
-}
-
-/*
- * Reset and continue streaming.
- *
- * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
- * register is supposed to be sufficient to recover from a camera
- * interface error, but it doesn't seem to be enough. If we only do
- * that then subsequent image captures are out of sync by either one
- * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
- * entire camera subsystem prevents the problem with frame
- * synchronization.
- */
-static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
-
- if (atomic_read(&cam->in_reset) != 1)
- goto out;
-
- omap24xxcam_hwinit(cam);
-
- omap24xxcam_sensor_if_enable(cam);
-
- omap24xxcam_sgdma_process(&cam->sgdma);
-
- if (cam->sgdma_in_queue)
- omap24xxcam_core_enable(cam);
-
-out:
- atomic_dec(&cam->in_reset);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-}
-
-static ssize_t
-omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct omap24xxcam_device *cam = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
-}
-static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
-
-/*
- * Stop capture and restart it. I.e. reset the camera during use.
- */
-static void omap24xxcam_reset(struct omap24xxcam_device *cam)
-{
- omap24xxcam_capture_stop(cam);
- omap24xxcam_capture_cont(cam);
-}
-
-/*
- * The main interrupt handler.
- */
-static irqreturn_t omap24xxcam_isr(int irq, void *arg)
-{
- struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
- u32 irqstatus;
- unsigned int irqhandled = 0;
-
- irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
-
- if (irqstatus &
- (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
- | CAM_IRQSTATUS_DMA_IRQ0)) {
- omap24xxcam_dma_isr(&cam->sgdma.dma);
- irqhandled = 1;
- }
- if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
- omap24xxcam_core_isr(cam);
- irqhandled = 1;
- }
- if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
- dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
-
- return IRQ_RETVAL(irqhandled);
-}
-
-/*
- *
- * Sensor handling.
- *
- */
-
-/*
- * Enable the external sensor interface. Try to negotiate interface
- * parameters with the sensor and start using the new ones. The calls
- * to sensor_if_enable and sensor_if_disable need not to be balanced.
- */
-static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
-{
- int rval;
- struct v4l2_ifparm p;
-
- rval = vidioc_int_g_ifparm(cam->sdev, &p);
- if (rval) {
- dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
- return rval;
- }
-
- cam->if_type = p.if_type;
-
- cam->cc_ctrl = CC_CTRL_CC_EN;
-
- switch (p.if_type) {
- case V4L2_IF_TYPE_BT656:
- if (p.u.bt656.frame_start_on_rising_vs)
- cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
- if (p.u.bt656.bt_sync_correct)
- cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
- if (p.u.bt656.swap)
- cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
- if (p.u.bt656.latch_clk_inv)
- cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
- if (p.u.bt656.nobt_hs_inv)
- cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
- if (p.u.bt656.nobt_vs_inv)
- cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
-
- switch (p.u.bt656.mode) {
- case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
- break;
- case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
- break;
- case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
- break;
- case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
- break;
- case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
- break;
- default:
- dev_err(cam->dev,
- "bt656 interface mode %d not supported\n",
- p.u.bt656.mode);
- return -EINVAL;
- }
- /*
- * The clock rate that the sensor wants has changed.
- * We have to adjust the xclk from OMAP 2 side to
- * match the sensor's wish as closely as possible.
- */
- if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
- u32 xclk = p.u.bt656.clock_curr;
- u32 divisor;
-
- if (xclk == 0)
- return -EINVAL;
-
- if (xclk > CAM_MCLK)
- xclk = CAM_MCLK;
-
- divisor = CAM_MCLK / xclk;
- if (divisor * xclk < CAM_MCLK)
- divisor++;
- if (CAM_MCLK / divisor < p.u.bt656.clock_min
- && divisor > 1)
- divisor--;
- if (divisor > 30)
- divisor = 30;
-
- xclk = CAM_MCLK / divisor;
-
- if (xclk < p.u.bt656.clock_min
- || xclk > p.u.bt656.clock_max)
- return -EINVAL;
-
- cam->if_u.bt656.xclk = xclk;
- }
- omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
- break;
- default:
- /* FIXME: how about other interfaces? */
- dev_err(cam->dev, "interface type %d not supported\n",
- p.if_type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
-{
- switch (cam->if_type) {
- case V4L2_IF_TYPE_BT656:
- omap24xxcam_core_xclk_set(cam, 0);
- break;
- }
-}
-
-/*
- * Initialise the sensor hardware.
- */
-static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
-{
- int err = 0;
- struct v4l2_int_device *sdev = cam->sdev;
-
- omap24xxcam_clock_on(cam);
- err = omap24xxcam_sensor_if_enable(cam);
- if (err) {
- dev_err(cam->dev, "sensor interface could not be enabled at "
- "initialisation, %d\n", err);
- cam->sdev = NULL;
- goto out;
- }
-
- /* power up sensor during sensor initialization */
- vidioc_int_s_power(sdev, 1);
-
- err = vidioc_int_dev_init(sdev);
- if (err) {
- dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
- /* Sensor init failed --- it's nonexistent to us! */
- cam->sdev = NULL;
- goto out;
- }
-
- dev_info(cam->dev, "sensor is %s\n", sdev->name);
-
-out:
- omap24xxcam_sensor_if_disable(cam);
- omap24xxcam_clock_off(cam);
-
- vidioc_int_s_power(sdev, 0);
-
- return err;
-}
-
-static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
-{
- if (cam->sdev)
- vidioc_int_dev_exit(cam->sdev);
-}
-
-static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
-{
- omap24xxcam_sensor_if_disable(cam);
- omap24xxcam_clock_off(cam);
- vidioc_int_s_power(cam->sdev, 0);
-}
-
-/*
- * Power-up and configure camera sensor. It's ready for capturing now.
- */
-static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
-{
- int rval;
-
- omap24xxcam_clock_on(cam);
-
- omap24xxcam_sensor_if_enable(cam);
-
- rval = vidioc_int_s_power(cam->sdev, 1);
- if (rval)
- goto out;
-
- rval = vidioc_int_init(cam->sdev);
- if (rval)
- goto out;
-
- return 0;
-
-out:
- omap24xxcam_sensor_disable(cam);
-
- return rval;
-}
-
-static void omap24xxcam_sensor_reset_work(struct work_struct *work)
-{
- struct omap24xxcam_device *cam =
- container_of(work, struct omap24xxcam_device,
- sensor_reset_work);
-
- if (atomic_read(&cam->reset_disable))
- return;
-
- omap24xxcam_capture_stop(cam);
-
- if (vidioc_int_reset(cam->sdev) == 0) {
- vidioc_int_init(cam->sdev);
- } else {
- /* Can't reset it by vidioc_int_reset. */
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_sensor_enable(cam);
- }
-
- omap24xxcam_capture_cont(cam);
-}
-
-/*
- *
- * IOCTL interface.
- *
- */
-
-static int vidioc_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
-
- strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
- strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
-
- return rval;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_fmt_cap(cam->sdev, f);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- rval = vidioc_int_s_fmt_cap(cam->sdev, f);
-
-out:
- mutex_unlock(&cam->mutex);
-
- if (!rval) {
- mutex_lock(&ofh->vbq.vb_lock);
- ofh->pix = f->fmt.pix;
- mutex_unlock(&ofh->vbq.vb_lock);
- }
-
- memset(f, 0, sizeof(*f));
- vidioc_g_fmt_vid_cap(file, fh, f);
-
- return rval;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_try_fmt_cap(cam->sdev, f);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *b)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- mutex_unlock(&cam->mutex);
- return -EBUSY;
- }
-
- omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
- mutex_unlock(&cam->mutex);
-
- rval = videobuf_reqbufs(&ofh->vbq, b);
-
- /*
- * Either videobuf_reqbufs failed or the buffers are not
- * memory-mapped (which would need special attention).
- */
- if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
- goto out;
-
- rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
- if (rval)
- omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
-
-out:
- return rval;
-}
-
-static int vidioc_querybuf(struct file *file, void *fh,
- struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
-
- return videobuf_querybuf(&ofh->vbq, b);
-}
-
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
-
- return videobuf_qbuf(&ofh->vbq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct videobuf_buffer *vb;
- int rval;
-
-videobuf_dqbuf_again:
- rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
- if (rval)
- goto out;
-
- vb = ofh->vbq.bufs[b->index];
-
- mutex_lock(&cam->mutex);
- /* _needs_reset returns -EIO if reset is required. */
- rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
- mutex_unlock(&cam->mutex);
- if (rval == -EIO)
- schedule_work(&cam->sensor_reset_work);
- else
- rval = 0;
-
-out:
- /*
- * This is a hack. We don't want to show -EIO to the user
- * space. Requeue the buffer and try again if we're not doing
- * this in non-blocking mode.
- */
- if (rval == -EIO) {
- videobuf_qbuf(&ofh->vbq, b);
- if (!(file->f_flags & O_NONBLOCK))
- goto videobuf_dqbuf_again;
- /*
- * We don't have a videobuf_buffer now --- maybe next
- * time...
- */
- rval = -EAGAIN;
- }
-
- return rval;
-}
-
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- rval = omap24xxcam_sensor_if_enable(cam);
- if (rval) {
- dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
- goto out;
- }
-
- rval = videobuf_streamon(&ofh->vbq);
- if (!rval) {
- cam->streaming = file;
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- }
-
-out:
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct videobuf_queue *q = &ofh->vbq;
- int rval;
-
- atomic_inc(&cam->reset_disable);
-
- flush_work_sync(&cam->sensor_reset_work);
-
- rval = videobuf_streamoff(q);
- if (!rval) {
- mutex_lock(&cam->mutex);
- cam->streaming = NULL;
- mutex_unlock(&cam->mutex);
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- }
-
- atomic_dec(&cam->reset_disable);
-
- return rval;
-}
-
-static int vidioc_enum_input(struct file *file, void *fh,
- struct v4l2_input *inp)
-{
- if (inp->index > 0)
- return -EINVAL;
-
- strlcpy(inp->name, "camera", sizeof(inp->name));
- inp->type = V4L2_INPUT_TYPE_CAMERA;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
-{
- if (i > 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *fh,
- struct v4l2_queryctrl *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- rval = vidioc_int_queryctrl(cam->sdev, a);
-
- return rval;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh,
- struct v4l2_control *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_ctrl(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh,
- struct v4l2_control *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_s_ctrl(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_g_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a) {
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_parm(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct v4l2_streamparm old_streamparm;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
- if (rval)
- goto out;
-
- rval = vidioc_int_s_parm(cam->sdev, a);
- if (rval)
- goto out;
-
- rval = omap24xxcam_sensor_if_enable(cam);
- /*
- * Revert to old streaming parameters if enabling sensor
- * interface with the new ones failed.
- */
- if (rval)
- vidioc_int_s_parm(cam->sdev, &old_streamparm);
-
-out:
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-/*
- *
- * File operations.
- *
- */
-
-static unsigned int omap24xxcam_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
- struct videobuf_buffer *vb;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming != file) {
- mutex_unlock(&cam->mutex);
- return POLLERR;
- }
- mutex_unlock(&cam->mutex);
-
- mutex_lock(&fh->vbq.vb_lock);
- if (list_empty(&fh->vbq.stream)) {
- mutex_unlock(&fh->vbq.vb_lock);
- return POLLERR;
- }
- vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
- mutex_unlock(&fh->vbq.vb_lock);
-
- poll_wait(file, &vb->done, wait);
-
- if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static int omap24xxcam_mmap_buffers(struct file *file,
- struct vm_area_struct *vma)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
- struct videobuf_queue *vbq = &fh->vbq;
- unsigned int first, last, size, i, j;
- int err = 0;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- mutex_unlock(&cam->mutex);
- return -EBUSY;
- }
- mutex_unlock(&cam->mutex);
- mutex_lock(&vbq->vb_lock);
-
- /* look for first buffer to map */
- for (first = 0; first < VIDEO_MAX_FRAME; first++) {
- if (NULL == vbq->bufs[first])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
- continue;
- if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
- break;
- }
-
- /* look for last buffer to map */
- for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
- if (NULL == vbq->bufs[last])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
- continue;
- size += vbq->bufs[last]->bsize;
- if (size == (vma->vm_end - vma->vm_start))
- break;
- }
-
- size = 0;
- for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) {
- struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
-
- for (j = 0; j < dma->sglen; j++) {
- err = remap_pfn_range(
- vma, vma->vm_start + size,
- page_to_pfn(sg_page(&dma->sglist[j])),
- sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
- if (err)
- goto out;
- size += sg_dma_len(&dma->sglist[j]);
- }
- }
-
-out:
- mutex_unlock(&vbq->vb_lock);
-
- return err;
-}
-
-static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- int rval;
-
- /* let the video-buf mapper check arguments and set-up structures */
- rval = videobuf_mmap_mapper(&fh->vbq, vma);
- if (rval)
- return rval;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- /* do mapping to our allocated buffers */
- rval = omap24xxcam_mmap_buffers(file, vma);
- /*
- * In case of error, free vma->vm_private_data allocated by
- * videobuf_mmap_mapper.
- */
- if (rval)
- kfree(vma->vm_private_data);
-
- return rval;
-}
-
-static int omap24xxcam_open(struct file *file)
-{
- struct omap24xxcam_device *cam = omap24xxcam.priv;
- struct omap24xxcam_fh *fh;
- struct v4l2_format format;
-
- if (!cam || !cam->vfd)
- return -ENODEV;
-
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (fh == NULL)
- return -ENOMEM;
-
- mutex_lock(&cam->mutex);
- if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
- mutex_unlock(&cam->mutex);
- goto out_try_module_get;
- }
-
- if (atomic_inc_return(&cam->users) == 1) {
- omap24xxcam_hwinit(cam);
- if (omap24xxcam_sensor_enable(cam)) {
- mutex_unlock(&cam->mutex);
- goto out_omap24xxcam_sensor_enable;
- }
- }
- mutex_unlock(&cam->mutex);
-
- fh->cam = cam;
- mutex_lock(&cam->mutex);
- vidioc_int_g_fmt_cap(cam->sdev, &format);
- mutex_unlock(&cam->mutex);
- /* FIXME: how about fh->pix when there are more users? */
- fh->pix = format.fmt.pix;
-
- file->private_data = fh;
-
- spin_lock_init(&fh->vbq_lock);
-
- videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
- &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), fh, NULL);
-
- return 0;
-
-out_omap24xxcam_sensor_enable:
- omap24xxcam_poweron_reset(cam);
- module_put(cam->sdev->module);
-
-out_try_module_get:
- kfree(fh);
-
- return -ENODEV;
-}
-
-static int omap24xxcam_release(struct file *file)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
-
- atomic_inc(&cam->reset_disable);
-
- flush_work_sync(&cam->sensor_reset_work);
-
- /* stop streaming capture */
- videobuf_streamoff(&fh->vbq);
-
- mutex_lock(&cam->mutex);
- if (cam->streaming == file) {
- cam->streaming = NULL;
- mutex_unlock(&cam->mutex);
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- } else {
- mutex_unlock(&cam->mutex);
- }
-
- atomic_dec(&cam->reset_disable);
-
- omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
-
- /*
- * Make sure the reset work we might have scheduled is not
- * pending! It may be run *only* if we have users. (And it may
- * not be scheduled anymore since streaming is already
- * disabled.)
- */
- flush_work_sync(&cam->sensor_reset_work);
-
- mutex_lock(&cam->mutex);
- if (atomic_dec_return(&cam->users) == 0) {
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_poweron_reset(cam);
- }
- mutex_unlock(&cam->mutex);
-
- file->private_data = NULL;
-
- module_put(cam->sdev->module);
- kfree(fh);
-
- return 0;
-}
-
-static struct v4l2_file_operations omap24xxcam_fops = {
- .ioctl = video_ioctl2,
- .poll = omap24xxcam_poll,
- .mmap = omap24xxcam_mmap,
- .open = omap24xxcam_open,
- .release = omap24xxcam_release,
-};
-
-/*
- *
- * Power management.
- *
- */
-
-#ifdef CONFIG_PM
-static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (atomic_read(&cam->users) == 0)
- return 0;
-
- if (!atomic_read(&cam->reset_disable))
- omap24xxcam_capture_stop(cam);
-
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_poweron_reset(cam);
-
- return 0;
-}
-
-static int omap24xxcam_resume(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (atomic_read(&cam->users) == 0)
- return 0;
-
- omap24xxcam_hwinit(cam);
- omap24xxcam_sensor_enable(cam);
-
- if (!atomic_read(&cam->reset_disable))
- omap24xxcam_capture_cont(cam);
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
- .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_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .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_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_parm = vidioc_g_parm,
- .vidioc_s_parm = vidioc_s_parm,
-};
-
-/*
- *
- * Camera device (i.e. /dev/video).
- *
- */
-
-static int omap24xxcam_device_register(struct v4l2_int_device *s)
-{
- struct omap24xxcam_device *cam = s->u.slave->master->priv;
- struct video_device *vfd;
- int rval;
-
- /* We already have a slave. */
- if (cam->sdev)
- return -EBUSY;
-
- cam->sdev = s;
-
- if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
- dev_err(cam->dev, "could not register sysfs entry\n");
- rval = -EBUSY;
- goto err;
- }
-
- /* initialize the video_device struct */
- vfd = cam->vfd = video_device_alloc();
- if (!vfd) {
- dev_err(cam->dev, "could not allocate video device struct\n");
- rval = -ENOMEM;
- goto err;
- }
- vfd->release = video_device_release;
-
- vfd->parent = cam->dev;
-
- strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
- vfd->fops = &omap24xxcam_fops;
- vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
-
- omap24xxcam_hwinit(cam);
-
- rval = omap24xxcam_sensor_init(cam);
- if (rval)
- goto err;
-
- if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
- dev_err(cam->dev, "could not register V4L device\n");
- rval = -EBUSY;
- goto err;
- }
-
- omap24xxcam_poweron_reset(cam);
-
- dev_info(cam->dev, "registered device %s\n",
- video_device_node_name(vfd));
-
- return 0;
-
-err:
- omap24xxcam_device_unregister(s);
-
- return rval;
-}
-
-static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
-{
- struct omap24xxcam_device *cam = s->u.slave->master->priv;
-
- omap24xxcam_sensor_exit(cam);
-
- if (cam->vfd) {
- if (!video_is_registered(cam->vfd)) {
- /*
- * The device was never registered, so release the
- * video_device struct directly.
- */
- video_device_release(cam->vfd);
- } else {
- /*
- * The unregister function will release the
- * video_device struct as well as
- * unregistering it.
- */
- video_unregister_device(cam->vfd);
- }
- cam->vfd = NULL;
- }
-
- device_remove_file(cam->dev, &dev_attr_streaming);
-
- cam->sdev = NULL;
-}
-
-static struct v4l2_int_master omap24xxcam_master = {
- .attach = omap24xxcam_device_register,
- .detach = omap24xxcam_device_unregister,
-};
-
-static struct v4l2_int_device omap24xxcam = {
- .module = THIS_MODULE,
- .name = CAM_NAME,
- .type = v4l2_int_type_master,
- .u = {
- .master = &omap24xxcam_master
- },
-};
-
-/*
- *
- * Driver initialisation and deinitialisation.
- *
- */
-
-static int __devinit omap24xxcam_probe(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam;
- struct resource *mem;
- int irq;
-
- cam = kzalloc(sizeof(*cam), GFP_KERNEL);
- if (!cam) {
- dev_err(&pdev->dev, "could not allocate memory\n");
- goto err;
- }
-
- platform_set_drvdata(pdev, cam);
-
- cam->dev = &pdev->dev;
-
- /*
- * Impose a lower limit on the amount of memory allocated for
- * capture. We require at least enough memory to double-buffer
- * QVGA (300KB).
- */
- if (capture_mem < 320 * 240 * 2 * 2)
- capture_mem = 320 * 240 * 2 * 2;
- cam->capture_mem = capture_mem;
-
- /* request the mem region for the camera registers */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(cam->dev, "no mem resource?\n");
- goto err;
- }
- if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
- dev_err(cam->dev,
- "cannot reserve camera register I/O region\n");
- goto err;
- }
- cam->mmio_base_phys = mem->start;
- cam->mmio_size = resource_size(mem);
-
- /* map the region */
- cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
- if (!cam->mmio_base) {
- dev_err(cam->dev, "cannot map camera register I/O region\n");
- goto err;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(cam->dev, "no irq for camera?\n");
- goto err;
- }
-
- /* install the interrupt service routine */
- if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
- dev_err(cam->dev,
- "could not install interrupt service routine\n");
- goto err;
- }
- cam->irq = irq;
-
- if (omap24xxcam_clock_get(cam))
- goto err;
-
- INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
-
- mutex_init(&cam->mutex);
- spin_lock_init(&cam->core_enable_disable_lock);
-
- omap24xxcam_sgdma_init(&cam->sgdma,
- cam->mmio_base + CAMDMA_REG_OFFSET,
- omap24xxcam_stalled_dma_reset,
- (unsigned long)cam);
-
- omap24xxcam.priv = cam;
-
- if (v4l2_int_device_register(&omap24xxcam))
- goto err;
-
- return 0;
-
-err:
- omap24xxcam_remove(pdev);
- return -ENODEV;
-}
-
-static int omap24xxcam_remove(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (!cam)
- return 0;
-
- if (omap24xxcam.priv != NULL)
- v4l2_int_device_unregister(&omap24xxcam);
- omap24xxcam.priv = NULL;
-
- omap24xxcam_clock_put(cam);
-
- if (cam->irq) {
- free_irq(cam->irq, cam);
- cam->irq = 0;
- }
-
- if (cam->mmio_base) {
- iounmap((void *)cam->mmio_base);
- cam->mmio_base = 0;
- }
-
- if (cam->mmio_base_phys) {
- release_mem_region(cam->mmio_base_phys, cam->mmio_size);
- cam->mmio_base_phys = 0;
- }
-
- kfree(cam);
-
- return 0;
-}
-
-static struct platform_driver omap24xxcam_driver = {
- .probe = omap24xxcam_probe,
- .remove = omap24xxcam_remove,
-#ifdef CONFIG_PM
- .suspend = omap24xxcam_suspend,
- .resume = omap24xxcam_resume,
-#endif
- .driver = {
- .name = CAM_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(omap24xxcam_driver);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
-MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(OMAP24XXCAM_VERSION);
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,
- "Minor number for video device (-1 ==> auto assign)");
-module_param(capture_mem, int, 0);
-MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
- "buffers (default 4800kiB)");
diff --git a/drivers/media/video/omap24xxcam.h b/drivers/media/video/omap24xxcam.h
deleted file mode 100644
index d59727afe894..000000000000
--- a/drivers/media/video/omap24xxcam.h
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * drivers/media/video/omap24xxcam.h
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.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 OMAP24XXCAM_H
-#define OMAP24XXCAM_H
-
-#include <media/videobuf-dma-sg.h>
-#include <media/v4l2-int-device.h>
-
-/*
- *
- * General driver related definitions.
- *
- */
-
-#define CAM_NAME "omap24xxcam"
-
-#define CAM_MCLK 96000000
-
-/* number of bytes transferred per DMA request */
-#define DMA_THRESHOLD 32
-
-/*
- * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
- * the camera DMA controller.
- */
-#define NUM_CAMDMA_CHANNELS 4
-
-/*
- * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
- * be queued. (We don't have any overlay sglists now.)
- */
-#define NUM_SG_DMA (VIDEO_MAX_FRAME)
-
-/*
- *
- * Register definitions.
- *
- */
-
-/* subsystem register block offsets */
-#define CC_REG_OFFSET 0x00000400
-#define CAMDMA_REG_OFFSET 0x00000800
-#define CAMMMU_REG_OFFSET 0x00000C00
-
-/* define camera subsystem register offsets */
-#define CAM_REVISION 0x000
-#define CAM_SYSCONFIG 0x010
-#define CAM_SYSSTATUS 0x014
-#define CAM_IRQSTATUS 0x018
-#define CAM_GPO 0x040
-#define CAM_GPI 0x050
-
-/* define camera core register offsets */
-#define CC_REVISION 0x000
-#define CC_SYSCONFIG 0x010
-#define CC_SYSSTATUS 0x014
-#define CC_IRQSTATUS 0x018
-#define CC_IRQENABLE 0x01C
-#define CC_CTRL 0x040
-#define CC_CTRL_DMA 0x044
-#define CC_CTRL_XCLK 0x048
-#define CC_FIFODATA 0x04C
-#define CC_TEST 0x050
-#define CC_GENPAR 0x054
-#define CC_CCPFSCR 0x058
-#define CC_CCPFECR 0x05C
-#define CC_CCPLSCR 0x060
-#define CC_CCPLECR 0x064
-#define CC_CCPDFR 0x068
-
-/* define camera dma register offsets */
-#define CAMDMA_REVISION 0x000
-#define CAMDMA_IRQSTATUS_L0 0x008
-#define CAMDMA_IRQSTATUS_L1 0x00C
-#define CAMDMA_IRQSTATUS_L2 0x010
-#define CAMDMA_IRQSTATUS_L3 0x014
-#define CAMDMA_IRQENABLE_L0 0x018
-#define CAMDMA_IRQENABLE_L1 0x01C
-#define CAMDMA_IRQENABLE_L2 0x020
-#define CAMDMA_IRQENABLE_L3 0x024
-#define CAMDMA_SYSSTATUS 0x028
-#define CAMDMA_OCP_SYSCONFIG 0x02C
-#define CAMDMA_CAPS_0 0x064
-#define CAMDMA_CAPS_2 0x06C
-#define CAMDMA_CAPS_3 0x070
-#define CAMDMA_CAPS_4 0x074
-#define CAMDMA_GCR 0x078
-#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
-#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
-#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
-#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
-#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
-#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
-#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
-#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
-#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
-#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
-#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
-#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
-#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
-#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
-#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
-#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
-#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
-#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
-
-/* define camera mmu register offsets */
-#define CAMMMU_REVISION 0x000
-#define CAMMMU_SYSCONFIG 0x010
-#define CAMMMU_SYSSTATUS 0x014
-#define CAMMMU_IRQSTATUS 0x018
-#define CAMMMU_IRQENABLE 0x01C
-#define CAMMMU_WALKING_ST 0x040
-#define CAMMMU_CNTL 0x044
-#define CAMMMU_FAULT_AD 0x048
-#define CAMMMU_TTB 0x04C
-#define CAMMMU_LOCK 0x050
-#define CAMMMU_LD_TLB 0x054
-#define CAMMMU_CAM 0x058
-#define CAMMMU_RAM 0x05C
-#define CAMMMU_GFLUSH 0x060
-#define CAMMMU_FLUSH_ENTRY 0x064
-#define CAMMMU_READ_CAM 0x068
-#define CAMMMU_READ_RAM 0x06C
-#define CAMMMU_EMU_FAULT_AD 0x070
-
-/* Define bit fields within selected registers */
-#define CAM_REVISION_MAJOR (15 << 4)
-#define CAM_REVISION_MAJOR_SHIFT 4
-#define CAM_REVISION_MINOR (15 << 0)
-#define CAM_REVISION_MINOR_SHIFT 0
-
-#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
-#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CAM_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
-#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
-#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
-#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
-#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
-
-#define CAM_GPO_CAM_S_P_EN (1 << 1)
-#define CAM_GPO_CAM_CCP_MODE (1 << 0)
-
-#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
-#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
-#define CAP_GPI_CAM_MSTANDBY (1 << 21)
-#define CAP_GPI_CAM_WAIT (1 << 20)
-#define CAP_GPI_CAM_S_DATA (1 << 17)
-#define CAP_GPI_CAM_S_CLK (1 << 16)
-#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
-#define CAP_GPI_CAM_P_DATA_SHIFT 3
-#define CAP_GPI_CAM_P_VS (1 << 2)
-#define CAP_GPI_CAM_P_HS (1 << 1)
-#define CAP_GPI_CAM_P_CLK (1 << 0)
-
-#define CC_REVISION_MAJOR (15 << 4)
-#define CC_REVISION_MAJOR_SHIFT 4
-#define CC_REVISION_MINOR (15 << 0)
-#define CC_REVISION_MINOR_SHIFT 0
-
-#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
-#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
-#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
-#define CC_SYSCONFIG_SOFTRESET (1 << 1)
-#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CC_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CC_IRQSTATUS_FS_IRQ (1 << 19)
-#define CC_IRQSTATUS_LE_IRQ (1 << 18)
-#define CC_IRQSTATUS_LS_IRQ (1 << 17)
-#define CC_IRQSTATUS_FE_IRQ (1 << 16)
-#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
-#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
-#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
-#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
-#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
-#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
-#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
-#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
-
-#define CC_IRQENABLE_FS_IRQ (1 << 19)
-#define CC_IRQENABLE_LE_IRQ (1 << 18)
-#define CC_IRQENABLE_LS_IRQ (1 << 17)
-#define CC_IRQENABLE_FE_IRQ (1 << 16)
-#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
-#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
-#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
-#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
-#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
-#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
-#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
-#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
-
-#define CC_CTRL_CC_ONE_SHOT (1 << 20)
-#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
-#define CC_CTRL_CC_RST (1 << 18)
-#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
-#define CC_CTRL_CC_EN (1 << 16)
-#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
-#define CC_CTRL_BT_CORRECT (1 << 12)
-#define CC_CTRL_PAR_ORDERCAM (1 << 11)
-#define CC_CTRL_PAR_CLK_POL (1 << 10)
-#define CC_CTRL_NOBT_HS_POL (1 << 9)
-#define CC_CTRL_NOBT_VS_POL (1 << 8)
-#define CC_CTRL_PAR_MODE (7 << 1)
-#define CC_CTRL_PAR_MODE_SHIFT 1
-#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
-#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
-#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
-#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
-#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
-#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
-#define CC_CTRL_CCP_MODE (1 << 0)
-
-#define CC_CTRL_DMA_EN (1 << 8)
-#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
-#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
-
-#define CC_CTRL_XCLK_DIV (0x1F << 0)
-#define CC_CTRL_XCLK_DIV_SHIFT 0
-#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
-#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
-#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
-
-#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
-#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
-#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
-#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
-#define CC_TEST_FIFO_LEVEL (0xFF << 8)
-#define CC_TEST_FIFO_LEVEL_SHIFT 8
-#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
-#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
-
-#define CC_GENPAR_FIFO_DEPTH (7 << 0)
-#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
-
-#define CC_CCPDFR_ALPHA (0xFF << 8)
-#define CC_CCPDFR_ALPHA_SHIFT 8
-#define CC_CCPDFR_DATAFORMAT (15 << 0)
-#define CC_CCPDFR_DATAFORMAT_SHIFT 0
-#define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0)
-#define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0)
-#define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
-#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
-
-#define CAMDMA_REVISION_MAJOR (15 << 4)
-#define CAMDMA_REVISION_MAJOR_SHIFT 4
-#define CAMDMA_REVISION_MINOR (15 << 0)
-#define CAMDMA_REVISION_MINOR_SHIFT 0
-
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
-#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
-#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
-#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
-#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
-#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
-#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
-#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
-
-#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
-#define CAMDMA_CCR_PREFETCH (1 << 23)
-#define CAMDMA_CCR_SUPERVISOR (1 << 22)
-#define CAMDMA_CCR_SECURE (1 << 21)
-#define CAMDMA_CCR_BS (1 << 18)
-#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
-#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
-#define CAMDMA_CCR_DST_AMODE (3 << 14)
-#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
-#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
-#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
-#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
-#define CAMDMA_CCR_SRC_AMODE (3 << 12)
-#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
-#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
-#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
-#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
-#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
-#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
-#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
-#define CAMDMA_CCR_ENABLE (1 << 7)
-#define CAMDMA_CCR_PRIO (1 << 6)
-#define CAMDMA_CCR_FS (1 << 5)
-#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
-#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
-
-#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
-#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
-#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
-
-#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
-#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
-#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
-#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
-#define CAMDMA_CICR_PACKET_IE (1 << 7)
-#define CAMDMA_CICR_BLOCK_IE (1 << 5)
-#define CAMDMA_CICR_LAST_IE (1 << 4)
-#define CAMDMA_CICR_FRAME_IE (1 << 3)
-#define CAMDMA_CICR_HALF_IE (1 << 2)
-#define CAMDMA_CICR_DROP_IE (1 << 1)
-
-#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
-#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
-#define CAMDMA_CSR_SECURE_ERR (1 << 9)
-#define CAMDMA_CSR_TRANS_ERR (1 << 8)
-#define CAMDMA_CSR_PACKET (1 << 7)
-#define CAMDMA_CSR_SYNC (1 << 6)
-#define CAMDMA_CSR_BLOCK (1 << 5)
-#define CAMDMA_CSR_LAST (1 << 4)
-#define CAMDMA_CSR_FRAME (1 << 3)
-#define CAMDMA_CSR_HALF (1 << 2)
-#define CAMDMA_CSR_DROP (1 << 1)
-
-#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
-#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
-#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
-#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
-#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
-#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
-#define CAMDMA_CSDP_DST_PACKED (1 << 13)
-#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
-#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
-#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
-#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
-#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
-#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
-#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
-
-#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
-
-/*
- *
- * Declarations.
- *
- */
-
-/* forward declarations */
-struct omap24xxcam_sgdma;
-struct omap24xxcam_dma;
-
-typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
- u32 status, void *arg);
-typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
- u32 status, void *arg);
-
-struct channel_state {
- dma_callback_t callback;
- void *arg;
-};
-
-/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
-struct sgdma_state {
- const struct scatterlist *sglist;
- int sglen; /* number of sglist entries */
- int next_sglist; /* index of next sglist entry to process */
- unsigned int bytes_read; /* number of bytes read */
- unsigned int len; /* total length of sglist (excluding
- * bytes due to page alignment) */
- int queued_sglist; /* number of sglist entries queued for DMA */
- u32 csr; /* DMA return code */
- sgdma_callback_t callback;
- void *arg;
-};
-
-/* physical DMA channel management */
-struct omap24xxcam_dma {
- spinlock_t lock; /* Lock for the whole structure. */
-
- void __iomem *base; /* base address for dma controller */
-
- /* While dma_stop!=0, an attempt to start a new DMA transfer will
- * fail.
- */
- atomic_t dma_stop;
- int free_dmach; /* number of dma channels free */
- int next_dmach; /* index of next dma channel to use */
- struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
-};
-
-/* scatter-gather DMA (scatterlist stuff) management */
-struct omap24xxcam_sgdma {
- struct omap24xxcam_dma dma;
-
- spinlock_t lock; /* Lock for the fields below. */
- int free_sgdma; /* number of free sg dma slots */
- int next_sgdma; /* index of next sg dma slot to use */
- struct sgdma_state sg_state[NUM_SG_DMA];
-
- /* Reset timer data */
- struct timer_list reset_timer;
-};
-
-/* per-device data structure */
-struct omap24xxcam_device {
- /*** mutex ***/
- /*
- * mutex serialises access to this structure. Also camera
- * opening and releasing is synchronised by this.
- */
- struct mutex mutex;
-
- /*** general driver state information ***/
- atomic_t users;
- /*
- * Lock to serialise core enabling and disabling and access to
- * sgdma_in_queue.
- */
- spinlock_t core_enable_disable_lock;
- /*
- * Number or sgdma requests in scatter-gather queue, protected
- * by the lock above.
- */
- int sgdma_in_queue;
- /*
- * Sensor interface parameters: interface type, CC_CTRL
- * register value and interface specific data.
- */
- int if_type;
- union {
- struct parallel {
- u32 xclk;
- } bt656;
- } if_u;
- u32 cc_ctrl;
-
- /*** subsystem structures ***/
- struct omap24xxcam_sgdma sgdma;
-
- /*** hardware resources ***/
- unsigned int irq;
- void __iomem *mmio_base;
- unsigned long mmio_base_phys;
- unsigned long mmio_size;
-
- /*** interfaces and device ***/
- struct v4l2_int_device *sdev;
- struct device *dev;
- struct video_device *vfd;
-
- /*** camera and sensor reset related stuff ***/
- struct work_struct sensor_reset_work;
- /*
- * We're in the middle of a reset. Don't enable core if this
- * is non-zero! This exists to help decisionmaking in a case
- * where videobuf_qbuf is called while we are in the middle of
- * a reset.
- */
- atomic_t in_reset;
- /*
- * Non-zero if we don't want any resets for now. Used to
- * prevent reset work to run when we're about to stop
- * streaming.
- */
- atomic_t reset_disable;
-
- /*** video device parameters ***/
- int capture_mem;
-
- /*** camera module clocks ***/
- struct clk *fck;
- struct clk *ick;
-
- /*** capture data ***/
- /* file handle, if streaming is on */
- struct file *streaming;
-};
-
-/* Per-file handle data. */
-struct omap24xxcam_fh {
- spinlock_t vbq_lock; /* spinlock for the videobuf queue */
- struct videobuf_queue vbq;
- struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
- atomic_t field_count; /* field counter for videobuf_buffer */
- /* accessing cam here doesn't need serialisation: it's constant */
- struct omap24xxcam_device *cam;
-};
-
-/*
- *
- * Register I/O functions.
- *
- */
-
-static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
-{
- return readl(base + offset);
-}
-
-static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
- u32 val)
-{
- writel(val, base + offset);
- return val;
-}
-
-static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
- u32 val, u32 mask)
-{
- u32 __iomem *addr = base + offset;
- u32 new_val = (readl(addr) & ~mask) | (val & mask);
-
- writel(new_val, addr);
- return new_val;
-}
-
-/*
- *
- * Function prototypes.
- *
- */
-
-/* dma prototypes */
-
-void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma);
-void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
-
-/* sgdma prototypes */
-
-void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
-int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
- const struct scatterlist *sglist, int sglen,
- int len, sgdma_callback_t callback, void *arg);
-void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
-void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- void __iomem *base,
- void (*reset_callback)(unsigned long data),
- unsigned long reset_callback_data);
-void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
-
-#endif
diff --git a/drivers/media/video/omap3isp/cfa_coef_table.h b/drivers/media/video/omap3isp/cfa_coef_table.h
deleted file mode 100644
index c60df0ed075a..000000000000
--- a/drivers/media/video/omap3isp/cfa_coef_table.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * cfa_coef_table.h
- *
- * TI OMAP3 ISP - CFA coefficients table
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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
- */
-
-244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
-247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
-244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
-247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
-244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
-247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
- 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
- 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
- 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
- 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
- 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
- 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
- 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
- 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
- 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
- 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
- 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
- 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
- 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
- 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
- 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
- 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
- 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
- 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
-244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
-250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
-244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
-250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
-244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
-248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
-250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
deleted file mode 100644
index 1c347633e663..000000000000
--- a/drivers/media/video/omap3isp/isp.c
+++ /dev/null
@@ -1,2230 +0,0 @@
-/*
- * isp.c
- *
- * TI OMAP3 ISP - Core
- *
- * Copyright (C) 2006-2010 Nokia Corporation
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * Contributors:
- * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- * David Cohen <dacohen@gmail.com>
- * Stanimir Varbanov <svarbanov@mm-sol.com>
- * Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
- * Tuukka Toivonen <tuukkat76@gmail.com>
- * Sergio Aguirre <saaguirre@ti.com>
- * Antti Koskipaa <akoskipa@gmail.com>
- * Ivan T. Ivanov <iivanov@mm-sol.com>
- * RaniSuneela <r-m@ti.com>
- * Atanas Filipov <afilipov@mm-sol.com>
- * Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
- * Hiroshi DOYU <hiroshi.doyu@nokia.com>
- * Nayden Kanchev <nkanchev@mm-sol.com>
- * Phil Carmody <ext-phil.2.carmody@nokia.com>
- * Artem Bityutskiy <artem.bityutskiy@nokia.com>
- * Dominic Curran <dcurran@ti.com>
- * Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
- * Pallavi Kulkarni <p-kulkarni@ti.com>
- * Vaibhav Hiremath <hvaibhav@ti.com>
- * Mohit Jalori <mjalori@ti.com>
- * Sameer Venkatraman <sameerv@ti.com>
- * Senthilvadivu Guruswamy <svadivu@ti.com>
- * Thara Gopinath <thara@ti.com>
- * Toni Leinonen <toni.leinonen@nokia.com>
- * Troy Laramy <t-laramy@ti.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 <asm/cacheflush.h>
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/vmalloc.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "ispccdc.h"
-#include "isppreview.h"
-#include "ispresizer.h"
-#include "ispcsi2.h"
-#include "ispccp2.h"
-#include "isph3a.h"
-#include "isphist.h"
-
-static unsigned int autoidle;
-module_param(autoidle, int, 0444);
-MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
-
-static void isp_save_ctx(struct isp_device *isp);
-
-static void isp_restore_ctx(struct isp_device *isp);
-
-static const struct isp_res_mapping isp_res_maps[] = {
- {
- .isp_rev = ISP_REVISION_2_0,
- .map = 1 << OMAP3_ISP_IOMEM_MAIN |
- 1 << OMAP3_ISP_IOMEM_CCP2 |
- 1 << OMAP3_ISP_IOMEM_CCDC |
- 1 << OMAP3_ISP_IOMEM_HIST |
- 1 << OMAP3_ISP_IOMEM_H3A |
- 1 << OMAP3_ISP_IOMEM_PREV |
- 1 << OMAP3_ISP_IOMEM_RESZ |
- 1 << OMAP3_ISP_IOMEM_SBL |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY2,
- },
- {
- .isp_rev = ISP_REVISION_15_0,
- .map = 1 << OMAP3_ISP_IOMEM_MAIN |
- 1 << OMAP3_ISP_IOMEM_CCP2 |
- 1 << OMAP3_ISP_IOMEM_CCDC |
- 1 << OMAP3_ISP_IOMEM_HIST |
- 1 << OMAP3_ISP_IOMEM_H3A |
- 1 << OMAP3_ISP_IOMEM_PREV |
- 1 << OMAP3_ISP_IOMEM_RESZ |
- 1 << OMAP3_ISP_IOMEM_SBL |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY2 |
- 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
- 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
- 1 << OMAP3_ISP_IOMEM_CSIPHY1 |
- 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2,
- },
-};
-
-/* Structure for saving/restoring ISP module registers */
-static struct isp_reg isp_reg_list[] = {
- {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
- {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0},
- {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0},
- {0, ISP_TOK_TERM, 0}
-};
-
-/*
- * omap3isp_flush - Post pending L3 bus writes by doing a register readback
- * @isp: OMAP3 ISP device
- *
- * In order to force posting of pending writes, we need to write and
- * readback the same register, in this case the revision register.
- *
- * See this link for reference:
- * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
- */
-void omap3isp_flush(struct isp_device *isp)
-{
- isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
-}
-
-/*
- * isp_enable_interrupts - Enable ISP interrupts.
- * @isp: OMAP3 ISP device
- */
-static void isp_enable_interrupts(struct isp_device *isp)
-{
- static const u32 irq = IRQ0ENABLE_CSIA_IRQ
- | IRQ0ENABLE_CSIB_IRQ
- | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ
- | IRQ0ENABLE_CCDC_LSC_DONE_IRQ
- | IRQ0ENABLE_CCDC_VD0_IRQ
- | IRQ0ENABLE_CCDC_VD1_IRQ
- | IRQ0ENABLE_HS_VS_IRQ
- | IRQ0ENABLE_HIST_DONE_IRQ
- | IRQ0ENABLE_H3A_AWB_DONE_IRQ
- | IRQ0ENABLE_H3A_AF_DONE_IRQ
- | IRQ0ENABLE_PRV_DONE_IRQ
- | IRQ0ENABLE_RSZ_DONE_IRQ;
-
- isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
-}
-
-/*
- * isp_disable_interrupts - Disable ISP interrupts.
- * @isp: OMAP3 ISP device
- */
-static void isp_disable_interrupts(struct isp_device *isp)
-{
- isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
-}
-
-/**
- * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
- * @isp: OMAP3 ISP device
- * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
- * @xclksel: XCLK to configure (0 = A, 1 = B).
- *
- * Configures the specified MCLK divisor in the ISP timing control register
- * (TCTRL_CTRL) to generate the desired xclk clock value.
- *
- * Divisor = cam_mclk_hz / xclk
- *
- * Returns the final frequency that is actually being generated
- **/
-static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
-{
- u32 divisor;
- u32 currentxclk;
- unsigned long mclk_hz;
-
- if (!omap3isp_get(isp))
- return 0;
-
- mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
-
- if (xclk >= mclk_hz) {
- divisor = ISPTCTRL_CTRL_DIV_BYPASS;
- currentxclk = mclk_hz;
- } else if (xclk >= 2) {
- divisor = mclk_hz / xclk;
- if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
- divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
- currentxclk = mclk_hz / divisor;
- } else {
- divisor = xclk;
- currentxclk = 0;
- }
-
- switch (xclksel) {
- case ISP_XCLK_A:
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
- ISPTCTRL_CTRL_DIVA_MASK,
- divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
- dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
- currentxclk);
- break;
- case ISP_XCLK_B:
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
- ISPTCTRL_CTRL_DIVB_MASK,
- divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
- dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
- currentxclk);
- break;
- case ISP_XCLK_NONE:
- default:
- omap3isp_put(isp);
- dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
- "xclk. Must be 0 (A) or 1 (B).\n");
- return -EINVAL;
- }
-
- /* Do we go from stable whatever to clock? */
- if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
- omap3isp_get(isp);
- /* Stopping the clock. */
- else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
- omap3isp_put(isp);
-
- isp->xclk_divisor[xclksel - 1] = divisor;
-
- omap3isp_put(isp);
-
- return currentxclk;
-}
-
-/*
- * isp_power_settings - Sysconfig settings, for Power Management.
- * @isp: OMAP3 ISP device
- * @idle: Consider idle state.
- *
- * Sets the power settings for the ISP, and SBL bus.
- */
-static void isp_power_settings(struct isp_device *isp, int idle)
-{
- isp_reg_writel(isp,
- ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
- ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) <<
- ISP_SYSCONFIG_MIDLEMODE_SHIFT) |
- ((isp->revision == ISP_REVISION_15_0) ?
- ISP_SYSCONFIG_AUTOIDLE : 0),
- OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
-
- if (isp->autoidle)
- isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
- ISP_CTRL);
-}
-
-/*
- * Configure the bridge and lane shifter. Valid inputs are
- *
- * CCDC_INPUT_PARALLEL: Parallel interface
- * CCDC_INPUT_CSI2A: CSI2a receiver
- * CCDC_INPUT_CCP2B: CCP2b receiver
- * CCDC_INPUT_CSI2C: CSI2c receiver
- *
- * The bridge and lane shifter are configured according to the selected input
- * and the ISP platform data.
- */
-void omap3isp_configure_bridge(struct isp_device *isp,
- enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata,
- unsigned int shift)
-{
- u32 ispctrl_val;
-
- ispctrl_val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
- ispctrl_val &= ~ISPCTRL_SHIFT_MASK;
- ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
- ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
- ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
-
- switch (input) {
- case CCDC_INPUT_PARALLEL:
- ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
- ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
- ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
- shift += pdata->data_lane_shift * 2;
- break;
-
- case CCDC_INPUT_CSI2A:
- ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA;
- break;
-
- case CCDC_INPUT_CCP2B:
- ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
- break;
-
- case CCDC_INPUT_CSI2C:
- ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC;
- break;
-
- default:
- return;
- }
-
- ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
-
- ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
- ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
-
- isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
-}
-
-void omap3isp_hist_dma_done(struct isp_device *isp)
-{
- if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
- omap3isp_stat_pcr_busy(&isp->isp_hist)) {
- /* Histogram cannot be enabled in this frame anymore */
- atomic_set(&isp->isp_hist.buf_err, 1);
- dev_dbg(isp->dev, "hist: Out of synchronization with "
- "CCDC. Ignoring next buffer.\n");
- }
-}
-
-static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
-{
- static const char *name[] = {
- "CSIA_IRQ",
- "res1",
- "res2",
- "CSIB_LCM_IRQ",
- "CSIB_IRQ",
- "res5",
- "res6",
- "res7",
- "CCDC_VD0_IRQ",
- "CCDC_VD1_IRQ",
- "CCDC_VD2_IRQ",
- "CCDC_ERR_IRQ",
- "H3A_AF_DONE_IRQ",
- "H3A_AWB_DONE_IRQ",
- "res14",
- "res15",
- "HIST_DONE_IRQ",
- "CCDC_LSC_DONE",
- "CCDC_LSC_PREFETCH_COMPLETED",
- "CCDC_LSC_PREFETCH_ERROR",
- "PRV_DONE_IRQ",
- "CBUFF_IRQ",
- "res22",
- "res23",
- "RSZ_DONE_IRQ",
- "OVF_IRQ",
- "res26",
- "res27",
- "MMU_ERR_IRQ",
- "OCP_ERR_IRQ",
- "SEC_ERR_IRQ",
- "HS_VS_IRQ",
- };
- int i;
-
- dev_dbg(isp->dev, "ISP IRQ: ");
-
- for (i = 0; i < ARRAY_SIZE(name); i++) {
- if ((1 << i) & irqstatus)
- printk(KERN_CONT "%s ", name[i]);
- }
- printk(KERN_CONT "\n");
-}
-
-static void isp_isr_sbl(struct isp_device *isp)
-{
- struct device *dev = isp->dev;
- struct isp_pipeline *pipe;
- u32 sbl_pcr;
-
- /*
- * Handle shared buffer logic overflows for video buffers.
- * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
- */
- sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
- isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
- sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
-
- if (sbl_pcr)
- dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
-
- 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) {
- 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)) {
- 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);
-
- if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF)
- omap3isp_stat_sbl_overflow(&isp->isp_aewb);
-}
-
-/*
- * isp_isr - Interrupt Service Routine for Camera ISP module.
- * @irq: Not used currently.
- * @_isp: Pointer to the OMAP3 ISP device
- *
- * Handles the corresponding callback if plugged in.
- *
- * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
- * IRQ wasn't handled.
- */
-static irqreturn_t isp_isr(int irq, void *_isp)
-{
- static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ |
- IRQ0STATUS_CCDC_LSC_DONE_IRQ |
- IRQ0STATUS_CCDC_VD0_IRQ |
- IRQ0STATUS_CCDC_VD1_IRQ |
- IRQ0STATUS_HS_VS_IRQ;
- struct isp_device *isp = _isp;
- u32 irqstatus;
-
- 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)
- omap3isp_csi2_isr(&isp->isp_csi2a);
-
- 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)
- omap3isp_preview_isr_frame_sync(&isp->isp_prev);
- if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
- omap3isp_resizer_isr_frame_sync(&isp->isp_res);
- omap3isp_stat_isr_frame_sync(&isp->isp_aewb);
- omap3isp_stat_isr_frame_sync(&isp->isp_af);
- omap3isp_stat_isr_frame_sync(&isp->isp_hist);
- }
-
- if (irqstatus & ccdc_events)
- omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events);
-
- if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) {
- if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER)
- omap3isp_resizer_isr_frame_sync(&isp->isp_res);
- omap3isp_preview_isr(&isp->isp_prev);
- }
-
- if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ)
- omap3isp_resizer_isr(&isp->isp_res);
-
- if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ)
- omap3isp_stat_isr(&isp->isp_aewb);
-
- if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ)
- omap3isp_stat_isr(&isp->isp_af);
-
- if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ)
- omap3isp_stat_isr(&isp->isp_hist);
-
- omap3isp_flush(isp);
-
-#if defined(DEBUG) && defined(ISP_ISR_DEBUG)
- isp_isr_dbg(isp, irqstatus);
-#endif
-
- return IRQ_HANDLED;
-}
-
-/* -----------------------------------------------------------------------------
- * Pipeline power management
- *
- * Entities must be powered up when part of a pipeline that contains at least
- * one open video device node.
- *
- * To achieve this use the entity use_count field to track the number of users.
- * For entities corresponding to video device nodes the use_count field stores
- * the users count of the node. For entities corresponding to subdevs the
- * use_count field stores the total number of users of all video device nodes
- * in the pipeline.
- *
- * The omap3isp_pipeline_pm_use() function must be called in the open() and
- * close() handlers of video device nodes. It increments or decrements the use
- * count of all subdev entities in the pipeline.
- *
- * To react to link management on powered pipelines, the link setup notification
- * callback updates the use count of all entities in the source and sink sides
- * of the link.
- */
-
-/*
- * isp_pipeline_pm_use_count - Count the number of users of a pipeline
- * @entity: The entity
- *
- * Return the total number of users of all video device nodes in the pipeline.
- */
-static int isp_pipeline_pm_use_count(struct media_entity *entity)
-{
- struct media_entity_graph graph;
- int use = 0;
-
- media_entity_graph_walk_start(&graph, entity);
-
- while ((entity = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
- use += entity->use_count;
- }
-
- return use;
-}
-
-/*
- * isp_pipeline_pm_power_one - Apply power change to an entity
- * @entity: The entity
- * @change: Use count change
- *
- * Change the entity use count by @change. If the entity is a subdev update its
- * power state by calling the core::s_power operation when the use count goes
- * from 0 to != 0 or from != 0 to 0.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
-{
- struct v4l2_subdev *subdev;
- int ret;
-
- subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
- ? media_entity_to_v4l2_subdev(entity) : NULL;
-
- if (entity->use_count == 0 && change > 0 && subdev != NULL) {
- ret = v4l2_subdev_call(subdev, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
- }
-
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- if (entity->use_count == 0 && change < 0 && subdev != NULL)
- v4l2_subdev_call(subdev, core, s_power, 0);
-
- return 0;
-}
-
-/*
- * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
- * @entity: The entity
- * @change: Use count change
- *
- * Walk the pipeline to update the use count and the power state of all non-node
- * entities.
- *
- * Return 0 on success or a negative error code on failure.
- */
-static int isp_pipeline_pm_power(struct media_entity *entity, int change)
-{
- struct media_entity_graph graph;
- struct media_entity *first = entity;
- int ret = 0;
-
- if (!change)
- return 0;
-
- media_entity_graph_walk_start(&graph, entity);
-
- while (!ret && (entity = media_entity_graph_walk_next(&graph)))
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
- ret = isp_pipeline_pm_power_one(entity, change);
-
- if (!ret)
- return 0;
-
- media_entity_graph_walk_start(&graph, first);
-
- while ((first = media_entity_graph_walk_next(&graph))
- && first != entity)
- if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
- isp_pipeline_pm_power_one(first, -change);
-
- return ret;
-}
-
-/*
- * omap3isp_pipeline_pm_use - Update the use count of an entity
- * @entity: The entity
- * @use: Use (1) or stop using (0) the entity
- *
- * Update the use count of all entities in the pipeline and power entities on or
- * off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. No failure can occur when the use parameter is
- * set to 0.
- */
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
-{
- int change = use ? 1 : -1;
- int ret;
-
- mutex_lock(&entity->parent->graph_mutex);
-
- /* Apply use count to node. */
- entity->use_count += change;
- WARN_ON(entity->use_count < 0);
-
- /* Apply power change to connected non-nodes. */
- ret = isp_pipeline_pm_power(entity, change);
- if (ret < 0)
- entity->use_count -= change;
-
- mutex_unlock(&entity->parent->graph_mutex);
-
- return ret;
-}
-
-/*
- * isp_pipeline_link_notify - Link management notification callback
- * @source: Pad at the start of the link
- * @sink: Pad at the end of the link
- * @flags: New link flags that will be applied
- *
- * React to link management on powered pipelines by updating the use count of
- * all entities in the source and sink sides of the link. Entities are powered
- * on or off accordingly.
- *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. This function will not fail for disconnection
- * events.
- */
-static int isp_pipeline_link_notify(struct media_pad *source,
- struct media_pad *sink, u32 flags)
-{
- int source_use = isp_pipeline_pm_use_count(source->entity);
- int sink_use = isp_pipeline_pm_use_count(sink->entity);
- int ret;
-
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- /* Powering off entities is assumed to never fail. */
- isp_pipeline_pm_power(source->entity, -sink_use);
- isp_pipeline_pm_power(sink->entity, -source_use);
- return 0;
- }
-
- ret = isp_pipeline_pm_power(source->entity, sink_use);
- if (ret < 0)
- return ret;
-
- ret = isp_pipeline_pm_power(sink->entity, source_use);
- if (ret < 0)
- isp_pipeline_pm_power(source->entity, -sink_use);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * Pipeline stream management
- */
-
-/*
- * isp_pipeline_enable - Enable streaming on a pipeline
- * @pipe: ISP pipeline
- * @mode: Stream mode (single shot or continuous)
- *
- * Walk the entities chain starting at the pipeline output video node and start
- * all modules in the chain in the given mode.
- *
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
- */
-static int isp_pipeline_enable(struct isp_pipeline *pipe,
- enum isp_pipeline_stream_state mode)
-{
- struct isp_device *isp = pipe->output->isp;
- struct media_entity *entity;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
- unsigned long flags;
- int ret;
-
- /* If the preview engine crashed it might not respond to read/write
- * operations on the L4 bus. This would result in a bus fault and a
- * kernel oops. Refuse to start streaming in that case. This check must
- * be performed before the loop below to avoid starting entities if the
- * pipeline won't start anyway (those entities would then likely fail to
- * stop, making the problem worse).
- */
- if ((pipe->entities & isp->crashed) &
- (1U << isp->isp_prev.subdev.entity.id))
- return -EIO;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- pipe->do_propagation = false;
-
- entity = &pipe->output->video.entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- pad = media_entity_remote_source(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
-
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
-
- ret = v4l2_subdev_call(subdev, video, s_stream, mode);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
-
- if (subdev == &isp->isp_ccdc.subdev) {
- v4l2_subdev_call(&isp->isp_aewb.subdev, video,
- s_stream, mode);
- v4l2_subdev_call(&isp->isp_af.subdev, video,
- s_stream, mode);
- v4l2_subdev_call(&isp->isp_hist.subdev, video,
- s_stream, mode);
- pipe->do_propagation = true;
- }
- }
-
- return 0;
-}
-
-static int isp_pipeline_wait_resizer(struct isp_device *isp)
-{
- return omap3isp_resizer_busy(&isp->isp_res);
-}
-
-static int isp_pipeline_wait_preview(struct isp_device *isp)
-{
- return omap3isp_preview_busy(&isp->isp_prev);
-}
-
-static int isp_pipeline_wait_ccdc(struct isp_device *isp)
-{
- return omap3isp_stat_busy(&isp->isp_af)
- || omap3isp_stat_busy(&isp->isp_aewb)
- || omap3isp_stat_busy(&isp->isp_hist)
- || omap3isp_ccdc_busy(&isp->isp_ccdc);
-}
-
-#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000)
-
-static int isp_pipeline_wait(struct isp_device *isp,
- int(*busy)(struct isp_device *isp))
-{
- unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
-
- while (!time_after(jiffies, timeout)) {
- if (!busy(isp))
- return 0;
- }
-
- return 1;
-}
-
-/*
- * isp_pipeline_disable - Disable streaming on a pipeline
- * @pipe: ISP pipeline
- *
- * Walk the entities chain starting at the pipeline output video node and stop
- * all modules in the chain. Wait synchronously for the modules to be stopped if
- * necessary.
- *
- * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
- * can't be stopped (in which case a software reset of the ISP is probably
- * necessary).
- */
-static int isp_pipeline_disable(struct isp_pipeline *pipe)
-{
- struct isp_device *isp = pipe->output->isp;
- struct media_entity *entity;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
- int failure = 0;
- int ret;
-
- /*
- * We need to stop all the modules after CCDC first or they'll
- * never stop since they may not get a full frame from CCDC.
- */
- entity = &pipe->output->video.entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- pad = media_entity_remote_source(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
-
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
-
- if (subdev == &isp->isp_ccdc.subdev) {
- v4l2_subdev_call(&isp->isp_aewb.subdev,
- video, s_stream, 0);
- v4l2_subdev_call(&isp->isp_af.subdev,
- video, s_stream, 0);
- v4l2_subdev_call(&isp->isp_hist.subdev,
- video, s_stream, 0);
- }
-
- v4l2_subdev_call(subdev, video, s_stream, 0);
-
- if (subdev == &isp->isp_res.subdev)
- ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
- else if (subdev == &isp->isp_prev.subdev)
- ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
- else if (subdev == &isp->isp_ccdc.subdev)
- ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
- else
- ret = 0;
-
- if (ret) {
- dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
- /* If the entity failed to stopped, assume it has
- * crashed. Mark it as such, the ISP will be reset when
- * applications will release it.
- */
- isp->crashed |= 1U << subdev->entity.id;
- failure = -ETIMEDOUT;
- }
- }
-
- return failure;
-}
-
-/*
- * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline
- * @pipe: ISP pipeline
- * @state: Stream state (stopped, single shot or continuous)
- *
- * Set the pipeline to the given stream state. Pipelines can be started in
- * single-shot or continuous mode.
- *
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise. The pipeline state is not updated when the operation
- * fails, except when stopping the pipeline.
- */
-int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
- enum isp_pipeline_stream_state state)
-{
- int ret;
-
- if (state == ISP_PIPELINE_STREAM_STOPPED)
- ret = isp_pipeline_disable(pipe);
- else
- ret = isp_pipeline_enable(pipe, state);
-
- if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED)
- pipe->stream_state = state;
-
- return ret;
-}
-
-/*
- * isp_pipeline_resume - Resume streaming on a pipeline
- * @pipe: ISP pipeline
- *
- * Resume video output and input and re-enable pipeline.
- */
-static void isp_pipeline_resume(struct isp_pipeline *pipe)
-{
- int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT;
-
- omap3isp_video_resume(pipe->output, !singleshot);
- if (singleshot)
- omap3isp_video_resume(pipe->input, 0);
- isp_pipeline_enable(pipe, pipe->stream_state);
-}
-
-/*
- * isp_pipeline_suspend - Suspend streaming on a pipeline
- * @pipe: ISP pipeline
- *
- * Suspend pipeline.
- */
-static void isp_pipeline_suspend(struct isp_pipeline *pipe)
-{
- isp_pipeline_disable(pipe);
-}
-
-/*
- * isp_pipeline_is_last - Verify if entity has an enabled link to the output
- * video node
- * @me: ISP module's media entity
- *
- * Returns 1 if the entity has an enabled link to the output video node or 0
- * otherwise. It's true only while pipeline can have no more than one output
- * node.
- */
-static int isp_pipeline_is_last(struct media_entity *me)
-{
- struct isp_pipeline *pipe;
- struct media_pad *pad;
-
- if (!me->pipe)
- return 0;
- pipe = to_isp_pipeline(me);
- if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
- pad = media_entity_remote_source(&pipe->output->pad);
- return pad->entity == me;
-}
-
-/*
- * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module
- * @me: ISP module's media entity
- *
- * Suspend the whole pipeline if module's entity has an enabled link to the
- * output video node. It works only while pipeline can have no more than one
- * output node.
- */
-static void isp_suspend_module_pipeline(struct media_entity *me)
-{
- if (isp_pipeline_is_last(me))
- isp_pipeline_suspend(to_isp_pipeline(me));
-}
-
-/*
- * isp_resume_module_pipeline - Resume pipeline to which belongs the module
- * @me: ISP module's media entity
- *
- * Resume the whole pipeline if module's entity has an enabled link to the
- * output video node. It works only while pipeline can have no more than one
- * output node.
- */
-static void isp_resume_module_pipeline(struct media_entity *me)
-{
- if (isp_pipeline_is_last(me))
- isp_pipeline_resume(to_isp_pipeline(me));
-}
-
-/*
- * isp_suspend_modules - Suspend ISP submodules.
- * @isp: OMAP3 ISP device
- *
- * Returns 0 if suspend left in idle state all the submodules properly,
- * or returns 1 if a general Reset is required to suspend the submodules.
- */
-static int isp_suspend_modules(struct isp_device *isp)
-{
- unsigned long timeout;
-
- omap3isp_stat_suspend(&isp->isp_aewb);
- omap3isp_stat_suspend(&isp->isp_af);
- omap3isp_stat_suspend(&isp->isp_hist);
- isp_suspend_module_pipeline(&isp->isp_res.subdev.entity);
- isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity);
- isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity);
- isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity);
- isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity);
-
- timeout = jiffies + ISP_STOP_TIMEOUT;
- while (omap3isp_stat_busy(&isp->isp_af)
- || omap3isp_stat_busy(&isp->isp_aewb)
- || omap3isp_stat_busy(&isp->isp_hist)
- || omap3isp_preview_busy(&isp->isp_prev)
- || omap3isp_resizer_busy(&isp->isp_res)
- || omap3isp_ccdc_busy(&isp->isp_ccdc)) {
- if (time_after(jiffies, timeout)) {
- dev_info(isp->dev, "can't stop modules.\n");
- return 1;
- }
- msleep(1);
- }
-
- return 0;
-}
-
-/*
- * isp_resume_modules - Resume ISP submodules.
- * @isp: OMAP3 ISP device
- */
-static void isp_resume_modules(struct isp_device *isp)
-{
- omap3isp_stat_resume(&isp->isp_aewb);
- omap3isp_stat_resume(&isp->isp_af);
- omap3isp_stat_resume(&isp->isp_hist);
- isp_resume_module_pipeline(&isp->isp_res.subdev.entity);
- isp_resume_module_pipeline(&isp->isp_prev.subdev.entity);
- isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity);
- isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity);
- isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity);
-}
-
-/*
- * isp_reset - Reset ISP with a timeout wait for idle.
- * @isp: OMAP3 ISP device
- */
-static int isp_reset(struct isp_device *isp)
-{
- unsigned long timeout = 0;
-
- isp_reg_writel(isp,
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
- | ISP_SYSCONFIG_SOFTRESET,
- OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
- while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN,
- ISP_SYSSTATUS) & 0x1)) {
- if (timeout++ > 10000) {
- dev_alert(isp->dev, "cannot reset ISP\n");
- return -ETIMEDOUT;
- }
- udelay(1);
- }
-
- isp->crashed = 0;
- return 0;
-}
-
-/*
- * isp_save_context - Saves the values of the ISP module registers.
- * @isp: OMAP3 ISP device
- * @reg_list: Structure containing pairs of register address and value to
- * modify on OMAP.
- */
-static void
-isp_save_context(struct isp_device *isp, struct isp_reg *reg_list)
-{
- struct isp_reg *next = reg_list;
-
- for (; next->reg != ISP_TOK_TERM; next++)
- next->val = isp_reg_readl(isp, next->mmio_range, next->reg);
-}
-
-/*
- * isp_restore_context - Restores the values of the ISP module registers.
- * @isp: OMAP3 ISP device
- * @reg_list: Structure containing pairs of register address and value to
- * modify on OMAP.
- */
-static void
-isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list)
-{
- struct isp_reg *next = reg_list;
-
- for (; next->reg != ISP_TOK_TERM; next++)
- isp_reg_writel(isp, next->val, next->mmio_range, next->reg);
-}
-
-/*
- * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
- * @isp: OMAP3 ISP device
- *
- * Routine for saving the context of each module in the ISP.
- * CCDC, HIST, H3A, PREV, RESZ and MMU.
- */
-static void isp_save_ctx(struct isp_device *isp)
-{
- isp_save_context(isp, isp_reg_list);
- omap_iommu_save_ctx(isp->dev);
-}
-
-/*
- * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
- * @isp: OMAP3 ISP device
- *
- * Routine for restoring the context of each module in the ISP.
- * CCDC, HIST, H3A, PREV, RESZ and MMU.
- */
-static void isp_restore_ctx(struct isp_device *isp)
-{
- isp_restore_context(isp, isp_reg_list);
- omap_iommu_restore_ctx(isp->dev);
- omap3isp_ccdc_restore_context(isp);
- omap3isp_preview_restore_context(isp);
-}
-
-/* -----------------------------------------------------------------------------
- * SBL resources management
- */
-#define OMAP3_ISP_SBL_READ (OMAP3_ISP_SBL_CSI1_READ | \
- OMAP3_ISP_SBL_CCDC_LSC_READ | \
- OMAP3_ISP_SBL_PREVIEW_READ | \
- OMAP3_ISP_SBL_RESIZER_READ)
-#define OMAP3_ISP_SBL_WRITE (OMAP3_ISP_SBL_CSI1_WRITE | \
- OMAP3_ISP_SBL_CSI2A_WRITE | \
- OMAP3_ISP_SBL_CSI2C_WRITE | \
- OMAP3_ISP_SBL_CCDC_WRITE | \
- OMAP3_ISP_SBL_PREVIEW_WRITE)
-
-void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res)
-{
- u32 sbl = 0;
-
- isp->sbl_resources |= res;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)
- sbl |= ISPCTRL_SBL_SHARED_RPORTA;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)
- sbl |= ISPCTRL_SBL_SHARED_RPORTB;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)
- sbl |= ISPCTRL_SBL_SHARED_WPORTC;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)
- sbl |= ISPCTRL_SBL_WR0_RAM_EN;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE)
- sbl |= ISPCTRL_SBL_WR1_RAM_EN;
-
- if (isp->sbl_resources & OMAP3_ISP_SBL_READ)
- sbl |= ISPCTRL_SBL_RD_RAM_EN;
-
- isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
-}
-
-void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res)
-{
- u32 sbl = 0;
-
- isp->sbl_resources &= ~res;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ))
- sbl |= ISPCTRL_SBL_SHARED_RPORTA;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ))
- sbl |= ISPCTRL_SBL_SHARED_RPORTB;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE))
- sbl |= ISPCTRL_SBL_SHARED_WPORTC;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE))
- sbl |= ISPCTRL_SBL_WR0_RAM_EN;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE))
- sbl |= ISPCTRL_SBL_WR1_RAM_EN;
-
- if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ))
- sbl |= ISPCTRL_SBL_RD_RAM_EN;
-
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
-}
-
-/*
- * isp_module_sync_idle - Helper to sync module with its idle state
- * @me: ISP submodule's media entity
- * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
- * @stopping: flag which tells module wants to stop
- *
- * This function checks if ISP submodule needs to wait for next interrupt. If
- * yes, makes the caller to sleep while waiting for such event.
- */
-int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
- atomic_t *stopping)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(me);
-
- if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED ||
- (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT &&
- !isp_pipeline_ready(pipe)))
- return 0;
-
- /*
- * atomic_set() doesn't include memory barrier on ARM platform for SMP
- * scenario. We'll call it here to avoid race conditions.
- */
- atomic_set(stopping, 1);
- smp_mb();
-
- /*
- * If module is the last one, it's writing to memory. In this case,
- * it's necessary to check if the module is already paused due to
- * DMA queue underrun or if it has to wait for next interrupt to be
- * idle.
- * If it isn't the last one, the function won't sleep but *stopping
- * will still be set to warn next submodule caller's interrupt the
- * module wants to be idle.
- */
- if (isp_pipeline_is_last(me)) {
- struct isp_video *video = pipe->output;
- unsigned long flags;
- spin_lock_irqsave(&video->queue->irqlock, flags);
- if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
- spin_unlock_irqrestore(&video->queue->irqlock, flags);
- atomic_set(stopping, 0);
- smp_mb();
- return 0;
- }
- spin_unlock_irqrestore(&video->queue->irqlock, flags);
- if (!wait_event_timeout(*wait, !atomic_read(stopping),
- msecs_to_jiffies(1000))) {
- atomic_set(stopping, 0);
- smp_mb();
- return -ETIMEDOUT;
- }
- }
-
- return 0;
-}
-
-/*
- * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
- * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
- * @stopping: flag which tells module wants to stop
- *
- * This function checks if ISP submodule was stopping. In case of yes, it
- * notices the caller by setting stopping to 0 and waking up the wait queue.
- * Returns 1 if it was stopping or 0 otherwise.
- */
-int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
- atomic_t *stopping)
-{
- if (atomic_cmpxchg(stopping, 1, 0)) {
- wake_up(wait);
- return 1;
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * Clock management
- */
-
-#define ISPCTRL_CLKS_MASK (ISPCTRL_H3A_CLK_EN | \
- ISPCTRL_HIST_CLK_EN | \
- ISPCTRL_RSZ_CLK_EN | \
- (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \
- (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN))
-
-static void __isp_subclk_update(struct isp_device *isp)
-{
- u32 clk = 0;
-
- if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A)
- clk |= ISPCTRL_H3A_CLK_EN;
-
- if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
- clk |= ISPCTRL_HIST_CLK_EN;
-
- if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER)
- clk |= ISPCTRL_RSZ_CLK_EN;
-
- /* NOTE: For CCDC & Preview submodules, we need to affect internal
- * RAM as well.
- */
- if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
- clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
-
- if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW)
- clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN;
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_CLKS_MASK, clk);
-}
-
-void omap3isp_subclk_enable(struct isp_device *isp,
- enum isp_subclk_resource res)
-{
- isp->subclk_resources |= res;
-
- __isp_subclk_update(isp);
-}
-
-void omap3isp_subclk_disable(struct isp_device *isp,
- enum isp_subclk_resource res)
-{
- isp->subclk_resources &= ~res;
-
- __isp_subclk_update(isp);
-}
-
-/*
- * isp_enable_clocks - Enable ISP clocks
- * @isp: OMAP3 ISP device
- *
- * Return 0 if successful, or clk_enable return value if any of tthem fails.
- */
-static int isp_enable_clocks(struct isp_device *isp)
-{
- int r;
- unsigned long rate;
- int divisor;
-
- /*
- * cam_mclk clock chain:
- * dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk
- *
- * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are
- * set to the same value. Hence the rate set for dpll4_m5
- * has to be twice of what is set on OMAP3430 to get
- * the required value for cam_mclk
- */
- if (cpu_is_omap3630())
- divisor = 1;
- else
- divisor = 2;
-
- r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]);
- if (r) {
- dev_err(isp->dev, "clk_enable cam_ick failed\n");
- goto out_clk_enable_ick;
- }
- r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK],
- CM_CAM_MCLK_HZ/divisor);
- if (r) {
- dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n");
- goto out_clk_enable_mclk;
- }
- r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]);
- if (r) {
- dev_err(isp->dev, "clk_enable cam_mclk failed\n");
- goto out_clk_enable_mclk;
- }
- rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
- if (rate != CM_CAM_MCLK_HZ)
- dev_warn(isp->dev, "unexpected cam_mclk rate:\n"
- " expected : %d\n"
- " actual : %ld\n", CM_CAM_MCLK_HZ, rate);
- r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]);
- if (r) {
- dev_err(isp->dev, "clk_enable csi2_fck failed\n");
- goto out_clk_enable_csi2_fclk;
- }
- return 0;
-
-out_clk_enable_csi2_fclk:
- clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
-out_clk_enable_mclk:
- clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
-out_clk_enable_ick:
- return r;
-}
-
-/*
- * isp_disable_clocks - Disable ISP clocks
- * @isp: OMAP3 ISP device
- */
-static void isp_disable_clocks(struct isp_device *isp)
-{
- clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
- clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
- clk_disable(isp->clock[ISP_CLK_CSI2_FCK]);
-}
-
-static const char *isp_clocks[] = {
- "cam_ick",
- "cam_mclk",
- "dpll4_m5_ck",
- "csi2_96m_fck",
- "l3_ick",
-};
-
-static void isp_put_clocks(struct isp_device *isp)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
- if (isp->clock[i]) {
- clk_put(isp->clock[i]);
- isp->clock[i] = NULL;
- }
- }
-}
-
-static int isp_get_clocks(struct isp_device *isp)
-{
- struct clk *clk;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
- clk = clk_get(isp->dev, isp_clocks[i]);
- if (IS_ERR(clk)) {
- dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
- isp_put_clocks(isp);
- return PTR_ERR(clk);
- }
-
- isp->clock[i] = clk;
- }
-
- return 0;
-}
-
-/*
- * omap3isp_get - Acquire the ISP resource.
- *
- * Initializes the clocks for the first acquire.
- *
- * Increment the reference count on the ISP. If the first reference is taken,
- * enable clocks and power-up all submodules.
- *
- * Return a pointer to the ISP device structure, or NULL if an error occurred.
- */
-struct isp_device *omap3isp_get(struct isp_device *isp)
-{
- struct isp_device *__isp = isp;
-
- if (isp == NULL)
- return NULL;
-
- mutex_lock(&isp->isp_mutex);
- if (isp->ref_count > 0)
- goto out;
-
- if (isp_enable_clocks(isp) < 0) {
- __isp = NULL;
- goto out;
- }
-
- /* We don't want to restore context before saving it! */
- if (isp->has_context)
- isp_restore_ctx(isp);
- else
- isp->has_context = 1;
-
- isp_enable_interrupts(isp);
-
-out:
- if (__isp != NULL)
- isp->ref_count++;
- mutex_unlock(&isp->isp_mutex);
-
- return __isp;
-}
-
-/*
- * omap3isp_put - Release the ISP
- *
- * Decrement the reference count on the ISP. If the last reference is released,
- * power-down all submodules, disable clocks and free temporary buffers.
- */
-void omap3isp_put(struct isp_device *isp)
-{
- if (isp == NULL)
- return;
-
- mutex_lock(&isp->isp_mutex);
- BUG_ON(isp->ref_count == 0);
- if (--isp->ref_count == 0) {
- isp_disable_interrupts(isp);
- if (isp->domain)
- isp_save_ctx(isp);
- /* Reset the ISP if an entity has failed to stop. This is the
- * only way to recover from such conditions.
- */
- if (isp->crashed)
- isp_reset(isp);
- isp_disable_clocks(isp);
- }
- mutex_unlock(&isp->isp_mutex);
-}
-
-/* --------------------------------------------------------------------------
- * Platform device driver
- */
-
-/*
- * omap3isp_print_status - Prints the values of the ISP Control Module registers
- * @isp: OMAP3 ISP device
- */
-#define ISP_PRINT_REGISTER(isp, name)\
- dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name))
-#define SBL_PRINT_REGISTER(isp, name)\
- dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name))
-
-void omap3isp_print_status(struct isp_device *isp)
-{
- dev_dbg(isp->dev, "-------------ISP Register dump--------------\n");
-
- ISP_PRINT_REGISTER(isp, SYSCONFIG);
- ISP_PRINT_REGISTER(isp, SYSSTATUS);
- ISP_PRINT_REGISTER(isp, IRQ0ENABLE);
- ISP_PRINT_REGISTER(isp, IRQ0STATUS);
- ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH);
- ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY);
- ISP_PRINT_REGISTER(isp, CTRL);
- ISP_PRINT_REGISTER(isp, TCTRL_CTRL);
- ISP_PRINT_REGISTER(isp, TCTRL_FRAME);
- ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY);
- ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY);
- ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY);
- ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH);
- ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH);
- ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH);
-
- SBL_PRINT_REGISTER(isp, PCR);
- SBL_PRINT_REGISTER(isp, SDR_REQ_EXP);
-
- dev_dbg(isp->dev, "--------------------------------------------\n");
-}
-
-#ifdef CONFIG_PM
-
-/*
- * Power management support.
- *
- * As the ISP can't properly handle an input video stream interruption on a non
- * frame boundary, the ISP pipelines need to be stopped before sensors get
- * suspended. However, as suspending the sensors can require a running clock,
- * which can be provided by the ISP, the ISP can't be completely suspended
- * before the sensor.
- *
- * To solve this problem power management support is split into prepare/complete
- * and suspend/resume operations. The pipelines are stopped in prepare() and the
- * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in
- * resume(), and the the pipelines are restarted in complete().
- *
- * TODO: PM dependencies between the ISP and sensors are not modeled explicitly
- * yet.
- */
-static int isp_pm_prepare(struct device *dev)
-{
- struct isp_device *isp = dev_get_drvdata(dev);
- int reset;
-
- WARN_ON(mutex_is_locked(&isp->isp_mutex));
-
- if (isp->ref_count == 0)
- return 0;
-
- reset = isp_suspend_modules(isp);
- isp_disable_interrupts(isp);
- isp_save_ctx(isp);
- if (reset)
- isp_reset(isp);
-
- return 0;
-}
-
-static int isp_pm_suspend(struct device *dev)
-{
- struct isp_device *isp = dev_get_drvdata(dev);
-
- WARN_ON(mutex_is_locked(&isp->isp_mutex));
-
- if (isp->ref_count)
- isp_disable_clocks(isp);
-
- return 0;
-}
-
-static int isp_pm_resume(struct device *dev)
-{
- struct isp_device *isp = dev_get_drvdata(dev);
-
- if (isp->ref_count == 0)
- return 0;
-
- return isp_enable_clocks(isp);
-}
-
-static void isp_pm_complete(struct device *dev)
-{
- struct isp_device *isp = dev_get_drvdata(dev);
-
- if (isp->ref_count == 0)
- return;
-
- isp_restore_ctx(isp);
- isp_enable_interrupts(isp);
- isp_resume_modules(isp);
-}
-
-#else
-
-#define isp_pm_prepare NULL
-#define isp_pm_suspend NULL
-#define isp_pm_resume NULL
-#define isp_pm_complete NULL
-
-#endif /* CONFIG_PM */
-
-static void isp_unregister_entities(struct isp_device *isp)
-{
- omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
- omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
- omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
- omap3isp_preview_unregister_entities(&isp->isp_prev);
- omap3isp_resizer_unregister_entities(&isp->isp_res);
- omap3isp_stat_unregister_entities(&isp->isp_aewb);
- omap3isp_stat_unregister_entities(&isp->isp_af);
- omap3isp_stat_unregister_entities(&isp->isp_hist);
-
- v4l2_device_unregister(&isp->v4l2_dev);
- media_device_unregister(&isp->media_dev);
-}
-
-/*
- * isp_register_subdev_group - Register a group of subdevices
- * @isp: OMAP3 ISP device
- * @board_info: I2C subdevs board information array
- *
- * Register all I2C subdevices in the board_info array. The array must be
- * terminated by a NULL entry, and the first entry must be the sensor.
- *
- * Return a pointer to the sensor media entity if it has been successfully
- * registered, or NULL otherwise.
- */
-static struct v4l2_subdev *
-isp_register_subdev_group(struct isp_device *isp,
- struct isp_subdev_i2c_board_info *board_info)
-{
- struct v4l2_subdev *sensor = NULL;
- unsigned int first;
-
- if (board_info->board_info == NULL)
- return NULL;
-
- for (first = 1; board_info->board_info; ++board_info, first = 0) {
- struct v4l2_subdev *subdev;
- struct i2c_adapter *adapter;
-
- adapter = i2c_get_adapter(board_info->i2c_adapter_id);
- if (adapter == NULL) {
- printk(KERN_ERR "%s: Unable to get I2C adapter %d for "
- "device %s\n", __func__,
- board_info->i2c_adapter_id,
- board_info->board_info->type);
- continue;
- }
-
- subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
- board_info->board_info, NULL);
- if (subdev == NULL) {
- printk(KERN_ERR "%s: Unable to register subdev %s\n",
- __func__, board_info->board_info->type);
- continue;
- }
-
- if (first)
- sensor = subdev;
- }
-
- return sensor;
-}
-
-static int isp_register_entities(struct isp_device *isp)
-{
- struct isp_platform_data *pdata = isp->pdata;
- struct isp_v4l2_subdevs_group *subdevs;
- int ret;
-
- isp->media_dev.dev = isp->dev;
- strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
- sizeof(isp->media_dev.model));
- isp->media_dev.hw_revision = isp->revision;
- isp->media_dev.link_notify = isp_pipeline_link_notify;
- ret = media_device_register(&isp->media_dev);
- if (ret < 0) {
- printk(KERN_ERR "%s: Media device registration failed (%d)\n",
- __func__, ret);
- return ret;
- }
-
- isp->v4l2_dev.mdev = &isp->media_dev;
- ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
- if (ret < 0) {
- printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
- __func__, ret);
- goto done;
- }
-
- /* Register internal entities */
- ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_preview_register_entities(&isp->isp_prev,
- &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev);
- if (ret < 0)
- goto done;
-
- /* Register external entities */
- for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
- struct v4l2_subdev *sensor;
- struct media_entity *input;
- unsigned int flags;
- unsigned int pad;
-
- sensor = isp_register_subdev_group(isp, subdevs->subdevs);
- if (sensor == NULL)
- continue;
-
- sensor->host_priv = subdevs;
-
- /* Connect the sensor to the correct interface module. Parallel
- * sensors are connected directly to the CCDC, while serial
- * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
- * through CSIPHY1 or CSIPHY2.
- */
- switch (subdevs->interface) {
- case ISP_INTERFACE_PARALLEL:
- input = &isp->isp_ccdc.subdev.entity;
- pad = CCDC_PAD_SINK;
- flags = 0;
- break;
-
- case ISP_INTERFACE_CSI2A_PHY2:
- input = &isp->isp_csi2a.subdev.entity;
- pad = CSI2_PAD_SINK;
- flags = MEDIA_LNK_FL_IMMUTABLE
- | MEDIA_LNK_FL_ENABLED;
- break;
-
- case ISP_INTERFACE_CCP2B_PHY1:
- case ISP_INTERFACE_CCP2B_PHY2:
- input = &isp->isp_ccp2.subdev.entity;
- pad = CCP2_PAD_SINK;
- flags = 0;
- break;
-
- case ISP_INTERFACE_CSI2C_PHY1:
- input = &isp->isp_csi2c.subdev.entity;
- pad = CSI2_PAD_SINK;
- flags = MEDIA_LNK_FL_IMMUTABLE
- | MEDIA_LNK_FL_ENABLED;
- break;
-
- default:
- printk(KERN_ERR "%s: invalid interface type %u\n",
- __func__, subdevs->interface);
- ret = -EINVAL;
- goto done;
- }
-
- ret = media_entity_create_link(&sensor->entity, 0, input, pad,
- flags);
- if (ret < 0)
- goto done;
- }
-
- ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
-
-done:
- if (ret < 0)
- isp_unregister_entities(isp);
-
- return ret;
-}
-
-static void isp_cleanup_modules(struct isp_device *isp)
-{
- omap3isp_h3a_aewb_cleanup(isp);
- omap3isp_h3a_af_cleanup(isp);
- omap3isp_hist_cleanup(isp);
- omap3isp_resizer_cleanup(isp);
- omap3isp_preview_cleanup(isp);
- omap3isp_ccdc_cleanup(isp);
- omap3isp_ccp2_cleanup(isp);
- omap3isp_csi2_cleanup(isp);
-}
-
-static int isp_initialize_modules(struct isp_device *isp)
-{
- int ret;
-
- ret = omap3isp_csiphy_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "CSI PHY initialization failed\n");
- goto error_csiphy;
- }
-
- ret = omap3isp_csi2_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "CSI2 initialization failed\n");
- goto error_csi2;
- }
-
- ret = omap3isp_ccp2_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "CCP2 initialization failed\n");
- goto error_ccp2;
- }
-
- ret = omap3isp_ccdc_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "CCDC initialization failed\n");
- goto error_ccdc;
- }
-
- ret = omap3isp_preview_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "Preview initialization failed\n");
- goto error_preview;
- }
-
- ret = omap3isp_resizer_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "Resizer initialization failed\n");
- goto error_resizer;
- }
-
- ret = omap3isp_hist_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "Histogram initialization failed\n");
- goto error_hist;
- }
-
- ret = omap3isp_h3a_aewb_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "H3A AEWB initialization failed\n");
- goto error_h3a_aewb;
- }
-
- ret = omap3isp_h3a_af_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "H3A AF initialization failed\n");
- goto error_h3a_af;
- }
-
- /* Connect the submodules. */
- ret = media_entity_create_link(
- &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_aewb.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_af.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_hist.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- return 0;
-
-error_link:
- omap3isp_h3a_af_cleanup(isp);
-error_h3a_af:
- omap3isp_h3a_aewb_cleanup(isp);
-error_h3a_aewb:
- omap3isp_hist_cleanup(isp);
-error_hist:
- omap3isp_resizer_cleanup(isp);
-error_resizer:
- omap3isp_preview_cleanup(isp);
-error_preview:
- omap3isp_ccdc_cleanup(isp);
-error_ccdc:
- omap3isp_ccp2_cleanup(isp);
-error_ccp2:
- omap3isp_csi2_cleanup(isp);
-error_csi2:
-error_csiphy:
- return ret;
-}
-
-/*
- * isp_remove - Remove ISP platform device
- * @pdev: Pointer to ISP platform device
- *
- * Always returns 0.
- */
-static int __devexit isp_remove(struct platform_device *pdev)
-{
- struct isp_device *isp = platform_get_drvdata(pdev);
- int i;
-
- isp_unregister_entities(isp);
- isp_cleanup_modules(isp);
-
- omap3isp_get(isp);
- iommu_detach_device(isp->domain, &pdev->dev);
- iommu_domain_free(isp->domain);
- isp->domain = NULL;
- omap3isp_put(isp);
-
- free_irq(isp->irq_num, isp);
- isp_put_clocks(isp);
-
- for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp->mmio_base[i]) {
- iounmap(isp->mmio_base[i]);
- isp->mmio_base[i] = NULL;
- }
-
- if (isp->mmio_base_phys[i]) {
- release_mem_region(isp->mmio_base_phys[i],
- isp->mmio_size[i]);
- isp->mmio_base_phys[i] = 0;
- }
- }
-
- regulator_put(isp->isp_csiphy1.vdd);
- regulator_put(isp->isp_csiphy2.vdd);
- kfree(isp);
-
- return 0;
-}
-
-static int isp_map_mem_resource(struct platform_device *pdev,
- struct isp_device *isp,
- enum isp_mem_resources res)
-{
- struct resource *mem;
-
- /* request the mem region for the camera registers */
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
- if (!mem) {
- dev_err(isp->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
- if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
- dev_err(isp->dev,
- "cannot reserve camera register I/O region\n");
- return -ENODEV;
- }
- isp->mmio_base_phys[res] = mem->start;
- isp->mmio_size[res] = resource_size(mem);
-
- /* map the region */
- isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
- isp->mmio_size[res]);
- if (!isp->mmio_base[res]) {
- dev_err(isp->dev, "cannot map camera register I/O region\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*
- * isp_probe - Probe ISP platform device
- * @pdev: Pointer to ISP platform device
- *
- * Returns 0 if successful,
- * -ENOMEM if no memory available,
- * -ENODEV if no platform device resources found
- * or no space for remapping registers,
- * -EINVAL if couldn't install ISR,
- * or clk_get return error value.
- */
-static int __devinit isp_probe(struct platform_device *pdev)
-{
- struct isp_platform_data *pdata = pdev->dev.platform_data;
- struct isp_device *isp;
- int ret;
- int i, m;
-
- if (pdata == NULL)
- return -EINVAL;
-
- isp = kzalloc(sizeof(*isp), GFP_KERNEL);
- if (!isp) {
- dev_err(&pdev->dev, "could not allocate memory\n");
- return -ENOMEM;
- }
-
- isp->autoidle = autoidle;
- isp->platform_cb.set_xclk = isp_set_xclk;
-
- mutex_init(&isp->isp_mutex);
- spin_lock_init(&isp->stat_lock);
-
- isp->dev = &pdev->dev;
- isp->pdata = pdata;
- isp->ref_count = 0;
-
- isp->raw_dmamask = DMA_BIT_MASK(32);
- isp->dev->dma_mask = &isp->raw_dmamask;
- isp->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
- platform_set_drvdata(pdev, isp);
-
- /* Regulators */
- isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
- isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
-
- /* Clocks */
- ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
- if (ret < 0)
- goto error;
-
- ret = isp_get_clocks(isp);
- if (ret < 0)
- goto error;
-
- if (omap3isp_get(isp) == NULL)
- goto error;
-
- ret = isp_reset(isp);
- if (ret < 0)
- goto error_isp;
-
- /* Memory resources */
- isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
- dev_info(isp->dev, "Revision %d.%d found\n",
- (isp->revision & 0xf0) >> 4, isp->revision & 0x0f);
-
- for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
- if (isp->revision == isp_res_maps[m].isp_rev)
- break;
-
- if (m == ARRAY_SIZE(isp_res_maps)) {
- dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n",
- (isp->revision & 0xf0) >> 4, isp->revision & 0xf);
- ret = -ENODEV;
- goto error_isp;
- }
-
- for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp_res_maps[m].map & 1 << i) {
- ret = isp_map_mem_resource(pdev, isp, i);
- if (ret)
- goto error_isp;
- }
- }
-
- isp->domain = iommu_domain_alloc(pdev->dev.bus);
- if (!isp->domain) {
- dev_err(isp->dev, "can't alloc iommu domain\n");
- ret = -ENOMEM;
- goto error_isp;
- }
-
- ret = iommu_attach_device(isp->domain, &pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
- goto free_domain;
- }
-
- /* Interrupt */
- isp->irq_num = platform_get_irq(pdev, 0);
- if (isp->irq_num <= 0) {
- dev_err(isp->dev, "No IRQ resource\n");
- ret = -ENODEV;
- goto detach_dev;
- }
-
- if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
- dev_err(isp->dev, "Unable to request IRQ\n");
- ret = -EINVAL;
- goto detach_dev;
- }
-
- /* Entities */
- ret = isp_initialize_modules(isp);
- if (ret < 0)
- goto error_irq;
-
- ret = isp_register_entities(isp);
- if (ret < 0)
- goto error_modules;
-
- isp_power_settings(isp, 1);
- omap3isp_put(isp);
-
- return 0;
-
-error_modules:
- isp_cleanup_modules(isp);
-error_irq:
- free_irq(isp->irq_num, isp);
-detach_dev:
- iommu_detach_device(isp->domain, &pdev->dev);
-free_domain:
- iommu_domain_free(isp->domain);
-error_isp:
- omap3isp_put(isp);
-error:
- isp_put_clocks(isp);
-
- for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp->mmio_base[i]) {
- iounmap(isp->mmio_base[i]);
- isp->mmio_base[i] = NULL;
- }
-
- if (isp->mmio_base_phys[i]) {
- release_mem_region(isp->mmio_base_phys[i],
- isp->mmio_size[i]);
- isp->mmio_base_phys[i] = 0;
- }
- }
- regulator_put(isp->isp_csiphy2.vdd);
- regulator_put(isp->isp_csiphy1.vdd);
- platform_set_drvdata(pdev, NULL);
-
- mutex_destroy(&isp->isp_mutex);
- kfree(isp);
-
- return ret;
-}
-
-static const struct dev_pm_ops omap3isp_pm_ops = {
- .prepare = isp_pm_prepare,
- .suspend = isp_pm_suspend,
- .resume = isp_pm_resume,
- .complete = isp_pm_complete,
-};
-
-static struct platform_device_id omap3isp_id_table[] = {
- { "omap3isp", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
-
-static struct platform_driver omap3isp_driver = {
- .probe = isp_probe,
- .remove = __devexit_p(isp_remove),
- .id_table = omap3isp_id_table,
- .driver = {
- .owner = THIS_MODULE,
- .name = "omap3isp",
- .pm = &omap3isp_pm_ops,
- },
-};
-
-module_platform_driver(omap3isp_driver);
-
-MODULE_AUTHOR("Nokia Corporation");
-MODULE_DESCRIPTION("TI OMAP3 ISP driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION);
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
deleted file mode 100644
index fc7af3e32efd..000000000000
--- a/drivers/media/video/omap3isp/isp.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * isp.h
- *
- * TI OMAP3 ISP - Core
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 OMAP3_ISP_CORE_H
-#define OMAP3_ISP_CORE_H
-
-#include <media/omap3isp.h>
-#include <media/v4l2-device.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
-#include <linux/iommu.h>
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-
-#include "ispstat.h"
-#include "ispccdc.h"
-#include "ispreg.h"
-#include "ispresizer.h"
-#include "isppreview.h"
-#include "ispcsiphy.h"
-#include "ispcsi2.h"
-#include "ispccp2.h"
-
-#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
-
-#define ISP_TOK_TERM 0xFFFFFFFF /*
- * terminating token for ISP
- * modules reg list
- */
-#define to_isp_device(ptr_module) \
- container_of(ptr_module, struct isp_device, isp_##ptr_module)
-#define to_device(ptr_module) \
- (to_isp_device(ptr_module)->dev)
-
-enum isp_mem_resources {
- OMAP3_ISP_IOMEM_MAIN,
- OMAP3_ISP_IOMEM_CCP2,
- OMAP3_ISP_IOMEM_CCDC,
- OMAP3_ISP_IOMEM_HIST,
- OMAP3_ISP_IOMEM_H3A,
- OMAP3_ISP_IOMEM_PREV,
- OMAP3_ISP_IOMEM_RESZ,
- OMAP3_ISP_IOMEM_SBL,
- OMAP3_ISP_IOMEM_CSI2A_REGS1,
- OMAP3_ISP_IOMEM_CSIPHY2,
- OMAP3_ISP_IOMEM_CSI2A_REGS2,
- OMAP3_ISP_IOMEM_CSI2C_REGS1,
- OMAP3_ISP_IOMEM_CSIPHY1,
- OMAP3_ISP_IOMEM_CSI2C_REGS2,
- OMAP3_ISP_IOMEM_LAST
-};
-
-enum isp_sbl_resource {
- OMAP3_ISP_SBL_CSI1_READ = 0x1,
- OMAP3_ISP_SBL_CSI1_WRITE = 0x2,
- OMAP3_ISP_SBL_CSI2A_WRITE = 0x4,
- OMAP3_ISP_SBL_CSI2C_WRITE = 0x8,
- OMAP3_ISP_SBL_CCDC_LSC_READ = 0x10,
- OMAP3_ISP_SBL_CCDC_WRITE = 0x20,
- OMAP3_ISP_SBL_PREVIEW_READ = 0x40,
- OMAP3_ISP_SBL_PREVIEW_WRITE = 0x80,
- OMAP3_ISP_SBL_RESIZER_READ = 0x100,
- OMAP3_ISP_SBL_RESIZER_WRITE = 0x200,
-};
-
-enum isp_subclk_resource {
- OMAP3_ISP_SUBCLK_CCDC = (1 << 0),
- OMAP3_ISP_SUBCLK_H3A = (1 << 1),
- OMAP3_ISP_SUBCLK_HIST = (1 << 2),
- OMAP3_ISP_SUBCLK_PREVIEW = (1 << 3),
- OMAP3_ISP_SUBCLK_RESIZER = (1 << 4),
-};
-
-/* ISP: OMAP 34xx ES 1.0 */
-#define ISP_REVISION_1_0 0x10
-/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */
-#define ISP_REVISION_2_0 0x20
-/* ISP2P: OMAP 36xx */
-#define ISP_REVISION_15_0 0xF0
-
-/*
- * struct isp_res_mapping - Map ISP io resources to ISP revision.
- * @isp_rev: ISP_REVISION_x_x
- * @map: bitmap for enum isp_mem_resources
- */
-struct isp_res_mapping {
- u32 isp_rev;
- u32 map;
-};
-
-/*
- * struct isp_reg - Structure for ISP register values.
- * @reg: 32-bit Register address.
- * @val: 32-bit Register value.
- */
-struct isp_reg {
- enum isp_mem_resources mmio_range;
- u32 reg;
- u32 val;
-};
-
-struct isp_platform_callback {
- u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
- int (*csiphy_config)(struct isp_csiphy *phy,
- struct isp_csiphy_dphy_cfg *dphy,
- struct isp_csiphy_lanes_cfg *lanes);
-};
-
-/*
- * struct isp_device - ISP device structure.
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @revision: Stores current ISP module revision.
- * @irq_num: Currently used IRQ number.
- * @mmio_base: Array with kernel base addresses for ioremapped ISP register
- * regions.
- * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
- * regions.
- * @mmio_size: Array with ISP register regions size in bytes.
- * @raw_dmamask: Raw DMA mask
- * @stat_lock: Spinlock for handling statistics
- * @isp_mutex: Mutex for serializing requests to ISP.
- * @crashed: Bitmask of crashed entities (indexed by entity ID)
- * @has_context: Context has been saved at least once and can be restored.
- * @ref_count: Reference count for handling multiple ISP requests.
- * @cam_ick: Pointer to camera interface clock structure.
- * @cam_mclk: Pointer to camera functional clock structure.
- * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
- * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
- * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
- * @irq: Currently attached ISP ISR callbacks information structure.
- * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
- * @isp_hist: Pointer to current settings for ISP Histogram SCM.
- * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
- * White Balance SCM.
- * @isp_res: Pointer to current settings for ISP Resizer.
- * @isp_prev: Pointer to current settings for ISP Preview.
- * @isp_ccdc: Pointer to current settings for ISP CCDC.
- * @iommu: Pointer to requested IOMMU instance for ISP.
- * @platform_cb: ISP driver callback function pointers for platform code
- *
- * This structure is used to store the OMAP ISP Information.
- */
-struct isp_device {
- struct v4l2_device v4l2_dev;
- struct media_device media_dev;
- struct device *dev;
- u32 revision;
-
- /* platform HW resources */
- struct isp_platform_data *pdata;
- unsigned int irq_num;
-
- void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
- unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
- resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
-
- u64 raw_dmamask;
-
- /* ISP Obj */
- spinlock_t stat_lock; /* common lock for statistic drivers */
- struct mutex isp_mutex; /* For handling ref_count field */
- u32 crashed;
- int has_context;
- int ref_count;
- unsigned int autoidle;
- u32 xclk_divisor[2]; /* Two clocks, a and b. */
-#define ISP_CLK_CAM_ICK 0
-#define ISP_CLK_CAM_MCLK 1
-#define ISP_CLK_DPLL4_M5_CK 2
-#define ISP_CLK_CSI2_FCK 3
-#define ISP_CLK_L3_ICK 4
- struct clk *clock[5];
-
- /* ISP modules */
- struct ispstat isp_af;
- struct ispstat isp_aewb;
- struct ispstat isp_hist;
- struct isp_res_device isp_res;
- struct isp_prev_device isp_prev;
- struct isp_ccdc_device isp_ccdc;
- struct isp_csi2_device isp_csi2a;
- struct isp_csi2_device isp_csi2c;
- struct isp_ccp2_device isp_ccp2;
- struct isp_csiphy isp_csiphy1;
- struct isp_csiphy isp_csiphy2;
-
- unsigned int sbl_resources;
- unsigned int subclk_resources;
-
- struct iommu_domain *domain;
-
- struct isp_platform_callback platform_cb;
-};
-
-#define v4l2_dev_to_isp_device(dev) \
- container_of(dev, struct isp_device, v4l2_dev)
-
-void omap3isp_hist_dma_done(struct isp_device *isp);
-
-void omap3isp_flush(struct isp_device *isp);
-
-int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
- atomic_t *stopping);
-
-int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
- atomic_t *stopping);
-
-int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
- enum isp_pipeline_stream_state state);
-void omap3isp_configure_bridge(struct isp_device *isp,
- enum ccdc_input_entity input,
- const struct isp_parallel_platform_data *pdata,
- unsigned int shift);
-
-struct isp_device *omap3isp_get(struct isp_device *isp);
-void omap3isp_put(struct isp_device *isp);
-
-void omap3isp_print_status(struct isp_device *isp);
-
-void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res);
-void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res);
-
-void omap3isp_subclk_enable(struct isp_device *isp,
- enum isp_subclk_resource res);
-void omap3isp_subclk_disable(struct isp_device *isp,
- enum isp_subclk_resource res);
-
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
-
-int omap3isp_register_entities(struct platform_device *pdev,
- struct v4l2_device *v4l2_dev);
-void omap3isp_unregister_entities(struct platform_device *pdev);
-
-/*
- * isp_reg_readl - Read value of an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @isp_mmio_range: Range to which the register offset refers to.
- * @reg_offset: Register offset to read from.
- *
- * Returns an unsigned 32 bit value with the required register contents.
- */
-static inline
-u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
- u32 reg_offset)
-{
- return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
-}
-
-/*
- * isp_reg_writel - Write value to an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @reg_value: 32 bit value to write to the register.
- * @isp_mmio_range: Range to which the register offset refers to.
- * @reg_offset: Register offset to write into.
- */
-static inline
-void isp_reg_writel(struct isp_device *isp, u32 reg_value,
- enum isp_mem_resources isp_mmio_range, u32 reg_offset)
-{
- __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
-}
-
-/*
- * isp_reg_and - Clear individual bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @mmio_range: Range to which the register offset refers to.
- * @reg: Register offset to work on.
- * @clr_bits: 32 bit value which would be cleared in the register.
- */
-static inline
-void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
- u32 reg, u32 clr_bits)
-{
- u32 v = isp_reg_readl(isp, mmio_range, reg);
-
- isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg);
-}
-
-/*
- * isp_reg_set - Set individual bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @mmio_range: Range to which the register offset refers to.
- * @reg: Register offset to work on.
- * @set_bits: 32 bit value which would be set in the register.
- */
-static inline
-void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
- u32 reg, u32 set_bits)
-{
- u32 v = isp_reg_readl(isp, mmio_range, reg);
-
- isp_reg_writel(isp, v | set_bits, mmio_range, reg);
-}
-
-/*
- * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @mmio_range: Range to which the register offset refers to.
- * @reg: Register offset to work on.
- * @clr_bits: 32 bit value which would be cleared in the register.
- * @set_bits: 32 bit value which would be set in the register.
- *
- * The clear operation is done first, and then the set operation.
- */
-static inline
-void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
- u32 reg, u32 clr_bits, u32 set_bits)
-{
- u32 v = isp_reg_readl(isp, mmio_range, reg);
-
- isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg);
-}
-
-static inline enum v4l2_buf_type
-isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad)
-{
- if (pad >= subdev->entity.num_pads)
- return 0;
-
- if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK)
- return V4L2_BUF_TYPE_VIDEO_OUTPUT;
- else
- return V4L2_BUF_TYPE_VIDEO_CAPTURE;
-}
-
-#endif /* OMAP3_ISP_CORE_H */
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
deleted file mode 100644
index f1220d3d4970..000000000000
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ /dev/null
@@ -1,2535 +0,0 @@
-/*
- * ispccdc.c
- *
- * TI OMAP3 ISP - CCDC module
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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/uaccess.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <media/v4l2-event.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "ispccdc.h"
-
-#define CCDC_MIN_WIDTH 32
-#define CCDC_MIN_HEIGHT 32
-
-static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
- unsigned int pad, enum v4l2_subdev_format_whence which);
-
-static const unsigned int ccdc_fmts[] = {
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y12_1X12,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_SRGGB12_1X12,
- V4L2_MBUS_FMT_SBGGR12_1X12,
- V4L2_MBUS_FMT_SGBRG12_1X12,
-};
-
-/*
- * ccdc_print_status - Print current CCDC Module register values.
- * @ccdc: Pointer to ISP CCDC device.
- *
- * Also prints other debug information stored in the CCDC module.
- */
-#define CCDC_PRINT_REGISTER(isp, name)\
- dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
-
-static void ccdc_print_status(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
-
- CCDC_PRINT_REGISTER(isp, PCR);
- CCDC_PRINT_REGISTER(isp, SYN_MODE);
- CCDC_PRINT_REGISTER(isp, HD_VD_WID);
- CCDC_PRINT_REGISTER(isp, PIX_LINES);
- CCDC_PRINT_REGISTER(isp, HORZ_INFO);
- CCDC_PRINT_REGISTER(isp, VERT_START);
- CCDC_PRINT_REGISTER(isp, VERT_LINES);
- CCDC_PRINT_REGISTER(isp, CULLING);
- CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
- CCDC_PRINT_REGISTER(isp, SDOFST);
- CCDC_PRINT_REGISTER(isp, SDR_ADDR);
- CCDC_PRINT_REGISTER(isp, CLAMP);
- CCDC_PRINT_REGISTER(isp, DCSUB);
- CCDC_PRINT_REGISTER(isp, COLPTN);
- CCDC_PRINT_REGISTER(isp, BLKCMP);
- CCDC_PRINT_REGISTER(isp, FPC);
- CCDC_PRINT_REGISTER(isp, FPC_ADDR);
- CCDC_PRINT_REGISTER(isp, VDINT);
- CCDC_PRINT_REGISTER(isp, ALAW);
- CCDC_PRINT_REGISTER(isp, REC656IF);
- CCDC_PRINT_REGISTER(isp, CFG);
- CCDC_PRINT_REGISTER(isp, FMTCFG);
- CCDC_PRINT_REGISTER(isp, FMT_HORZ);
- CCDC_PRINT_REGISTER(isp, FMT_VERT);
- CCDC_PRINT_REGISTER(isp, PRGEVEN0);
- CCDC_PRINT_REGISTER(isp, PRGEVEN1);
- CCDC_PRINT_REGISTER(isp, PRGODD0);
- CCDC_PRINT_REGISTER(isp, PRGODD1);
- CCDC_PRINT_REGISTER(isp, VP_OUT);
- CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
- CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
- CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
- CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
-
- dev_dbg(isp->dev, "--------------------------------------------\n");
-}
-
-/*
- * omap3isp_ccdc_busy - Get busy state of the CCDC.
- * @ccdc: Pointer to ISP CCDC device.
- */
-int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
- ISPCCDC_PCR_BUSY;
-}
-
-/* -----------------------------------------------------------------------------
- * Lens Shading Compensation
- */
-
-/*
- * ccdc_lsc_validate_config - Check that LSC configuration is valid.
- * @ccdc: Pointer to ISP CCDC device.
- * @lsc_cfg: the LSC configuration to check.
- *
- * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
- */
-static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
- struct omap3isp_ccdc_lsc_config *lsc_cfg)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- struct v4l2_mbus_framefmt *format;
- unsigned int paxel_width, paxel_height;
- unsigned int paxel_shift_x, paxel_shift_y;
- unsigned int min_width, min_height, min_size;
- unsigned int input_width, input_height;
-
- paxel_shift_x = lsc_cfg->gain_mode_m;
- paxel_shift_y = lsc_cfg->gain_mode_n;
-
- if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
- (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
- dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
- return -EINVAL;
- }
-
- if (lsc_cfg->offset & 3) {
- dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
- "4\n");
- return -EINVAL;
- }
-
- if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
- dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
- return -EINVAL;
- }
-
- format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- input_width = format->width;
- input_height = format->height;
-
- /* Calculate minimum bytesize for validation */
- paxel_width = 1 << paxel_shift_x;
- min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
- >> paxel_shift_x) + 1;
-
- paxel_height = 1 << paxel_shift_y;
- min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
- >> paxel_shift_y) + 1;
-
- min_size = 4 * min_width * min_height;
- if (min_size > lsc_cfg->size) {
- dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
- return -EINVAL;
- }
- if (lsc_cfg->offset < (min_width * 4)) {
- dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
- return -EINVAL;
- }
- if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
- dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
-{
- isp_reg_writel(to_isp_device(ccdc), addr,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
-}
-
-/*
- * ccdc_lsc_setup_regs - Configures the lens shading compensation module
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
- struct omap3isp_ccdc_lsc_config *cfg)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- int reg;
-
- isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_TABLE_OFFSET);
-
- reg = 0;
- reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
- reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
- reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
- isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
-
- reg = 0;
- reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
- reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
- reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
- reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
- isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_INITIAL);
-}
-
-static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- unsigned int wait;
-
- isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
- OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-
- /* timeout 1 ms */
- for (wait = 0; wait < 1000; wait++) {
- if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
- IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
- isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
- OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- return 0;
- }
-
- rmb();
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
-/*
- * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
- * @ccdc: Pointer to ISP CCDC device.
- * @enable: 0 Disables LSC, 1 Enables LSC.
- */
-static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- const struct v4l2_mbus_framefmt *format =
- __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
- V4L2_SUBDEV_FORMAT_ACTIVE);
-
- if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
- return -EINVAL;
-
- if (enable)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
- ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
-
- if (enable) {
- if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
- ccdc->lsc.state = LSC_STATE_STOPPED;
- dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
- return -ETIMEDOUT;
- }
- ccdc->lsc.state = LSC_STATE_RUNNING;
- } else {
- ccdc->lsc.state = LSC_STATE_STOPPING;
- }
-
- return 0;
-}
-
-static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
- ISPCCDC_LSC_BUSY;
-}
-
-/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
- * @ccdc: Pointer to ISP CCDC device
- * @req: New configuration request
- *
- * context: in_interrupt()
- */
-static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
- struct ispccdc_lsc_config_req *req)
-{
- if (!req->enable)
- return -EINVAL;
-
- if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
- dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
- return -EINVAL;
- }
-
- if (ccdc_lsc_busy(ccdc))
- return -EBUSY;
-
- ccdc_lsc_setup_regs(ccdc, &req->config);
- ccdc_lsc_program_table(ccdc, req->table);
- return 0;
-}
-
-/*
- * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
- * @ccdc: Pointer to ISP CCDC device.
- *
- * Disables LSC, and defers enablement to shadow registers update time.
- */
-static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- /*
- * From OMAP3 TRM: When this event is pending, the module
- * goes into transparent mode (output =input). Normal
- * operation can be resumed at the start of the next frame
- * after:
- * 1) Clearing this event
- * 2) Disabling the LSC module
- * 3) Enabling it
- */
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
- ISPCCDC_LSC_ENABLE);
- ccdc->lsc.state = LSC_STATE_STOPPED;
-}
-
-static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
- struct ispccdc_lsc_config_req *req)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- if (req == NULL)
- return;
-
- if (req->iovm)
- dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
- req->iovm->sgt->nents, DMA_TO_DEVICE);
- if (req->table)
- omap_iommu_vfree(isp->domain, isp->dev, req->table);
- kfree(req);
-}
-
-static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
- struct list_head *queue)
-{
- struct ispccdc_lsc_config_req *req, *n;
- unsigned long flags;
-
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
- list_for_each_entry_safe(req, n, queue, list) {
- list_del(&req->list);
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
- ccdc_lsc_free_request(ccdc, req);
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
- }
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-}
-
-static void ccdc_lsc_free_table_work(struct work_struct *work)
-{
- struct isp_ccdc_device *ccdc;
- struct ispccdc_lsc *lsc;
-
- lsc = container_of(work, struct ispccdc_lsc, table_work);
- ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
-
- ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
-}
-
-/*
- * ccdc_lsc_config - Configure the LSC module from a userspace request
- *
- * Store the request LSC configuration in the LSC engine request pointer. The
- * configuration will be applied to the hardware when the CCDC will be enabled,
- * or at the next LSC interrupt if the CCDC is already running.
- */
-static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
- struct omap3isp_ccdc_update_config *config)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- struct ispccdc_lsc_config_req *req;
- unsigned long flags;
- void *table;
- u16 update;
- int ret;
-
- update = config->update &
- (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
- if (!update)
- return 0;
-
- if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
- dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
- "need to be supplied\n", __func__);
- return -EINVAL;
- }
-
- req = kzalloc(sizeof(*req), GFP_KERNEL);
- if (req == NULL)
- return -ENOMEM;
-
- if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
- if (copy_from_user(&req->config, config->lsc_cfg,
- sizeof(req->config))) {
- ret = -EFAULT;
- goto done;
- }
-
- req->enable = 1;
-
- req->table = omap_iommu_vmalloc(isp->domain, isp->dev, 0,
- req->config.size, IOMMU_FLAG);
- if (IS_ERR_VALUE(req->table)) {
- req->table = 0;
- ret = -ENOMEM;
- goto done;
- }
-
- req->iovm = omap_find_iovm_area(isp->dev, req->table);
- if (req->iovm == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
- req->iovm->sgt->nents, DMA_TO_DEVICE)) {
- ret = -ENOMEM;
- req->iovm = NULL;
- goto done;
- }
-
- dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
- req->iovm->sgt->nents, DMA_TO_DEVICE);
-
- table = omap_da_to_va(isp->dev, req->table);
- if (copy_from_user(table, config->lsc, req->config.size)) {
- ret = -EFAULT;
- goto done;
- }
-
- dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
- req->iovm->sgt->nents, DMA_TO_DEVICE);
- }
-
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
- if (ccdc->lsc.request) {
- list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
- schedule_work(&ccdc->lsc.table_work);
- }
- ccdc->lsc.request = req;
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-
- ret = 0;
-
-done:
- if (ret < 0)
- ccdc_lsc_free_request(ccdc, req);
-
- return ret;
-}
-
-static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
- if (ccdc->lsc.active) {
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
- return 1;
- }
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
- return 0;
-}
-
-static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
-{
- struct ispccdc_lsc *lsc = &ccdc->lsc;
-
- if (lsc->state != LSC_STATE_STOPPED)
- return -EINVAL;
-
- if (lsc->active) {
- list_add_tail(&lsc->active->list, &lsc->free_queue);
- lsc->active = NULL;
- }
-
- if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
- omap3isp_sbl_disable(to_isp_device(ccdc),
- OMAP3_ISP_SBL_CCDC_LSC_READ);
- list_add_tail(&lsc->request->list, &lsc->free_queue);
- lsc->request = NULL;
- goto done;
- }
-
- lsc->active = lsc->request;
- lsc->request = NULL;
- __ccdc_lsc_enable(ccdc, 1);
-
-done:
- if (!list_empty(&lsc->free_queue))
- schedule_work(&lsc->table_work);
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * Parameters configuration
- */
-
-/*
- * ccdc_configure_clamp - Configure optical-black or digital clamping
- * @ccdc: Pointer to ISP CCDC device.
- *
- * The CCDC performs either optical-black or digital clamp. Configure and enable
- * the selected clamp method.
- */
-static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- u32 clamp;
-
- if (ccdc->obclamp) {
- clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
- clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
- clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
- clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
- isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
- } else {
- isp_reg_writel(isp, ccdc->clamp.dcsubval,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
- }
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
- ISPCCDC_CLAMP_CLAMPEN,
- ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
-}
-
-/*
- * ccdc_configure_fpc - Configure Faulty Pixel Correction
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
-
- if (!ccdc->fpc_en)
- return;
-
- isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FPC_ADDR);
- /* The FPNUM field must be set before enabling FPC. */
- isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
- isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
- ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
-}
-
-/*
- * ccdc_configure_black_comp - Configure Black Level Compensation.
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- u32 blcomp;
-
- blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
- blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
- blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
- blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
-
- isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
-}
-
-/*
- * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
- ISPCCDC_SYN_MODE_LPF,
- ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
-}
-
-/*
- * ccdc_configure_alaw - Configure A-law compression.
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- u32 alaw = 0;
-
- switch (ccdc->syncif.datsz) {
- case 8:
- return;
-
- case 10:
- alaw = ISPCCDC_ALAW_GWDI_9_0;
- break;
- case 11:
- alaw = ISPCCDC_ALAW_GWDI_10_1;
- break;
- case 12:
- alaw = ISPCCDC_ALAW_GWDI_11_2;
- break;
- case 13:
- alaw = ISPCCDC_ALAW_GWDI_12_3;
- break;
- }
-
- if (ccdc->alaw)
- alaw |= ISPCCDC_ALAW_CCDTBL;
-
- isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
-}
-
-/*
- * ccdc_config_imgattr - Configure sensor image specific attributes.
- * @ccdc: Pointer to ISP CCDC device.
- * @colptn: Color pattern of the sensor.
- */
-static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
-}
-
-/*
- * ccdc_config - Set CCDC configuration from userspace
- * @ccdc: Pointer to ISP CCDC device.
- * @userspace_add: Structure containing CCDC configuration sent from userspace.
- *
- * Returns 0 if successful, -EINVAL if the pointer to the configuration
- * structure is null, or the copy_from_user function fails to copy user space
- * memory to kernel space memory.
- */
-static int ccdc_config(struct isp_ccdc_device *ccdc,
- struct omap3isp_ccdc_update_config *ccdc_struct)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- unsigned long flags;
-
- spin_lock_irqsave(&ccdc->lock, flags);
- ccdc->shadow_update = 1;
- spin_unlock_irqrestore(&ccdc->lock, flags);
-
- if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
- ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
- ccdc->update |= OMAP3ISP_CCDC_ALAW;
- }
-
- if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
- ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
- ccdc->update |= OMAP3ISP_CCDC_LPF;
- }
-
- if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
- if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
- sizeof(ccdc->clamp))) {
- ccdc->shadow_update = 0;
- return -EFAULT;
- }
-
- ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
- ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
- }
-
- if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
- if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
- sizeof(ccdc->blcomp))) {
- ccdc->shadow_update = 0;
- return -EFAULT;
- }
-
- ccdc->update |= OMAP3ISP_CCDC_BCOMP;
- }
-
- ccdc->shadow_update = 0;
-
- if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
- u32 table_old = 0;
- u32 table_new;
- u32 size;
-
- if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
- return -EBUSY;
-
- ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
-
- if (ccdc->fpc_en) {
- if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
- sizeof(ccdc->fpc)))
- return -EFAULT;
-
- /*
- * table_new must be 64-bytes aligned, but it's
- * already done by omap_iommu_vmalloc().
- */
- size = ccdc->fpc.fpnum * 4;
- table_new = omap_iommu_vmalloc(isp->domain, isp->dev,
- 0, size, IOMMU_FLAG);
- if (IS_ERR_VALUE(table_new))
- return -ENOMEM;
-
- if (copy_from_user(omap_da_to_va(isp->dev, table_new),
- (__force void __user *)
- ccdc->fpc.fpcaddr, size)) {
- omap_iommu_vfree(isp->domain, isp->dev,
- table_new);
- return -EFAULT;
- }
-
- table_old = ccdc->fpc.fpcaddr;
- ccdc->fpc.fpcaddr = table_new;
- }
-
- ccdc_configure_fpc(ccdc);
- if (table_old != 0)
- omap_iommu_vfree(isp->domain, isp->dev, table_old);
- }
-
- return ccdc_lsc_config(ccdc, ccdc_struct);
-}
-
-static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
-{
- if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
- ccdc_configure_alaw(ccdc);
- ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
- }
-
- if (ccdc->update & OMAP3ISP_CCDC_LPF) {
- ccdc_configure_lpf(ccdc);
- ccdc->update &= ~OMAP3ISP_CCDC_LPF;
- }
-
- if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
- ccdc_configure_clamp(ccdc);
- ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
- }
-
- if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
- ccdc_configure_black_comp(ccdc);
- ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
- }
-}
-
-/*
- * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
- * @dev: Pointer to ISP device
- */
-void omap3isp_ccdc_restore_context(struct isp_device *isp)
-{
- struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
-
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
-
- ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
- | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
- ccdc_apply_controls(ccdc);
- ccdc_configure_fpc(ccdc);
-}
-
-/* -----------------------------------------------------------------------------
- * Format- and pipeline-related configuration helpers
- */
-
-/*
- * ccdc_config_vp - Configure the Video Port.
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
- struct isp_device *isp = to_isp_device(ccdc);
- unsigned long l3_ick = pipe->l3_ick;
- unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
- unsigned int div = 0;
- u32 fmtcfg_vp;
-
- fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
- & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
-
- switch (ccdc->syncif.datsz) {
- case 8:
- case 10:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
- break;
- case 11:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
- break;
- case 12:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
- break;
- case 13:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
- break;
- };
-
- if (pipe->input)
- div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
- else if (pipe->external_rate)
- div = l3_ick / pipe->external_rate;
-
- div = clamp(div, 2U, max_div);
- fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
-
- isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-
-/*
- * ccdc_enable_vp - Enable Video Port.
- * @ccdc: Pointer to ISP CCDC device.
- * @enable: 0 Disables VP, 1 Enables VP
- *
- * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
- */
-static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
- ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
-}
-
-/*
- * ccdc_config_outlineoffset - Configure memory saving output line offset
- * @ccdc: Pointer to ISP CCDC device.
- * @offset: Address offset to start a new line. Must be twice the
- * Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- * output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
- *
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
- */
-static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
- u32 offset, u8 oddeven, u8 numlines)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_writel(isp, offset & 0xffff,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
-
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- ISPCCDC_SDOFST_FINV);
-
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- ISPCCDC_SDOFST_FOFST_4L);
-
- switch (oddeven) {
- case EVENEVEN:
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
- break;
- case ODDEVEN:
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
- break;
- case EVENODD:
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
- break;
- case ODDODD:
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
- break;
- default:
- break;
- }
-}
-
-/*
- * ccdc_set_outaddr - Set memory address to save output image
- * @ccdc: Pointer to ISP CCDC device.
- * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
- *
- * Sets the memory address where the output will be saved.
- */
-static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
-}
-
-/*
- * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
- * @ccdc: Pointer to ISP CCDC device.
- * @max_rate: Maximum calculated data rate.
- *
- * Returns in *max_rate less value between calculated and passed
- */
-void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
- unsigned int *max_rate)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
- unsigned int rate;
-
- if (pipe == NULL)
- return;
-
- /*
- * TRM says that for parallel sensors the maximum data rate
- * should be 90% form L3/2 clock, otherwise just L3/2.
- */
- if (ccdc->input == CCDC_INPUT_PARALLEL)
- rate = pipe->l3_ick / 2 * 9 / 10;
- else
- rate = pipe->l3_ick / 2;
-
- *max_rate = min(*max_rate, rate);
-}
-
-/*
- * ccdc_config_sync_if - Set CCDC sync interface configuration
- * @ccdc: Pointer to ISP CCDC device.
- * @syncif: Structure containing the sync parameters like field state, CCDC in
- * master/slave mode, raw/yuv data, polarity of data, field, hs, vs
- * signals.
- */
-static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
- struct ispccdc_syncif *syncif)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_SYN_MODE);
-
- syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
-
- if (syncif->fldstat)
- syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
-
- syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK;
- switch (syncif->datsz) {
- case 8:
- syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
- break;
- case 10:
- syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
- break;
- case 11:
- syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
- break;
- case 12:
- syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
- break;
- };
-
- if (syncif->fldmode)
- syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
-
- if (syncif->datapol)
- syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
-
- if (syncif->fldpol)
- syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
-
- if (syncif->hdpol)
- syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
-
- if (syncif->vdpol)
- syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
-
- if (syncif->ccdc_mastermode) {
- syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
- isp_reg_writel(isp,
- syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
- | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_HD_VD_WID);
-
- isp_reg_writel(isp,
- syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
- | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_PIX_LINES);
- } else
- syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
- ISPCCDC_SYN_MODE_VDHDOUT);
-
- isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
-
- if (!syncif->bt_r656_en)
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
- ISPCCDC_REC656IF_R656ON);
-}
-
-/* CCDC formats descriptions */
-static const u32 ccdc_sgrbg_pattern =
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
-static const u32 ccdc_srggb_pattern =
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
-static const u32 ccdc_sbggr_pattern =
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
-static const u32 ccdc_sgbrg_pattern =
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
-static void ccdc_configure(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
- struct isp_parallel_platform_data *pdata = NULL;
- struct v4l2_subdev *sensor;
- struct v4l2_mbus_framefmt *format;
- const struct v4l2_rect *crop;
- const struct isp_format_info *fmt_info;
- struct v4l2_subdev_format fmt_src;
- unsigned int depth_out;
- unsigned int depth_in = 0;
- struct media_pad *pad;
- unsigned long flags;
- unsigned int shift;
- u32 syn_mode;
- u32 ccdc_pattern;
-
- pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
- sensor = media_entity_to_v4l2_subdev(pad->entity);
- if (ccdc->input == CCDC_INPUT_PARALLEL)
- pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
- ->bus.parallel;
-
- /* Compute shift value for lane shifter to configure the bridge. */
- fmt_src.pad = pad->index;
- fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
- fmt_info = omap3isp_video_format_info(fmt_src.format.code);
- depth_in = fmt_info->bpp;
- }
-
- fmt_info = omap3isp_video_format_info
- (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
- depth_out = fmt_info->bpp;
-
- shift = depth_in - depth_out;
- omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
-
- ccdc->syncif.datsz = depth_out;
- ccdc->syncif.hdpol = pdata ? pdata->hs_pol : 0;
- ccdc->syncif.vdpol = pdata ? pdata->vs_pol : 0;
- ccdc_config_sync_if(ccdc, &ccdc->syncif);
-
- /* CCDC_PAD_SINK */
- format = &ccdc->formats[CCDC_PAD_SINK];
-
- syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
-
- /* Use the raw, unprocessed data when writing to memory. The H3A and
- * histogram modules are still fed with lens shading corrected data.
- */
- syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
-
- if (ccdc->output & CCDC_OUTPUT_MEMORY)
- syn_mode |= ISPCCDC_SYN_MODE_WEN;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
-
- if (ccdc->output & CCDC_OUTPUT_RESIZER)
- syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
-
- /* Use PACK8 mode for 1byte per pixel formats. */
- if (omap3isp_video_format_info(format->code)->bpp <= 8)
- syn_mode |= ISPCCDC_SYN_MODE_PACK8;
- else
- syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
-
- isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
-
- /* Mosaic filter */
- switch (format->code) {
- case V4L2_MBUS_FMT_SRGGB10_1X10:
- case V4L2_MBUS_FMT_SRGGB12_1X12:
- ccdc_pattern = ccdc_srggb_pattern;
- break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SBGGR12_1X12:
- ccdc_pattern = ccdc_sbggr_pattern;
- break;
- case V4L2_MBUS_FMT_SGBRG10_1X10:
- case V4L2_MBUS_FMT_SGBRG12_1X12:
- ccdc_pattern = ccdc_sgbrg_pattern;
- break;
- default:
- /* Use GRBG */
- ccdc_pattern = ccdc_sgrbg_pattern;
- break;
- }
- ccdc_config_imgattr(ccdc, ccdc_pattern);
-
- /* Generate VD0 on the last line of the image and VD1 on the
- * 2/3 height line.
- */
- isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
- ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
-
- /* CCDC_PAD_SOURCE_OF */
- crop = &ccdc->crop;
-
- isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
- ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
- isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
- isp_reg_writel(isp, (crop->height - 1)
- << ISPCCDC_VERT_LINES_NLV_SHIFT,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
-
- ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
-
- /* CCDC_PAD_SOURCE_VP */
- format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
-
- isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
- (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
- isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
- ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
-
- isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
- (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
-
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
- if (ccdc->lsc.request == NULL)
- goto unlock;
-
- WARN_ON(ccdc->lsc.active);
-
- /* Get last good LSC configuration. If it is not supported for
- * the current active resolution discard it.
- */
- if (ccdc->lsc.active == NULL &&
- __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
- ccdc->lsc.active = ccdc->lsc.request;
- } else {
- list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
- schedule_work(&ccdc->lsc.table_work);
- }
-
- ccdc->lsc.request = NULL;
-
-unlock:
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-
- ccdc_apply_controls(ccdc);
-}
-
-static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
- ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
-}
-
-static int ccdc_disable(struct isp_ccdc_device *ccdc)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&ccdc->lock, flags);
- if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
- ccdc->stopping = CCDC_STOP_REQUEST;
- spin_unlock_irqrestore(&ccdc->lock, flags);
-
- ret = wait_event_timeout(ccdc->wait,
- ccdc->stopping == CCDC_STOP_FINISHED,
- msecs_to_jiffies(2000));
- if (ret == 0) {
- ret = -ETIMEDOUT;
- dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
- }
-
- omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
-
- mutex_lock(&ccdc->ioctl_lock);
- ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
- ccdc->lsc.request = ccdc->lsc.active;
- ccdc->lsc.active = NULL;
- cancel_work_sync(&ccdc->lsc.table_work);
- ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
- mutex_unlock(&ccdc->ioctl_lock);
-
- ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
-
- return ret > 0 ? 0 : ret;
-}
-
-static void ccdc_enable(struct isp_ccdc_device *ccdc)
-{
- if (ccdc_lsc_is_configured(ccdc))
- __ccdc_lsc_enable(ccdc, 1);
- __ccdc_enable(ccdc, 1);
-}
-
-/* -----------------------------------------------------------------------------
- * Interrupt handling
- */
-
-/*
- * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
- * @ccdc: Pointer to ISP CCDC device.
- *
- * Returns zero if the CCDC is idle and the image has been written to
- * memory, too.
- */
-static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
-{
- struct isp_device *isp = to_isp_device(ccdc);
-
- return omap3isp_ccdc_busy(ccdc)
- | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
- ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
- ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
- ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
- ISPSBL_CCDC_WR_0_DATA_READY);
-}
-
-/*
- * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
- * @ccdc: Pointer to ISP CCDC device.
- * @max_wait: Max retry count in us for wait for idle/busy transition.
- */
-static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
- unsigned int max_wait)
-{
- unsigned int wait = 0;
-
- if (max_wait == 0)
- max_wait = 10000; /* 10 ms */
-
- for (wait = 0; wait <= max_wait; wait++) {
- if (!ccdc_sbl_busy(ccdc))
- return 0;
-
- rmb();
- udelay(1);
- }
-
- return -EBUSY;
-}
-
-/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
- * @ccdc: Pointer to ISP CCDC device.
- * @event: Pointing which event trigger handler
- *
- * Return 1 when the event and stopping request combination is satisfied,
- * zero otherwise.
- */
-static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
-{
- int rval = 0;
-
- switch ((ccdc->stopping & 3) | event) {
- case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
- if (ccdc->lsc.state != LSC_STATE_STOPPED)
- __ccdc_lsc_enable(ccdc, 0);
- __ccdc_enable(ccdc, 0);
- ccdc->stopping = CCDC_STOP_EXECUTED;
- return 1;
-
- case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
- ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
- if (ccdc->lsc.state == LSC_STATE_STOPPED)
- ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
- rval = 1;
- break;
-
- case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
- ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
- rval = 1;
- break;
-
- case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
- return 1;
- }
-
- if (ccdc->stopping == CCDC_STOP_FINISHED) {
- wake_up(&ccdc->wait);
- rval = 1;
- }
-
- return rval;
-}
-
-static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
- struct video_device *vdev = ccdc->subdev.devnode;
- struct v4l2_event event;
-
- /* Frame number propagation */
- atomic_inc(&pipe->frame_number);
-
- memset(&event, 0, sizeof(event));
- event.type = V4L2_EVENT_FRAME_SYNC;
- event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
-
- v4l2_event_queue(vdev, &event);
-}
-
-/*
- * ccdc_lsc_isr - Handle LSC events
- * @ccdc: Pointer to ISP CCDC device.
- * @events: LSC events
- */
-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);
- pipe->error = true;
- dev_dbg(to_device(ccdc), "lsc prefetch error\n");
- }
-
- if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
- return;
-
- /* LSC_DONE interrupt occur, there are two cases
- * 1. stopping for reconfiguration
- * 2. stopping because of STREAM OFF command
- */
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
-
- if (ccdc->lsc.state == LSC_STATE_STOPPING)
- ccdc->lsc.state = LSC_STATE_STOPPED;
-
- if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
- goto done;
-
- if (ccdc->lsc.state != LSC_STATE_RECONFIG)
- goto done;
-
- /* LSC is in STOPPING state, change to the new state */
- ccdc->lsc.state = LSC_STATE_STOPPED;
-
- /* This is an exception. Start of frame and LSC_DONE interrupt
- * have been received on the same time. Skip this event and wait
- * for better times.
- */
- if (events & IRQ0STATUS_HS_VS_IRQ)
- goto done;
-
- /* The LSC engine is stopped at this point. Enable it if there's a
- * pending request.
- */
- if (ccdc->lsc.request == NULL)
- goto done;
-
- ccdc_lsc_enable(ccdc);
-
-done:
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-}
-
-static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
- struct isp_device *isp = to_isp_device(ccdc);
- struct isp_buffer *buffer;
- int restart = 0;
-
- /* The CCDC generates VD0 interrupts even when disabled (the datasheet
- * doesn't explicitly state if that's supposed to happen or not, so it
- * can be considered as a hardware bug or as a feature, but we have to
- * deal with it anyway). Disabling the CCDC when no buffer is available
- * would thus not be enough, we need to handle the situation explicitly.
- */
- if (list_empty(&ccdc->video_out.dmaqueue))
- goto done;
-
- /* We're in continuous mode, and memory writes were disabled due to a
- * buffer underrun. Reenable them now that we have a buffer. The buffer
- * address has been set in ccdc_video_queue.
- */
- if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
- restart = 1;
- ccdc->underrun = 0;
- goto done;
- }
-
- if (ccdc_sbl_wait_idle(ccdc, 1000)) {
- dev_info(isp->dev, "CCDC won't become idle!\n");
- goto done;
- }
-
- buffer = omap3isp_video_buffer_next(&ccdc->video_out);
- if (buffer != NULL) {
- ccdc_set_outaddr(ccdc, buffer->isp_addr);
- restart = 1;
- }
-
- pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
-
- if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
- isp_pipeline_ready(pipe))
- omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_SINGLESHOT);
-
-done:
- return restart;
-}
-
-/*
- * ccdc_vd0_isr - Handle VD0 event
- * @ccdc: Pointer to ISP CCDC device.
- *
- * Executes LSC deferred enablement before next frame starts.
- */
-static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
-{
- unsigned long flags;
- int restart = 0;
-
- if (ccdc->output & CCDC_OUTPUT_MEMORY)
- restart = ccdc_isr_buffer(ccdc);
-
- spin_lock_irqsave(&ccdc->lock, flags);
- if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
- spin_unlock_irqrestore(&ccdc->lock, flags);
- return;
- }
-
- if (!ccdc->shadow_update)
- ccdc_apply_controls(ccdc);
- spin_unlock_irqrestore(&ccdc->lock, flags);
-
- if (restart)
- ccdc_enable(ccdc);
-}
-
-/*
- * ccdc_vd1_isr - Handle VD1 event
- * @ccdc: Pointer to ISP CCDC device.
- */
-static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
-
- /*
- * Depending on the CCDC pipeline state, CCDC stopping should be
- * handled differently. In SINGLESHOT we emulate an internal CCDC
- * stopping because the CCDC hw works only in continuous mode.
- * When CONTINUOUS pipeline state is used and the CCDC writes it's
- * data to memory the CCDC and LSC are stopped immediately but
- * without change the CCDC stopping state machine. The CCDC
- * stopping state machine should be used only when user request
- * for stopping is received (SINGLESHOT is an exeption).
- */
- switch (ccdc->state) {
- case ISP_PIPELINE_STREAM_SINGLESHOT:
- ccdc->stopping = CCDC_STOP_REQUEST;
- break;
-
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- if (ccdc->output & CCDC_OUTPUT_MEMORY) {
- if (ccdc->lsc.state != LSC_STATE_STOPPED)
- __ccdc_lsc_enable(ccdc, 0);
- __ccdc_enable(ccdc, 0);
- }
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- break;
- }
-
- if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
- goto done;
-
- if (ccdc->lsc.request == NULL)
- goto done;
-
- /*
- * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
- * do the appropriate changes in registers
- */
- if (ccdc->lsc.state == LSC_STATE_RUNNING) {
- __ccdc_lsc_enable(ccdc, 0);
- ccdc->lsc.state = LSC_STATE_RECONFIG;
- goto done;
- }
-
- /* LSC has been in STOPPED state, enable it */
- if (ccdc->lsc.state == LSC_STATE_STOPPED)
- ccdc_lsc_enable(ccdc);
-
-done:
- spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-}
-
-/*
- * omap3isp_ccdc_isr - Configure CCDC during interframe time.
- * @ccdc: Pointer to ISP CCDC device.
- * @events: CCDC events
- */
-int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
-{
- if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
-
- if (events & IRQ0STATUS_CCDC_VD1_IRQ)
- ccdc_vd1_isr(ccdc);
-
- ccdc_lsc_isr(ccdc, events);
-
- if (events & IRQ0STATUS_CCDC_VD0_IRQ)
- ccdc_vd0_isr(ccdc);
-
- if (events & IRQ0STATUS_HS_VS_IRQ)
- ccdc_hs_vs_isr(ccdc);
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * ISP video operations
- */
-
-static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
-{
- struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
-
- if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
- return -ENODEV;
-
- ccdc_set_outaddr(ccdc, buffer->isp_addr);
-
- /* We now have a buffer queued on the output, restart the pipeline
- * on the next CCDC interrupt if running in continuous mode (or when
- * starting the stream).
- */
- ccdc->underrun = 1;
-
- return 0;
-}
-
-static const struct isp_video_operations ccdc_video_ops = {
- .queue = ccdc_video_queue,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev operations
- */
-
-/*
- * ccdc_ioctl - CCDC module private ioctl's
- * @sd: ISP CCDC V4L2 subdevice
- * @cmd: ioctl command
- * @arg: ioctl argument
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- int ret;
-
- switch (cmd) {
- case VIDIOC_OMAP3ISP_CCDC_CFG:
- mutex_lock(&ccdc->ioctl_lock);
- ret = ccdc_config(ccdc, arg);
- mutex_unlock(&ccdc->ioctl_lock);
- break;
-
- default:
- return -ENOIOCTLCMD;
- }
-
- return ret;
-}
-
-static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- if (sub->type != V4L2_EVENT_FRAME_SYNC)
- return -EINVAL;
-
- /* line number is zero at frame start */
- if (sub->id != 0)
- return -EINVAL;
-
- return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
-}
-
-static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- return v4l2_event_unsubscribe(fh, sub);
-}
-
-/*
- * ccdc_set_stream - Enable/Disable streaming on the CCDC module
- * @sd: ISP CCDC V4L2 subdevice
- * @enable: Enable/disable stream
- *
- * When writing to memory, the CCDC hardware can't be enabled without a memory
- * buffer to write to. As the s_stream operation is called in response to a
- * STREAMON call without any buffer queued yet, just update the enabled field
- * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
- *
- * When not writing to memory enable the CCDC immediately.
- */
-static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct isp_device *isp = to_isp_device(ccdc);
- int ret = 0;
-
- if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
- if (enable == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
-
- omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
- ISPCCDC_CFG_VDLC);
-
- ccdc_configure(ccdc);
-
- /* TODO: Don't configure the video port if all of its output
- * links are inactive.
- */
- ccdc_config_vp(ccdc);
- ccdc_enable_vp(ccdc, 1);
- ccdc_print_status(ccdc);
- }
-
- switch (enable) {
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- if (ccdc->output & CCDC_OUTPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
-
- if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
- ccdc_enable(ccdc);
-
- ccdc->underrun = 0;
- break;
-
- case ISP_PIPELINE_STREAM_SINGLESHOT:
- if (ccdc->output & CCDC_OUTPUT_MEMORY &&
- ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
-
- ccdc_enable(ccdc);
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- ret = ccdc_disable(ccdc);
- if (ccdc->output & CCDC_OUTPUT_MEMORY)
- omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
- omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
- ccdc->underrun = 0;
- break;
- }
-
- ccdc->state = enable;
- return ret;
-}
-
-static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
- else
- return &ccdc->formats[pad];
-}
-
-static struct v4l2_rect *
-__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
- else
- return &ccdc->crop;
-}
-
-/*
- * ccdc_try_format - Try video format on a pad
- * @ccdc: ISP CCDC device
- * @fh : V4L2 subdev file handle
- * @pad: Pad number
- * @fmt: Format
- */
-static void
-ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
- unsigned int pad, struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- struct v4l2_mbus_framefmt *format;
- const struct isp_format_info *info;
- unsigned int width = fmt->width;
- unsigned int height = fmt->height;
- struct v4l2_rect *crop;
- unsigned int i;
-
- switch (pad) {
- case CCDC_PAD_SINK:
- /* TODO: If the CCDC output formatter pad is connected directly
- * to the resizer, only YUV formats can be used.
- */
- for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
- if (fmt->code == ccdc_fmts[i])
- break;
- }
-
- /* If not found, use SGRBG10 as default */
- if (i >= ARRAY_SIZE(ccdc_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
-
- /* Clamp the input size. */
- fmt->width = clamp_t(u32, width, 32, 4096);
- fmt->height = clamp_t(u32, height, 32, 4096);
- break;
-
- case CCDC_PAD_SOURCE_OF:
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
- memcpy(fmt, format, sizeof(*fmt));
-
- /* Hardcode the output size to the crop rectangle size. */
- crop = __ccdc_get_crop(ccdc, fh, which);
- fmt->width = crop->width;
- fmt->height = crop->height;
- break;
-
- case CCDC_PAD_SOURCE_VP:
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
- memcpy(fmt, format, sizeof(*fmt));
-
- /* The video port interface truncates the data to 10 bits. */
- info = omap3isp_video_format_info(fmt->code);
- fmt->code = info->truncated;
-
- /* The number of lines that can be clocked out from the video
- * port output must be at least one line less than the number
- * of input lines.
- */
- fmt->width = clamp_t(u32, width, 32, fmt->width);
- fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
- break;
- }
-
- /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
- * stored on 2 bytes.
- */
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- fmt->field = V4L2_FIELD_NONE;
-}
-
-/*
- * ccdc_try_crop - Validate a crop rectangle
- * @ccdc: ISP CCDC device
- * @sink: format on the sink pad
- * @crop: crop rectangle to be validated
- */
-static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
- const struct v4l2_mbus_framefmt *sink,
- struct v4l2_rect *crop)
-{
- const struct isp_format_info *info;
- unsigned int max_width;
-
- /* For Bayer formats, restrict left/top and width/height to even values
- * to keep the Bayer pattern.
- */
- info = omap3isp_video_format_info(sink->code);
- if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
- crop->left &= ~1;
- crop->top &= ~1;
- }
-
- crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
- crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
-
- /* The data formatter truncates the number of horizontal output pixels
- * to a multiple of 16. To avoid clipping data, allow callers to request
- * an output size bigger than the input size up to the nearest multiple
- * of 16.
- */
- max_width = (sink->width - crop->left + 15) & ~15;
- crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
- & ~15;
- crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
- sink->height - crop->top);
-
- /* Odd width/height values don't make sense for Bayer formats. */
- if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
- crop->width &= ~1;
- crop->height &= ~1;
- }
-}
-
-/*
- * ccdc_enum_mbus_code - Handle pixel format enumeration
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @code : pointer to v4l2_subdev_mbus_code_enum structure
- * return -EINVAL or zero on success
- */
-static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- switch (code->pad) {
- case CCDC_PAD_SINK:
- if (code->index >= ARRAY_SIZE(ccdc_fmts))
- return -EINVAL;
-
- code->code = ccdc_fmts[code->index];
- break;
-
- case CCDC_PAD_SOURCE_OF:
- case CCDC_PAD_SOURCE_VP:
- /* No format conversion inside CCDC */
- if (code->index != 0)
- return -EINVAL;
-
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
-
- code->code = format->code;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * ccdc_get_selection - Retrieve a selection rectangle on a pad
- * @sd: ISP CCDC V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangles are the crop rectangles on the output formatter
- * source pad.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- if (sel->pad != CCDC_PAD_SOURCE_OF)
- return -EINVAL;
-
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP_BOUNDS:
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = INT_MAX;
- sel->r.height = INT_MAX;
-
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
- ccdc_try_crop(ccdc, format, &sel->r);
- break;
-
- case V4L2_SEL_TGT_CROP:
- sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * ccdc_set_selection - Set a selection rectangle on a pad
- * @sd: ISP CCDC V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangle is the actual crop rectangle on the output
- * formatter source pad.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- if (sel->target != V4L2_SEL_TGT_CROP ||
- sel->pad != CCDC_PAD_SOURCE_OF)
- return -EINVAL;
-
- /* The crop rectangle can't be changed while streaming. */
- if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
- return -EBUSY;
-
- /* Modifying the crop rectangle always changes the format on the source
- * pad. If the KEEP_CONFIG flag is set, just return the current crop
- * rectangle.
- */
- if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
- return 0;
- }
-
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
- ccdc_try_crop(ccdc, format, &sel->r);
- *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
-
- /* Update the source format. */
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
-
- return 0;
-}
-
-/*
- * ccdc_get_format - Retrieve the video format on a pad
- * @sd : ISP CCDC V4L2 subdevice
- * @fh : V4L2 subdev file handle
- * @fmt: Format
- *
- * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
- * to the format type.
- */
-static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- fmt->format = *format;
- return 0;
-}
-
-/*
- * ccdc_set_format - Set the video format on a pad
- * @sd : ISP CCDC V4L2 subdevice
- * @fh : V4L2 subdev file handle
- * @fmt: Format
- *
- * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
- * to the format type.
- */
-static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *crop;
-
- format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- /* Propagate the format from sink to source */
- if (fmt->pad == CCDC_PAD_SINK) {
- /* Reset the crop rectangle. */
- crop = __ccdc_get_crop(ccdc, fh, fmt->which);
- crop->left = 0;
- crop->top = 0;
- crop->width = fmt->format.width;
- crop->height = fmt->format.height;
-
- ccdc_try_crop(ccdc, &fmt->format, crop);
-
- /* Update the source formats. */
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
- fmt->which);
- *format = fmt->format;
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
- fmt->which);
-
- format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
- fmt->which);
- *format = fmt->format;
- ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
- fmt->which);
- }
-
- return 0;
-}
-
-/*
- * Decide whether desired output pixel code can be obtained with
- * the lane shifter by shifting the input pixel code.
- * @in: input pixelcode to shifter
- * @out: output pixelcode from shifter
- * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
- *
- * return true if the combination is possible
- * return false otherwise
- */
-static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
- enum v4l2_mbus_pixelcode out,
- unsigned int additional_shift)
-{
- const struct isp_format_info *in_info, *out_info;
-
- if (in == out)
- return true;
-
- in_info = omap3isp_video_format_info(in);
- out_info = omap3isp_video_format_info(out);
-
- if ((in_info->flavor == 0) || (out_info->flavor == 0))
- return false;
-
- if (in_info->flavor != out_info->flavor)
- return false;
-
- return in_info->bpp - out_info->bpp + additional_shift <= 6;
-}
-
-static int ccdc_link_validate(struct v4l2_subdev *sd,
- struct media_link *link,
- struct v4l2_subdev_format *source_fmt,
- struct v4l2_subdev_format *sink_fmt)
-{
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- unsigned long parallel_shift;
-
- /* Check if the two ends match */
- if (source_fmt->format.width != sink_fmt->format.width ||
- source_fmt->format.height != sink_fmt->format.height)
- return -EPIPE;
-
- /* We've got a parallel sensor here. */
- if (ccdc->input == CCDC_INPUT_PARALLEL) {
- struct isp_parallel_platform_data *pdata =
- &((struct isp_v4l2_subdevs_group *)
- media_entity_to_v4l2_subdev(link->source->entity)
- ->host_priv)->bus.parallel;
- parallel_shift = pdata->data_lane_shift * 2;
- } else {
- parallel_shift = 0;
- }
-
- /* Lane shifter may be used to drop bits on CCDC sink pad */
- if (!ccdc_is_shiftable(source_fmt->format.code,
- sink_fmt->format.code, parallel_shift))
- return -EPIPE;
-
- return 0;
-}
-
-/*
- * ccdc_init_formats - Initialize formats on all pads
- * @sd: ISP CCDC V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. If fh is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
- */
-static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = CCDC_PAD_SINK;
- format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
- format.format.width = 4096;
- format.format.height = 4096;
- ccdc_set_format(sd, fh, &format);
-
- return 0;
-}
-
-/* V4L2 subdev core operations */
-static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
- .ioctl = ccdc_ioctl,
- .subscribe_event = ccdc_subscribe_event,
- .unsubscribe_event = ccdc_unsubscribe_event,
-};
-
-/* V4L2 subdev video operations */
-static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
- .s_stream = ccdc_set_stream,
-};
-
-/* V4L2 subdev pad operations */
-static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
- .enum_mbus_code = ccdc_enum_mbus_code,
- .enum_frame_size = ccdc_enum_frame_size,
- .get_fmt = ccdc_get_format,
- .set_fmt = ccdc_set_format,
- .get_selection = ccdc_get_selection,
- .set_selection = ccdc_set_selection,
- .link_validate = ccdc_link_validate,
-};
-
-/* V4L2 subdev operations */
-static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
- .core = &ccdc_v4l2_core_ops,
- .video = &ccdc_v4l2_video_ops,
- .pad = &ccdc_v4l2_pad_ops,
-};
-
-/* V4L2 subdev internal operations */
-static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
- .open = ccdc_init_formats,
-};
-
-/* -----------------------------------------------------------------------------
- * Media entity operations
- */
-
-/*
- * ccdc_link_setup - Setup CCDC connections
- * @entity: CCDC media entity
- * @local: Pad at the local end of the link
- * @remote: Pad at the remote end of the link
- * @flags: Link flags
- *
- * return -EINVAL or zero on success
- */
-static int ccdc_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
- struct isp_device *isp = to_isp_device(ccdc);
-
- switch (local->index | media_entity_type(remote->entity)) {
- case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
- /* Read from the sensor (parallel interface), CCP2, CSI2a or
- * CSI2c.
- */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ccdc->input = CCDC_INPUT_NONE;
- break;
- }
-
- if (ccdc->input != CCDC_INPUT_NONE)
- return -EBUSY;
-
- if (remote->entity == &isp->isp_ccp2.subdev.entity)
- ccdc->input = CCDC_INPUT_CCP2B;
- else if (remote->entity == &isp->isp_csi2a.subdev.entity)
- ccdc->input = CCDC_INPUT_CSI2A;
- else if (remote->entity == &isp->isp_csi2c.subdev.entity)
- ccdc->input = CCDC_INPUT_CSI2C;
- else
- ccdc->input = CCDC_INPUT_PARALLEL;
-
- break;
-
- /*
- * The ISP core doesn't support pipelines with multiple video outputs.
- * Revisit this when it will be implemented, and return -EBUSY for now.
- */
-
- case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
- /* Write to preview engine, histogram and H3A. When none of
- * those links are active, the video port can be disabled.
- */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
- return -EBUSY;
- ccdc->output |= CCDC_OUTPUT_PREVIEW;
- } else {
- ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
- }
- break;
-
- case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
- /* Write to memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
- return -EBUSY;
- ccdc->output |= CCDC_OUTPUT_MEMORY;
- } else {
- ccdc->output &= ~CCDC_OUTPUT_MEMORY;
- }
- break;
-
- case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
- /* Write to resizer */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
- return -EBUSY;
- ccdc->output |= CCDC_OUTPUT_RESIZER;
- } else {
- ccdc->output &= ~CCDC_OUTPUT_RESIZER;
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* media operations */
-static const struct media_entity_operations ccdc_media_ops = {
- .link_setup = ccdc_link_setup,
- .link_validate = v4l2_subdev_link_validate,
-};
-
-void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
-{
- v4l2_device_unregister_subdev(&ccdc->subdev);
- omap3isp_video_unregister(&ccdc->video_out);
-}
-
-int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
- struct v4l2_device *vdev)
-{
- int ret;
-
- /* Register the subdev and video node. */
- ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&ccdc->video_out, vdev);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- omap3isp_ccdc_unregister_entities(ccdc);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * ISP CCDC initialisation and cleanup
- */
-
-/*
- * ccdc_init_entities - Initialize V4L2 subdev and media entity
- * @ccdc: ISP CCDC module
- *
- * Return 0 on success and a negative error code on failure.
- */
-static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
-{
- struct v4l2_subdev *sd = &ccdc->subdev;
- struct media_pad *pads = ccdc->pads;
- struct media_entity *me = &sd->entity;
- int ret;
-
- ccdc->input = CCDC_INPUT_NONE;
-
- v4l2_subdev_init(sd, &ccdc_v4l2_ops);
- sd->internal_ops = &ccdc_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for isp subdevs */
- v4l2_set_subdevdata(sd, ccdc);
- sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
- pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
-
- me->ops = &ccdc_media_ops;
- ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
- if (ret < 0)
- return ret;
-
- ccdc_init_formats(sd, NULL);
-
- ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ccdc->video_out.ops = &ccdc_video_ops;
- ccdc->video_out.isp = to_isp_device(ccdc);
- ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
- ccdc->video_out.bpl_alignment = 32;
-
- ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
- if (ret < 0)
- goto error_video;
-
- /* Connect the CCDC subdev to the video node. */
- ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
- &ccdc->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
- return 0;
-
-error_link:
- omap3isp_video_cleanup(&ccdc->video_out);
-error_video:
- media_entity_cleanup(me);
- return ret;
-}
-
-/*
- * omap3isp_ccdc_init - CCDC module initialization.
- * @dev: Device pointer specific to the OMAP3 ISP.
- *
- * TODO: Get the initialisation values from platform data.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-int omap3isp_ccdc_init(struct isp_device *isp)
-{
- struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
- int ret;
-
- spin_lock_init(&ccdc->lock);
- init_waitqueue_head(&ccdc->wait);
- mutex_init(&ccdc->ioctl_lock);
-
- ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
-
- INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
- ccdc->lsc.state = LSC_STATE_STOPPED;
- INIT_LIST_HEAD(&ccdc->lsc.free_queue);
- spin_lock_init(&ccdc->lsc.req_lock);
-
- ccdc->syncif.ccdc_mastermode = 0;
- ccdc->syncif.datapol = 0;
- ccdc->syncif.datsz = 0;
- ccdc->syncif.fldmode = 0;
- ccdc->syncif.fldout = 0;
- ccdc->syncif.fldpol = 0;
- ccdc->syncif.fldstat = 0;
-
- ccdc->clamp.oblen = 0;
- ccdc->clamp.dcsubval = 0;
-
- ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
- ccdc_apply_controls(ccdc);
-
- ret = ccdc_init_entities(ccdc);
- if (ret < 0) {
- mutex_destroy(&ccdc->ioctl_lock);
- return ret;
- }
-
- return 0;
-}
-
-/*
- * omap3isp_ccdc_cleanup - CCDC module cleanup.
- * @dev: Device pointer specific to the OMAP3 ISP.
- */
-void omap3isp_ccdc_cleanup(struct isp_device *isp)
-{
- struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
-
- omap3isp_video_cleanup(&ccdc->video_out);
- media_entity_cleanup(&ccdc->subdev.entity);
-
- /* Free LSC requests. As the CCDC is stopped there's no active request,
- * so only the pending request and the free queue need to be handled.
- */
- ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
- cancel_work_sync(&ccdc->lsc.table_work);
- ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
-
- if (ccdc->fpc.fpcaddr != 0)
- omap_iommu_vfree(isp->domain, isp->dev, ccdc->fpc.fpcaddr);
-
- mutex_destroy(&ccdc->ioctl_lock);
-}
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
deleted file mode 100644
index 890f6b3a68fd..000000000000
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * ispccdc.h
- *
- * TI OMAP3 ISP - CCDC module
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 OMAP3_ISP_CCDC_H
-#define OMAP3_ISP_CCDC_H
-
-#include <linux/omap3isp.h>
-#include <linux/workqueue.h>
-
-#include "ispvideo.h"
-
-enum ccdc_input_entity {
- CCDC_INPUT_NONE,
- CCDC_INPUT_PARALLEL,
- CCDC_INPUT_CSI2A,
- CCDC_INPUT_CCP2B,
- CCDC_INPUT_CSI2C
-};
-
-#define CCDC_OUTPUT_MEMORY (1 << 0)
-#define CCDC_OUTPUT_PREVIEW (1 << 1)
-#define CCDC_OUTPUT_RESIZER (1 << 2)
-
-#define OMAP3ISP_CCDC_NEVENTS 16
-
-/*
- * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC
- * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave.
- * @fldstat: Field state. 0 - Odd Field, 1 - Even Field.
- * @datsz: Data size.
- * @fldmode: 0 - Progressive, 1 - Interlaced.
- * @datapol: 0 - Positive, 1 - Negative.
- * @fldpol: 0 - Positive, 1 - Negative.
- * @hdpol: 0 - Positive, 1 - Negative.
- * @vdpol: 0 - Positive, 1 - Negative.
- * @fldout: 0 - Input, 1 - Output.
- * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output.
- * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output.
- * @ppln: Number of pixels per line, used for HS/VS Output.
- * @hlprf: Number of half lines per frame, used for HS/VS Output.
- * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode.
- */
-struct ispccdc_syncif {
- u8 ccdc_mastermode;
- u8 fldstat;
- u8 datsz;
- u8 fldmode;
- u8 datapol;
- u8 fldpol;
- u8 hdpol;
- u8 vdpol;
- u8 fldout;
- u8 hs_width;
- u8 vs_width;
- u8 ppln;
- u8 hlprf;
- u8 bt_r656_en;
-};
-
-enum ispccdc_lsc_state {
- LSC_STATE_STOPPED = 0,
- LSC_STATE_STOPPING = 1,
- LSC_STATE_RUNNING = 2,
- LSC_STATE_RECONFIG = 3,
-};
-
-struct ispccdc_lsc_config_req {
- struct list_head list;
- struct omap3isp_ccdc_lsc_config config;
- unsigned char enable;
- u32 table;
- struct iovm_struct *iovm;
-};
-
-/*
- * ispccdc_lsc - CCDC LSC parameters
- * @update_config: Set when user changes config
- * @request_enable: Whether LSC is requested to be enabled
- * @config: LSC config set by user
- * @update_table: Set when user provides a new LSC table to table_new
- * @table_new: LSC table set by user, ISP address
- * @table_inuse: LSC table currently in use, ISP address
- */
-struct ispccdc_lsc {
- enum ispccdc_lsc_state state;
- struct work_struct table_work;
-
- /* LSC queue of configurations */
- spinlock_t req_lock;
- struct ispccdc_lsc_config_req *request; /* requested configuration */
- struct ispccdc_lsc_config_req *active; /* active configuration */
- struct list_head free_queue; /* configurations for freeing */
-};
-
-#define CCDC_STOP_NOT_REQUESTED 0x00
-#define CCDC_STOP_REQUEST 0x01
-#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST)
-#define CCDC_STOP_CCDC_FINISHED 0x04
-#define CCDC_STOP_LSC_FINISHED 0x08
-#define CCDC_STOP_FINISHED \
- (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
-
-#define CCDC_EVENT_VD1 0x10
-#define CCDC_EVENT_VD0 0x20
-#define CCDC_EVENT_LSC_DONE 0x40
-
-/* Sink and source CCDC pads */
-#define CCDC_PAD_SINK 0
-#define CCDC_PAD_SOURCE_OF 1
-#define CCDC_PAD_SOURCE_VP 2
-#define CCDC_PADS_NUM 3
-
-/*
- * struct isp_ccdc_device - Structure for the CCDC module to store its own
- * information
- * @subdev: V4L2 subdevice
- * @pads: Sink and source media entity pads
- * @formats: Active video formats
- * @crop: Active crop rectangle on the OF source pad
- * @input: Active input
- * @output: Active outputs
- * @video_out: Output video node
- * @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)
- * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
- * @blcomp: Black level compensation configuration
- * @clamp: Optical-black or digital clamp configuration
- * @fpc: Faulty pixels correction configuration
- * @lsc: Lens shading compensation configuration
- * @update: Bitmask of controls to update during the next interrupt
- * @shadow_update: Controls update in progress by userspace
- * @syncif: Interface synchronization configuration
- * @underrun: A buffer underrun occurred and a new buffer has been queued
- * @state: Streaming state
- * @lock: Serializes shadow_update with interrupt handler
- * @wait: Wait queue used to stop the module
- * @stopping: Stopping state
- * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
- */
-struct isp_ccdc_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[CCDC_PADS_NUM];
- struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
- struct v4l2_rect crop;
-
- enum ccdc_input_entity input;
- unsigned int output;
- struct isp_video video_out;
-
- unsigned int alaw:1,
- lpf:1,
- obclamp:1,
- fpc_en:1;
- struct omap3isp_ccdc_blcomp blcomp;
- struct omap3isp_ccdc_bclamp clamp;
- struct omap3isp_ccdc_fpc fpc;
- struct ispccdc_lsc lsc;
- unsigned int update;
- unsigned int shadow_update;
-
- struct ispccdc_syncif syncif;
-
- unsigned int underrun:1;
- enum isp_pipeline_stream_state state;
- spinlock_t lock;
- wait_queue_head_t wait;
- unsigned int stopping;
- struct mutex ioctl_lock;
-};
-
-struct isp_device;
-
-int omap3isp_ccdc_init(struct isp_device *isp);
-void omap3isp_ccdc_cleanup(struct isp_device *isp);
-int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
- struct v4l2_device *vdev);
-void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
-
-int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
-int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
-void omap3isp_ccdc_restore_context(struct isp_device *isp);
-void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
- unsigned int *max_rate);
-
-#endif /* OMAP3_ISP_CCDC_H */
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
deleted file mode 100644
index a1724362b6d5..000000000000
--- a/drivers/media/video/omap3isp/ispcsi2.c
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * ispcsi2.c
- *
- * TI OMAP3 ISP - CSI2 module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 <media/v4l2-common.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/mm.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "ispcsi2.h"
-
-/*
- * csi2_if_enable - Enable CSI2 Receiver interface.
- * @enable: enable flag
- *
- */
-static void csi2_if_enable(struct isp_device *isp,
- struct isp_csi2_device *csi2, u8 enable)
-{
- struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
-
- isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN,
- enable ? ISPCSI2_CTRL_IF_EN : 0);
-
- currctrl->if_enable = enable;
-}
-
-/*
- * csi2_recv_config - CSI2 receiver module configuration.
- * @currctrl: isp_csi2_ctrl_cfg structure
- *
- */
-static void csi2_recv_config(struct isp_device *isp,
- struct isp_csi2_device *csi2,
- struct isp_csi2_ctrl_cfg *currctrl)
-{
- u32 reg;
-
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL);
-
- if (currctrl->frame_mode)
- reg |= ISPCSI2_CTRL_FRAME;
- else
- reg &= ~ISPCSI2_CTRL_FRAME;
-
- if (currctrl->vp_clk_enable)
- reg |= ISPCSI2_CTRL_VP_CLK_EN;
- else
- reg &= ~ISPCSI2_CTRL_VP_CLK_EN;
-
- if (currctrl->vp_only_enable)
- reg |= ISPCSI2_CTRL_VP_ONLY_EN;
- else
- reg &= ~ISPCSI2_CTRL_VP_ONLY_EN;
-
- reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
- reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
-
- if (currctrl->ecc_enable)
- reg |= ISPCSI2_CTRL_ECC_EN;
- else
- reg &= ~ISPCSI2_CTRL_ECC_EN;
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL);
-}
-
-static const unsigned int csi2_input_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
-};
-
-/* To set the format on the CSI2 requires a mapping function that takes
- * the following inputs:
- * - 2 different formats (at this time)
- * - 2 destinations (mem, vp+mem) (vp only handled separately)
- * - 2 decompression options (on, off)
- * - 2 isp revisions (certain format must be handled differently on OMAP3630)
- * Output should be CSI2 frame format code
- * Array indices as follows: [format][dest][decompr][is_3630]
- * Not all combinations are valid. 0 means invalid.
- */
-static const u16 __csi2_fmt_map[2][2][2][2] = {
- /* RAW10 formats */
- {
- /* Output to memory */
- {
- /* No DPCM decompression */
- { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 },
- /* DPCM decompression */
- { 0, 0 },
- },
- /* Output to both */
- {
- /* No DPCM decompression */
- { CSI2_PIX_FMT_RAW10_EXP16_VP,
- CSI2_PIX_FMT_RAW10_EXP16_VP },
- /* DPCM decompression */
- { 0, 0 },
- },
- },
- /* RAW10 DPCM8 formats */
- {
- /* Output to memory */
- {
- /* No DPCM decompression */
- { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 },
- /* DPCM decompression */
- { CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
- CSI2_USERDEF_8BIT_DATA1_DPCM10 },
- },
- /* Output to both */
- {
- /* No DPCM decompression */
- { CSI2_PIX_FMT_RAW8_VP,
- CSI2_PIX_FMT_RAW8_VP },
- /* DPCM decompression */
- { CSI2_PIX_FMT_RAW8_DPCM10_VP,
- CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
- },
- },
-};
-
-/*
- * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
- * @csi2: ISP CSI2 device
- *
- * Returns CSI2 physical format id
- */
-static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
-{
- const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
- int fmtidx, destidx, is_3630;
-
- switch (fmt->code) {
- case V4L2_MBUS_FMT_SGRBG10_1X10:
- case V4L2_MBUS_FMT_SRGGB10_1X10:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SGBRG10_1X10:
- fmtidx = 0;
- break;
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
- fmtidx = 1;
- break;
- default:
- WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
- fmt->code);
- return 0;
- }
-
- if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
- !(csi2->output & CSI2_OUTPUT_MEMORY)) {
- /* Neither output enabled is a valid combination */
- return CSI2_PIX_FMT_OTHERS;
- }
-
- /* If we need to skip frames at the beginning of the stream disable the
- * video port to avoid sending the skipped frames to the CCDC.
- */
- destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
- is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
-
- return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630];
-}
-
-/*
- * csi2_set_outaddr - Set memory address to save output image
- * @csi2: Pointer to ISP CSI2a device.
- * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
- *
- * Sets the memory address where the output will be saved.
- *
- * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
- * boundary.
- */
-static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
-{
- struct isp_device *isp = csi2->isp;
- struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
-
- ctx->ping_addr = addr;
- ctx->pong_addr = addr;
- isp_reg_writel(isp, ctx->ping_addr,
- csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
- isp_reg_writel(isp, ctx->pong_addr,
- csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
-}
-
-/*
- * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
- * be enabled by CSI2.
- * @format_id: mapped format id
- *
- */
-static inline int is_usr_def_mapping(u32 format_id)
-{
- return (format_id & 0x40) ? 1 : 0;
-}
-
-/*
- * csi2_ctx_enable - Enable specified CSI2 context
- * @ctxnum: Context number, valid between 0 and 7 values.
- * @enable: enable
- *
- */
-static void csi2_ctx_enable(struct isp_device *isp,
- struct isp_csi2_device *csi2, u8 ctxnum, u8 enable)
-{
- struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
- unsigned int skip = 0;
- u32 reg;
-
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
-
- if (enable) {
- if (csi2->frame_skip)
- skip = csi2->frame_skip;
- else if (csi2->output & CSI2_OUTPUT_MEMORY)
- skip = 1;
-
- reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK;
- reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK
- | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
- | ISPCSI2_CTX_CTRL1_CTX_EN;
- } else {
- reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN;
- }
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
- ctx->enabled = enable;
-}
-
-/*
- * csi2_ctx_config - CSI2 context configuration.
- * @ctx: context configuration
- *
- */
-static void csi2_ctx_config(struct isp_device *isp,
- struct isp_csi2_device *csi2,
- struct isp_csi2_ctx_cfg *ctx)
-{
- u32 reg;
-
- /* Set up CSI2_CTx_CTRL1 */
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
-
- if (ctx->eof_enabled)
- reg |= ISPCSI2_CTX_CTRL1_EOF_EN;
- else
- reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN;
-
- if (ctx->eol_enabled)
- reg |= ISPCSI2_CTX_CTRL1_EOL_EN;
- else
- reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN;
-
- if (ctx->checksum_enabled)
- reg |= ISPCSI2_CTX_CTRL1_CS_EN;
- else
- reg &= ~ISPCSI2_CTX_CTRL1_CS_EN;
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
-
- /* Set up CSI2_CTx_CTRL2 */
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
-
- reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
- reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
-
- reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
- reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT;
-
- if (ctx->dpcm_decompress) {
- if (ctx->dpcm_predictor)
- reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED;
- else
- reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED;
- }
-
- if (is_usr_def_mapping(ctx->format_id)) {
- reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK;
- reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
- }
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
-
- /* Set up CSI2_CTx_CTRL3 */
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
- reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
- reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
-
- /* Set up CSI2_CTx_DAT_OFST */
- reg = isp_reg_readl(isp, csi2->regs1,
- ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
- reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
- reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
- isp_reg_writel(isp, reg, csi2->regs1,
- ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
-
- isp_reg_writel(isp, ctx->ping_addr,
- csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
-
- isp_reg_writel(isp, ctx->pong_addr,
- csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
-}
-
-/*
- * csi2_timing_config - CSI2 timing configuration.
- * @timing: csi2_timing_cfg structure
- */
-static void csi2_timing_config(struct isp_device *isp,
- struct isp_csi2_device *csi2,
- struct isp_csi2_timing_cfg *timing)
-{
- u32 reg;
-
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING);
-
- if (timing->force_rx_mode)
- reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
- else
- reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
-
- if (timing->stop_state_16x)
- reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
- else
- reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
-
- if (timing->stop_state_4x)
- reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
- else
- reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
-
- reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum);
- reg |= timing->stop_state_counter <<
- ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum);
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING);
-}
-
-/*
- * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
- * @enable: Enable/disable CSI2 Context interrupts
- */
-static void csi2_irq_ctx_set(struct isp_device *isp,
- struct isp_csi2_device *csi2, int enable)
-{
- int i;
-
- for (i = 0; i < 8; i++) {
- isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1,
- ISPCSI2_CTX_IRQSTATUS(i));
- if (enable)
- isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
- ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
- else
- isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
- ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
- }
-}
-
-/*
- * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
- * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
- */
-static void csi2_irq_complexio1_set(struct isp_device *isp,
- struct isp_csi2_device *csi2, int enable)
-{
- u32 reg;
- reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT |
- ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER |
- ISPCSI2_PHY_IRQENABLE_STATEULPM5 |
- ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 |
- ISPCSI2_PHY_IRQENABLE_ERRESC5 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 |
- ISPCSI2_PHY_IRQENABLE_STATEULPM4 |
- ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 |
- ISPCSI2_PHY_IRQENABLE_ERRESC4 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 |
- ISPCSI2_PHY_IRQENABLE_STATEULPM3 |
- ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 |
- ISPCSI2_PHY_IRQENABLE_ERRESC3 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 |
- ISPCSI2_PHY_IRQENABLE_STATEULPM2 |
- ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 |
- ISPCSI2_PHY_IRQENABLE_ERRESC2 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 |
- ISPCSI2_PHY_IRQENABLE_STATEULPM1 |
- ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 |
- ISPCSI2_PHY_IRQENABLE_ERRESC1 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 |
- ISPCSI2_PHY_IRQENABLE_ERRSOTHS1;
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
- if (enable)
- reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
- else
- reg = 0;
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
-}
-
-/*
- * csi2_irq_status_set - Enables CSI2 Status IRQs.
- * @enable: Enable/disable CSI2 Status interrupts
- */
-static void csi2_irq_status_set(struct isp_device *isp,
- struct isp_csi2_device *csi2, int enable)
-{
- u32 reg;
- reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
- ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
- ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
- ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
- ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
- ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
- ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
- ISPCSI2_IRQSTATUS_CONTEXT(0);
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS);
- if (enable)
- reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE);
- else
- reg = 0;
-
- isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE);
-}
-
-/*
- * omap3isp_csi2_reset - Resets the CSI2 module.
- *
- * Must be called with the phy lock held.
- *
- * Returns 0 if successful, or -EBUSY if power command didn't respond.
- */
-int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
-{
- struct isp_device *isp = csi2->isp;
- u8 soft_reset_retries = 0;
- u32 reg;
- int i;
-
- if (!csi2->available)
- return -ENODEV;
-
- if (csi2->phy->phy_in_use)
- return -EBUSY;
-
- isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
- ISPCSI2_SYSCONFIG_SOFT_RESET);
-
- do {
- reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) &
- ISPCSI2_SYSSTATUS_RESET_DONE;
- if (reg == ISPCSI2_SYSSTATUS_RESET_DONE)
- break;
- soft_reset_retries++;
- if (soft_reset_retries < 5)
- udelay(100);
- } while (soft_reset_retries < 5);
-
- if (soft_reset_retries == 5) {
- printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
- return -EBUSY;
- }
-
- if (isp->revision == ISP_REVISION_15_0)
- isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG,
- ISPCSI2_PHY_CFG_RESET_CTRL);
-
- i = 100;
- do {
- reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1)
- & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK;
- if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK)
- break;
- udelay(100);
- } while (--i > 0);
-
- if (i == 0) {
- printk(KERN_ERR
- "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
- return -EBUSY;
- }
-
- if (isp->autoidle)
- isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
- ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
- ISPCSI2_SYSCONFIG_AUTO_IDLE,
- ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART |
- ((isp->revision == ISP_REVISION_15_0) ?
- ISPCSI2_SYSCONFIG_AUTO_IDLE : 0));
- else
- isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
- ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
- ISPCSI2_SYSCONFIG_AUTO_IDLE,
- ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO);
-
- return 0;
-}
-
-static int csi2_configure(struct isp_csi2_device *csi2)
-{
- const struct isp_v4l2_subdevs_group *pdata;
- struct isp_device *isp = csi2->isp;
- struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
- struct v4l2_subdev *sensor;
- struct media_pad *pad;
-
- /*
- * CSI2 fields that can be updated while the context has
- * been enabled or the interface has been enabled are not
- * updated dynamically currently. So we do not allow to
- * reconfigure if either has been enabled
- */
- if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
- return -EBUSY;
-
- pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
- sensor = media_entity_to_v4l2_subdev(pad->entity);
- pdata = sensor->host_priv;
-
- csi2->frame_skip = 0;
- v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
-
- csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
- csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
- csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
-
- timing->ionum = 1;
- timing->force_rx_mode = 1;
- timing->stop_state_16x = 1;
- timing->stop_state_4x = 1;
- timing->stop_state_counter = 0x1FF;
-
- /*
- * The CSI2 receiver can't do any format conversion except DPCM
- * decompression, so every set_format call configures both pads
- * and enables DPCM decompression as a special case:
- */
- if (csi2->formats[CSI2_PAD_SINK].code !=
- csi2->formats[CSI2_PAD_SOURCE].code)
- csi2->dpcm_decompress = true;
- else
- csi2->dpcm_decompress = false;
-
- csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
-
- if (csi2->video_out.bpl_padding == 0)
- csi2->contexts[0].data_offset = 0;
- else
- csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
-
- /*
- * Enable end of frame and end of line signals generation for
- * context 0. These signals are generated from CSI2 receiver to
- * qualify the last pixel of a frame and the last pixel of a line.
- * Without enabling the signals CSI2 receiver writes data to memory
- * beyond buffer size and/or data line offset is not handled correctly.
- */
- csi2->contexts[0].eof_enabled = 1;
- csi2->contexts[0].eol_enabled = 1;
-
- csi2_irq_complexio1_set(isp, csi2, 1);
- csi2_irq_ctx_set(isp, csi2, 1);
- csi2_irq_status_set(isp, csi2, 1);
-
- /* Set configuration (timings, format and links) */
- csi2_timing_config(isp, csi2, timing);
- csi2_recv_config(isp, csi2, &csi2->ctrl);
- csi2_ctx_config(isp, csi2, &csi2->contexts[0]);
-
- return 0;
-}
-
-/*
- * csi2_print_status - Prints CSI2 debug information.
- */
-#define CSI2_PRINT_REGISTER(isp, regs, name)\
- dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \
- isp_reg_readl(isp, regs, ISPCSI2_##name))
-
-static void csi2_print_status(struct isp_csi2_device *csi2)
-{
- struct isp_device *isp = csi2->isp;
-
- if (!csi2->available)
- return;
-
- dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n");
-
- CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING);
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0));
- CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0));
-
- dev_dbg(isp->dev, "--------------------------------------------\n");
-}
-
-/* -----------------------------------------------------------------------------
- * Interrupt handling
- */
-
-/*
- * csi2_isr_buffer - Does buffer handling at end-of-frame
- * when writing to memory.
- */
-static void csi2_isr_buffer(struct isp_csi2_device *csi2)
-{
- struct isp_device *isp = csi2->isp;
- struct isp_buffer *buffer;
-
- csi2_ctx_enable(isp, csi2, 0, 0);
-
- buffer = omap3isp_video_buffer_next(&csi2->video_out);
-
- /*
- * Let video queue operation restart engine if there is an underrun
- * condition.
- */
- if (buffer == NULL)
- return;
-
- csi2_set_outaddr(csi2, buffer->isp_addr);
- csi2_ctx_enable(isp, csi2, 0, 1);
-}
-
-static void csi2_isr_ctx(struct isp_csi2_device *csi2,
- struct isp_csi2_ctx_cfg *ctx)
-{
- struct isp_device *isp = csi2->isp;
- unsigned int n = ctx->ctxnum;
- u32 status;
-
- status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
- isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
-
- if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
- return;
-
- /* Skip interrupts until we reach the frame skip count. The CSI2 will be
- * automatically disabled, as the frame skip count has been programmed
- * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
- *
- * It would have been nice to rely on the FRAME_NUMBER interrupt instead
- * but it turned out that the interrupt is only generated when the CSI2
- * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
- * correctly and reaches 0 when data is forwarded to the video port only
- * but no interrupt arrives). Maybe a CSI2 hardware bug.
- */
- if (csi2->frame_skip) {
- csi2->frame_skip--;
- if (csi2->frame_skip == 0) {
- ctx->format_id = csi2_ctx_map_format(csi2);
- csi2_ctx_config(isp, csi2, ctx);
- csi2_ctx_enable(isp, csi2, n, 1);
- }
- return;
- }
-
- if (csi2->output & CSI2_OUTPUT_MEMORY)
- csi2_isr_buffer(csi2);
-}
-
-/*
- * omap3isp_csi2_isr - CSI2 interrupt handling.
- */
-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;
-
- if (!csi2->available)
- return;
-
- csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
- isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
-
- /* Failure Cases */
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
- cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1,
- ISPCSI2_PHY_IRQSTATUS);
- isp_reg_writel(isp, cpxio1_irqstatus,
- csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
- dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
- "%x\n", cpxio1_irqstatus);
- pipe->error = true;
- }
-
- if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
- ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
- ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
- ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
- ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
- dev_dbg(isp->dev, "CSI2 Err:"
- " OCP:%d,"
- " Short_pack:%d,"
- " ECC:%d,"
- " CPXIO2:%d,"
- " FIFO_OVF:%d,"
- "\n",
- (csi2_irqstatus &
- ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
- (csi2_irqstatus &
- ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
- (csi2_irqstatus &
- ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
- (csi2_irqstatus &
- ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
- (csi2_irqstatus &
- ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
- pipe->error = true;
- }
-
- if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
- return;
-
- /* Successful cases */
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
- csi2_isr_ctx(csi2, &csi2->contexts[0]);
-
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
- dev_dbg(isp->dev, "CSI2: ECC correction done\n");
-}
-
-/* -----------------------------------------------------------------------------
- * ISP video operations
- */
-
-/*
- * csi2_queue - Queues the first buffer when using memory output
- * @video: The video node
- * @buffer: buffer to queue
- */
-static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
-{
- struct isp_device *isp = video->isp;
- struct isp_csi2_device *csi2 = &isp->isp_csi2a;
-
- csi2_set_outaddr(csi2, buffer->isp_addr);
-
- /*
- * If streaming was enabled before there was a buffer queued
- * or underrun happened in the ISR, the hardware was not enabled
- * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set.
- * Enable it now.
- */
- if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
- /* Enable / disable context 0 and IRQs */
- csi2_if_enable(isp, csi2, 1);
- csi2_ctx_enable(isp, csi2, 0, 1);
- isp_video_dmaqueue_flags_clr(&csi2->video_out);
- }
-
- return 0;
-}
-
-static const struct isp_video_operations csi2_ispvideo_ops = {
- .queue = csi2_queue,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev operations
- */
-
-static struct v4l2_mbus_framefmt *
-__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
- else
- return &csi2->formats[pad];
-}
-
-static void
-csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
- unsigned int pad, struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- enum v4l2_mbus_pixelcode pixelcode;
- struct v4l2_mbus_framefmt *format;
- const struct isp_format_info *info;
- unsigned int i;
-
- switch (pad) {
- case CSI2_PAD_SINK:
- /* Clamp the width and height to valid range (1-8191). */
- for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
- if (fmt->code == csi2_input_fmts[i])
- break;
- }
-
- /* If not found, use SGRBG10 as default */
- if (i >= ARRAY_SIZE(csi2_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
-
- fmt->width = clamp_t(u32, fmt->width, 1, 8191);
- fmt->height = clamp_t(u32, fmt->height, 1, 8191);
- break;
-
- case CSI2_PAD_SOURCE:
- /* Source format same as sink format, except for DPCM
- * compression.
- */
- pixelcode = fmt->code;
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
- memcpy(fmt, format, sizeof(*fmt));
-
- /*
- * Only Allow DPCM decompression, and check that the
- * pattern is preserved
- */
- info = omap3isp_video_format_info(fmt->code);
- if (info->uncompressed == pixelcode)
- fmt->code = pixelcode;
- break;
- }
-
- /* RGB, non-interlaced */
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- fmt->field = V4L2_FIELD_NONE;
-}
-
-/*
- * csi2_enum_mbus_code - Handle pixel format enumeration
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @code : pointer to v4l2_subdev_mbus_code_enum structure
- * return -EINVAL or zero on success
- */
-static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
- const struct isp_format_info *info;
-
- if (code->pad == CSI2_PAD_SINK) {
- if (code->index >= ARRAY_SIZE(csi2_input_fmts))
- return -EINVAL;
-
- code->code = csi2_input_fmts[code->index];
- } else {
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
- switch (code->index) {
- case 0:
- /* Passthrough sink pad code */
- code->code = format->code;
- break;
- case 1:
- /* Uncompressed code */
- info = omap3isp_video_format_info(format->code);
- if (info->uncompressed == format->code)
- return -EINVAL;
-
- code->code = info->uncompressed;
- break;
- default:
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int csi2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * csi2_get_format - Handle get format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- fmt->format = *format;
- return 0;
-}
-
-/*
- * csi2_set_format - Handle set format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- /* Propagate the format from sink to source */
- if (fmt->pad == CSI2_PAD_SINK) {
- format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
- fmt->which);
- *format = fmt->format;
- csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
- }
-
- return 0;
-}
-
-/*
- * csi2_init_formats - Initialize formats on all pads
- * @sd: ISP CSI2 V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. If fh is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
- */
-static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = CSI2_PAD_SINK;
- format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
- format.format.width = 4096;
- format.format.height = 4096;
- csi2_set_format(sd, fh, &format);
-
- return 0;
-}
-
-/*
- * csi2_set_stream - Enable/Disable streaming on the CSI2 module
- * @sd: ISP CSI2 V4L2 subdevice
- * @enable: ISP pipeline stream state
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct isp_device *isp = csi2->isp;
- struct isp_video *video_out = &csi2->video_out;
-
- switch (enable) {
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- if (omap3isp_csiphy_acquire(csi2->phy) < 0)
- return -ENODEV;
- if (csi2->output & CSI2_OUTPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
- csi2_configure(csi2);
- csi2_print_status(csi2);
-
- /*
- * When outputting to memory with no buffer available, let the
- * buffer queue handler start the hardware. A DMA queue flag
- * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
- * a buffer available.
- */
- if (csi2->output & CSI2_OUTPUT_MEMORY &&
- !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED))
- break;
- /* Enable context 0 and IRQs */
- atomic_set(&csi2->stopping, 0);
- csi2_ctx_enable(isp, csi2, 0, 1);
- csi2_if_enable(isp, csi2, 1);
- isp_video_dmaqueue_flags_clr(video_out);
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- if (csi2->state == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
- if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait,
- &csi2->stopping))
- dev_dbg(isp->dev, "%s: module stop timeout.\n",
- sd->name);
- csi2_ctx_enable(isp, csi2, 0, 0);
- csi2_if_enable(isp, csi2, 0);
- csi2_irq_ctx_set(isp, csi2, 0);
- omap3isp_csiphy_release(csi2->phy);
- isp_video_dmaqueue_flags_clr(video_out);
- omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
- break;
- }
-
- csi2->state = enable;
- return 0;
-}
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops csi2_video_ops = {
- .s_stream = csi2_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
- .enum_mbus_code = csi2_enum_mbus_code,
- .enum_frame_size = csi2_enum_frame_size,
- .get_fmt = csi2_get_format,
- .set_fmt = csi2_set_format,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops csi2_ops = {
- .video = &csi2_video_ops,
- .pad = &csi2_pad_ops,
-};
-
-/* subdev internal operations */
-static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
- .open = csi2_init_formats,
-};
-
-/* -----------------------------------------------------------------------------
- * Media entity operations
- */
-
-/*
- * csi2_link_setup - Setup CSI2 connections.
- * @entity : Pointer to media entity structure
- * @local : Pointer to local pad array
- * @remote : Pointer to remote pad array
- * @flags : Link flags
- * return -EINVAL or zero on success
- */
-static int csi2_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
-
- /*
- * The ISP core doesn't support pipelines with multiple video outputs.
- * Revisit this when it will be implemented, and return -EBUSY for now.
- */
-
- switch (local->index | media_entity_type(remote->entity)) {
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (csi2->output & ~CSI2_OUTPUT_MEMORY)
- return -EBUSY;
- csi2->output |= CSI2_OUTPUT_MEMORY;
- } else {
- csi2->output &= ~CSI2_OUTPUT_MEMORY;
- }
- break;
-
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (csi2->output & ~CSI2_OUTPUT_CCDC)
- return -EBUSY;
- csi2->output |= CSI2_OUTPUT_CCDC;
- } else {
- csi2->output &= ~CSI2_OUTPUT_CCDC;
- }
- break;
-
- default:
- /* Link from camera to CSI2 is fixed... */
- return -EINVAL;
- }
-
- ctrl->vp_only_enable =
- (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true;
- ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC);
-
- return 0;
-}
-
-/* media operations */
-static const struct media_entity_operations csi2_media_ops = {
- .link_setup = csi2_link_setup,
- .link_validate = v4l2_subdev_link_validate,
-};
-
-void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
-{
- v4l2_device_unregister_subdev(&csi2->subdev);
- omap3isp_video_unregister(&csi2->video_out);
-}
-
-int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
- struct v4l2_device *vdev)
-{
- int ret;
-
- /* Register the subdev and video nodes. */
- ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&csi2->video_out, vdev);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- omap3isp_csi2_unregister_entities(csi2);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * ISP CSI2 initialisation and cleanup
- */
-
-/*
- * csi2_init_entities - Initialize subdev and media entity.
- * @csi2: Pointer to csi2 structure.
- * return -ENOMEM or zero on success
- */
-static int csi2_init_entities(struct isp_csi2_device *csi2)
-{
- struct v4l2_subdev *sd = &csi2->subdev;
- struct media_pad *pads = csi2->pads;
- struct media_entity *me = &sd->entity;
- int ret;
-
- v4l2_subdev_init(sd, &csi2_ops);
- sd->internal_ops = &csi2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
-
- sd->grp_id = 1 << 16; /* group ID for isp subdevs */
- v4l2_set_subdevdata(sd, csi2);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-
- me->ops = &csi2_media_ops;
- ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
- if (ret < 0)
- return ret;
-
- csi2_init_formats(sd, NULL);
-
- /* Video device node */
- csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- csi2->video_out.ops = &csi2_ispvideo_ops;
- csi2->video_out.bpl_alignment = 32;
- csi2->video_out.bpl_zero_padding = 1;
- csi2->video_out.bpl_max = 0x1ffe0;
- csi2->video_out.isp = csi2->isp;
- csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
-
- ret = omap3isp_video_init(&csi2->video_out, "CSI2a");
- if (ret < 0)
- goto error_video;
-
- /* Connect the CSI2 subdev to the video node. */
- ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
- &csi2->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
- return 0;
-
-error_link:
- omap3isp_video_cleanup(&csi2->video_out);
-error_video:
- media_entity_cleanup(&csi2->subdev.entity);
- return ret;
-}
-
-/*
- * omap3isp_csi2_init - Routine for module driver init
- */
-int omap3isp_csi2_init(struct isp_device *isp)
-{
- struct isp_csi2_device *csi2a = &isp->isp_csi2a;
- struct isp_csi2_device *csi2c = &isp->isp_csi2c;
- int ret;
-
- csi2a->isp = isp;
- csi2a->available = 1;
- csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1;
- csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2;
- csi2a->phy = &isp->isp_csiphy2;
- csi2a->state = ISP_PIPELINE_STREAM_STOPPED;
- init_waitqueue_head(&csi2a->wait);
-
- ret = csi2_init_entities(csi2a);
- if (ret < 0)
- return ret;
-
- if (isp->revision == ISP_REVISION_15_0) {
- csi2c->isp = isp;
- csi2c->available = 1;
- csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1;
- csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2;
- csi2c->phy = &isp->isp_csiphy1;
- csi2c->state = ISP_PIPELINE_STREAM_STOPPED;
- init_waitqueue_head(&csi2c->wait);
- }
-
- return 0;
-}
-
-/*
- * omap3isp_csi2_cleanup - Routine for module driver cleanup
- */
-void omap3isp_csi2_cleanup(struct isp_device *isp)
-{
- struct isp_csi2_device *csi2a = &isp->isp_csi2a;
-
- omap3isp_video_cleanup(&csi2a->video_out);
- media_entity_cleanup(&csi2a->subdev.entity);
-}
diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c
deleted file mode 100644
index a3c76bf18175..000000000000
--- a/drivers/media/video/omap3isp/isph3a_aewb.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * isph3a.c
- *
- * TI OMAP3 ISP - H3A module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: David Cohen <dacohen@gmail.com>
- * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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/slab.h>
-#include <linux/uaccess.h>
-
-#include "isp.h"
-#include "isph3a.h"
-#include "ispstat.h"
-
-/*
- * h3a_aewb_update_regs - Helper function to update h3a registers.
- */
-static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
-{
- struct omap3isp_h3a_aewb_config *conf = priv;
- u32 pcr;
- u32 win1;
- u32 start;
- u32 blk;
- u32 subwin;
-
- if (aewb->state == ISPSTAT_DISABLED)
- return;
-
- isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
- OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
-
- if (!aewb->update)
- return;
-
- /* Converting config metadata into reg values */
- pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
- pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
-
- win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
- win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
- win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
- win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
-
- start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
- start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
-
- blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
- blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
-
- subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
- ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
- subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
- ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
-
- isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
- isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AEWINSTART);
- isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
- isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AEWSUBWIN);
- isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- ISPH3A_PCR_AEW_MASK, pcr);
-
- aewb->update = 0;
- aewb->config_counter += aewb->inc_config;
- aewb->inc_config = 0;
- aewb->buf_size = conf->buf_size;
-}
-
-static void h3a_aewb_enable(struct ispstat *aewb, int enable)
-{
- if (enable) {
- isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- ISPH3A_PCR_AEW_EN);
- /* This bit is already set if AF is enabled */
- if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
- isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_H3A_CLK_EN);
- } else {
- isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- ISPH3A_PCR_AEW_EN);
- /* This bit can't be cleared if AF is enabled */
- if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
- isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_H3A_CLK_EN);
- }
-}
-
-static int h3a_aewb_busy(struct ispstat *aewb)
-{
- return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
- & ISPH3A_PCR_BUSYAEAWB;
-}
-
-static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
-{
- /* Number of configured windows + extra row for black data */
- u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
-
- /*
- * Unsaturated block counts for each 8 windows.
- * 1 extra for the last (win_count % 8) windows if win_count is not
- * divisible by 8.
- */
- win_count += (win_count + 7) / 8;
-
- return win_count * AEWB_PACKET_SIZE;
-}
-
-static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
-{
- struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
- u32 buf_size;
-
- if (unlikely(user_cfg->saturation_limit >
- OMAP3ISP_AEWB_MAX_SATURATION_LIM))
- return -EINVAL;
-
- if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
- user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
- user_cfg->win_height & 0x01))
- return -EINVAL;
-
- if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
- user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
- user_cfg->win_width & 0x01))
- return -EINVAL;
-
- if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
- user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
- return -EINVAL;
-
- if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
- user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
- return -EINVAL;
-
- if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
- return -EINVAL;
-
- if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
- return -EINVAL;
-
- if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
- return -EINVAL;
-
- if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
- user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
- user_cfg->blk_win_height & 0x01))
- return -EINVAL;
-
- if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
- user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
- user_cfg->subsample_ver_inc & 0x01))
- return -EINVAL;
-
- if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
- user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
- user_cfg->subsample_hor_inc & 0x01))
- return -EINVAL;
-
- buf_size = h3a_aewb_get_buf_size(user_cfg);
- if (buf_size > user_cfg->buf_size)
- user_cfg->buf_size = buf_size;
- else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
- user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
-
- return 0;
-}
-
-/*
- * h3a_aewb_set_params - Helper function to check & store user given params.
- * @new_conf: Pointer to AE and AWB parameters struct.
- *
- * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
- * program them during ISR.
- */
-static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
-{
- struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
- struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
- int update = 0;
-
- if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
- cur_cfg->saturation_limit = user_cfg->saturation_limit;
- update = 1;
- }
- if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
- cur_cfg->alaw_enable = user_cfg->alaw_enable;
- update = 1;
- }
- if (cur_cfg->win_height != user_cfg->win_height) {
- cur_cfg->win_height = user_cfg->win_height;
- update = 1;
- }
- if (cur_cfg->win_width != user_cfg->win_width) {
- cur_cfg->win_width = user_cfg->win_width;
- update = 1;
- }
- if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
- cur_cfg->ver_win_count = user_cfg->ver_win_count;
- update = 1;
- }
- if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
- cur_cfg->hor_win_count = user_cfg->hor_win_count;
- update = 1;
- }
- if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
- cur_cfg->ver_win_start = user_cfg->ver_win_start;
- update = 1;
- }
- if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
- cur_cfg->hor_win_start = user_cfg->hor_win_start;
- update = 1;
- }
- if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
- cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
- update = 1;
- }
- if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
- cur_cfg->blk_win_height = user_cfg->blk_win_height;
- update = 1;
- }
- if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
- cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
- update = 1;
- }
- if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
- cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
- update = 1;
- }
-
- if (update || !aewb->configured) {
- aewb->inc_config++;
- aewb->update = 1;
- cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
- }
-}
-
-static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct ispstat *stat = v4l2_get_subdevdata(sd);
-
- switch (cmd) {
- case VIDIOC_OMAP3ISP_AEWB_CFG:
- return omap3isp_stat_config(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_REQ:
- return omap3isp_stat_request_statistics(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_EN: {
- unsigned long *en = arg;
- return omap3isp_stat_enable(stat, !!*en);
- }
- }
-
- return -ENOIOCTLCMD;
-}
-
-static const struct ispstat_ops h3a_aewb_ops = {
- .validate_params = h3a_aewb_validate_params,
- .set_params = h3a_aewb_set_params,
- .setup_regs = h3a_aewb_setup_regs,
- .enable = h3a_aewb_enable,
- .busy = h3a_aewb_busy,
-};
-
-static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
- .ioctl = h3a_aewb_ioctl,
- .subscribe_event = omap3isp_stat_subscribe_event,
- .unsubscribe_event = omap3isp_stat_unsubscribe_event,
-};
-
-static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
- .s_stream = omap3isp_stat_s_stream,
-};
-
-static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
- .core = &h3a_aewb_subdev_core_ops,
- .video = &h3a_aewb_subdev_video_ops,
-};
-
-/*
- * omap3isp_h3a_aewb_init - Module Initialisation.
- */
-int omap3isp_h3a_aewb_init(struct isp_device *isp)
-{
- struct ispstat *aewb = &isp->isp_aewb;
- struct omap3isp_h3a_aewb_config *aewb_cfg;
- struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
- int ret;
-
- aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
- if (!aewb_cfg)
- return -ENOMEM;
-
- memset(aewb, 0, sizeof(*aewb));
- aewb->ops = &h3a_aewb_ops;
- aewb->priv = aewb_cfg;
- aewb->dma_ch = -1;
- aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
- aewb->isp = isp;
-
- /* Set recover state configuration */
- aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
- if (!aewb_recover_cfg) {
- dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
- "recover configuration.\n");
- ret = -ENOMEM;
- goto err_recover_alloc;
- }
-
- aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
- aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
- aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
- aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
- aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
- aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
- aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
- aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
- aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
- aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
-
- if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
- dev_err(aewb->isp->dev, "AEWB: recover configuration is "
- "invalid.\n");
- ret = -EINVAL;
- goto err_conf;
- }
-
- aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
- aewb->recover_priv = aewb_recover_cfg;
-
- ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
- if (ret)
- goto err_conf;
-
- return 0;
-
-err_conf:
- kfree(aewb_recover_cfg);
-err_recover_alloc:
- kfree(aewb_cfg);
-
- return ret;
-}
-
-/*
- * omap3isp_h3a_aewb_cleanup - Module exit.
- */
-void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
-{
- kfree(isp->isp_aewb.priv);
- kfree(isp->isp_aewb.recover_priv);
- omap3isp_stat_cleanup(&isp->isp_aewb);
-}
diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c
deleted file mode 100644
index 58e0bc414899..000000000000
--- a/drivers/media/video/omap3isp/isph3a_af.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * isph3a_af.c
- *
- * TI OMAP3 ISP - H3A AF module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: David Cohen <dacohen@gmail.com>
- * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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
- */
-
-/* Linux specific include files */
-#include <linux/device.h>
-#include <linux/slab.h>
-
-#include "isp.h"
-#include "isph3a.h"
-#include "ispstat.h"
-
-#define IS_OUT_OF_BOUNDS(value, min, max) \
- (((value) < (min)) || ((value) > (max)))
-
-static void h3a_af_setup_regs(struct ispstat *af, void *priv)
-{
- struct omap3isp_h3a_af_config *conf = priv;
- u32 pcr;
- u32 pax1;
- u32 pax2;
- u32 paxstart;
- u32 coef;
- u32 base_coef_set0;
- u32 base_coef_set1;
- int index;
-
- if (af->state == ISPSTAT_DISABLED)
- return;
-
- isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AFBUFST);
-
- if (!af->update)
- return;
-
- /* Configure Hardware Registers */
- pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;
- /* Set height in AFPAX1 */
- pax1 |= (conf->paxel.height >> 1) - 1;
- isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
-
- /* Configure AFPAX2 Register */
- /* Set Line Increment in AFPAX2 Register */
- pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;
- /* Set Vertical Count */
- pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;
- /* Set Horizontal Count */
- pax2 |= (conf->paxel.h_cnt - 1);
- isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
-
- /* Configure PAXSTART Register */
- /*Configure Horizontal Start */
- paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;
- /* Configure Vertical Start */
- paxstart |= conf->paxel.v_start;
- isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AFPAXSTART);
-
- /*SetIIRSH Register */
- isp_reg_writel(af->isp, conf->iir.h_start,
- OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
-
- base_coef_set0 = ISPH3A_AFCOEF010;
- base_coef_set1 = ISPH3A_AFCOEF110;
- for (index = 0; index <= 8; index += 2) {
- /*Set IIR Filter0 Coefficients */
- coef = 0;
- coef |= conf->iir.coeff_set0[index];
- coef |= conf->iir.coeff_set0[index + 1] <<
- AF_COEF_SHIFT;
- isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
- base_coef_set0);
- base_coef_set0 += AFCOEF_OFFSET;
-
- /*Set IIR Filter1 Coefficients */
- coef = 0;
- coef |= conf->iir.coeff_set1[index];
- coef |= conf->iir.coeff_set1[index + 1] <<
- AF_COEF_SHIFT;
- isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
- base_coef_set1);
- base_coef_set1 += AFCOEF_OFFSET;
- }
- /* set AFCOEF0010 Register */
- isp_reg_writel(af->isp, conf->iir.coeff_set0[10],
- OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
- /* set AFCOEF1010 Register */
- isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
- OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
-
- /* PCR Register */
- /* Set RGB Position */
- pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;
- /* Set Accumulator Mode */
- if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)
- pcr |= AF_FVMODE;
- /* Set A-law */
- if (conf->alaw_enable)
- pcr |= AF_ALAW_EN;
- /* HMF Configurations */
- if (conf->hmf.enable) {
- /* Enable HMF */
- pcr |= AF_MED_EN;
- /* Set Median Threshold */
- pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;
- }
- /* Set PCR Register */
- isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- AF_PCR_MASK, pcr);
-
- af->update = 0;
- af->config_counter += af->inc_config;
- af->inc_config = 0;
- af->buf_size = conf->buf_size;
-}
-
-static void h3a_af_enable(struct ispstat *af, int enable)
-{
- if (enable) {
- isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- ISPH3A_PCR_AF_EN);
- /* This bit is already set if AEWB is enabled */
- if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
- isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_H3A_CLK_EN);
- } else {
- isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
- ISPH3A_PCR_AF_EN);
- /* This bit can't be cleared if AEWB is enabled */
- if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
- isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_H3A_CLK_EN);
- }
-}
-
-static int h3a_af_busy(struct ispstat *af)
-{
- return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
- & ISPH3A_PCR_BUSYAF;
-}
-
-static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)
-{
- return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;
-}
-
-/* Function to check paxel parameters */
-static int h3a_af_validate_params(struct ispstat *af, void *new_conf)
-{
- struct omap3isp_h3a_af_config *user_cfg = new_conf;
- struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;
- struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;
- int index;
- u32 buf_size;
-
- /* Check horizontal Count */
- if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,
- OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,
- OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))
- return -EINVAL;
-
- /* Check Vertical Count */
- if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
- OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,
- OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))
- return -EINVAL;
-
- if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,
- OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||
- paxel_cfg->height % 2)
- return -EINVAL;
-
- /* Check width */
- if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,
- OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||
- paxel_cfg->width % 2)
- return -EINVAL;
-
- /* Check Line Increment */
- if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
- OMAP3ISP_AF_PAXEL_INCREMENT_MIN,
- OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||
- paxel_cfg->line_inc % 2)
- return -EINVAL;
-
- /* Check Horizontal Start */
- if ((paxel_cfg->h_start < iir_cfg->h_start) ||
- IS_OUT_OF_BOUNDS(paxel_cfg->h_start,
- OMAP3ISP_AF_PAXEL_HZSTART_MIN,
- OMAP3ISP_AF_PAXEL_HZSTART_MAX))
- return -EINVAL;
-
- /* Check IIR */
- for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
- if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)
- return -EINVAL;
-
- if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)
- return -EINVAL;
- }
-
- if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,
- OMAP3ISP_AF_IIRSH_MAX))
- return -EINVAL;
-
- /* Hack: If paxel size is 12, the 10th AF window may be corrupted */
- if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&
- (paxel_cfg->width * paxel_cfg->height == 12))
- return -EINVAL;
-
- buf_size = h3a_af_get_buf_size(user_cfg);
- if (buf_size > user_cfg->buf_size)
- /* User buf_size request wasn't enough */
- user_cfg->buf_size = buf_size;
- else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)
- user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;
-
- return 0;
-}
-
-/* Update local parameters */
-static void h3a_af_set_params(struct ispstat *af, void *new_conf)
-{
- struct omap3isp_h3a_af_config *user_cfg = new_conf;
- struct omap3isp_h3a_af_config *cur_cfg = af->priv;
- int update = 0;
- int index;
-
- /* alaw */
- if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
- update = 1;
- goto out;
- }
-
- /* hmf */
- if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {
- update = 1;
- goto out;
- }
- if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {
- update = 1;
- goto out;
- }
-
- /* rgbpos */
- if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {
- update = 1;
- goto out;
- }
-
- /* iir */
- if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {
- update = 1;
- goto out;
- }
- for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
- if (cur_cfg->iir.coeff_set0[index] !=
- user_cfg->iir.coeff_set0[index]) {
- update = 1;
- goto out;
- }
- if (cur_cfg->iir.coeff_set1[index] !=
- user_cfg->iir.coeff_set1[index]) {
- update = 1;
- goto out;
- }
- }
-
- /* paxel */
- if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||
- (cur_cfg->paxel.height != user_cfg->paxel.height) ||
- (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||
- (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||
- (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||
- (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||
- (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {
- update = 1;
- goto out;
- }
-
- /* af_mode */
- if (cur_cfg->fvmode != user_cfg->fvmode)
- update = 1;
-
-out:
- if (update || !af->configured) {
- memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));
- af->inc_config++;
- af->update = 1;
- /*
- * User might be asked for a bigger buffer than necessary for
- * this configuration. In order to return the right amount of
- * data during buffer request, let's calculate the size here
- * instead of stick with user_cfg->buf_size.
- */
- cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);
- }
-}
-
-static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct ispstat *stat = v4l2_get_subdevdata(sd);
-
- switch (cmd) {
- case VIDIOC_OMAP3ISP_AF_CFG:
- return omap3isp_stat_config(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_REQ:
- return omap3isp_stat_request_statistics(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_EN: {
- int *en = arg;
- return omap3isp_stat_enable(stat, !!*en);
- }
- }
-
- return -ENOIOCTLCMD;
-
-}
-
-static const struct ispstat_ops h3a_af_ops = {
- .validate_params = h3a_af_validate_params,
- .set_params = h3a_af_set_params,
- .setup_regs = h3a_af_setup_regs,
- .enable = h3a_af_enable,
- .busy = h3a_af_busy,
-};
-
-static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {
- .ioctl = h3a_af_ioctl,
- .subscribe_event = omap3isp_stat_subscribe_event,
- .unsubscribe_event = omap3isp_stat_unsubscribe_event,
-};
-
-static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {
- .s_stream = omap3isp_stat_s_stream,
-};
-
-static const struct v4l2_subdev_ops h3a_af_subdev_ops = {
- .core = &h3a_af_subdev_core_ops,
- .video = &h3a_af_subdev_video_ops,
-};
-
-/* Function to register the AF character device driver. */
-int omap3isp_h3a_af_init(struct isp_device *isp)
-{
- struct ispstat *af = &isp->isp_af;
- struct omap3isp_h3a_af_config *af_cfg;
- struct omap3isp_h3a_af_config *af_recover_cfg;
- int ret;
-
- af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
- if (af_cfg == NULL)
- return -ENOMEM;
-
- memset(af, 0, sizeof(*af));
- af->ops = &h3a_af_ops;
- af->priv = af_cfg;
- af->dma_ch = -1;
- af->event_type = V4L2_EVENT_OMAP3ISP_AF;
- af->isp = isp;
-
- /* Set recover state configuration */
- af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
- if (!af_recover_cfg) {
- dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
- "configuration.\n");
- ret = -ENOMEM;
- goto err_recover_alloc;
- }
-
- af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
- af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;
- af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;
- af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;
- af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;
- af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;
- if (h3a_af_validate_params(af, af_recover_cfg)) {
- dev_err(af->isp->dev, "AF: recover configuration is "
- "invalid.\n");
- ret = -EINVAL;
- goto err_conf;
- }
-
- af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
- af->recover_priv = af_recover_cfg;
-
- ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
- if (ret)
- goto err_conf;
-
- return 0;
-
-err_conf:
- kfree(af_recover_cfg);
-err_recover_alloc:
- kfree(af_cfg);
-
- return ret;
-}
-
-void omap3isp_h3a_af_cleanup(struct isp_device *isp)
-{
- kfree(isp->isp_af.priv);
- kfree(isp->isp_af.recover_priv);
- omap3isp_stat_cleanup(&isp->isp_af);
-}
diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c
deleted file mode 100644
index 1163907bcddc..000000000000
--- a/drivers/media/video/omap3isp/isphist.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * isphist.c
- *
- * TI OMAP3 ISP - Histogram module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: David Cohen <dacohen@gmail.com>
- * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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/slab.h>
-#include <linux/uaccess.h>
-#include <linux/device.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "isphist.h"
-
-#define HIST_CONFIG_DMA 1
-
-#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
-
-/*
- * hist_reset_mem - clear Histogram memory before start stats engine.
- */
-static void hist_reset_mem(struct ispstat *hist)
-{
- struct isp_device *isp = hist->isp;
- struct omap3isp_hist_config *conf = hist->priv;
- unsigned int i;
-
- isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
-
- /*
- * By setting it, the histogram internal buffer is being cleared at the
- * same time it's being read. This bit must be cleared afterwards.
- */
- isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
-
- /*
- * We'll clear 4 words at each iteration for optimization. It avoids
- * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
- */
- for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) {
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- }
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
-
- hist->wait_acc_frames = conf->num_acc_frames;
-}
-
-static void hist_dma_config(struct ispstat *hist)
-{
- hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
- hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
- hist->dma_config.frame_count = 1;
- hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
- hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
- hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
- hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
-}
-
-/*
- * hist_setup_regs - Helper function to update Histogram registers.
- */
-static void hist_setup_regs(struct ispstat *hist, void *priv)
-{
- struct isp_device *isp = hist->isp;
- struct omap3isp_hist_config *conf = priv;
- int c;
- u32 cnt;
- u32 wb_gain;
- u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS];
- u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS];
-
- if (!hist->update || hist->state == ISPSTAT_DISABLED ||
- hist->state == ISPSTAT_DISABLING)
- return;
-
- cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT;
-
- wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT;
- wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT;
- wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT;
- if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER)
- wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT;
-
- /* Regions size and position */
- for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
- if (c < conf->num_regions) {
- reg_hor[c] = conf->region[c].h_start <<
- ISPHIST_REG_START_SHIFT;
- reg_hor[c] = conf->region[c].h_end <<
- ISPHIST_REG_END_SHIFT;
- reg_ver[c] = conf->region[c].v_start <<
- ISPHIST_REG_START_SHIFT;
- reg_ver[c] = conf->region[c].v_end <<
- ISPHIST_REG_END_SHIFT;
- } else {
- reg_hor[c] = 0;
- reg_ver[c] = 0;
- }
- }
-
- cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT;
- switch (conf->hist_bins) {
- case OMAP3ISP_HIST_BINS_256:
- cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) <<
- ISPHIST_CNT_SHIFT_SHIFT;
- break;
- case OMAP3ISP_HIST_BINS_128:
- cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) <<
- ISPHIST_CNT_SHIFT_SHIFT;
- break;
- case OMAP3ISP_HIST_BINS_64:
- cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) <<
- ISPHIST_CNT_SHIFT_SHIFT;
- break;
- default: /* OMAP3ISP_HIST_BINS_32 */
- cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) <<
- ISPHIST_CNT_SHIFT_SHIFT;
- break;
- }
-
- hist_reset_mem(hist);
-
- isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
- isp_reg_writel(isp, wb_gain, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
- isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ);
- isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT);
- isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ);
- isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT);
- isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ);
- isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT);
- isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ);
- isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT);
-
- hist->update = 0;
- hist->config_counter += hist->inc_config;
- hist->inc_config = 0;
- hist->buf_size = conf->buf_size;
-}
-
-static void hist_enable(struct ispstat *hist, int enable)
-{
- if (enable) {
- isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
- ISPHIST_PCR_ENABLE);
- isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_HIST_CLK_EN);
- } else {
- isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
- ISPHIST_PCR_ENABLE);
- isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_HIST_CLK_EN);
- }
-}
-
-static int hist_busy(struct ispstat *hist)
-{
- return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
- & ISPHIST_PCR_BUSY;
-}
-
-static void hist_dma_cb(int lch, u16 ch_status, void *data)
-{
- struct ispstat *hist = data;
-
- if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
- dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
- ch_status);
- omap_stop_dma(lch);
- hist_reset_mem(hist);
- atomic_set(&hist->buf_err, 1);
- }
- isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
- ISPHIST_CNT_CLEAR);
-
- omap3isp_stat_dma_isr(hist);
- if (hist->state != ISPSTAT_DISABLED)
- omap3isp_hist_dma_done(hist->isp);
-}
-
-static int hist_buf_dma(struct ispstat *hist)
-{
- dma_addr_t dma_addr = hist->active_buf->dma_addr;
-
- if (unlikely(!dma_addr)) {
- dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
- hist_reset_mem(hist);
- return STAT_NO_BUF;
- }
-
- isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
- isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
- ISPHIST_CNT_CLEAR);
- omap3isp_flush(hist->isp);
- hist->dma_config.dst_start = dma_addr;
- hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
- omap_set_dma_params(hist->dma_ch, &hist->dma_config);
-
- omap_start_dma(hist->dma_ch);
-
- return STAT_BUF_WAITING_DMA;
-}
-
-static int hist_buf_pio(struct ispstat *hist)
-{
- struct isp_device *isp = hist->isp;
- u32 *buf = hist->active_buf->virt_addr;
- unsigned int i;
-
- if (!buf) {
- dev_dbg(isp->dev, "hist: invalid PIO buffer address\n");
- hist_reset_mem(hist);
- return STAT_NO_BUF;
- }
-
- isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
-
- /*
- * By setting it, the histogram internal buffer is being cleared at the
- * same time it's being read. This bit must be cleared just after all
- * data is acquired.
- */
- isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
-
- /*
- * We'll read 4 times a 4-bytes-word at each iteration for
- * optimization. It avoids 3/4 of the jumps. We also know buf_size is
- * divisible by 16.
- */
- for (i = hist->buf_size / 16; i > 0; i--) {
- *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- }
- isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
- ISPHIST_CNT_CLEAR);
-
- return STAT_BUF_DONE;
-}
-
-/*
- * hist_buf_process - Callback from ISP driver for HIST interrupt.
- */
-static int hist_buf_process(struct ispstat *hist)
-{
- struct omap3isp_hist_config *user_cfg = hist->priv;
- int ret;
-
- if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) {
- hist_reset_mem(hist);
- return STAT_NO_BUF;
- }
-
- if (--(hist->wait_acc_frames))
- return STAT_NO_BUF;
-
- if (HIST_USING_DMA(hist))
- ret = hist_buf_dma(hist);
- else
- ret = hist_buf_pio(hist);
-
- hist->wait_acc_frames = user_cfg->num_acc_frames;
-
- return ret;
-}
-
-static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
-{
- return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions;
-}
-
-/*
- * hist_validate_params - Helper function to check user given params.
- * @user_cfg: Pointer to user configuration structure.
- *
- * Returns 0 on success configuration.
- */
-static int hist_validate_params(struct ispstat *hist, void *new_conf)
-{
- struct omap3isp_hist_config *user_cfg = new_conf;
- int c;
- u32 buf_size;
-
- if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3)
- return -EINVAL;
-
- /* Regions size and position */
-
- if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) ||
- (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS))
- return -EINVAL;
-
- /* Regions */
- for (c = 0; c < user_cfg->num_regions; c++) {
- if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK)
- return -EINVAL;
- if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK)
- return -EINVAL;
- if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK)
- return -EINVAL;
- if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK)
- return -EINVAL;
- if (user_cfg->region[c].h_start > user_cfg->region[c].h_end)
- return -EINVAL;
- if (user_cfg->region[c].v_start > user_cfg->region[c].v_end)
- return -EINVAL;
- }
-
- switch (user_cfg->num_regions) {
- case 1:
- if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256)
- return -EINVAL;
- break;
- case 2:
- if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128)
- return -EINVAL;
- break;
- default: /* 3 or 4 */
- if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64)
- return -EINVAL;
- break;
- }
-
- buf_size = hist_get_buf_size(user_cfg);
- if (buf_size > user_cfg->buf_size)
- /* User's buf_size request wasn't enoght */
- user_cfg->buf_size = buf_size;
- else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
- user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
-
- return 0;
-}
-
-static int hist_comp_params(struct ispstat *hist,
- struct omap3isp_hist_config *user_cfg)
-{
- struct omap3isp_hist_config *cur_cfg = hist->priv;
- int c;
-
- if (cur_cfg->cfa != user_cfg->cfa)
- return 1;
-
- if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
- return 1;
-
- if (cur_cfg->hist_bins != user_cfg->hist_bins)
- return 1;
-
- for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) {
- if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3)
- break;
- else if (cur_cfg->wg[c] != user_cfg->wg[c])
- return 1;
- }
-
- if (cur_cfg->num_regions != user_cfg->num_regions)
- return 1;
-
- /* Regions */
- for (c = 0; c < user_cfg->num_regions; c++) {
- if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start)
- return 1;
- if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end)
- return 1;
- if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start)
- return 1;
- if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end)
- return 1;
- }
-
- return 0;
-}
-
-/*
- * hist_update_params - Helper function to check and store user given params.
- * @new_conf: Pointer to user configuration structure.
- */
-static void hist_set_params(struct ispstat *hist, void *new_conf)
-{
- struct omap3isp_hist_config *user_cfg = new_conf;
- struct omap3isp_hist_config *cur_cfg = hist->priv;
-
- if (!hist->configured || hist_comp_params(hist, user_cfg)) {
- memcpy(cur_cfg, user_cfg, sizeof(*user_cfg));
- if (user_cfg->num_acc_frames == 0)
- user_cfg->num_acc_frames = 1;
- hist->inc_config++;
- hist->update = 1;
- /*
- * User might be asked for a bigger buffer than necessary for
- * this configuration. In order to return the right amount of
- * data during buffer request, let's calculate the size here
- * instead of stick with user_cfg->buf_size.
- */
- cur_cfg->buf_size = hist_get_buf_size(cur_cfg);
-
- }
-}
-
-static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct ispstat *stat = v4l2_get_subdevdata(sd);
-
- switch (cmd) {
- case VIDIOC_OMAP3ISP_HIST_CFG:
- return omap3isp_stat_config(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_REQ:
- return omap3isp_stat_request_statistics(stat, arg);
- case VIDIOC_OMAP3ISP_STAT_EN: {
- int *en = arg;
- return omap3isp_stat_enable(stat, !!*en);
- }
- }
-
- return -ENOIOCTLCMD;
-
-}
-
-static const struct ispstat_ops hist_ops = {
- .validate_params = hist_validate_params,
- .set_params = hist_set_params,
- .setup_regs = hist_setup_regs,
- .enable = hist_enable,
- .busy = hist_busy,
- .buf_process = hist_buf_process,
-};
-
-static const struct v4l2_subdev_core_ops hist_subdev_core_ops = {
- .ioctl = hist_ioctl,
- .subscribe_event = omap3isp_stat_subscribe_event,
- .unsubscribe_event = omap3isp_stat_unsubscribe_event,
-};
-
-static const struct v4l2_subdev_video_ops hist_subdev_video_ops = {
- .s_stream = omap3isp_stat_s_stream,
-};
-
-static const struct v4l2_subdev_ops hist_subdev_ops = {
- .core = &hist_subdev_core_ops,
- .video = &hist_subdev_video_ops,
-};
-
-/*
- * omap3isp_hist_init - Module Initialization.
- */
-int omap3isp_hist_init(struct isp_device *isp)
-{
- struct ispstat *hist = &isp->isp_hist;
- struct omap3isp_hist_config *hist_cfg;
- int ret = -1;
-
- hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
- if (hist_cfg == NULL)
- return -ENOMEM;
-
- memset(hist, 0, sizeof(*hist));
- if (HIST_CONFIG_DMA)
- ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
- hist_dma_cb, hist, &hist->dma_ch);
- if (ret) {
- if (HIST_CONFIG_DMA)
- dev_warn(isp->dev, "hist: DMA request channel failed. "
- "Using PIO only.\n");
- hist->dma_ch = -1;
- } else {
- dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
- hist_dma_config(hist);
- omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
- }
-
- hist->ops = &hist_ops;
- hist->priv = hist_cfg;
- hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
- hist->isp = isp;
-
- ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
- if (ret) {
- kfree(hist_cfg);
- if (HIST_USING_DMA(hist))
- omap_free_dma(hist->dma_ch);
- }
-
- return ret;
-}
-
-/*
- * omap3isp_hist_cleanup - Module cleanup.
- */
-void omap3isp_hist_cleanup(struct isp_device *isp)
-{
- if (HIST_USING_DMA(&isp->isp_hist))
- omap_free_dma(isp->isp_hist.dma_ch);
- kfree(isp->isp_hist.priv);
- omap3isp_stat_cleanup(&isp->isp_hist);
-}
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
deleted file mode 100644
index 53f5a703e31a..000000000000
--- a/drivers/media/video/omap3isp/isppreview.c
+++ /dev/null
@@ -1,2369 +0,0 @@
-/*
- * isppreview.c
- *
- * TI OMAP3 ISP driver - Preview module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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/mm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "isppreview.h"
-
-/* Default values in Office Fluorescent Light for RGBtoRGB Blending */
-static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
- { /* RGB-RGB Matrix */
- {0x01E2, 0x0F30, 0x0FEE},
- {0x0F9B, 0x01AC, 0x0FB9},
- {0x0FE0, 0x0EC0, 0x0260}
- }, /* RGB Offset */
- {0x0000, 0x0000, 0x0000}
-};
-
-/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/
-static struct omap3isp_prev_csc flr_prev_csc = {
- { /* CSC Coef Matrix */
- {66, 129, 25},
- {-38, -75, 112},
- {112, -94 , -18}
- }, /* CSC Offset */
- {0x0, 0x0, 0x0}
-};
-
-/* Default values in Office Fluorescent Light for CFA Gradient*/
-#define FLR_CFA_GRADTHRS_HORZ 0x28
-#define FLR_CFA_GRADTHRS_VERT 0x28
-
-/* Default values in Office Fluorescent Light for Chroma Suppression*/
-#define FLR_CSUP_GAIN 0x0D
-#define FLR_CSUP_THRES 0xEB
-
-/* Default values in Office Fluorescent Light for Noise Filter*/
-#define FLR_NF_STRGTH 0x03
-
-/* Default values for White Balance */
-#define FLR_WBAL_DGAIN 0x100
-#define FLR_WBAL_COEF 0x20
-
-/* Default values in Office Fluorescent Light for Black Adjustment*/
-#define FLR_BLKADJ_BLUE 0x0
-#define FLR_BLKADJ_GREEN 0x0
-#define FLR_BLKADJ_RED 0x0
-
-#define DEF_DETECT_CORRECT_VAL 0xe
-
-/*
- * Margins and image size limits.
- *
- * The preview engine crops several rows and columns internally depending on
- * which filters are enabled. To avoid format changes when the filters are
- * enabled or disabled (which would prevent them from being turned on or off
- * during streaming), the driver assumes all the filters are enabled when
- * computing sink crop and source format limits.
- *
- * If a filter is disabled, additional cropping is automatically added at the
- * preview engine input by the driver to avoid overflow at line and frame end.
- * This is completely transparent for applications.
- *
- * Median filter 4 pixels
- * Noise filter,
- * Faulty pixels correction 4 pixels, 4 lines
- * CFA filter 4 pixels, 4 lines in Bayer mode
- * 2 lines in other modes
- * Color suppression 2 pixels
- * or luma enhancement
- * -------------------------------------------------------------
- * Maximum total 14 pixels, 8 lines
- *
- * The color suppression and luma enhancement filters are applied after bayer to
- * YUV conversion. They thus can crop one pixel on the left and one pixel on the
- * right side of the image without changing the color pattern. When both those
- * filters are disabled, the driver must crop the two pixels on the same side of
- * the image to avoid changing the bayer pattern. The left margin is thus set to
- * 8 pixels and the right margin to 6 pixels.
- */
-
-#define PREV_MARGIN_LEFT 8
-#define PREV_MARGIN_RIGHT 6
-#define PREV_MARGIN_TOP 4
-#define PREV_MARGIN_BOTTOM 4
-
-#define PREV_MIN_IN_WIDTH 64
-#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_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.
- * Array is initialised with the values from.the tables text file.
- */
-
-/*
- * CFA Filter Coefficient Table
- *
- */
-static u32 cfa_coef_table[] = {
-#include "cfa_coef_table.h"
-};
-
-/*
- * Default Gamma Correction Table - All components
- */
-static u32 gamma_table[] = {
-#include "gamma_table.h"
-};
-
-/*
- * Noise Filter Threshold table
- */
-static u32 noise_filter_table[] = {
-#include "noise_filter_table.h"
-};
-
-/*
- * Luminance Enhancement Table
- */
-static u32 luma_enhance_table[] = {
-#include "luma_enhance_table.h"
-};
-
-/*
- * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
- * @enable: 1 - Reverse the A-Law done in CCDC.
- */
-static void
-preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
-}
-
-/*
- * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
- * @prev -
- * @enable: 1 - Enable, 0 - Disable
- *
- * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
- * The process is applied for each captured frame.
- */
-static void
-preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DRKFCAP);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DRKFCAP);
-}
-
-/*
- * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
- * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
- * subtracted with the pixels in the current frame.
- *
- * The process is applied for each captured frame.
- */
-static void
-preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DRKFEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DRKFEN);
-}
-
-/*
- * preview_config_drkf_shadcomp - Configures shift value in shading comp.
- * @scomp_shtval: 3bit value of shift used in shading compensation.
- */
-static void
-preview_config_drkf_shadcomp(struct isp_prev_device *prev,
- const void *scomp_shtval)
-{
- struct isp_device *isp = to_isp_device(prev);
- const u32 *shtval = scomp_shtval;
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SCOMP_SFT_MASK,
- *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT);
-}
-
-/*
- * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
- * @enable: 1 - Enables Horizontal Median Filter.
- */
-static void
-preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_HMEDEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_HMEDEN);
-}
-
-/*
- * preview_config_hmed - Configures the Horizontal Median Filter.
- * @prev_hmed: Structure containing the odd and even distance between the
- * pixels in the image along with the filter threshold.
- */
-static void
-preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_hmed *hmed = prev_hmed;
-
- isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
- (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
- (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
- OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
-}
-
-/*
- * preview_config_noisefilter - Configures the Noise Filter.
- * @prev_nf: Structure containing the noisefilter table, strength to be used
- * for the noise filter and the defect correction enable flag.
- */
-static void
-preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_nf *nf = prev_nf;
- unsigned int i;
-
- isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
- isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
- isp_reg_writel(isp, nf->table[i],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
- }
-}
-
-/*
- * preview_config_dcor - Configures the defect correction
- * @prev_dcor: Structure containing the defect correct thresholds
- */
-static void
-preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_dcor *dcor = prev_dcor;
-
- isp_reg_writel(isp, dcor->detect_correct[0],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
- isp_reg_writel(isp, dcor->detect_correct[1],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
- isp_reg_writel(isp, dcor->detect_correct[2],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
- isp_reg_writel(isp, dcor->detect_correct[3],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DCCOUP,
- dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
-}
-
-/*
- * preview_config_cfa - Configures the CFA Interpolation parameters.
- * @prev_cfa: Structure containing the CFA interpolation table, CFA format
- * in the image, vertical and horizontal gradient threshold.
- */
-static void
-preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_cfa *cfa = prev_cfa;
- unsigned int i;
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_CFAFMT_MASK,
- cfa->format << ISPPRV_PCR_CFAFMT_SHIFT);
-
- isp_reg_writel(isp,
- (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
- (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
-
- isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-
- for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) {
- isp_reg_writel(isp, cfa->table[i],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
- }
-}
-
-/*
- * preview_config_gammacorrn - Configures the Gamma Correction table values
- * @gtable: Structure containing the table for red, blue, green gamma table.
- */
-static void
-preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_gtables *gt = gtable;
- unsigned int i;
-
- isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
- isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_DATA);
-
- isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
- isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_DATA);
-
- isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
- isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_DATA);
-}
-
-/*
- * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
- * @ytable: Structure containing the table for Luminance Enhancement table.
- */
-static void
-preview_config_luma_enhancement(struct isp_prev_device *prev,
- const void *ytable)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_luma *yt = ytable;
- unsigned int i;
-
- isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
- isp_reg_writel(isp, yt->table[i],
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
- }
-}
-
-/*
- * preview_config_chroma_suppression - Configures the Chroma Suppression.
- * @csup: Structure containing the threshold value for suppression
- * and the hypass filter enable flag.
- */
-static void
-preview_config_chroma_suppression(struct isp_prev_device *prev,
- const void *csup)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_csup *cs = csup;
-
- isp_reg_writel(isp,
- cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
- (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
- OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
-}
-
-/*
- * preview_enable_noisefilter - Enables/Disables the Noise Filter.
- * @enable: 1 - Enables the Noise Filter.
- */
-static void
-preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_NFEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_NFEN);
-}
-
-/*
- * preview_enable_dcor - Enables/Disables the defect correction.
- * @enable: 1 - Enables the defect correction.
- */
-static void
-preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DCOREN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_DCOREN);
-}
-
-/*
- * preview_enable_gammabypass - Enables/Disables the GammaByPass
- * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
- * 0 - Goes through Gamma Correction. input and output is 10bit.
- */
-static void
-preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_GAMMA_BYPASS);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_GAMMA_BYPASS);
-}
-
-/*
- * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
- * @enable: 1 - Enable the Luminance Enhancement.
- */
-static void
-preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_YNENHEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_YNENHEN);
-}
-
-/*
- * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
- * @enable: 1 - Enable the Chrominance Suppression.
- */
-static void
-preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SUPEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SUPEN);
-}
-
-/*
- * preview_config_whitebalance - Configures the White Balance parameters.
- * @prev_wbal: Structure containing the digital gain and white balance
- * coefficient.
- *
- * Coefficient matrix always with default values.
- */
-static void
-preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_wbal *wbal = prev_wbal;
- u32 val;
-
- isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
-
- val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
- val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
- val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
- val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
-
- isp_reg_writel(isp,
- ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
- ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
- ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
- ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
- ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
- ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
- ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
- ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
- ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
- ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
- ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
- ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
- ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
- ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
- ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
- ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
-}
-
-/*
- * preview_config_blkadj - Configures the Black Adjustment parameters.
- * @prev_blkadj: Structure containing the black adjustment towards red, green,
- * blue.
- */
-static void
-preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_blkadj *blkadj = prev_blkadj;
-
- isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
- (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
- (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
- OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
-}
-
-/*
- * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
- * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
- * offset.
- */
-static void
-preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb;
- u32 val;
-
- val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
- val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
-
- val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
- val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
-
- val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
- val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
-
- val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
- val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
-
- val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
-
- val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
- val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
-
- val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
-}
-
-/*
- * Configures the color space conversion (RGB toYCbYCr) matrix
- * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
- * YCbCr offset.
- */
-static void
-preview_config_csc(struct isp_prev_device *prev, const void *prev_csc)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_csc *csc = prev_csc;
- u32 val;
-
- val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
- val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
- val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
-
- val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
- val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
- val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
-
- val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
- val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
- val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
-
- val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
- val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
- val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
- isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
-}
-
-/*
- * preview_update_contrast - Updates the contrast.
- * @contrast: Pointer to hold the current programmed contrast value.
- *
- * Value should be programmed before enabling the module.
- */
-static void
-preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
-{
- struct prev_params *params;
- unsigned long flags;
-
- spin_lock_irqsave(&prev->params.lock, flags);
- params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
- ? &prev->params.params[0] : &prev->params.params[1];
-
- if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
- params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
- params->update |= OMAP3ISP_PREV_CONTRAST;
- }
- spin_unlock_irqrestore(&prev->params.lock, flags);
-}
-
-/*
- * preview_config_contrast - Configures the Contrast.
- * @params: Contrast value (u8 pointer, U8Q0 format).
- *
- * Value should be programmed before enabling the module.
- */
-static void
-preview_config_contrast(struct isp_prev_device *prev, const void *params)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
- 0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
- *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT);
-}
-
-/*
- * preview_update_brightness - Updates the brightness in preview module.
- * @brightness: Pointer to hold the current programmed brightness value.
- *
- */
-static void
-preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
-{
- struct prev_params *params;
- unsigned long flags;
-
- spin_lock_irqsave(&prev->params.lock, flags);
- params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
- ? &prev->params.params[0] : &prev->params.params[1];
-
- if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
- params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
- params->update |= OMAP3ISP_PREV_BRIGHTNESS;
- }
- spin_unlock_irqrestore(&prev->params.lock, flags);
-}
-
-/*
- * preview_config_brightness - Configures the brightness.
- * @params: Brightness value (u8 pointer, U8Q0 format).
- */
-static void
-preview_config_brightness(struct isp_prev_device *prev, const void *params)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
- 0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
- *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT);
-}
-
-/*
- * preview_config_yc_range - Configures the max and min Y and C values.
- * @yclimit: Structure containing the range of Y and C values.
- */
-static void
-preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
-{
- struct isp_device *isp = to_isp_device(prev);
- const struct omap3isp_prev_yclimit *yc = yclimit;
-
- isp_reg_writel(isp,
- yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
- yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
- yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
- yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
-}
-
-static u32
-preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
-{
- u32 active = prev->params.active;
-
- if (shadow) {
- /* Mark all shadow parameters we are going to touch as busy. */
- prev->params.params[0].busy |= ~active & update;
- prev->params.params[1].busy |= active & update;
- } else {
- /* Mark all active parameters we are going to touch as busy. */
- update = (prev->params.params[0].update & active)
- | (prev->params.params[1].update & ~active);
-
- prev->params.params[0].busy |= active & update;
- prev->params.params[1].busy |= ~active & update;
- }
-
- return update;
-}
-
-static void
-preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
-{
- u32 active = prev->params.active;
-
- if (shadow) {
- /* Set the update flag for shadow parameters that have been
- * updated and clear the busy flag for all shadow parameters.
- */
- prev->params.params[0].update |= (~active & update);
- prev->params.params[1].update |= (active & update);
- prev->params.params[0].busy &= active;
- prev->params.params[1].busy &= ~active;
- } else {
- /* Clear the update flag for active parameters that have been
- * applied and the busy flag for all active parameters.
- */
- prev->params.params[0].update &= ~(active & update);
- prev->params.params[1].update &= ~(~active & update);
- prev->params.params[0].busy &= ~active;
- prev->params.params[1].busy &= active;
- }
-}
-
-static void preview_params_switch(struct isp_prev_device *prev)
-{
- u32 to_switch;
-
- /* Switch active parameters with updated shadow parameters when the
- * shadow parameter has been updated and neither the active not the
- * shadow parameter is busy.
- */
- to_switch = (prev->params.params[0].update & ~prev->params.active)
- | (prev->params.params[1].update & prev->params.active);
- to_switch &= ~(prev->params.params[0].busy |
- prev->params.params[1].busy);
- if (to_switch == 0)
- return;
-
- prev->params.active ^= to_switch;
-
- /* Remove the update flag for the shadow copy of parameters we have
- * switched.
- */
- prev->params.params[0].update &= ~(~prev->params.active & to_switch);
- prev->params.params[1].update &= ~(prev->params.active & to_switch);
-}
-
-/* preview parameters update structure */
-struct preview_update {
- void (*config)(struct isp_prev_device *, const void *);
- void (*enable)(struct isp_prev_device *, u8);
- unsigned int param_offset;
- unsigned int param_size;
- unsigned int config_offset;
- bool skip;
-};
-
-/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
-static const struct preview_update update_attrs[] = {
- /* OMAP3ISP_PREV_LUMAENH */ {
- preview_config_luma_enhancement,
- preview_enable_luma_enhancement,
- offsetof(struct prev_params, luma),
- FIELD_SIZEOF(struct prev_params, luma),
- offsetof(struct omap3isp_prev_update_config, luma),
- }, /* OMAP3ISP_PREV_INVALAW */ {
- NULL,
- preview_enable_invalaw,
- }, /* OMAP3ISP_PREV_HRZ_MED */ {
- preview_config_hmed,
- preview_enable_hmed,
- offsetof(struct prev_params, hmed),
- FIELD_SIZEOF(struct prev_params, hmed),
- offsetof(struct omap3isp_prev_update_config, hmed),
- }, /* OMAP3ISP_PREV_CFA */ {
- preview_config_cfa,
- NULL,
- offsetof(struct prev_params, cfa),
- FIELD_SIZEOF(struct prev_params, cfa),
- offsetof(struct omap3isp_prev_update_config, cfa),
- }, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
- preview_config_chroma_suppression,
- preview_enable_chroma_suppression,
- offsetof(struct prev_params, csup),
- FIELD_SIZEOF(struct prev_params, csup),
- offsetof(struct omap3isp_prev_update_config, csup),
- }, /* OMAP3ISP_PREV_WB */ {
- preview_config_whitebalance,
- NULL,
- offsetof(struct prev_params, wbal),
- FIELD_SIZEOF(struct prev_params, wbal),
- offsetof(struct omap3isp_prev_update_config, wbal),
- }, /* OMAP3ISP_PREV_BLKADJ */ {
- preview_config_blkadj,
- NULL,
- offsetof(struct prev_params, blkadj),
- FIELD_SIZEOF(struct prev_params, blkadj),
- offsetof(struct omap3isp_prev_update_config, blkadj),
- }, /* OMAP3ISP_PREV_RGB2RGB */ {
- preview_config_rgb_blending,
- NULL,
- offsetof(struct prev_params, rgb2rgb),
- FIELD_SIZEOF(struct prev_params, rgb2rgb),
- offsetof(struct omap3isp_prev_update_config, rgb2rgb),
- }, /* OMAP3ISP_PREV_COLOR_CONV */ {
- preview_config_csc,
- NULL,
- offsetof(struct prev_params, csc),
- FIELD_SIZEOF(struct prev_params, csc),
- offsetof(struct omap3isp_prev_update_config, csc),
- }, /* OMAP3ISP_PREV_YC_LIMIT */ {
- preview_config_yc_range,
- NULL,
- offsetof(struct prev_params, yclimit),
- FIELD_SIZEOF(struct prev_params, yclimit),
- offsetof(struct omap3isp_prev_update_config, yclimit),
- }, /* OMAP3ISP_PREV_DEFECT_COR */ {
- preview_config_dcor,
- preview_enable_dcor,
- offsetof(struct prev_params, dcor),
- FIELD_SIZEOF(struct prev_params, dcor),
- offsetof(struct omap3isp_prev_update_config, dcor),
- }, /* OMAP3ISP_PREV_GAMMABYPASS */ {
- NULL,
- preview_enable_gammabypass,
- }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
- NULL,
- preview_enable_drkframe_capture,
- }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
- NULL,
- preview_enable_drkframe,
- }, /* OMAP3ISP_PREV_LENS_SHADING */ {
- preview_config_drkf_shadcomp,
- preview_enable_drkframe,
- }, /* OMAP3ISP_PREV_NF */ {
- preview_config_noisefilter,
- preview_enable_noisefilter,
- offsetof(struct prev_params, nf),
- FIELD_SIZEOF(struct prev_params, nf),
- offsetof(struct omap3isp_prev_update_config, nf),
- }, /* OMAP3ISP_PREV_GAMMA */ {
- preview_config_gammacorrn,
- NULL,
- offsetof(struct prev_params, gamma),
- FIELD_SIZEOF(struct prev_params, gamma),
- offsetof(struct omap3isp_prev_update_config, gamma),
- }, /* OMAP3ISP_PREV_CONTRAST */ {
- preview_config_contrast,
- NULL,
- offsetof(struct prev_params, contrast),
- 0, 0, true,
- }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
- preview_config_brightness,
- NULL,
- offsetof(struct prev_params, brightness),
- 0, 0, true,
- },
-};
-
-/*
- * preview_config - Copy and update local structure with userspace preview
- * configuration.
- * @prev: ISP preview engine
- * @cfg: Configuration
- *
- * Return zero if success or -EFAULT if the configuration can't be copied from
- * userspace.
- */
-static int preview_config(struct isp_prev_device *prev,
- struct omap3isp_prev_update_config *cfg)
-{
- unsigned long flags;
- unsigned int i;
- int rval = 0;
- u32 update;
- u32 active;
-
- if (cfg->update == 0)
- return 0;
-
- /* Mark the shadow parameters we're going to update as busy. */
- spin_lock_irqsave(&prev->params.lock, flags);
- preview_params_lock(prev, cfg->update, true);
- active = prev->params.active;
- spin_unlock_irqrestore(&prev->params.lock, flags);
-
- update = 0;
-
- for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
- const struct preview_update *attr = &update_attrs[i];
- struct prev_params *params;
- unsigned int bit = 1 << i;
-
- if (attr->skip || !(cfg->update & bit))
- continue;
-
- params = &prev->params.params[!!(active & bit)];
-
- if (cfg->flag & bit) {
- void __user *from = *(void * __user *)
- ((void *)cfg + attr->config_offset);
- void *to = (void *)params + attr->param_offset;
- size_t size = attr->param_size;
-
- if (to && from && size) {
- if (copy_from_user(to, from, size)) {
- rval = -EFAULT;
- break;
- }
- }
- params->features |= bit;
- } else {
- params->features &= ~bit;
- }
-
- update |= bit;
- }
-
- spin_lock_irqsave(&prev->params.lock, flags);
- preview_params_unlock(prev, update, true);
- preview_params_switch(prev);
- spin_unlock_irqrestore(&prev->params.lock, flags);
-
- return rval;
-}
-
-/*
- * preview_setup_hw - Setup preview registers and/or internal memory
- * @prev: pointer to preview private structure
- * @update: Bitmask of parameters to setup
- * @active: Bitmask of parameters active in set 0
- * Note: can be called from interrupt context
- * Return none
- */
-static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
- u32 active)
-{
- unsigned int i;
- u32 features;
-
- if (update == 0)
- return;
-
- features = (prev->params.params[0].features & active)
- | (prev->params.params[1].features & ~active);
-
- for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
- const struct preview_update *attr = &update_attrs[i];
- struct prev_params *params;
- unsigned int bit = 1 << i;
- void *param_ptr;
-
- if (!(update & bit))
- continue;
-
- params = &prev->params.params[!(active & bit)];
-
- if (params->features & bit) {
- if (attr->config) {
- param_ptr = (void *)params + attr->param_offset;
- attr->config(prev, param_ptr);
- }
- if (attr->enable)
- attr->enable(prev, 1);
- } else {
- if (attr->enable)
- attr->enable(prev, 0);
- }
- }
-}
-
-/*
- * preview_config_ycpos - Configure byte layout of YUV image.
- * @mode: Indicates the required byte layout.
- */
-static void
-preview_config_ycpos(struct isp_prev_device *prev,
- enum v4l2_mbus_pixelcode pixelcode)
-{
- struct isp_device *isp = to_isp_device(prev);
- enum preview_ycpos_mode mode;
-
- switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- mode = YCPOS_CrYCbY;
- break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
- mode = YCPOS_YCrYCb;
- break;
- default:
- return;
- }
-
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_YCPOS_CrYCbY,
- mode << ISPPRV_PCR_YCPOS_SHIFT);
-}
-
-/*
- * preview_config_averager - Enable / disable / configure averager
- * @average: Average value to be configured.
- */
-static void preview_config_averager(struct isp_prev_device *prev, u8 average)
-{
- struct isp_device *isp = to_isp_device(prev);
- struct prev_params *params;
- int reg = 0;
-
- params = (prev->params.active & OMAP3ISP_PREV_CFA)
- ? &prev->params.params[0] : &prev->params.params[1];
-
- if (params->cfa.format == OMAP3ISP_CFAFMT_BAYER)
- reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
- ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
- average;
- else if (params->cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
- reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
- ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
- average;
- isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
-}
-
-/*
- * preview_config_input_format - Configure the input format
- * @prev: The preview engine
- * @format: Format on the preview engine sink pad
- *
- * Enable CFA interpolation for Bayer formats and disable it for greyscale
- * formats.
- */
-static void preview_config_input_format(struct isp_prev_device *prev,
- const struct v4l2_mbus_framefmt *format)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (format->code != V4L2_MBUS_FMT_Y10_1X10)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_CFAEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_CFAEN);
-}
-
-/*
- * preview_config_input_size - Configure the input frame size
- *
- * The preview engine crops several rows and columns internally depending on
- * which processing blocks are enabled. The driver assumes all those blocks are
- * enabled when reporting source pad formats to userspace. If this assumption is
- * not true, rows and columns must be manually cropped at the preview engine
- * input to avoid overflows at the end of lines and frames.
- *
- * See the explanation at the PREV_MARGIN_* definitions for more details.
- */
-static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
-{
- const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
- struct isp_device *isp = to_isp_device(prev);
- unsigned int sph = prev->crop.left;
- unsigned int eph = prev->crop.left + prev->crop.width - 1;
- unsigned int slv = prev->crop.top;
- unsigned int elv = prev->crop.top + prev->crop.height - 1;
- u32 features;
-
- if (format->code != V4L2_MBUS_FMT_Y10_1X10) {
- sph -= 2;
- eph += 2;
- slv -= 2;
- elv += 2;
- }
-
- features = (prev->params.params[0].features & active)
- | (prev->params.params[1].features & ~active);
-
- if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
- sph -= 2;
- eph += 2;
- slv -= 2;
- elv += 2;
- }
- if (features & OMAP3ISP_PREV_HRZ_MED) {
- sph -= 2;
- eph += 2;
- }
- if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
- sph -= 2;
-
- isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
- isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
- OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
-}
-
-/*
- * preview_config_inlineoffset - Configures the Read address line offset.
- * @prev: Preview module
- * @offset: Line offset
- *
- * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
- * However, a hardware bug requires the memory start address to be aligned on a
- * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
- * well.
- */
-static void
-preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
- ISPPRV_RADR_OFFSET);
-}
-
-/*
- * preview_set_inaddr - Sets memory address of input frame.
- * @addr: 32bit memory address aligned on 32byte boundary.
- *
- * Configures the memory address from which the input frame is to be read.
- */
-static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
-}
-
-/*
- * preview_config_outlineoffset - Configures the Write address line offset.
- * @offset: Line Offset for the preview output.
- *
- * The offset must be a multiple of 32 bytes.
- */
-static void preview_config_outlineoffset(struct isp_prev_device *prev,
- u32 offset)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
- ISPPRV_WADD_OFFSET);
-}
-
-/*
- * preview_set_outaddr - Sets the memory address to store output frame
- * @addr: 32bit memory address aligned on 32byte boundary.
- *
- * Configures the memory address to which the output frame is written.
- */
-static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
-}
-
-static void preview_adjust_bandwidth(struct isp_prev_device *prev)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
- struct isp_device *isp = to_isp_device(prev);
- const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
- unsigned long l3_ick = pipe->l3_ick;
- struct v4l2_fract *timeperframe;
- unsigned int cycles_per_frame;
- unsigned int requests_per_frame;
- unsigned int cycles_per_request;
- unsigned int minimum;
- unsigned int maximum;
- unsigned int value;
-
- if (prev->input != PREVIEW_INPUT_MEMORY) {
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
- ISPSBL_SDR_REQ_PRV_EXP_MASK);
- return;
- }
-
- /* Compute the minimum number of cycles per request, based on the
- * pipeline maximum data rate. This is an absolute lower bound if we
- * don't want SBL overflows, so round the value up.
- */
- cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
- pipe->max_rate);
- minimum = DIV_ROUND_UP(cycles_per_request, 32);
-
- /* Compute the maximum number of cycles per request, based on the
- * requested frame rate. This is a soft upper bound to achieve a frame
- * rate equal or higher than the requested value, so round the value
- * down.
- */
- timeperframe = &pipe->max_timeperframe;
-
- requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
- cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
- timeperframe->denominator);
- cycles_per_request = cycles_per_frame / requests_per_frame;
-
- maximum = cycles_per_request / 32;
-
- value = max(minimum, maximum);
-
- dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
- ISPSBL_SDR_REQ_PRV_EXP_MASK,
- value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
-}
-
-/*
- * omap3isp_preview_busy - Gets busy state of preview module.
- */
-int omap3isp_preview_busy(struct isp_prev_device *prev)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
- & ISPPRV_PCR_BUSY;
-}
-
-/*
- * omap3isp_preview_restore_context - Restores the values of preview registers
- */
-void omap3isp_preview_restore_context(struct isp_device *isp)
-{
- struct isp_prev_device *prev = &isp->isp_prev;
- const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
-
- prev->params.params[0].update = prev->params.active & update;
- prev->params.params[1].update = ~prev->params.active & update;
-
- preview_setup_hw(prev, update, prev->params.active);
-
- prev->params.params[0].update = 0;
- prev->params.params[1].update = 0;
-}
-
-/*
- * preview_print_status - Dump preview module registers to the kernel log
- */
-#define PREV_PRINT_REGISTER(isp, name)\
- dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
-
-static void preview_print_status(struct isp_prev_device *prev)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
-
- PREV_PRINT_REGISTER(isp, PCR);
- PREV_PRINT_REGISTER(isp, HORZ_INFO);
- PREV_PRINT_REGISTER(isp, VERT_INFO);
- PREV_PRINT_REGISTER(isp, RSDR_ADDR);
- PREV_PRINT_REGISTER(isp, RADR_OFFSET);
- PREV_PRINT_REGISTER(isp, DSDR_ADDR);
- PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
- PREV_PRINT_REGISTER(isp, WSDR_ADDR);
- PREV_PRINT_REGISTER(isp, WADD_OFFSET);
- PREV_PRINT_REGISTER(isp, AVE);
- PREV_PRINT_REGISTER(isp, HMED);
- PREV_PRINT_REGISTER(isp, NF);
- PREV_PRINT_REGISTER(isp, WB_DGAIN);
- PREV_PRINT_REGISTER(isp, WBGAIN);
- PREV_PRINT_REGISTER(isp, WBSEL);
- PREV_PRINT_REGISTER(isp, CFA);
- PREV_PRINT_REGISTER(isp, BLKADJOFF);
- PREV_PRINT_REGISTER(isp, RGB_MAT1);
- PREV_PRINT_REGISTER(isp, RGB_MAT2);
- PREV_PRINT_REGISTER(isp, RGB_MAT3);
- PREV_PRINT_REGISTER(isp, RGB_MAT4);
- PREV_PRINT_REGISTER(isp, RGB_MAT5);
- PREV_PRINT_REGISTER(isp, RGB_OFF1);
- PREV_PRINT_REGISTER(isp, RGB_OFF2);
- PREV_PRINT_REGISTER(isp, CSC0);
- PREV_PRINT_REGISTER(isp, CSC1);
- PREV_PRINT_REGISTER(isp, CSC2);
- PREV_PRINT_REGISTER(isp, CSC_OFFSET);
- PREV_PRINT_REGISTER(isp, CNT_BRT);
- PREV_PRINT_REGISTER(isp, CSUP);
- PREV_PRINT_REGISTER(isp, SETUP_YC);
- PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
- PREV_PRINT_REGISTER(isp, CDC_THR0);
- PREV_PRINT_REGISTER(isp, CDC_THR1);
- PREV_PRINT_REGISTER(isp, CDC_THR2);
- PREV_PRINT_REGISTER(isp, CDC_THR3);
-
- dev_dbg(isp->dev, "--------------------------------------------\n");
-}
-
-/*
- * preview_init_params - init image processing parameters.
- * @prev: pointer to previewer private structure
- */
-static void preview_init_params(struct isp_prev_device *prev)
-{
- struct prev_params *params;
- unsigned int i;
-
- spin_lock_init(&prev->params.lock);
-
- prev->params.active = ~0;
- prev->params.params[0].busy = 0;
- prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
- prev->params.params[1].busy = 0;
- prev->params.params[1].update = 0;
-
- params = &prev->params.params[0];
-
- /* Init values */
- params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
- params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
- params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
- memcpy(params->cfa.table, cfa_coef_table,
- sizeof(params->cfa.table));
- params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
- params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
- params->csup.gain = FLR_CSUP_GAIN;
- params->csup.thres = FLR_CSUP_THRES;
- params->csup.hypf_en = 0;
- memcpy(params->luma.table, luma_enhance_table,
- sizeof(params->luma.table));
- params->nf.spread = FLR_NF_STRGTH;
- memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
- params->dcor.couplet_mode_en = 1;
- for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
- params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
- memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
- memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
- memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
- params->wbal.dgain = FLR_WBAL_DGAIN;
- params->wbal.coef0 = FLR_WBAL_COEF;
- params->wbal.coef1 = FLR_WBAL_COEF;
- params->wbal.coef2 = FLR_WBAL_COEF;
- params->wbal.coef3 = FLR_WBAL_COEF;
- params->blkadj.red = FLR_BLKADJ_RED;
- params->blkadj.green = FLR_BLKADJ_GREEN;
- params->blkadj.blue = FLR_BLKADJ_BLUE;
- params->rgb2rgb = flr_rgb2rgb;
- params->csc = flr_prev_csc;
- params->yclimit.minC = ISPPRV_YC_MIN;
- params->yclimit.maxC = ISPPRV_YC_MAX;
- params->yclimit.minY = ISPPRV_YC_MIN;
- params->yclimit.maxY = ISPPRV_YC_MAX;
-
- params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
- | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
- | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
- | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
- | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
- | OMAP3ISP_PREV_CONTRAST;
-}
-
-/*
- * preview_max_out_width - Handle previewer hardware ouput limitations
- * @isp_revision : ISP revision
- * returns maximum width output for current isp revision
- */
-static unsigned int preview_max_out_width(struct isp_prev_device *prev)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- switch (isp->revision) {
- case ISP_REVISION_1_0:
- return PREV_MAX_OUT_WIDTH_REV_1;
-
- case ISP_REVISION_2_0:
- default:
- return PREV_MAX_OUT_WIDTH_REV_2;
-
- case ISP_REVISION_15_0:
- return PREV_MAX_OUT_WIDTH_REV_15;
- }
-}
-
-static void preview_configure(struct isp_prev_device *prev)
-{
- struct isp_device *isp = to_isp_device(prev);
- struct v4l2_mbus_framefmt *format;
- unsigned long flags;
- u32 update;
- u32 active;
-
- spin_lock_irqsave(&prev->params.lock, flags);
- /* Mark all active parameters we are going to touch as busy. */
- update = preview_params_lock(prev, 0, false);
- active = prev->params.active;
- spin_unlock_irqrestore(&prev->params.lock, flags);
-
- preview_setup_hw(prev, update, active);
-
- if (prev->output & PREVIEW_OUTPUT_MEMORY)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SDRPORT);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SDRPORT);
-
- if (prev->output & PREVIEW_OUTPUT_RESIZER)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_RSZPORT);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_RSZPORT);
-
- /* PREV_PAD_SINK */
- format = &prev->formats[PREV_PAD_SINK];
-
- preview_adjust_bandwidth(prev);
-
- preview_config_input_format(prev, format);
- preview_config_input_size(prev, active);
-
- if (prev->input == PREVIEW_INPUT_CCDC)
- preview_config_inlineoffset(prev, 0);
- else
- preview_config_inlineoffset(prev,
- ALIGN(format->width, 0x20) * 2);
-
- /* PREV_PAD_SOURCE */
- format = &prev->formats[PREV_PAD_SOURCE];
-
- if (prev->output & PREVIEW_OUTPUT_MEMORY)
- preview_config_outlineoffset(prev,
- ALIGN(format->width, 0x10) * 2);
-
- preview_config_averager(prev, 0);
- preview_config_ycpos(prev, format->code);
-
- spin_lock_irqsave(&prev->params.lock, flags);
- preview_params_unlock(prev, update, false);
- spin_unlock_irqrestore(&prev->params.lock, flags);
-}
-
-/* -----------------------------------------------------------------------------
- * Interrupt handling
- */
-
-static void preview_enable_oneshot(struct isp_prev_device *prev)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
- * bit is set. As the preview engine is used in single-shot mode, we
- * need to set PCR.SOURCE before enabling the preview engine.
- */
- if (prev->input == PREVIEW_INPUT_MEMORY)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_SOURCE);
-
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
-}
-
-void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
-{
- /*
- * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
- * condition, the module was paused and now we have a buffer queued
- * on the output again. Restart the pipeline if running in continuous
- * mode.
- */
- if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
- prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
- preview_enable_oneshot(prev);
- isp_video_dmaqueue_flags_clr(&prev->video_out);
- }
-}
-
-static void preview_isr_buffer(struct isp_prev_device *prev)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
- struct isp_buffer *buffer;
- int restart = 0;
-
- if (prev->input == PREVIEW_INPUT_MEMORY) {
- 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);
- if (buffer != NULL) {
- preview_set_outaddr(prev, buffer->isp_addr);
- restart = 1;
- }
- pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
- }
-
- switch (prev->state) {
- case ISP_PIPELINE_STREAM_SINGLESHOT:
- if (isp_pipeline_ready(pipe))
- omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_SINGLESHOT);
- break;
-
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- /* If an underrun occurs, the video queue operation handler will
- * restart the preview engine. Otherwise restart it immediately.
- */
- if (restart)
- preview_enable_oneshot(prev);
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- default:
- return;
- }
-}
-
-/*
- * omap3isp_preview_isr - ISP preview engine interrupt handler
- *
- * Manage the preview engine video buffers and configure shadowed registers.
- */
-void omap3isp_preview_isr(struct isp_prev_device *prev)
-{
- unsigned long flags;
- u32 update;
- u32 active;
-
- if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
- return;
-
- spin_lock_irqsave(&prev->params.lock, flags);
- preview_params_switch(prev);
- update = preview_params_lock(prev, 0, false);
- active = prev->params.active;
- spin_unlock_irqrestore(&prev->params.lock, flags);
-
- preview_setup_hw(prev, update, active);
- preview_config_input_size(prev, active);
-
- if (prev->input == PREVIEW_INPUT_MEMORY ||
- prev->output & PREVIEW_OUTPUT_MEMORY)
- preview_isr_buffer(prev);
- else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
- preview_enable_oneshot(prev);
-
- spin_lock_irqsave(&prev->params.lock, flags);
- preview_params_unlock(prev, update, false);
- spin_unlock_irqrestore(&prev->params.lock, flags);
-}
-
-/* -----------------------------------------------------------------------------
- * ISP video operations
- */
-
-static int preview_video_queue(struct isp_video *video,
- struct isp_buffer *buffer)
-{
- struct isp_prev_device *prev = &video->isp->isp_prev;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- preview_set_inaddr(prev, buffer->isp_addr);
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- preview_set_outaddr(prev, buffer->isp_addr);
-
- return 0;
-}
-
-static const struct isp_video_operations preview_video_ops = {
- .queue = preview_video_queue,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev operations
- */
-
-/*
- * preview_s_ctrl - Handle set control subdev method
- * @ctrl: pointer to v4l2 control structure
- */
-static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct isp_prev_device *prev =
- container_of(ctrl->handler, struct isp_prev_device, ctrls);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- preview_update_brightness(prev, ctrl->val);
- break;
- case V4L2_CID_CONTRAST:
- preview_update_contrast(prev, ctrl->val);
- break;
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops preview_ctrl_ops = {
- .s_ctrl = preview_s_ctrl,
-};
-
-/*
- * preview_ioctl - Handle preview module private ioctl's
- * @prev: pointer to preview context structure
- * @cmd: configuration command
- * @arg: configuration argument
- * return -EINVAL or zero on success
- */
-static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
-
- switch (cmd) {
- case VIDIOC_OMAP3ISP_PRV_CFG:
- return preview_config(prev, arg);
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-/*
- * preview_set_stream - Enable/Disable streaming on preview subdev
- * @sd : pointer to v4l2 subdev structure
- * @enable: 1 == Enable, 0 == Disable
- * return -EINVAL or zero on success
- */
-static int preview_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct isp_video *video_out = &prev->video_out;
- struct isp_device *isp = to_isp_device(prev);
- struct device *dev = to_device(prev);
-
- if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
- if (enable == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
-
- omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
- preview_configure(prev);
- atomic_set(&prev->stopping, 0);
- preview_print_status(prev);
- }
-
- switch (enable) {
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- if (prev->output & PREVIEW_OUTPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
-
- if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
- !(prev->output & PREVIEW_OUTPUT_MEMORY))
- preview_enable_oneshot(prev);
-
- isp_video_dmaqueue_flags_clr(video_out);
- break;
-
- case ISP_PIPELINE_STREAM_SINGLESHOT:
- if (prev->input == PREVIEW_INPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
- if (prev->output & PREVIEW_OUTPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
-
- preview_enable_oneshot(prev);
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
- &prev->stopping))
- dev_dbg(dev, "%s: stop timeout.\n", sd->name);
- omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
- omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
- omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
- isp_video_dmaqueue_flags_clr(video_out);
- break;
- }
-
- prev->state = enable;
- return 0;
-}
-
-static struct v4l2_mbus_framefmt *
-__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
- else
- return &prev->formats[pad];
-}
-
-static struct v4l2_rect *
-__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK);
- else
- return &prev->crop;
-}
-
-/* previewer format descriptions */
-static const unsigned int preview_input_fmts[] = {
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
-};
-
-static const unsigned int preview_output_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
-};
-
-/*
- * preview_try_format - Validate a format
- * @prev: ISP preview engine
- * @fh: V4L2 subdev file handle
- * @pad: pad number
- * @fmt: format to be validated
- * @which: try/active format selector
- *
- * Validate and adjust the given format for the given pad based on the preview
- * engine limits and the format and crop rectangles on other pads.
- */
-static void preview_try_format(struct isp_prev_device *prev,
- struct v4l2_subdev_fh *fh, unsigned int pad,
- struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- enum v4l2_mbus_pixelcode pixelcode;
- struct v4l2_rect *crop;
- unsigned int i;
-
- switch (pad) {
- case PREV_PAD_SINK:
- /* When reading data from the CCDC, the input size has already
- * been mangled by the CCDC output pad so it can be accepted
- * as-is.
- *
- * When reading data from memory, clamp the requested width and
- * height. The TRM doesn't specify a minimum input height, make
- * sure we got enough lines to enable the noise filter and color
- * filter array interpolation.
- */
- if (prev->input == PREVIEW_INPUT_MEMORY) {
- fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
- preview_max_out_width(prev));
- fmt->height = clamp_t(u32, fmt->height,
- PREV_MIN_IN_HEIGHT,
- PREV_MAX_IN_HEIGHT);
- }
-
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
-
- for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
- if (fmt->code == preview_input_fmts[i])
- break;
- }
-
- /* If not found, use SGRBG10 as default */
- if (i >= ARRAY_SIZE(preview_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
- break;
-
- case PREV_PAD_SOURCE:
- pixelcode = fmt->code;
- *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);
-
- switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_UYVY8_1X16:
- fmt->code = pixelcode;
- break;
-
- default:
- fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
- break;
- }
-
- /* The preview module output size is configurable through the
- * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This
- * is not supported yet, hardcode the output size to the crop
- * rectangle size.
- */
- crop = __preview_get_crop(prev, fh, which);
- fmt->width = crop->width;
- fmt->height = crop->height;
-
- fmt->colorspace = V4L2_COLORSPACE_JPEG;
- break;
- }
-
- fmt->field = V4L2_FIELD_NONE;
-}
-
-/*
- * preview_try_crop - Validate a crop rectangle
- * @prev: ISP preview engine
- * @sink: format on the sink pad
- * @crop: crop rectangle to be validated
- *
- * The preview engine crops lines and columns for its internal operation,
- * depending on which filters are enabled. Enforce minimum crop margins to
- * handle that transparently for userspace.
- *
- * See the explanation at the PREV_MARGIN_* definitions for more details.
- */
-static void preview_try_crop(struct isp_prev_device *prev,
- const struct v4l2_mbus_framefmt *sink,
- struct v4l2_rect *crop)
-{
- unsigned int left = PREV_MARGIN_LEFT;
- unsigned int right = sink->width - PREV_MARGIN_RIGHT;
- unsigned int top = PREV_MARGIN_TOP;
- unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM;
-
- /* When processing data on-the-fly from the CCDC, at least 2 pixels must
- * be cropped from the left and right sides of the image. As we don't
- * know which filters will be enabled, increase the left and right
- * margins by two.
- */
- if (prev->input == PREVIEW_INPUT_CCDC) {
- left += 2;
- right -= 2;
- }
-
- /* Restrict left/top to even values to keep the Bayer pattern. */
- crop->left &= ~1;
- crop->top &= ~1;
-
- crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH);
- crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT);
- crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH,
- right - crop->left);
- crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT,
- bottom - crop->top);
-}
-
-/*
- * preview_enum_mbus_code - Handle pixel format enumeration
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @code : pointer to v4l2_subdev_mbus_code_enum structure
- * return -EINVAL or zero on success
- */
-static int preview_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- switch (code->pad) {
- case PREV_PAD_SINK:
- if (code->index >= ARRAY_SIZE(preview_input_fmts))
- return -EINVAL;
-
- code->code = preview_input_fmts[code->index];
- break;
- case PREV_PAD_SOURCE:
- if (code->index >= ARRAY_SIZE(preview_output_fmts))
- return -EINVAL;
-
- code->code = preview_output_fmts[code->index];
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int preview_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * preview_get_selection - Retrieve a selection rectangle on a pad
- * @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangles are the crop rectangles on the sink pad.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int preview_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- if (sel->pad != PREV_PAD_SINK)
- return -EINVAL;
-
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP_BOUNDS:
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = INT_MAX;
- sel->r.height = INT_MAX;
-
- format = __preview_get_format(prev, fh, PREV_PAD_SINK,
- sel->which);
- preview_try_crop(prev, format, &sel->r);
- break;
-
- case V4L2_SEL_TGT_CROP:
- sel->r = *__preview_get_crop(prev, fh, sel->which);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * preview_set_selection - Set a selection rectangle on a pad
- * @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangle is the actual crop rectangle on the sink pad.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int preview_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- if (sel->target != V4L2_SEL_TGT_CROP ||
- sel->pad != PREV_PAD_SINK)
- return -EINVAL;
-
- /* The crop rectangle can't be changed while streaming. */
- if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
- return -EBUSY;
-
- /* Modifying the crop rectangle always changes the format on the source
- * pad. If the KEEP_CONFIG flag is set, just return the current crop
- * rectangle.
- */
- if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__preview_get_crop(prev, fh, sel->which);
- return 0;
- }
-
- format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
- preview_try_crop(prev, format, &sel->r);
- *__preview_get_crop(prev, fh, sel->which) = sel->r;
-
- /* Update the source format. */
- format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
- preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
-
- return 0;
-}
-
-/*
- * preview_get_format - Handle get format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- fmt->format = *format;
- return 0;
-}
-
-/*
- * preview_set_format - Handle set format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *crop;
-
- format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- /* Propagate the format from sink to source */
- if (fmt->pad == PREV_PAD_SINK) {
- /* Reset the crop rectangle. */
- crop = __preview_get_crop(prev, fh, fmt->which);
- crop->left = 0;
- crop->top = 0;
- crop->width = fmt->format.width;
- crop->height = fmt->format.height;
-
- preview_try_crop(prev, &fmt->format, crop);
-
- /* Update the source format. */
- format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
- fmt->which);
- preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
- fmt->which);
- }
-
- return 0;
-}
-
-/*
- * preview_init_formats - Initialize formats on all pads
- * @sd: ISP preview V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. If fh is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
- */
-static int preview_init_formats(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = PREV_PAD_SINK;
- format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
- format.format.width = 4096;
- format.format.height = 4096;
- preview_set_format(sd, fh, &format);
-
- return 0;
-}
-
-/* subdev core operations */
-static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
- .ioctl = preview_ioctl,
-};
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
- .s_stream = preview_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
- .enum_mbus_code = preview_enum_mbus_code,
- .enum_frame_size = preview_enum_frame_size,
- .get_fmt = preview_get_format,
- .set_fmt = preview_set_format,
- .get_selection = preview_get_selection,
- .set_selection = preview_set_selection,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops preview_v4l2_ops = {
- .core = &preview_v4l2_core_ops,
- .video = &preview_v4l2_video_ops,
- .pad = &preview_v4l2_pad_ops,
-};
-
-/* subdev internal operations */
-static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
- .open = preview_init_formats,
-};
-
-/* -----------------------------------------------------------------------------
- * Media entity operations
- */
-
-/*
- * preview_link_setup - Setup previewer connections.
- * @entity : Pointer to media entity structure
- * @local : Pointer to local pad array
- * @remote : Pointer to remote pad array
- * @flags : Link flags
- * return -EINVAL or zero on success
- */
-static int preview_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
-
- switch (local->index | media_entity_type(remote->entity)) {
- case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
- /* read from memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (prev->input == PREVIEW_INPUT_CCDC)
- return -EBUSY;
- prev->input = PREVIEW_INPUT_MEMORY;
- } else {
- if (prev->input == PREVIEW_INPUT_MEMORY)
- prev->input = PREVIEW_INPUT_NONE;
- }
- break;
-
- case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
- /* read from ccdc */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (prev->input == PREVIEW_INPUT_MEMORY)
- return -EBUSY;
- prev->input = PREVIEW_INPUT_CCDC;
- } else {
- if (prev->input == PREVIEW_INPUT_CCDC)
- prev->input = PREVIEW_INPUT_NONE;
- }
- break;
-
- /*
- * The ISP core doesn't support pipelines with multiple video outputs.
- * Revisit this when it will be implemented, and return -EBUSY for now.
- */
-
- case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
- /* write to memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
- return -EBUSY;
- prev->output |= PREVIEW_OUTPUT_MEMORY;
- } else {
- prev->output &= ~PREVIEW_OUTPUT_MEMORY;
- }
- break;
-
- case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
- /* write to resizer */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
- return -EBUSY;
- prev->output |= PREVIEW_OUTPUT_RESIZER;
- } else {
- prev->output &= ~PREVIEW_OUTPUT_RESIZER;
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* media operations */
-static const struct media_entity_operations preview_media_ops = {
- .link_setup = preview_link_setup,
- .link_validate = v4l2_subdev_link_validate,
-};
-
-void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
-{
- v4l2_device_unregister_subdev(&prev->subdev);
- omap3isp_video_unregister(&prev->video_in);
- omap3isp_video_unregister(&prev->video_out);
-}
-
-int omap3isp_preview_register_entities(struct isp_prev_device *prev,
- struct v4l2_device *vdev)
-{
- int ret;
-
- /* Register the subdev and video nodes. */
- ret = v4l2_device_register_subdev(vdev, &prev->subdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&prev->video_in, vdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&prev->video_out, vdev);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- omap3isp_preview_unregister_entities(prev);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * ISP previewer initialisation and cleanup
- */
-
-/*
- * preview_init_entities - Initialize subdev and media entity.
- * @prev : Pointer to preview structure
- * return -ENOMEM or zero on success
- */
-static int preview_init_entities(struct isp_prev_device *prev)
-{
- struct v4l2_subdev *sd = &prev->subdev;
- struct media_pad *pads = prev->pads;
- struct media_entity *me = &sd->entity;
- int ret;
-
- prev->input = PREVIEW_INPUT_NONE;
-
- v4l2_subdev_init(sd, &preview_v4l2_ops);
- sd->internal_ops = &preview_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for isp subdevs */
- v4l2_set_subdevdata(sd, prev);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- v4l2_ctrl_handler_init(&prev->ctrls, 2);
- v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
- ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
- ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
- v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
- ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
- ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
- v4l2_ctrl_handler_setup(&prev->ctrls);
- sd->ctrl_handler = &prev->ctrls;
-
- pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- me->ops = &preview_media_ops;
- ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
- if (ret < 0)
- return ret;
-
- preview_init_formats(sd, NULL);
-
- /* According to the OMAP34xx TRM, video buffers need to be aligned on a
- * 32 bytes boundary. However, an undocumented hardware bug requires a
- * 64 bytes boundary at the preview engine input.
- */
- prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- prev->video_in.ops = &preview_video_ops;
- prev->video_in.isp = to_isp_device(prev);
- prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
- prev->video_in.bpl_alignment = 64;
- prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- prev->video_out.ops = &preview_video_ops;
- prev->video_out.isp = to_isp_device(prev);
- prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
- prev->video_out.bpl_alignment = 32;
-
- ret = omap3isp_video_init(&prev->video_in, "preview");
- if (ret < 0)
- goto error_video_in;
-
- ret = omap3isp_video_init(&prev->video_out, "preview");
- if (ret < 0)
- goto error_video_out;
-
- /* Connect the video nodes to the previewer subdev. */
- ret = media_entity_create_link(&prev->video_in.video.entity, 0,
- &prev->subdev.entity, PREV_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
- &prev->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
- return 0;
-
-error_link:
- omap3isp_video_cleanup(&prev->video_out);
-error_video_out:
- omap3isp_video_cleanup(&prev->video_in);
-error_video_in:
- media_entity_cleanup(&prev->subdev.entity);
- return ret;
-}
-
-/*
- * omap3isp_preview_init - Previewer initialization.
- * @dev : Pointer to ISP device
- * return -ENOMEM or zero on success
- */
-int omap3isp_preview_init(struct isp_device *isp)
-{
- struct isp_prev_device *prev = &isp->isp_prev;
-
- init_waitqueue_head(&prev->wait);
-
- preview_init_params(prev);
-
- return preview_init_entities(prev);
-}
-
-void omap3isp_preview_cleanup(struct isp_device *isp)
-{
- struct isp_prev_device *prev = &isp->isp_prev;
-
- v4l2_ctrl_handler_free(&prev->ctrls);
- omap3isp_video_cleanup(&prev->video_in);
- omap3isp_video_cleanup(&prev->video_out);
- media_entity_cleanup(&prev->subdev.entity);
-}
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
deleted file mode 100644
index 6663ab64e4b1..000000000000
--- a/drivers/media/video/omap3isp/isppreview.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * isppreview.h
- *
- * TI OMAP3 ISP - Preview module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 OMAP3_ISP_PREVIEW_H
-#define OMAP3_ISP_PREVIEW_H
-
-#include <linux/omap3isp.h>
-#include <linux/types.h>
-#include <media/v4l2-ctrls.h>
-
-#include "ispvideo.h"
-
-#define ISPPRV_BRIGHT_STEP 0x1
-#define ISPPRV_BRIGHT_DEF 0x0
-#define ISPPRV_BRIGHT_LOW 0x0
-#define ISPPRV_BRIGHT_HIGH 0xFF
-#define ISPPRV_BRIGHT_UNITS 0x1
-
-#define ISPPRV_CONTRAST_STEP 0x1
-#define ISPPRV_CONTRAST_DEF 0x10
-#define ISPPRV_CONTRAST_LOW 0x0
-#define ISPPRV_CONTRAST_HIGH 0xFF
-#define ISPPRV_CONTRAST_UNITS 0x1
-
-/* Additional features not listed in linux/omap3isp.h */
-#define OMAP3ISP_PREV_CONTRAST (1 << 17)
-#define OMAP3ISP_PREV_BRIGHTNESS (1 << 18)
-#define OMAP3ISP_PREV_FEATURES_END (1 << 19)
-
-enum preview_input_entity {
- PREVIEW_INPUT_NONE,
- PREVIEW_INPUT_CCDC,
- PREVIEW_INPUT_MEMORY,
-};
-
-#define PREVIEW_OUTPUT_RESIZER (1 << 1)
-#define PREVIEW_OUTPUT_MEMORY (1 << 2)
-
-/* Configure byte layout of YUV image */
-enum preview_ycpos_mode {
- YCPOS_YCrYCb = 0,
- YCPOS_YCbYCr = 1,
- YCPOS_CbYCrY = 2,
- YCPOS_CrYCbY = 3
-};
-
-/*
- * struct prev_params - Structure for all configuration
- * @busy: Bitmask of busy parameters (being updated or used)
- * @update: Bitmask of the parameters to be updated
- * @features: Set of features enabled.
- * @cfa: CFA coefficients.
- * @csup: Chroma suppression coefficients.
- * @luma: Luma enhancement coefficients.
- * @nf: Noise filter coefficients.
- * @dcor: Noise filter coefficients.
- * @gamma: Gamma coefficients.
- * @wbal: White Balance parameters.
- * @blkadj: Black adjustment parameters.
- * @rgb2rgb: RGB blending parameters.
- * @csc: Color space conversion (RGB to YCbCr) parameters.
- * @hmed: Horizontal median filter.
- * @yclimit: YC limits parameters.
- * @contrast: Contrast.
- * @brightness: Brightness.
- */
-struct prev_params {
- u32 busy;
- u32 update;
- u32 features;
- struct omap3isp_prev_cfa cfa;
- struct omap3isp_prev_csup csup;
- struct omap3isp_prev_luma luma;
- struct omap3isp_prev_nf nf;
- struct omap3isp_prev_dcor dcor;
- struct omap3isp_prev_gtables gamma;
- struct omap3isp_prev_wbal wbal;
- struct omap3isp_prev_blkadj blkadj;
- struct omap3isp_prev_rgbtorgb rgb2rgb;
- struct omap3isp_prev_csc csc;
- struct omap3isp_prev_hmed hmed;
- struct omap3isp_prev_yclimit yclimit;
- u8 contrast;
- u8 brightness;
-};
-
-/* Sink and source previewer pads */
-#define PREV_PAD_SINK 0
-#define PREV_PAD_SOURCE 1
-#define PREV_PADS_NUM 2
-
-/*
- * struct isp_prev_device - Structure for storing ISP Preview module information
- * @subdev: V4L2 subdevice
- * @pads: Media entity pads
- * @formats: Active formats at the subdev pad
- * @crop: Active crop rectangle
- * @input: Module currently connected to the input pad
- * @output: Bitmask of the active output
- * @video_in: Input video entity
- * @video_out: Output video entity
- * @params.params : Active and shadow parameters sets
- * @params.active: Bitmask of parameters active in set 0
- * @params.lock: Parameters lock, protects params.active and params.shadow
- * @underrun: Whether the preview entity has queued buffers on the output
- * @state: Current preview pipeline state
- *
- * This structure is used to store the OMAP ISP Preview module Information.
- */
-struct isp_prev_device {
- struct v4l2_subdev subdev;
- struct media_pad pads[PREV_PADS_NUM];
- struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
- struct v4l2_rect crop;
-
- struct v4l2_ctrl_handler ctrls;
-
- enum preview_input_entity input;
- unsigned int output;
- struct isp_video video_in;
- struct isp_video video_out;
-
- struct {
- struct prev_params params[2];
- u32 active;
- spinlock_t lock;
- } params;
-
- enum isp_pipeline_stream_state state;
- wait_queue_head_t wait;
- atomic_t stopping;
-};
-
-struct isp_device;
-
-int omap3isp_preview_init(struct isp_device *isp);
-void omap3isp_preview_cleanup(struct isp_device *isp);
-
-int omap3isp_preview_register_entities(struct isp_prev_device *prv,
- struct v4l2_device *vdev);
-void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
-
-void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
-void omap3isp_preview_isr(struct isp_prev_device *prev);
-
-int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
-
-void omap3isp_preview_restore_context(struct isp_device *isp);
-
-#endif /* OMAP3_ISP_PREVIEW_H */
diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c
deleted file mode 100644
index 9bebb1e57aab..000000000000
--- a/drivers/media/video/omap3isp/ispqueue.c
+++ /dev/null
@@ -1,1157 +0,0 @@
-/*
- * ispqueue.c
- *
- * TI OMAP3 ISP - Video buffers queue handling
- *
- * Copyright (C) 2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 <asm/cacheflush.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/poll.h>
-#include <linux/scatterlist.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include "ispqueue.h"
-
-/* -----------------------------------------------------------------------------
- * Video buffers management
- */
-
-/*
- * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP
- *
- * The typical operation required here is Cache Invalidation across
- * the (user space) buffer address range. And this _must_ be done
- * at QBUF stage (and *only* at QBUF).
- *
- * We try to use optimal cache invalidation function:
- * - dmac_map_area:
- * - used when the number of pages are _low_.
- * - it becomes quite slow as the number of pages increase.
- * - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
- * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
- *
- * - flush_cache_all:
- * - used when the number of pages are _high_.
- * - time taken in the range of 500-900 us.
- * - has a higher penalty but, as whole dcache + icache is invalidated
- */
-/*
- * FIXME: dmac_inv_range crashes randomly on the user space buffer
- * address. Fall back to flush_cache_all for now.
- */
-#define ISP_CACHE_FLUSH_PAGES_MAX 0
-
-static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf)
-{
- if (buf->skip_cache)
- return;
-
- if (buf->vbuf.m.userptr == 0 || buf->npages == 0 ||
- buf->npages > ISP_CACHE_FLUSH_PAGES_MAX)
- flush_cache_all();
- else {
- dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length,
- DMA_FROM_DEVICE);
- outer_inv_range(buf->vbuf.m.userptr,
- buf->vbuf.m.userptr + buf->vbuf.length);
- }
-}
-
-/*
- * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped
- *
- * Lock the VMAs underlying the given buffer into memory. This avoids the
- * userspace buffer mapping from being swapped out, making VIPT cache handling
- * easier.
- *
- * Note that the pages will not be freed as the buffers have been locked to
- * memory using by a call to get_user_pages(), but the userspace mapping could
- * still disappear if the VMAs are not locked. This is caused by the memory
- * management code trying to be as lock-less as possible, which results in the
- * userspace mapping manager not finding out that the pages are locked under
- * some conditions.
- */
-static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock)
-{
- struct vm_area_struct *vma;
- unsigned long start;
- unsigned long end;
- int ret = 0;
-
- if (buf->vbuf.memory == V4L2_MEMORY_MMAP)
- return 0;
-
- /* We can be called from workqueue context if the current task dies to
- * unlock the VMAs. In that case there's no current memory management
- * context so unlocking can't be performed, but the VMAs have been or
- * are getting destroyed anyway so it doesn't really matter.
- */
- if (!current || !current->mm)
- return lock ? -EINVAL : 0;
-
- start = buf->vbuf.m.userptr;
- end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
-
- down_write(&current->mm->mmap_sem);
- spin_lock(&current->mm->page_table_lock);
-
- do {
- vma = find_vma(current->mm, start);
- if (vma == NULL) {
- ret = -EFAULT;
- goto out;
- }
-
- if (lock)
- vma->vm_flags |= VM_LOCKED;
- else
- vma->vm_flags &= ~VM_LOCKED;
-
- start = vma->vm_end + 1;
- } while (vma->vm_end < end);
-
- if (lock)
- buf->vm_flags |= VM_LOCKED;
- else
- buf->vm_flags &= ~VM_LOCKED;
-
-out:
- spin_unlock(&current->mm->page_table_lock);
- up_write(&current->mm->mmap_sem);
- return ret;
-}
-
-/*
- * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer
- *
- * Iterate over the vmalloc'ed area and create a scatter list entry for every
- * page.
- */
-static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
-{
- struct scatterlist *sglist;
- unsigned int npages;
- unsigned int i;
- void *addr;
-
- addr = buf->vaddr;
- npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT;
-
- sglist = vmalloc(npages * sizeof(*sglist));
- if (sglist == NULL)
- return -ENOMEM;
-
- sg_init_table(sglist, npages);
-
- for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
- struct page *page = vmalloc_to_page(addr);
-
- if (page == NULL || PageHighMem(page)) {
- vfree(sglist);
- return -EINVAL;
- }
-
- sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
- }
-
- buf->sglen = npages;
- buf->sglist = sglist;
-
- return 0;
-}
-
-/*
- * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
- *
- * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
- */
-static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
-{
- struct scatterlist *sglist;
- unsigned int offset = buf->offset;
- unsigned int i;
-
- sglist = vmalloc(buf->npages * sizeof(*sglist));
- if (sglist == NULL)
- return -ENOMEM;
-
- sg_init_table(sglist, buf->npages);
-
- for (i = 0; i < buf->npages; ++i) {
- if (PageHighMem(buf->pages[i])) {
- vfree(sglist);
- return -EINVAL;
- }
-
- sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset,
- offset);
- offset = 0;
- }
-
- buf->sglen = buf->npages;
- buf->sglist = sglist;
-
- return 0;
-}
-
-/*
- * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
- *
- * Create a scatter list of physically contiguous pages starting at the buffer
- * memory physical address.
- */
-static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
-{
- struct scatterlist *sglist;
- unsigned int offset = buf->offset;
- unsigned long pfn = buf->paddr >> PAGE_SHIFT;
- unsigned int i;
-
- sglist = vmalloc(buf->npages * sizeof(*sglist));
- if (sglist == NULL)
- return -ENOMEM;
-
- sg_init_table(sglist, buf->npages);
-
- for (i = 0; i < buf->npages; ++i, ++pfn) {
- sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset,
- offset);
- /* PFNMAP buffers will not get DMA-mapped, set the DMA address
- * manually.
- */
- sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset;
- offset = 0;
- }
-
- buf->sglen = buf->npages;
- buf->sglist = sglist;
-
- return 0;
-}
-
-/*
- * isp_video_buffer_cleanup - Release pages for a userspace VMA.
- *
- * Release pages locked by a call isp_video_buffer_prepare_user and free the
- * pages table.
- */
-static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
-{
- enum dma_data_direction direction;
- unsigned int i;
-
- if (buf->queue->ops->buffer_cleanup)
- buf->queue->ops->buffer_cleanup(buf);
-
- if (!(buf->vm_flags & VM_PFNMAP)) {
- direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
- ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen,
- direction);
- }
-
- vfree(buf->sglist);
- buf->sglist = NULL;
- buf->sglen = 0;
-
- if (buf->pages != NULL) {
- isp_video_buffer_lock_vma(buf, 0);
-
- for (i = 0; i < buf->npages; ++i)
- page_cache_release(buf->pages[i]);
-
- vfree(buf->pages);
- buf->pages = NULL;
- }
-
- buf->npages = 0;
- buf->skip_cache = false;
-}
-
-/*
- * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory.
- *
- * This function creates a list of pages for a userspace VMA. The number of
- * pages is first computed based on the buffer size, and pages are then
- * retrieved by a call to get_user_pages.
- *
- * Pages are pinned to memory by get_user_pages, making them available for DMA
- * transfers. However, due to memory management optimization, it seems the
- * get_user_pages doesn't guarantee that the pinned pages will not be written
- * to swap and removed from the userspace mapping(s). When this happens, a page
- * fault can be generated when accessing those unmapped pages.
- *
- * If the fault is triggered by a page table walk caused by VIPT cache
- * management operations, the page fault handler might oops if the MM semaphore
- * is held, as it can't handle kernel page faults in that case. To fix that, a
- * fixup entry needs to be added to the cache management code, or the userspace
- * VMA must be locked to avoid removing pages from the userspace mapping in the
- * first place.
- *
- * If the number of pages retrieved is smaller than the number required by the
- * buffer size, the function returns -EFAULT.
- */
-static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
-{
- unsigned long data;
- unsigned int first;
- unsigned int last;
- int ret;
-
- data = buf->vbuf.m.userptr;
- first = (data & PAGE_MASK) >> PAGE_SHIFT;
- last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
-
- buf->offset = data & ~PAGE_MASK;
- buf->npages = last - first + 1;
- buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
- if (buf->pages == NULL)
- return -ENOMEM;
-
- down_read(&current->mm->mmap_sem);
- ret = get_user_pages(current, current->mm, data & PAGE_MASK,
- buf->npages,
- buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
- buf->pages, NULL);
- up_read(&current->mm->mmap_sem);
-
- if (ret != buf->npages) {
- buf->npages = ret < 0 ? 0 : ret;
- isp_video_buffer_cleanup(buf);
- return -EFAULT;
- }
-
- ret = isp_video_buffer_lock_vma(buf, 1);
- if (ret < 0)
- isp_video_buffer_cleanup(buf);
-
- return ret;
-}
-
-/*
- * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer
- *
- * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
- * memory and if they span a single VMA.
- *
- * Return 0 if the buffer is valid, or -EFAULT otherwise.
- */
-static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
-{
- struct vm_area_struct *vma;
- unsigned long prev_pfn;
- unsigned long this_pfn;
- unsigned long start;
- unsigned long end;
- dma_addr_t pa;
- int ret = -EFAULT;
-
- start = buf->vbuf.m.userptr;
- end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
-
- buf->offset = start & ~PAGE_MASK;
- buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
- buf->pages = NULL;
-
- down_read(&current->mm->mmap_sem);
- vma = find_vma(current->mm, start);
- if (vma == NULL || vma->vm_end < end)
- goto done;
-
- for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
- ret = follow_pfn(vma, start, &this_pfn);
- if (ret)
- goto done;
-
- if (prev_pfn == 0)
- pa = this_pfn << PAGE_SHIFT;
- else if (this_pfn != prev_pfn + 1) {
- ret = -EFAULT;
- goto done;
- }
-
- prev_pfn = this_pfn;
- }
-
- buf->paddr = pa + buf->offset;
- ret = 0;
-
-done:
- up_read(&current->mm->mmap_sem);
- return ret;
-}
-
-/*
- * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
- *
- * This function locates the VMAs for the buffer's userspace address and checks
- * that their flags match. The only flag that we need to care for at the moment
- * is VM_PFNMAP.
- *
- * The buffer vm_flags field is set to the first VMA flags.
- *
- * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs
- * have incompatible flags.
- */
-static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
-{
- struct vm_area_struct *vma;
- pgprot_t vm_page_prot;
- unsigned long start;
- unsigned long end;
- int ret = -EFAULT;
-
- start = buf->vbuf.m.userptr;
- end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
-
- down_read(&current->mm->mmap_sem);
-
- do {
- vma = find_vma(current->mm, start);
- if (vma == NULL)
- goto done;
-
- if (start == buf->vbuf.m.userptr) {
- buf->vm_flags = vma->vm_flags;
- vm_page_prot = vma->vm_page_prot;
- }
-
- if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP)
- goto done;
-
- if (vm_page_prot != vma->vm_page_prot)
- goto done;
-
- start = vma->vm_end + 1;
- } while (vma->vm_end < end);
-
- /* Skip cache management to enhance performances for non-cached or
- * write-combining buffers.
- */
- if (vm_page_prot == pgprot_noncached(vm_page_prot) ||
- vm_page_prot == pgprot_writecombine(vm_page_prot))
- buf->skip_cache = true;
-
- ret = 0;
-
-done:
- up_read(&current->mm->mmap_sem);
- return ret;
-}
-
-/*
- * isp_video_buffer_prepare - Make a buffer ready for operation
- *
- * Preparing a buffer involves:
- *
- * - validating VMAs (userspace buffers only)
- * - locking pages and VMAs into memory (userspace buffers only)
- * - building page and scatter-gather lists
- * - mapping buffers for DMA operation
- * - performing driver-specific preparation
- *
- * The function must be called in userspace context with a valid mm context
- * (this excludes cleanup paths such as sys_close when the userspace process
- * segfaults).
- */
-static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
-{
- enum dma_data_direction direction;
- int ret;
-
- switch (buf->vbuf.memory) {
- case V4L2_MEMORY_MMAP:
- ret = isp_video_buffer_sglist_kernel(buf);
- break;
-
- case V4L2_MEMORY_USERPTR:
- ret = isp_video_buffer_prepare_vm_flags(buf);
- if (ret < 0)
- return ret;
-
- if (buf->vm_flags & VM_PFNMAP) {
- ret = isp_video_buffer_prepare_pfnmap(buf);
- if (ret < 0)
- return ret;
-
- ret = isp_video_buffer_sglist_pfnmap(buf);
- } else {
- ret = isp_video_buffer_prepare_user(buf);
- if (ret < 0)
- return ret;
-
- ret = isp_video_buffer_sglist_user(buf);
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- if (ret < 0)
- goto done;
-
- if (!(buf->vm_flags & VM_PFNMAP)) {
- direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
- ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen,
- direction);
- if (ret != buf->sglen) {
- ret = -EFAULT;
- goto done;
- }
- }
-
- if (buf->queue->ops->buffer_prepare)
- ret = buf->queue->ops->buffer_prepare(buf);
-
-done:
- if (ret < 0) {
- isp_video_buffer_cleanup(buf);
- return ret;
- }
-
- return ret;
-}
-
-/*
- * isp_video_queue_query - Query the status of a given buffer
- *
- * Locking: must be called with the queue lock held.
- */
-static void isp_video_buffer_query(struct isp_video_buffer *buf,
- struct v4l2_buffer *vbuf)
-{
- memcpy(vbuf, &buf->vbuf, sizeof(*vbuf));
-
- if (buf->vma_use_count)
- vbuf->flags |= V4L2_BUF_FLAG_MAPPED;
-
- switch (buf->state) {
- case ISP_BUF_STATE_ERROR:
- vbuf->flags |= V4L2_BUF_FLAG_ERROR;
- case ISP_BUF_STATE_DONE:
- vbuf->flags |= V4L2_BUF_FLAG_DONE;
- case ISP_BUF_STATE_QUEUED:
- case ISP_BUF_STATE_ACTIVE:
- vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
- break;
- case ISP_BUF_STATE_IDLE:
- default:
- break;
- }
-}
-
-/*
- * isp_video_buffer_wait - Wait for a buffer to be ready
- *
- * In non-blocking mode, return immediately with 0 if the buffer is ready or
- * -EAGAIN if the buffer is in the QUEUED or ACTIVE state.
- *
- * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait
- * queue using the same condition.
- */
-static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
-{
- if (nonblocking) {
- return (buf->state != ISP_BUF_STATE_QUEUED &&
- buf->state != ISP_BUF_STATE_ACTIVE)
- ? 0 : -EAGAIN;
- }
-
- return wait_event_interruptible(buf->wait,
- buf->state != ISP_BUF_STATE_QUEUED &&
- buf->state != ISP_BUF_STATE_ACTIVE);
-}
-
-/* -----------------------------------------------------------------------------
- * Queue management
- */
-
-/*
- * isp_video_queue_free - Free video buffers memory
- *
- * Buffers can only be freed if the queue isn't streaming and if no buffer is
- * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
- *
- * This function must be called with the queue lock held.
- */
-static int isp_video_queue_free(struct isp_video_queue *queue)
-{
- unsigned int i;
-
- if (queue->streaming)
- return -EBUSY;
-
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffers[i]->vma_use_count != 0)
- return -EBUSY;
- }
-
- for (i = 0; i < queue->count; ++i) {
- struct isp_video_buffer *buf = queue->buffers[i];
-
- isp_video_buffer_cleanup(buf);
-
- vfree(buf->vaddr);
- buf->vaddr = NULL;
-
- kfree(buf);
- queue->buffers[i] = NULL;
- }
-
- INIT_LIST_HEAD(&queue->queue);
- queue->count = 0;
- return 0;
-}
-
-/*
- * isp_video_queue_alloc - Allocate video buffers memory
- *
- * This function must be called with the queue lock held.
- */
-static int isp_video_queue_alloc(struct isp_video_queue *queue,
- unsigned int nbuffers,
- unsigned int size, enum v4l2_memory memory)
-{
- struct isp_video_buffer *buf;
- unsigned int i;
- void *mem;
- int ret;
-
- /* Start by freeing the buffers. */
- ret = isp_video_queue_free(queue);
- if (ret < 0)
- return ret;
-
- /* Bail out of no buffers should be allocated. */
- if (nbuffers == 0)
- return 0;
-
- /* Initialize the allocated buffers. */
- for (i = 0; i < nbuffers; ++i) {
- buf = kzalloc(queue->bufsize, GFP_KERNEL);
- if (buf == NULL)
- break;
-
- if (memory == V4L2_MEMORY_MMAP) {
- /* Allocate video buffers memory for mmap mode. Align
- * the size to the page size.
- */
- mem = vmalloc_32_user(PAGE_ALIGN(size));
- if (mem == NULL) {
- kfree(buf);
- break;
- }
-
- buf->vbuf.m.offset = i * PAGE_ALIGN(size);
- buf->vaddr = mem;
- }
-
- buf->vbuf.index = i;
- buf->vbuf.length = size;
- buf->vbuf.type = queue->type;
- buf->vbuf.field = V4L2_FIELD_NONE;
- buf->vbuf.memory = memory;
-
- buf->queue = queue;
- init_waitqueue_head(&buf->wait);
-
- queue->buffers[i] = buf;
- }
-
- if (i == 0)
- return -ENOMEM;
-
- queue->count = i;
- return nbuffers;
-}
-
-/**
- * omap3isp_video_queue_cleanup - Clean up the video buffers queue
- * @queue: Video buffers queue
- *
- * Free all allocated resources and clean up the video buffers queue. The queue
- * must not be busy (no ongoing video stream) and buffers must have been
- * unmapped.
- *
- * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been
- * unmapped.
- */
-int omap3isp_video_queue_cleanup(struct isp_video_queue *queue)
-{
- return isp_video_queue_free(queue);
-}
-
-/**
- * omap3isp_video_queue_init - Initialize the video buffers queue
- * @queue: Video buffers queue
- * @type: V4L2 buffer type (capture or output)
- * @ops: Driver-specific queue operations
- * @dev: Device used for DMA operations
- * @bufsize: Size of the driver-specific buffer structure
- *
- * Initialize the video buffers queue with the supplied parameters.
- *
- * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or
- * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet.
- *
- * Buffer objects will be allocated using the given buffer size to allow room
- * for driver-specific fields. Driver-specific buffer structures must start
- * with a struct isp_video_buffer field. Drivers with no driver-specific buffer
- * structure must pass the size of the isp_video_buffer structure in the bufsize
- * parameter.
- *
- * Return 0 on success.
- */
-int omap3isp_video_queue_init(struct isp_video_queue *queue,
- enum v4l2_buf_type type,
- const struct isp_video_queue_operations *ops,
- struct device *dev, unsigned int bufsize)
-{
- INIT_LIST_HEAD(&queue->queue);
- mutex_init(&queue->lock);
- spin_lock_init(&queue->irqlock);
-
- queue->type = type;
- queue->ops = ops;
- queue->dev = dev;
- queue->bufsize = bufsize;
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 operations
- */
-
-/**
- * omap3isp_video_queue_reqbufs - Allocate video buffers memory
- *
- * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It
- * allocated video buffer objects and, for MMAP buffers, buffer memory.
- *
- * If the number of buffers is 0, all buffers are freed and the function returns
- * without performing any allocation.
- *
- * If the number of buffers is not 0, currently allocated buffers (if any) are
- * freed and the requested number of buffers are allocated. Depending on
- * driver-specific requirements and on memory availability, a number of buffer
- * smaller or bigger than requested can be allocated. This isn't considered as
- * an error.
- *
- * Return 0 on success or one of the following error codes:
- *
- * -EINVAL if the buffer type or index are invalid
- * -EBUSY if the queue is busy (streaming or buffers mapped)
- * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition
- */
-int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
- struct v4l2_requestbuffers *rb)
-{
- unsigned int nbuffers = rb->count;
- unsigned int size;
- int ret;
-
- if (rb->type != queue->type)
- return -EINVAL;
-
- queue->ops->queue_prepare(queue, &nbuffers, &size);
- if (size == 0)
- return -EINVAL;
-
- nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS);
-
- mutex_lock(&queue->lock);
-
- ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory);
- if (ret < 0)
- goto done;
-
- rb->count = ret;
- ret = 0;
-
-done:
- mutex_unlock(&queue->lock);
- return ret;
-}
-
-/**
- * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue
- *
- * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It
- * returns the status of a given video buffer.
- *
- * Return 0 on success or -EINVAL if the buffer type or index are invalid.
- */
-int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
- struct v4l2_buffer *vbuf)
-{
- struct isp_video_buffer *buf;
- int ret = 0;
-
- if (vbuf->type != queue->type)
- return -EINVAL;
-
- mutex_lock(&queue->lock);
-
- if (vbuf->index >= queue->count) {
- ret = -EINVAL;
- goto done;
- }
-
- buf = queue->buffers[vbuf->index];
- isp_video_buffer_query(buf, vbuf);
-
-done:
- mutex_unlock(&queue->lock);
- return ret;
-}
-
-/**
- * omap3isp_video_queue_qbuf - Queue a buffer
- *
- * This function is intended to be used as a VIDIOC_QBUF ioctl handler.
- *
- * The v4l2_buffer structure passed from userspace is first sanity tested. If
- * sane, the buffer is then processed and added to the main queue and, if the
- * queue is streaming, to the IRQ queue.
- *
- * Before being enqueued, USERPTR buffers are checked for address changes. If
- * the buffer has a different userspace address, the old memory area is unlocked
- * and the new memory area is locked.
- */
-int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
- struct v4l2_buffer *vbuf)
-{
- struct isp_video_buffer *buf;
- unsigned long flags;
- int ret = -EINVAL;
-
- if (vbuf->type != queue->type)
- goto done;
-
- mutex_lock(&queue->lock);
-
- if (vbuf->index >= queue->count)
- goto done;
-
- buf = queue->buffers[vbuf->index];
-
- if (vbuf->memory != buf->vbuf.memory)
- goto done;
-
- if (buf->state != ISP_BUF_STATE_IDLE)
- goto done;
-
- if (vbuf->memory == V4L2_MEMORY_USERPTR &&
- vbuf->length < buf->vbuf.length)
- goto done;
-
- if (vbuf->memory == V4L2_MEMORY_USERPTR &&
- vbuf->m.userptr != buf->vbuf.m.userptr) {
- isp_video_buffer_cleanup(buf);
- buf->vbuf.m.userptr = vbuf->m.userptr;
- buf->prepared = 0;
- }
-
- if (!buf->prepared) {
- ret = isp_video_buffer_prepare(buf);
- if (ret < 0)
- goto done;
- buf->prepared = 1;
- }
-
- isp_video_buffer_cache_sync(buf);
-
- buf->state = ISP_BUF_STATE_QUEUED;
- list_add_tail(&buf->stream, &queue->queue);
-
- if (queue->streaming) {
- spin_lock_irqsave(&queue->irqlock, flags);
- queue->ops->buffer_queue(buf);
- spin_unlock_irqrestore(&queue->irqlock, flags);
- }
-
- ret = 0;
-
-done:
- mutex_unlock(&queue->lock);
- return ret;
-}
-
-/**
- * omap3isp_video_queue_dqbuf - Dequeue a buffer
- *
- * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
- *
- * The v4l2_buffer structure passed from userspace is first sanity tested. If
- * sane, the buffer is then processed and added to the main queue and, if the
- * queue is streaming, to the IRQ queue.
- *
- * Before being enqueued, USERPTR buffers are checked for address changes. If
- * the buffer has a different userspace address, the old memory area is unlocked
- * and the new memory area is locked.
- */
-int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
- struct v4l2_buffer *vbuf, int nonblocking)
-{
- struct isp_video_buffer *buf;
- int ret;
-
- if (vbuf->type != queue->type)
- return -EINVAL;
-
- mutex_lock(&queue->lock);
-
- if (list_empty(&queue->queue)) {
- ret = -EINVAL;
- goto done;
- }
-
- buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
- ret = isp_video_buffer_wait(buf, nonblocking);
- if (ret < 0)
- goto done;
-
- list_del(&buf->stream);
-
- isp_video_buffer_query(buf, vbuf);
- buf->state = ISP_BUF_STATE_IDLE;
- vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED;
-
-done:
- mutex_unlock(&queue->lock);
- return ret;
-}
-
-/**
- * omap3isp_video_queue_streamon - Start streaming
- *
- * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It
- * starts streaming on the queue and calls the buffer_queue operation for all
- * queued buffers.
- *
- * Return 0 on success.
- */
-int omap3isp_video_queue_streamon(struct isp_video_queue *queue)
-{
- struct isp_video_buffer *buf;
- unsigned long flags;
-
- mutex_lock(&queue->lock);
-
- if (queue->streaming)
- goto done;
-
- queue->streaming = 1;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- list_for_each_entry(buf, &queue->queue, stream)
- queue->ops->buffer_queue(buf);
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
- mutex_unlock(&queue->lock);
- return 0;
-}
-
-/**
- * omap3isp_video_queue_streamoff - Stop streaming
- *
- * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It
- * stops streaming on the queue and wakes up all the buffers.
- *
- * Drivers must stop the hardware and synchronize with interrupt handlers and/or
- * delayed works before calling this function to make sure no buffer will be
- * touched by the driver and/or hardware.
- */
-void omap3isp_video_queue_streamoff(struct isp_video_queue *queue)
-{
- struct isp_video_buffer *buf;
- unsigned long flags;
- unsigned int i;
-
- mutex_lock(&queue->lock);
-
- if (!queue->streaming)
- goto done;
-
- queue->streaming = 0;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- for (i = 0; i < queue->count; ++i) {
- buf = queue->buffers[i];
-
- if (buf->state == ISP_BUF_STATE_ACTIVE)
- wake_up(&buf->wait);
-
- buf->state = ISP_BUF_STATE_IDLE;
- }
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
- INIT_LIST_HEAD(&queue->queue);
-
-done:
- mutex_unlock(&queue->lock);
-}
-
-/**
- * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE
- *
- * This function is intended to be used with suspend/resume operations. It
- * discards all 'done' buffers as they would be too old to be requested after
- * resume.
- *
- * Drivers must stop the hardware and synchronize with interrupt handlers and/or
- * delayed works before calling this function to make sure no buffer will be
- * touched by the driver and/or hardware.
- */
-void omap3isp_video_queue_discard_done(struct isp_video_queue *queue)
-{
- struct isp_video_buffer *buf;
- unsigned int i;
-
- mutex_lock(&queue->lock);
-
- if (!queue->streaming)
- goto done;
-
- for (i = 0; i < queue->count; ++i) {
- buf = queue->buffers[i];
-
- if (buf->state == ISP_BUF_STATE_DONE)
- buf->state = ISP_BUF_STATE_ERROR;
- }
-
-done:
- mutex_unlock(&queue->lock);
-}
-
-static void isp_video_queue_vm_open(struct vm_area_struct *vma)
-{
- struct isp_video_buffer *buf = vma->vm_private_data;
-
- buf->vma_use_count++;
-}
-
-static void isp_video_queue_vm_close(struct vm_area_struct *vma)
-{
- struct isp_video_buffer *buf = vma->vm_private_data;
-
- buf->vma_use_count--;
-}
-
-static const struct vm_operations_struct isp_video_queue_vm_ops = {
- .open = isp_video_queue_vm_open,
- .close = isp_video_queue_vm_close,
-};
-
-/**
- * omap3isp_video_queue_mmap - Map buffers to userspace
- *
- * This function is intended to be used as an mmap() file operation handler. It
- * maps a buffer to userspace based on the VMA offset.
- *
- * Only buffers of memory type MMAP are supported.
- */
-int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
- struct vm_area_struct *vma)
-{
- struct isp_video_buffer *uninitialized_var(buf);
- unsigned long size;
- unsigned int i;
- int ret = 0;
-
- mutex_lock(&queue->lock);
-
- for (i = 0; i < queue->count; ++i) {
- buf = queue->buffers[i];
- if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count) {
- ret = -EINVAL;
- goto done;
- }
-
- size = vma->vm_end - vma->vm_start;
-
- if (buf->vbuf.memory != V4L2_MEMORY_MMAP ||
- size != PAGE_ALIGN(buf->vbuf.length)) {
- ret = -EINVAL;
- goto done;
- }
-
- ret = remap_vmalloc_range(vma, buf->vaddr, 0);
- if (ret < 0)
- goto done;
-
- vma->vm_ops = &isp_video_queue_vm_ops;
- vma->vm_private_data = buf;
- isp_video_queue_vm_open(vma);
-
-done:
- mutex_unlock(&queue->lock);
- return ret;
-}
-
-/**
- * omap3isp_video_queue_poll - Poll video queue state
- *
- * This function is intended to be used as a poll() file operation handler. It
- * polls the state of the video buffer at the front of the queue and returns an
- * events mask.
- *
- * If no buffer is present at the front of the queue, POLLERR is returned.
- */
-unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
- struct file *file, poll_table *wait)
-{
- struct isp_video_buffer *buf;
- unsigned int mask = 0;
-
- mutex_lock(&queue->lock);
- if (list_empty(&queue->queue)) {
- mask |= POLLERR;
- goto done;
- }
- buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
-
- poll_wait(file, &buf->wait, wait);
- if (buf->state == ISP_BUF_STATE_DONE ||
- buf->state == ISP_BUF_STATE_ERROR) {
- if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- mask |= POLLIN | POLLRDNORM;
- else
- mask |= POLLOUT | POLLWRNORM;
- }
-
-done:
- mutex_unlock(&queue->lock);
- return mask;
-}
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
deleted file mode 100644
index ae17d917f77b..000000000000
--- a/drivers/media/video/omap3isp/ispresizer.c
+++ /dev/null
@@ -1,1776 +0,0 @@
-/*
- * ispresizer.c
- *
- * TI OMAP3 ISP - Resizer module
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2009 Texas Instruments, Inc
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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/mm.h>
-#include <linux/module.h>
-
-#include "isp.h"
-#include "ispreg.h"
-#include "ispresizer.h"
-
-/*
- * Resizer Constants
- */
-#define MIN_RESIZE_VALUE 64
-#define MID_RESIZE_VALUE 512
-#define MAX_RESIZE_VALUE 1024
-
-#define MIN_IN_WIDTH 32
-#define MIN_IN_HEIGHT 32
-#define MAX_IN_WIDTH_MEMORY_MODE 4095
-#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
-#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
-#define MAX_IN_HEIGHT 4095
-
-#define MIN_OUT_WIDTH 16
-#define MIN_OUT_HEIGHT 2
-#define MAX_OUT_HEIGHT 4095
-
-/*
- * Resizer Use Constraints
- * "TRM ES3.1, table 12-46"
- */
-#define MAX_4TAP_OUT_WIDTH_ES1 1280
-#define MAX_7TAP_OUT_WIDTH_ES1 640
-#define MAX_4TAP_OUT_WIDTH_ES2 3312
-#define MAX_7TAP_OUT_WIDTH_ES2 1650
-#define MAX_4TAP_OUT_WIDTH_3630 4096
-#define MAX_7TAP_OUT_WIDTH_3630 2048
-
-/*
- * Constants for ratio calculation
- */
-#define RESIZE_DIVISOR 256
-#define DEFAULT_PHASE 1
-
-/*
- * Default (and only) configuration of filter coefficients.
- * 7-tap mode is for scale factors 0.25x to 0.5x.
- * 4-tap mode is for scale factors 0.5x to 4.0x.
- * There shouldn't be any reason to recalculate these, EVER.
- */
-static const struct isprsz_coef filter_coefs = {
- /* For 8-phase 4-tap horizontal filter: */
- {
- 0x0000, 0x0100, 0x0000, 0x0000,
- 0x03FA, 0x00F6, 0x0010, 0x0000,
- 0x03F9, 0x00DB, 0x002C, 0x0000,
- 0x03FB, 0x00B3, 0x0053, 0x03FF,
- 0x03FD, 0x0082, 0x0084, 0x03FD,
- 0x03FF, 0x0053, 0x00B3, 0x03FB,
- 0x0000, 0x002C, 0x00DB, 0x03F9,
- 0x0000, 0x0010, 0x00F6, 0x03FA
- },
- /* For 8-phase 4-tap vertical filter: */
- {
- 0x0000, 0x0100, 0x0000, 0x0000,
- 0x03FA, 0x00F6, 0x0010, 0x0000,
- 0x03F9, 0x00DB, 0x002C, 0x0000,
- 0x03FB, 0x00B3, 0x0053, 0x03FF,
- 0x03FD, 0x0082, 0x0084, 0x03FD,
- 0x03FF, 0x0053, 0x00B3, 0x03FB,
- 0x0000, 0x002C, 0x00DB, 0x03F9,
- 0x0000, 0x0010, 0x00F6, 0x03FA
- },
- /* For 4-phase 7-tap horizontal filter: */
- #define DUMMY 0
- {
- 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
- 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
- 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
- 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
- },
- /* For 4-phase 7-tap vertical filter: */
- {
- 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
- 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
- 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
- 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
- }
- /*
- * The dummy padding is required in 7-tap mode because of how the
- * registers are arranged physically.
- */
- #undef DUMMY
-};
-
-/*
- * __resizer_get_format - helper function for getting resizer format
- * @res : pointer to resizer private structure
- * @pad : pad number
- * @fh : V4L2 subdev file handle
- * @which : wanted subdev format
- * return zero
- */
-static struct v4l2_mbus_framefmt *
-__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(fh, pad);
- else
- return &res->formats[pad];
-}
-
-/*
- * __resizer_get_crop - helper function for getting resizer crop rectangle
- * @res : pointer to resizer private structure
- * @fh : V4L2 subdev file handle
- * @which : wanted subdev crop rectangle
- */
-static struct v4l2_rect *
-__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
- else
- return &res->crop.request;
-}
-
-/*
- * resizer_set_filters - Set resizer filters
- * @res: Device context.
- * @h_coeff: horizontal coefficient
- * @v_coeff: vertical coefficient
- * Return none
- */
-static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
- const u16 *v_coeff)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
- int i;
-
- startaddr_h = ISPRSZ_HFILT10;
- startaddr_v = ISPRSZ_VFILT10;
-
- for (i = 0; i < COEFF_CNT; i += 2) {
- tmp_h = h_coeff[i] |
- (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
- tmp_v = v_coeff[i] |
- (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
- isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
- isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
- startaddr_h += 4;
- startaddr_v += 4;
- }
-}
-
-/*
- * resizer_set_bilinear - Chrominance horizontal algorithm select
- * @res: Device context.
- * @type: Filtering interpolation type.
- *
- * Filtering that is same as luminance processing is
- * intended only for downsampling, and bilinear interpolation
- * is intended only for upsampling.
- */
-static void resizer_set_bilinear(struct isp_res_device *res,
- enum resizer_chroma_algo type)
-{
- struct isp_device *isp = to_isp_device(res);
-
- if (type == RSZ_BILINEAR)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_CBILIN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_CBILIN);
-}
-
-/*
- * resizer_set_ycpos - Luminance and chrominance order
- * @res: Device context.
- * @order: order type.
- */
-static void resizer_set_ycpos(struct isp_res_device *res,
- enum v4l2_mbus_pixelcode pixelcode)
-{
- struct isp_device *isp = to_isp_device(res);
-
- switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_YCPOS);
- break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_YCPOS);
- break;
- default:
- return;
- }
-}
-
-/*
- * resizer_set_phase - Setup horizontal and vertical starting phase
- * @res: Device context.
- * @h_phase: horizontal phase parameters.
- * @v_phase: vertical phase parameters.
- *
- * Horizontal and vertical phase range is 0 to 7
- */
-static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
- u32 v_phase)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 rgval = 0;
-
- rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
- ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
- rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
- rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
-
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
-}
-
-/*
- * resizer_set_luma - Setup luminance enhancer parameters
- * @res: Device context.
- * @luma: Structure for luminance enhancer parameters.
- *
- * Algorithm select:
- * 0x0: Disable
- * 0x1: [-1 2 -1]/2 high-pass filter
- * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
- *
- * Maximum gain:
- * The data is coded in U4Q4 representation.
- *
- * Slope:
- * The data is coded in U4Q4 representation.
- *
- * Coring offset:
- * The data is coded in U8Q0 representation.
- *
- * The new luminance value is computed as:
- * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
- */
-static void resizer_set_luma(struct isp_res_device *res,
- struct resizer_luma_yenh *luma)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 rgval = 0;
-
- rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
- & ISPRSZ_YENH_ALGO_MASK;
- rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
- & ISPRSZ_YENH_GAIN_MASK;
- rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
- & ISPRSZ_YENH_SLOP_MASK;
- rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
- & ISPRSZ_YENH_CORE_MASK;
-
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
-}
-
-/*
- * resizer_set_source - Input source select
- * @res: Device context.
- * @source: Input source type
- *
- * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
- * Preview/CCDC engine, otherwise from memory.
- */
-static void resizer_set_source(struct isp_res_device *res,
- enum resizer_input_entity source)
-{
- struct isp_device *isp = to_isp_device(res);
-
- if (source == RESIZER_INPUT_MEMORY)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_INPSRC);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_INPSRC);
-}
-
-/*
- * resizer_set_ratio - Setup horizontal and vertical resizing value
- * @res: Device context.
- * @ratio: Structure for ratio parameters.
- *
- * Resizing range from 64 to 1024
- */
-static void resizer_set_ratio(struct isp_res_device *res,
- const struct resizer_ratio *ratio)
-{
- struct isp_device *isp = to_isp_device(res);
- const u16 *h_filter, *v_filter;
- u32 rgval = 0;
-
- rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
- ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
- rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
- & ISPRSZ_CNT_HRSZ_MASK;
- rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
- & ISPRSZ_CNT_VRSZ_MASK;
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
-
- /* prepare horizontal filter coefficients */
- if (ratio->horz > MID_RESIZE_VALUE)
- h_filter = &filter_coefs.h_filter_coef_7tap[0];
- else
- h_filter = &filter_coefs.h_filter_coef_4tap[0];
-
- /* prepare vertical filter coefficients */
- if (ratio->vert > MID_RESIZE_VALUE)
- v_filter = &filter_coefs.v_filter_coef_7tap[0];
- else
- v_filter = &filter_coefs.v_filter_coef_4tap[0];
-
- resizer_set_filters(res, h_filter, v_filter);
-}
-
-/*
- * resizer_set_dst_size - Setup the output height and width
- * @res: Device context.
- * @width: Output width.
- * @height: Output height.
- *
- * Width :
- * The value must be EVEN.
- *
- * Height:
- * The number of bytes written to SDRAM must be
- * a multiple of 16-bytes if the vertical resizing factor
- * is greater than 1x (upsizing)
- */
-static void resizer_set_output_size(struct isp_res_device *res,
- u32 width, u32 height)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 rgval = 0;
-
- dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
- rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
- & ISPRSZ_OUT_SIZE_HORZ_MASK;
- rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
- & ISPRSZ_OUT_SIZE_VERT_MASK;
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
-}
-
-/*
- * resizer_set_output_offset - Setup memory offset for the output lines.
- * @res: Device context.
- * @offset: Memory offset.
- *
- * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
- * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
- * the SDRAM line offset must be set on a 256-byte boundary
- */
-static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
-{
- struct isp_device *isp = to_isp_device(res);
-
- isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
-}
-
-/*
- * resizer_set_start - Setup vertical and horizontal start position
- * @res: Device context.
- * @left: Horizontal start position.
- * @top: Vertical start position.
- *
- * Vertical start line:
- * This field makes sense only when the resizer obtains its input
- * from the preview engine/CCDC
- *
- * Horizontal start pixel:
- * Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
- * When the resizer gets its input from SDRAM, this field must be set
- * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
- */
-static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 rgval = 0;
-
- rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
- & ISPRSZ_IN_START_HORZ_ST_MASK;
- rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
- & ISPRSZ_IN_START_VERT_ST_MASK;
-
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
-}
-
-/*
- * resizer_set_input_size - Setup the input size
- * @res: Device context.
- * @width: The range is 0 to 4095 pixels
- * @height: The range is 0 to 4095 lines
- */
-static void resizer_set_input_size(struct isp_res_device *res,
- u32 width, u32 height)
-{
- struct isp_device *isp = to_isp_device(res);
- u32 rgval = 0;
-
- dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
-
- rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
- & ISPRSZ_IN_SIZE_HORZ_MASK;
- rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
- & ISPRSZ_IN_SIZE_VERT_MASK;
-
- isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
-}
-
-/*
- * resizer_set_src_offs - Setup the memory offset for the input lines
- * @res: Device context.
- * @offset: Memory offset.
- *
- * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
- * boundary; the 5 LSBs are read-only. This field must be programmed to be
- * 0x0 if the resizer input is from preview engine/CCDC.
- */
-static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
-{
- struct isp_device *isp = to_isp_device(res);
-
- isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
-}
-
-/*
- * resizer_set_intype - Input type select
- * @res: Device context.
- * @type: Pixel format type.
- */
-static void resizer_set_intype(struct isp_res_device *res,
- enum resizer_colors_type type)
-{
- struct isp_device *isp = to_isp_device(res);
-
- if (type == RSZ_COLOR8)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_INPTYP);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
- ISPRSZ_CNT_INPTYP);
-}
-
-/*
- * __resizer_set_inaddr - Helper function for set input address
- * @res : pointer to resizer private data structure
- * @addr: input address
- * return none
- */
-static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
-{
- struct isp_device *isp = to_isp_device(res);
-
- isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
-}
-
-/*
- * The data rate at the horizontal resizer output must not exceed half the
- * functional clock or 100 MP/s, whichever is lower. According to the TRM
- * there's no similar requirement for the vertical resizer output. However
- * experience showed that vertical upscaling by 4 leads to SBL overflows (with
- * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
- * output data rate to the functional clock or 200 MP/s, whichever is lower,
- * seems to get rid of SBL overflows.
- *
- * The maximum data rate at the output of the horizontal resizer can thus be
- * computed with
- *
- * max intermediate rate <= L3 clock * input height / output height
- * max intermediate rate <= L3 clock / 2
- *
- * The maximum data rate at the resizer input is then
- *
- * max input rate <= max intermediate rate * input width / output width
- *
- * where the input width and height are the resizer input crop rectangle size.
- * The TRM doesn't clearly explain if that's a maximum instant data rate or a
- * maximum average data rate.
- */
-void omap3isp_resizer_max_rate(struct isp_res_device *res,
- unsigned int *max_rate)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
- const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
- unsigned long limit = min(pipe->l3_ick, 200000000UL);
- unsigned long clock;
-
- clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
- clock = min(clock, limit / 2);
- *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
-}
-
-/*
- * When the resizer processes images from memory, the driver must slow down read
- * requests on the input to at least comply with the internal data rate
- * requirements. If the application real-time requirements can cope with slower
- * processing, the resizer can be slowed down even more to put less pressure on
- * the overall system.
- *
- * When the resizer processes images on the fly (either from the CCDC or the
- * preview module), the same data rate requirements apply but they can't be
- * enforced at the resizer level. The image input module (sensor, CCP2 or
- * preview module) must not provide image data faster than the resizer can
- * process.
- *
- * For live image pipelines, the data rate is set by the frame format, size and
- * rate. The sensor output frame rate must not exceed the maximum resizer data
- * rate.
- *
- * The resizer slows down read requests by inserting wait cycles in the SBL
- * requests. The maximum number of 256-byte requests per second can be computed
- * as (the data rate is multiplied by 2 to convert from pixels per second to
- * bytes per second)
- *
- * request per second = data rate * 2 / 256
- * cycles per request = cycles per second / requests per second
- *
- * The number of cycles per second is controlled by the L3 clock, leading to
- *
- * cycles per request = L3 frequency / 2 * 256 / data rate
- */
-static void resizer_adjust_bandwidth(struct isp_res_device *res)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
- struct isp_device *isp = to_isp_device(res);
- unsigned long l3_ick = pipe->l3_ick;
- struct v4l2_fract *timeperframe;
- unsigned int cycles_per_frame;
- unsigned int requests_per_frame;
- unsigned int cycles_per_request;
- unsigned int granularity;
- unsigned int minimum;
- unsigned int maximum;
- unsigned int value;
-
- if (res->input != RESIZER_INPUT_MEMORY) {
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
- ISPSBL_SDR_REQ_RSZ_EXP_MASK);
- return;
- }
-
- switch (isp->revision) {
- case ISP_REVISION_1_0:
- case ISP_REVISION_2_0:
- default:
- granularity = 1024;
- break;
-
- case ISP_REVISION_15_0:
- granularity = 32;
- break;
- }
-
- /* Compute the minimum number of cycles per request, based on the
- * pipeline maximum data rate. This is an absolute lower bound if we
- * don't want SBL overflows, so round the value up.
- */
- cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
- pipe->max_rate);
- minimum = DIV_ROUND_UP(cycles_per_request, granularity);
-
- /* Compute the maximum number of cycles per request, based on the
- * requested frame rate. This is a soft upper bound to achieve a frame
- * rate equal or higher than the requested value, so round the value
- * down.
- */
- timeperframe = &pipe->max_timeperframe;
-
- requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
- * res->crop.active.height;
- cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
- timeperframe->denominator);
- cycles_per_request = cycles_per_frame / requests_per_frame;
-
- maximum = cycles_per_request / granularity;
-
- value = max(minimum, maximum);
-
- dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
- ISPSBL_SDR_REQ_RSZ_EXP_MASK,
- value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
-}
-
-/*
- * omap3isp_resizer_busy - Checks if ISP resizer is busy.
- *
- * Returns busy field from ISPRSZ_PCR register.
- */
-int omap3isp_resizer_busy(struct isp_res_device *res)
-{
- struct isp_device *isp = to_isp_device(res);
-
- return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
- ISPRSZ_PCR_BUSY;
-}
-
-/*
- * resizer_set_inaddr - Sets the memory address of the input frame.
- * @addr: 32bit memory address aligned on 32byte boundary.
- */
-static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
-{
- res->addr_base = addr;
-
- /* This will handle crop settings in stream off state */
- if (res->crop_offset)
- addr += res->crop_offset & ~0x1f;
-
- __resizer_set_inaddr(res, addr);
-}
-
-/*
- * Configures the memory address to which the output frame is written.
- * @addr: 32bit memory address aligned on 32byte boundary.
- * Note: For SBL efficiency reasons the address should be on a 256-byte
- * boundary.
- */
-static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
-{
- struct isp_device *isp = to_isp_device(res);
-
- /*
- * Set output address. This needs to be in its own function
- * because it changes often.
- */
- isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
- OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
-}
-
-/*
- * resizer_print_status - Prints the values of the resizer module registers.
- */
-#define RSZ_PRINT_REGISTER(isp, name)\
- dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
- isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
-
-static void resizer_print_status(struct isp_res_device *res)
-{
- struct isp_device *isp = to_isp_device(res);
-
- dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
-
- RSZ_PRINT_REGISTER(isp, PCR);
- RSZ_PRINT_REGISTER(isp, CNT);
- RSZ_PRINT_REGISTER(isp, OUT_SIZE);
- RSZ_PRINT_REGISTER(isp, IN_START);
- RSZ_PRINT_REGISTER(isp, IN_SIZE);
- RSZ_PRINT_REGISTER(isp, SDR_INADD);
- RSZ_PRINT_REGISTER(isp, SDR_INOFF);
- RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
- RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
- RSZ_PRINT_REGISTER(isp, YENH);
-
- dev_dbg(isp->dev, "--------------------------------------------\n");
-}
-
-/*
- * resizer_calc_ratios - Helper function for calculate resizer ratios
- * @res: pointer to resizer private data structure
- * @input: input frame size
- * @output: output frame size
- * @ratio : return calculated ratios
- * return none
- *
- * The resizer uses a polyphase sample rate converter. The upsampling filter
- * has a fixed number of phases that depend on the resizing ratio. As the ratio
- * computation depends on the number of phases, we need to compute a first
- * approximation and then refine it.
- *
- * The input/output/ratio relationship is given by the OMAP34xx TRM:
- *
- * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
- * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
- * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
- * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
- * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
- * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
- *
- * iw and ih are the input width and height after cropping. Those equations need
- * to be satisfied exactly for the resizer to work correctly.
- *
- * The equations can't be easily reverted, as the >> 8 operation is not linear.
- * In addition, not all input sizes can be achieved for a given output size. To
- * get the highest input size lower than or equal to the requested input size,
- * we need to compute the highest resizing ratio that satisfies the following
- * inequality (taking the 4-tap mode width equation as an example)
- *
- * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
- *
- * (where iw is the requested input width) which can be rewritten as
- *
- * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
- * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b
- * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16
- *
- * where b is the value of the 8 least significant bits of the right hand side
- * expression of the last inequality. The highest resizing ratio value will be
- * achieved when b is equal to its maximum value of 255. That resizing ratio
- * value will still satisfy the original inequality, as b will disappear when
- * the expression will be shifted right by 8.
- *
- * The reverted the equations thus become
- *
- * - 8-phase, 4-tap mode
- * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
- * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
- * - 4-phase, 7-tap mode
- * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
- * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
- *
- * The ratios are integer values, and are rounded down to ensure that the
- * cropped input size is not bigger than the uncropped input size.
- *
- * As the number of phases/taps, used to select the correct equations to compute
- * the ratio, depends on the ratio, we start with the 4-tap mode equations to
- * compute an approximation of the ratio, and switch to the 7-tap mode equations
- * if the approximation is higher than the ratio threshold.
- *
- * As the 7-tap mode equations will return a ratio smaller than or equal to the
- * 4-tap mode equations, the resulting ratio could become lower than or equal to
- * the ratio threshold. This 'equations loop' isn't an issue as long as the
- * correct equations are used to compute the final input size. Starting with the
- * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
- * loop', the smallest of the ratio values will be used, never exceeding the
- * requested input size.
- *
- * We first clamp the output size according to the hardware capabilitie to avoid
- * auto-cropping the input more than required to satisfy the TRM equations. The
- * minimum output size is achieved with a scaling factor of 1024. It is thus
- * computed using the 7-tap equations.
- *
- * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
- * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
- *
- * Similarly, the maximum output size is achieved with a scaling factor of 64
- * and computed using the 4-tap equations.
- *
- * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
- * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
- *
- * The additional +255 term compensates for the round down operation performed
- * by the TRM equations when shifting the value right by 8 bits.
- *
- * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
- * the maximum value guarantees that the ratio value will never be smaller than
- * the minimum, but it could still slightly exceed the maximum. Clamping the
- * ratio will thus result in a resizing factor slightly larger than the
- * requested value.
- *
- * To accommodate that, and make sure the TRM equations are satisfied exactly, we
- * compute the input crop rectangle as the last step.
- *
- * As if the situation wasn't complex enough, the maximum output width depends
- * on the vertical resizing ratio. Fortunately, the output height doesn't
- * depend on the horizontal resizing ratio. We can then start by computing the
- * output height and the vertical ratio, and then move to computing the output
- * width and the horizontal ratio.
- */
-static void resizer_calc_ratios(struct isp_res_device *res,
- struct v4l2_rect *input,
- struct v4l2_mbus_framefmt *output,
- struct resizer_ratio *ratio)
-{
- struct isp_device *isp = to_isp_device(res);
- const unsigned int spv = DEFAULT_PHASE;
- const unsigned int sph = DEFAULT_PHASE;
- unsigned int upscaled_width;
- unsigned int upscaled_height;
- unsigned int min_width;
- unsigned int min_height;
- unsigned int max_width;
- unsigned int max_height;
- unsigned int width_alignment;
- unsigned int width;
- unsigned int height;
-
- /*
- * Clamp the output height based on the hardware capabilities and
- * compute the vertical resizing ratio.
- */
- min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
- min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
- max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
- max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
- output->height = clamp(output->height, min_height, max_height);
-
- ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
- / (output->height - 1);
- if (ratio->vert > MID_RESIZE_VALUE)
- ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
- / (output->height - 1);
- ratio->vert = clamp_t(unsigned int, ratio->vert,
- MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
-
- if (ratio->vert <= MID_RESIZE_VALUE) {
- upscaled_height = (output->height - 1) * ratio->vert
- + 32 * spv + 16;
- height = (upscaled_height >> 8) + 4;
- } else {
- upscaled_height = (output->height - 1) * ratio->vert
- + 64 * spv + 32;
- height = (upscaled_height >> 8) + 7;
- }
-
- /*
- * Compute the minimum and maximum output widths based on the hardware
- * capabilities. The maximum depends on the vertical resizing ratio.
- */
- min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
- min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
-
- if (ratio->vert <= MID_RESIZE_VALUE) {
- switch (isp->revision) {
- case ISP_REVISION_1_0:
- max_width = MAX_4TAP_OUT_WIDTH_ES1;
- break;
-
- case ISP_REVISION_2_0:
- default:
- max_width = MAX_4TAP_OUT_WIDTH_ES2;
- break;
-
- case ISP_REVISION_15_0:
- max_width = MAX_4TAP_OUT_WIDTH_3630;
- break;
- }
- } else {
- switch (isp->revision) {
- case ISP_REVISION_1_0:
- max_width = MAX_7TAP_OUT_WIDTH_ES1;
- break;
-
- case ISP_REVISION_2_0:
- default:
- max_width = MAX_7TAP_OUT_WIDTH_ES2;
- break;
-
- case ISP_REVISION_15_0:
- max_width = MAX_7TAP_OUT_WIDTH_3630;
- break;
- }
- }
- max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
- + 1, max_width);
-
- /*
- * The output width must be even, and must be a multiple of 16 bytes
- * when upscaling vertically. Clamp the output width to the valid range.
- * Take the alignment into account (the maximum width in 7-tap mode on
- * ES2 isn't a multiple of 8) and align the result up to make sure it
- * won't be smaller than the minimum.
- */
- width_alignment = ratio->vert < 256 ? 8 : 2;
- output->width = clamp(output->width, min_width,
- max_width & ~(width_alignment - 1));
- output->width = ALIGN(output->width, width_alignment);
-
- ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
- / (output->width - 1);
- if (ratio->horz > MID_RESIZE_VALUE)
- ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
- / (output->width - 1);
- ratio->horz = clamp_t(unsigned int, ratio->horz,
- MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
-
- if (ratio->horz <= MID_RESIZE_VALUE) {
- upscaled_width = (output->width - 1) * ratio->horz
- + 32 * sph + 16;
- width = (upscaled_width >> 8) + 7;
- } else {
- upscaled_width = (output->width - 1) * ratio->horz
- + 64 * sph + 32;
- width = (upscaled_width >> 8) + 7;
- }
-
- /* Center the new crop rectangle. */
- input->left += (input->width - width) / 2;
- input->top += (input->height - height) / 2;
- input->width = width;
- input->height = height;
-}
-
-/*
- * resizer_set_crop_params - Setup hardware with cropping parameters
- * @res : resizer private structure
- * @crop_rect : current crop rectangle
- * @ratio : resizer ratios
- * return none
- */
-static void resizer_set_crop_params(struct isp_res_device *res,
- const struct v4l2_mbus_framefmt *input,
- const struct v4l2_mbus_framefmt *output)
-{
- resizer_set_ratio(res, &res->ratio);
-
- /* Set chrominance horizontal algorithm */
- if (res->ratio.horz >= RESIZE_DIVISOR)
- resizer_set_bilinear(res, RSZ_THE_SAME);
- else
- resizer_set_bilinear(res, RSZ_BILINEAR);
-
- resizer_adjust_bandwidth(res);
-
- if (res->input == RESIZER_INPUT_MEMORY) {
- /* Calculate additional offset for crop */
- res->crop_offset = (res->crop.active.top * input->width +
- res->crop.active.left) * 2;
- /*
- * Write lowest 4 bits of horizontal pixel offset (in pixels),
- * vertical start must be 0.
- */
- resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
-
- /*
- * Set start (read) address for cropping, in bytes.
- * Lowest 5 bits must be zero.
- */
- __resizer_set_inaddr(res,
- res->addr_base + (res->crop_offset & ~0x1f));
- } else {
- /*
- * Set vertical start line and horizontal starting pixel.
- * If the input is from CCDC/PREV, horizontal start field is
- * in bytes (twice number of pixels).
- */
- resizer_set_start(res, res->crop.active.left * 2,
- res->crop.active.top);
- /* Input address and offset must be 0 for preview/ccdc input */
- __resizer_set_inaddr(res, 0);
- resizer_set_input_offset(res, 0);
- }
-
- /* Set the input size */
- resizer_set_input_size(res, res->crop.active.width,
- res->crop.active.height);
-}
-
-static void resizer_configure(struct isp_res_device *res)
-{
- struct v4l2_mbus_framefmt *informat, *outformat;
- struct resizer_luma_yenh luma = {0, 0, 0, 0};
-
- resizer_set_source(res, res->input);
-
- informat = &res->formats[RESZ_PAD_SINK];
- outformat = &res->formats[RESZ_PAD_SOURCE];
-
- /* RESZ_PAD_SINK */
- if (res->input == RESIZER_INPUT_VP)
- resizer_set_input_offset(res, 0);
- else
- resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
-
- /* YUV422 interleaved, default phase, no luma enhancement */
- resizer_set_intype(res, RSZ_YUV422);
- resizer_set_ycpos(res, informat->code);
- resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
- resizer_set_luma(res, &luma);
-
- /* RESZ_PAD_SOURCE */
- resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
- resizer_set_output_size(res, outformat->width, outformat->height);
-
- resizer_set_crop_params(res, informat, outformat);
-}
-
-/* -----------------------------------------------------------------------------
- * Interrupt handling
- */
-
-static void resizer_enable_oneshot(struct isp_res_device *res)
-{
- struct isp_device *isp = to_isp_device(res);
-
- isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
- ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
-}
-
-void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
-{
- /*
- * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
- * condition, the module was paused and now we have a buffer queued
- * on the output again. Restart the pipeline if running in continuous
- * mode.
- */
- if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
- res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
- resizer_enable_oneshot(res);
- isp_video_dmaqueue_flags_clr(&res->video_out);
- }
-}
-
-static void resizer_isr_buffer(struct isp_res_device *res)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
- struct isp_buffer *buffer;
- int restart = 0;
-
- if (res->state == ISP_PIPELINE_STREAM_STOPPED)
- return;
-
- /* Complete the output buffer and, if reading from memory, the input
- * buffer.
- */
- buffer = omap3isp_video_buffer_next(&res->video_out);
- if (buffer != NULL) {
- resizer_set_outaddr(res, buffer->isp_addr);
- restart = 1;
- }
-
- pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
-
- if (res->input == RESIZER_INPUT_MEMORY) {
- buffer = omap3isp_video_buffer_next(&res->video_in);
- if (buffer != NULL)
- resizer_set_inaddr(res, buffer->isp_addr);
- pipe->state |= ISP_PIPELINE_IDLE_INPUT;
- }
-
- if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
- if (isp_pipeline_ready(pipe))
- omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_SINGLESHOT);
- } else {
- /* If an underrun occurs, the video queue operation handler will
- * restart the resizer. Otherwise restart it immediately.
- */
- if (restart)
- resizer_enable_oneshot(res);
- }
-}
-
-/*
- * omap3isp_resizer_isr - ISP resizer interrupt handler
- *
- * Manage the resizer video buffers and configure shadowed and busy-locked
- * registers.
- */
-void omap3isp_resizer_isr(struct isp_res_device *res)
-{
- struct v4l2_mbus_framefmt *informat, *outformat;
-
- if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
- return;
-
- if (res->applycrop) {
- outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- resizer_set_crop_params(res, informat, outformat);
- res->applycrop = 0;
- }
-
- resizer_isr_buffer(res);
-}
-
-/* -----------------------------------------------------------------------------
- * ISP video operations
- */
-
-static int resizer_video_queue(struct isp_video *video,
- struct isp_buffer *buffer)
-{
- struct isp_res_device *res = &video->isp->isp_res;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- resizer_set_inaddr(res, buffer->isp_addr);
-
- /*
- * We now have a buffer queued on the output. Despite what the
- * TRM says, the resizer can't be restarted immediately.
- * Enabling it in one shot mode in the middle of a frame (or at
- * least asynchronously to the frame) results in the output
- * being shifted randomly left/right and up/down, as if the
- * hardware didn't synchronize itself to the beginning of the
- * frame correctly.
- *
- * Restart the resizer on the next sync interrupt if running in
- * continuous mode or when starting the stream.
- */
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- resizer_set_outaddr(res, buffer->isp_addr);
-
- return 0;
-}
-
-static const struct isp_video_operations resizer_video_ops = {
- .queue = resizer_video_queue,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev operations
- */
-
-/*
- * resizer_set_stream - Enable/Disable streaming on resizer subdev
- * @sd: ISP resizer V4L2 subdev
- * @enable: 1 == Enable, 0 == Disable
- *
- * The resizer hardware can't be enabled without a memory buffer to write to.
- * As the s_stream operation is called in response to a STREAMON call without
- * any buffer queued yet, just update the state field and return immediately.
- * The resizer will be enabled in resizer_video_queue().
- */
-static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct isp_video *video_out = &res->video_out;
- struct isp_device *isp = to_isp_device(res);
- struct device *dev = to_device(res);
-
- if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
- if (enable == ISP_PIPELINE_STREAM_STOPPED)
- return 0;
-
- omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
- resizer_configure(res);
- resizer_print_status(res);
- }
-
- switch (enable) {
- case ISP_PIPELINE_STREAM_CONTINUOUS:
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
- if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
- resizer_enable_oneshot(res);
- isp_video_dmaqueue_flags_clr(video_out);
- }
- break;
-
- case ISP_PIPELINE_STREAM_SINGLESHOT:
- if (res->input == RESIZER_INPUT_MEMORY)
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
- omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
-
- resizer_enable_oneshot(res);
- break;
-
- case ISP_PIPELINE_STREAM_STOPPED:
- if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
- &res->stopping))
- dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
- omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
- OMAP3_ISP_SBL_RESIZER_WRITE);
- omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
- isp_video_dmaqueue_flags_clr(video_out);
- break;
- }
-
- res->state = enable;
- return 0;
-}
-
-/*
- * resizer_try_crop - mangles crop parameters.
- */
-static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
- const struct v4l2_mbus_framefmt *source,
- struct v4l2_rect *crop)
-{
- const unsigned int spv = DEFAULT_PHASE;
- const unsigned int sph = DEFAULT_PHASE;
-
- /* Crop rectangle is constrained by the output size so that zoom ratio
- * cannot exceed +/-4.0.
- */
- unsigned int min_width =
- ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
- unsigned int min_height =
- ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
- unsigned int max_width =
- ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
- unsigned int max_height =
- ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
-
- crop->width = clamp_t(u32, crop->width, min_width, max_width);
- crop->height = clamp_t(u32, crop->height, min_height, max_height);
-
- /* Crop can not go beyond of the input rectangle */
- crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
- crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
- sink->width - crop->left);
- crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
- crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
- sink->height - crop->top);
-}
-
-/*
- * resizer_get_selection - Retrieve a selection rectangle on a pad
- * @sd: ISP resizer V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangles are the crop rectangles on the sink pad.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int resizer_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format_source;
- struct v4l2_mbus_framefmt *format_sink;
- struct resizer_ratio ratio;
-
- if (sel->pad != RESZ_PAD_SINK)
- return -EINVAL;
-
- format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
- sel->which);
- format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
- sel->which);
-
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP_BOUNDS:
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = INT_MAX;
- sel->r.height = INT_MAX;
-
- resizer_try_crop(format_sink, format_source, &sel->r);
- resizer_calc_ratios(res, &sel->r, format_source, &ratio);
- break;
-
- case V4L2_SEL_TGT_CROP:
- sel->r = *__resizer_get_crop(res, fh, sel->which);
- resizer_calc_ratios(res, &sel->r, format_source, &ratio);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * resizer_set_selection - Set a selection rectangle on a pad
- * @sd: ISP resizer V4L2 subdevice
- * @fh: V4L2 subdev file handle
- * @sel: Selection rectangle
- *
- * The only supported rectangle is the actual crop rectangle on the sink pad.
- *
- * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
- * was always set.
- *
- * Return 0 on success or a negative error code otherwise.
- */
-static int resizer_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct isp_device *isp = to_isp_device(res);
- struct v4l2_mbus_framefmt *format_sink, *format_source;
- struct resizer_ratio ratio;
-
- if (sel->target != V4L2_SEL_TGT_CROP ||
- sel->pad != RESZ_PAD_SINK)
- return -EINVAL;
-
- format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
- sel->which);
- format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
- sel->which);
-
- dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
- sel->r.left, sel->r.top, sel->r.width, sel->r.height,
- sel->which);
-
- dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
- format_sink->width, format_sink->height,
- format_source->width, format_source->height);
-
- /* Clamp the crop rectangle to the bounds, and then mangle it further to
- * fulfill the TRM equations. Store the clamped but otherwise unmangled
- * rectangle to avoid cropping the input multiple times: when an
- * application sets the output format, the current crop rectangle is
- * mangled during crop rectangle computation, which would lead to a new,
- * smaller input crop rectangle every time the output size is set if we
- * stored the mangled rectangle.
- */
- resizer_try_crop(format_sink, format_source, &sel->r);
- *__resizer_get_crop(res, fh, sel->which) = sel->r;
- resizer_calc_ratios(res, &sel->r, format_source, &ratio);
-
- if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- return 0;
-
- res->ratio = ratio;
- res->crop.active = sel->r;
-
- /*
- * set_selection can be called while streaming is on. In this case the
- * crop values will be set in the next IRQ.
- */
- if (res->state != ISP_PIPELINE_STREAM_STOPPED)
- res->applycrop = 1;
-
- return 0;
-}
-
-/* resizer pixel formats */
-static const unsigned int resizer_formats[] = {
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
-};
-
-static unsigned int resizer_max_in_width(struct isp_res_device *res)
-{
- struct isp_device *isp = to_isp_device(res);
-
- if (res->input == RESIZER_INPUT_MEMORY) {
- return MAX_IN_WIDTH_MEMORY_MODE;
- } else {
- if (isp->revision == ISP_REVISION_1_0)
- return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
- else
- return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
- }
-}
-
-/*
- * resizer_try_format - Handle try format by pad subdev method
- * @res : ISP resizer device
- * @fh : V4L2 subdev file handle
- * @pad : pad num
- * @fmt : pointer to v4l2 format structure
- * @which : wanted subdev format
- */
-static void resizer_try_format(struct isp_res_device *res,
- struct v4l2_subdev_fh *fh, unsigned int pad,
- struct v4l2_mbus_framefmt *fmt,
- enum v4l2_subdev_format_whence which)
-{
- struct v4l2_mbus_framefmt *format;
- struct resizer_ratio ratio;
- struct v4l2_rect crop;
-
- switch (pad) {
- case RESZ_PAD_SINK:
- if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
- fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
- fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
-
- fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
- resizer_max_in_width(res));
- fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
- MAX_IN_HEIGHT);
- break;
-
- case RESZ_PAD_SOURCE:
- format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
- fmt->code = format->code;
-
- crop = *__resizer_get_crop(res, fh, which);
- resizer_calc_ratios(res, &crop, fmt, &ratio);
- break;
- }
-
- fmt->colorspace = V4L2_COLORSPACE_JPEG;
- fmt->field = V4L2_FIELD_NONE;
-}
-
-/*
- * resizer_enum_mbus_code - Handle pixel format enumeration
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @code : pointer to v4l2_subdev_mbus_code_enum structure
- * return -EINVAL or zero on success
- */
-static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- if (code->pad == RESZ_PAD_SINK) {
- if (code->index >= ARRAY_SIZE(resizer_formats))
- return -EINVAL;
-
- code->code = resizer_formats[code->index];
- } else {
- if (code->index != 0)
- return -EINVAL;
-
- format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
- V4L2_SUBDEV_FORMAT_TRY);
- code->code = format->code;
- }
-
- return 0;
-}
-
-static int resizer_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt format;
-
- if (fse->index != 0)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = 1;
- format.height = 1;
- resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->min_width = format.width;
- fse->min_height = format.height;
-
- if (format.code != fse->code)
- return -EINVAL;
-
- format.code = fse->code;
- format.width = -1;
- format.height = -1;
- resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
- fse->max_width = format.width;
- fse->max_height = format.height;
-
- return 0;
-}
-
-/*
- * resizer_get_format - Handle get format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt : pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
-
- format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- fmt->format = *format;
- return 0;
-}
-
-/*
- * resizer_set_format - Handle set format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @fh : V4L2 subdev file handle
- * @fmt : pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
-static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *crop;
-
- format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
- if (format == NULL)
- return -EINVAL;
-
- resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
-
- if (fmt->pad == RESZ_PAD_SINK) {
- /* reset crop rectangle */
- crop = __resizer_get_crop(res, fh, fmt->which);
- crop->left = 0;
- crop->top = 0;
- crop->width = fmt->format.width;
- crop->height = fmt->format.height;
-
- /* Propagate the format from sink to source */
- format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
- fmt->which);
- *format = fmt->format;
- resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
- fmt->which);
- }
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- /* Compute and store the active crop rectangle and resizer
- * ratios. format already points to the source pad active
- * format.
- */
- res->crop.active = res->crop.request;
- resizer_calc_ratios(res, &res->crop.active, format,
- &res->ratio);
- }
-
- return 0;
-}
-
-/*
- * resizer_init_formats - Initialize formats on all pads
- * @sd: ISP resizer V4L2 subdevice
- * @fh: V4L2 subdev file handle
- *
- * Initialize all pad formats with default values. If fh is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
- */
-static int resizer_init_formats(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh)
-{
- struct v4l2_subdev_format format;
-
- memset(&format, 0, sizeof(format));
- format.pad = RESZ_PAD_SINK;
- format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
- format.format.width = 4096;
- format.format.height = 4096;
- resizer_set_format(sd, fh, &format);
-
- return 0;
-}
-
-/* subdev video operations */
-static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
- .s_stream = resizer_set_stream,
-};
-
-/* subdev pad operations */
-static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
- .enum_mbus_code = resizer_enum_mbus_code,
- .enum_frame_size = resizer_enum_frame_size,
- .get_fmt = resizer_get_format,
- .set_fmt = resizer_set_format,
- .get_selection = resizer_get_selection,
- .set_selection = resizer_set_selection,
-};
-
-/* subdev operations */
-static const struct v4l2_subdev_ops resizer_v4l2_ops = {
- .video = &resizer_v4l2_video_ops,
- .pad = &resizer_v4l2_pad_ops,
-};
-
-/* subdev internal operations */
-static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
- .open = resizer_init_formats,
-};
-
-/* -----------------------------------------------------------------------------
- * Media entity operations
- */
-
-/*
- * resizer_link_setup - Setup resizer connections.
- * @entity : Pointer to media entity structure
- * @local : Pointer to local pad array
- * @remote : Pointer to remote pad array
- * @flags : Link flags
- * return -EINVAL or zero on success
- */
-static int resizer_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
-
- switch (local->index | media_entity_type(remote->entity)) {
- case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
- /* read from memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (res->input == RESIZER_INPUT_VP)
- return -EBUSY;
- res->input = RESIZER_INPUT_MEMORY;
- } else {
- if (res->input == RESIZER_INPUT_MEMORY)
- res->input = RESIZER_INPUT_NONE;
- }
- break;
-
- case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
- /* read from ccdc or previewer */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (res->input == RESIZER_INPUT_MEMORY)
- return -EBUSY;
- res->input = RESIZER_INPUT_VP;
- } else {
- if (res->input == RESIZER_INPUT_VP)
- res->input = RESIZER_INPUT_NONE;
- }
- break;
-
- case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
- /* resizer always write to memory */
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* media operations */
-static const struct media_entity_operations resizer_media_ops = {
- .link_setup = resizer_link_setup,
- .link_validate = v4l2_subdev_link_validate,
-};
-
-void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
-{
- v4l2_device_unregister_subdev(&res->subdev);
- omap3isp_video_unregister(&res->video_in);
- omap3isp_video_unregister(&res->video_out);
-}
-
-int omap3isp_resizer_register_entities(struct isp_res_device *res,
- struct v4l2_device *vdev)
-{
- int ret;
-
- /* Register the subdev and video nodes. */
- ret = v4l2_device_register_subdev(vdev, &res->subdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&res->video_in, vdev);
- if (ret < 0)
- goto error;
-
- ret = omap3isp_video_register(&res->video_out, vdev);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- omap3isp_resizer_unregister_entities(res);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * ISP resizer initialization and cleanup
- */
-
-/*
- * resizer_init_entities - Initialize resizer subdev and media entity.
- * @res : Pointer to resizer device structure
- * return -ENOMEM or zero on success
- */
-static int resizer_init_entities(struct isp_res_device *res)
-{
- struct v4l2_subdev *sd = &res->subdev;
- struct media_pad *pads = res->pads;
- struct media_entity *me = &sd->entity;
- int ret;
-
- res->input = RESIZER_INPUT_NONE;
-
- v4l2_subdev_init(sd, &resizer_v4l2_ops);
- sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
- sd->grp_id = 1 << 16; /* group ID for isp subdevs */
- v4l2_set_subdevdata(sd, res);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
- pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-
- me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
- if (ret < 0)
- return ret;
-
- resizer_init_formats(sd, NULL);
-
- res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- res->video_in.ops = &resizer_video_ops;
- res->video_in.isp = to_isp_device(res);
- res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
- res->video_in.bpl_alignment = 32;
- res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- res->video_out.ops = &resizer_video_ops;
- res->video_out.isp = to_isp_device(res);
- res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
- res->video_out.bpl_alignment = 32;
-
- ret = omap3isp_video_init(&res->video_in, "resizer");
- if (ret < 0)
- goto error_video_in;
-
- ret = omap3isp_video_init(&res->video_out, "resizer");
- if (ret < 0)
- goto error_video_out;
-
- /* Connect the video nodes to the resizer subdev. */
- ret = media_entity_create_link(&res->video_in.video.entity, 0,
- &res->subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
- &res->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
- return 0;
-
-error_link:
- omap3isp_video_cleanup(&res->video_out);
-error_video_out:
- omap3isp_video_cleanup(&res->video_in);
-error_video_in:
- media_entity_cleanup(&res->subdev.entity);
- return ret;
-}
-
-/*
- * isp_resizer_init - Resizer initialization.
- * @isp : Pointer to ISP device
- * return -ENOMEM or zero on success
- */
-int omap3isp_resizer_init(struct isp_device *isp)
-{
- struct isp_res_device *res = &isp->isp_res;
-
- init_waitqueue_head(&res->wait);
- atomic_set(&res->stopping, 0);
- return resizer_init_entities(res);
-}
-
-void omap3isp_resizer_cleanup(struct isp_device *isp)
-{
- struct isp_res_device *res = &isp->isp_res;
-
- omap3isp_video_cleanup(&res->video_in);
- omap3isp_video_cleanup(&res->video_out);
- media_entity_cleanup(&res->subdev.entity);
-}
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
deleted file mode 100644
index b37379d39cdd..000000000000
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ /dev/null
@@ -1,1392 +0,0 @@
-/*
- * ispvideo.c
- *
- * TI OMAP3 ISP - Generic video node
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 <asm/cacheflush.h>
-#include <linux/clk.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-#include <plat/omap-pm.h>
-
-#include "ispvideo.h"
-#include "isp.h"
-
-
-/* -----------------------------------------------------------------------------
- * Helper functions
- */
-
-/*
- * NOTE: When adding new media bus codes, always remember to add
- * corresponding in-memory formats to the table below!!!
- */
-static struct isp_format_info formats[] = {
- { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_GREY, 8, },
- { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_Y10, 10, },
- { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_PIX_FMT_Y12, 12, },
- { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR8, 8, },
- { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG8, 8, },
- { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG8, 8, },
- { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB8, 8, },
- { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10, 0,
- V4L2_PIX_FMT_SBGGR10DPCM8, 8, },
- { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGBRG10_1X10, 0,
- V4L2_PIX_FMT_SGBRG10DPCM8, 8, },
- { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10, 0,
- V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
- { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
- V4L2_MBUS_FMT_SRGGB10_1X10, 0,
- V4L2_PIX_FMT_SRGGB10DPCM8, 8, },
- { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR10, 10, },
- { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG10, 10, },
- { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG10, 10, },
- { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB10, 10, },
- { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_PIX_FMT_SBGGR12, 12, },
- { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_PIX_FMT_SGBRG12, 12, },
- { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_PIX_FMT_SGRBG12, 12, },
- { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_PIX_FMT_SRGGB12, 12, },
- { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_UYVY8_1X16, 0,
- V4L2_PIX_FMT_UYVY, 16, },
- { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16, 0,
- V4L2_PIX_FMT_YUYV, 16, },
-};
-
-const struct isp_format_info *
-omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- if (formats[i].code == code)
- return &formats[i];
- }
-
- return NULL;
-}
-
-/*
- * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
- * @video: ISP video instance
- * @mbus: v4l2_mbus_framefmt format (input)
- * @pix: v4l2_pix_format format (output)
- *
- * Fill the output pix structure with information from the input mbus format.
- * The bytesperline and sizeimage fields are computed from the requested bytes
- * per line value in the pix format and information from the video instance.
- *
- * Return the number of padding bytes at end of line.
- */
-static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
- const struct v4l2_mbus_framefmt *mbus,
- struct v4l2_pix_format *pix)
-{
- unsigned int bpl = pix->bytesperline;
- unsigned int min_bpl;
- unsigned int i;
-
- memset(pix, 0, sizeof(*pix));
- pix->width = mbus->width;
- pix->height = mbus->height;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- if (formats[i].code == mbus->code)
- break;
- }
-
- if (WARN_ON(i == ARRAY_SIZE(formats)))
- return 0;
-
- min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
-
- /* Clamp the requested bytes per line value. If the maximum bytes per
- * line value is zero, the module doesn't support user configurable line
- * sizes. Override the requested value with the minimum in that case.
- */
- if (video->bpl_max)
- bpl = clamp(bpl, min_bpl, video->bpl_max);
- else
- bpl = min_bpl;
-
- if (!video->bpl_zero_padding || bpl != min_bpl)
- bpl = ALIGN(bpl, video->bpl_alignment);
-
- pix->pixelformat = formats[i].pixelformat;
- pix->bytesperline = bpl;
- pix->sizeimage = pix->bytesperline * pix->height;
- pix->colorspace = mbus->colorspace;
- pix->field = mbus->field;
-
- return bpl - min_bpl;
-}
-
-static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
- struct v4l2_mbus_framefmt *mbus)
-{
- unsigned int i;
-
- memset(mbus, 0, sizeof(*mbus));
- mbus->width = pix->width;
- mbus->height = pix->height;
-
- /* 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;
- }
-
- mbus->code = formats[i].code;
- mbus->colorspace = pix->colorspace;
- mbus->field = pix->field;
-}
-
-static struct v4l2_subdev *
-isp_video_remote_subdev(struct isp_video *video, u32 *pad)
-{
- struct media_pad *remote;
-
- remote = media_entity_remote_source(&video->pad);
-
- if (remote == NULL ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- return NULL;
-
- if (pad)
- *pad = remote->index;
-
- return media_entity_to_v4l2_subdev(remote->entity);
-}
-
-/* Return a pointer to the ISP video instance at the far end of the pipeline. */
-static int isp_video_get_graph_data(struct isp_video *video,
- struct isp_pipeline *pipe)
-{
- struct media_entity_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->parent;
- struct isp_video *far_end = NULL;
-
- mutex_lock(&mdev->graph_mutex);
- media_entity_graph_walk_start(&graph, entity);
-
- while ((entity = media_entity_graph_walk_next(&graph))) {
- struct isp_video *__video;
-
- pipe->entities |= 1 << entity->id;
-
- if (far_end != NULL)
- continue;
-
- if (entity == &video->video.entity)
- continue;
-
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
- continue;
-
- __video = to_isp_video(media_entity_to_video_device(entity));
- if (__video->type != video->type)
- far_end = __video;
- }
-
- mutex_unlock(&mdev->graph_mutex);
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- pipe->input = far_end;
- pipe->output = video;
- } else {
- if (far_end == NULL)
- return -EPIPE;
-
- pipe->input = video;
- pipe->output = far_end;
- }
-
- return 0;
-}
-
-/*
- * Validate a pipeline by checking both ends of all links for format
- * discrepancies.
- *
- * Compute the minimum time per frame value as the maximum of time per frame
- * limits reported by every block in the pipeline.
- *
- * Return 0 if all formats match, or -EPIPE if at least one link is found with
- * different formats on its two ends or if the pipeline doesn't start with a
- * video source (either a subdev with no input pad, or a non-subdev entity).
- */
-static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
-{
- struct isp_device *isp = pipe->output->isp;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
-
- subdev = isp_video_remote_subdev(pipe->output, NULL);
- if (subdev == NULL)
- return -EPIPE;
-
- while (1) {
- /* Retrieve the sink format */
- pad = &subdev->entity.pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- /* Update the maximum frame rate */
- if (subdev == &isp->isp_res.subdev)
- omap3isp_resizer_max_rate(&isp->isp_res,
- &pipe->max_rate);
-
- /* Retrieve the source format. Return an error if no source
- * entity can be found, and stop checking the pipeline if the
- * source entity isn't a subdev.
- */
- pad = media_entity_remote_source(pad);
- if (pad == NULL)
- return -EPIPE;
-
- if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
-
- subdev = media_entity_to_v4l2_subdev(pad->entity);
- }
-
- return 0;
-}
-
-static int
-__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
-{
- struct v4l2_subdev_format fmt;
- struct v4l2_subdev *subdev;
- u32 pad;
- int ret;
-
- subdev = isp_video_remote_subdev(video, &pad);
- if (subdev == NULL)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
-
- fmt.pad = pad;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
- if (ret == -ENOIOCTLCMD)
- ret = -EINVAL;
-
- mutex_unlock(&video->mutex);
-
- if (ret)
- return ret;
-
- format->type = video->type;
- return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
-}
-
-static int
-isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
-{
- struct v4l2_format format;
- int ret;
-
- memcpy(&format, &vfh->format, sizeof(format));
- ret = __isp_video_get_format(video, &format);
- if (ret < 0)
- return ret;
-
- if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
- vfh->format.fmt.pix.height != format.fmt.pix.height ||
- vfh->format.fmt.pix.width != format.fmt.pix.width ||
- vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
- vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
- return -EINVAL;
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * IOMMU management
- */
-
-#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
-
-/*
- * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @sglist: Pointer to source Scatter gather list to allocate.
- * @sglen: Number of elements of the scatter-gatter list.
- *
- * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
- * we ran out of memory.
- */
-static dma_addr_t
-ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
-{
- struct sg_table *sgt;
- u32 da;
-
- sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
- if (sgt == NULL)
- return -ENOMEM;
-
- sgt->sgl = (struct scatterlist *)sglist;
- sgt->nents = sglen;
- sgt->orig_nents = sglen;
-
- da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG);
- if (IS_ERR_VALUE(da))
- kfree(sgt);
-
- return da;
-}
-
-/*
- * ispmmu_vunmap - Unmap a device address from the ISP MMU
- * @dev: Device pointer specific to the OMAP3 ISP.
- * @da: Device address generated from a ispmmu_vmap call.
- */
-static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
-{
- struct sg_table *sgt;
-
- sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da);
- kfree(sgt);
-}
-
-/* -----------------------------------------------------------------------------
- * Video queue operations
- */
-
-static void isp_video_queue_prepare(struct isp_video_queue *queue,
- unsigned int *nbuffers, unsigned int *size)
-{
- struct isp_video_fh *vfh =
- container_of(queue, struct isp_video_fh, queue);
- struct isp_video *video = vfh->video;
-
- *size = vfh->format.fmt.pix.sizeimage;
- if (*size == 0)
- return;
-
- *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
-}
-
-static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
-{
- struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
- struct isp_buffer *buffer = to_isp_buffer(buf);
- struct isp_video *video = vfh->video;
-
- if (buffer->isp_addr) {
- ispmmu_vunmap(video->isp, buffer->isp_addr);
- buffer->isp_addr = 0;
- }
-}
-
-static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
-{
- struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
- struct isp_buffer *buffer = to_isp_buffer(buf);
- struct isp_video *video = vfh->video;
- unsigned long addr;
-
- addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
- if (IS_ERR_VALUE(addr))
- return -EIO;
-
- if (!IS_ALIGNED(addr, 32)) {
- dev_dbg(video->isp->dev, "Buffer address must be "
- "aligned to 32 bytes boundary.\n");
- ispmmu_vunmap(video->isp, buffer->isp_addr);
- return -EINVAL;
- }
-
- buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
- buffer->isp_addr = addr;
- return 0;
-}
-
-/*
- * isp_video_buffer_queue - Add buffer to streaming queue
- * @buf: Video buffer
- *
- * In memory-to-memory mode, start streaming on the pipeline if buffers are
- * queued on both the input and the output, if the pipeline isn't already busy.
- * If the pipeline is busy, it will be restarted in the output module interrupt
- * handler.
- */
-static void isp_video_buffer_queue(struct isp_video_buffer *buf)
-{
- struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
- struct isp_buffer *buffer = to_isp_buffer(buf);
- struct isp_video *video = vfh->video;
- struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
- enum isp_pipeline_state state;
- unsigned long flags;
- unsigned int empty;
- unsigned int start;
-
- empty = list_empty(&video->dmaqueue);
- list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
-
- if (empty) {
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- state = ISP_PIPELINE_QUEUE_OUTPUT;
- else
- state = ISP_PIPELINE_QUEUE_INPUT;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state |= state;
- video->ops->queue(video, buffer);
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
-
- start = isp_pipeline_ready(pipe);
- if (start)
- pipe->state |= ISP_PIPELINE_STREAM;
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- if (start)
- omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_SINGLESHOT);
- }
-}
-
-static const struct isp_video_queue_operations isp_video_queue_ops = {
- .queue_prepare = &isp_video_queue_prepare,
- .buffer_prepare = &isp_video_buffer_prepare,
- .buffer_queue = &isp_video_buffer_queue,
- .buffer_cleanup = &isp_video_buffer_cleanup,
-};
-
-/*
- * omap3isp_video_buffer_next - Complete the current buffer and return the next
- * @video: ISP video object
- *
- * Remove the current video buffer from the DMA queue and fill its timestamp,
- * field count and state fields before waking up its completion handler.
- *
- * 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)
-{
- struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
- struct isp_video_queue *queue = video->queue;
- enum isp_pipeline_state state;
- struct isp_video_buffer *buf;
- unsigned long flags;
- struct timespec ts;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- if (WARN_ON(list_empty(&video->dmaqueue))) {
- spin_unlock_irqrestore(&queue->irqlock, flags);
- return NULL;
- }
-
- buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
- irqlist);
- list_del(&buf->irqlist);
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
- ktime_get_ts(&ts);
- buf->vbuf.timestamp.tv_sec = ts.tv_sec;
- buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
-
- /* Do frame number propagation only if this is the output video node.
- * Frame number either comes from the CSI receivers or it gets
- * incremented here if H3A is not active.
- * Note: There is no guarantee that the output buffer will finish
- * first, so the input number might lag behind by 1 in some cases.
- */
- if (video == pipe->output && !pipe->do_propagation)
- buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
- else
- buf->vbuf.sequence = atomic_read(&pipe->frame_number);
-
- /* 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);
-
- if (list_empty(&video->dmaqueue)) {
- if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- state = ISP_PIPELINE_QUEUE_OUTPUT
- | ISP_PIPELINE_STREAM;
- else
- state = ISP_PIPELINE_QUEUE_INPUT
- | ISP_PIPELINE_STREAM;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~state;
- if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
- spin_unlock_irqrestore(&pipe->lock, flags);
- return NULL;
- }
-
- if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~ISP_PIPELINE_STREAM;
- spin_unlock_irqrestore(&pipe->lock, flags);
- }
-
- buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
- irqlist);
- buf->state = ISP_BUF_STATE_ACTIVE;
- return to_isp_buffer(buf);
-}
-
-/*
- * omap3isp_video_resume - Perform resume operation on the buffers
- * @video: ISP video object
- * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise
- *
- * This function is intended to be used on suspend/resume scenario. It
- * requests video queue layer to discard buffers marked as DONE if it's in
- * continuous mode and requests ISP modules to queue again the ACTIVE buffer
- * if there's any.
- */
-void omap3isp_video_resume(struct isp_video *video, int continuous)
-{
- struct isp_buffer *buf = NULL;
-
- if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- omap3isp_video_queue_discard_done(video->queue);
-
- if (!list_empty(&video->dmaqueue)) {
- buf = list_first_entry(&video->dmaqueue,
- struct isp_buffer, buffer.irqlist);
- video->ops->queue(video, buf);
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
- } else {
- if (continuous)
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
- }
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 ioctls
- */
-
-static int
-isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
-{
- struct isp_video *video = video_drvdata(file);
-
- strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
- strlcpy(cap->card, video->video.name, sizeof(cap->card));
- strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- else
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static int
-isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
-
- if (format->type != video->type)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
- *format = vfh->format;
- mutex_unlock(&video->mutex);
-
- return 0;
-}
-
-static int
-isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
- struct v4l2_mbus_framefmt fmt;
-
- if (format->type != video->type)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
-
- /* Fill the bytesperline and sizeimage fields by converting to media bus
- * format and back to pixel format.
- */
- isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
- isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
-
- vfh->format = *format;
-
- mutex_unlock(&video->mutex);
- return 0;
-}
-
-static int
-isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev_format fmt;
- struct v4l2_subdev *subdev;
- u32 pad;
- int ret;
-
- if (format->type != video->type)
- return -EINVAL;
-
- subdev = isp_video_remote_subdev(video, &pad);
- if (subdev == NULL)
- return -EINVAL;
-
- isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
-
- fmt.pad = pad;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
- if (ret)
- return ret == -ENOIOCTLCMD ? -EINVAL : ret;
-
- isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
- return 0;
-}
-
-static int
-isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev *subdev;
- int ret;
-
- subdev = isp_video_remote_subdev(video, NULL);
- if (subdev == NULL)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
- ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
- mutex_unlock(&video->mutex);
-
- return ret == -ENOIOCTLCMD ? -EINVAL : ret;
-}
-
-static int
-isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev_format format;
- struct v4l2_subdev *subdev;
- u32 pad;
- int ret;
-
- subdev = isp_video_remote_subdev(video, &pad);
- if (subdev == NULL)
- return -EINVAL;
-
- /* Try the get crop operation first and fallback to get format if not
- * implemented.
- */
- ret = v4l2_subdev_call(subdev, video, g_crop, crop);
- if (ret != -ENOIOCTLCMD)
- return ret;
-
- format.pad = pad;
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
- if (ret < 0)
- return ret == -ENOIOCTLCMD ? -EINVAL : ret;
-
- crop->c.left = 0;
- crop->c.top = 0;
- crop->c.width = format.format.width;
- crop->c.height = format.format.height;
-
- return 0;
-}
-
-static int
-isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_subdev *subdev;
- int ret;
-
- subdev = isp_video_remote_subdev(video, NULL);
- if (subdev == NULL)
- return -EINVAL;
-
- mutex_lock(&video->mutex);
- ret = v4l2_subdev_call(subdev, video, s_crop, crop);
- mutex_unlock(&video->mutex);
-
- return ret == -ENOIOCTLCMD ? -EINVAL : ret;
-}
-
-static int
-isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
-
- if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
- video->type != a->type)
- return -EINVAL;
-
- memset(a, 0, sizeof(*a));
- a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
- a->parm.output.timeperframe = vfh->timeperframe;
-
- return 0;
-}
-
-static int
-isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
-
- if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
- video->type != a->type)
- return -EINVAL;
-
- if (a->parm.output.timeperframe.denominator == 0)
- a->parm.output.timeperframe.denominator = 1;
-
- vfh->timeperframe = a->parm.output.timeperframe;
-
- return 0;
-}
-
-static int
-isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
-
- return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
-}
-
-static int
-isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
-
- return omap3isp_video_queue_querybuf(&vfh->queue, b);
-}
-
-static int
-isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
-
- return omap3isp_video_queue_qbuf(&vfh->queue, b);
-}
-
-static int
-isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
-
- return omap3isp_video_queue_dqbuf(&vfh->queue, b,
- file->f_flags & O_NONBLOCK);
-}
-
-static int isp_video_check_external_subdevs(struct isp_video *video,
- struct isp_pipeline *pipe)
-{
- struct isp_device *isp = video->isp;
- struct media_entity *ents[] = {
- &isp->isp_csi2a.subdev.entity,
- &isp->isp_csi2c.subdev.entity,
- &isp->isp_ccp2.subdev.entity,
- &isp->isp_ccdc.subdev.entity
- };
- struct media_pad *source_pad;
- struct media_entity *source = NULL;
- struct media_entity *sink;
- struct v4l2_subdev_format fmt;
- struct v4l2_ext_controls ctrls;
- struct v4l2_ext_control ctrl;
- unsigned int i;
- int ret = 0;
-
- for (i = 0; i < ARRAY_SIZE(ents); i++) {
- /* Is the entity part of the pipeline? */
- if (!(pipe->entities & (1 << ents[i]->id)))
- continue;
-
- /* ISP entities have always sink pad == 0. Find source. */
- source_pad = media_entity_remote_source(&ents[i]->pads[0]);
- if (source_pad == NULL)
- continue;
-
- source = source_pad->entity;
- sink = ents[i];
- break;
- }
-
- if (!source) {
- dev_warn(isp->dev, "can't find source, failing now\n");
- return ret;
- }
-
- if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
- return 0;
-
- pipe->external = media_entity_to_v4l2_subdev(source);
-
- fmt.pad = source_pad->index;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
- pad, get_fmt, NULL, &fmt);
- if (unlikely(ret < 0)) {
- dev_warn(isp->dev, "get_fmt returned null!\n");
- return ret;
- }
-
- pipe->external_bpp = omap3isp_video_format_info(fmt.format.code)->bpp;
-
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&ctrl, 0, sizeof(ctrl));
-
- ctrl.id = V4L2_CID_PIXEL_RATE;
-
- ctrls.count = 1;
- ctrls.controls = &ctrl;
-
- ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
- if (ret < 0) {
- dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
- pipe->external->name);
- return ret;
- }
-
- pipe->external_rate = ctrl.value64;
-
- if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
- unsigned int rate = UINT_MAX;
- /*
- * Check that maximum allowed CCDC pixel rate isn't
- * exceeded by the pixel rate.
- */
- omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
- if (pipe->external_rate > rate)
- return -ENOSPC;
- }
-
- return 0;
-}
-
-/*
- * Stream management
- *
- * Every ISP pipeline has a single input and a single output. The input can be
- * either a sensor or a video node. The output is always a video node.
- *
- * As every pipeline has an output video node, the ISP video objects at the
- * pipeline output stores the pipeline state. It tracks the streaming state of
- * both the input and output, as well as the availability of buffers.
- *
- * In sensor-to-memory mode, frames are always available at the pipeline input.
- * Starting the sensor usually requires I2C transfers and must be done in
- * interruptible context. The pipeline is started and stopped synchronously
- * to the stream on/off commands. All modules in the pipeline will get their
- * subdev set stream handler called. The module at the end of the pipeline must
- * delay starting the hardware until buffers are available at its output.
- *
- * In memory-to-memory mode, starting/stopping the stream requires
- * synchronization between the input and output. ISP modules can't be stopped
- * in the middle of a frame, and at least some of the modules seem to become
- * busy as soon as they're started, even if they don't receive a frame start
- * event. For that reason frames need to be processed in single-shot mode. The
- * driver needs to wait until a frame is completely processed and written to
- * memory before restarting the pipeline for the next frame. Pipelined
- * processing might be possible but requires more testing.
- *
- * Stream start must be delayed until buffers are available at both the input
- * and output. The pipeline must be started in the videobuf queue callback with
- * the buffers queue spinlock held. The modules subdev set stream operation must
- * not sleep.
- */
-static int
-isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
- enum isp_pipeline_state state;
- struct isp_pipeline *pipe;
- unsigned long flags;
- int ret;
-
- if (type != video->type)
- return -EINVAL;
-
- mutex_lock(&video->stream_lock);
-
- if (video->streaming) {
- mutex_unlock(&video->stream_lock);
- return -EBUSY;
- }
-
- /* Start streaming on the pipeline. No link touching an entity in the
- * pipeline can be activated or deactivated once streaming is started.
- */
- pipe = video->video.entity.pipe
- ? to_isp_pipeline(&video->video.entity) : &video->pipe;
-
- pipe->entities = 0;
-
- if (video->isp->pdata->set_constraints)
- video->isp->pdata->set_constraints(video->isp, true);
- pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
- pipe->max_rate = pipe->l3_ick;
-
- ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
- if (ret < 0)
- goto err_pipeline_start;
-
- /* Verify that the currently configured format matches the output of
- * the connected subdev.
- */
- ret = isp_video_check_format(video, vfh);
- if (ret < 0)
- goto err_check_format;
-
- video->bpl_padding = ret;
- video->bpl_value = vfh->format.fmt.pix.bytesperline;
-
- ret = isp_video_get_graph_data(video, pipe);
- if (ret < 0)
- goto err_check_format;
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
- else
- state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
-
- ret = isp_video_check_external_subdevs(video, pipe);
- if (ret < 0)
- goto err_check_format;
-
- /* Validate the pipeline and update its state. */
- ret = isp_video_validate_pipeline(pipe);
- if (ret < 0)
- goto err_check_format;
-
- pipe->error = false;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~ISP_PIPELINE_STREAM;
- pipe->state |= state;
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- /* Set the maximum time per frame as the value requested by userspace.
- * This is a soft limit that can be overridden if the hardware doesn't
- * support the request limit.
- */
- if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- pipe->max_timeperframe = vfh->timeperframe;
-
- video->queue = &vfh->queue;
- INIT_LIST_HEAD(&video->dmaqueue);
- atomic_set(&pipe->frame_number, -1);
-
- ret = omap3isp_video_queue_streamon(&vfh->queue);
- if (ret < 0)
- goto err_check_format;
-
- /* In sensor-to-memory mode, the stream can be started synchronously
- * to the stream on command. In memory-to-memory mode, it will be
- * started when buffers are queued on both the input and output.
- */
- if (pipe->input == NULL) {
- ret = omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_CONTINUOUS);
- if (ret < 0)
- goto err_set_stream;
- spin_lock_irqsave(&video->queue->irqlock, flags);
- if (list_empty(&video->dmaqueue))
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
- spin_unlock_irqrestore(&video->queue->irqlock, flags);
- }
-
- video->streaming = 1;
-
- mutex_unlock(&video->stream_lock);
- return 0;
-
-err_set_stream:
- omap3isp_video_queue_streamoff(&vfh->queue);
-err_check_format:
- media_entity_pipeline_stop(&video->video.entity);
-err_pipeline_start:
- if (video->isp->pdata->set_constraints)
- video->isp->pdata->set_constraints(video->isp, false);
- /* The DMA queue must be emptied here, otherwise CCDC interrupts that
- * will get triggered the next time the CCDC is powered up will try to
- * access buffers that might have been freed but still present in the
- * DMA queue. This can easily get triggered if the above
- * omap3isp_pipeline_set_stream() call fails on a system with a
- * free-running sensor.
- */
- INIT_LIST_HEAD(&video->dmaqueue);
- video->queue = NULL;
-
- mutex_unlock(&video->stream_lock);
- return ret;
-}
-
-static int
-isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(fh);
- struct isp_video *video = video_drvdata(file);
- struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
- enum isp_pipeline_state state;
- unsigned int streaming;
- unsigned long flags;
-
- if (type != video->type)
- return -EINVAL;
-
- mutex_lock(&video->stream_lock);
-
- /* Make sure we're not streaming yet. */
- mutex_lock(&vfh->queue.lock);
- streaming = vfh->queue.streaming;
- mutex_unlock(&vfh->queue.lock);
-
- if (!streaming)
- goto done;
-
- /* Update the pipeline state. */
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- state = ISP_PIPELINE_STREAM_OUTPUT
- | ISP_PIPELINE_QUEUE_OUTPUT;
- else
- state = ISP_PIPELINE_STREAM_INPUT
- | ISP_PIPELINE_QUEUE_INPUT;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~state;
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- /* Stop the stream. */
- omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
- omap3isp_video_queue_streamoff(&vfh->queue);
- video->queue = NULL;
- video->streaming = 0;
-
- if (video->isp->pdata->set_constraints)
- video->isp->pdata->set_constraints(video->isp, false);
- media_entity_pipeline_stop(&video->video.entity);
-
-done:
- mutex_unlock(&video->stream_lock);
- return 0;
-}
-
-static int
-isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
-{
- if (input->index > 0)
- return -EINVAL;
-
- strlcpy(input->name, "camera", sizeof(input->name));
- input->type = V4L2_INPUT_TYPE_CAMERA;
-
- return 0;
-}
-
-static int
-isp_video_g_input(struct file *file, void *fh, unsigned int *input)
-{
- *input = 0;
-
- return 0;
-}
-
-static int
-isp_video_s_input(struct file *file, void *fh, unsigned int input)
-{
- return input == 0 ? 0 : -EINVAL;
-}
-
-static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
- .vidioc_querycap = isp_video_querycap,
- .vidioc_g_fmt_vid_cap = isp_video_get_format,
- .vidioc_s_fmt_vid_cap = isp_video_set_format,
- .vidioc_try_fmt_vid_cap = isp_video_try_format,
- .vidioc_g_fmt_vid_out = isp_video_get_format,
- .vidioc_s_fmt_vid_out = isp_video_set_format,
- .vidioc_try_fmt_vid_out = isp_video_try_format,
- .vidioc_cropcap = isp_video_cropcap,
- .vidioc_g_crop = isp_video_get_crop,
- .vidioc_s_crop = isp_video_set_crop,
- .vidioc_g_parm = isp_video_get_param,
- .vidioc_s_parm = isp_video_set_param,
- .vidioc_reqbufs = isp_video_reqbufs,
- .vidioc_querybuf = isp_video_querybuf,
- .vidioc_qbuf = isp_video_qbuf,
- .vidioc_dqbuf = isp_video_dqbuf,
- .vidioc_streamon = isp_video_streamon,
- .vidioc_streamoff = isp_video_streamoff,
- .vidioc_enum_input = isp_video_enum_input,
- .vidioc_g_input = isp_video_g_input,
- .vidioc_s_input = isp_video_s_input,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 file operations
- */
-
-static int isp_video_open(struct file *file)
-{
- struct isp_video *video = video_drvdata(file);
- struct isp_video_fh *handle;
- int ret = 0;
-
- handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (handle == NULL)
- return -ENOMEM;
-
- v4l2_fh_init(&handle->vfh, &video->video);
- v4l2_fh_add(&handle->vfh);
-
- /* If this is the first user, initialise the pipeline. */
- if (omap3isp_get(video->isp) == NULL) {
- ret = -EBUSY;
- goto done;
- }
-
- ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
- if (ret < 0) {
- omap3isp_put(video->isp);
- goto done;
- }
-
- omap3isp_video_queue_init(&handle->queue, video->type,
- &isp_video_queue_ops, video->isp->dev,
- sizeof(struct isp_buffer));
-
- memset(&handle->format, 0, sizeof(handle->format));
- handle->format.type = video->type;
- handle->timeperframe.denominator = 1;
-
- handle->video = video;
- file->private_data = &handle->vfh;
-
-done:
- if (ret < 0) {
- v4l2_fh_del(&handle->vfh);
- kfree(handle);
- }
-
- return ret;
-}
-
-static int isp_video_release(struct file *file)
-{
- struct isp_video *video = video_drvdata(file);
- struct v4l2_fh *vfh = file->private_data;
- struct isp_video_fh *handle = to_isp_video_fh(vfh);
-
- /* Disable streaming and free the buffers queue resources. */
- isp_video_streamoff(file, vfh, video->type);
-
- mutex_lock(&handle->queue.lock);
- omap3isp_video_queue_cleanup(&handle->queue);
- mutex_unlock(&handle->queue.lock);
-
- omap3isp_pipeline_pm_use(&video->video.entity, 0);
-
- /* Release the file handle. */
- v4l2_fh_del(vfh);
- kfree(handle);
- file->private_data = NULL;
-
- omap3isp_put(video->isp);
-
- return 0;
-}
-
-static unsigned int isp_video_poll(struct file *file, poll_table *wait)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
- struct isp_video_queue *queue = &vfh->queue;
-
- return omap3isp_video_queue_poll(queue, file, wait);
-}
-
-static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
-
- return omap3isp_video_queue_mmap(&vfh->queue, vma);
-}
-
-static struct v4l2_file_operations isp_video_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
- .open = isp_video_open,
- .release = isp_video_release,
- .poll = isp_video_poll,
- .mmap = isp_video_mmap,
-};
-
-/* -----------------------------------------------------------------------------
- * ISP video core
- */
-
-static const struct isp_video_operations isp_video_dummy_ops = {
-};
-
-int omap3isp_video_init(struct isp_video *video, const char *name)
-{
- const char *direction;
- int ret;
-
- switch (video->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- direction = "output";
- video->pad.flags = MEDIA_PAD_FL_SINK;
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- direction = "input";
- video->pad.flags = MEDIA_PAD_FL_SOURCE;
- break;
-
- default:
- return -EINVAL;
- }
-
- ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
- if (ret < 0)
- return ret;
-
- mutex_init(&video->mutex);
- atomic_set(&video->active, 0);
-
- spin_lock_init(&video->pipe.lock);
- mutex_init(&video->stream_lock);
-
- /* Initialize the video device. */
- if (video->ops == NULL)
- video->ops = &isp_video_dummy_ops;
-
- video->video.fops = &isp_video_fops;
- snprintf(video->video.name, sizeof(video->video.name),
- "OMAP3 ISP %s %s", name, direction);
- video->video.vfl_type = VFL_TYPE_GRABBER;
- video->video.release = video_device_release_empty;
- video->video.ioctl_ops = &isp_video_ioctl_ops;
- video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
-
- video_set_drvdata(&video->video, video);
-
- return 0;
-}
-
-void omap3isp_video_cleanup(struct isp_video *video)
-{
- media_entity_cleanup(&video->video.entity);
- mutex_destroy(&video->stream_lock);
- mutex_destroy(&video->mutex);
-}
-
-int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
-{
- int ret;
-
- video->video.v4l2_dev = vdev;
-
- ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
- if (ret < 0)
- printk(KERN_ERR "%s: could not register video device (%d)\n",
- __func__, ret);
-
- return ret;
-}
-
-void omap3isp_video_unregister(struct isp_video *video)
-{
- if (video_is_registered(&video->video))
- video_unregister_device(&video->video);
-}
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
deleted file mode 100644
index 5acc909500ec..000000000000
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * ispvideo.h
- *
- * TI OMAP3 ISP - Generic video node
- *
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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 OMAP3_ISP_VIDEO_H
-#define OMAP3_ISP_VIDEO_H
-
-#include <linux/v4l2-mediabus.h>
-#include <media/media-entity.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-fh.h>
-
-#include "ispqueue.h"
-
-#define ISP_VIDEO_DRIVER_NAME "ispvideo"
-#define ISP_VIDEO_DRIVER_VERSION "0.0.2"
-
-struct isp_device;
-struct isp_video;
-struct v4l2_mbus_framefmt;
-struct v4l2_pix_format;
-
-/*
- * struct isp_format_info - ISP media bus format information
- * @code: V4L2 media bus format code
- * @truncated: V4L2 media bus format code for the same format truncated to 10
- * bits. Identical to @code if the format is 10 bits wide or less.
- * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
- * format. Identical to @code if the format is not DPCM compressed.
- * @flavor: V4L2 media bus format code for the same pixel layout but
- * shifted to be 8 bits per pixel. =0 if format is not shiftable.
- * @pixelformat: V4L2 pixel format FCC identifier
- * @bpp: Bits per pixel
- */
-struct isp_format_info {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_mbus_pixelcode truncated;
- enum v4l2_mbus_pixelcode uncompressed;
- enum v4l2_mbus_pixelcode flavor;
- u32 pixelformat;
- unsigned int bpp;
-};
-
-enum isp_pipeline_stream_state {
- ISP_PIPELINE_STREAM_STOPPED = 0,
- ISP_PIPELINE_STREAM_CONTINUOUS = 1,
- ISP_PIPELINE_STREAM_SINGLESHOT = 2,
-};
-
-enum isp_pipeline_state {
- /* The stream has been started on the input video node. */
- ISP_PIPELINE_STREAM_INPUT = 1,
- /* The stream has been started on the output video node. */
- ISP_PIPELINE_STREAM_OUTPUT = 2,
- /* At least one buffer is queued on the input video node. */
- ISP_PIPELINE_QUEUE_INPUT = 4,
- /* At least one buffer is queued on the output video node. */
- ISP_PIPELINE_QUEUE_OUTPUT = 8,
- /* The input entity is idle, ready to be started. */
- ISP_PIPELINE_IDLE_INPUT = 16,
- /* The output entity is idle, ready to be started. */
- ISP_PIPELINE_IDLE_OUTPUT = 32,
- /* The pipeline is currently streaming. */
- ISP_PIPELINE_STREAM = 64,
-};
-
-/*
- * struct isp_pipeline - An ISP hardware pipeline
- * @error: A hardware error occurred during capture
- * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
- */
-struct isp_pipeline {
- struct media_pipeline pipe;
- spinlock_t lock; /* Pipeline state and queue flags */
- unsigned int state;
- enum isp_pipeline_stream_state stream_state;
- struct isp_video *input;
- struct isp_video *output;
- u32 entities;
- unsigned long l3_ick;
- unsigned int max_rate;
- atomic_t frame_number;
- bool do_propagation; /* of frame number */
- bool error;
- struct v4l2_fract max_timeperframe;
- struct v4l2_subdev *external;
- unsigned int external_rate;
- unsigned int external_bpp;
-};
-
-#define to_isp_pipeline(__e) \
- container_of((__e)->pipe, struct isp_pipeline, pipe)
-
-static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
-{
- return pipe->state == (ISP_PIPELINE_STREAM_INPUT |
- ISP_PIPELINE_STREAM_OUTPUT |
- ISP_PIPELINE_QUEUE_INPUT |
- ISP_PIPELINE_QUEUE_OUTPUT |
- ISP_PIPELINE_IDLE_INPUT |
- ISP_PIPELINE_IDLE_OUTPUT);
-}
-
-/*
- * struct isp_buffer - ISP buffer
- * @buffer: ISP video buffer
- * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
- */
-struct isp_buffer {
- struct isp_video_buffer buffer;
- dma_addr_t isp_addr;
-};
-
-#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer)
-
-enum isp_video_dmaqueue_flags {
- /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */
- ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
- /* Set when queuing buffer to an empty DMA queue */
- ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
-};
-
-#define isp_video_dmaqueue_flags_clr(video) \
- ({ (video)->dmaqueue_flags = 0; })
-
-/*
- * struct isp_video_operations - ISP video operations
- * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
- * if there was no buffer previously queued.
- */
-struct isp_video_operations {
- int(*queue)(struct isp_video *video, struct isp_buffer *buffer);
-};
-
-struct isp_video {
- struct video_device video;
- enum v4l2_buf_type type;
- struct media_pad pad;
-
- struct mutex mutex; /* format and crop settings */
- atomic_t active;
-
- struct isp_device *isp;
-
- unsigned int capture_mem;
- unsigned int bpl_alignment; /* alignment value */
- unsigned int bpl_zero_padding; /* whether the alignment is optional */
- unsigned int bpl_max; /* maximum bytes per line value */
- unsigned int bpl_value; /* bytes per line value */
- unsigned int bpl_padding; /* padding at end of line */
-
- /* Entity video node streaming */
- unsigned int streaming:1;
-
- /* Pipeline state */
- struct isp_pipeline pipe;
- struct mutex stream_lock; /* pipeline and stream states */
-
- /* Video buffers queue */
- struct isp_video_queue *queue;
- struct list_head dmaqueue;
- enum isp_video_dmaqueue_flags dmaqueue_flags;
-
- const struct isp_video_operations *ops;
-};
-
-#define to_isp_video(vdev) container_of(vdev, struct isp_video, video)
-
-struct isp_video_fh {
- struct v4l2_fh vfh;
- struct isp_video *video;
- struct isp_video_queue queue;
- struct v4l2_format format;
- struct v4l2_fract timeperframe;
-};
-
-#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh)
-#define isp_video_queue_to_isp_video_fh(q) \
- container_of(q, struct isp_video_fh, queue)
-
-int omap3isp_video_init(struct isp_video *video, const char *name);
-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);
-void omap3isp_video_resume(struct isp_video *video, int continuous);
-struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
-
-const struct isp_format_info *
-omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
-
-#endif /* OMAP3_ISP_VIDEO_H */
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c
deleted file mode 100644
index 7c44d1fe3c87..000000000000
--- a/drivers/media/video/ov2640.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*
- * ov2640 Camera Driver
- *
- * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
- *
- * Based on ov772x, ov9640 drivers and previous non merged implementations.
- *
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2006, OmniVision
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-ctrls.h>
-
-#define VAL_SET(x, mask, rshift, lshift) \
- ((((x) >> rshift) & mask) << lshift)
-/*
- * DSP registers
- * register offset for BANK_SEL == BANK_SEL_DSP
- */
-#define R_BYPASS 0x05 /* Bypass DSP */
-#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */
-#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */
-#define QS 0x44 /* Quantization Scale Factor */
-#define CTRLI 0x50
-#define CTRLI_LP_DP 0x80
-#define CTRLI_ROUND 0x40
-#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)
-#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)
-#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */
-#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
-#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */
-#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
-#define XOFFL 0x53 /* OFFSET_X[7:0] */
-#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
-#define YOFFL 0x54 /* OFFSET_Y[7:0] */
-#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
-#define VHYX 0x55 /* Offset and size completion */
-#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7)
-#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3)
-#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4)
-#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0)
-#define DPRP 0x56
-#define TEST 0x57 /* Horizontal size completion */
-#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7)
-#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */
-#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)
-#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */
-#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)
-#define ZMHH 0x5C /* Zoom: Speed and H&W completion */
-#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)
-#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2)
-#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0)
-#define BPADDR 0x7C /* SDE Indirect Register Access: Address */
-#define BPDATA 0x7D /* SDE Indirect Register Access: Data */
-#define CTRL2 0x86 /* DSP Module enable 2 */
-#define CTRL2_DCW_EN 0x20
-#define CTRL2_SDE_EN 0x10
-#define CTRL2_UV_ADJ_EN 0x08
-#define CTRL2_UV_AVG_EN 0x04
-#define CTRL2_CMX_EN 0x01
-#define CTRL3 0x87 /* DSP Module enable 3 */
-#define CTRL3_BPC_EN 0x80
-#define CTRL3_WPC_EN 0x40
-#define SIZEL 0x8C /* Image Size Completion */
-#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)
-#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3)
-#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0)
-#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */
-#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
-#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */
-#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
-#define CTRL0 0xC2 /* DSP Module enable 0 */
-#define CTRL0_AEC_EN 0x80
-#define CTRL0_AEC_SEL 0x40
-#define CTRL0_STAT_SEL 0x20
-#define CTRL0_VFIRST 0x10
-#define CTRL0_YUV422 0x08
-#define CTRL0_YUV_EN 0x04
-#define CTRL0_RGB_EN 0x02
-#define CTRL0_RAW_EN 0x01
-#define CTRL1 0xC3 /* DSP Module enable 1 */
-#define CTRL1_CIP 0x80
-#define CTRL1_DMY 0x40
-#define CTRL1_RAW_GMA 0x20
-#define CTRL1_DG 0x10
-#define CTRL1_AWB 0x08
-#define CTRL1_AWB_GAIN 0x04
-#define CTRL1_LENC 0x02
-#define CTRL1_PRE 0x01
-#define R_DVP_SP 0xD3 /* DVP output speed control */
-#define R_DVP_SP_AUTO_MODE 0x80
-#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);
- * = sysclk (48)/(2*[6:0]) (RAW);*/
-#define IMAGE_MODE 0xDA /* Image Output Format Select */
-#define IMAGE_MODE_Y8_DVP_EN 0x40
-#define IMAGE_MODE_JPEG_EN 0x10
-#define IMAGE_MODE_YUV422 0x00
-#define IMAGE_MODE_RAW10 0x04 /* (DVP) */
-#define IMAGE_MODE_RGB565 0x08
-#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output
- * mode (0 for HREF is same as sensor) */
-#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP
- * 1: Low byte first UYVY (C2[4] =0)
- * VYUY (C2[4] =1)
- * 0: High byte first YUYV (C2[4]=0)
- * YVYU (C2[4] = 1) */
-#define RESET 0xE0 /* Reset */
-#define RESET_MICROC 0x40
-#define RESET_SCCB 0x20
-#define RESET_JPEG 0x10
-#define RESET_DVP 0x04
-#define RESET_IPU 0x02
-#define RESET_CIF 0x01
-#define REGED 0xED /* Register ED */
-#define REGED_CLK_OUT_DIS 0x10
-#define MS_SP 0xF0 /* SCCB Master Speed */
-#define SS_ID 0xF7 /* SCCB Slave ID */
-#define SS_CTRL 0xF8 /* SCCB Slave Control */
-#define SS_CTRL_ADD_AUTO_INC 0x20
-#define SS_CTRL_EN 0x08
-#define SS_CTRL_DELAY_CLK 0x04
-#define SS_CTRL_ACC_EN 0x02
-#define SS_CTRL_SEN_PASS_THR 0x01
-#define MC_BIST 0xF9 /* Microcontroller misc register */
-#define MC_BIST_RESET 0x80 /* Microcontroller Reset */
-#define MC_BIST_BOOT_ROM_SEL 0x40
-#define MC_BIST_12KB_SEL 0x20
-#define MC_BIST_12KB_MASK 0x30
-#define MC_BIST_512KB_SEL 0x08
-#define MC_BIST_512KB_MASK 0x0C
-#define MC_BIST_BUSY_BIT_R 0x02
-#define MC_BIST_MC_RES_ONE_SH_W 0x02
-#define MC_BIST_LAUNCH 0x01
-#define BANK_SEL 0xFF /* Register Bank Select */
-#define BANK_SEL_DSP 0x00
-#define BANK_SEL_SENS 0x01
-
-/*
- * Sensor registers
- * register offset for BANK_SEL == BANK_SEL_SENS
- */
-#define GAIN 0x00 /* AGC - Gain control gain setting */
-#define COM1 0x03 /* Common control 1 */
-#define COM1_1_DUMMY_FR 0x40
-#define COM1_3_DUMMY_FR 0x80
-#define COM1_7_DUMMY_FR 0xC0
-#define COM1_VWIN_LSB_UXGA 0x0F
-#define COM1_VWIN_LSB_SVGA 0x0A
-#define COM1_VWIN_LSB_CIF 0x06
-#define REG04 0x04 /* Register 04 */
-#define REG04_DEF 0x20 /* Always set */
-#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */
-#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */
-#define REG04_VREF_EN 0x10
-#define REG04_HREF_EN 0x08
-#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0)
-#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */
-#define COM2 0x09 /* Common control 2 */
-#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
- /* Output drive capability */
-#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */
-#define PID 0x0A /* Product ID Number MSB */
-#define VER 0x0B /* Product ID Number LSB */
-#define COM3 0x0C /* Common control 3 */
-#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */
-#define COM3_BAND_AUTO 0x02 /* Auto Banding */
-#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the
- * snapshot sequence*/
-#define AEC 0x10 /* AEC[9:2] Exposure Value */
-#define CLKRC 0x11 /* Internal clock */
-#define CLKRC_EN 0x80
-#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */
-#define COM7 0x12 /* Common control 7 */
-#define COM7_SRST 0x80 /* Initiates system reset. All registers are
- * set to factory default values after which
- * the chip resumes normal operation */
-#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */
-#define COM7_RES_SVGA 0x40 /* SVGA */
-#define COM7_RES_CIF 0x20 /* CIF */
-#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */
-#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */
-#define COM8 0x13 /* Common control 8 */
-#define COM8_DEF 0xC0 /* Banding filter ON/OFF */
-#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */
-#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
-#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
-#define COM9 0x14 /* Common control 9
- * Automatic gain ceiling - maximum AGC value [7:5]*/
-#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */
-#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */
-#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */
-#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */
-#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */
-#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */
-#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */
-#define COM10 0x15 /* Common control 10 */
-#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */
-#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of
- * PCLK (user can latch data at the next
- * falling edge of PCLK).
- * 0 otherwise. */
-#define COM10_HREF_INV 0x08 /* Invert HREF polarity:
- * HREF negative for valid data*/
-#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */
-#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */
-#define HEND 0x18 /* Horizontal Window end MSB 8 bit */
-#define VSTART 0x19 /* Vertical Window start MSB 8 bit */
-#define VEND 0x1A /* Vertical Window end MSB 8 bit */
-#define MIDH 0x1C /* Manufacturer ID byte - high */
-#define MIDL 0x1D /* Manufacturer ID byte - low */
-#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
-#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
-#define VV 0x26 /* AGC/AEC Fast mode operating region */
-#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4)
-#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0)
-#define REG2A 0x2A /* Dummy pixel insert MSB */
-#define FRARL 0x2B /* Dummy pixel insert LSB */
-#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
-#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */
-#define YAVG 0x2F /* Y/G Channel Average value */
-#define REG32 0x32 /* Common Control 32 */
-#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */
-#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */
-#define ARCOM2 0x34 /* Zoom: Horizontal start point */
-#define REG45 0x45 /* Register 45 */
-#define FLL 0x46 /* Frame Length Adjustment LSBs */
-#define FLH 0x47 /* Frame Length Adjustment MSBs */
-#define COM19 0x48 /* Zoom: Vertical start point */
-#define ZOOMS 0x49 /* Zoom: Vertical start point */
-#define COM22 0x4B /* Flash light control */
-#define COM25 0x4E /* For Banding operations */
-#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */
-#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */
-#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */
-#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */
-#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */
-#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */
-#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */
-#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */
-
-/*
- * ID
- */
-#define MANUFACTURER_ID 0x7FA2
-#define PID_OV2640 0x2642
-#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
-
-/*
- * Struct
- */
-struct regval_list {
- u8 reg_num;
- u8 value;
-};
-
-/* Supported resolutions */
-enum ov2640_width {
- W_QCIF = 176,
- W_QVGA = 320,
- W_CIF = 352,
- W_VGA = 640,
- W_SVGA = 800,
- W_XGA = 1024,
- W_SXGA = 1280,
- W_UXGA = 1600,
-};
-
-enum ov2640_height {
- H_QCIF = 144,
- H_QVGA = 240,
- H_CIF = 288,
- H_VGA = 480,
- H_SVGA = 600,
- H_XGA = 768,
- H_SXGA = 1024,
- H_UXGA = 1200,
-};
-
-struct ov2640_win_size {
- char *name;
- enum ov2640_width width;
- enum ov2640_height height;
- const struct regval_list *regs;
-};
-
-
-struct ov2640_priv {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- enum v4l2_mbus_pixelcode cfmt_code;
- const struct ov2640_win_size *win;
- int model;
-};
-
-/*
- * Registers settings
- */
-
-#define ENDMARKER { 0xff, 0xff }
-
-static const struct regval_list ov2640_init_regs[] = {
- { BANK_SEL, BANK_SEL_DSP },
- { 0x2c, 0xff },
- { 0x2e, 0xdf },
- { BANK_SEL, BANK_SEL_SENS },
- { 0x3c, 0x32 },
- { CLKRC, CLKRC_DIV_SET(1) },
- { COM2, COM2_OCAP_Nx_SET(3) },
- { REG04, REG04_DEF | REG04_HREF_EN },
- { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN },
- { COM9, COM9_AGC_GAIN_8x | 0x08},
- { 0x2c, 0x0c },
- { 0x33, 0x78 },
- { 0x3a, 0x33 },
- { 0x3b, 0xfb },
- { 0x3e, 0x00 },
- { 0x43, 0x11 },
- { 0x16, 0x10 },
- { 0x39, 0x02 },
- { 0x35, 0x88 },
- { 0x22, 0x0a },
- { 0x37, 0x40 },
- { 0x23, 0x00 },
- { ARCOM2, 0xa0 },
- { 0x06, 0x02 },
- { 0x06, 0x88 },
- { 0x07, 0xc0 },
- { 0x0d, 0xb7 },
- { 0x0e, 0x01 },
- { 0x4c, 0x00 },
- { 0x4a, 0x81 },
- { 0x21, 0x99 },
- { AEW, 0x40 },
- { AEB, 0x38 },
- { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) },
- { 0x5c, 0x00 },
- { 0x63, 0x00 },
- { FLL, 0x22 },
- { COM3, 0x38 | COM3_BAND_AUTO },
- { REG5D, 0x55 },
- { REG5E, 0x7d },
- { REG5F, 0x7d },
- { REG60, 0x55 },
- { HISTO_LOW, 0x70 },
- { HISTO_HIGH, 0x80 },
- { 0x7c, 0x05 },
- { 0x20, 0x80 },
- { 0x28, 0x30 },
- { 0x6c, 0x00 },
- { 0x6d, 0x80 },
- { 0x6e, 0x00 },
- { 0x70, 0x02 },
- { 0x71, 0x94 },
- { 0x73, 0xc1 },
- { 0x3d, 0x34 },
- { COM7, COM7_RES_UXGA | COM7_ZOOM_EN },
- { 0x5a, 0x57 },
- { BD50, 0xbb },
- { BD60, 0x9c },
- { BANK_SEL, BANK_SEL_DSP },
- { 0xe5, 0x7f },
- { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
- { 0x41, 0x24 },
- { RESET, RESET_JPEG | RESET_DVP },
- { 0x76, 0xff },
- { 0x33, 0xa0 },
- { 0x42, 0x20 },
- { 0x43, 0x18 },
- { 0x4c, 0x00 },
- { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
- { 0x88, 0x3f },
- { 0xd7, 0x03 },
- { 0xd9, 0x10 },
- { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 },
- { 0xc8, 0x08 },
- { 0xc9, 0x80 },
- { BPADDR, 0x00 },
- { BPDATA, 0x00 },
- { BPADDR, 0x03 },
- { BPDATA, 0x48 },
- { BPDATA, 0x48 },
- { BPADDR, 0x08 },
- { BPDATA, 0x20 },
- { BPDATA, 0x10 },
- { BPDATA, 0x0e },
- { 0x90, 0x00 },
- { 0x91, 0x0e },
- { 0x91, 0x1a },
- { 0x91, 0x31 },
- { 0x91, 0x5a },
- { 0x91, 0x69 },
- { 0x91, 0x75 },
- { 0x91, 0x7e },
- { 0x91, 0x88 },
- { 0x91, 0x8f },
- { 0x91, 0x96 },
- { 0x91, 0xa3 },
- { 0x91, 0xaf },
- { 0x91, 0xc4 },
- { 0x91, 0xd7 },
- { 0x91, 0xe8 },
- { 0x91, 0x20 },
- { 0x92, 0x00 },
- { 0x93, 0x06 },
- { 0x93, 0xe3 },
- { 0x93, 0x03 },
- { 0x93, 0x03 },
- { 0x93, 0x00 },
- { 0x93, 0x02 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x93, 0x00 },
- { 0x96, 0x00 },
- { 0x97, 0x08 },
- { 0x97, 0x19 },
- { 0x97, 0x02 },
- { 0x97, 0x0c },
- { 0x97, 0x24 },
- { 0x97, 0x30 },
- { 0x97, 0x28 },
- { 0x97, 0x26 },
- { 0x97, 0x02 },
- { 0x97, 0x98 },
- { 0x97, 0x80 },
- { 0x97, 0x00 },
- { 0x97, 0x00 },
- { 0xa4, 0x00 },
- { 0xa8, 0x00 },
- { 0xc5, 0x11 },
- { 0xc6, 0x51 },
- { 0xbf, 0x80 },
- { 0xc7, 0x10 },
- { 0xb6, 0x66 },
- { 0xb8, 0xA5 },
- { 0xb7, 0x64 },
- { 0xb9, 0x7C },
- { 0xb3, 0xaf },
- { 0xb4, 0x97 },
- { 0xb5, 0xFF },
- { 0xb0, 0xC5 },
- { 0xb1, 0x94 },
- { 0xb2, 0x0f },
- { 0xc4, 0x5c },
- { 0xa6, 0x00 },
- { 0xa7, 0x20 },
- { 0xa7, 0xd8 },
- { 0xa7, 0x1b },
- { 0xa7, 0x31 },
- { 0xa7, 0x00 },
- { 0xa7, 0x18 },
- { 0xa7, 0x20 },
- { 0xa7, 0xd8 },
- { 0xa7, 0x19 },
- { 0xa7, 0x31 },
- { 0xa7, 0x00 },
- { 0xa7, 0x18 },
- { 0xa7, 0x20 },
- { 0xa7, 0xd8 },
- { 0xa7, 0x19 },
- { 0xa7, 0x31 },
- { 0xa7, 0x00 },
- { 0xa7, 0x18 },
- { 0x7f, 0x00 },
- { 0xe5, 0x1f },
- { 0xe1, 0x77 },
- { 0xdd, 0x7f },
- { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
- ENDMARKER,
-};
-
-/*
- * Register settings for window size
- * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.
- * Then the different zooming configurations will setup the output image size.
- */
-static const struct regval_list ov2640_size_change_preamble_regs[] = {
- { BANK_SEL, BANK_SEL_DSP },
- { RESET, RESET_DVP },
- { HSIZE8, HSIZE8_SET(W_UXGA) },
- { VSIZE8, VSIZE8_SET(H_UXGA) },
- { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
- CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
- { HSIZE, HSIZE_SET(W_UXGA) },
- { VSIZE, VSIZE_SET(H_UXGA) },
- { XOFFL, XOFFL_SET(0) },
- { YOFFL, YOFFL_SET(0) },
- { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
- VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
- { TEST, TEST_HSIZE_SET(W_UXGA) },
- ENDMARKER,
-};
-
-#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \
- { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \
- CTRLI_H_DIV_SET(h_div)}, \
- { ZMOW, ZMOW_OUTW_SET(x) }, \
- { ZMOH, ZMOH_OUTH_SET(y) }, \
- { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \
- { R_DVP_SP, pclk_div }, \
- { RESET, 0x00}
-
-static const struct regval_list ov2640_qcif_regs[] = {
- PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_qvga_regs[] = {
- PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_cif_regs[] = {
- PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_vga_regs[] = {
- PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_svga_regs[] = {
- PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_xga_regs[] = {
- PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
- { CTRLI, 0x00},
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_sxga_regs[] = {
- PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
- { CTRLI, 0x00},
- { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_uxga_regs[] = {
- PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
- { CTRLI, 0x00},
- { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
- ENDMARKER,
-};
-
-#define OV2640_SIZE(n, w, h, r) \
- {.name = n, .width = w , .height = h, .regs = r }
-
-static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
- OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
- OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
- OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
- OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
- OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
- OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
- OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
- OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
-};
-
-/*
- * Register settings for pixel formats
- */
-static const struct regval_list ov2640_format_change_preamble_regs[] = {
- { BANK_SEL, BANK_SEL_DSP },
- { R_BYPASS, R_BYPASS_USE_DSP },
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_yuv422_regs[] = {
- { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },
- { 0xD7, 0x01 },
- { 0x33, 0xa0 },
- { 0xe1, 0x67 },
- { RESET, 0x00 },
- { R_BYPASS, R_BYPASS_USE_DSP },
- ENDMARKER,
-};
-
-static const struct regval_list ov2640_rgb565_regs[] = {
- { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },
- { 0xd7, 0x03 },
- { RESET, 0x00 },
- { R_BYPASS, R_BYPASS_USE_DSP },
- ENDMARKER,
-};
-
-static enum v4l2_mbus_pixelcode ov2640_codes[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
-};
-
-/*
- * General functions
- */
-static struct ov2640_priv *to_ov2640(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct ov2640_priv,
- subdev);
-}
-
-static int ov2640_write_array(struct i2c_client *client,
- const struct regval_list *vals)
-{
- int ret;
-
- while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {
- ret = i2c_smbus_write_byte_data(client,
- vals->reg_num, vals->value);
- dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",
- vals->reg_num, vals->value);
-
- if (ret < 0)
- return ret;
- vals++;
- }
- return 0;
-}
-
-static int ov2640_mask_set(struct i2c_client *client,
- u8 reg, u8 mask, u8 set)
-{
- s32 val = i2c_smbus_read_byte_data(client, reg);
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);
-
- return i2c_smbus_write_byte_data(client, reg, val);
-}
-
-static int ov2640_reset(struct i2c_client *client)
-{
- int ret;
- const struct regval_list reset_seq[] = {
- {BANK_SEL, BANK_SEL_SENS},
- {COM7, COM7_SRST},
- ENDMARKER,
- };
-
- ret = ov2640_write_array(client, reset_seq);
- if (ret)
- goto err;
-
- msleep(5);
-err:
- dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);
- return ret;
-}
-
-/*
- * soc_camera_ops functions
- */
-static int ov2640_s_stream(struct v4l2_subdev *sd, int enable)
-{
- return 0;
-}
-
-static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd =
- &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u8 val;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- val = ctrl->val ? REG04_VFLIP_IMG : 0x00;
- return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val);
- case V4L2_CID_HFLIP:
- val = ctrl->val ? REG04_HFLIP_IMG : 0x00;
- return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
- }
-
- return -EINVAL;
-}
-
-static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov2640_priv *priv = to_ov2640(client);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov2640_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- reg->size = 1;
- if (reg->reg > 0xff)
- return -EINVAL;
-
- ret = i2c_smbus_read_byte_data(client, reg->reg);
- if (ret < 0)
- return ret;
-
- reg->val = ret;
-
- return 0;
-}
-
-static int ov2640_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg > 0xff ||
- reg->val > 0xff)
- return -EINVAL;
-
- return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
-}
-#endif
-
-/* Select the nearest higher resolution for capture */
-static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
-{
- int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
-
- for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
- if (ov2640_supported_win_sizes[i].width >= *width &&
- ov2640_supported_win_sizes[i].height >= *height) {
- *width = ov2640_supported_win_sizes[i].width;
- *height = ov2640_supported_win_sizes[i].height;
- return &ov2640_supported_win_sizes[i];
- }
- }
-
- *width = ov2640_supported_win_sizes[default_size].width;
- *height = ov2640_supported_win_sizes[default_size].height;
- return &ov2640_supported_win_sizes[default_size];
-}
-
-static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
- enum v4l2_mbus_pixelcode code)
-{
- struct ov2640_priv *priv = to_ov2640(client);
- const struct regval_list *selected_cfmt_regs;
- int ret;
-
- /* select win */
- priv->win = ov2640_select_win(width, height);
-
- /* select format */
- priv->cfmt_code = 0;
- switch (code) {
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__);
- selected_cfmt_regs = ov2640_rgb565_regs;
- break;
- default:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__);
- selected_cfmt_regs = ov2640_yuv422_regs;
- }
-
- /* reset hardware */
- ov2640_reset(client);
-
- /* initialize the sensor with default data */
- dev_dbg(&client->dev, "%s: Init default", __func__);
- ret = ov2640_write_array(client, ov2640_init_regs);
- if (ret < 0)
- goto err;
-
- /* select preamble */
- dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
- ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
- if (ret < 0)
- goto err;
-
- /* set size win */
- ret = ov2640_write_array(client, priv->win->regs);
- if (ret < 0)
- goto err;
-
- /* cfmt preamble */
- dev_dbg(&client->dev, "%s: Set cfmt", __func__);
- ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);
- if (ret < 0)
- goto err;
-
- /* set cfmt */
- ret = ov2640_write_array(client, selected_cfmt_regs);
- if (ret < 0)
- goto err;
-
- priv->cfmt_code = code;
- *width = priv->win->width;
- *height = priv->win->height;
-
- return 0;
-
-err:
- dev_err(&client->dev, "%s: Error %d", __func__, ret);
- ov2640_reset(client);
- priv->win = NULL;
-
- return ret;
-}
-
-static int ov2640_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov2640_priv *priv = to_ov2640(client);
-
- if (!priv->win) {
- u32 width = W_SVGA, height = H_SVGA;
- priv->win = ov2640_select_win(&width, &height);
- priv->cfmt_code = V4L2_MBUS_FMT_UYVY8_2X8;
- }
-
- mf->width = priv->win->width;
- mf->height = priv->win->height;
- mf->code = priv->cfmt_code;
-
- switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- }
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int ov2640_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
-
- switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- }
-
- ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code);
-
- return ret;
-}
-
-static int ov2640_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- const struct ov2640_win_size *win;
-
- /*
- * select suitable win
- */
- win = ov2640_select_win(&mf->width, &mf->height);
-
- mf->field = V4L2_FIELD_NONE;
-
- switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- }
-
- return 0;
-}
-
-static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov2640_codes))
- return -EINVAL;
-
- *code = ov2640_codes[index];
- return 0;
-}
-
-static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = W_UXGA;
- a->c.height = H_UXGA;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = W_UXGA;
- a->bounds.height = H_UXGA;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov2640_video_probe(struct i2c_client *client)
-{
- struct ov2640_priv *priv = to_ov2640(client);
- u8 pid, ver, midh, midl;
- const char *devname;
- int ret;
-
- /*
- * check and show product ID and manufacturer ID
- */
- i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
- pid = i2c_smbus_read_byte_data(client, PID);
- ver = i2c_smbus_read_byte_data(client, VER);
- midh = i2c_smbus_read_byte_data(client, MIDH);
- midl = i2c_smbus_read_byte_data(client, MIDL);
-
- switch (VERSION(pid, ver)) {
- case PID_OV2640:
- devname = "ov2640";
- priv->model = V4L2_IDENT_OV2640;
- break;
- default:
- dev_err(&client->dev,
- "Product ID error %x:%x\n", pid, ver);
- ret = -ENODEV;
- goto err;
- }
-
- dev_info(&client->dev,
- "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
- devname, pid, ver, midh, midl);
-
- return v4l2_ctrl_handler_setup(&priv->hdl);
-
-err:
- return ret;
-}
-
-static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
- .s_ctrl = ov2640_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
- .g_chip_ident = ov2640_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov2640_g_register,
- .s_register = ov2640_s_register,
-#endif
-};
-
-static int ov2640_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
- .s_stream = ov2640_s_stream,
- .g_mbus_fmt = ov2640_g_fmt,
- .s_mbus_fmt = ov2640_s_fmt,
- .try_mbus_fmt = ov2640_try_fmt,
- .cropcap = ov2640_cropcap,
- .g_crop = ov2640_g_crop,
- .enum_mbus_fmt = ov2640_enum_fmt,
- .g_mbus_config = ov2640_g_mbus_config,
-};
-
-static struct v4l2_subdev_ops ov2640_subdev_ops = {
- .core = &ov2640_subdev_core_ops,
- .video = &ov2640_subdev_video_ops,
-};
-
-/*
- * i2c_driver functions
- */
-static int ov2640_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov2640_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int ret;
-
- if (!icl) {
- dev_err(&adapter->dev,
- "OV2640: Missing platform_data for driver\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&adapter->dev,
- "OV2640: I2C-Adapter doesn't support SMBUS\n");
- return -EIO;
- }
-
- priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&adapter->dev,
- "Failed to allocate memory for private data!\n");
- return -ENOMEM;
- }
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
- v4l2_ctrl_handler_init(&priv->hdl, 2);
- v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
-
- ret = ov2640_video_probe(client);
- if (ret) {
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- } else {
- dev_info(&adapter->dev, "OV2640 Probed\n");
- }
-
- return ret;
-}
-
-static int ov2640_remove(struct i2c_client *client)
-{
- struct ov2640_priv *priv = to_ov2640(client);
-
- v4l2_device_unregister_subdev(&priv->subdev);
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id ov2640_id[] = {
- { "ov2640", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov2640_id);
-
-static struct i2c_driver ov2640_i2c_driver = {
- .driver = {
- .name = "ov2640",
- },
- .probe = ov2640_probe,
- .remove = ov2640_remove,
- .id_table = ov2640_id,
-};
-
-module_i2c_driver(ov2640_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
-MODULE_AUTHOR("Alberto Panizzo");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
deleted file mode 100644
index 0bc93313d37a..000000000000
--- a/drivers/media/video/ov5642.c
+++ /dev/null
@@ -1,1073 +0,0 @@
-/*
- * Driver for OV5642 CMOS Image Sensor from Omnivision
- *
- * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
- *
- * Based on Sony IMX074 Camera Driver
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * Based on Omnivision OV7670 Camera Driver
- * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * 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/bitops.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-subdev.h>
-
-/* OV5642 registers */
-#define REG_CHIP_ID_HIGH 0x300a
-#define REG_CHIP_ID_LOW 0x300b
-
-#define REG_WINDOW_START_X_HIGH 0x3800
-#define REG_WINDOW_START_X_LOW 0x3801
-#define REG_WINDOW_START_Y_HIGH 0x3802
-#define REG_WINDOW_START_Y_LOW 0x3803
-#define REG_WINDOW_WIDTH_HIGH 0x3804
-#define REG_WINDOW_WIDTH_LOW 0x3805
-#define REG_WINDOW_HEIGHT_HIGH 0x3806
-#define REG_WINDOW_HEIGHT_LOW 0x3807
-#define REG_OUT_WIDTH_HIGH 0x3808
-#define REG_OUT_WIDTH_LOW 0x3809
-#define REG_OUT_HEIGHT_HIGH 0x380a
-#define REG_OUT_HEIGHT_LOW 0x380b
-#define REG_OUT_TOTAL_WIDTH_HIGH 0x380c
-#define REG_OUT_TOTAL_WIDTH_LOW 0x380d
-#define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e
-#define REG_OUT_TOTAL_HEIGHT_LOW 0x380f
-#define REG_OUTPUT_FORMAT 0x4300
-#define REG_ISP_CTRL_01 0x5001
-#define REG_AVG_WINDOW_END_X_HIGH 0x5682
-#define REG_AVG_WINDOW_END_X_LOW 0x5683
-#define REG_AVG_WINDOW_END_Y_HIGH 0x5686
-#define REG_AVG_WINDOW_END_Y_LOW 0x5687
-
-/* active pixel array size */
-#define OV5642_SENSOR_SIZE_X 2592
-#define OV5642_SENSOR_SIZE_Y 1944
-
-/*
- * About OV5642 resolution, cropping and binning:
- * This sensor supports it all, at least in the feature description.
- * Unfortunately, no combination of appropriate registers settings could make
- * the chip work the intended way. As it works with predefined register lists,
- * some undocumented registers are presumably changed there to achieve their
- * goals.
- * This driver currently only works for resolutions up to 720 lines with a
- * 1:1 scale. Hopefully these restrictions will be removed in the future.
- */
-#define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X
-#define OV5642_MAX_HEIGHT 720
-
-/* default sizes */
-#define OV5642_DEFAULT_WIDTH 1280
-#define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT
-
-/* minimum extra blanking */
-#define BLANKING_EXTRA_WIDTH 500
-#define BLANKING_EXTRA_HEIGHT 20
-
-/*
- * the sensor's autoexposure is buggy when setting total_height low.
- * It tries to expose longer than 1 frame period without taking care of it
- * and this leads to weird output. So we set 1000 lines as minimum.
- */
-#define BLANKING_MIN_HEIGHT 1000
-
-struct regval_list {
- u16 reg_num;
- u8 value;
-};
-
-static struct regval_list ov5642_default_regs_init[] = {
- { 0x3103, 0x93 },
- { 0x3008, 0x82 },
- { 0x3017, 0x7f },
- { 0x3018, 0xfc },
- { 0x3810, 0xc2 },
- { 0x3615, 0xf0 },
- { 0x3000, 0x0 },
- { 0x3001, 0x0 },
- { 0x3002, 0x0 },
- { 0x3003, 0x0 },
- { 0x3004, 0xff },
- { 0x3030, 0x2b },
- { 0x3011, 0x8 },
- { 0x3010, 0x10 },
- { 0x3604, 0x60 },
- { 0x3622, 0x60 },
- { 0x3621, 0x9 },
- { 0x3709, 0x0 },
- { 0x4000, 0x21 },
- { 0x401d, 0x22 },
- { 0x3600, 0x54 },
- { 0x3605, 0x4 },
- { 0x3606, 0x3f },
- { 0x3c01, 0x80 },
- { 0x300d, 0x22 },
- { 0x3623, 0x22 },
- { 0x5000, 0x4f },
- { 0x5020, 0x4 },
- { 0x5181, 0x79 },
- { 0x5182, 0x0 },
- { 0x5185, 0x22 },
- { 0x5197, 0x1 },
- { 0x5500, 0xa },
- { 0x5504, 0x0 },
- { 0x5505, 0x7f },
- { 0x5080, 0x8 },
- { 0x300e, 0x18 },
- { 0x4610, 0x0 },
- { 0x471d, 0x5 },
- { 0x4708, 0x6 },
- { 0x370c, 0xa0 },
- { 0x5687, 0x94 },
- { 0x501f, 0x0 },
- { 0x5000, 0x4f },
- { 0x5001, 0xcf },
- { 0x4300, 0x30 },
- { 0x4300, 0x30 },
- { 0x460b, 0x35 },
- { 0x471d, 0x0 },
- { 0x3002, 0xc },
- { 0x3002, 0x0 },
- { 0x4713, 0x3 },
- { 0x471c, 0x50 },
- { 0x4721, 0x2 },
- { 0x4402, 0x90 },
- { 0x460c, 0x22 },
- { 0x3815, 0x44 },
- { 0x3503, 0x7 },
- { 0x3501, 0x73 },
- { 0x3502, 0x80 },
- { 0x350b, 0x0 },
- { 0x3818, 0xc8 },
- { 0x3824, 0x11 },
- { 0x3a00, 0x78 },
- { 0x3a1a, 0x4 },
- { 0x3a13, 0x30 },
- { 0x3a18, 0x0 },
- { 0x3a19, 0x7c },
- { 0x3a08, 0x12 },
- { 0x3a09, 0xc0 },
- { 0x3a0a, 0xf },
- { 0x3a0b, 0xa0 },
- { 0x350c, 0x7 },
- { 0x350d, 0xd0 },
- { 0x3a0d, 0x8 },
- { 0x3a0e, 0x6 },
- { 0x3500, 0x0 },
- { 0x3501, 0x0 },
- { 0x3502, 0x0 },
- { 0x350a, 0x0 },
- { 0x350b, 0x0 },
- { 0x3503, 0x0 },
- { 0x3a0f, 0x3c },
- { 0x3a10, 0x32 },
- { 0x3a1b, 0x3c },
- { 0x3a1e, 0x32 },
- { 0x3a11, 0x80 },
- { 0x3a1f, 0x20 },
- { 0x3030, 0x2b },
- { 0x3a02, 0x0 },
- { 0x3a03, 0x7d },
- { 0x3a04, 0x0 },
- { 0x3a14, 0x0 },
- { 0x3a15, 0x7d },
- { 0x3a16, 0x0 },
- { 0x3a00, 0x78 },
- { 0x3a08, 0x9 },
- { 0x3a09, 0x60 },
- { 0x3a0a, 0x7 },
- { 0x3a0b, 0xd0 },
- { 0x3a0d, 0x10 },
- { 0x3a0e, 0xd },
- { 0x4407, 0x4 },
- { 0x5193, 0x70 },
- { 0x589b, 0x0 },
- { 0x589a, 0xc0 },
- { 0x401e, 0x20 },
- { 0x4001, 0x42 },
- { 0x401c, 0x6 },
- { 0x3825, 0xac },
- { 0x3827, 0xc },
- { 0x528a, 0x1 },
- { 0x528b, 0x4 },
- { 0x528c, 0x8 },
- { 0x528d, 0x10 },
- { 0x528e, 0x20 },
- { 0x528f, 0x28 },
- { 0x5290, 0x30 },
- { 0x5292, 0x0 },
- { 0x5293, 0x1 },
- { 0x5294, 0x0 },
- { 0x5295, 0x4 },
- { 0x5296, 0x0 },
- { 0x5297, 0x8 },
- { 0x5298, 0x0 },
- { 0x5299, 0x10 },
- { 0x529a, 0x0 },
- { 0x529b, 0x20 },
- { 0x529c, 0x0 },
- { 0x529d, 0x28 },
- { 0x529e, 0x0 },
- { 0x529f, 0x30 },
- { 0x5282, 0x0 },
- { 0x5300, 0x0 },
- { 0x5301, 0x20 },
- { 0x5302, 0x0 },
- { 0x5303, 0x7c },
- { 0x530c, 0x0 },
- { 0x530d, 0xc },
- { 0x530e, 0x20 },
- { 0x530f, 0x80 },
- { 0x5310, 0x20 },
- { 0x5311, 0x80 },
- { 0x5308, 0x20 },
- { 0x5309, 0x40 },
- { 0x5304, 0x0 },
- { 0x5305, 0x30 },
- { 0x5306, 0x0 },
- { 0x5307, 0x80 },
- { 0x5314, 0x8 },
- { 0x5315, 0x20 },
- { 0x5319, 0x30 },
- { 0x5316, 0x10 },
- { 0x5317, 0x0 },
- { 0x5318, 0x2 },
- { 0x5380, 0x1 },
- { 0x5381, 0x0 },
- { 0x5382, 0x0 },
- { 0x5383, 0x4e },
- { 0x5384, 0x0 },
- { 0x5385, 0xf },
- { 0x5386, 0x0 },
- { 0x5387, 0x0 },
- { 0x5388, 0x1 },
- { 0x5389, 0x15 },
- { 0x538a, 0x0 },
- { 0x538b, 0x31 },
- { 0x538c, 0x0 },
- { 0x538d, 0x0 },
- { 0x538e, 0x0 },
- { 0x538f, 0xf },
- { 0x5390, 0x0 },
- { 0x5391, 0xab },
- { 0x5392, 0x0 },
- { 0x5393, 0xa2 },
- { 0x5394, 0x8 },
- { 0x5480, 0x14 },
- { 0x5481, 0x21 },
- { 0x5482, 0x36 },
- { 0x5483, 0x57 },
- { 0x5484, 0x65 },
- { 0x5485, 0x71 },
- { 0x5486, 0x7d },
- { 0x5487, 0x87 },
- { 0x5488, 0x91 },
- { 0x5489, 0x9a },
- { 0x548a, 0xaa },
- { 0x548b, 0xb8 },
- { 0x548c, 0xcd },
- { 0x548d, 0xdd },
- { 0x548e, 0xea },
- { 0x548f, 0x1d },
- { 0x5490, 0x5 },
- { 0x5491, 0x0 },
- { 0x5492, 0x4 },
- { 0x5493, 0x20 },
- { 0x5494, 0x3 },
- { 0x5495, 0x60 },
- { 0x5496, 0x2 },
- { 0x5497, 0xb8 },
- { 0x5498, 0x2 },
- { 0x5499, 0x86 },
- { 0x549a, 0x2 },
- { 0x549b, 0x5b },
- { 0x549c, 0x2 },
- { 0x549d, 0x3b },
- { 0x549e, 0x2 },
- { 0x549f, 0x1c },
- { 0x54a0, 0x2 },
- { 0x54a1, 0x4 },
- { 0x54a2, 0x1 },
- { 0x54a3, 0xed },
- { 0x54a4, 0x1 },
- { 0x54a5, 0xc5 },
- { 0x54a6, 0x1 },
- { 0x54a7, 0xa5 },
- { 0x54a8, 0x1 },
- { 0x54a9, 0x6c },
- { 0x54aa, 0x1 },
- { 0x54ab, 0x41 },
- { 0x54ac, 0x1 },
- { 0x54ad, 0x20 },
- { 0x54ae, 0x0 },
- { 0x54af, 0x16 },
- { 0x54b0, 0x1 },
- { 0x54b1, 0x20 },
- { 0x54b2, 0x0 },
- { 0x54b3, 0x10 },
- { 0x54b4, 0x0 },
- { 0x54b5, 0xf0 },
- { 0x54b6, 0x0 },
- { 0x54b7, 0xdf },
- { 0x5402, 0x3f },
- { 0x5403, 0x0 },
- { 0x3406, 0x0 },
- { 0x5180, 0xff },
- { 0x5181, 0x52 },
- { 0x5182, 0x11 },
- { 0x5183, 0x14 },
- { 0x5184, 0x25 },
- { 0x5185, 0x24 },
- { 0x5186, 0x6 },
- { 0x5187, 0x8 },
- { 0x5188, 0x8 },
- { 0x5189, 0x7c },
- { 0x518a, 0x60 },
- { 0x518b, 0xb2 },
- { 0x518c, 0xb2 },
- { 0x518d, 0x44 },
- { 0x518e, 0x3d },
- { 0x518f, 0x58 },
- { 0x5190, 0x46 },
- { 0x5191, 0xf8 },
- { 0x5192, 0x4 },
- { 0x5193, 0x70 },
- { 0x5194, 0xf0 },
- { 0x5195, 0xf0 },
- { 0x5196, 0x3 },
- { 0x5197, 0x1 },
- { 0x5198, 0x4 },
- { 0x5199, 0x12 },
- { 0x519a, 0x4 },
- { 0x519b, 0x0 },
- { 0x519c, 0x6 },
- { 0x519d, 0x82 },
- { 0x519e, 0x0 },
- { 0x5025, 0x80 },
- { 0x3a0f, 0x38 },
- { 0x3a10, 0x30 },
- { 0x3a1b, 0x3a },
- { 0x3a1e, 0x2e },
- { 0x3a11, 0x60 },
- { 0x3a1f, 0x10 },
- { 0x5688, 0xa6 },
- { 0x5689, 0x6a },
- { 0x568a, 0xea },
- { 0x568b, 0xae },
- { 0x568c, 0xa6 },
- { 0x568d, 0x6a },
- { 0x568e, 0x62 },
- { 0x568f, 0x26 },
- { 0x5583, 0x40 },
- { 0x5584, 0x40 },
- { 0x5580, 0x2 },
- { 0x5000, 0xcf },
- { 0x5800, 0x27 },
- { 0x5801, 0x19 },
- { 0x5802, 0x12 },
- { 0x5803, 0xf },
- { 0x5804, 0x10 },
- { 0x5805, 0x15 },
- { 0x5806, 0x1e },
- { 0x5807, 0x2f },
- { 0x5808, 0x15 },
- { 0x5809, 0xd },
- { 0x580a, 0xa },
- { 0x580b, 0x9 },
- { 0x580c, 0xa },
- { 0x580d, 0xc },
- { 0x580e, 0x12 },
- { 0x580f, 0x19 },
- { 0x5810, 0xb },
- { 0x5811, 0x7 },
- { 0x5812, 0x4 },
- { 0x5813, 0x3 },
- { 0x5814, 0x3 },
- { 0x5815, 0x6 },
- { 0x5816, 0xa },
- { 0x5817, 0xf },
- { 0x5818, 0xa },
- { 0x5819, 0x5 },
- { 0x581a, 0x1 },
- { 0x581b, 0x0 },
- { 0x581c, 0x0 },
- { 0x581d, 0x3 },
- { 0x581e, 0x8 },
- { 0x581f, 0xc },
- { 0x5820, 0xa },
- { 0x5821, 0x5 },
- { 0x5822, 0x1 },
- { 0x5823, 0x0 },
- { 0x5824, 0x0 },
- { 0x5825, 0x3 },
- { 0x5826, 0x8 },
- { 0x5827, 0xc },
- { 0x5828, 0xe },
- { 0x5829, 0x8 },
- { 0x582a, 0x6 },
- { 0x582b, 0x4 },
- { 0x582c, 0x5 },
- { 0x582d, 0x7 },
- { 0x582e, 0xb },
- { 0x582f, 0x12 },
- { 0x5830, 0x18 },
- { 0x5831, 0x10 },
- { 0x5832, 0xc },
- { 0x5833, 0xa },
- { 0x5834, 0xb },
- { 0x5835, 0xe },
- { 0x5836, 0x15 },
- { 0x5837, 0x19 },
- { 0x5838, 0x32 },
- { 0x5839, 0x1f },
- { 0x583a, 0x18 },
- { 0x583b, 0x16 },
- { 0x583c, 0x17 },
- { 0x583d, 0x1e },
- { 0x583e, 0x26 },
- { 0x583f, 0x53 },
- { 0x5840, 0x10 },
- { 0x5841, 0xf },
- { 0x5842, 0xd },
- { 0x5843, 0xc },
- { 0x5844, 0xe },
- { 0x5845, 0x9 },
- { 0x5846, 0x11 },
- { 0x5847, 0x10 },
- { 0x5848, 0x10 },
- { 0x5849, 0x10 },
- { 0x584a, 0x10 },
- { 0x584b, 0xe },
- { 0x584c, 0x10 },
- { 0x584d, 0x10 },
- { 0x584e, 0x11 },
- { 0x584f, 0x10 },
- { 0x5850, 0xf },
- { 0x5851, 0xc },
- { 0x5852, 0xf },
- { 0x5853, 0x10 },
- { 0x5854, 0x10 },
- { 0x5855, 0xf },
- { 0x5856, 0xe },
- { 0x5857, 0xb },
- { 0x5858, 0x10 },
- { 0x5859, 0xd },
- { 0x585a, 0xd },
- { 0x585b, 0xc },
- { 0x585c, 0xc },
- { 0x585d, 0xc },
- { 0x585e, 0xb },
- { 0x585f, 0xc },
- { 0x5860, 0xc },
- { 0x5861, 0xc },
- { 0x5862, 0xd },
- { 0x5863, 0x8 },
- { 0x5864, 0x11 },
- { 0x5865, 0x18 },
- { 0x5866, 0x18 },
- { 0x5867, 0x19 },
- { 0x5868, 0x17 },
- { 0x5869, 0x19 },
- { 0x586a, 0x16 },
- { 0x586b, 0x13 },
- { 0x586c, 0x13 },
- { 0x586d, 0x12 },
- { 0x586e, 0x13 },
- { 0x586f, 0x16 },
- { 0x5870, 0x14 },
- { 0x5871, 0x12 },
- { 0x5872, 0x10 },
- { 0x5873, 0x11 },
- { 0x5874, 0x11 },
- { 0x5875, 0x16 },
- { 0x5876, 0x14 },
- { 0x5877, 0x11 },
- { 0x5878, 0x10 },
- { 0x5879, 0xf },
- { 0x587a, 0x10 },
- { 0x587b, 0x14 },
- { 0x587c, 0x13 },
- { 0x587d, 0x12 },
- { 0x587e, 0x11 },
- { 0x587f, 0x11 },
- { 0x5880, 0x12 },
- { 0x5881, 0x15 },
- { 0x5882, 0x14 },
- { 0x5883, 0x15 },
- { 0x5884, 0x15 },
- { 0x5885, 0x15 },
- { 0x5886, 0x13 },
- { 0x5887, 0x17 },
- { 0x3710, 0x10 },
- { 0x3632, 0x51 },
- { 0x3702, 0x10 },
- { 0x3703, 0xb2 },
- { 0x3704, 0x18 },
- { 0x370b, 0x40 },
- { 0x370d, 0x3 },
- { 0x3631, 0x1 },
- { 0x3632, 0x52 },
- { 0x3606, 0x24 },
- { 0x3620, 0x96 },
- { 0x5785, 0x7 },
- { 0x3a13, 0x30 },
- { 0x3600, 0x52 },
- { 0x3604, 0x48 },
- { 0x3606, 0x1b },
- { 0x370d, 0xb },
- { 0x370f, 0xc0 },
- { 0x3709, 0x1 },
- { 0x3823, 0x0 },
- { 0x5007, 0x0 },
- { 0x5009, 0x0 },
- { 0x5011, 0x0 },
- { 0x5013, 0x0 },
- { 0x519e, 0x0 },
- { 0x5086, 0x0 },
- { 0x5087, 0x0 },
- { 0x5088, 0x0 },
- { 0x5089, 0x0 },
- { 0x302b, 0x0 },
- { 0x3503, 0x7 },
- { 0x3011, 0x8 },
- { 0x350c, 0x2 },
- { 0x350d, 0xe4 },
- { 0x3621, 0xc9 },
- { 0x370a, 0x81 },
- { 0xffff, 0xff },
-};
-
-static struct regval_list ov5642_default_regs_finalise[] = {
- { 0x3810, 0xc2 },
- { 0x3818, 0xc9 },
- { 0x381c, 0x10 },
- { 0x381d, 0xa0 },
- { 0x381e, 0x5 },
- { 0x381f, 0xb0 },
- { 0x3820, 0x0 },
- { 0x3821, 0x0 },
- { 0x3824, 0x11 },
- { 0x3a08, 0x1b },
- { 0x3a09, 0xc0 },
- { 0x3a0a, 0x17 },
- { 0x3a0b, 0x20 },
- { 0x3a0d, 0x2 },
- { 0x3a0e, 0x1 },
- { 0x401c, 0x4 },
- { 0x5682, 0x5 },
- { 0x5683, 0x0 },
- { 0x5686, 0x2 },
- { 0x5687, 0xcc },
- { 0x5001, 0x4f },
- { 0x589b, 0x6 },
- { 0x589a, 0xc5 },
- { 0x3503, 0x0 },
- { 0x460c, 0x20 },
- { 0x460b, 0x37 },
- { 0x471c, 0xd0 },
- { 0x471d, 0x5 },
- { 0x3815, 0x1 },
- { 0x3818, 0xc1 },
- { 0x501f, 0x0 },
- { 0x5002, 0xe0 },
- { 0x4300, 0x32 }, /* UYVY */
- { 0x3002, 0x1c },
- { 0x4800, 0x14 },
- { 0x4801, 0xf },
- { 0x3007, 0x3b },
- { 0x300e, 0x4 },
- { 0x4803, 0x50 },
- { 0x3815, 0x1 },
- { 0x4713, 0x2 },
- { 0x4842, 0x1 },
- { 0x300f, 0xe },
- { 0x3003, 0x3 },
- { 0x3003, 0x1 },
- { 0xffff, 0xff },
-};
-
-struct ov5642_datafmt {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-struct ov5642 {
- struct v4l2_subdev subdev;
- const struct ov5642_datafmt *fmt;
- struct v4l2_rect crop_rect;
-
- /* blanking information */
- int total_width;
- int total_height;
-};
-
-static const struct ov5642_datafmt ov5642_colour_fmts[] = {
- {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
-};
-
-static struct ov5642 *to_ov5642(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
-}
-
-/* Find a data format by a pixel code in an array */
-static const struct ov5642_datafmt
- *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
- if (ov5642_colour_fmts[i].code == code)
- return ov5642_colour_fmts + i;
-
- return NULL;
-}
-
-static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
-{
- int ret;
- /* We have 16-bit i2c addresses - care for endianess */
- unsigned char data[2] = { reg >> 8, reg & 0xff };
-
- ret = i2c_master_send(client, data, 2);
- if (ret < 2) {
- dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
- __func__, reg);
- return ret < 0 ? ret : -EIO;
- }
-
- ret = i2c_master_recv(client, val, 1);
- if (ret < 1) {
- dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
- __func__, reg);
- return ret < 0 ? ret : -EIO;
- }
- return 0;
-}
-
-static int reg_write(struct i2c_client *client, u16 reg, u8 val)
-{
- int ret;
- unsigned char data[3] = { reg >> 8, reg & 0xff, val };
-
- ret = i2c_master_send(client, data, 3);
- if (ret < 3) {
- dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
- __func__, reg);
- return ret < 0 ? ret : -EIO;
- }
-
- return 0;
-}
-
-/*
- * convenience function to write 16 bit register values that are split up
- * into two consecutive high and low parts
- */
-static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
-{
- int ret;
-
- ret = reg_write(client, reg, val16 >> 8);
- if (ret)
- return ret;
- return reg_write(client, reg + 1, val16 & 0x00ff);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u8 val;
-
- if (reg->reg & ~0xffff)
- return -EINVAL;
-
- reg->size = 1;
-
- ret = reg_read(client, reg->reg, &val);
- if (!ret)
- reg->val = (__u64)val;
-
- return ret;
-}
-
-static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg & ~0xffff || reg->val & ~0xff)
- return -EINVAL;
-
- return reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov5642_write_array(struct i2c_client *client,
- struct regval_list *vals)
-{
- while (vals->reg_num != 0xffff || vals->value != 0xff) {
- int ret = reg_write(client, vals->reg_num, vals->value);
- if (ret < 0)
- return ret;
- vals++;
- }
- dev_dbg(&client->dev, "Register list loaded\n");
- return 0;
-}
-
-static int ov5642_set_resolution(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
- int width = priv->crop_rect.width;
- int height = priv->crop_rect.height;
- int total_width = priv->total_width;
- int total_height = priv->total_height;
- int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
- int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
- int ret;
-
- /*
- * This should set the starting point for cropping.
- * Doesn't work so far.
- */
- ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
- if (!ret)
- ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
- if (!ret) {
- priv->crop_rect.left = start_x;
- priv->crop_rect.top = start_y;
- }
-
- if (!ret)
- ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
- if (!ret)
- ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
- if (ret)
- return ret;
- priv->crop_rect.width = width;
- priv->crop_rect.height = height;
-
- /* Set the output window size. Only 1:1 scale is supported so far. */
- ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
- if (!ret)
- ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
-
- /* Total width = output size + blanking */
- if (!ret)
- ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
- if (!ret)
- ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
-
- /* Sets the window for AWB calculations */
- if (!ret)
- ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
- if (!ret)
- ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
-
- return ret;
-}
-
-static int ov5642_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
- const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
-
- mf->width = priv->crop_rect.width;
- mf->height = priv->crop_rect.height;
-
- if (!fmt) {
- mf->code = ov5642_colour_fmts[0].code;
- mf->colorspace = ov5642_colour_fmts[0].colorspace;
- }
-
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int ov5642_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
-
- /* MIPI CSI could have changed the format, double-check */
- if (!ov5642_find_datafmt(mf->code))
- return -EINVAL;
-
- ov5642_try_fmt(sd, mf);
- priv->fmt = ov5642_find_datafmt(mf->code);
-
- return 0;
-}
-
-static int ov5642_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
-
- const struct ov5642_datafmt *fmt = priv->fmt;
-
- mf->code = fmt->code;
- mf->colorspace = fmt->colorspace;
- mf->width = priv->crop_rect.width;
- mf->height = priv->crop_rect.height;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov5642_colour_fmts))
- return -EINVAL;
-
- *code = ov5642_colour_fmts[index].code;
- return 0;
-}
-
-static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_OV5642;
- id->revision = 0;
-
- return 0;
-}
-
-static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
- struct v4l2_rect *rect = &a->c;
- int ret;
-
- v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1,
- &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0);
-
- priv->crop_rect.width = rect->width;
- priv->crop_rect.height = rect->height;
- priv->total_width = rect->width + BLANKING_EXTRA_WIDTH;
- priv->total_height = max_t(int, rect->height +
- BLANKING_EXTRA_HEIGHT,
- BLANKING_MIN_HEIGHT);
- priv->crop_rect.width = rect->width;
- priv->crop_rect.height = rect->height;
-
- ret = ov5642_write_array(client, ov5642_default_regs_init);
- if (!ret)
- ret = ov5642_set_resolution(sd);
- if (!ret)
- ret = ov5642_write_array(client, ov5642_default_regs_finalise);
-
- return ret;
-}
-
-static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5642 *priv = to_ov5642(client);
- struct v4l2_rect *rect = &a->c;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- *rect = priv->crop_rect;
-
- return 0;
-}
-
-static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = OV5642_MAX_WIDTH;
- a->bounds.height = OV5642_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- cfg->type = V4L2_MBUS_CSI2;
- cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
-
- return 0;
-}
-
-static int ov5642_s_power(struct v4l2_subdev *sd, int on)
-{
- struct i2c_client *client;
- int ret;
-
- if (!on)
- return 0;
-
- client = v4l2_get_subdevdata(sd);
- ret = ov5642_write_array(client, ov5642_default_regs_init);
- if (!ret)
- ret = ov5642_set_resolution(sd);
- if (!ret)
- ret = ov5642_write_array(client, ov5642_default_regs_finalise);
-
- return ret;
-}
-
-static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
- .s_mbus_fmt = ov5642_s_fmt,
- .g_mbus_fmt = ov5642_g_fmt,
- .try_mbus_fmt = ov5642_try_fmt,
- .enum_mbus_fmt = ov5642_enum_fmt,
- .s_crop = ov5642_s_crop,
- .g_crop = ov5642_g_crop,
- .cropcap = ov5642_cropcap,
- .g_mbus_config = ov5642_g_mbus_config,
-};
-
-static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
- .s_power = ov5642_s_power,
- .g_chip_ident = ov5642_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov5642_get_register,
- .s_register = ov5642_set_register,
-#endif
-};
-
-static struct v4l2_subdev_ops ov5642_subdev_ops = {
- .core = &ov5642_subdev_core_ops,
- .video = &ov5642_subdev_video_ops,
-};
-
-static int ov5642_video_probe(struct i2c_client *client)
-{
- int ret;
- u8 id_high, id_low;
- u16 id;
-
- /* Read sensor Model ID */
- ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
- if (ret < 0)
- return ret;
-
- id = id_high << 8;
-
- ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
- if (ret < 0)
- return ret;
-
- id |= id_low;
-
- dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
-
- if (id != 0x5642)
- return -ENODEV;
-
- return 0;
-}
-
-static int ov5642_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov5642 *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "OV5642: missing platform data!\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
-
- priv->fmt = &ov5642_colour_fmts[0];
-
- priv->crop_rect.width = OV5642_DEFAULT_WIDTH;
- priv->crop_rect.height = OV5642_DEFAULT_HEIGHT;
- priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
- priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
- priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
- priv->total_height = BLANKING_MIN_HEIGHT;
-
- ret = ov5642_video_probe(client);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- kfree(priv);
- return ret;
-}
-
-static int ov5642_remove(struct i2c_client *client)
-{
- struct ov5642 *priv = to_ov5642(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- if (icl->free_bus)
- icl->free_bus(icl);
- kfree(priv);
-
- return 0;
-}
-
-static const struct i2c_device_id ov5642_id[] = {
- { "ov5642", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov5642_id);
-
-static struct i2c_driver ov5642_i2c_driver = {
- .driver = {
- .name = "ov5642",
- },
- .probe = ov5642_probe,
- .remove = ov5642_remove,
- .id_table = ov5642_id,
-};
-
-module_i2c_driver(ov5642_i2c_driver);
-
-MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
-MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
deleted file mode 100644
index 3e028b1970dd..000000000000
--- a/drivers/media/video/ov6650.c
+++ /dev/null
@@ -1,1053 +0,0 @@
-/*
- * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor
- *
- * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
- *
- * Based on OmniVision OV96xx Camera Driver
- * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
- *
- * Based on ov772x camera driver:
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov7670 and soc_camera_platform driver,
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * Hardware specific bits initialy based on former work by Matt Callow
- * drivers/media/video/omap/sensor_ov6650.c
- * Copyright (C) 2006 Matt Callow
- *
- * 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/bitops.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-
-/* Register definitions */
-#define REG_GAIN 0x00 /* range 00 - 3F */
-#define REG_BLUE 0x01
-#define REG_RED 0x02
-#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */
-#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */
-
-#define REG_BRT 0x06
-
-#define REG_PIDH 0x0a
-#define REG_PIDL 0x0b
-
-#define REG_AECH 0x10
-#define REG_CLKRC 0x11 /* Data Format and Internal Clock */
- /* [7:6] Input system clock (MHz)*/
- /* 00=8, 01=12, 10=16, 11=24 */
- /* [5:0]: Internal Clock Pre-Scaler */
-#define REG_COMA 0x12 /* [7] Reset */
-#define REG_COMB 0x13
-#define REG_COMC 0x14
-#define REG_COMD 0x15
-#define REG_COML 0x16
-#define REG_HSTRT 0x17
-#define REG_HSTOP 0x18
-#define REG_VSTRT 0x19
-#define REG_VSTOP 0x1a
-#define REG_PSHFT 0x1b
-#define REG_MIDH 0x1c
-#define REG_MIDL 0x1d
-#define REG_HSYNS 0x1e
-#define REG_HSYNE 0x1f
-#define REG_COME 0x20
-#define REG_YOFF 0x21
-#define REG_UOFF 0x22
-#define REG_VOFF 0x23
-#define REG_AEW 0x24
-#define REG_AEB 0x25
-#define REG_COMF 0x26
-#define REG_COMG 0x27
-#define REG_COMH 0x28
-#define REG_COMI 0x29
-
-#define REG_FRARL 0x2b
-#define REG_COMJ 0x2c
-#define REG_COMK 0x2d
-#define REG_AVGY 0x2e
-#define REG_REF0 0x2f
-#define REG_REF1 0x30
-#define REG_REF2 0x31
-#define REG_FRAJH 0x32
-#define REG_FRAJL 0x33
-#define REG_FACT 0x34
-#define REG_L1AEC 0x35
-#define REG_AVGU 0x36
-#define REG_AVGV 0x37
-
-#define REG_SPCB 0x60
-#define REG_SPCC 0x61
-#define REG_GAM1 0x62
-#define REG_GAM2 0x63
-#define REG_GAM3 0x64
-#define REG_SPCD 0x65
-
-#define REG_SPCE 0x68
-#define REG_ADCL 0x69
-
-#define REG_RMCO 0x6c
-#define REG_GMCO 0x6d
-#define REG_BMCO 0x6e
-
-
-/* Register bits, values, etc. */
-#define OV6650_PIDH 0x66 /* high byte of product ID number */
-#define OV6650_PIDL 0x50 /* low byte of product ID number */
-#define OV6650_MIDH 0x7F /* high byte of mfg ID */
-#define OV6650_MIDL 0xA2 /* low byte of mfg ID */
-
-#define DEF_GAIN 0x00
-#define DEF_BLUE 0x80
-#define DEF_RED 0x80
-
-#define SAT_SHIFT 4
-#define SAT_MASK (0xf << SAT_SHIFT)
-#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK)
-
-#define HUE_EN BIT(5)
-#define HUE_MASK 0x1f
-#define DEF_HUE 0x10
-#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK))
-
-#define DEF_AECH 0x4D
-
-#define CLKRC_6MHz 0x00
-#define CLKRC_12MHz 0x40
-#define CLKRC_16MHz 0x80
-#define CLKRC_24MHz 0xc0
-#define CLKRC_DIV_MASK 0x3f
-#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1)
-
-#define COMA_RESET BIT(7)
-#define COMA_QCIF BIT(5)
-#define COMA_RAW_RGB BIT(4)
-#define COMA_RGB BIT(3)
-#define COMA_BW BIT(2)
-#define COMA_WORD_SWAP BIT(1)
-#define COMA_BYTE_SWAP BIT(0)
-#define DEF_COMA 0x00
-
-#define COMB_FLIP_V BIT(7)
-#define COMB_FLIP_H BIT(5)
-#define COMB_BAND_FILTER BIT(4)
-#define COMB_AWB BIT(2)
-#define COMB_AGC BIT(1)
-#define COMB_AEC BIT(0)
-#define DEF_COMB 0x5f
-
-#define COML_ONE_CHANNEL BIT(7)
-
-#define DEF_HSTRT 0x24
-#define DEF_HSTOP 0xd4
-#define DEF_VSTRT 0x04
-#define DEF_VSTOP 0x94
-
-#define COMF_HREF_LOW BIT(4)
-
-#define COMJ_PCLK_RISING BIT(4)
-#define COMJ_VSYNC_HIGH BIT(0)
-
-/* supported resolutions */
-#define W_QCIF (DEF_HSTOP - DEF_HSTRT)
-#define W_CIF (W_QCIF << 1)
-#define H_QCIF (DEF_VSTOP - DEF_VSTRT)
-#define H_CIF (H_QCIF << 1)
-
-#define FRAME_RATE_MAX 30
-
-
-struct ov6650_reg {
- u8 reg;
- u8 val;
-};
-
-struct ov6650 {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct {
- /* exposure/autoexposure cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
- };
- struct {
- /* gain/autogain cluster */
- struct v4l2_ctrl *autogain;
- struct v4l2_ctrl *gain;
- };
- struct {
- /* blue/red/autowhitebalance cluster */
- struct v4l2_ctrl *autowb;
- struct v4l2_ctrl *blue;
- struct v4l2_ctrl *red;
- };
- bool half_scale; /* scale down output by 2 */
- struct v4l2_rect rect; /* sensor cropping window */
- unsigned long pclk_limit; /* from host */
- unsigned long pclk_max; /* from resolution and format */
- struct v4l2_fract tpf; /* as requested with s_parm */
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-
-static enum v4l2_mbus_pixelcode ov6650_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_YVYU8_2X8,
- V4L2_MBUS_FMT_VYUY8_2X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_Y8_1X8,
-};
-
-/* read a register */
-static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
-{
- int ret;
- u8 data = reg;
- struct i2c_msg msg = {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = &data,
- };
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0)
- goto err;
-
- msg.flags = I2C_M_RD;
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0)
- goto err;
-
- *val = data;
- return 0;
-
-err:
- dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
- return ret;
-}
-
-/* write a register */
-static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val)
-{
- int ret;
- unsigned char data[2] = { reg, val };
- struct i2c_msg msg = {
- .addr = client->addr,
- .flags = 0,
- .len = 2,
- .buf = data,
- };
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- udelay(100);
-
- if (ret < 0) {
- dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
- return ret;
- }
- return 0;
-}
-
-
-/* Read a register, alter its bits, write it back */
-static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask)
-{
- u8 val;
- int ret;
-
- ret = ov6650_reg_read(client, reg, &val);
- if (ret) {
- dev_err(&client->dev,
- "[Read]-Modify-Write of register 0x%02x failed!\n",
- reg);
- return ret;
- }
-
- val &= ~mask;
- val |= set;
-
- ret = ov6650_reg_write(client, reg, val);
- if (ret)
- dev_err(&client->dev,
- "Read-Modify-[Write] of register 0x%02x failed!\n",
- reg);
-
- return ret;
-}
-
-static struct ov6650 *to_ov6650(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct ov6650, subdev);
-}
-
-/* Start/Stop streaming from the device */
-static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
-{
- return 0;
-}
-
-/* Get status of additional camera capabilities */
-static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
- struct v4l2_subdev *sd = &priv->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- uint8_t reg, reg2;
- int ret;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTOGAIN:
- ret = ov6650_reg_read(client, REG_GAIN, &reg);
- if (!ret)
- priv->gain->val = reg;
- return ret;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = ov6650_reg_read(client, REG_BLUE, &reg);
- if (!ret)
- ret = ov6650_reg_read(client, REG_RED, &reg2);
- if (!ret) {
- priv->blue->val = reg;
- priv->red->val = reg2;
- }
- return ret;
- case V4L2_CID_EXPOSURE_AUTO:
- ret = ov6650_reg_read(client, REG_AECH, &reg);
- if (!ret)
- priv->exposure->val = reg;
- return ret;
- }
- return -EINVAL;
-}
-
-/* Set status of additional camera capabilities */
-static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
- struct v4l2_subdev *sd = &priv->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTOGAIN:
- ret = ov6650_reg_rmw(client, REG_COMB,
- ctrl->val ? COMB_AGC : 0, COMB_AGC);
- if (!ret && !ctrl->val)
- ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val);
- return ret;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = ov6650_reg_rmw(client, REG_COMB,
- ctrl->val ? COMB_AWB : 0, COMB_AWB);
- if (!ret && !ctrl->val) {
- ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val);
- if (!ret)
- ret = ov6650_reg_write(client, REG_RED,
- priv->red->val);
- }
- return ret;
- case V4L2_CID_SATURATION:
- return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val),
- SAT_MASK);
- case V4L2_CID_HUE:
- return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val),
- HUE_MASK);
- case V4L2_CID_BRIGHTNESS:
- return ov6650_reg_write(client, REG_BRT, ctrl->val);
- case V4L2_CID_EXPOSURE_AUTO:
- ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val ==
- V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC);
- if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL)
- ret = ov6650_reg_write(client, REG_AECH,
- priv->exposure->val);
- return ret;
- case V4L2_CID_GAMMA:
- return ov6650_reg_write(client, REG_GAM1, ctrl->val);
- case V4L2_CID_VFLIP:
- return ov6650_reg_rmw(client, REG_COMB,
- ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V);
- case V4L2_CID_HFLIP:
- return ov6650_reg_rmw(client, REG_COMB,
- ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H);
- }
-
- return -EINVAL;
-}
-
-/* Get chip identification */
-static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- id->ident = V4L2_IDENT_OV6650;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov6650_get_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u8 val;
-
- if (reg->reg & ~0xff)
- return -EINVAL;
-
- reg->size = 1;
-
- ret = ov6650_reg_read(client, reg->reg, &val);
- if (!ret)
- reg->val = (__u64)val;
-
- return ret;
-}
-
-static int ov6650_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg & ~0xff || reg->val & ~0xff)
- return -EINVAL;
-
- return ov6650_reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
-
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->c = priv->rect;
-
- return 0;
-}
-
-static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
- struct v4l2_rect *rect = &a->c;
- int ret;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- rect->left = ALIGN(rect->left, 2);
- rect->width = ALIGN(rect->width, 2);
- rect->top = ALIGN(rect->top, 2);
- rect->height = ALIGN(rect->height, 2);
- soc_camera_limit_side(&rect->left, &rect->width,
- DEF_HSTRT << 1, 2, W_CIF);
- soc_camera_limit_side(&rect->top, &rect->height,
- DEF_VSTRT << 1, 2, H_CIF);
-
- ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1);
- if (!ret) {
- priv->rect.left = rect->left;
- ret = ov6650_reg_write(client, REG_HSTOP,
- (rect->left + rect->width) >> 1);
- }
- if (!ret) {
- priv->rect.width = rect->width;
- ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1);
- }
- if (!ret) {
- priv->rect.top = rect->top;
- ret = ov6650_reg_write(client, REG_VSTOP,
- (rect->top + rect->height) >> 1);
- }
- if (!ret)
- priv->rect.height = rect->height;
-
- return ret;
-}
-
-static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- a->bounds.left = DEF_HSTRT << 1;
- a->bounds.top = DEF_VSTRT << 1;
- a->bounds.width = W_CIF;
- a->bounds.height = H_CIF;
- a->defrect = a->bounds;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov6650_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
-
- mf->width = priv->rect.width >> priv->half_scale;
- mf->height = priv->rect.height >> priv->half_scale;
- mf->code = priv->code;
- mf->colorspace = priv->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
-{
- return width > rect->width >> 1 || height > rect->height >> 1;
-}
-
-static u8 to_clkrc(struct v4l2_fract *timeperframe,
- unsigned long pclk_limit, unsigned long pclk_max)
-{
- unsigned long pclk;
-
- if (timeperframe->numerator && timeperframe->denominator)
- pclk = pclk_max * timeperframe->denominator /
- (FRAME_RATE_MAX * timeperframe->numerator);
- else
- pclk = pclk_max;
-
- if (pclk_limit && pclk_limit < pclk)
- pclk = pclk_limit;
-
- return (pclk_max - 1) / pclk;
-}
-
-/* set the format we will capture in */
-static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
- struct soc_camera_sense *sense = icd->sense;
- struct ov6650 *priv = to_ov6650(client);
- bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
- struct v4l2_crop a = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .c = {
- .left = priv->rect.left + (priv->rect.width >> 1) -
- (mf->width >> (1 - half_scale)),
- .top = priv->rect.top + (priv->rect.height >> 1) -
- (mf->height >> (1 - half_scale)),
- .width = mf->width << half_scale,
- .height = mf->height << half_scale,
- },
- };
- enum v4l2_mbus_pixelcode code = mf->code;
- unsigned long mclk, pclk;
- u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
- int ret;
-
- /* select color matrix configuration for given color encoding */
- switch (code) {
- case V4L2_MBUS_FMT_Y8_1X8:
- dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
- coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
- coma_set |= COMA_BW;
- break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
- coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
- coma_set |= COMA_WORD_SWAP;
- break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
- dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
- coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
- COMA_BYTE_SWAP;
- break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
- if (half_scale) {
- coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
- coma_set |= COMA_BYTE_SWAP;
- } else {
- coma_mask |= COMA_RGB | COMA_BW;
- coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
- }
- break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
- dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
- if (half_scale) {
- coma_mask |= COMA_RGB | COMA_BW;
- coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
- } else {
- coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
- coma_set |= COMA_BYTE_SWAP;
- }
- break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
- coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
- coma_set |= COMA_RAW_RGB | COMA_RGB;
- break;
- default:
- dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
- return -EINVAL;
- }
- priv->code = code;
-
- if (code == V4L2_MBUS_FMT_Y8_1X8 ||
- code == V4L2_MBUS_FMT_SBGGR8_1X8) {
- coml_mask = COML_ONE_CHANNEL;
- coml_set = 0;
- priv->pclk_max = 4000000;
- } else {
- coml_mask = 0;
- coml_set = COML_ONE_CHANNEL;
- priv->pclk_max = 8000000;
- }
-
- if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
- priv->colorspace = V4L2_COLORSPACE_SRGB;
- else if (code != 0)
- priv->colorspace = V4L2_COLORSPACE_JPEG;
-
- if (half_scale) {
- dev_dbg(&client->dev, "max resolution: QCIF\n");
- coma_set |= COMA_QCIF;
- priv->pclk_max /= 2;
- } else {
- dev_dbg(&client->dev, "max resolution: CIF\n");
- coma_mask |= COMA_QCIF;
- }
- priv->half_scale = half_scale;
-
- if (sense) {
- if (sense->master_clock == 8000000) {
- dev_dbg(&client->dev, "8MHz input clock\n");
- clkrc = CLKRC_6MHz;
- } else if (sense->master_clock == 12000000) {
- dev_dbg(&client->dev, "12MHz input clock\n");
- clkrc = CLKRC_12MHz;
- } else if (sense->master_clock == 16000000) {
- dev_dbg(&client->dev, "16MHz input clock\n");
- clkrc = CLKRC_16MHz;
- } else if (sense->master_clock == 24000000) {
- dev_dbg(&client->dev, "24MHz input clock\n");
- clkrc = CLKRC_24MHz;
- } else {
- dev_err(&client->dev,
- "unsupported input clock, check platform data\n");
- return -EINVAL;
- }
- mclk = sense->master_clock;
- priv->pclk_limit = sense->pixel_clock_max;
- } else {
- clkrc = CLKRC_24MHz;
- mclk = 24000000;
- priv->pclk_limit = 0;
- dev_dbg(&client->dev, "using default 24MHz input clock\n");
- }
-
- clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
-
- pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
- dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
- mclk / pclk, 10 * mclk % pclk / pclk);
-
- ret = ov6650_s_crop(sd, &a);
- if (!ret)
- ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
- if (!ret)
- ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
- if (!ret)
- ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
-
- if (!ret) {
- mf->colorspace = priv->colorspace;
- mf->width = priv->rect.width >> half_scale;
- mf->height = priv->rect.height >> half_scale;
- }
-
- return ret;
-}
-
-static int ov6650_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
-
- if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
- v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
- &mf->height, 2, H_CIF, 1, 0);
-
- mf->field = V4L2_FIELD_NONE;
-
- switch (mf->code) {
- case V4L2_MBUS_FMT_Y10_1X10:
- mf->code = V4L2_MBUS_FMT_Y8_1X8;
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- break;
- default:
- mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- }
-
- return 0;
-}
-
-static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov6650_codes))
- return -EINVAL;
-
- *code = ov6650_codes[index];
- return 0;
-}
-
-static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
- 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 = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
- priv->pclk_limit, priv->pclk_max));
- cp->timeperframe.denominator = FRAME_RATE_MAX;
-
- dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
- cp->timeperframe.numerator, cp->timeperframe.denominator);
-
- return 0;
-}
-
-static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov6650 *priv = to_ov6650(client);
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
- int div, ret;
- u8 clkrc;
-
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cp->extendedmode != 0)
- return -EINVAL;
-
- if (tpf->numerator == 0 || tpf->denominator == 0)
- div = 1; /* Reset to full rate */
- else
- div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator;
-
- if (div == 0)
- div = 1;
- else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
- div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
-
- /*
- * Keep result to be used as tpf limit
- * for subseqent clock divider calculations
- */
- priv->tpf.numerator = div;
- priv->tpf.denominator = FRAME_RATE_MAX;
-
- clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
-
- ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
- if (!ret) {
- tpf->numerator = GET_CLKRC_DIV(clkrc);
- tpf->denominator = FRAME_RATE_MAX;
- }
-
- return ret;
-}
-
-/* Soft reset the camera. This has nothing to do with the RESET pin! */
-static int ov6650_reset(struct i2c_client *client)
-{
- int ret;
-
- dev_dbg(&client->dev, "reset\n");
-
- ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
- if (ret)
- dev_err(&client->dev,
- "An error occurred while entering soft reset!\n");
-
- return ret;
-}
-
-/* program default register values */
-static int ov6650_prog_dflt(struct i2c_client *client)
-{
- int ret;
-
- dev_dbg(&client->dev, "initializing\n");
-
- ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */
- if (!ret)
- ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
-
- return ret;
-}
-
-static int ov6650_video_probe(struct i2c_client *client)
-{
- u8 pidh, pidl, midh, midl;
- int ret = 0;
-
- /*
- * check and show product ID and manufacturer ID
- */
- ret = ov6650_reg_read(client, REG_PIDH, &pidh);
- if (!ret)
- ret = ov6650_reg_read(client, REG_PIDL, &pidl);
- if (!ret)
- ret = ov6650_reg_read(client, REG_MIDH, &midh);
- if (!ret)
- ret = ov6650_reg_read(client, REG_MIDL, &midl);
-
- if (ret)
- return ret;
-
- if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) {
- dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n",
- pidh, pidl);
- return -ENODEV;
- }
-
- dev_info(&client->dev,
- "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n",
- pidh, pidl, midh, midl);
-
- ret = ov6650_reset(client);
- if (!ret)
- ret = ov6650_prog_dflt(client);
-
- return ret;
-}
-
-static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
- .g_volatile_ctrl = ov6550_g_volatile_ctrl,
- .s_ctrl = ov6550_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops ov6650_core_ops = {
- .g_chip_ident = ov6650_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov6650_get_register,
- .s_register = ov6650_set_register,
-#endif
-};
-
-/* Request bus settings on camera side */
-static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_MASTER |
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-/* Alter bus settings on camera side */
-static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
- int ret;
-
- if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
- else
- ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
- if (ret)
- return ret;
-
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
- else
- ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
- if (ret)
- return ret;
-
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
- ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
- else
- ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
-
- return ret;
-}
-
-static struct v4l2_subdev_video_ops ov6650_video_ops = {
- .s_stream = ov6650_s_stream,
- .g_mbus_fmt = ov6650_g_fmt,
- .s_mbus_fmt = ov6650_s_fmt,
- .try_mbus_fmt = ov6650_try_fmt,
- .enum_mbus_fmt = ov6650_enum_fmt,
- .cropcap = ov6650_cropcap,
- .g_crop = ov6650_g_crop,
- .s_crop = ov6650_s_crop,
- .g_parm = ov6650_g_parm,
- .s_parm = ov6650_s_parm,
- .g_mbus_config = ov6650_g_mbus_config,
- .s_mbus_config = ov6650_s_mbus_config,
-};
-
-static struct v4l2_subdev_ops ov6650_subdev_ops = {
- .core = &ov6650_core_ops,
- .video = &ov6650_video_ops,
-};
-
-/*
- * i2c_driver function
- */
-static int ov6650_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov6650 *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "Missing platform_data for driver\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&client->dev,
- "Failed to allocate memory for private data!\n");
- return -ENOMEM;
- }
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
- v4l2_ctrl_handler_init(&priv->hdl, 13);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN);
- priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE);
- priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_SATURATION, 0, 0xf, 1, 0x8);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80);
- priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl,
- &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
- V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
- priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH);
- v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
- V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
-
- priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
- v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
- v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
- v4l2_ctrl_auto_cluster(2, &priv->autoexposure,
- V4L2_EXPOSURE_MANUAL, true);
-
- priv->rect.left = DEF_HSTRT << 1;
- priv->rect.top = DEF_VSTRT << 1;
- priv->rect.width = W_CIF;
- priv->rect.height = H_CIF;
- priv->half_scale = false;
- priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
- priv->colorspace = V4L2_COLORSPACE_JPEG;
-
- ret = ov6650_video_probe(client);
- if (!ret)
- ret = v4l2_ctrl_handler_setup(&priv->hdl);
-
- if (ret) {
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
-
- return ret;
-}
-
-static int ov6650_remove(struct i2c_client *client)
-{
- struct ov6650 *priv = to_ov6650(client);
-
- v4l2_device_unregister_subdev(&priv->subdev);
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id ov6650_id[] = {
- { "ov6650", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov6650_id);
-
-static struct i2c_driver ov6650_i2c_driver = {
- .driver = {
- .name = "ov6650",
- },
- .probe = ov6650_probe,
- .remove = ov6650_remove,
- .id_table = ov6650_id,
-};
-
-module_i2c_driver(ov6650_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
-MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
deleted file mode 100644
index 6d79b89b8603..000000000000
--- a/drivers/media/video/ov772x.c
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * ov772x Camera Driver
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov7670 and soc_camera_platform driver,
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/ov772x.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-subdev.h>
-
-/*
- * register offset
- */
-#define GAIN 0x00 /* AGC - Gain control gain setting */
-#define BLUE 0x01 /* AWB - Blue channel gain setting */
-#define RED 0x02 /* AWB - Red channel gain setting */
-#define GREEN 0x03 /* AWB - Green channel gain setting */
-#define COM1 0x04 /* Common control 1 */
-#define BAVG 0x05 /* U/B Average Level */
-#define GAVG 0x06 /* Y/Gb Average Level */
-#define RAVG 0x07 /* V/R Average Level */
-#define AECH 0x08 /* Exposure Value - AEC MSBs */
-#define COM2 0x09 /* Common control 2 */
-#define PID 0x0A /* Product ID Number MSB */
-#define VER 0x0B /* Product ID Number LSB */
-#define COM3 0x0C /* Common control 3 */
-#define COM4 0x0D /* Common control 4 */
-#define COM5 0x0E /* Common control 5 */
-#define COM6 0x0F /* Common control 6 */
-#define AEC 0x10 /* Exposure Value */
-#define CLKRC 0x11 /* Internal clock */
-#define COM7 0x12 /* Common control 7 */
-#define COM8 0x13 /* Common control 8 */
-#define COM9 0x14 /* Common control 9 */
-#define COM10 0x15 /* Common control 10 */
-#define REG16 0x16 /* Register 16 */
-#define HSTART 0x17 /* Horizontal sensor size */
-#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */
-#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */
-#define VSIZE 0x1A /* Vertical sensor size */
-#define PSHFT 0x1B /* Data format - pixel delay select */
-#define MIDH 0x1C /* Manufacturer ID byte - high */
-#define MIDL 0x1D /* Manufacturer ID byte - low */
-#define LAEC 0x1F /* Fine AEC value */
-#define COM11 0x20 /* Common control 11 */
-#define BDBASE 0x22 /* Banding filter Minimum AEC value */
-#define DBSTEP 0x23 /* Banding filter Maximum Setp */
-#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
-#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
-#define VPT 0x26 /* AGC/AEC Fast mode operating region */
-#define REG28 0x28 /* Register 28 */
-#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */
-#define EXHCH 0x2A /* Dummy pixel insert MSB */
-#define EXHCL 0x2B /* Dummy pixel insert LSB */
-#define VOUTSIZE 0x2C /* Vertical data output size MSBs */
-#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
-#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */
-#define YAVE 0x2F /* Y/G Channel Average value */
-#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */
-#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */
-#define HREF 0x32 /* Image start and size control */
-#define DM_LNL 0x33 /* Dummy line low 8 bits */
-#define DM_LNH 0x34 /* Dummy line high 8 bits */
-#define ADOFF_B 0x35 /* AD offset compensation value for B channel */
-#define ADOFF_R 0x36 /* AD offset compensation value for R channel */
-#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */
-#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */
-#define OFF_B 0x39 /* Analog process B channel offset value */
-#define OFF_R 0x3A /* Analog process R channel offset value */
-#define OFF_GB 0x3B /* Analog process Gb channel offset value */
-#define OFF_GR 0x3C /* Analog process Gr channel offset value */
-#define COM12 0x3D /* Common control 12 */
-#define COM13 0x3E /* Common control 13 */
-#define COM14 0x3F /* Common control 14 */
-#define COM15 0x40 /* Common control 15*/
-#define COM16 0x41 /* Common control 16 */
-#define TGT_B 0x42 /* BLC blue channel target value */
-#define TGT_R 0x43 /* BLC red channel target value */
-#define TGT_GB 0x44 /* BLC Gb channel target value */
-#define TGT_GR 0x45 /* BLC Gr channel target value */
-/* for ov7720 */
-#define LCC0 0x46 /* Lens correction control 0 */
-#define LCC1 0x47 /* Lens correction option 1 - X coordinate */
-#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */
-#define LCC3 0x49 /* Lens correction option 3 */
-#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */
-#define LCC5 0x4B /* Lens correction option 5 */
-#define LCC6 0x4C /* Lens correction option 6 */
-/* for ov7725 */
-#define LC_CTR 0x46 /* Lens correction control */
-#define LC_XC 0x47 /* X coordinate of lens correction center relative */
-#define LC_YC 0x48 /* Y coordinate of lens correction center relative */
-#define LC_COEF 0x49 /* Lens correction coefficient */
-#define LC_RADI 0x4A /* Lens correction radius */
-#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */
-#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */
-
-#define FIXGAIN 0x4D /* Analog fix gain amplifer */
-#define AREF0 0x4E /* Sensor reference control */
-#define AREF1 0x4F /* Sensor reference current control */
-#define AREF2 0x50 /* Analog reference control */
-#define AREF3 0x51 /* ADC reference control */
-#define AREF4 0x52 /* ADC reference control */
-#define AREF5 0x53 /* ADC reference control */
-#define AREF6 0x54 /* Analog reference control */
-#define AREF7 0x55 /* Analog reference control */
-#define UFIX 0x60 /* U channel fixed value output */
-#define VFIX 0x61 /* V channel fixed value output */
-#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
-#define AWB_CTRL0 0x63 /* AWB control byte 0 */
-#define DSP_CTRL1 0x64 /* DSP control byte 1 */
-#define DSP_CTRL2 0x65 /* DSP control byte 2 */
-#define DSP_CTRL3 0x66 /* DSP control byte 3 */
-#define DSP_CTRL4 0x67 /* DSP control byte 4 */
-#define AWB_BIAS 0x68 /* AWB BLC level clip */
-#define AWB_CTRL1 0x69 /* AWB control 1 */
-#define AWB_CTRL2 0x6A /* AWB control 2 */
-#define AWB_CTRL3 0x6B /* AWB control 3 */
-#define AWB_CTRL4 0x6C /* AWB control 4 */
-#define AWB_CTRL5 0x6D /* AWB control 5 */
-#define AWB_CTRL6 0x6E /* AWB control 6 */
-#define AWB_CTRL7 0x6F /* AWB control 7 */
-#define AWB_CTRL8 0x70 /* AWB control 8 */
-#define AWB_CTRL9 0x71 /* AWB control 9 */
-#define AWB_CTRL10 0x72 /* AWB control 10 */
-#define AWB_CTRL11 0x73 /* AWB control 11 */
-#define AWB_CTRL12 0x74 /* AWB control 12 */
-#define AWB_CTRL13 0x75 /* AWB control 13 */
-#define AWB_CTRL14 0x76 /* AWB control 14 */
-#define AWB_CTRL15 0x77 /* AWB control 15 */
-#define AWB_CTRL16 0x78 /* AWB control 16 */
-#define AWB_CTRL17 0x79 /* AWB control 17 */
-#define AWB_CTRL18 0x7A /* AWB control 18 */
-#define AWB_CTRL19 0x7B /* AWB control 19 */
-#define AWB_CTRL20 0x7C /* AWB control 20 */
-#define AWB_CTRL21 0x7D /* AWB control 21 */
-#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
-#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
-#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
-#define GAM4 0x81 /* Gamma Curve 4th segment input end point */
-#define GAM5 0x82 /* Gamma Curve 5th segment input end point */
-#define GAM6 0x83 /* Gamma Curve 6th segment input end point */
-#define GAM7 0x84 /* Gamma Curve 7th segment input end point */
-#define GAM8 0x85 /* Gamma Curve 8th segment input end point */
-#define GAM9 0x86 /* Gamma Curve 9th segment input end point */
-#define GAM10 0x87 /* Gamma Curve 10th segment input end point */
-#define GAM11 0x88 /* Gamma Curve 11th segment input end point */
-#define GAM12 0x89 /* Gamma Curve 12th segment input end point */
-#define GAM13 0x8A /* Gamma Curve 13th segment input end point */
-#define GAM14 0x8B /* Gamma Curve 14th segment input end point */
-#define GAM15 0x8C /* Gamma Curve 15th segment input end point */
-#define SLOP 0x8D /* Gamma curve highest segment slope */
-#define DNSTH 0x8E /* De-noise threshold */
-#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */
-#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
-#define DNSOFF 0x91 /* Auto De-noise threshold control */
-#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */
-#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */
-#define MTX1 0x94 /* Matrix coefficient 1 */
-#define MTX2 0x95 /* Matrix coefficient 2 */
-#define MTX3 0x96 /* Matrix coefficient 3 */
-#define MTX4 0x97 /* Matrix coefficient 4 */
-#define MTX5 0x98 /* Matrix coefficient 5 */
-#define MTX6 0x99 /* Matrix coefficient 6 */
-#define MTX_CTRL 0x9A /* Matrix control */
-#define BRIGHT 0x9B /* Brightness control */
-#define CNTRST 0x9C /* Contrast contrast */
-#define CNTRST_CTRL 0x9D /* Contrast contrast center */
-#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */
-#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */
-#define SCAL0 0xA0 /* Scaling control 0 */
-#define SCAL1 0xA1 /* Scaling control 1 */
-#define SCAL2 0xA2 /* Scaling control 2 */
-#define FIFODLYM 0xA3 /* FIFO manual mode delay control */
-#define FIFODLYA 0xA4 /* FIFO auto mode delay control */
-#define SDE 0xA6 /* Special digital effect control */
-#define USAT 0xA7 /* U component saturation control */
-#define VSAT 0xA8 /* V component saturation control */
-/* for ov7720 */
-#define HUE0 0xA9 /* Hue control 0 */
-#define HUE1 0xAA /* Hue control 1 */
-/* for ov7725 */
-#define HUECOS 0xA9 /* Cosine value */
-#define HUESIN 0xAA /* Sine value */
-
-#define SIGN 0xAB /* Sign bit for Hue and contrast */
-#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */
-
-/*
- * register detail
- */
-
-/* COM2 */
-#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
- /* Output drive capability */
-#define OCAP_1x 0x00 /* 1x */
-#define OCAP_2x 0x01 /* 2x */
-#define OCAP_3x 0x02 /* 3x */
-#define OCAP_4x 0x03 /* 4x */
-
-/* COM3 */
-#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
-#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
-
-#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
-#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
-#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */
-#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */
-#define SWAP_ML 0x08 /* Swap output MSB/LSB */
- /* Tri-state option for output clock */
-#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */
- /* 1: No tri-state at this period */
- /* Tri-state option for output data */
-#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */
- /* 1: No tri-state at this period */
-#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */
-
-/* COM4 */
- /* PLL frequency control */
-#define PLL_BYPASS 0x00 /* 00: Bypass PLL */
-#define PLL_4x 0x40 /* 01: PLL 4x */
-#define PLL_6x 0x80 /* 10: PLL 6x */
-#define PLL_8x 0xc0 /* 11: PLL 8x */
- /* AEC evaluate window */
-#define AEC_FULL 0x00 /* 00: Full window */
-#define AEC_1p2 0x10 /* 01: 1/2 window */
-#define AEC_1p4 0x20 /* 10: 1/4 window */
-#define AEC_2p3 0x30 /* 11: Low 2/3 window */
-
-/* COM5 */
-#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */
-#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */
- /* Auto frame rate max rate control */
-#define AFR_NO_RATE 0x00 /* No reduction of frame rate */
-#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */
-#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */
-#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */
- /* Auto frame rate active point control */
-#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */
-#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */
-#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */
-#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */
- /* AEC max step control */
-#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */
- /* 1 : No limit to AEC increase step */
-
-/* COM7 */
- /* SCCB Register Reset */
-#define SCCB_RESET 0x80 /* 0 : No change */
- /* 1 : Resets all registers to default */
- /* Resolution selection */
-#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */
-#define SLCT_VGA 0x00 /* 0 : VGA */
-#define SLCT_QVGA 0x40 /* 1 : QVGA */
-#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */
- /* RGB output format control */
-#define FMT_MASK 0x0c /* Mask of color format */
-#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */
-#define FMT_RGB565 0x04 /* 01 : RGB 565 */
-#define FMT_RGB555 0x08 /* 10 : RGB 555 */
-#define FMT_RGB444 0x0c /* 11 : RGB 444 */
- /* Output format control */
-#define OFMT_MASK 0x03 /* Mask of output format */
-#define OFMT_YUV 0x00 /* 00 : YUV */
-#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */
-#define OFMT_RGB 0x02 /* 10 : RGB */
-#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */
-
-/* COM8 */
-#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */
- /* AEC Setp size limit */
-#define UNLMT_STEP 0x40 /* 0 : Step size is limited */
- /* 1 : Unlimited step size */
-#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */
-#define AEC_BND 0x10 /* Enable AEC below banding value */
-#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */
-#define AGC_ON 0x04 /* AGC Enable */
-#define AWB_ON 0x02 /* AWB Enable */
-#define AEC_ON 0x01 /* AEC Enable */
-
-/* COM9 */
-#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */
- /* Automatic gain ceiling - maximum AGC value */
-#define GAIN_2x 0x00 /* 000 : 2x */
-#define GAIN_4x 0x10 /* 001 : 4x */
-#define GAIN_8x 0x20 /* 010 : 8x */
-#define GAIN_16x 0x30 /* 011 : 16x */
-#define GAIN_32x 0x40 /* 100 : 32x */
-#define GAIN_64x 0x50 /* 101 : 64x */
-#define GAIN_128x 0x60 /* 110 : 128x */
-#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */
-#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */
-
-/* COM11 */
-#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */
-#define SGLF_TRIG 0x01 /* Single frame transfer trigger */
-
-/* EXHCH */
-#define VSIZE_LSB 0x04 /* Vertical data output size LSB */
-
-/* DSP_CTRL1 */
-#define FIFO_ON 0x80 /* FIFO enable/disable selection */
-#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */
-#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */
-#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */
-#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */
-#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */
-#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */
-#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */
-
-/* DSP_CTRL3 */
-#define UV_MASK 0x80 /* UV output sequence option */
-#define UV_ON 0x80 /* ON */
-#define UV_OFF 0x00 /* OFF */
-#define CBAR_MASK 0x20 /* DSP Color bar mask */
-#define CBAR_ON 0x20 /* ON */
-#define CBAR_OFF 0x00 /* OFF */
-
-/* HSTART */
-#define HST_VGA 0x23
-#define HST_QVGA 0x3F
-
-/* HSIZE */
-#define HSZ_VGA 0xA0
-#define HSZ_QVGA 0x50
-
-/* VSTART */
-#define VST_VGA 0x07
-#define VST_QVGA 0x03
-
-/* VSIZE */
-#define VSZ_VGA 0xF0
-#define VSZ_QVGA 0x78
-
-/* HOUTSIZE */
-#define HOSZ_VGA 0xA0
-#define HOSZ_QVGA 0x50
-
-/* VOUTSIZE */
-#define VOSZ_VGA 0xF0
-#define VOSZ_QVGA 0x78
-
-/* DSPAUTO (DSP Auto Function ON/OFF Control) */
-#define AWB_ACTRL 0x80 /* AWB auto threshold control */
-#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */
-#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */
-#define UV_ACTRL 0x10 /* UV adjust auto slope control */
-#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */
-#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */
-
-/*
- * ID
- */
-#define OV7720 0x7720
-#define OV7725 0x7721
-#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
-
-/*
- * struct
- */
-struct regval_list {
- unsigned char reg_num;
- unsigned char value;
-};
-
-struct ov772x_color_format {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
- u8 dsp3;
- u8 com3;
- u8 com7;
-};
-
-struct ov772x_win_size {
- char *name;
- __u32 width;
- __u32 height;
- unsigned char com7_bit;
- const struct regval_list *regs;
-};
-
-struct ov772x_priv {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct ov772x_camera_info *info;
- const struct ov772x_color_format *cfmt;
- const struct ov772x_win_size *win;
- int model;
- unsigned short flag_vflip:1;
- unsigned short flag_hflip:1;
- /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
- unsigned short band_filter;
-};
-
-#define ENDMARKER { 0xff, 0xff }
-
-/*
- * register setting for window size
- */
-static const struct regval_list ov772x_qvga_regs[] = {
- { HSTART, HST_QVGA },
- { HSIZE, HSZ_QVGA },
- { VSTART, VST_QVGA },
- { VSIZE, VSZ_QVGA },
- { HOUTSIZE, HOSZ_QVGA },
- { VOUTSIZE, VOSZ_QVGA },
- ENDMARKER,
-};
-
-static const struct regval_list ov772x_vga_regs[] = {
- { HSTART, HST_VGA },
- { HSIZE, HSZ_VGA },
- { VSTART, VST_VGA },
- { VSIZE, VSZ_VGA },
- { HOUTSIZE, HOSZ_VGA },
- { VOUTSIZE, VOSZ_VGA },
- ENDMARKER,
-};
-
-/*
- * supported color format list
- */
-static const struct ov772x_color_format ov772x_cfmts[] = {
- {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .dsp3 = 0x0,
- .com3 = SWAP_YUV,
- .com7 = OFMT_YUV,
- },
- {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .dsp3 = UV_ON,
- .com3 = SWAP_YUV,
- .com7 = OFMT_YUV,
- },
- {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .dsp3 = 0x0,
- .com3 = 0x0,
- .com7 = OFMT_YUV,
- },
- {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .dsp3 = 0x0,
- .com3 = SWAP_RGB,
- .com7 = FMT_RGB555 | OFMT_RGB,
- },
- {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .dsp3 = 0x0,
- .com3 = 0x0,
- .com7 = FMT_RGB555 | OFMT_RGB,
- },
- {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .dsp3 = 0x0,
- .com3 = SWAP_RGB,
- .com7 = FMT_RGB565 | OFMT_RGB,
- },
- {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .dsp3 = 0x0,
- .com3 = 0x0,
- .com7 = FMT_RGB565 | OFMT_RGB,
- },
-};
-
-
-/*
- * window size list
- */
-#define VGA_WIDTH 640
-#define VGA_HEIGHT 480
-#define QVGA_WIDTH 320
-#define QVGA_HEIGHT 240
-#define MAX_WIDTH VGA_WIDTH
-#define MAX_HEIGHT VGA_HEIGHT
-
-static const struct ov772x_win_size ov772x_win_vga = {
- .name = "VGA",
- .width = VGA_WIDTH,
- .height = VGA_HEIGHT,
- .com7_bit = SLCT_VGA,
- .regs = ov772x_vga_regs,
-};
-
-static const struct ov772x_win_size ov772x_win_qvga = {
- .name = "QVGA",
- .width = QVGA_WIDTH,
- .height = QVGA_HEIGHT,
- .com7_bit = SLCT_QVGA,
- .regs = ov772x_qvga_regs,
-};
-
-/*
- * general function
- */
-
-static struct ov772x_priv *to_ov772x(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct ov772x_priv,
- subdev);
-}
-
-static int ov772x_write_array(struct i2c_client *client,
- const struct regval_list *vals)
-{
- while (vals->reg_num != 0xff) {
- int ret = i2c_smbus_write_byte_data(client,
- vals->reg_num,
- vals->value);
- if (ret < 0)
- return ret;
- vals++;
- }
- return 0;
-}
-
-static int ov772x_mask_set(struct i2c_client *client,
- u8 command,
- u8 mask,
- u8 set)
-{
- s32 val = i2c_smbus_read_byte_data(client, command);
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- return i2c_smbus_write_byte_data(client, command, val);
-}
-
-static int ov772x_reset(struct i2c_client *client)
-{
- int ret = i2c_smbus_write_byte_data(client, COM7, SCCB_RESET);
- msleep(1);
- return ret;
-}
-
-/*
- * soc_camera_ops function
- */
-
-static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
-
- if (!enable) {
- ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
- return 0;
- }
-
- if (!priv->win || !priv->cfmt) {
- dev_err(&client->dev, "norm or win select error\n");
- return -EPERM;
- }
-
- ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
-
- dev_dbg(&client->dev, "format %d, win %s\n",
- priv->cfmt->code, priv->win->name);
-
- return 0;
-}
-
-static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov772x_priv *priv = container_of(ctrl->handler,
- struct ov772x_priv, hdl);
- struct v4l2_subdev *sd = &priv->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
- u8 val;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- val = ctrl->val ? VFLIP_IMG : 0x00;
- priv->flag_vflip = ctrl->val;
- if (priv->info->flags & OV772X_FLAG_VFLIP)
- val ^= VFLIP_IMG;
- return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
- case V4L2_CID_HFLIP:
- val = ctrl->val ? HFLIP_IMG : 0x00;
- priv->flag_hflip = ctrl->val;
- if (priv->info->flags & OV772X_FLAG_HFLIP)
- val ^= HFLIP_IMG;
- return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
- case V4L2_CID_BAND_STOP_FILTER:
- if (!ctrl->val) {
- /* Switch the filter off, it is on now */
- ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
- if (!ret)
- ret = ov772x_mask_set(client, COM8,
- BNDF_ON_OFF, 0);
- } else {
- /* Switch the filter on, set AEC low limit */
- val = 256 - ctrl->val;
- ret = ov772x_mask_set(client, COM8,
- BNDF_ON_OFF, BNDF_ON_OFF);
- if (!ret)
- ret = ov772x_mask_set(client, BDBASE,
- 0xff, val);
- }
- if (!ret)
- priv->band_filter = ctrl->val;
- return ret;
- }
-
- return -EINVAL;
-}
-
-static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
-
- id->ident = priv->model;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov772x_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- reg->size = 1;
- if (reg->reg > 0xff)
- return -EINVAL;
-
- ret = i2c_smbus_read_byte_data(client, reg->reg);
- if (ret < 0)
- return ret;
-
- reg->val = (__u64)ret;
-
- return 0;
-}
-
-static int ov772x_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg > 0xff ||
- reg->val > 0xff)
- return -EINVAL;
-
- return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
-}
-#endif
-
-static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
-{
- __u32 diff;
- const struct ov772x_win_size *win;
-
- /* default is QVGA */
- diff = abs(width - ov772x_win_qvga.width) +
- abs(height - ov772x_win_qvga.height);
- win = &ov772x_win_qvga;
-
- /* VGA */
- if (diff >
- abs(width - ov772x_win_vga.width) +
- abs(height - ov772x_win_vga.height))
- win = &ov772x_win_vga;
-
- return win;
-}
-
-static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height,
- enum v4l2_mbus_pixelcode code)
-{
- struct ov772x_priv *priv = to_ov772x(client);
- int ret = -EINVAL;
- u8 val;
- int i;
-
- /*
- * select format
- */
- priv->cfmt = NULL;
- for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
- if (code == ov772x_cfmts[i].code) {
- priv->cfmt = ov772x_cfmts + i;
- break;
- }
- }
- if (!priv->cfmt)
- goto ov772x_set_fmt_error;
-
- /*
- * select win
- */
- priv->win = ov772x_select_win(*width, *height);
-
- /*
- * reset hardware
- */
- ov772x_reset(client);
-
- /*
- * Edge Ctrl
- */
- if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
-
- /*
- * Manual Edge Control Mode
- *
- * Edge auto strength bit is set by default.
- * Remove it when manual mode.
- */
-
- ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- ret = ov772x_mask_set(client,
- EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
- priv->info->edgectrl.threshold);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- ret = ov772x_mask_set(client,
- EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
- priv->info->edgectrl.strength);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
- /*
- * Auto Edge Control Mode
- *
- * set upper and lower limit
- */
- ret = ov772x_mask_set(client,
- EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
- priv->info->edgectrl.upper);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- ret = ov772x_mask_set(client,
- EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
- priv->info->edgectrl.lower);
- if (ret < 0)
- goto ov772x_set_fmt_error;
- }
-
- /*
- * set size format
- */
- ret = ov772x_write_array(client, priv->win->regs);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- /*
- * set DSP_CTRL3
- */
- val = priv->cfmt->dsp3;
- if (val) {
- ret = ov772x_mask_set(client,
- DSP_CTRL3, UV_MASK, val);
- if (ret < 0)
- goto ov772x_set_fmt_error;
- }
-
- /*
- * set COM3
- */
- val = priv->cfmt->com3;
- if (priv->info->flags & OV772X_FLAG_VFLIP)
- val |= VFLIP_IMG;
- if (priv->info->flags & OV772X_FLAG_HFLIP)
- val |= HFLIP_IMG;
- if (priv->flag_vflip)
- val ^= VFLIP_IMG;
- if (priv->flag_hflip)
- val ^= HFLIP_IMG;
-
- ret = ov772x_mask_set(client,
- COM3, SWAP_MASK | IMG_MASK, val);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- /*
- * set COM7
- */
- val = priv->win->com7_bit | priv->cfmt->com7;
- ret = ov772x_mask_set(client,
- COM7, SLCT_MASK | FMT_MASK | OFMT_MASK,
- val);
- if (ret < 0)
- goto ov772x_set_fmt_error;
-
- /*
- * set COM8
- */
- if (priv->band_filter) {
- ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
- if (!ret)
- ret = ov772x_mask_set(client, BDBASE,
- 0xff, 256 - priv->band_filter);
- if (ret < 0)
- goto ov772x_set_fmt_error;
- }
-
- *width = priv->win->width;
- *height = priv->win->height;
-
- return ret;
-
-ov772x_set_fmt_error:
-
- ov772x_reset(client);
- priv->win = NULL;
- priv->cfmt = NULL;
-
- return ret;
-}
-
-static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = VGA_WIDTH;
- a->c.height = VGA_HEIGHT;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = VGA_WIDTH;
- a->bounds.height = VGA_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov772x_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
-
- if (!priv->win || !priv->cfmt) {
- priv->cfmt = &ov772x_cfmts[0];
- priv->win = ov772x_select_win(VGA_WIDTH, VGA_HEIGHT);
- }
-
- mf->width = priv->win->width;
- mf->height = priv->win->height;
- mf->code = priv->cfmt->code;
- mf->colorspace = priv->cfmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
-
- return 0;
-}
-
-static int ov772x_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
- int ret = ov772x_set_params(client, &mf->width, &mf->height,
- mf->code);
-
- if (!ret)
- mf->colorspace = priv->cfmt->colorspace;
-
- return ret;
-}
-
-static int ov772x_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
- const struct ov772x_win_size *win;
- int i;
-
- /*
- * select suitable win
- */
- win = ov772x_select_win(mf->width, mf->height);
-
- mf->width = win->width;
- mf->height = win->height;
- mf->field = V4L2_FIELD_NONE;
-
- for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++)
- if (mf->code == ov772x_cfmts[i].code)
- break;
-
- if (i == ARRAY_SIZE(ov772x_cfmts)) {
- /* Unsupported format requested. Propose either */
- if (priv->cfmt) {
- /* the current one or */
- mf->colorspace = priv->cfmt->colorspace;
- mf->code = priv->cfmt->code;
- } else {
- /* the default one */
- mf->colorspace = ov772x_cfmts[0].colorspace;
- mf->code = ov772x_cfmts[0].code;
- }
- } else {
- /* Also return the colorspace */
- mf->colorspace = ov772x_cfmts[i].colorspace;
- }
-
- return 0;
-}
-
-static int ov772x_video_probe(struct i2c_client *client)
-{
- struct ov772x_priv *priv = to_ov772x(client);
- u8 pid, ver;
- const char *devname;
-
- /*
- * check and show product ID and manufacturer ID
- */
- pid = i2c_smbus_read_byte_data(client, PID);
- ver = i2c_smbus_read_byte_data(client, VER);
-
- switch (VERSION(pid, ver)) {
- case OV7720:
- devname = "ov7720";
- priv->model = V4L2_IDENT_OV7720;
- break;
- case OV7725:
- devname = "ov7725";
- priv->model = V4L2_IDENT_OV7725;
- break;
- default:
- dev_err(&client->dev,
- "Product ID error %x:%x\n", pid, ver);
- return -ENODEV;
- }
-
- dev_info(&client->dev,
- "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
- devname,
- pid,
- ver,
- i2c_smbus_read_byte_data(client, MIDH),
- i2c_smbus_read_byte_data(client, MIDL));
- return v4l2_ctrl_handler_setup(&priv->hdl);
-}
-
-static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
- .s_ctrl = ov772x_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
- .g_chip_ident = ov772x_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov772x_g_register,
- .s_register = ov772x_s_register,
-#endif
-};
-
-static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov772x_cfmts))
- return -EINVAL;
-
- *code = ov772x_cfmts[index].code;
- return 0;
-}
-
-static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
- .s_stream = ov772x_s_stream,
- .g_mbus_fmt = ov772x_g_fmt,
- .s_mbus_fmt = ov772x_s_fmt,
- .try_mbus_fmt = ov772x_try_fmt,
- .cropcap = ov772x_cropcap,
- .g_crop = ov772x_g_crop,
- .enum_mbus_fmt = ov772x_enum_fmt,
- .g_mbus_config = ov772x_g_mbus_config,
-};
-
-static struct v4l2_subdev_ops ov772x_subdev_ops = {
- .core = &ov772x_subdev_core_ops,
- .video = &ov772x_subdev_video_ops,
-};
-
-/*
- * i2c_driver function
- */
-
-static int ov772x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov772x_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int ret;
-
- if (!icl || !icl->priv) {
- dev_err(&client->dev, "OV772X: missing platform data!\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&adapter->dev,
- "I2C-Adapter doesn't support "
- "I2C_FUNC_SMBUS_BYTE_DATA\n");
- return -EIO;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->info = icl->priv;
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
- v4l2_ctrl_handler_init(&priv->hdl, 3);
- v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
- V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
- priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
-
- ret = ov772x_video_probe(client);
- if (ret) {
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
-
- return ret;
-}
-
-static int ov772x_remove(struct i2c_client *client)
-{
- struct ov772x_priv *priv = to_ov772x(client);
-
- v4l2_device_unregister_subdev(&priv->subdev);
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id ov772x_id[] = {
- { "ov772x", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov772x_id);
-
-static struct i2c_driver ov772x_i2c_driver = {
- .driver = {
- .name = "ov772x",
- },
- .probe = ov772x_probe,
- .remove = ov772x_remove,
- .id_table = ov772x_id,
-};
-
-module_i2c_driver(ov772x_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for ov772x");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
deleted file mode 100644
index 9ed4ba4236c4..000000000000
--- a/drivers/media/video/ov9640.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- * OmniVision OV96xx Camera Driver
- *
- * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
- *
- * Based on ov772x camera driver:
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov7670 and soc_camera_platform driver,
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ctrls.h>
-
-#include "ov9640.h"
-
-#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev)
-
-/* default register setup */
-static const struct ov9640_reg ov9640_regs_dflt[] = {
- { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
- { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
- OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
- { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) },
- { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
- { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY },
- { OV9640_COM16, OV9640_COM16_RB_AVG },
-
- /* Gamma curve P */
- { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 },
- { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 },
- { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 },
- { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 },
-
- /* Gamma curve T */
- { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 },
- { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 },
- { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e },
- { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 },
-};
-
-/* Configurations
- * NOTE: for YUV, alter the following registers:
- * COM12 |= OV9640_COM12_YUV_AVG
- *
- * for RGB, alter the following registers:
- * COM7 |= OV9640_COM7_RGB
- * COM13 |= OV9640_COM13_RGB_AVG
- * COM15 |= proper RGB color encoding mode
- */
-static const struct ov9640_reg ov9640_regs_qqcif[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
- { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
- { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
- { OV9640_COM7, OV9640_COM7_QCIF },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qqvga[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
- { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
- { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
- { OV9640_COM7, OV9640_COM7_QVGA },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qcif[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
- { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
- { OV9640_COM7, OV9640_COM7_QCIF },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qvga[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
- { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
- { OV9640_COM7, OV9640_COM7_QVGA },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_cif[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
- { OV9640_COM3, OV9640_COM3_VP },
- { OV9640_COM7, OV9640_COM7_CIF },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_vga[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
- { OV9640_COM3, OV9640_COM3_VP },
- { OV9640_COM7, OV9640_COM7_VGA },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_sxga[] = {
- { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
- { OV9640_COM3, OV9640_COM3_VP },
- { OV9640_COM7, 0 },
- { OV9640_COM12, OV9640_COM12_RSVD },
- { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
- { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_yuv[] = {
- { OV9640_MTX1, 0x58 },
- { OV9640_MTX2, 0x48 },
- { OV9640_MTX3, 0x10 },
- { OV9640_MTX4, 0x28 },
- { OV9640_MTX5, 0x48 },
- { OV9640_MTX6, 0x70 },
- { OV9640_MTX7, 0x40 },
- { OV9640_MTX8, 0x40 },
- { OV9640_MTX9, 0x40 },
- { OV9640_MTXS, 0x0f },
-};
-
-static const struct ov9640_reg ov9640_regs_rgb[] = {
- { OV9640_MTX1, 0x71 },
- { OV9640_MTX2, 0x3e },
- { OV9640_MTX3, 0x0c },
- { OV9640_MTX4, 0x33 },
- { OV9640_MTX5, 0x72 },
- { OV9640_MTX6, 0x00 },
- { OV9640_MTX7, 0x2b },
- { OV9640_MTX8, 0x66 },
- { OV9640_MTX9, 0xd2 },
- { OV9640_MTXS, 0x65 },
-};
-
-static enum v4l2_mbus_pixelcode ov9640_codes[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
-};
-
-/* read a register */
-static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
-{
- int ret;
- u8 data = reg;
- struct i2c_msg msg = {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = &data,
- };
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0)
- goto err;
-
- msg.flags = I2C_M_RD;
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0)
- goto err;
-
- *val = data;
- return 0;
-
-err:
- dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
- return ret;
-}
-
-/* write a register */
-static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
-{
- int ret;
- u8 _val;
- unsigned char data[2] = { reg, val };
- struct i2c_msg msg = {
- .addr = client->addr,
- .flags = 0,
- .len = 2,
- .buf = data,
- };
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0) {
- dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
- return ret;
- }
-
- /* we have to read the register back ... no idea why, maybe HW bug */
- ret = ov9640_reg_read(client, reg, &_val);
- if (ret)
- dev_err(&client->dev,
- "Failed reading back register 0x%02x!\n", reg);
-
- return 0;
-}
-
-
-/* Read a register, alter its bits, write it back */
-static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
-{
- u8 val;
- int ret;
-
- ret = ov9640_reg_read(client, reg, &val);
- if (ret) {
- dev_err(&client->dev,
- "[Read]-Modify-Write of register %02x failed!\n", reg);
- return val;
- }
-
- val |= set;
- val &= ~unset;
-
- ret = ov9640_reg_write(client, reg, val);
- if (ret)
- dev_err(&client->dev,
- "Read-Modify-[Write] of register %02x failed!\n", reg);
-
- return ret;
-}
-
-/* Soft reset the camera. This has nothing to do with the RESET pin! */
-static int ov9640_reset(struct i2c_client *client)
-{
- int ret;
-
- ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
- if (ret)
- dev_err(&client->dev,
- "An error occurred while entering soft reset!\n");
-
- return ret;
-}
-
-/* Start/Stop streaming from the device */
-static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
-{
- return 0;
-}
-
-/* Set status of additional camera capabilities */
-static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl);
- struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- return ov9640_reg_rmw(client, OV9640_MVFP,
- OV9640_MVFP_V, 0);
- return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
- case V4L2_CID_HFLIP:
- if (ctrl->val)
- return ov9640_reg_rmw(client, OV9640_MVFP,
- OV9640_MVFP_H, 0);
- return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
- }
- return -EINVAL;
-}
-
-/* Get chip identification */
-static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
- id->ident = priv->model;
- id->revision = priv->revision;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9640_get_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u8 val;
-
- if (reg->reg & ~0xff)
- return -EINVAL;
-
- reg->size = 1;
-
- ret = ov9640_reg_read(client, reg->reg, &val);
- if (ret)
- return ret;
-
- reg->val = (__u64)val;
-
- return 0;
-}
-
-static int ov9640_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg & ~0xff || reg->val & ~0xff)
- return -EINVAL;
-
- return ov9640_reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-/* select nearest higher resolution for capture */
-static void ov9640_res_roundup(u32 *width, u32 *height)
-{
- int i;
- enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
- int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
- int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
-
- for (i = 0; i < ARRAY_SIZE(res_x); i++) {
- if (res_x[i] >= *width && res_y[i] >= *height) {
- *width = res_x[i];
- *height = res_y[i];
- return;
- }
- }
-
- *width = res_x[SXGA];
- *height = res_y[SXGA];
-}
-
-/* Prepare necessary register changes depending on color encoding */
-static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
- struct ov9640_reg_alt *alt)
-{
- switch (code) {
- default:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- alt->com12 = OV9640_COM12_YUV_AVG;
- alt->com13 = OV9640_COM13_Y_DELAY_EN |
- OV9640_COM13_YUV_DLY(0x01);
- break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- alt->com7 = OV9640_COM7_RGB;
- alt->com13 = OV9640_COM13_RGB_AVG;
- alt->com15 = OV9640_COM15_RGB_555;
- break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- alt->com7 = OV9640_COM7_RGB;
- alt->com13 = OV9640_COM13_RGB_AVG;
- alt->com15 = OV9640_COM15_RGB_565;
- break;
- };
-}
-
-/* Setup registers according to resolution and color encoding */
-static int ov9640_write_regs(struct i2c_client *client, u32 width,
- enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts)
-{
- const struct ov9640_reg *ov9640_regs, *matrix_regs;
- int ov9640_regs_len, matrix_regs_len;
- int i, ret;
- u8 val;
-
- /* select register configuration for given resolution */
- switch (width) {
- case W_QQCIF:
- ov9640_regs = ov9640_regs_qqcif;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif);
- break;
- case W_QQVGA:
- ov9640_regs = ov9640_regs_qqvga;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga);
- break;
- case W_QCIF:
- ov9640_regs = ov9640_regs_qcif;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif);
- break;
- case W_QVGA:
- ov9640_regs = ov9640_regs_qvga;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga);
- break;
- case W_CIF:
- ov9640_regs = ov9640_regs_cif;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif);
- break;
- case W_VGA:
- ov9640_regs = ov9640_regs_vga;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga);
- break;
- case W_SXGA:
- ov9640_regs = ov9640_regs_sxga;
- ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga);
- break;
- default:
- dev_err(&client->dev, "Failed to select resolution!\n");
- return -EINVAL;
- }
-
- /* select color matrix configuration for given color encoding */
- if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
- matrix_regs = ov9640_regs_yuv;
- matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
- } else {
- matrix_regs = ov9640_regs_rgb;
- matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
- }
-
- /* write register settings into the module */
- for (i = 0; i < ov9640_regs_len; i++) {
- val = ov9640_regs[i].val;
-
- switch (ov9640_regs[i].reg) {
- case OV9640_COM7:
- val |= alts->com7;
- break;
- case OV9640_COM12:
- val |= alts->com12;
- break;
- case OV9640_COM13:
- val |= alts->com13;
- break;
- case OV9640_COM15:
- val |= alts->com15;
- break;
- }
-
- ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
- if (ret)
- return ret;
- }
-
- /* write color matrix configuration into the module */
- for (i = 0; i < matrix_regs_len; i++) {
- ret = ov9640_reg_write(client, matrix_regs[i].reg,
- matrix_regs[i].val);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-/* program default register values */
-static int ov9640_prog_dflt(struct i2c_client *client)
-{
- int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
- ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
- ov9640_regs_dflt[i].val);
- if (ret)
- return ret;
- }
-
- /* wait for the changes to actually happen, 140ms are not enough yet */
- mdelay(150);
-
- return 0;
-}
-
-/* set the format we will capture in */
-static int ov9640_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9640_reg_alt alts = {0};
- enum v4l2_colorspace cspace;
- enum v4l2_mbus_pixelcode code = mf->code;
- int ret;
-
- ov9640_res_roundup(&mf->width, &mf->height);
- ov9640_alter_regs(mf->code, &alts);
-
- ov9640_reset(client);
-
- ret = ov9640_prog_dflt(client);
- if (ret)
- return ret;
-
- switch (code) {
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- cspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- cspace = V4L2_COLORSPACE_JPEG;
- }
-
- ret = ov9640_write_regs(client, mf->width, code, &alts);
- if (!ret) {
- mf->code = code;
- mf->colorspace = cspace;
- }
-
- return ret;
-}
-
-static int ov9640_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- ov9640_res_roundup(&mf->width, &mf->height);
-
- mf->field = V4L2_FIELD_NONE;
-
- switch (mf->code) {
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- mf->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- }
-
- return 0;
-}
-
-static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov9640_codes))
- return -EINVAL;
-
- *code = ov9640_codes[index];
- return 0;
-}
-
-static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = W_SXGA;
- a->c.height = H_SXGA;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = W_SXGA;
- a->bounds.height = H_SXGA;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov9640_video_probe(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov9640_priv *priv = to_ov9640_sensor(sd);
- u8 pid, ver, midh, midl;
- const char *devname;
- int ret = 0;
-
- /*
- * check and show product ID and manufacturer ID
- */
-
- ret = ov9640_reg_read(client, OV9640_PID, &pid);
- if (!ret)
- ret = ov9640_reg_read(client, OV9640_VER, &ver);
- if (!ret)
- ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
- if (!ret)
- ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
- if (ret)
- return ret;
-
- switch (VERSION(pid, ver)) {
- case OV9640_V2:
- devname = "ov9640";
- priv->model = V4L2_IDENT_OV9640;
- priv->revision = 2;
- break;
- case OV9640_V3:
- devname = "ov9640";
- priv->model = V4L2_IDENT_OV9640;
- priv->revision = 3;
- break;
- default:
- dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
- return -ENODEV;
- }
-
- dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
- devname, pid, ver, midh, midl);
-
- return v4l2_ctrl_handler_setup(&priv->hdl);
-}
-
-static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
- .s_ctrl = ov9640_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops ov9640_core_ops = {
- .g_chip_ident = ov9640_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov9640_get_register,
- .s_register = ov9640_set_register,
-#endif
-
-};
-
-/* Request bus settings on camera side */
-static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops ov9640_video_ops = {
- .s_stream = ov9640_s_stream,
- .s_mbus_fmt = ov9640_s_fmt,
- .try_mbus_fmt = ov9640_try_fmt,
- .enum_mbus_fmt = ov9640_enum_fmt,
- .cropcap = ov9640_cropcap,
- .g_crop = ov9640_g_crop,
- .g_mbus_config = ov9640_g_mbus_config,
-};
-
-static struct v4l2_subdev_ops ov9640_subdev_ops = {
- .core = &ov9640_core_ops,
- .video = &ov9640_video_ops,
-};
-
-/*
- * i2c_driver function
- */
-static int ov9640_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov9640_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "Missing platform_data for driver\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&client->dev,
- "Failed to allocate memory for private data!\n");
- return -ENOMEM;
- }
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
-
- v4l2_ctrl_handler_init(&priv->hdl, 2);
- v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
-
- ret = ov9640_video_probe(client);
-
- if (ret) {
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
-
- return ret;
-}
-
-static int ov9640_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
- v4l2_device_unregister_subdev(&priv->subdev);
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id ov9640_id[] = {
- { "ov9640", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov9640_id);
-
-static struct i2c_driver ov9640_i2c_driver = {
- .driver = {
- .name = "ov9640",
- },
- .probe = ov9640_probe,
- .remove = ov9640_remove,
- .id_table = ov9640_id,
-};
-
-module_i2c_driver(ov9640_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
-MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c
deleted file mode 100644
index 3eb07c22516e..000000000000
--- a/drivers/media/video/ov9740.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/*
- * OmniVision OV9740 Camera Driver
- *
- * Copyright (C) 2011 NVIDIA Corporation
- *
- * Based on ov9640 camera driver.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-
-#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev)
-
-/* General Status Registers */
-#define OV9740_MODEL_ID_HI 0x0000
-#define OV9740_MODEL_ID_LO 0x0001
-#define OV9740_REVISION_NUMBER 0x0002
-#define OV9740_MANUFACTURER_ID 0x0003
-#define OV9740_SMIA_VERSION 0x0004
-
-/* General Setup Registers */
-#define OV9740_MODE_SELECT 0x0100
-#define OV9740_IMAGE_ORT 0x0101
-#define OV9740_SOFTWARE_RESET 0x0103
-#define OV9740_GRP_PARAM_HOLD 0x0104
-#define OV9740_MSK_CORRUP_FM 0x0105
-
-/* Timing Setting */
-#define OV9740_FRM_LENGTH_LN_HI 0x0340 /* VTS */
-#define OV9740_FRM_LENGTH_LN_LO 0x0341 /* VTS */
-#define OV9740_LN_LENGTH_PCK_HI 0x0342 /* HTS */
-#define OV9740_LN_LENGTH_PCK_LO 0x0343 /* HTS */
-#define OV9740_X_ADDR_START_HI 0x0344
-#define OV9740_X_ADDR_START_LO 0x0345
-#define OV9740_Y_ADDR_START_HI 0x0346
-#define OV9740_Y_ADDR_START_LO 0x0347
-#define OV9740_X_ADDR_END_HI 0x0348
-#define OV9740_X_ADDR_END_LO 0x0349
-#define OV9740_Y_ADDR_END_HI 0x034a
-#define OV9740_Y_ADDR_END_LO 0x034b
-#define OV9740_X_OUTPUT_SIZE_HI 0x034c
-#define OV9740_X_OUTPUT_SIZE_LO 0x034d
-#define OV9740_Y_OUTPUT_SIZE_HI 0x034e
-#define OV9740_Y_OUTPUT_SIZE_LO 0x034f
-
-/* IO Control Registers */
-#define OV9740_IO_CREL00 0x3002
-#define OV9740_IO_CREL01 0x3004
-#define OV9740_IO_CREL02 0x3005
-#define OV9740_IO_OUTPUT_SEL01 0x3026
-#define OV9740_IO_OUTPUT_SEL02 0x3027
-
-/* AWB Registers */
-#define OV9740_AWB_MANUAL_CTRL 0x3406
-
-/* Analog Control Registers */
-#define OV9740_ANALOG_CTRL01 0x3601
-#define OV9740_ANALOG_CTRL02 0x3602
-#define OV9740_ANALOG_CTRL03 0x3603
-#define OV9740_ANALOG_CTRL04 0x3604
-#define OV9740_ANALOG_CTRL10 0x3610
-#define OV9740_ANALOG_CTRL12 0x3612
-#define OV9740_ANALOG_CTRL15 0x3615
-#define OV9740_ANALOG_CTRL20 0x3620
-#define OV9740_ANALOG_CTRL21 0x3621
-#define OV9740_ANALOG_CTRL22 0x3622
-#define OV9740_ANALOG_CTRL30 0x3630
-#define OV9740_ANALOG_CTRL31 0x3631
-#define OV9740_ANALOG_CTRL32 0x3632
-#define OV9740_ANALOG_CTRL33 0x3633
-
-/* Sensor Control */
-#define OV9740_SENSOR_CTRL03 0x3703
-#define OV9740_SENSOR_CTRL04 0x3704
-#define OV9740_SENSOR_CTRL05 0x3705
-#define OV9740_SENSOR_CTRL07 0x3707
-
-/* Timing Control */
-#define OV9740_TIMING_CTRL17 0x3817
-#define OV9740_TIMING_CTRL19 0x3819
-#define OV9740_TIMING_CTRL33 0x3833
-#define OV9740_TIMING_CTRL35 0x3835
-
-/* Banding Filter */
-#define OV9740_AEC_MAXEXPO_60_H 0x3a02
-#define OV9740_AEC_MAXEXPO_60_L 0x3a03
-#define OV9740_AEC_B50_STEP_HI 0x3a08
-#define OV9740_AEC_B50_STEP_LO 0x3a09
-#define OV9740_AEC_B60_STEP_HI 0x3a0a
-#define OV9740_AEC_B60_STEP_LO 0x3a0b
-#define OV9740_AEC_CTRL0D 0x3a0d
-#define OV9740_AEC_CTRL0E 0x3a0e
-#define OV9740_AEC_MAXEXPO_50_H 0x3a14
-#define OV9740_AEC_MAXEXPO_50_L 0x3a15
-
-/* AEC/AGC Control */
-#define OV9740_AEC_ENABLE 0x3503
-#define OV9740_GAIN_CEILING_01 0x3a18
-#define OV9740_GAIN_CEILING_02 0x3a19
-#define OV9740_AEC_HI_THRESHOLD 0x3a11
-#define OV9740_AEC_3A1A 0x3a1a
-#define OV9740_AEC_CTRL1B_WPT2 0x3a1b
-#define OV9740_AEC_CTRL0F_WPT 0x3a0f
-#define OV9740_AEC_CTRL10_BPT 0x3a10
-#define OV9740_AEC_CTRL1E_BPT2 0x3a1e
-#define OV9740_AEC_LO_THRESHOLD 0x3a1f
-
-/* BLC Control */
-#define OV9740_BLC_AUTO_ENABLE 0x4002
-#define OV9740_BLC_MODE 0x4005
-
-/* VFIFO */
-#define OV9740_VFIFO_READ_START_HI 0x4608
-#define OV9740_VFIFO_READ_START_LO 0x4609
-
-/* DVP Control */
-#define OV9740_DVP_VSYNC_CTRL02 0x4702
-#define OV9740_DVP_VSYNC_MODE 0x4704
-#define OV9740_DVP_VSYNC_CTRL06 0x4706
-
-/* PLL Setting */
-#define OV9740_PLL_MODE_CTRL01 0x3104
-#define OV9740_PRE_PLL_CLK_DIV 0x0305
-#define OV9740_PLL_MULTIPLIER 0x0307
-#define OV9740_VT_SYS_CLK_DIV 0x0303
-#define OV9740_VT_PIX_CLK_DIV 0x0301
-#define OV9740_PLL_CTRL3010 0x3010
-#define OV9740_VFIFO_CTRL00 0x460e
-
-/* ISP Control */
-#define OV9740_ISP_CTRL00 0x5000
-#define OV9740_ISP_CTRL01 0x5001
-#define OV9740_ISP_CTRL03 0x5003
-#define OV9740_ISP_CTRL05 0x5005
-#define OV9740_ISP_CTRL12 0x5012
-#define OV9740_ISP_CTRL19 0x5019
-#define OV9740_ISP_CTRL1A 0x501a
-#define OV9740_ISP_CTRL1E 0x501e
-#define OV9740_ISP_CTRL1F 0x501f
-#define OV9740_ISP_CTRL20 0x5020
-#define OV9740_ISP_CTRL21 0x5021
-
-/* AWB */
-#define OV9740_AWB_CTRL00 0x5180
-#define OV9740_AWB_CTRL01 0x5181
-#define OV9740_AWB_CTRL02 0x5182
-#define OV9740_AWB_CTRL03 0x5183
-#define OV9740_AWB_ADV_CTRL01 0x5184
-#define OV9740_AWB_ADV_CTRL02 0x5185
-#define OV9740_AWB_ADV_CTRL03 0x5186
-#define OV9740_AWB_ADV_CTRL04 0x5187
-#define OV9740_AWB_ADV_CTRL05 0x5188
-#define OV9740_AWB_ADV_CTRL06 0x5189
-#define OV9740_AWB_ADV_CTRL07 0x518a
-#define OV9740_AWB_ADV_CTRL08 0x518b
-#define OV9740_AWB_ADV_CTRL09 0x518c
-#define OV9740_AWB_ADV_CTRL10 0x518d
-#define OV9740_AWB_ADV_CTRL11 0x518e
-#define OV9740_AWB_CTRL0F 0x518f
-#define OV9740_AWB_CTRL10 0x5190
-#define OV9740_AWB_CTRL11 0x5191
-#define OV9740_AWB_CTRL12 0x5192
-#define OV9740_AWB_CTRL13 0x5193
-#define OV9740_AWB_CTRL14 0x5194
-
-/* MIPI Control */
-#define OV9740_MIPI_CTRL00 0x4800
-#define OV9740_MIPI_3837 0x3837
-#define OV9740_MIPI_CTRL01 0x4801
-#define OV9740_MIPI_CTRL03 0x4803
-#define OV9740_MIPI_CTRL05 0x4805
-#define OV9740_VFIFO_RD_CTRL 0x4601
-#define OV9740_MIPI_CTRL_3012 0x3012
-#define OV9740_SC_CMMM_MIPI_CTR 0x3014
-
-#define OV9740_MAX_WIDTH 1280
-#define OV9740_MAX_HEIGHT 720
-
-/* Misc. structures */
-struct ov9740_reg {
- u16 reg;
- u8 val;
-};
-
-struct ov9740_priv {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
-
- int ident;
- u16 model;
- u8 revision;
- u8 manid;
- u8 smiaver;
-
- bool flag_vflip;
- bool flag_hflip;
-
- /* For suspend/resume. */
- struct v4l2_mbus_framefmt current_mf;
- bool current_enable;
-};
-
-static const struct ov9740_reg ov9740_defaults[] = {
- /* Software Reset */
- { OV9740_SOFTWARE_RESET, 0x01 },
-
- /* Banding Filter */
- { OV9740_AEC_B50_STEP_HI, 0x00 },
- { OV9740_AEC_B50_STEP_LO, 0xe8 },
- { OV9740_AEC_CTRL0E, 0x03 },
- { OV9740_AEC_MAXEXPO_50_H, 0x15 },
- { OV9740_AEC_MAXEXPO_50_L, 0xc6 },
- { OV9740_AEC_B60_STEP_HI, 0x00 },
- { OV9740_AEC_B60_STEP_LO, 0xc0 },
- { OV9740_AEC_CTRL0D, 0x04 },
- { OV9740_AEC_MAXEXPO_60_H, 0x18 },
- { OV9740_AEC_MAXEXPO_60_L, 0x20 },
-
- /* LC */
- { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
- { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
-
- /* Un-documented OV9740 registers */
- { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
- { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
- { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
- { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
- { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
- { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
- { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
- { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
- { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
- { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
- { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
- { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
- { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
- { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
- { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
- { 0x583c, 0x5f },
-
- /* Y Gamma */
- { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
- { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
- { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
- { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
-
- /* UV Gamma */
- { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
- { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
- { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
- { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
- { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
- { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
- { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
- { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
-
- /* AWB */
- { OV9740_AWB_CTRL00, 0xf0 },
- { OV9740_AWB_CTRL01, 0x00 },
- { OV9740_AWB_CTRL02, 0x41 },
- { OV9740_AWB_CTRL03, 0x42 },
- { OV9740_AWB_ADV_CTRL01, 0x8a },
- { OV9740_AWB_ADV_CTRL02, 0x61 },
- { OV9740_AWB_ADV_CTRL03, 0xce },
- { OV9740_AWB_ADV_CTRL04, 0xa8 },
- { OV9740_AWB_ADV_CTRL05, 0x17 },
- { OV9740_AWB_ADV_CTRL06, 0x1f },
- { OV9740_AWB_ADV_CTRL07, 0x27 },
- { OV9740_AWB_ADV_CTRL08, 0x41 },
- { OV9740_AWB_ADV_CTRL09, 0x34 },
- { OV9740_AWB_ADV_CTRL10, 0xf0 },
- { OV9740_AWB_ADV_CTRL11, 0x10 },
- { OV9740_AWB_CTRL0F, 0xff },
- { OV9740_AWB_CTRL10, 0x00 },
- { OV9740_AWB_CTRL11, 0xff },
- { OV9740_AWB_CTRL12, 0x00 },
- { OV9740_AWB_CTRL13, 0xff },
- { OV9740_AWB_CTRL14, 0x00 },
-
- /* CIP */
- { 0x530d, 0x12 },
-
- /* CMX */
- { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
- { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
- { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
- { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
- { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
- { 0x5394, 0x18 },
-
- /* 50/60 Detection */
- { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
-
- /* Output Select */
- { OV9740_IO_OUTPUT_SEL01, 0x00 },
- { OV9740_IO_OUTPUT_SEL02, 0x00 },
- { OV9740_IO_CREL00, 0x00 },
- { OV9740_IO_CREL01, 0x00 },
- { OV9740_IO_CREL02, 0x00 },
-
- /* AWB Control */
- { OV9740_AWB_MANUAL_CTRL, 0x00 },
-
- /* Analog Control */
- { OV9740_ANALOG_CTRL03, 0xaa },
- { OV9740_ANALOG_CTRL32, 0x2f },
- { OV9740_ANALOG_CTRL20, 0x66 },
- { OV9740_ANALOG_CTRL21, 0xc0 },
- { OV9740_ANALOG_CTRL31, 0x52 },
- { OV9740_ANALOG_CTRL33, 0x50 },
- { OV9740_ANALOG_CTRL30, 0xca },
- { OV9740_ANALOG_CTRL04, 0x0c },
- { OV9740_ANALOG_CTRL01, 0x40 },
- { OV9740_ANALOG_CTRL02, 0x16 },
- { OV9740_ANALOG_CTRL10, 0xa1 },
- { OV9740_ANALOG_CTRL12, 0x24 },
- { OV9740_ANALOG_CTRL22, 0x9f },
- { OV9740_ANALOG_CTRL15, 0xf0 },
-
- /* Sensor Control */
- { OV9740_SENSOR_CTRL03, 0x42 },
- { OV9740_SENSOR_CTRL04, 0x10 },
- { OV9740_SENSOR_CTRL05, 0x45 },
- { OV9740_SENSOR_CTRL07, 0x14 },
-
- /* Timing Control */
- { OV9740_TIMING_CTRL33, 0x04 },
- { OV9740_TIMING_CTRL35, 0x02 },
- { OV9740_TIMING_CTRL19, 0x6e },
- { OV9740_TIMING_CTRL17, 0x94 },
-
- /* AEC/AGC Control */
- { OV9740_AEC_ENABLE, 0x10 },
- { OV9740_GAIN_CEILING_01, 0x00 },
- { OV9740_GAIN_CEILING_02, 0x7f },
- { OV9740_AEC_HI_THRESHOLD, 0xa0 },
- { OV9740_AEC_3A1A, 0x05 },
- { OV9740_AEC_CTRL1B_WPT2, 0x50 },
- { OV9740_AEC_CTRL0F_WPT, 0x50 },
- { OV9740_AEC_CTRL10_BPT, 0x4c },
- { OV9740_AEC_CTRL1E_BPT2, 0x4c },
- { OV9740_AEC_LO_THRESHOLD, 0x26 },
-
- /* BLC Control */
- { OV9740_BLC_AUTO_ENABLE, 0x45 },
- { OV9740_BLC_MODE, 0x18 },
-
- /* DVP Control */
- { OV9740_DVP_VSYNC_CTRL02, 0x04 },
- { OV9740_DVP_VSYNC_MODE, 0x00 },
- { OV9740_DVP_VSYNC_CTRL06, 0x08 },
-
- /* PLL Setting */
- { OV9740_PLL_MODE_CTRL01, 0x20 },
- { OV9740_PRE_PLL_CLK_DIV, 0x03 },
- { OV9740_PLL_MULTIPLIER, 0x4c },
- { OV9740_VT_SYS_CLK_DIV, 0x01 },
- { OV9740_VT_PIX_CLK_DIV, 0x08 },
- { OV9740_PLL_CTRL3010, 0x01 },
- { OV9740_VFIFO_CTRL00, 0x82 },
-
- /* Timing Setting */
- /* VTS */
- { OV9740_FRM_LENGTH_LN_HI, 0x03 },
- { OV9740_FRM_LENGTH_LN_LO, 0x07 },
- /* HTS */
- { OV9740_LN_LENGTH_PCK_HI, 0x06 },
- { OV9740_LN_LENGTH_PCK_LO, 0x62 },
-
- /* MIPI Control */
- { OV9740_MIPI_CTRL00, 0x44 }, /* 0x64 for discontinuous clk */
- { OV9740_MIPI_3837, 0x01 },
- { OV9740_MIPI_CTRL01, 0x0f },
- { OV9740_MIPI_CTRL03, 0x05 },
- { OV9740_MIPI_CTRL05, 0x10 },
- { OV9740_VFIFO_RD_CTRL, 0x16 },
- { OV9740_MIPI_CTRL_3012, 0x70 },
- { OV9740_SC_CMMM_MIPI_CTR, 0x01 },
-
- /* YUYV order */
- { OV9740_ISP_CTRL19, 0x02 },
-};
-
-static enum v4l2_mbus_pixelcode ov9740_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
-};
-
-/* read a register */
-static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
-{
- int ret;
- struct i2c_msg msg[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 2,
- .buf = (u8 *)&reg,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = val,
- },
- };
-
- reg = swab16(reg);
-
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0) {
- dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
- return ret;
- }
-
- return 0;
-}
-
-/* write a register */
-static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
-{
- struct i2c_msg msg;
- struct {
- u16 reg;
- u8 val;
- } __packed buf;
- int ret;
-
- reg = swab16(reg);
-
- buf.reg = reg;
- buf.val = val;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = 3;
- msg.buf = (u8 *)&buf;
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0) {
- dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
- return ret;
- }
-
- return 0;
-}
-
-
-/* Read a register, alter its bits, write it back */
-static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
-{
- u8 val;
- int ret;
-
- ret = ov9740_reg_read(client, reg, &val);
- if (ret < 0) {
- dev_err(&client->dev,
- "[Read]-Modify-Write of register 0x%04x failed!\n",
- reg);
- return ret;
- }
-
- val |= set;
- val &= ~unset;
-
- ret = ov9740_reg_write(client, reg, val);
- if (ret < 0) {
- dev_err(&client->dev,
- "Read-Modify-[Write] of register 0x%04x failed!\n",
- reg);
- return ret;
- }
-
- return 0;
-}
-
-static int ov9740_reg_write_array(struct i2c_client *client,
- const struct ov9740_reg *regarray,
- int regarraylen)
-{
- int i;
- int ret;
-
- for (i = 0; i < regarraylen; i++) {
- ret = ov9740_reg_write(client,
- regarray[i].reg, regarray[i].val);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/* Start/Stop streaming from the device */
-static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9740_priv *priv = to_ov9740(sd);
- int ret;
-
- /* Program orientation register. */
- if (priv->flag_vflip)
- ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
- else
- ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
- if (ret < 0)
- return ret;
-
- if (priv->flag_hflip)
- ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
- else
- ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
- if (ret < 0)
- return ret;
-
- if (enable) {
- dev_dbg(&client->dev, "Enabling Streaming\n");
- /* Start Streaming */
- ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
-
- } else {
- dev_dbg(&client->dev, "Disabling Streaming\n");
- /* Software Reset */
- ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
- if (!ret)
- /* Setting Streaming to Standby */
- ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
- 0x00);
- }
-
- priv->current_enable = enable;
-
- return ret;
-}
-
-/* select nearest higher resolution for capture */
-static void ov9740_res_roundup(u32 *width, u32 *height)
-{
- /* Width must be a multiple of 4 pixels. */
- *width = ALIGN(*width, 4);
-
- /* Max resolution is 1280x720 (720p). */
- if (*width > OV9740_MAX_WIDTH)
- *width = OV9740_MAX_WIDTH;
-
- if (*height > OV9740_MAX_HEIGHT)
- *height = OV9740_MAX_HEIGHT;
-}
-
-/* Setup registers according to resolution and color encoding */
-static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
-{
- u32 x_start;
- u32 y_start;
- u32 x_end;
- u32 y_end;
- bool scaling = 0;
- u32 scale_input_x;
- u32 scale_input_y;
- int ret;
-
- if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
- scaling = 1;
-
- /*
- * Try to use as much of the sensor area as possible when supporting
- * smaller resolutions. Depending on the aspect ratio of the
- * chosen resolution, we can either use the full width of the sensor,
- * or the full height of the sensor (or both if the aspect ratio is
- * the same as 1280x720.
- */
- if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
- scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
- scale_input_y = OV9740_MAX_HEIGHT;
- } else {
- scale_input_x = OV9740_MAX_WIDTH;
- scale_input_y = (OV9740_MAX_WIDTH * height) / width;
- }
-
- /* These describe the area of the sensor to use. */
- x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
- y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
- x_end = x_start + scale_input_x - 1;
- y_end = y_start + scale_input_y - 1;
-
- ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
- if (ret)
- goto done;
-
- ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
- if (ret)
- goto done;
-
- ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
- if (ret)
- goto done;
-
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
- if (ret)
- goto done;
-
- ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
- (scale_input_x - width) >> 8);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
- (scale_input_x - width) & 0xff);
- if (ret)
- goto done;
-
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
- (scaling << 4));
- if (ret)
- goto done;
- ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
-
-done:
- return ret;
-}
-
-/* set the format we will capture in */
-static int ov9740_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9740_priv *priv = to_ov9740(sd);
- enum v4l2_colorspace cspace;
- enum v4l2_mbus_pixelcode code = mf->code;
- int ret;
-
- ov9740_res_roundup(&mf->width, &mf->height);
-
- switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
- cspace = V4L2_COLORSPACE_SRGB;
- break;
- default:
- return -EINVAL;
- }
-
- ret = ov9740_reg_write_array(client, ov9740_defaults,
- ARRAY_SIZE(ov9740_defaults));
- if (ret < 0)
- return ret;
-
- ret = ov9740_set_res(client, mf->width, mf->height);
- if (ret < 0)
- return ret;
-
- mf->code = code;
- mf->colorspace = cspace;
-
- memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt));
-
- return ret;
-}
-
-static int ov9740_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- ov9740_res_roundup(&mf->width, &mf->height);
-
- mf->field = V4L2_FIELD_NONE;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
- mf->colorspace = V4L2_COLORSPACE_SRGB;
-
- return 0;
-}
-
-static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(ov9740_codes))
- return -EINVAL;
-
- *code = ov9740_codes[index];
-
- return 0;
-}
-
-static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = OV9740_MAX_WIDTH;
- a->bounds.height = OV9740_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = OV9740_MAX_WIDTH;
- a->c.height = OV9740_MAX_HEIGHT;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-/* Set status of additional camera capabilities */
-static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov9740_priv *priv =
- container_of(ctrl->handler, struct ov9740_priv, hdl);
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- priv->flag_vflip = ctrl->val;
- break;
- case V4L2_CID_HFLIP:
- priv->flag_hflip = ctrl->val;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Get chip identification */
-static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct ov9740_priv *priv = to_ov9740(sd);
-
- id->ident = priv->ident;
- id->revision = priv->revision;
-
- return 0;
-}
-
-static int ov9740_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ov9740_priv *priv = to_ov9740(sd);
-
- if (!priv->current_enable)
- return 0;
-
- if (on) {
- ov9740_s_fmt(sd, &priv->current_mf);
- ov9740_s_stream(sd, priv->current_enable);
- } else {
- ov9740_s_stream(sd, 0);
- priv->current_enable = true;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9740_get_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u8 val;
-
- if (reg->reg & ~0xffff)
- return -EINVAL;
-
- reg->size = 2;
-
- ret = ov9740_reg_read(client, reg->reg, &val);
- if (ret)
- return ret;
-
- reg->val = (__u64)val;
-
- return ret;
-}
-
-static int ov9740_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg & ~0xffff || reg->val & ~0xff)
- return -EINVAL;
-
- return ov9740_reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov9740_video_probe(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov9740_priv *priv = to_ov9740(sd);
- u8 modelhi, modello;
- int ret;
-
- /*
- * check and show product ID and manufacturer ID
- */
- ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
- if (ret < 0)
- goto err;
-
- ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
- if (ret < 0)
- goto err;
-
- priv->model = (modelhi << 8) | modello;
-
- ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
- if (ret < 0)
- goto err;
-
- ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
- if (ret < 0)
- goto err;
-
- ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
- if (ret < 0)
- goto err;
-
- if (priv->model != 0x9740) {
- ret = -ENODEV;
- goto err;
- }
-
- priv->ident = V4L2_IDENT_OV9740;
-
- dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
- "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
- priv->model, priv->revision, priv->manid, priv->smiaver);
-
-err:
- return ret;
-}
-
-/* Request bus settings on camera side */
-static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops ov9740_video_ops = {
- .s_stream = ov9740_s_stream,
- .s_mbus_fmt = ov9740_s_fmt,
- .try_mbus_fmt = ov9740_try_fmt,
- .enum_mbus_fmt = ov9740_enum_fmt,
- .cropcap = ov9740_cropcap,
- .g_crop = ov9740_g_crop,
- .g_mbus_config = ov9740_g_mbus_config,
-};
-
-static struct v4l2_subdev_core_ops ov9740_core_ops = {
- .g_chip_ident = ov9740_g_chip_ident,
- .s_power = ov9740_s_power,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = ov9740_get_register,
- .s_register = ov9740_set_register,
-#endif
-};
-
-static struct v4l2_subdev_ops ov9740_subdev_ops = {
- .core = &ov9740_core_ops,
- .video = &ov9740_video_ops,
-};
-
-static const struct v4l2_ctrl_ops ov9740_ctrl_ops = {
- .s_ctrl = ov9740_s_ctrl,
-};
-
-/*
- * i2c_driver function
- */
-static int ov9740_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct ov9740_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl) {
- dev_err(&client->dev, "Missing platform_data for driver\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&client->dev, "Failed to allocate private data!\n");
- return -ENOMEM;
- }
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
- v4l2_ctrl_handler_init(&priv->hdl, 13);
- v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
-
- ret = ov9740_video_probe(client);
- if (!ret)
- ret = v4l2_ctrl_handler_setup(&priv->hdl);
- if (ret < 0) {
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
-
- return ret;
-}
-
-static int ov9740_remove(struct i2c_client *client)
-{
- struct ov9740_priv *priv = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(&priv->subdev);
- v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id ov9740_id[] = {
- { "ov9740", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ov9740_id);
-
-static struct i2c_driver ov9740_i2c_driver = {
- .driver = {
- .name = "ov9740",
- },
- .probe = ov9740_probe,
- .remove = ov9740_remove,
- .id_table = ov9740_id,
-};
-
-module_i2c_driver(ov9740_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
-MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
deleted file mode 100644
index 25e412ecad2c..000000000000
--- a/drivers/media/video/pvrusb2/Kconfig
+++ /dev/null
@@ -1,65 +0,0 @@
-config VIDEO_PVRUSB2
- tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_V4L2 && I2C
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_CX2341X
- select VIDEO_SAA711X
- select VIDEO_CX25840
- select VIDEO_MSP3400
- select VIDEO_WM8775
- select VIDEO_CS53L32A
- ---help---
- This is a video4linux driver for Conexant 23416 based
- usb2 personal video recorder devices.
-
- To compile this driver as a module, choose M here: the
- module will be called pvrusb2
-
-config VIDEO_PVRUSB2_SYSFS
- bool "pvrusb2 sysfs support (EXPERIMENTAL)"
- default y
- depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
- ---help---
- This option enables the operation of a sysfs based
- interface for query and control of the pvrusb2 driver.
-
- This is not generally needed for v4l applications,
- although certain applications are optimized to take
- advantage of this feature.
-
- If you are in doubt, say Y.
-
- Note: This feature is experimental and subject to change.
-
-config VIDEO_PVRUSB2_DVB
- bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
- default y
- depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
- select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
- ---help---
-
- This option enables a DVB interface for the pvrusb2 driver.
- If your device does not support digital television, this
- feature will have no affect on the driver's operation.
-
- If you are in doubt, say Y.
-
-config VIDEO_PVRUSB2_DEBUGIFC
- bool "pvrusb2 debug interface"
- depends on VIDEO_PVRUSB2_SYSFS
- ---help---
- This option enables the inclusion of a debug interface
- in the pvrusb2 driver, hosted through sysfs.
-
- You do not need to select this option unless you plan
- on debugging the driver or performing a manual firmware
- extraction.
-
- If you are in doubt, say N.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
deleted file mode 100644
index c17f37d964ad..000000000000
--- a/drivers/media/video/pvrusb2/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
-obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
-obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
-
-pvrusb2-objs := pvrusb2-i2c-core.o \
- pvrusb2-audio.o \
- pvrusb2-encoder.o pvrusb2-video-v4l.o \
- pvrusb2-eeprom.o \
- pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
- pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
- pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
- pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
- pvrusb2-cs53l32a.o \
- $(obj-pvrusb2-dvb-y) \
- $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
-
-obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.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
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
deleted file mode 100644
index d8c898278e8c..000000000000
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- *
- *
- * Copyright (C) 2007 Mike Isely <isely@pobox.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
- *
- * 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
- *
- */
-
-/*
-
-This source file should encompass ALL per-device type information for the
-driver. To define a new device, add elements to the pvr2_device_table and
-pvr2_device_desc structures.
-
-*/
-
-#include "pvrusb2-devattr.h"
-#include <linux/usb.h>
-#include <linux/module.h>
-/* This is needed in order to pull in tuner type ids... */
-#include <linux/i2c.h>
-#include <media/tuner.h>
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
-#include "pvrusb2-hdw-internal.h"
-#include "lgdt330x.h"
-#include "s5h1409.h"
-#include "s5h1411.h"
-#include "tda10048.h"
-#include "tda18271.h"
-#include "tda8290.h"
-#include "tuner-simple.h"
-#endif
-
-
-/*------------------------------------------------------------------------*/
-/* Hauppauge PVR-USB2 Model 29xxx */
-
-static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
- { .module_id = PVR2_CLIENT_ID_SAA7115 },
- { .module_id = PVR2_CLIENT_ID_MSP3400 },
- { .module_id = PVR2_CLIENT_ID_TUNER },
- { .module_id = PVR2_CLIENT_ID_DEMOD },
-};
-
-static const char *pvr2_fw1_names_29xxx[] = {
- "v4l-pvrusb2-29xxx-01.fw",
-};
-
-static const struct pvr2_device_desc pvr2_device_29xxx = {
- .description = "WinTV PVR USB2 Model 29xxx",
- .shortname = "29xxx",
- .client_table.lst = pvr2_cli_29xxx,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
- .fx2_firmware.lst = pvr2_fw1_names_29xxx,
- .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
- .flag_has_hauppauge_rom = !0,
- .flag_has_analogtuner = !0,
- .flag_has_fmradio = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
- .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
- .ir_scheme = PVR2_IR_SCHEME_29XXX,
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* Hauppauge PVR-USB2 Model 24xxx */
-
-static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
- { .module_id = PVR2_CLIENT_ID_CX25840 },
- { .module_id = PVR2_CLIENT_ID_TUNER },
- { .module_id = PVR2_CLIENT_ID_WM8775 },
- { .module_id = PVR2_CLIENT_ID_DEMOD },
-};
-
-static const char *pvr2_fw1_names_24xxx[] = {
- "v4l-pvrusb2-24xxx-01.fw",
-};
-
-static const struct pvr2_device_desc pvr2_device_24xxx = {
- .description = "WinTV PVR USB2 Model 24xxx",
- .shortname = "24xxx",
- .client_table.lst = pvr2_cli_24xxx,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
- .fx2_firmware.lst = pvr2_fw1_names_24xxx,
- .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
- .flag_has_cx25840 = !0,
- .flag_has_wm8775 = !0,
- .flag_has_hauppauge_rom = !0,
- .flag_has_analogtuner = !0,
- .flag_has_fmradio = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
- .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
- .ir_scheme = PVR2_IR_SCHEME_24XXX,
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* GOTVIEW USB2.0 DVD2 */
-
-static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
- { .module_id = PVR2_CLIENT_ID_CX25840 },
- { .module_id = PVR2_CLIENT_ID_TUNER },
- { .module_id = PVR2_CLIENT_ID_DEMOD },
-};
-
-static const struct pvr2_device_desc pvr2_device_gotview_2 = {
- .description = "Gotview USB 2.0 DVD 2",
- .shortname = "gv2",
- .client_table.lst = pvr2_cli_gotview_2,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
- .flag_has_cx25840 = !0,
- .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
- .flag_has_analogtuner = !0,
- .flag_has_fmradio = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* GOTVIEW USB2.0 DVD Deluxe */
-
-/* (same module list as gotview_2) */
-
-static const struct pvr2_device_desc pvr2_device_gotview_2d = {
- .description = "Gotview USB 2.0 DVD Deluxe",
- .shortname = "gv2d",
- .client_table.lst = pvr2_cli_gotview_2,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
- .flag_has_cx25840 = !0,
- .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* Terratec Grabster AV400 */
-
-static const struct pvr2_device_client_desc pvr2_cli_av400[] = {
- { .module_id = PVR2_CLIENT_ID_CX25840 },
-};
-
-static const struct pvr2_device_desc pvr2_device_av400 = {
- .description = "Terratec Grabster AV400",
- .shortname = "av400",
- .flag_is_experimental = 1,
- .client_table.lst = pvr2_cli_av400,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_av400),
- .flag_has_cx25840 = !0,
- .flag_has_analogtuner = 0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_AV400,
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* OnAir Creator */
-
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
-static struct lgdt330x_config pvr2_lgdt3303_config = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3303,
- .clock_polarity_flip = 1,
-};
-
-static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
-{
- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
- return 0;
-
- return -EIO;
-}
-
-static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
-{
- dvb_attach(simple_tuner_attach, adap->fe,
- &adap->channel.hdw->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
-
- return 0;
-}
-
-static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
- .frontend_attach = pvr2_lgdt3303_attach,
- .tuner_attach = pvr2_lgh06xf_attach,
-};
-#endif
-
-static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = {
- { .module_id = PVR2_CLIENT_ID_SAA7115 },
- { .module_id = PVR2_CLIENT_ID_CS53L32A },
- { .module_id = PVR2_CLIENT_ID_TUNER },
-};
-
-static const struct pvr2_device_desc pvr2_device_onair_creator = {
- .description = "OnAir Creator Hybrid USB tuner",
- .shortname = "oac",
- .client_table.lst = pvr2_cli_onair_creator,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator),
- .default_tuner_type = TUNER_LG_TDVS_H06XF,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .flag_digital_requires_cx23416 = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
- .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
- .default_std_mask = V4L2_STD_NTSC_M,
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
- .dvb_props = &pvr2_onair_creator_fe_props,
-#endif
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* OnAir USB 2.0 */
-
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
-static struct lgdt330x_config pvr2_lgdt3302_config = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3302,
-};
-
-static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
-{
- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
- return 0;
-
- return -EIO;
-}
-
-static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
-{
- dvb_attach(simple_tuner_attach, adap->fe,
- &adap->channel.hdw->i2c_adap, 0x61,
- TUNER_PHILIPS_FCV1236D);
-
- return 0;
-}
-
-static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
- .frontend_attach = pvr2_lgdt3302_attach,
- .tuner_attach = pvr2_fcv1236d_attach,
-};
-#endif
-
-static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = {
- { .module_id = PVR2_CLIENT_ID_SAA7115 },
- { .module_id = PVR2_CLIENT_ID_CS53L32A },
- { .module_id = PVR2_CLIENT_ID_TUNER },
-};
-
-static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
- .description = "OnAir USB2 Hybrid USB tuner",
- .shortname = "oa2",
- .client_table.lst = pvr2_cli_onair_usb2,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2),
- .default_tuner_type = TUNER_PHILIPS_FCV1236D,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .flag_digital_requires_cx23416 = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
- .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
- .default_std_mask = V4L2_STD_NTSC_M,
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
- .dvb_props = &pvr2_onair_usb2_fe_props,
-#endif
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* Hauppauge PVR-USB2 Model 73xxx */
-
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
-static struct tda10048_config hauppauge_tda10048_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_PARALLEL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_50,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3800,
- .dtv8_if_freq_khz = TDA10048_IF_4300,
- .clk_freq_khz = TDA10048_CLK_16000,
- .disable_gate_access = 1,
-};
-
-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,
-};
-
-static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
-{
- adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
- return 0;
-
- return -EIO;
-}
-
-static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
-{
- dvb_attach(tda829x_attach, adap->fe,
- &adap->channel.hdw->i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, adap->fe, 0x60,
- &adap->channel.hdw->i2c_adap,
- &hauppauge_tda18271_dvb_config);
-
- return 0;
-}
-
-static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
- .frontend_attach = pvr2_tda10048_attach,
- .tuner_attach = pvr2_73xxx_tda18271_8295_attach,
-};
-#endif
-
-static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
- { .module_id = PVR2_CLIENT_ID_CX25840 },
- { .module_id = PVR2_CLIENT_ID_TUNER,
- .i2c_address_list = "\x42"},
-};
-
-static const char *pvr2_fw1_names_73xxx[] = {
- "v4l-pvrusb2-73xxx-01.fw",
-};
-
-static const struct pvr2_device_desc pvr2_device_73xxx = {
- .description = "WinTV HVR-1900 Model 73xxx",
- .shortname = "73xxx",
- .client_table.lst = pvr2_cli_73xxx,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
- .fx2_firmware.lst = pvr2_fw1_names_73xxx,
- .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
- .flag_has_cx25840 = !0,
- .flag_has_hauppauge_rom = !0,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .flag_fx2_16kb = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
- .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
- .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
- .ir_scheme = PVR2_IR_SCHEME_ZILOG,
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
- .dvb_props = &pvr2_73xxx_dvb_props,
-#endif
-};
-
-
-
-/*------------------------------------------------------------------------*/
-/* Hauppauge PVR-USB2 Model 75xxx */
-
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
-static struct s5h1409_config pvr2_s5h1409_config = {
- .demod_address = 0x32 >> 1,
- .output_mode = S5H1409_PARALLEL_OUTPUT,
- .gpio = S5H1409_GPIO_OFF,
- .qam_if = 4000,
- .inversion = S5H1409_INVERSION_ON,
- .status_mode = S5H1409_DEMODLOCKING,
-};
-
-static struct s5h1411_config pvr2_s5h1411_config = {
- .output_mode = S5H1411_PARALLEL_OUTPUT,
- .gpio = S5H1411_GPIO_OFF,
- .vsb_if = S5H1411_IF_44000,
- .qam_if = S5H1411_IF_4000,
- .inversion = S5H1411_INVERSION_ON,
- .status_mode = S5H1411_DEMODLOCKING,
-};
-
-static struct tda18271_std_map hauppauge_tda18271_std_map = {
- .atsc_6 = { .if_freq = 5380, .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 hauppauge_tda18271_config = {
- .std_map = &hauppauge_tda18271_std_map,
- .gate = TDA18271_GATE_ANALOG,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
-{
- adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
- return 0;
-
- return -EIO;
-}
-
-static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
-{
- adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
- return 0;
-
- return -EIO;
-}
-
-static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
-{
- dvb_attach(tda829x_attach, adap->fe,
- &adap->channel.hdw->i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, adap->fe, 0x60,
- &adap->channel.hdw->i2c_adap,
- &hauppauge_tda18271_config);
-
- return 0;
-}
-
-static const struct pvr2_dvb_props pvr2_750xx_dvb_props = {
- .frontend_attach = pvr2_s5h1409_attach,
- .tuner_attach = pvr2_tda18271_8295_attach,
-};
-
-static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
- .frontend_attach = pvr2_s5h1411_attach,
- .tuner_attach = pvr2_tda18271_8295_attach,
-};
-#endif
-
-static const char *pvr2_fw1_names_75xxx[] = {
- "v4l-pvrusb2-73xxx-01.fw",
-};
-
-static const struct pvr2_device_desc pvr2_device_750xx = {
- .description = "WinTV HVR-1950 Model 750xx",
- .shortname = "750xx",
- .client_table.lst = pvr2_cli_73xxx,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
- .fx2_firmware.lst = pvr2_fw1_names_75xxx,
- .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
- .flag_has_cx25840 = !0,
- .flag_has_hauppauge_rom = !0,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .flag_fx2_16kb = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
- .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
- .default_std_mask = V4L2_STD_NTSC_M,
- .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
- .ir_scheme = PVR2_IR_SCHEME_ZILOG,
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
- .dvb_props = &pvr2_750xx_dvb_props,
-#endif
-};
-
-static const struct pvr2_device_desc pvr2_device_751xx = {
- .description = "WinTV HVR-1950 Model 751xx",
- .shortname = "751xx",
- .client_table.lst = pvr2_cli_73xxx,
- .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
- .fx2_firmware.lst = pvr2_fw1_names_75xxx,
- .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
- .flag_has_cx25840 = !0,
- .flag_has_hauppauge_rom = !0,
- .flag_has_analogtuner = !0,
- .flag_has_composite = !0,
- .flag_has_svideo = !0,
- .flag_fx2_16kb = !0,
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
- .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
- .default_std_mask = V4L2_STD_NTSC_M,
- .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
- .ir_scheme = PVR2_IR_SCHEME_ZILOG,
-#ifdef CONFIG_VIDEO_PVRUSB2_DVB
- .dvb_props = &pvr2_751xx_dvb_props,
-#endif
-};
-
-
-
-/*------------------------------------------------------------------------*/
-
-struct usb_device_id pvr2_device_table[] = {
- { USB_DEVICE(0x2040, 0x2900),
- .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
- { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */
- .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
- { USB_DEVICE(0x2040, 0x2400),
- .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
- { USB_DEVICE(0x1164, 0x0622),
- .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
- { USB_DEVICE(0x1164, 0x0602),
- .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
- { USB_DEVICE(0x11ba, 0x1003),
- .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
- { USB_DEVICE(0x11ba, 0x1001),
- .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
- { USB_DEVICE(0x2040, 0x7300),
- .driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
- { USB_DEVICE(0x2040, 0x7500),
- .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
- { USB_DEVICE(0x2040, 0x7501),
- .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
- { USB_DEVICE(0x0ccd, 0x0039),
- .driver_info = (kernel_ulong_t)&pvr2_device_av400},
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, pvr2_device_table);
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
deleted file mode 100644
index f5c8ec261e87..000000000000
--- a/drivers/media/video/pwc/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
-pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
-
-obj-$(CONFIG_USB_PWC) += pwc.o
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
deleted file mode 100644
index f6419b22c258..000000000000
--- a/drivers/media/video/rj54n1cb0c.c
+++ /dev/null
@@ -1,1414 +0,0 @@
-/*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
- *
- * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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/delay.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/rj54n1cb0c.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-
-#define RJ54N1_DEV_CODE 0x0400
-#define RJ54N1_DEV_CODE2 0x0401
-#define RJ54N1_OUT_SEL 0x0403
-#define RJ54N1_XY_OUTPUT_SIZE_S_H 0x0404
-#define RJ54N1_X_OUTPUT_SIZE_S_L 0x0405
-#define RJ54N1_Y_OUTPUT_SIZE_S_L 0x0406
-#define RJ54N1_XY_OUTPUT_SIZE_P_H 0x0407
-#define RJ54N1_X_OUTPUT_SIZE_P_L 0x0408
-#define RJ54N1_Y_OUTPUT_SIZE_P_L 0x0409
-#define RJ54N1_LINE_LENGTH_PCK_S_H 0x040a
-#define RJ54N1_LINE_LENGTH_PCK_S_L 0x040b
-#define RJ54N1_LINE_LENGTH_PCK_P_H 0x040c
-#define RJ54N1_LINE_LENGTH_PCK_P_L 0x040d
-#define RJ54N1_RESIZE_N 0x040e
-#define RJ54N1_RESIZE_N_STEP 0x040f
-#define RJ54N1_RESIZE_STEP 0x0410
-#define RJ54N1_RESIZE_HOLD_H 0x0411
-#define RJ54N1_RESIZE_HOLD_L 0x0412
-#define RJ54N1_H_OBEN_OFS 0x0413
-#define RJ54N1_V_OBEN_OFS 0x0414
-#define RJ54N1_RESIZE_CONTROL 0x0415
-#define RJ54N1_STILL_CONTROL 0x0417
-#define RJ54N1_INC_USE_SEL_H 0x0425
-#define RJ54N1_INC_USE_SEL_L 0x0426
-#define RJ54N1_MIRROR_STILL_MODE 0x0427
-#define RJ54N1_INIT_START 0x0428
-#define RJ54N1_SCALE_1_2_LEV 0x0429
-#define RJ54N1_SCALE_4_LEV 0x042a
-#define RJ54N1_Y_GAIN 0x04d8
-#define RJ54N1_APT_GAIN_UP 0x04fa
-#define RJ54N1_RA_SEL_UL 0x0530
-#define RJ54N1_BYTE_SWAP 0x0531
-#define RJ54N1_OUT_SIGPO 0x053b
-#define RJ54N1_WB_SEL_WEIGHT_I 0x054e
-#define RJ54N1_BIT8_WB 0x0569
-#define RJ54N1_HCAPS_WB 0x056a
-#define RJ54N1_VCAPS_WB 0x056b
-#define RJ54N1_HCAPE_WB 0x056c
-#define RJ54N1_VCAPE_WB 0x056d
-#define RJ54N1_EXPOSURE_CONTROL 0x058c
-#define RJ54N1_FRAME_LENGTH_S_H 0x0595
-#define RJ54N1_FRAME_LENGTH_S_L 0x0596
-#define RJ54N1_FRAME_LENGTH_P_H 0x0597
-#define RJ54N1_FRAME_LENGTH_P_L 0x0598
-#define RJ54N1_PEAK_H 0x05b7
-#define RJ54N1_PEAK_50 0x05b8
-#define RJ54N1_PEAK_60 0x05b9
-#define RJ54N1_PEAK_DIFF 0x05ba
-#define RJ54N1_IOC 0x05ef
-#define RJ54N1_TG_BYPASS 0x0700
-#define RJ54N1_PLL_L 0x0701
-#define RJ54N1_PLL_N 0x0702
-#define RJ54N1_PLL_EN 0x0704
-#define RJ54N1_RATIO_TG 0x0706
-#define RJ54N1_RATIO_T 0x0707
-#define RJ54N1_RATIO_R 0x0708
-#define RJ54N1_RAMP_TGCLK_EN 0x0709
-#define RJ54N1_OCLK_DSP 0x0710
-#define RJ54N1_RATIO_OP 0x0711
-#define RJ54N1_RATIO_O 0x0712
-#define RJ54N1_OCLK_SEL_EN 0x0713
-#define RJ54N1_CLK_RST 0x0717
-#define RJ54N1_RESET_STANDBY 0x0718
-#define RJ54N1_FWFLG 0x07fe
-
-#define E_EXCLK (1 << 7)
-#define SOFT_STDBY (1 << 4)
-#define SEN_RSTX (1 << 2)
-#define TG_RSTX (1 << 1)
-#define DSP_RSTX (1 << 0)
-
-#define RESIZE_HOLD_SEL (1 << 2)
-#define RESIZE_GO (1 << 1)
-
-/*
- * When cropping, the camera automatically centers the cropped region, there
- * doesn't seem to be a way to specify an explicit location of the rectangle.
- */
-#define RJ54N1_COLUMN_SKIP 0
-#define RJ54N1_ROW_SKIP 0
-#define RJ54N1_MAX_WIDTH 1600
-#define RJ54N1_MAX_HEIGHT 1200
-
-#define PLL_L 2
-#define PLL_N 0x31
-
-/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
-
-/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
-struct rj54n1_datafmt {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct rj54n1_datafmt *rj54n1_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct rj54n1_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 rj54n1_datafmt rj54n1_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
-};
-
-struct rj54n1_clock_div {
- u8 ratio_tg; /* can be 0 or an odd number */
- u8 ratio_t;
- u8 ratio_r;
- u8 ratio_op;
- u8 ratio_o;
-};
-
-struct rj54n1 {
- struct v4l2_subdev subdev;
- struct v4l2_ctrl_handler hdl;
- struct rj54n1_clock_div clk_div;
- const struct rj54n1_datafmt *fmt;
- struct v4l2_rect rect; /* Sensor window */
- unsigned int tgclk_mhz;
- bool auto_wb;
- unsigned short width; /* Output window */
- unsigned short height;
- unsigned short resize; /* Sensor * 1024 / resize = Output */
- unsigned short scale;
- u8 bank;
-};
-
-struct rj54n1_reg_val {
- u16 reg;
- u8 val;
-};
-
-static const struct rj54n1_reg_val bank_4[] = {
- {0x417, 0},
- {0x42c, 0},
- {0x42d, 0xf0},
- {0x42e, 0},
- {0x42f, 0x50},
- {0x430, 0xf5},
- {0x431, 0x16},
- {0x432, 0x20},
- {0x433, 0},
- {0x434, 0xc8},
- {0x43c, 8},
- {0x43e, 0x90},
- {0x445, 0x83},
- {0x4ba, 0x58},
- {0x4bb, 4},
- {0x4bc, 0x20},
- {0x4db, 4},
- {0x4fe, 2},
-};
-
-static const struct rj54n1_reg_val bank_5[] = {
- {0x514, 0},
- {0x516, 0},
- {0x518, 0},
- {0x51a, 0},
- {0x51d, 0xff},
- {0x56f, 0x28},
- {0x575, 0x40},
- {0x5bc, 0x48},
- {0x5c1, 6},
- {0x5e5, 0x11},
- {0x5e6, 0x43},
- {0x5e7, 0x33},
- {0x5e8, 0x21},
- {0x5e9, 0x30},
- {0x5ea, 0x0},
- {0x5eb, 0xa5},
- {0x5ec, 0xff},
- {0x5fe, 2},
-};
-
-static const struct rj54n1_reg_val bank_7[] = {
- {0x70a, 0},
- {0x714, 0xff},
- {0x715, 0xff},
- {0x716, 0x1f},
- {0x7FE, 2},
-};
-
-static const struct rj54n1_reg_val bank_8[] = {
- {0x800, 0x00},
- {0x801, 0x01},
- {0x802, 0x61},
- {0x805, 0x00},
- {0x806, 0x00},
- {0x807, 0x00},
- {0x808, 0x00},
- {0x809, 0x01},
- {0x80A, 0x61},
- {0x80B, 0x00},
- {0x80C, 0x01},
- {0x80D, 0x00},
- {0x80E, 0x00},
- {0x80F, 0x00},
- {0x810, 0x00},
- {0x811, 0x01},
- {0x812, 0x61},
- {0x813, 0x00},
- {0x814, 0x11},
- {0x815, 0x00},
- {0x816, 0x41},
- {0x817, 0x00},
- {0x818, 0x51},
- {0x819, 0x01},
- {0x81A, 0x1F},
- {0x81B, 0x00},
- {0x81C, 0x01},
- {0x81D, 0x00},
- {0x81E, 0x11},
- {0x81F, 0x00},
- {0x820, 0x41},
- {0x821, 0x00},
- {0x822, 0x51},
- {0x823, 0x00},
- {0x824, 0x00},
- {0x825, 0x00},
- {0x826, 0x47},
- {0x827, 0x01},
- {0x828, 0x4F},
- {0x829, 0x00},
- {0x82A, 0x00},
- {0x82B, 0x00},
- {0x82C, 0x30},
- {0x82D, 0x00},
- {0x82E, 0x40},
- {0x82F, 0x00},
- {0x830, 0xB3},
- {0x831, 0x00},
- {0x832, 0xE3},
- {0x833, 0x00},
- {0x834, 0x00},
- {0x835, 0x00},
- {0x836, 0x00},
- {0x837, 0x00},
- {0x838, 0x00},
- {0x839, 0x01},
- {0x83A, 0x61},
- {0x83B, 0x00},
- {0x83C, 0x01},
- {0x83D, 0x00},
- {0x83E, 0x00},
- {0x83F, 0x00},
- {0x840, 0x00},
- {0x841, 0x01},
- {0x842, 0x61},
- {0x843, 0x00},
- {0x844, 0x1D},
- {0x845, 0x00},
- {0x846, 0x00},
- {0x847, 0x00},
- {0x848, 0x00},
- {0x849, 0x01},
- {0x84A, 0x1F},
- {0x84B, 0x00},
- {0x84C, 0x05},
- {0x84D, 0x00},
- {0x84E, 0x19},
- {0x84F, 0x01},
- {0x850, 0x21},
- {0x851, 0x01},
- {0x852, 0x5D},
- {0x853, 0x00},
- {0x854, 0x00},
- {0x855, 0x00},
- {0x856, 0x19},
- {0x857, 0x01},
- {0x858, 0x21},
- {0x859, 0x00},
- {0x85A, 0x00},
- {0x85B, 0x00},
- {0x85C, 0x00},
- {0x85D, 0x00},
- {0x85E, 0x00},
- {0x85F, 0x00},
- {0x860, 0xB3},
- {0x861, 0x00},
- {0x862, 0xE3},
- {0x863, 0x00},
- {0x864, 0x00},
- {0x865, 0x00},
- {0x866, 0x00},
- {0x867, 0x00},
- {0x868, 0x00},
- {0x869, 0xE2},
- {0x86A, 0x00},
- {0x86B, 0x01},
- {0x86C, 0x06},
- {0x86D, 0x00},
- {0x86E, 0x00},
- {0x86F, 0x00},
- {0x870, 0x60},
- {0x871, 0x8C},
- {0x872, 0x10},
- {0x873, 0x00},
- {0x874, 0xE0},
- {0x875, 0x00},
- {0x876, 0x27},
- {0x877, 0x01},
- {0x878, 0x00},
- {0x879, 0x00},
- {0x87A, 0x00},
- {0x87B, 0x03},
- {0x87C, 0x00},
- {0x87D, 0x00},
- {0x87E, 0x00},
- {0x87F, 0x00},
- {0x880, 0x00},
- {0x881, 0x00},
- {0x882, 0x00},
- {0x883, 0x00},
- {0x884, 0x00},
- {0x885, 0x00},
- {0x886, 0xF8},
- {0x887, 0x00},
- {0x888, 0x03},
- {0x889, 0x00},
- {0x88A, 0x64},
- {0x88B, 0x00},
- {0x88C, 0x03},
- {0x88D, 0x00},
- {0x88E, 0xB1},
- {0x88F, 0x00},
- {0x890, 0x03},
- {0x891, 0x01},
- {0x892, 0x1D},
- {0x893, 0x00},
- {0x894, 0x03},
- {0x895, 0x01},
- {0x896, 0x4B},
- {0x897, 0x00},
- {0x898, 0xE5},
- {0x899, 0x00},
- {0x89A, 0x01},
- {0x89B, 0x00},
- {0x89C, 0x01},
- {0x89D, 0x04},
- {0x89E, 0xC8},
- {0x89F, 0x00},
- {0x8A0, 0x01},
- {0x8A1, 0x01},
- {0x8A2, 0x61},
- {0x8A3, 0x00},
- {0x8A4, 0x01},
- {0x8A5, 0x00},
- {0x8A6, 0x00},
- {0x8A7, 0x00},
- {0x8A8, 0x00},
- {0x8A9, 0x00},
- {0x8AA, 0x7F},
- {0x8AB, 0x03},
- {0x8AC, 0x00},
- {0x8AD, 0x00},
- {0x8AE, 0x00},
- {0x8AF, 0x00},
- {0x8B0, 0x00},
- {0x8B1, 0x00},
- {0x8B6, 0x00},
- {0x8B7, 0x01},
- {0x8B8, 0x00},
- {0x8B9, 0x00},
- {0x8BA, 0x02},
- {0x8BB, 0x00},
- {0x8BC, 0xFF},
- {0x8BD, 0x00},
- {0x8FE, 2},
-};
-
-static const struct rj54n1_reg_val bank_10[] = {
- {0x10bf, 0x69}
-};
-
-/* Clock dividers - these are default register values, divider = register + 1 */
-static const struct rj54n1_clock_div clk_div = {
- .ratio_tg = 3 /* default: 5 */,
- .ratio_t = 4 /* default: 1 */,
- .ratio_r = 4 /* default: 0 */,
- .ratio_op = 1 /* default: 5 */,
- .ratio_o = 9 /* default: 0 */,
-};
-
-static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u16 reg)
-{
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- int ret;
-
- /* set bank */
- if (rj54n1->bank != reg >> 8) {
- dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
- ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
- if (ret < 0)
- return ret;
- rj54n1->bank = reg >> 8;
- }
- return i2c_smbus_read_byte_data(client, reg & 0xff);
-}
-
-static int reg_write(struct i2c_client *client, const u16 reg,
- const u8 data)
-{
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- int ret;
-
- /* set bank */
- if (rj54n1->bank != reg >> 8) {
- dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
- ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
- if (ret < 0)
- return ret;
- rj54n1->bank = reg >> 8;
- }
- dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
- return i2c_smbus_write_byte_data(client, reg & 0xff, data);
-}
-
-static int reg_set(struct i2c_client *client, const u16 reg,
- const u8 data, const u8 mask)
-{
- int ret;
-
- ret = reg_read(client, reg);
- if (ret < 0)
- return ret;
- return reg_write(client, reg, (ret & ~mask) | (data & mask));
-}
-
-static int reg_write_multiple(struct i2c_client *client,
- const struct rj54n1_reg_val *rv, const int n)
-{
- int i, ret;
-
- for (i = 0; i < n; i++) {
- ret = reg_write(client, rv->reg, rv->val);
- if (ret < 0)
- return ret;
- rv++;
- }
-
- return 0;
-}
-
-static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
- return -EINVAL;
-
- *code = rj54n1_colour_fmts[index].code;
- return 0;
-}
-
-static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- /* Switch between preview and still shot modes */
- return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
-}
-
-static int rj54n1_set_rect(struct i2c_client *client,
- u16 reg_x, u16 reg_y, u16 reg_xy,
- u32 width, u32 height)
-{
- int ret;
-
- ret = reg_write(client, reg_xy,
- ((width >> 4) & 0x70) |
- ((height >> 8) & 7));
-
- if (!ret)
- ret = reg_write(client, reg_x, width & 0xff);
- if (!ret)
- ret = reg_write(client, reg_y, height & 0xff);
-
- return ret;
-}
-
-/*
- * Some commands, specifically certain initialisation sequences, require
- * a commit operation.
- */
-static int rj54n1_commit(struct i2c_client *client)
-{
- int ret = reg_write(client, RJ54N1_INIT_START, 1);
- msleep(10);
- if (!ret)
- ret = reg_write(client, RJ54N1_INIT_START, 0);
- return ret;
-}
-
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
- s32 *out_w, s32 *out_h);
-
-static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- struct v4l2_rect *rect = &a->c;
- int dummy = 0, output_w, output_h,
- input_w = rect->width, input_h = rect->height;
- int ret;
-
- /* arbitrary minimum width and height, edges unimportant */
- soc_camera_limit_side(&dummy, &input_w,
- RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
-
- soc_camera_limit_side(&dummy, &input_h,
- RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
-
- output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
- output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
-
- dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
- input_w, input_h, rj54n1->resize, output_w, output_h);
-
- ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
- if (ret < 0)
- return ret;
-
- rj54n1->width = output_w;
- rj54n1->height = output_h;
- rj54n1->resize = ret;
- rj54n1->rect.width = input_w;
- rj54n1->rect.height = input_h;
-
- return 0;
-}
-
-static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
-
- a->c = rj54n1->rect;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = RJ54N1_COLUMN_SKIP;
- a->bounds.top = RJ54N1_ROW_SKIP;
- a->bounds.width = RJ54N1_MAX_WIDTH;
- a->bounds.height = RJ54N1_MAX_HEIGHT;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int rj54n1_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
-
- mf->code = rj54n1->fmt->code;
- mf->colorspace = rj54n1->fmt->colorspace;
- mf->field = V4L2_FIELD_NONE;
- mf->width = rj54n1->width;
- mf->height = rj54n1->height;
-
- return 0;
-}
-
-/*
- * The actual geometry configuration routine. It scales the input window into
- * the output one, updates the window sizes and returns an error or the resize
- * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
- */
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
- s32 *out_w, s32 *out_h)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
- output_w = *out_w, output_h = *out_h;
- u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
- unsigned int peak, peak_50, peak_60;
- int ret;
-
- /*
- * We have a problem with crops, where the window is larger than 512x384
- * and output window is larger than a half of the input one. In this
- * case we have to either reduce the input window to equal or below
- * 512x384 or the output window to equal or below 1/2 of the input.
- */
- if (output_w > max(512U, input_w / 2)) {
- if (2 * output_w > RJ54N1_MAX_WIDTH) {
- input_w = RJ54N1_MAX_WIDTH;
- output_w = RJ54N1_MAX_WIDTH / 2;
- } else {
- input_w = output_w * 2;
- }
-
- dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
- input_w, output_w);
- }
-
- if (output_h > max(384U, input_h / 2)) {
- if (2 * output_h > RJ54N1_MAX_HEIGHT) {
- input_h = RJ54N1_MAX_HEIGHT;
- output_h = RJ54N1_MAX_HEIGHT / 2;
- } else {
- input_h = output_h * 2;
- }
-
- dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
- input_h, output_h);
- }
-
- /* Idea: use the read mode for snapshots, handle separate geometries */
- ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
- RJ54N1_Y_OUTPUT_SIZE_S_L,
- RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
- if (!ret)
- ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
- RJ54N1_Y_OUTPUT_SIZE_P_L,
- RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
-
- if (ret < 0)
- return ret;
-
- if (output_w > input_w && output_h > input_h) {
- input_w = output_w;
- input_h = output_h;
-
- resize = 1024;
- } else {
- unsigned int resize_x, resize_y;
- resize_x = (input_w * 1024 + output_w / 2) / output_w;
- resize_y = (input_h * 1024 + output_h / 2) / output_h;
-
- /* We want max(resize_x, resize_y), check if it still fits */
- if (resize_x > resize_y &&
- (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
- resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
- output_h;
- else if (resize_y > resize_x &&
- (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
- resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
- output_w;
- else
- resize = max(resize_x, resize_y);
-
- /* Prohibited value ranges */
- switch (resize) {
- case 2040 ... 2047:
- resize = 2039;
- break;
- case 4080 ... 4095:
- resize = 4079;
- break;
- case 8160 ... 8191:
- resize = 8159;
- break;
- case 16320 ... 16384:
- resize = 16319;
- }
- }
-
- /* Set scaling */
- ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
- if (!ret)
- ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
-
- if (ret < 0)
- return ret;
-
- /*
- * Configure a skipping bitmask. The sensor will select a skipping value
- * among set bits automatically. This is very unclear in the datasheet
- * too. I was told, in this register one enables all skipping values,
- * that are required for a specific resize, and the camera selects
- * automatically, which ones to use. But it is unclear how to identify,
- * which cropping values are needed. Secondly, why don't we just set all
- * bits and let the camera choose? Would it increase processing time and
- * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
- * improve the image quality or stability for larger frames (see comment
- * above), but I didn't check the framerate.
- */
- skip = min(resize / 1024, 15U);
-
- inc_sel = 1 << skip;
-
- if (inc_sel <= 2)
- inc_sel = 0xc;
- else if (resize & 1023 && skip < 15)
- inc_sel |= 1 << (skip + 1);
-
- ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
- if (!ret)
- ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
-
- if (!rj54n1->auto_wb) {
- /* Auto white balance window */
- wb_left = output_w / 16;
- wb_right = (3 * output_w / 4 - 3) / 4;
- wb_top = output_h / 16;
- wb_bottom = (3 * output_h / 4 - 3) / 4;
- wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
- ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
-
- if (!ret)
- ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
- if (!ret)
- ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
- if (!ret)
- ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
- if (!ret)
- ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
- if (!ret)
- ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
- }
-
- /* Antiflicker */
- peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
- 10000;
- peak_50 = peak / 6;
- peak_60 = peak / 5;
-
- if (!ret)
- ret = reg_write(client, RJ54N1_PEAK_H,
- ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
- if (!ret)
- ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
- if (!ret)
- ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
- if (!ret)
- ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
-
- /* Start resizing */
- if (!ret)
- ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
- RESIZE_HOLD_SEL | RESIZE_GO | 1);
-
- if (ret < 0)
- return ret;
-
- /* Constant taken from manufacturer's example */
- msleep(230);
-
- ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
- if (ret < 0)
- return ret;
-
- *in_w = (output_w * resize + 512) / 1024;
- *in_h = (output_h * resize + 512) / 1024;
- *out_w = output_w;
- *out_h = output_h;
-
- dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
- *in_w, *in_h, resize, output_w, output_h, skip);
-
- return resize;
-}
-
-static int rj54n1_set_clock(struct i2c_client *client)
-{
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- int ret;
-
- /* Enable external clock */
- ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
- /* Leave stand-by. Note: use this when implementing suspend / resume */
- if (!ret)
- ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
-
- if (!ret)
- ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
- if (!ret)
- ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
-
- /* TGCLK dividers */
- if (!ret)
- ret = reg_write(client, RJ54N1_RATIO_TG,
- rj54n1->clk_div.ratio_tg);
- if (!ret)
- ret = reg_write(client, RJ54N1_RATIO_T,
- rj54n1->clk_div.ratio_t);
- if (!ret)
- ret = reg_write(client, RJ54N1_RATIO_R,
- rj54n1->clk_div.ratio_r);
-
- /* Enable TGCLK & RAMP */
- if (!ret)
- ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
-
- /* Disable clock output */
- if (!ret)
- ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
-
- /* Set divisors */
- if (!ret)
- ret = reg_write(client, RJ54N1_RATIO_OP,
- rj54n1->clk_div.ratio_op);
- if (!ret)
- ret = reg_write(client, RJ54N1_RATIO_O,
- rj54n1->clk_div.ratio_o);
-
- /* Enable OCLK */
- if (!ret)
- ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
-
- /* Use PLL for Timing Generator, write 2 to reserved bits */
- if (!ret)
- ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
-
- /* Take sensor out of reset */
- if (!ret)
- ret = reg_write(client, RJ54N1_RESET_STANDBY,
- E_EXCLK | SEN_RSTX);
- /* Enable PLL */
- if (!ret)
- ret = reg_write(client, RJ54N1_PLL_EN, 1);
-
- /* Wait for PLL to stabilise */
- msleep(10);
-
- /* Enable clock to frequency divider */
- if (!ret)
- ret = reg_write(client, RJ54N1_CLK_RST, 1);
-
- if (!ret)
- ret = reg_read(client, RJ54N1_CLK_RST);
- if (ret != 1) {
- dev_err(&client->dev,
- "Resetting RJ54N1CB0C clock failed: %d!\n", ret);
- return -EIO;
- }
-
- /* Start the PLL */
- ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
-
- /* Enable OCLK */
- if (!ret)
- ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
-
- return ret;
-}
-
-static int rj54n1_reg_init(struct i2c_client *client)
-{
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- int ret = rj54n1_set_clock(client);
-
- if (!ret)
- ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
- if (!ret)
- ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
-
- /* Set binning divisors */
- if (!ret)
- ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
- if (!ret)
- ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
-
- /* Switch to fixed resize mode */
- if (!ret)
- ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
- RESIZE_HOLD_SEL | 1);
-
- /* Set gain */
- if (!ret)
- ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
-
- /*
- * Mirror the image back: default is upside down and left-to-right...
- * Set manual preview / still shot switching
- */
- if (!ret)
- ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
-
- if (!ret)
- ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
-
- /* Auto exposure area */
- if (!ret)
- ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
- /* Check current auto WB config */
- if (!ret)
- ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
- if (ret >= 0) {
- rj54n1->auto_wb = ret & 0x80;
- ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
- }
- if (!ret)
- ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
-
- if (!ret)
- ret = reg_write(client, RJ54N1_RESET_STANDBY,
- E_EXCLK | DSP_RSTX | SEN_RSTX);
-
- /* Commit init */
- if (!ret)
- ret = rj54n1_commit(client);
-
- /* Take DSP, TG, sensor out of reset */
- if (!ret)
- ret = reg_write(client, RJ54N1_RESET_STANDBY,
- E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
-
- /* Start register update? Same register as 0x?FE in many bank_* sets */
- if (!ret)
- ret = reg_write(client, RJ54N1_FWFLG, 2);
-
- /* Constant taken from manufacturer's example */
- msleep(700);
-
- return ret;
-}
-
-static int rj54n1_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- const struct rj54n1_datafmt *fmt;
- int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE;
-
- dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
- __func__, mf->code, mf->width, mf->height);
-
- fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
- ARRAY_SIZE(rj54n1_colour_fmts));
- if (!fmt) {
- fmt = rj54n1->fmt;
- mf->code = fmt->code;
- }
-
- mf->field = V4L2_FIELD_NONE;
- mf->colorspace = fmt->colorspace;
-
- v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
- &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
-
- return 0;
-}
-
-static int rj54n1_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- const struct rj54n1_datafmt *fmt;
- int output_w, output_h, max_w, max_h,
- input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
- int ret;
-
- /*
- * The host driver can call us without .try_fmt(), so, we have to take
- * care ourseleves
- */
- rj54n1_try_fmt(sd, mf);
-
- /*
- * Verify if the sensor has just been powered on. TODO: replace this
- * with proper PM, when a suitable API is available.
- */
- ret = reg_read(client, RJ54N1_RESET_STANDBY);
- if (ret < 0)
- return ret;
-
- if (!(ret & E_EXCLK)) {
- ret = rj54n1_reg_init(client);
- if (ret < 0)
- return ret;
- }
-
- dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
- __func__, mf->code, mf->width, mf->height);
-
- /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
- switch (mf->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
- ret = reg_write(client, RJ54N1_OUT_SEL, 0);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
- break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
- ret = reg_write(client, RJ54N1_OUT_SEL, 0);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
- break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
- break;
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
- break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 4);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
- if (!ret)
- ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
- break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 4);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
- if (!ret)
- ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
- break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 4);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
- if (!ret)
- ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
- break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
- ret = reg_write(client, RJ54N1_OUT_SEL, 4);
- if (!ret)
- ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
- if (!ret)
- ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
- break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- ret = reg_write(client, RJ54N1_OUT_SEL, 5);
- break;
- default:
- ret = -EINVAL;
- }
-
- /* Special case: a raw mode with 10 bits of data per clock tick */
- if (!ret)
- ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
- (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2);
-
- if (ret < 0)
- return ret;
-
- /* Supported scales 1:1 >= scale > 1:16 */
- max_w = mf->width * (16 * 1024 - 1) / 1024;
- if (input_w > max_w)
- input_w = max_w;
- max_h = mf->height * (16 * 1024 - 1) / 1024;
- if (input_h > max_h)
- input_h = max_h;
-
- output_w = mf->width;
- output_h = mf->height;
-
- ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
- if (ret < 0)
- return ret;
-
- fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
- ARRAY_SIZE(rj54n1_colour_fmts));
-
- rj54n1->fmt = fmt;
- rj54n1->resize = ret;
- rj54n1->rect.width = input_w;
- rj54n1->rect.height = input_h;
- rj54n1->width = output_w;
- rj54n1->height = output_h;
-
- mf->width = output_w;
- mf->height = output_h;
- mf->field = V4L2_FIELD_NONE;
- mf->colorspace = fmt->colorspace;
-
- return 0;
-}
-
-static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
- return -EINVAL;
-
- if (id->match.addr != client->addr)
- return -ENODEV;
-
- id->ident = V4L2_IDENT_RJ54N1CB0C;
- id->revision = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int rj54n1_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
- reg->reg < 0x400 || reg->reg > 0x1fff)
- /* Registers > 0x0800 are only available from Sharp support */
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- reg->size = 1;
- reg->val = reg_read(client, reg->reg);
-
- if (reg->val > 0xff)
- return -EIO;
-
- return 0;
-}
-
-static int rj54n1_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
- reg->reg < 0x400 || reg->reg > 0x1fff)
- /* Registers >= 0x0800 are only available from Sharp support */
- return -EINVAL;
-
- if (reg->match.addr != client->addr)
- return -ENODEV;
-
- if (reg_write(client, reg->reg, reg->val) < 0)
- return -EIO;
-
- return 0;
-}
-#endif
-
-static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl);
- struct v4l2_subdev *sd = &rj54n1->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int data;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (ctrl->val)
- data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
- else
- data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_HFLIP:
- if (ctrl->val)
- data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
- else
- data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
- if (data < 0)
- return -EIO;
- return 0;
- case V4L2_CID_GAIN:
- if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0)
- return -EIO;
- return 0;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- /* Auto WB area - whole image */
- if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7,
- 0x80) < 0)
- return -EIO;
- rj54n1->auto_wb = ctrl->val;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
- .s_ctrl = rj54n1_s_ctrl,
-};
-
-static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
- .g_chip_ident = rj54n1_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = rj54n1_g_register,
- .s_register = rj54n1_s_register,
-#endif
-};
-
-static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags =
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
- if (soc_camera_apply_board_flags(icl, cfg) &
- V4L2_MBUS_PCLK_SAMPLE_RISING)
- return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
- else
- return reg_write(client, RJ54N1_OUT_SIGPO, 0);
-}
-
-static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
- .s_stream = rj54n1_s_stream,
- .s_mbus_fmt = rj54n1_s_fmt,
- .g_mbus_fmt = rj54n1_g_fmt,
- .try_mbus_fmt = rj54n1_try_fmt,
- .enum_mbus_fmt = rj54n1_enum_fmt,
- .g_crop = rj54n1_g_crop,
- .s_crop = rj54n1_s_crop,
- .cropcap = rj54n1_cropcap,
- .g_mbus_config = rj54n1_g_mbus_config,
- .s_mbus_config = rj54n1_s_mbus_config,
-};
-
-static struct v4l2_subdev_ops rj54n1_subdev_ops = {
- .core = &rj54n1_subdev_core_ops,
- .video = &rj54n1_subdev_video_ops,
-};
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int rj54n1_video_probe(struct i2c_client *client,
- struct rj54n1_pdata *priv)
-{
- int data1, data2;
- int ret;
-
- /* Read out the chip version register */
- data1 = reg_read(client, RJ54N1_DEV_CODE);
- data2 = reg_read(client, RJ54N1_DEV_CODE2);
-
- if (data1 != 0x51 || data2 != 0x10) {
- ret = -ENODEV;
- dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
- data1, data2);
- goto ei2c;
- }
-
- /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
- ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
- if (ret < 0)
- goto ei2c;
-
- dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
- data1, data2);
-
-ei2c:
- return ret;
-}
-
-static int rj54n1_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct rj54n1 *rj54n1;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct rj54n1_pdata *rj54n1_priv;
- int ret;
-
- if (!icl || !icl->priv) {
- dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
- return -EINVAL;
- }
-
- rj54n1_priv = icl->priv;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_warn(&adapter->dev,
- "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
- return -EIO;
- }
-
- rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL);
- if (!rj54n1)
- return -ENOMEM;
-
- v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
- v4l2_ctrl_handler_init(&rj54n1->hdl, 4);
- v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
- V4L2_CID_GAIN, 0, 127, 1, 66);
- v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
- V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
- if (rj54n1->hdl.error) {
- int err = rj54n1->hdl.error;
-
- kfree(rj54n1);
- return err;
- }
-
- rj54n1->clk_div = clk_div;
- rj54n1->rect.left = RJ54N1_COLUMN_SKIP;
- rj54n1->rect.top = RJ54N1_ROW_SKIP;
- rj54n1->rect.width = RJ54N1_MAX_WIDTH;
- rj54n1->rect.height = RJ54N1_MAX_HEIGHT;
- rj54n1->width = RJ54N1_MAX_WIDTH;
- rj54n1->height = RJ54N1_MAX_HEIGHT;
- rj54n1->fmt = &rj54n1_colour_fmts[0];
- rj54n1->resize = 1024;
- rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
- (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
-
- ret = rj54n1_video_probe(client, rj54n1_priv);
- if (ret < 0) {
- v4l2_ctrl_handler_free(&rj54n1->hdl);
- kfree(rj54n1);
- return ret;
- }
- return v4l2_ctrl_handler_setup(&rj54n1->hdl);
-}
-
-static int rj54n1_remove(struct i2c_client *client)
-{
- struct rj54n1 *rj54n1 = to_rj54n1(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- v4l2_device_unregister_subdev(&rj54n1->subdev);
- if (icl->free_bus)
- icl->free_bus(icl);
- v4l2_ctrl_handler_free(&rj54n1->hdl);
- kfree(rj54n1);
-
- return 0;
-}
-
-static const struct i2c_device_id rj54n1_id[] = {
- { "rj54n1cb0c", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, rj54n1_id);
-
-static struct i2c_driver rj54n1_i2c_driver = {
- .driver = {
- .name = "rj54n1cb0c",
- },
- .probe = rj54n1_probe,
- .remove = rj54n1_remove,
- .id_table = rj54n1_id,
-};
-
-module_i2c_driver(rj54n1_i2c_driver);
-
-MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
deleted file mode 100644
index 95007dda0c93..000000000000
--- a/drivers/media/video/s2255drv.c
+++ /dev/null
@@ -1,2689 +0,0 @@
-/*
- * s2255drv.c - a driver for the Sensoray 2255 USB video capture device
- *
- * Copyright (C) 2007-2010 by Sensoray Company Inc.
- * Dean Anderson
- *
- * Some video buffer code based on vivi driver:
- *
- * Sensoray 2255 device supports 4 simultaneous channels.
- * The channels are not "crossbar" inputs, they are physically
- * attached to separate video decoders.
- *
- * Because of USB2.0 bandwidth limitations. There is only a
- * certain amount of data which may be transferred at one time.
- *
- * Example maximum bandwidth utilization:
- *
- * -full size, color mode YUYV or YUV422P: 2 channels at once
- * -full or half size Grey scale: all 4 channels at once
- * -half size, color mode YUYV or YUV422P: all 4 channels at once
- * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
- * at once.
- *
- * 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/module.h>
-#include <linux/firmware.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/mm.h>
-#include <media/videobuf-vmalloc.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/vmalloc.h>
-#include <linux/usb.h>
-
-#define S2255_VERSION "1.22.1"
-#define FIRMWARE_FILE_NAME "f2255usb.bin"
-
-/* default JPEG quality */
-#define S2255_DEF_JPEG_QUAL 50
-/* vendor request in */
-#define S2255_VR_IN 0
-/* vendor request out */
-#define S2255_VR_OUT 1
-/* firmware query */
-#define S2255_VR_FW 0x30
-/* USB endpoint number for configuring the device */
-#define S2255_CONFIG_EP 2
-/* maximum time for DSP to start responding after last FW word loaded(ms) */
-#define S2255_DSP_BOOTTIME 800
-/* maximum time to wait for firmware to load (ms) */
-#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME)
-#define S2255_DEF_BUFS 16
-#define S2255_SETMODE_TIMEOUT 500
-#define S2255_VIDSTATUS_TIMEOUT 350
-#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL)
-#define S2255_MARKER_RESPONSE cpu_to_le32(0x2255ACACL)
-#define S2255_RESPONSE_SETMODE cpu_to_le32(0x01)
-#define S2255_RESPONSE_FW cpu_to_le32(0x10)
-#define S2255_RESPONSE_STATUS cpu_to_le32(0x20)
-#define S2255_USB_XFER_SIZE (16 * 1024)
-#define MAX_CHANNELS 4
-#define SYS_FRAMES 4
-/* maximum size is PAL full size plus room for the marker header(s) */
-#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096)
-#define DEF_USB_BLOCK S2255_USB_XFER_SIZE
-#define LINE_SZ_4CIFS_NTSC 640
-#define LINE_SZ_2CIFS_NTSC 640
-#define LINE_SZ_1CIFS_NTSC 320
-#define LINE_SZ_4CIFS_PAL 704
-#define LINE_SZ_2CIFS_PAL 704
-#define LINE_SZ_1CIFS_PAL 352
-#define NUM_LINES_4CIFS_NTSC 240
-#define NUM_LINES_2CIFS_NTSC 240
-#define NUM_LINES_1CIFS_NTSC 240
-#define NUM_LINES_4CIFS_PAL 288
-#define NUM_LINES_2CIFS_PAL 288
-#define NUM_LINES_1CIFS_PAL 288
-#define LINE_SZ_DEF 640
-#define NUM_LINES_DEF 240
-
-
-/* predefined settings */
-#define FORMAT_NTSC 1
-#define FORMAT_PAL 2
-
-#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */
-#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */
-#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */
-/* SCALE_4CIFSI is the 2 fields interpolated into one */
-#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */
-
-#define COLOR_YUVPL 1 /* YUV planar */
-#define COLOR_YUVPK 2 /* YUV packed */
-#define COLOR_Y8 4 /* monochrome */
-#define COLOR_JPG 5 /* JPEG */
-
-#define MASK_COLOR 0x000000ff
-#define MASK_JPG_QUALITY 0x0000ff00
-#define MASK_INPUT_TYPE 0x000f0000
-/* frame decimation. */
-#define FDEC_1 1 /* capture every frame. default */
-#define FDEC_2 2 /* capture every 2nd frame */
-#define FDEC_3 3 /* capture every 3rd frame */
-#define FDEC_5 5 /* capture every 5th frame */
-
-/*-------------------------------------------------------
- * Default mode parameters.
- *-------------------------------------------------------*/
-#define DEF_SCALE SCALE_4CIFS
-#define DEF_COLOR COLOR_YUVPL
-#define DEF_FDEC FDEC_1
-#define DEF_BRIGHT 0
-#define DEF_CONTRAST 0x5c
-#define DEF_SATURATION 0x80
-#define DEF_HUE 0
-
-/* usb config commands */
-#define IN_DATA_TOKEN cpu_to_le32(0x2255c0de)
-#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))
-#define CMD_STATUS cpu_to_le32((CMD_2255 | 0x40))
-
-struct s2255_mode {
- u32 format; /* input video format (NTSC, PAL) */
- u32 scale; /* output video scale */
- u32 color; /* output video color format */
- u32 fdec; /* frame decimation */
- u32 bright; /* brightness */
- u32 contrast; /* contrast */
- u32 saturation; /* saturation */
- u32 hue; /* hue (NTSC only)*/
- u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/
- u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */
- u32 restart; /* if DSP requires restart */
-};
-
-
-#define S2255_READ_IDLE 0
-#define S2255_READ_FRAME 1
-
-/* frame structure */
-struct s2255_framei {
- unsigned long size;
- unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
- void *lpvbits; /* image data */
- unsigned long cur_size; /* current data copied to it */
-};
-
-/* image buffer structure */
-struct s2255_bufferi {
- unsigned long dwFrames; /* number of frames in buffer */
- struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */
-};
-
-#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \
- DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
- DEF_HUE, 0, DEF_USB_BLOCK, 0}
-
-struct s2255_dmaqueue {
- struct list_head active;
- struct s2255_dev *dev;
-};
-
-/* for firmware loading, fw_state */
-#define S2255_FW_NOTLOADED 0
-#define S2255_FW_LOADED_DSPWAIT 1
-#define S2255_FW_SUCCESS 2
-#define S2255_FW_FAILED 3
-#define S2255_FW_DISCONNECTING 4
-#define S2255_FW_MARKER cpu_to_le32(0x22552f2f)
-/* 2255 read states */
-#define S2255_READ_IDLE 0
-#define S2255_READ_FRAME 1
-struct s2255_fw {
- int fw_loaded;
- int fw_size;
- struct urb *fw_urb;
- atomic_t fw_state;
- void *pfw_data;
- wait_queue_head_t wait_fw;
- const struct firmware *fw;
-};
-
-struct s2255_pipeinfo {
- u32 max_transfer_size;
- u32 cur_transfer_size;
- u8 *transfer_buffer;
- u32 state;
- void *stream_urb;
- void *dev; /* back pointer to s2255_dev struct*/
- u32 err_count;
- u32 idx;
-};
-
-struct s2255_fmt; /*forward declaration */
-struct s2255_dev;
-
-struct s2255_channel {
- struct video_device vdev;
- int resources;
- struct s2255_dmaqueue vidq;
- struct s2255_bufferi buffer;
- struct s2255_mode mode;
- /* jpeg compression */
- struct v4l2_jpegcompression jc;
- /* capture parameters (for high quality mode full size) */
- struct v4l2_captureparm cap_parm;
- int cur_frame;
- int last_frame;
-
- int b_acquire;
- /* allocated image size */
- unsigned long req_image_size;
- /* received packet size */
- unsigned long pkt_size;
- int bad_payload;
- unsigned long frame_count;
- /* if JPEG image */
- int jpg_size;
- /* if channel configured to default state */
- int configured;
- wait_queue_head_t wait_setmode;
- int setmode_ready;
- /* video status items */
- int vidstatus;
- wait_queue_head_t wait_vidstatus;
- int vidstatus_ready;
- unsigned int width;
- unsigned int height;
- const struct s2255_fmt *fmt;
- int idx; /* channel number on device, 0-3 */
-};
-
-
-struct s2255_dev {
- struct s2255_channel channel[MAX_CHANNELS];
- struct v4l2_device v4l2_dev;
- atomic_t num_channels;
- int frames;
- struct mutex lock; /* channels[].vdev.lock */
- struct mutex open_lock;
- struct usb_device *udev;
- struct usb_interface *interface;
- u8 read_endpoint;
- struct timer_list timer;
- struct s2255_fw *fw_data;
- struct s2255_pipeinfo pipe;
- u32 cc; /* current channel */
- int frame_ready;
- int chn_ready;
- spinlock_t slock;
- /* dsp firmware version (f2255usb.bin) */
- int dsp_fw_ver;
- u16 pid; /* product id */
-};
-
-static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct s2255_dev, v4l2_dev);
-}
-
-struct s2255_fmt {
- char *name;
- u32 fourcc;
- int depth;
-};
-
-/* buffer for one video frame */
-struct s2255_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- const struct s2255_fmt *fmt;
-};
-
-struct s2255_fh {
- struct s2255_dev *dev;
- struct videobuf_queue vb_vidq;
- enum v4l2_buf_type type;
- struct s2255_channel *channel;
- int resources;
-};
-
-/* current cypress EEPROM firmware version */
-#define S2255_CUR_USB_FWVER ((3 << 8) | 12)
-/* current DSP FW version */
-#define S2255_CUR_DSP_FWVER 10104
-/* Need DSP version 5+ for video status feature */
-#define S2255_MIN_DSP_STATUS 5
-#define S2255_MIN_DSP_COLORFILTER 8
-#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC)
-
-/* private V4L2 controls */
-
-/*
- * The following chart displays how COLORFILTER should be set
- * =========================================================
- * = fourcc = COLORFILTER =
- * = ===============================
- * = = 0 = 1 =
- * =========================================================
- * = V4L2_PIX_FMT_GREY(Y8) = monochrome from = monochrome=
- * = = s-video or = composite =
- * = = B/W camera = input =
- * =========================================================
- * = other = color, svideo = color, =
- * = = = composite =
- * =========================================================
- *
- * Notes:
- * channels 0-3 on 2255 are composite
- * channels 0-1 on 2257 are composite, 2-3 are s-video
- * If COLORFILTER is 0 with a composite color camera connected,
- * the output will appear monochrome but hatching
- * will occur.
- * COLORFILTER is different from "color killer" and "color effects"
- * for reasons above.
- */
-#define S2255_V4L2_YC_ON 1
-#define S2255_V4L2_YC_OFF 0
-#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0)
-
-/* frame prefix size (sent once every frame) */
-#define PREFIX_SIZE 512
-
-/* Channels on box are in reverse order */
-static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
-
-static int debug;
-static int *s2255_debug = &debug;
-
-static int s2255_start_readpipe(struct s2255_dev *dev);
-static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_channel *channel);
-static int s2255_stop_acquire(struct s2255_channel *channel);
-static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
- int jpgsize);
-static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
-static int s2255_board_shutdown(struct s2255_dev *dev);
-static void s2255_fwload_start(struct s2255_dev *dev, int reset);
-static void s2255_destroy(struct s2255_dev *dev);
-static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
- u16 index, u16 value, void *buf,
- s32 buf_len, int bOut);
-
-/* dev_err macro with driver name */
-#define S2255_DRIVER_NAME "s2255"
-#define s2255_dev_err(dev, fmt, arg...) \
- dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (*s2255_debug >= (level)) { \
- printk(KERN_DEBUG S2255_DRIVER_NAME \
- ": " fmt, ##arg); \
- } \
- } while (0)
-
-static struct usb_driver s2255_driver;
-
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
-
-/* start video number */
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-
-/* Enable jpeg capture. */
-static int jpeg_enable = 1;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
-module_param(video_nr, int, 0644);
-MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
-module_param(jpeg_enable, int, 0644);
-MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
-
-/* USB device table */
-#define USB_SENSORAY_VID 0x1943
-static struct usb_device_id s2255_table[] = {
- {USB_DEVICE(USB_SENSORAY_VID, 0x2255)},
- {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, s2255_table);
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(400)
-
-/* image formats. */
-/* JPEG formats must be defined last to support jpeg_enable parameter */
-static const struct s2255_fmt formats[] = {
- {
- .name = "4:2:2, planar, YUV422P",
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .depth = 16
-
- }, {
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16
-
- }, {
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16
- }, {
- .name = "8bpp GREY",
- .fourcc = V4L2_PIX_FMT_GREY,
- .depth = 8
- }, {
- .name = "JPG",
- .fourcc = V4L2_PIX_FMT_JPEG,
- .depth = 24
- }, {
- .name = "MJPG",
- .fourcc = V4L2_PIX_FMT_MJPEG,
- .depth = 24
- }
-};
-
-static int norm_maxw(struct video_device *vdev)
-{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
- LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
-}
-
-static int norm_maxh(struct video_device *vdev)
-{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
- (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
-}
-
-static int norm_minw(struct video_device *vdev)
-{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
- LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
-}
-
-static int norm_minh(struct video_device *vdev)
-{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
- (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
-}
-
-
-/*
- * TODO: fixme: move YUV reordering to hardware
- * converts 2255 planar format to yuyv or uyvy
- */
-static void planar422p_to_yuv_packed(const unsigned char *in,
- unsigned char *out,
- int width, int height,
- int fmt)
-{
- unsigned char *pY;
- unsigned char *pCb;
- unsigned char *pCr;
- unsigned long size = height * width;
- unsigned int i;
- pY = (unsigned char *)in;
- pCr = (unsigned char *)in + height * width;
- pCb = (unsigned char *)in + height * width + (height * width / 2);
- for (i = 0; i < size * 2; i += 4) {
- out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;
- out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;
- out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;
- out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;
- }
- return;
-}
-
-static void s2255_reset_dsppower(struct s2255_dev *dev)
-{
- s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
- msleep(10);
- s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
- msleep(600);
- s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
- return;
-}
-
-/* kickstarts the firmware loading. from probe
- */
-static void s2255_timer(unsigned long user_data)
-{
- struct s2255_fw *data = (struct s2255_fw *)user_data;
- dprintk(100, "%s\n", __func__);
- if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
- printk(KERN_ERR "s2255: can't submit urb\n");
- atomic_set(&data->fw_state, S2255_FW_FAILED);
- /* wake up anything waiting for the firmware */
- wake_up(&data->wait_fw);
- return;
- }
-}
-
-
-/* this loads the firmware asynchronously.
- Originally this was done synchroously in probe.
- But it is better to load it asynchronously here than block
- inside the probe function. Blocking inside probe affects boot time.
- FW loading is triggered by the timer in the probe function
-*/
-static void s2255_fwchunk_complete(struct urb *urb)
-{
- struct s2255_fw *data = urb->context;
- struct usb_device *udev = urb->dev;
- int len;
- dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
- if (urb->status) {
- dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
- atomic_set(&data->fw_state, S2255_FW_FAILED);
- /* wake up anything waiting for the firmware */
- wake_up(&data->wait_fw);
- return;
- }
- if (data->fw_urb == NULL) {
- s2255_dev_err(&udev->dev, "disconnected\n");
- atomic_set(&data->fw_state, S2255_FW_FAILED);
- /* wake up anything waiting for the firmware */
- wake_up(&data->wait_fw);
- return;
- }
-#define CHUNK_SIZE 512
- /* all USB transfers must be done with continuous kernel memory.
- can't allocate more than 128k in current linux kernel, so
- upload the firmware in chunks
- */
- if (data->fw_loaded < data->fw_size) {
- len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ?
- data->fw_size % CHUNK_SIZE : CHUNK_SIZE;
-
- if (len < CHUNK_SIZE)
- memset(data->pfw_data, 0, CHUNK_SIZE);
-
- dprintk(100, "completed len %d, loaded %d \n", len,
- data->fw_loaded);
-
- memcpy(data->pfw_data,
- (char *) data->fw->data + data->fw_loaded, len);
-
- usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2),
- data->pfw_data, CHUNK_SIZE,
- s2255_fwchunk_complete, data);
- if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
- dev_err(&udev->dev, "failed submit URB\n");
- atomic_set(&data->fw_state, S2255_FW_FAILED);
- /* wake up anything waiting for the firmware */
- wake_up(&data->wait_fw);
- return;
- }
- data->fw_loaded += len;
- } else {
- atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
- dprintk(100, "%s: firmware upload complete\n", __func__);
- }
- return;
-
-}
-
-static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
-{
- struct s2255_dmaqueue *dma_q = &channel->vidq;
- struct s2255_buffer *buf;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- unsigned long flags = 0;
- int rc = 0;
- spin_lock_irqsave(&dev->slock, flags);
- if (list_empty(&dma_q->active)) {
- dprintk(1, "No active queue to serve\n");
- rc = -1;
- goto unlock;
- }
- buf = list_entry(dma_q->active.next,
- struct s2255_buffer, vb.queue);
- list_del(&buf->vb.queue);
- do_gettimeofday(&buf->vb.ts);
- s2255_fillbuff(channel, buf, jpgsize);
- wake_up(&buf->vb.done);
- dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
-unlock:
- spin_unlock_irqrestore(&dev->slock, flags);
- return rc;
-}
-
-static const struct s2255_fmt *format_by_fourcc(int fourcc)
-{
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(formats); i++) {
- if (-1 == formats[i].fourcc)
- continue;
- if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
- (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
- continue;
- if (formats[i].fourcc == fourcc)
- return formats + i;
- }
- return NULL;
-}
-
-/* video buffer vmalloc implementation based partly on VIVI driver which is
- * Copyright (c) 2006 by
- * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- * Ted Walther <ted--a.t--enumera.com>
- * John Sokol <sokol--a.t--videotechnology.com>
- * http://v4l.videotechnology.com/
- *
- */
-static void s2255_fillbuff(struct s2255_channel *channel,
- struct s2255_buffer *buf, int jpgsize)
-{
- int pos = 0;
- struct timeval ts;
- const char *tmpbuf;
- char *vbuf = videobuf_to_vmalloc(&buf->vb);
- unsigned long last_frame;
-
- if (!vbuf)
- return;
- last_frame = channel->last_frame;
- if (last_frame != -1) {
- tmpbuf =
- (const char *)channel->buffer.frame[last_frame].lpvbits;
- switch (buf->fmt->fourcc) {
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
- vbuf, buf->vb.width,
- buf->vb.height,
- buf->fmt->fourcc);
- break;
- case V4L2_PIX_FMT_GREY:
- memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
- break;
- case V4L2_PIX_FMT_JPEG:
- case V4L2_PIX_FMT_MJPEG:
- buf->vb.size = jpgsize;
- memcpy(vbuf, tmpbuf, buf->vb.size);
- break;
- case V4L2_PIX_FMT_YUV422P:
- memcpy(vbuf, tmpbuf,
- buf->vb.width * buf->vb.height * 2);
- break;
- default:
- printk(KERN_DEBUG "s2255: unknown format?\n");
- }
- channel->last_frame = -1;
- } else {
- printk(KERN_ERR "s2255: =======no frame\n");
- return;
-
- }
- dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
- (unsigned long)vbuf, pos);
- /* tell v4l buffer was filled */
-
- buf->vb.field_count = channel->frame_count * 2;
- do_gettimeofday(&ts);
- buf->vb.ts = ts;
- buf->vb.state = VIDEOBUF_DONE;
-}
-
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- *size = channel->width * channel->height * (channel->fmt->depth >> 3);
-
- if (0 == *count)
- *count = S2255_DEF_BUFS;
-
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
-{
- dprintk(4, "%s\n", __func__);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- int rc;
- int w = channel->width;
- int h = channel->height;
- dprintk(4, "%s, field=%d\n", __func__, field);
- if (channel->fmt == NULL)
- return -EINVAL;
-
- if ((w < norm_minw(&channel->vdev)) ||
- (w > norm_maxw(&channel->vdev)) ||
- (h < norm_minh(&channel->vdev)) ||
- (h > norm_maxh(&channel->vdev))) {
- dprintk(4, "invalid buffer prepare\n");
- return -EINVAL;
- }
- buf->vb.size = w * h * (channel->fmt->depth >> 3);
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
- dprintk(4, "invalid buffer prepare\n");
- return -EINVAL;
- }
-
- buf->fmt = channel->fmt;
- buf->vb.width = w;
- buf->vb.height = h;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dmaqueue *vidq = &channel->vidq;
- dprintk(1, "%s\n", __func__);
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- dprintk(4, "%s %d\n", __func__, fh->channel->idx);
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops s2255_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-
-static int res_get(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- /* is it free? */
- if (channel->resources)
- return 0; /* no, someone else uses it */
- /* it's free, grab it */
- channel->resources = 1;
- fh->resources = 1;
- dprintk(1, "s2255: res: get\n");
- return 1;
-}
-
-static int res_locked(struct s2255_fh *fh)
-{
- return fh->channel->resources;
-}
-
-static int res_check(struct s2255_fh *fh)
-{
- return fh->resources;
-}
-
-
-static void res_free(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- channel->resources = 0;
- fh->resources = 0;
- dprintk(1, "res: put\n");
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *qmenu)
-{
- static const char *colorfilter[] = {
- "Off",
- "On",
- NULL
- };
- if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) {
- int i;
- const char **menu_items = colorfilter;
- for (i = 0; i < qmenu->index && menu_items[i]; i++)
- ; /* do nothing (from v4l2-common.c) */
- if (menu_items[i] == NULL || menu_items[i][0] == '\0')
- return -EINVAL;
- strlcpy(qmenu->name, menu_items[qmenu->index],
- sizeof(qmenu->name));
- return 0;
- }
- return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- strlcpy(cap->driver, "s2255", sizeof(cap->driver));
- strlcpy(cap->card, "s2255", sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- 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;
- dprintk(4, "name %s\n", formats[index].name);
- strlcpy(f->description, formats[index].name, sizeof(f->description));
- f->pixelformat = formats[index].fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
-
- f->fmt.pix.width = channel->width;
- f->fmt.pix.height = channel->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = channel->fmt->fourcc;
- f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
- 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)
-{
- const struct s2255_fmt *fmt;
- enum v4l2_field field;
- int b_any_field = 0;
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc;
- is_ntsc =
- (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
- if (fmt == NULL)
- return -EINVAL;
-
- field = f->fmt.pix.field;
- if (field == V4L2_FIELD_ANY)
- b_any_field = 1;
-
- dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
- __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
- if (is_ntsc) {
- /* NTSC */
- if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
- f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
- if (b_any_field) {
- field = V4L2_FIELD_SEQ_TB;
- } else if (!((field == V4L2_FIELD_INTERLACED) ||
- (field == V4L2_FIELD_SEQ_TB) ||
- (field == V4L2_FIELD_INTERLACED_TB))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
- } else {
- f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
- if (b_any_field) {
- field = V4L2_FIELD_TOP;
- } else if (!((field == V4L2_FIELD_TOP) ||
- (field == V4L2_FIELD_BOTTOM))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
-
- }
- if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
- f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
- else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
- f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
- else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
- f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
- else
- f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
- } else {
- /* PAL */
- if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
- f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
- if (b_any_field) {
- field = V4L2_FIELD_SEQ_TB;
- } else if (!((field == V4L2_FIELD_INTERLACED) ||
- (field == V4L2_FIELD_SEQ_TB) ||
- (field == V4L2_FIELD_INTERLACED_TB))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
- } else {
- f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
- if (b_any_field) {
- field = V4L2_FIELD_TOP;
- } else if (!((field == V4L2_FIELD_TOP) ||
- (field == V4L2_FIELD_BOTTOM))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
- }
- if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
- f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
- field = V4L2_FIELD_SEQ_TB;
- } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
- f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
- field = V4L2_FIELD_TOP;
- } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
- f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
- field = V4L2_FIELD_TOP;
- } else {
- f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
- field = V4L2_FIELD_TOP;
- }
- }
- f->fmt.pix.field = field;
- f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- dprintk(50, "%s: set width %d height %d field %d\n", __func__,
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- const struct s2255_fmt *fmt;
- struct videobuf_queue *q = &fh->vb_vidq;
- struct s2255_mode mode;
- int ret;
-
- ret = vidioc_try_fmt_vid_cap(file, fh, f);
-
- if (ret < 0)
- return ret;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
- if (fmt == NULL)
- return -EINVAL;
-
- mutex_lock(&q->vb_lock);
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- dprintk(1, "queue busy\n");
- ret = -EBUSY;
- goto out_s_fmt;
- }
-
- if (res_locked(fh)) {
- dprintk(1, "%s: channel busy\n", __func__);
- ret = -EBUSY;
- goto out_s_fmt;
- }
- mode = channel->mode;
- channel->fmt = fmt;
- channel->width = f->fmt.pix.width;
- channel->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
- if (channel->width > norm_minw(&channel->vdev)) {
- if (channel->height > norm_minh(&channel->vdev)) {
- if (channel->cap_parm.capturemode &
- V4L2_MODE_HIGHQUALITY)
- mode.scale = SCALE_4CIFSI;
- else
- mode.scale = SCALE_4CIFS;
- } else
- mode.scale = SCALE_2CIFS;
-
- } else {
- mode.scale = SCALE_1CIFS;
- }
- /* color mode */
- switch (channel->fmt->fourcc) {
- case V4L2_PIX_FMT_GREY:
- mode.color &= ~MASK_COLOR;
- mode.color |= COLOR_Y8;
- break;
- case V4L2_PIX_FMT_JPEG:
- case V4L2_PIX_FMT_MJPEG:
- mode.color &= ~MASK_COLOR;
- mode.color |= COLOR_JPG;
- mode.color |= (channel->jc.quality << 8);
- break;
- case V4L2_PIX_FMT_YUV422P:
- mode.color &= ~MASK_COLOR;
- mode.color |= COLOR_YUVPL;
- break;
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- default:
- mode.color &= ~MASK_COLOR;
- mode.color |= COLOR_YUVPK;
- break;
- }
- if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
- mode.restart = 1;
- else if (mode.scale != channel->mode.scale)
- mode.restart = 1;
- else if (mode.format != channel->mode.format)
- mode.restart = 1;
- channel->mode = mode;
- (void) s2255_set_mode(channel, &mode);
- ret = 0;
-out_s_fmt:
- mutex_unlock(&q->vb_lock);
- return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_reqbufs(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_querybuf(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_qbuf(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
- return rc;
-}
-
-/* write to the configuration pipe, synchronously */
-static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
- int size)
-{
- int pipe;
- int done;
- long retval = -1;
- if (udev) {
- pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP);
- retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500);
- }
- return retval;
-}
-
-static u32 get_transfer_size(struct s2255_mode *mode)
-{
- int linesPerFrame = LINE_SZ_DEF;
- int pixelsPerLine = NUM_LINES_DEF;
- u32 outImageSize;
- u32 usbInSize;
- unsigned int mask_mult;
-
- if (mode == NULL)
- return 0;
-
- if (mode->format == FORMAT_NTSC) {
- switch (mode->scale) {
- case SCALE_4CIFS:
- case SCALE_4CIFSI:
- linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
- pixelsPerLine = LINE_SZ_4CIFS_NTSC;
- break;
- case SCALE_2CIFS:
- linesPerFrame = NUM_LINES_2CIFS_NTSC;
- pixelsPerLine = LINE_SZ_2CIFS_NTSC;
- break;
- case SCALE_1CIFS:
- linesPerFrame = NUM_LINES_1CIFS_NTSC;
- pixelsPerLine = LINE_SZ_1CIFS_NTSC;
- break;
- default:
- break;
- }
- } else if (mode->format == FORMAT_PAL) {
- switch (mode->scale) {
- case SCALE_4CIFS:
- case SCALE_4CIFSI:
- linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
- pixelsPerLine = LINE_SZ_4CIFS_PAL;
- break;
- case SCALE_2CIFS:
- linesPerFrame = NUM_LINES_2CIFS_PAL;
- pixelsPerLine = LINE_SZ_2CIFS_PAL;
- break;
- case SCALE_1CIFS:
- linesPerFrame = NUM_LINES_1CIFS_PAL;
- pixelsPerLine = LINE_SZ_1CIFS_PAL;
- break;
- default:
- break;
- }
- }
- outImageSize = linesPerFrame * pixelsPerLine;
- if ((mode->color & MASK_COLOR) != COLOR_Y8) {
- /* 2 bytes/pixel if not monochrome */
- outImageSize *= 2;
- }
-
- /* total bytes to send including prefix and 4K padding;
- must be a multiple of USB_READ_SIZE */
- usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */
- mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1;
- /* if size not a multiple of USB_READ_SIZE */
- if (usbInSize & ~mask_mult)
- usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK);
- return usbInSize;
-}
-
-static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
-{
- struct device *dev = &sdev->udev->dev;
- dev_info(dev, "------------------------------------------------\n");
- dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
- dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
- dev_info(dev, "bright: 0x%x\n", mode->bright);
- dev_info(dev, "------------------------------------------------\n");
-}
-
-/*
- * set mode is the function which controls the DSP.
- * the restart parameter in struct s2255_mode should be set whenever
- * the image size could change via color format, video system or image
- * size.
- * When the restart parameter is set, we sleep for ONE frame to allow the
- * DSP time to get the new frame
- */
-static int s2255_set_mode(struct s2255_channel *channel,
- struct s2255_mode *mode)
-{
- int res;
- __le32 *buffer;
- unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- dprintk(3, "%s channel: %d\n", __func__, channel->idx);
- /* if JPEG, set the quality */
- if ((mode->color & MASK_COLOR) == COLOR_JPG) {
- mode->color &= ~MASK_COLOR;
- mode->color |= COLOR_JPG;
- mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (channel->jc.quality << 8);
- }
- /* save the mode */
- channel->mode = *mode;
- channel->req_image_size = get_transfer_size(mode);
- dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
- /* set the mode */
- buffer[0] = IN_DATA_TOKEN;
- buffer[1] = (__le32) cpu_to_le32(chn_rev);
- buffer[2] = CMD_SET_MODE;
- memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
- channel->setmode_ready = 0;
- res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- if (debug)
- s2255_print_cfg(dev, mode);
- kfree(buffer);
- /* wait at least 3 frames before continuing */
- if (mode->restart) {
- wait_event_timeout(channel->wait_setmode,
- (channel->setmode_ready != 0),
- msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
- if (channel->setmode_ready != 1) {
- printk(KERN_DEBUG "s2255: no set mode response\n");
- res = -EFAULT;
- }
- }
- /* clear the restart flag */
- channel->mode.restart = 0;
- dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
- return res;
-}
-
-static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
-{
- int res;
- __le32 *buffer;
- u32 chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- dprintk(4, "%s chan %d\n", __func__, channel->idx);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
- /* form the get vid status command */
- buffer[0] = IN_DATA_TOKEN;
- buffer[1] = (__le32) cpu_to_le32(chn_rev);
- buffer[2] = CMD_STATUS;
- *pstatus = 0;
- channel->vidstatus_ready = 0;
- res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- kfree(buffer);
- wait_event_timeout(channel->wait_vidstatus,
- (channel->vidstatus_ready != 0),
- msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
- if (channel->vidstatus_ready != 1) {
- printk(KERN_DEBUG "s2255: no vidstatus response\n");
- res = -EFAULT;
- }
- *pstatus = channel->vidstatus;
- dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
- return res;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- int res;
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
- int j;
- dprintk(4, "%s\n", __func__);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&dev->udev->dev, "invalid fh type0\n");
- return -EINVAL;
- }
- if (i != fh->type) {
- dev_err(&dev->udev->dev, "invalid fh type1\n");
- return -EINVAL;
- }
-
- if (!res_get(fh)) {
- s2255_dev_err(&dev->udev->dev, "stream busy\n");
- return -EBUSY;
- }
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
- channel->frame_count = 0;
- for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = S2255_READ_IDLE;
- channel->buffer.frame[j].cur_size = 0;
- }
- res = videobuf_streamon(&fh->vb_vidq);
- if (res == 0) {
- s2255_start_acquire(channel);
- channel->b_acquire = 1;
- } else
- res_free(fh);
-
- return res;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct s2255_fh *fh = priv;
- dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- printk(KERN_ERR "invalid fh type0\n");
- return -EINVAL;
- }
- if (i != fh->type) {
- printk(KERN_ERR "invalid type i\n");
- return -EINVAL;
- }
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
- struct s2255_fh *fh = priv;
- struct s2255_mode mode;
- struct videobuf_queue *q = &fh->vb_vidq;
- int ret = 0;
- mutex_lock(&q->vb_lock);
- if (videobuf_queue_is_busy(q)) {
- dprintk(1, "queue busy\n");
- ret = -EBUSY;
- goto out_s_std;
- }
- if (res_locked(fh)) {
- dprintk(1, "can't change standard after started\n");
- ret = -EBUSY;
- goto out_s_std;
- }
- mode = fh->channel->mode;
- if (*i & V4L2_STD_NTSC) {
- dprintk(4, "%s NTSC\n", __func__);
- /* if changing format, reset frame decimation/intervals */
- if (mode.format != FORMAT_NTSC) {
- mode.restart = 1;
- mode.format = FORMAT_NTSC;
- mode.fdec = FDEC_1;
- }
- } else if (*i & V4L2_STD_PAL) {
- dprintk(4, "%s PAL\n", __func__);
- if (mode.format != FORMAT_PAL) {
- mode.restart = 1;
- mode.format = FORMAT_PAL;
- mode.fdec = FDEC_1;
- }
- } else {
- ret = -EINVAL;
- }
- if (mode.restart)
- s2255_set_mode(fh->channel, &mode);
-out_s_std:
- mutex_unlock(&q->vb_lock);
- return ret;
-}
-
-/* Sensoray 2255 is a multiple channel capture device.
- It does not have a "crossbar" of inputs.
- We use one V4L device per channel. The user must
- be aware that certain combinations are not allowed.
- For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
- at once in color(you can do full fps on 4 channels with greyscale.
-*/
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
- u32 status = 0;
- if (inp->index != 0)
- return -EINVAL;
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = S2255_NORMS;
- inp->status = 0;
- if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
- int rc;
- rc = s2255_cmd_status(fh->channel, &status);
- dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
- if (rc == 0)
- inp->status = (status & 0x01) ? 0
- : V4L2_IN_ST_NO_SIGNAL;
- }
- switch (dev->pid) {
- case 0x2255:
- default:
- strlcpy(inp->name, "Composite", sizeof(inp->name));
- break;
- case 0x2257:
- strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
- sizeof(inp->name));
- break;
- }
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- if (i > 0)
- return -EINVAL;
- return 0;
-}
-
-/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dev *dev = fh->dev;
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT);
- break;
- case V4L2_CID_CONTRAST:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST);
- break;
- case V4L2_CID_SATURATION:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION);
- break;
- case V4L2_CID_HUE:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE);
- break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
- strlcpy(qc->name, "Color Filter", sizeof(qc->name));
- qc->type = V4L2_CTRL_TYPE_MENU;
- qc->minimum = 0;
- qc->maximum = 1;
- qc->step = 1;
- qc->default_value = 1;
- qc->flags = 0;
- break;
- default:
- return -EINVAL;
- }
- dprintk(4, "%s, id %d\n", __func__, qc->id);
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = channel->mode.bright;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = channel->mode.contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = channel->mode.saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = channel->mode.hue;
- break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
- ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
- break;
- default:
- return -EINVAL;
- }
- dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- struct s2255_mode mode;
- mode = channel->mode;
- dprintk(4, "%s\n", __func__);
- /* update the mode to the corresponding value */
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- mode.bright = ctrl->value;
- break;
- case V4L2_CID_CONTRAST:
- mode.contrast = ctrl->value;
- break;
- case V4L2_CID_HUE:
- mode.hue = ctrl->value;
- break;
- case V4L2_CID_SATURATION:
- mode.saturation = ctrl->value;
- break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
- mode.color &= ~MASK_INPUT_TYPE;
- mode.color |= ((ctrl->value ? 0 : 1) << 16);
- break;
- default:
- return -EINVAL;
- }
- mode.restart = 0;
- /* set mode here. Note: stream does not need restarted.
- some V4L programs restart stream unnecessarily
- after a s_crtl.
- */
- s2255_set_mode(fh->channel, &mode);
- return 0;
-}
-
-static int vidioc_g_jpegcomp(struct file *file, void *priv,
- struct v4l2_jpegcompression *jc)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- *jc = channel->jc;
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
- return 0;
-}
-
-static int vidioc_s_jpegcomp(struct file *file, void *priv,
- struct v4l2_jpegcompression *jc)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- if (jc->quality < 0 || jc->quality > 100)
- return -EINVAL;
- channel->jc.quality = jc->quality;
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
- return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
- struct v4l2_streamparm *sp)
-{
- struct s2255_fh *fh = priv;
- __u32 def_num, def_dem;
- struct s2255_channel *channel = fh->channel;
- if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(sp, 0, sizeof(struct v4l2_streamparm));
- sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- sp->parm.capture.capturemode = channel->cap_parm.capturemode;
- def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
- sp->parm.capture.timeperframe.denominator = def_dem;
- switch (channel->mode.fdec) {
- default:
- case FDEC_1:
- sp->parm.capture.timeperframe.numerator = def_num;
- break;
- case FDEC_2:
- sp->parm.capture.timeperframe.numerator = def_num * 2;
- break;
- case FDEC_3:
- sp->parm.capture.timeperframe.numerator = def_num * 3;
- break;
- case FDEC_5:
- sp->parm.capture.timeperframe.numerator = def_num * 5;
- break;
- }
- dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
- sp->parm.capture.capturemode,
- sp->parm.capture.timeperframe.numerator,
- sp->parm.capture.timeperframe.denominator);
- return 0;
-}
-
-static int vidioc_s_parm(struct file *file, void *priv,
- struct v4l2_streamparm *sp)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- struct s2255_mode mode;
- int fdec = FDEC_1;
- __u32 def_num, def_dem;
- if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- mode = channel->mode;
- /* high quality capture mode requires a stream restart */
- if (channel->cap_parm.capturemode
- != sp->parm.capture.capturemode && res_locked(fh))
- return -EBUSY;
- def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
- if (def_dem != sp->parm.capture.timeperframe.denominator)
- sp->parm.capture.timeperframe.numerator = def_num;
- else if (sp->parm.capture.timeperframe.numerator <= def_num)
- sp->parm.capture.timeperframe.numerator = def_num;
- else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) {
- sp->parm.capture.timeperframe.numerator = def_num * 2;
- fdec = FDEC_2;
- } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) {
- sp->parm.capture.timeperframe.numerator = def_num * 3;
- fdec = FDEC_3;
- } else {
- sp->parm.capture.timeperframe.numerator = def_num * 5;
- fdec = FDEC_5;
- }
- mode.fdec = fdec;
- sp->parm.capture.timeperframe.denominator = def_dem;
- s2255_set_mode(channel, &mode);
- dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
- __func__,
- sp->parm.capture.capturemode,
- sp->parm.capture.timeperframe.numerator,
- sp->parm.capture.timeperframe.denominator, fdec);
- return 0;
-}
-
-static int vidioc_enum_frameintervals(struct file *file, void *priv,
- struct v4l2_frmivalenum *fe)
-{
- int is_ntsc = 0;
-#define NUM_FRAME_ENUMS 4
- int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
- if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS)
- return -EINVAL;
- switch (fe->width) {
- case 640:
- if (fe->height != 240 && fe->height != 480)
- return -EINVAL;
- is_ntsc = 1;
- break;
- case 320:
- if (fe->height != 240)
- return -EINVAL;
- is_ntsc = 1;
- break;
- case 704:
- if (fe->height != 288 && fe->height != 576)
- return -EINVAL;
- break;
- case 352:
- if (fe->height != 288)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fe->discrete.denominator = is_ntsc ? 30000 : 25000;
- fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
- dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
- fe->discrete.denominator);
- return 0;
-}
-
-static int s2255_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = video_drvdata(file);
- struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- struct s2255_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int state;
- dprintk(1, "s2255: open called (dev=%s)\n",
- video_device_node_name(vdev));
- /*
- * open lock necessary to prevent multiple instances
- * of v4l-conf (or other programs) from simultaneously
- * reloading firmware.
- */
- mutex_lock(&dev->open_lock);
- state = atomic_read(&dev->fw_data->fw_state);
- switch (state) {
- case S2255_FW_DISCONNECTING:
- mutex_unlock(&dev->open_lock);
- return -ENODEV;
- case S2255_FW_FAILED:
- s2255_dev_err(&dev->udev->dev,
- "firmware load failed. retrying.\n");
- s2255_fwload_start(dev, 1);
- wait_event_timeout(dev->fw_data->wait_fw,
- ((atomic_read(&dev->fw_data->fw_state)
- == S2255_FW_SUCCESS) ||
- (atomic_read(&dev->fw_data->fw_state)
- == S2255_FW_DISCONNECTING)),
- msecs_to_jiffies(S2255_LOAD_TIMEOUT));
- /* state may have changed, re-read */
- state = atomic_read(&dev->fw_data->fw_state);
- break;
- case S2255_FW_NOTLOADED:
- case S2255_FW_LOADED_DSPWAIT:
- /* give S2255_LOAD_TIMEOUT time for firmware to load in case
- driver loaded and then device immediately opened */
- printk(KERN_INFO "%s waiting for firmware load\n", __func__);
- wait_event_timeout(dev->fw_data->wait_fw,
- ((atomic_read(&dev->fw_data->fw_state)
- == S2255_FW_SUCCESS) ||
- (atomic_read(&dev->fw_data->fw_state)
- == S2255_FW_DISCONNECTING)),
- msecs_to_jiffies(S2255_LOAD_TIMEOUT));
- /* state may have changed, re-read */
- state = atomic_read(&dev->fw_data->fw_state);
- break;
- case S2255_FW_SUCCESS:
- default:
- break;
- }
- /* state may have changed in above switch statement */
- switch (state) {
- case S2255_FW_SUCCESS:
- break;
- case S2255_FW_FAILED:
- printk(KERN_INFO "2255 firmware load failed.\n");
- mutex_unlock(&dev->open_lock);
- return -ENODEV;
- case S2255_FW_DISCONNECTING:
- printk(KERN_INFO "%s: disconnecting\n", __func__);
- mutex_unlock(&dev->open_lock);
- return -ENODEV;
- case S2255_FW_LOADED_DSPWAIT:
- case S2255_FW_NOTLOADED:
- printk(KERN_INFO "%s: firmware not loaded yet"
- "please try again later\n",
- __func__);
- /*
- * Timeout on firmware load means device unusable.
- * Set firmware failure state.
- * On next s2255_open the firmware will be reloaded.
- */
- atomic_set(&dev->fw_data->fw_state,
- S2255_FW_FAILED);
- mutex_unlock(&dev->open_lock);
- return -EAGAIN;
- default:
- printk(KERN_INFO "%s: unknown state\n", __func__);
- mutex_unlock(&dev->open_lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->open_lock);
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
- file->private_data = fh;
- fh->dev = dev;
- fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->channel = channel;
- if (!channel->configured) {
- /* configure channel to default state */
- channel->fmt = &formats[0];
- s2255_set_mode(channel, &channel->mode);
- channel->configured = 1;
- }
- dprintk(1, "%s: dev=%s type=%s\n", __func__,
- video_device_node_name(vdev), v4l2_type_names[type]);
- dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&channel->vidq);
- dprintk(4, "%s: list_empty active=%d\n", __func__,
- list_empty(&channel->vidq.active));
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
- NULL, &dev->slock,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct s2255_buffer),
- fh, vdev->lock);
- return 0;
-}
-
-
-static unsigned int s2255_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct s2255_fh *fh = file->private_data;
- int rc;
- dprintk(100, "%s\n", __func__);
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
- rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
- return rc;
-}
-
-static void s2255_destroy(struct s2255_dev *dev)
-{
- /* board shutdown stops the read pipe if it is running */
- s2255_board_shutdown(dev);
- /* make sure firmware still not trying to load */
- del_timer(&dev->timer); /* only started in .probe and .open */
- if (dev->fw_data->fw_urb) {
- usb_kill_urb(dev->fw_data->fw_urb);
- usb_free_urb(dev->fw_data->fw_urb);
- dev->fw_data->fw_urb = NULL;
- }
- release_firmware(dev->fw_data->fw);
- kfree(dev->fw_data->pfw_data);
- kfree(dev->fw_data);
- /* reset the DSP so firmware can be reloaded next time */
- s2255_reset_dsppower(dev);
- mutex_destroy(&dev->open_lock);
- mutex_destroy(&dev->lock);
- usb_put_dev(dev->udev);
- v4l2_device_unregister(&dev->v4l2_dev);
- dprintk(1, "%s", __func__);
- kfree(dev);
-}
-
-static int s2255_release(struct file *file)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = fh->channel;
- if (!dev)
- return -ENODEV;
- /* turn off stream */
- if (res_check(fh)) {
- if (channel->b_acquire)
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- }
- videobuf_mmap_free(&fh->vb_vidq);
- dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
- kfree(fh);
- return 0;
-}
-
-static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
-{
- struct s2255_fh *fh = file->private_data;
- int ret;
-
- if (!fh)
- return -ENODEV;
- dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
- ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
- return ret;
-}
-
-static const struct v4l2_file_operations s2255_fops_v4l = {
- .owner = THIS_MODULE,
- .open = s2255_open,
- .release = s2255_release,
- .poll = s2255_poll,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = s2255_mmap_v4l,
-};
-
-static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
- .vidioc_querymenu = vidioc_querymenu,
- .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_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
- .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
- .vidioc_s_parm = vidioc_s_parm,
- .vidioc_g_parm = vidioc_g_parm,
- .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-};
-
-static void s2255_video_device_release(struct video_device *vdev)
-{
- struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- dprintk(4, "%s, chnls: %d \n", __func__,
- atomic_read(&dev->num_channels));
- if (atomic_dec_and_test(&dev->num_channels))
- s2255_destroy(dev);
- return;
-}
-
-static struct video_device template = {
- .name = "s2255v",
- .fops = &s2255_fops_v4l,
- .ioctl_ops = &s2255_ioctl_ops,
- .release = s2255_video_device_release,
- .tvnorms = S2255_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-static int s2255_probe_v4l(struct s2255_dev *dev)
-{
- int ret;
- int i;
- int cur_nr = video_nr;
- struct s2255_channel *channel;
- ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
- if (ret)
- return ret;
- /* initialize all video 4 linux */
- /* register 4 video devices */
- for (i = 0; i < MAX_CHANNELS; i++) {
- channel = &dev->channel[i];
- INIT_LIST_HEAD(&channel->vidq.active);
- channel->vidq.dev = dev;
- /* register 4 video devices */
- channel->vdev = template;
- channel->vdev.lock = &dev->lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &channel->vdev.flags);
- channel->vdev.v4l2_dev = &dev->v4l2_dev;
- video_set_drvdata(&channel->vdev, channel);
- if (video_nr == -1)
- ret = video_register_device(&channel->vdev,
- VFL_TYPE_GRABBER,
- video_nr);
- else
- ret = video_register_device(&channel->vdev,
- VFL_TYPE_GRABBER,
- cur_nr + i);
-
- if (ret) {
- dev_err(&dev->udev->dev,
- "failed to register video device!\n");
- break;
- }
- atomic_inc(&dev->num_channels);
- v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(&channel->vdev));
-
- }
- printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
- S2255_VERSION);
- /* if no channels registered, return error and probe will fail*/
- if (atomic_read(&dev->num_channels) == 0) {
- v4l2_device_unregister(&dev->v4l2_dev);
- return ret;
- }
- if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
- printk(KERN_WARNING "s2255: Not all channels available.\n");
- return 0;
-}
-
-/* this function moves the usb stream read pipe data
- * into the system buffers.
- * returns 0 on success, EAGAIN if more data to process( call this
- * function again).
- *
- * Received frame structure:
- * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME)
- * bytes 4-7: channel: 0-3
- * bytes 8-11: payload size: size of the frame
- * bytes 12-payloadsize+12: frame data
- */
-static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
-{
- char *pdest;
- u32 offset = 0;
- int bframe = 0;
- char *psrc;
- unsigned long copy_size;
- unsigned long size;
- s32 idx = -1;
- struct s2255_framei *frm;
- unsigned char *pdata;
- struct s2255_channel *channel;
- dprintk(100, "buffer to user\n");
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
- if (frm->ulState == S2255_READ_IDLE) {
- int jj;
- unsigned int cc;
- __le32 *pdword; /*data from dsp is little endian */
- int payload;
- /* search for marker codes */
- pdata = (unsigned char *)pipe_info->transfer_buffer;
- pdword = (__le32 *)pdata;
- for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
- switch (*pdword) {
- case S2255_MARKER_FRAME:
- dprintk(4, "found frame marker at offset:"
- " %d [%x %x]\n", jj, pdata[0],
- pdata[1]);
- offset = jj + PREFIX_SIZE;
- bframe = 1;
- cc = le32_to_cpu(pdword[1]);
- if (cc >= MAX_CHANNELS) {
- printk(KERN_ERR
- "bad channel\n");
- return -EINVAL;
- }
- /* reverse it */
- dev->cc = G_chnmap[cc];
- channel = &dev->channel[dev->cc];
- 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 = le32_to_cpu(pdword[4]);
- break;
- case S2255_MARKER_RESPONSE:
-
- pdata += DEF_USB_BLOCK;
- jj += DEF_USB_BLOCK;
- if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
- break;
- cc = G_chnmap[le32_to_cpu(pdword[1])];
- if (cc >= MAX_CHANNELS)
- break;
- channel = &dev->channel[cc];
- switch (pdword[2]) {
- case S2255_RESPONSE_SETMODE:
- /* check if channel valid */
- /* set mode ready */
- channel->setmode_ready = 1;
- wake_up(&channel->wait_setmode);
- dprintk(5, "setmode ready %d\n", cc);
- break;
- case S2255_RESPONSE_FW:
- dev->chn_ready |= (1 << cc);
- if ((dev->chn_ready & 0x0f) != 0x0f)
- break;
- /* all channels ready */
- printk(KERN_INFO "s2255: fw loaded\n");
- atomic_set(&dev->fw_data->fw_state,
- S2255_FW_SUCCESS);
- wake_up(&dev->fw_data->wait_fw);
- break;
- case S2255_RESPONSE_STATUS:
- channel->vidstatus = le32_to_cpu(pdword[3]);
- channel->vidstatus_ready = 1;
- wake_up(&channel->wait_vidstatus);
- dprintk(5, "got vidstatus %x chan %d\n",
- le32_to_cpu(pdword[3]), cc);
- break;
- default:
- printk(KERN_INFO "s2255 unknown resp\n");
- }
- default:
- pdata++;
- break;
- }
- if (bframe)
- break;
- } /* for */
- if (!bframe)
- return -EINVAL;
- }
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
- /* search done. now find out if should be acquiring on this channel */
- if (!channel->b_acquire) {
- /* we found a frame, but this channel is turned off */
- frm->ulState = S2255_READ_IDLE;
- return -EINVAL;
- }
-
- if (frm->ulState == S2255_READ_IDLE) {
- frm->ulState = S2255_READ_FRAME;
- frm->cur_size = 0;
- }
-
- /* skip the marker 512 bytes (and offset if out of sync) */
- psrc = (u8 *)pipe_info->transfer_buffer + offset;
-
-
- if (frm->lpvbits == NULL) {
- dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
- frm, dev, dev->cc, idx);
- return -ENOMEM;
- }
-
- pdest = frm->lpvbits + frm->cur_size;
-
- copy_size = (pipe_info->cur_transfer_size - offset);
-
- size = channel->pkt_size - PREFIX_SIZE;
-
- /* sanity check on pdest */
- if ((copy_size + frm->cur_size) < channel->req_image_size)
- memcpy(pdest, psrc, copy_size);
-
- frm->cur_size += copy_size;
- dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
-
- if (frm->cur_size >= size) {
- dprintk(2, "****************[%d]Buffer[%d]full*************\n",
- dev->cc, idx);
- channel->last_frame = channel->cur_frame;
- channel->cur_frame++;
- /* end of system frame ring buffer, start at zero */
- if ((channel->cur_frame == SYS_FRAMES) ||
- (channel->cur_frame == channel->buffer.dwFrames))
- channel->cur_frame = 0;
- /* frame ready */
- if (channel->b_acquire)
- s2255_got_frame(channel, channel->jpg_size);
- channel->frame_count++;
- frm->ulState = S2255_READ_IDLE;
- frm->cur_size = 0;
-
- }
- /* done successfully */
- return 0;
-}
-
-static void s2255_read_video_callback(struct s2255_dev *dev,
- struct s2255_pipeinfo *pipe_info)
-{
- int res;
- dprintk(50, "callback read video \n");
-
- if (dev->cc >= MAX_CHANNELS) {
- dev->cc = 0;
- dev_err(&dev->udev->dev, "invalid channel\n");
- return;
- }
- /* otherwise copy to the system buffers */
- res = save_frame(dev, pipe_info);
- if (res != 0)
- dprintk(4, "s2255: read callback failed\n");
-
- dprintk(50, "callback read video done\n");
- return;
-}
-
-static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
- u16 Index, u16 Value, void *TransferBuffer,
- s32 TransferBufferLength, int bOut)
-{
- int r;
- if (!bOut) {
- r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
- Request,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_IN,
- Value, Index, TransferBuffer,
- TransferBufferLength, HZ * 5);
- } else {
- r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
- Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- Value, Index, TransferBuffer,
- TransferBufferLength, HZ * 5);
- }
- return r;
-}
-
-/*
- * retrieve FX2 firmware version. future use.
- * @param dev pointer to device extension
- * @return -1 for fail, else returns firmware version as an int(16 bits)
- */
-static int s2255_get_fx2fw(struct s2255_dev *dev)
-{
- int fw;
- int ret;
- unsigned char transBuffer[64];
- ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
- S2255_VR_IN);
- if (ret < 0)
- dprintk(2, "get fw error: %x\n", ret);
- fw = transBuffer[0] + (transBuffer[1] << 8);
- dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
- return fw;
-}
-
-/*
- * Create the system ring buffer to copy frames into from the
- * usb read pipe.
- */
-static int s2255_create_sys_buffers(struct s2255_channel *channel)
-{
- unsigned long i;
- unsigned long reqsize;
- dprintk(1, "create sys buffers\n");
- channel->buffer.dwFrames = SYS_FRAMES;
- /* always allocate maximum size(PAL) for system buffers */
- reqsize = SYS_FRAMES_MAXSIZE;
-
- if (reqsize > SYS_FRAMES_MAXSIZE)
- reqsize = SYS_FRAMES_MAXSIZE;
-
- for (i = 0; i < SYS_FRAMES; i++) {
- /* allocate the frames */
- channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
- dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
- &channel->buffer.frame[i], channel->idx, i,
- channel->buffer.frame[i].lpvbits);
- channel->buffer.frame[i].size = reqsize;
- if (channel->buffer.frame[i].lpvbits == NULL) {
- printk(KERN_INFO "out of memory. using less frames\n");
- channel->buffer.dwFrames = i;
- break;
- }
- }
-
- /* make sure internal states are set */
- for (i = 0; i < SYS_FRAMES; i++) {
- channel->buffer.frame[i].ulState = 0;
- channel->buffer.frame[i].cur_size = 0;
- }
-
- channel->cur_frame = 0;
- channel->last_frame = -1;
- return 0;
-}
-
-static int s2255_release_sys_buffers(struct s2255_channel *channel)
-{
- unsigned long i;
- dprintk(1, "release sys buffers\n");
- for (i = 0; i < SYS_FRAMES; i++) {
- if (channel->buffer.frame[i].lpvbits) {
- dprintk(1, "vfree %p\n",
- channel->buffer.frame[i].lpvbits);
- vfree(channel->buffer.frame[i].lpvbits);
- }
- channel->buffer.frame[i].lpvbits = NULL;
- }
- return 0;
-}
-
-static int s2255_board_init(struct s2255_dev *dev)
-{
- struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
- int fw_ver;
- int j;
- struct s2255_pipeinfo *pipe = &dev->pipe;
- dprintk(4, "board init: %p", dev);
- memset(pipe, 0, sizeof(*pipe));
- pipe->dev = dev;
- pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
- pipe->max_transfer_size = S2255_USB_XFER_SIZE;
-
- pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
- GFP_KERNEL);
- if (pipe->transfer_buffer == NULL) {
- dprintk(1, "out of memory!\n");
- return -ENOMEM;
- }
- /* query the firmware */
- fw_ver = s2255_get_fx2fw(dev);
-
- printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
- (fw_ver >> 8) & 0xff,
- fw_ver & 0xff);
-
- if (fw_ver < S2255_CUR_USB_FWVER)
- printk(KERN_INFO "s2255: newer USB firmware available\n");
-
- for (j = 0; j < MAX_CHANNELS; j++) {
- struct s2255_channel *channel = &dev->channel[j];
- channel->b_acquire = 0;
- channel->mode = mode_def;
- if (dev->pid == 0x2257 && j > 1)
- channel->mode.color |= (1 << 16);
- channel->jc.quality = S2255_DEF_JPEG_QUAL;
- channel->width = LINE_SZ_4CIFS_NTSC;
- channel->height = NUM_LINES_4CIFS_NTSC * 2;
- channel->fmt = &formats[0];
- channel->mode.restart = 1;
- channel->req_image_size = get_transfer_size(&mode_def);
- channel->frame_count = 0;
- /* create the system buffers */
- s2255_create_sys_buffers(channel);
- }
- /* start read pipe */
- s2255_start_readpipe(dev);
- dprintk(1, "%s: success\n", __func__);
- return 0;
-}
-
-static int s2255_board_shutdown(struct s2255_dev *dev)
-{
- u32 i;
- dprintk(1, "%s: dev: %p", __func__, dev);
-
- for (i = 0; i < MAX_CHANNELS; i++) {
- if (dev->channel[i].b_acquire)
- s2255_stop_acquire(&dev->channel[i]);
- }
- s2255_stop_readpipe(dev);
- for (i = 0; i < MAX_CHANNELS; i++)
- s2255_release_sys_buffers(&dev->channel[i]);
- /* release transfer buffer */
- kfree(dev->pipe.transfer_buffer);
- return 0;
-}
-
-static void read_pipe_completion(struct urb *purb)
-{
- struct s2255_pipeinfo *pipe_info;
- struct s2255_dev *dev;
- int status;
- int pipe;
- pipe_info = purb->context;
- dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
- purb->status);
- if (pipe_info == NULL) {
- dev_err(&purb->dev->dev, "no context!\n");
- return;
- }
-
- dev = pipe_info->dev;
- if (dev == NULL) {
- dev_err(&purb->dev->dev, "no context!\n");
- return;
- }
- status = purb->status;
- /* if shutting down, do not resubmit, exit immediately */
- if (status == -ESHUTDOWN) {
- dprintk(2, "%s: err shutdown\n", __func__);
- pipe_info->err_count++;
- return;
- }
-
- if (pipe_info->state == 0) {
- dprintk(2, "%s: exiting USB pipe", __func__);
- return;
- }
-
- if (status == 0)
- s2255_read_video_callback(dev, pipe_info);
- else {
- pipe_info->err_count++;
- dprintk(1, "%s: failed URB %d\n", __func__, status);
- }
-
- pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
- /* reuse urb */
- usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
- pipe,
- pipe_info->transfer_buffer,
- pipe_info->cur_transfer_size,
- read_pipe_completion, pipe_info);
-
- if (pipe_info->state != 0) {
- if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
- dev_err(&dev->udev->dev, "error submitting urb\n");
- }
- } else {
- dprintk(2, "%s :complete state 0\n", __func__);
- }
- return;
-}
-
-static int s2255_start_readpipe(struct s2255_dev *dev)
-{
- int pipe;
- int retval;
- struct s2255_pipeinfo *pipe_info = &dev->pipe;
- pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
- dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
- pipe_info->state = 1;
- pipe_info->err_count = 0;
- pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pipe_info->stream_urb) {
- dev_err(&dev->udev->dev,
- "ReadStream: Unable to alloc URB\n");
- return -ENOMEM;
- }
- /* transfer buffer allocated in board_init */
- usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
- pipe,
- pipe_info->transfer_buffer,
- pipe_info->cur_transfer_size,
- read_pipe_completion, pipe_info);
- retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
- if (retval) {
- printk(KERN_ERR "s2255: start read pipe failed\n");
- return retval;
- }
- return 0;
-}
-
-/* starts acquisition process */
-static int s2255_start_acquire(struct s2255_channel *channel)
-{
- unsigned char *buffer;
- int res;
- unsigned long chn_rev;
- int j;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
-
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
- for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = 0;
- channel->buffer.frame[j].cur_size = 0;
- }
-
- /* send the start command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_START;
- res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- if (res != 0)
- dev_err(&dev->udev->dev, "CMD_START error\n");
-
- dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
- kfree(buffer);
- return 0;
-}
-
-static int s2255_stop_acquire(struct s2255_channel *channel)
-{
- unsigned char *buffer;
- int res;
- unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
- /* send the stop command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_STOP;
- res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- if (res != 0)
- dev_err(&dev->udev->dev, "CMD_STOP error\n");
- kfree(buffer);
- channel->b_acquire = 0;
- dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
- return res;
-}
-
-static void s2255_stop_readpipe(struct s2255_dev *dev)
-{
- struct s2255_pipeinfo *pipe = &dev->pipe;
-
- pipe->state = 0;
- if (pipe->stream_urb) {
- /* cancel urb */
- usb_kill_urb(pipe->stream_urb);
- usb_free_urb(pipe->stream_urb);
- pipe->stream_urb = NULL;
- }
- dprintk(4, "%s", __func__);
- return;
-}
-
-static void s2255_fwload_start(struct s2255_dev *dev, int reset)
-{
- if (reset)
- s2255_reset_dsppower(dev);
- dev->fw_data->fw_size = dev->fw_data->fw->size;
- atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
- memcpy(dev->fw_data->pfw_data,
- dev->fw_data->fw->data, CHUNK_SIZE);
- dev->fw_data->fw_loaded = CHUNK_SIZE;
- usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev,
- usb_sndbulkpipe(dev->udev, 2),
- dev->fw_data->pfw_data,
- CHUNK_SIZE, s2255_fwchunk_complete,
- dev->fw_data);
- mod_timer(&dev->timer, jiffies + HZ);
-}
-
-/* standard usb probe function */
-static int s2255_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct s2255_dev *dev = NULL;
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
- int i;
- int retval = -ENOMEM;
- __le32 *pdata;
- int fw_size;
- dprintk(2, "%s\n", __func__);
- /* allocate memory for our device state and initialize it to zero */
- dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
- if (dev == NULL) {
- s2255_dev_err(&interface->dev, "out of memory\n");
- return -ENOMEM;
- }
- atomic_set(&dev->num_channels, 0);
- dev->pid = id->idProduct;
- dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
- if (!dev->fw_data)
- goto errorFWDATA1;
- mutex_init(&dev->lock);
- mutex_init(&dev->open_lock);
- /* grab usb_device and save it */
- dev->udev = usb_get_dev(interface_to_usbdev(interface));
- if (dev->udev == NULL) {
- dev_err(&interface->dev, "null usb device\n");
- retval = -ENODEV;
- goto errorUDEV;
- }
- dprintk(1, "dev: %p, udev %p interface %p\n", dev,
- dev->udev, interface);
- dev->interface = interface;
- /* set up the endpoint information */
- iface_desc = interface->cur_altsetting;
- dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
- /* we found the bulk in endpoint */
- dev->read_endpoint = endpoint->bEndpointAddress;
- }
- }
-
- if (!dev->read_endpoint) {
- dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
- goto errorEP;
- }
- init_timer(&dev->timer);
- dev->timer.function = s2255_timer;
- dev->timer.data = (unsigned long)dev->fw_data;
- init_waitqueue_head(&dev->fw_data->wait_fw);
- for (i = 0; i < MAX_CHANNELS; i++) {
- struct s2255_channel *channel = &dev->channel[i];
- dev->channel[i].idx = i;
- init_waitqueue_head(&channel->wait_setmode);
- init_waitqueue_head(&channel->wait_vidstatus);
- }
-
- dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->fw_data->fw_urb) {
- dev_err(&interface->dev, "out of memory!\n");
- goto errorFWURB;
- }
-
- dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
- if (!dev->fw_data->pfw_data) {
- dev_err(&interface->dev, "out of memory!\n");
- goto errorFWDATA2;
- }
- /* load the first chunk */
- if (request_firmware(&dev->fw_data->fw,
- FIRMWARE_FILE_NAME, &dev->udev->dev)) {
- printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
- goto errorREQFW;
- }
- /* check the firmware is valid */
- fw_size = dev->fw_data->fw->size;
- pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
-
- if (*pdata != S2255_FW_MARKER) {
- printk(KERN_INFO "Firmware invalid.\n");
- retval = -ENODEV;
- goto errorFWMARKER;
- } else {
- /* make sure firmware is the latest */
- __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 = 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 &&
- dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- printk(KERN_WARNING "s2255: 2257 requires firmware %d"
- " or above.\n", S2255_MIN_DSP_COLORFILTER);
- }
- usb_reset_device(dev->udev);
- /* load 2255 board specific */
- retval = s2255_board_init(dev);
- if (retval)
- goto errorBOARDINIT;
- spin_lock_init(&dev->slock);
- s2255_fwload_start(dev, 0);
- /* loads v4l specific */
- retval = s2255_probe_v4l(dev);
- if (retval)
- goto errorBOARDINIT;
- dev_info(&interface->dev, "Sensoray 2255 detected\n");
- return 0;
-errorBOARDINIT:
- s2255_board_shutdown(dev);
-errorFWMARKER:
- release_firmware(dev->fw_data->fw);
-errorREQFW:
- kfree(dev->fw_data->pfw_data);
-errorFWDATA2:
- usb_free_urb(dev->fw_data->fw_urb);
-errorFWURB:
- del_timer(&dev->timer);
-errorEP:
- usb_put_dev(dev->udev);
-errorUDEV:
- kfree(dev->fw_data);
- mutex_destroy(&dev->open_lock);
- mutex_destroy(&dev->lock);
-errorFWDATA1:
- kfree(dev);
- printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
- return retval;
-}
-
-/* disconnect routine. when board is removed physically or with rmmod */
-static void s2255_disconnect(struct usb_interface *interface)
-{
- struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
- int i;
- int channels = atomic_read(&dev->num_channels);
- mutex_lock(&dev->lock);
- v4l2_device_disconnect(&dev->v4l2_dev);
- mutex_unlock(&dev->lock);
- /*see comments in the uvc_driver.c usb disconnect function */
- atomic_inc(&dev->num_channels);
- /* unregister each video device. */
- for (i = 0; i < channels; i++)
- video_unregister_device(&dev->channel[i].vdev);
- /* wake up any of our timers */
- atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
- wake_up(&dev->fw_data->wait_fw);
- for (i = 0; i < MAX_CHANNELS; i++) {
- dev->channel[i].setmode_ready = 1;
- wake_up(&dev->channel[i].wait_setmode);
- dev->channel[i].vidstatus_ready = 1;
- wake_up(&dev->channel[i].wait_vidstatus);
- }
- if (atomic_dec_and_test(&dev->num_channels))
- s2255_destroy(dev);
- dev_info(&interface->dev, "%s\n", __func__);
-}
-
-static struct usb_driver s2255_driver = {
- .name = S2255_DRIVER_NAME,
- .probe = s2255_probe,
- .disconnect = s2255_disconnect,
- .id_table = s2255_table,
-};
-
-module_usb_driver(s2255_driver);
-
-MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
-MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(S2255_VERSION);
-MODULE_FIRMWARE(FIRMWARE_FILE_NAME);
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c
deleted file mode 100644
index 6625e46a4638..000000000000
--- a/drivers/media/video/s5k6aa.c
+++ /dev/null
@@ -1,1670 +0,0 @@
-/*
- * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
- * with embedded SoC ISP.
- *
- * Copyright (C) 2011, Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * Based on a driver authored by Dongsoo Nathaniel Kim.
- * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@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/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/media.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-
-#include <media/media-entity.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-mediabus.h>
-#include <media/s5k6aa.h>
-
-static int debug;
-module_param(debug, int, 0644);
-
-#define DRIVER_NAME "S5K6AA"
-
-/* The token to indicate array termination */
-#define S5K6AA_TERM 0xffff
-#define S5K6AA_OUT_WIDTH_DEF 640
-#define S5K6AA_OUT_HEIGHT_DEF 480
-#define S5K6AA_WIN_WIDTH_MAX 1280
-#define S5K6AA_WIN_HEIGHT_MAX 1024
-#define S5K6AA_WIN_WIDTH_MIN 8
-#define S5K6AA_WIN_HEIGHT_MIN 8
-
-/*
- * H/W register Interface (0xD0000000 - 0xD0000FFF)
- */
-#define AHB_MSB_ADDR_PTR 0xfcfc
-#define GEN_REG_OFFSH 0xd000
-#define REG_CMDWR_ADDRH 0x0028
-#define REG_CMDWR_ADDRL 0x002a
-#define REG_CMDRD_ADDRH 0x002c
-#define REG_CMDRD_ADDRL 0x002e
-#define REG_CMDBUF0_ADDR 0x0f12
-#define REG_CMDBUF1_ADDR 0x0f10
-
-/*
- * Host S/W Register interface (0x70000000 - 0x70002000)
- * The value of the two most significant address bytes is 0x7000,
- * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
- */
-#define HOST_SWIF_OFFSH 0x7000
-
-/* Initialization parameters */
-/* Master clock frequency in KHz */
-#define REG_I_INCLK_FREQ_L 0x01b8
-#define REG_I_INCLK_FREQ_H 0x01ba
-#define MIN_MCLK_FREQ_KHZ 6000U
-#define MAX_MCLK_FREQ_KHZ 27000U
-#define REG_I_USE_NPVI_CLOCKS 0x01c6
-#define REG_I_USE_NMIPI_CLOCKS 0x01c8
-
-/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
-#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc)
-#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce)
-#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0)
-#define SYS_PLL_OUT_FREQ (48000000 / 4000)
-#define PCLK_FREQ_MIN (24000000 / 4000)
-#define PCLK_FREQ_MAX (48000000 / 4000)
-#define REG_I_INIT_PARAMS_UPDATED 0x01e0
-#define REG_I_ERROR_INFO 0x01e2
-
-/* General purpose parameters */
-#define REG_USER_BRIGHTNESS 0x01e4
-#define REG_USER_CONTRAST 0x01e6
-#define REG_USER_SATURATION 0x01e8
-#define REG_USER_SHARPBLUR 0x01ea
-
-#define REG_G_SPEC_EFFECTS 0x01ee
-#define REG_G_ENABLE_PREV 0x01f0
-#define REG_G_ENABLE_PREV_CHG 0x01f2
-#define REG_G_NEW_CFG_SYNC 0x01f8
-#define REG_G_PREVZOOM_IN_WIDTH 0x020a
-#define REG_G_PREVZOOM_IN_HEIGHT 0x020c
-#define REG_G_PREVZOOM_IN_XOFFS 0x020e
-#define REG_G_PREVZOOM_IN_YOFFS 0x0210
-#define REG_G_INPUTS_CHANGE_REQ 0x021a
-#define REG_G_ACTIVE_PREV_CFG 0x021c
-#define REG_G_PREV_CFG_CHG 0x021e
-#define REG_G_PREV_OPEN_AFTER_CH 0x0220
-#define REG_G_PREV_CFG_ERROR 0x0222
-
-/* Preview control section. n = 0...4. */
-#define PREG(n, x) ((n) * 0x26 + x)
-#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242)
-#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244)
-#define REG_P_FMT(n) PREG(n, 0x0246)
-#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248)
-#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a)
-#define REG_P_PVI_MASK(n) PREG(n, 0x024c)
-#define REG_P_CLK_INDEX(n) PREG(n, 0x024e)
-#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250)
-#define FR_RATE_DYNAMIC 0
-#define FR_RATE_FIXED 1
-#define FR_RATE_FIXED_ACCURATE 2
-#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252)
-#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */
-#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */
-/* Frame period in 0.1 ms units */
-#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254)
-#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256)
-/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
-#define US_TO_FR_TIME(__t) ((__t) / 100)
-#define S5K6AA_MIN_FR_TIME 33300 /* us */
-#define S5K6AA_MAX_FR_TIME 650000 /* us */
-#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */
-/* The below 5 registers are for "device correction" values */
-#define REG_P_COLORTEMP(n) PREG(n, 0x025e)
-#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262)
-
-/* Extended image property controls */
-/* Exposure time in 10 us units */
-#define REG_SF_USR_EXPOSURE_L 0x03c6
-#define REG_SF_USR_EXPOSURE_H 0x03c8
-#define REG_SF_USR_EXPOSURE_CHG 0x03ca
-#define REG_SF_USR_TOT_GAIN 0x03cc
-#define REG_SF_USR_TOT_GAIN_CHG 0x03ce
-#define REG_SF_RGAIN 0x03d0
-#define REG_SF_RGAIN_CHG 0x03d2
-#define REG_SF_GGAIN 0x03d4
-#define REG_SF_GGAIN_CHG 0x03d6
-#define REG_SF_BGAIN 0x03d8
-#define REG_SF_BGAIN_CHG 0x03da
-#define REG_SF_FLICKER_QUANT 0x03dc
-#define REG_SF_FLICKER_QUANT_CHG 0x03de
-
-/* Output interface (parallel/MIPI) setup */
-#define REG_OIF_EN_MIPI_LANES 0x03fa
-#define REG_OIF_EN_PACKETS 0x03fc
-#define REG_OIF_CFG_CHG 0x03fe
-
-/* Auto-algorithms enable mask */
-#define REG_DBG_AUTOALG_EN 0x0400
-#define AALG_ALL_EN_MASK (1 << 0)
-#define AALG_AE_EN_MASK (1 << 1)
-#define AALG_DIVLEI_EN_MASK (1 << 2)
-#define AALG_WB_EN_MASK (1 << 3)
-#define AALG_FLICKER_EN_MASK (1 << 5)
-#define AALG_FIT_EN_MASK (1 << 6)
-#define AALG_WRHW_EN_MASK (1 << 7)
-
-/* Firmware revision information */
-#define REG_FW_APIVER 0x012e
-#define S5K6AAFX_FW_APIVER 0x0001
-#define REG_FW_REVISION 0x0130
-
-/* For now we use only one user configuration register set */
-#define S5K6AA_MAX_PRESETS 1
-
-static const char * const s5k6aa_supply_names[] = {
- "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */
- "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */
- "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V)
- or 2.8V (2.6V to 3.0) */
- "vddio", /* I/O supply 1.8V (1.65V to 1.95V)
- or 2.8V (2.5V to 3.1V) */
-};
-#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
-
-enum s5k6aa_gpio_id {
- STBY,
- RST,
- GPIO_NUM,
-};
-
-struct s5k6aa_regval {
- u16 addr;
- u16 val;
-};
-
-struct s5k6aa_pixfmt {
- enum v4l2_mbus_pixelcode code;
- u32 colorspace;
- /* REG_P_FMT(x) register value */
- u16 reg_p_fmt;
-};
-
-struct s5k6aa_preset {
- /* output pixel format and resolution */
- struct v4l2_mbus_framefmt mbus_fmt;
- u8 clk_id;
- u8 index;
-};
-
-struct s5k6aa_ctrls {
- struct v4l2_ctrl_handler handler;
- /* Auto / manual white balance cluster */
- struct v4l2_ctrl *awb;
- struct v4l2_ctrl *gain_red;
- struct v4l2_ctrl *gain_blue;
- struct v4l2_ctrl *gain_green;
- /* Mirror cluster */
- struct v4l2_ctrl *hflip;
- struct v4l2_ctrl *vflip;
- /* Auto exposure / manual exposure and gain cluster */
- struct v4l2_ctrl *auto_exp;
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *gain;
-};
-
-struct s5k6aa_interval {
- u16 reg_fr_time;
- struct v4l2_fract interval;
- /* Maximum rectangle for the interval */
- struct v4l2_frmsize_discrete size;
-};
-
-struct s5k6aa {
- struct v4l2_subdev sd;
- struct media_pad pad;
-
- enum v4l2_mbus_type bus_type;
- u8 mipi_lanes;
-
- int (*s_power)(int enable);
- struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
- struct s5k6aa_gpio gpio[GPIO_NUM];
-
- /* external master clock frequency */
- unsigned long mclk_frequency;
- /* ISP internal master clock frequency */
- u16 clk_fop;
- /* output pixel clock frequency range */
- u16 pclk_fmin;
- u16 pclk_fmax;
-
- unsigned int inv_hflip:1;
- unsigned int inv_vflip:1;
-
- /* protects the struct members below */
- struct mutex lock;
-
- /* sensor matrix scan window */
- struct v4l2_rect ccd_rect;
-
- struct s5k6aa_ctrls ctrls;
- struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
- struct s5k6aa_preset *preset;
- const struct s5k6aa_interval *fiv;
-
- unsigned int streaming:1;
- unsigned int apply_cfg:1;
- unsigned int apply_crop:1;
- unsigned int power;
-};
-
-static struct s5k6aa_regval s5k6aa_analog_config[] = {
- /* Analog settings */
- { 0x112a, 0x0000 }, { 0x1132, 0x0000 },
- { 0x113e, 0x0000 }, { 0x115c, 0x0000 },
- { 0x1164, 0x0000 }, { 0x1174, 0x0000 },
- { 0x1178, 0x0000 }, { 0x077a, 0x0000 },
- { 0x077c, 0x0000 }, { 0x077e, 0x0000 },
- { 0x0780, 0x0000 }, { 0x0782, 0x0000 },
- { 0x0784, 0x0000 }, { 0x0786, 0x0000 },
- { 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
- { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
- { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
- { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
- { 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
- { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
-};
-
-/* TODO: Add RGB888 and Bayer format */
-static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
- /* range 16-240 */
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
- { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
-};
-
-static const struct s5k6aa_interval s5k6aa_intervals[] = {
- { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
- { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */
- { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */
- { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */
- { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */
-};
-
-#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
-
-static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
-}
-
-static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct s5k6aa, sd);
-}
-
-/* Set initial values for all preview presets */
-static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
-{
- struct s5k6aa_preset *preset = &s5k6aa->presets[0];
- int i;
-
- for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
- preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF;
- preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF;
- preset->mbus_fmt.code = s5k6aa_formats[0].code;
- preset->index = i;
- preset->clk_id = 0;
- preset++;
- }
-
- s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
- s5k6aa->preset = &s5k6aa->presets[0];
-}
-
-static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
-{
- u8 wbuf[2] = {addr >> 8, addr & 0xFF};
- struct i2c_msg msg[2];
- u8 rbuf[2];
- int ret;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 2;
- msg[0].buf = wbuf;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 2;
- msg[1].buf = rbuf;
-
- ret = i2c_transfer(client->adapter, msg, 2);
- *val = be16_to_cpu(*((u16 *)rbuf));
-
- v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
-
- return ret == 2 ? 0 : ret;
-}
-
-static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
-{
- u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
-
- int ret = i2c_master_send(client, buf, 4);
- v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
-
- return ret == 4 ? 0 : ret;
-}
-
-/* The command register write, assumes Command_Wr_addH = 0x7000. */
-static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
-{
- int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
- if (ret)
- return ret;
- return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
-}
-
-/* The command register read, assumes Command_Rd_addH = 0x7000. */
-static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
-{
- int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
- if (ret)
- return ret;
- return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
-}
-
-static int s5k6aa_write_array(struct v4l2_subdev *sd,
- const struct s5k6aa_regval *msg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u16 addr_incr = 0;
- int ret = 0;
-
- while (msg->addr != S5K6AA_TERM) {
- if (addr_incr != 2)
- ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
- msg->addr);
- if (ret)
- break;
- ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
- if (ret)
- break;
- /* Assume that msg->addr is always less than 0xfffc */
- addr_incr = (msg + 1)->addr - msg->addr;
- msg++;
- }
-
- return ret;
-}
-
-/* Configure the AHB high address bytes for GTG registers access */
-static int s5k6aa_set_ahb_address(struct i2c_client *client)
-{
- int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
- if (ret)
- return ret;
- ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
- if (ret)
- return ret;
- return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
-}
-
-/**
- * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
- *
- * Configure the internal ISP PLL for the required output frequency.
- * Locking: called with s5k6aa.lock mutex held.
- */
-static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
- u16 status;
- int ret;
-
- if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
- "Invalid clock frequency: %ld\n", fmclk))
- return -EINVAL;
-
- s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
- s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
- s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
-
- /* External input clock frequency in kHz */
- ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
- /* Internal PLL frequency */
- if (!ret)
- ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
- s5k6aa->pclk_fmin);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
- s5k6aa->pclk_fmax);
- if (!ret)
- ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
- if (!ret)
- ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
-
- return ret ? ret : (status ? -EINVAL : 0);
-}
-
-/* Set horizontal and vertical image flipping */
-static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int index = s5k6aa->preset->index;
-
- unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
- unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
-
- return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
-}
-
-/* Configure auto/manual white balance and R/G/B gains */
-static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
- u16 reg;
-
- int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &reg);
-
- if (!ret && !awb) {
- ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
- if (ret)
- return ret;
-
- ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
- if (ret)
- return ret;
-
- ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
- if (!ret)
- ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
- }
- if (!ret) {
- reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
- ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
- }
-
- return ret;
-}
-
-/* Program FW with exposure time, 'exposure' in us units */
-static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
-{
- unsigned int time = exposure / 10;
-
- int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
- if (!ret)
- ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
-}
-
-static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
-{
- int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
-}
-
-/* Set auto/manual exposure and total gain */
-static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- unsigned int exp_time = s5k6aa->ctrls.exposure->val;
- u16 auto_alg;
-
- int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
- if (ret)
- return ret;
-
- v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
- exp_time, value, auto_alg);
-
- if (value == V4L2_EXPOSURE_AUTO) {
- auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
- } else {
- ret = s5k6aa_set_user_exposure(c, exp_time);
- if (ret)
- return ret;
- ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
- if (ret)
- return ret;
- auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
- }
-
- return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
-}
-
-static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 auto_alg;
- int ret;
-
- ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
- if (ret)
- return ret;
-
- if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
- auto_alg |= AALG_FLICKER_EN_MASK;
- } else {
- auto_alg &= ~AALG_FLICKER_EN_MASK;
- /* The V4L2_CID_LINE_FREQUENCY control values match
- * the register values */
- ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
- if (ret)
- return ret;
- ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
- if (ret)
- return ret;
- }
-
- return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
-}
-
-static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- static const struct v4l2_control colorfx[] = {
- { V4L2_COLORFX_NONE, 0 },
- { V4L2_COLORFX_BW, 1 },
- { V4L2_COLORFX_NEGATIVE, 2 },
- { V4L2_COLORFX_SEPIA, 3 },
- { V4L2_COLORFX_SKY_BLUE, 4 },
- { V4L2_COLORFX_SKETCH, 5 },
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
- if (colorfx[i].id == val)
- return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
- colorfx[i].value);
- }
- return -EINVAL;
-}
-
-static int s5k6aa_preview_config_status(struct i2c_client *client)
-{
- u16 error = 0;
- int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
-
- v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
- return ret ? ret : (error ? -EINVAL : 0);
-}
-
-static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
- struct v4l2_mbus_framefmt *mf)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
- if (mf->colorspace == s5k6aa_formats[i].colorspace &&
- mf->code == s5k6aa_formats[i].code)
- return i;
- return 0;
-}
-
-static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
- struct s5k6aa_preset *preset)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
- int ret;
-
- ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
- preset->mbus_fmt.width);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
- preset->mbus_fmt.height);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FMT(preset->index),
- s5k6aa_formats[fmt_index].reg_p_fmt);
- return ret;
-}
-
-static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
- struct v4l2_rect *r = &s5k6aa->ccd_rect;
- int ret;
-
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
- if (!ret)
- ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
- if (!ret)
- s5k6aa->apply_crop = 0;
-
- return ret;
-}
-
-/**
- * s5k6aa_configure_video_bus - configure the video output interface
- * @bus_type: video bus type: parallel or MIPI-CSI
- * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
- *
- * Note: Only parallel bus operation has been tested.
- */
-static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
- enum v4l2_mbus_type bus_type, int nlanes)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 cfg = 0;
- int ret;
-
- /*
- * TODO: The sensor is supposed to support BT.601 and BT.656
- * but there is nothing indicating how to switch between both
- * in the datasheet. For now default BT.601 interface is assumed.
- */
- if (bus_type == V4L2_MBUS_CSI2)
- cfg = nlanes;
- else if (bus_type != V4L2_MBUS_PARALLEL)
- return -EINVAL;
-
- ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
- if (ret)
- return ret;
- return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
-}
-
-/* This function should be called when switching to new user configuration set*/
-static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
- int cid)
-{
- unsigned long end = jiffies + msecs_to_jiffies(timeout);
- u16 reg = 1;
- int ret;
-
- ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
- if (timeout == 0)
- return ret;
-
- while (ret >= 0 && time_is_after_jiffies(end)) {
- ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, &reg);
- if (!reg)
- return 0;
- usleep_range(1000, 5000);
- }
- return ret ? ret : -ETIMEDOUT;
-}
-
-/**
- * s5k6aa_set_prev_config - write user preview register set
- *
- * Configure output resolution and color fromat, pixel clock
- * frequency range, device frame rate type and frame period range.
- */
-static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
- struct s5k6aa_preset *preset)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int idx = preset->index;
- u16 frame_rate_q;
- int ret;
-
- if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
- frame_rate_q = FR_RATE_Q_BEST_FRRATE;
- else
- frame_rate_q = FR_RATE_Q_BEST_QUALITY;
-
- ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
- s5k6aa->pclk_fmax);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
- s5k6aa->pclk_fmin);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
- preset->clk_id);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
- FR_RATE_DYNAMIC);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
- frame_rate_q);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
- s5k6aa->fiv->reg_fr_time + 33);
- if (!ret)
- ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
- s5k6aa->fiv->reg_fr_time - 33);
- if (!ret)
- ret = s5k6aa_new_config_sync(client, 250, idx);
- if (!ret)
- ret = s5k6aa_preview_config_status(client);
- if (!ret)
- s5k6aa->apply_cfg = 0;
-
- v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
- s5k6aa->fiv->reg_fr_time, ret);
- return ret;
-}
-
-/**
- * s5k6aa_initialize_isp - basic ISP MCU initialization
- *
- * Configure AHB addresses for registers read/write; configure PLLs for
- * required output pixel clock. The ISP power supply needs to be already
- * enabled, with an optional H/W reset.
- * Locking: called with s5k6aa.lock mutex held.
- */
-static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- s5k6aa->apply_crop = 1;
- s5k6aa->apply_cfg = 1;
- msleep(100);
-
- ret = s5k6aa_set_ahb_address(client);
- if (ret)
- return ret;
- ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
- s5k6aa->mipi_lanes);
- if (ret)
- return ret;
- ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
- if (ret)
- return ret;
- msleep(20);
-
- return s5k6aa_configure_pixel_clocks(s5k6aa);
-}
-
-static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
-{
- if (!gpio_is_valid(priv->gpio[id].gpio))
- return 0;
- gpio_set_value(priv->gpio[id].gpio, !!val);
- return 1;
-}
-
-static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
-{
- return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
-}
-
-static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
-{
- return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
-}
-
-static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
-{
- int ret;
-
- ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
- if (ret)
- return ret;
- if (s5k6aa_gpio_deassert(s5k6aa, STBY))
- usleep_range(150, 200);
-
- if (s5k6aa->s_power)
- ret = s5k6aa->s_power(1);
- usleep_range(4000, 4000);
-
- if (s5k6aa_gpio_deassert(s5k6aa, RST))
- msleep(20);
-
- return ret;
-}
-
-static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
-{
- int ret;
-
- if (s5k6aa_gpio_assert(s5k6aa, RST))
- usleep_range(100, 150);
-
- if (s5k6aa->s_power) {
- ret = s5k6aa->s_power(0);
- if (ret)
- return ret;
- }
- if (s5k6aa_gpio_assert(s5k6aa, STBY))
- usleep_range(50, 100);
- s5k6aa->streaming = 0;
-
- return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
-}
-
-/*
- * V4L2 subdev core and video operations
- */
-static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
-
- if (!on == s5k6aa->power) {
- if (on) {
- ret = __s5k6aa_power_on(s5k6aa);
- if (!ret)
- ret = s5k6aa_initialize_isp(sd);
- } else {
- ret = __s5k6aa_power_off(s5k6aa);
- }
-
- if (!ret)
- s5k6aa->power += on ? 1 : -1;
- }
-
- mutex_unlock(&s5k6aa->lock);
-
- if (!on || ret || s5k6aa->power != 1)
- return ret;
-
- return v4l2_ctrl_handler_setup(sd->ctrl_handler);
-}
-
-static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- int ret = 0;
-
- ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
- if (!ret)
- ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
- if (!ret)
- s5k6aa->streaming = enable;
-
- return ret;
-}
-
-static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
-
- if (s5k6aa->streaming == !on) {
- if (!ret && s5k6aa->apply_cfg)
- ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
- if (s5k6aa->apply_crop)
- ret = s5k6aa_set_input_params(s5k6aa);
- if (!ret)
- ret = __s5k6aa_stream(s5k6aa, !!on);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
-
- mutex_lock(&s5k6aa->lock);
- fi->interval = s5k6aa->fiv->interval;
- mutex_unlock(&s5k6aa->lock);
-
- return 0;
-}
-
-static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
- const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
- unsigned int err, min_err = UINT_MAX;
- unsigned int i, fr_time;
-
- if (fi->interval.denominator == 0)
- return -EINVAL;
-
- fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
- const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
-
- if (mbus_fmt->width > iv->size.width ||
- mbus_fmt->height > iv->size.height)
- continue;
-
- err = abs(iv->reg_fr_time - fr_time);
- if (err < min_err) {
- fiv = iv;
- min_err = err;
- }
- }
- s5k6aa->fiv = fiv;
-
- v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
- fiv->reg_fr_time * 100);
- return 0;
-}
-
-static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
- fi->interval.numerator, fi->interval.denominator);
-
- mutex_lock(&s5k6aa->lock);
- ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
- s5k6aa->apply_cfg = 1;
-
- mutex_unlock(&s5k6aa->lock);
- return ret;
-}
-
-/*
- * V4L2 subdev pad level and video operations
- */
-static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_interval_enum *fie)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- const struct s5k6aa_interval *fi;
- int ret = 0;
-
- if (fie->index > ARRAY_SIZE(s5k6aa_intervals))
- return -EINVAL;
-
- v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &fie->height, S5K6AA_WIN_HEIGHT_MIN,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- mutex_lock(&s5k6aa->lock);
- fi = &s5k6aa_intervals[fie->index];
- if (fie->width > fi->size.width || fie->height > fi->size.height)
- ret = -EINVAL;
- else
- fie->interval = fi->interval;
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index >= ARRAY_SIZE(s5k6aa_formats))
- return -EINVAL;
-
- code->code = s5k6aa_formats[code->index].code;
- return 0;
-}
-
-static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- int i = ARRAY_SIZE(s5k6aa_formats);
-
- if (fse->index > 0)
- return -EINVAL;
-
- while (--i)
- if (fse->code == s5k6aa_formats[i].code)
- break;
-
- fse->code = s5k6aa_formats[i].code;
- fse->min_width = S5K6AA_WIN_WIDTH_MIN;
- fse->max_width = S5K6AA_WIN_WIDTH_MAX;
- fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
- fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
-
- return 0;
-}
-
-static struct v4l2_rect *
-__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &s5k6aa->ccd_rect;
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(fh, 0);
-
- return NULL;
-}
-
-static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
- struct v4l2_mbus_framefmt *mf)
-{
- unsigned int index;
-
- v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &mf->height, S5K6AA_WIN_HEIGHT_MIN,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
- mf->colorspace != V4L2_COLORSPACE_REC709)
- mf->colorspace = V4L2_COLORSPACE_JPEG;
-
- index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
-
- mf->colorspace = s5k6aa_formats[index].colorspace;
- mf->code = s5k6aa_formats[index].code;
- mf->field = V4L2_FIELD_NONE;
-}
-
-static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_mbus_framefmt *mf;
-
- memset(fmt->reserved, 0, sizeof(fmt->reserved));
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, 0);
- fmt->format = *mf;
- return 0;
- }
-
- mutex_lock(&s5k6aa->lock);
- fmt->format = s5k6aa->preset->mbus_fmt;
- mutex_unlock(&s5k6aa->lock);
-
- return 0;
-}
-
-static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct s5k6aa_preset *preset = s5k6aa->preset;
- struct v4l2_mbus_framefmt *mf;
- struct v4l2_rect *crop;
- int ret = 0;
-
- mutex_lock(&s5k6aa->lock);
- s5k6aa_try_format(s5k6aa, &fmt->format);
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(fh, fmt->pad);
- crop = v4l2_subdev_get_try_crop(fh, 0);
- } else {
- if (s5k6aa->streaming) {
- ret = -EBUSY;
- } else {
- mf = &preset->mbus_fmt;
- crop = &s5k6aa->ccd_rect;
- s5k6aa->apply_cfg = 1;
- }
- }
-
- if (ret == 0) {
- struct v4l2_subdev_frame_interval fiv = {
- .interval = {0, 1}
- };
-
- *mf = fmt->format;
- /*
- * Make sure the crop window is valid, i.e. its size is
- * greater than the output window, as the ISP supports
- * only down-scaling.
- */
- crop->width = clamp_t(unsigned int, crop->width, mf->width,
- S5K6AA_WIN_WIDTH_MAX);
- crop->height = clamp_t(unsigned int, crop->height, mf->height,
- S5K6AA_WIN_HEIGHT_MAX);
- crop->left = clamp_t(unsigned int, crop->left, 0,
- S5K6AA_WIN_WIDTH_MAX - crop->width);
- crop->top = clamp_t(unsigned int, crop->top, 0,
- S5K6AA_WIN_HEIGHT_MAX - crop->height);
-
- /* Reset to minimum possible frame interval */
- ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_rect *rect;
-
- memset(crop->reserved, 0, sizeof(crop->reserved));
- mutex_lock(&s5k6aa->lock);
-
- rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
- if (rect)
- crop->rect = *rect;
-
- mutex_unlock(&s5k6aa->lock);
-
- v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
- rect->left, rect->top, rect->width, rect->height);
-
- return 0;
-}
-
-static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- struct v4l2_mbus_framefmt *mf;
- unsigned int max_x, max_y;
- struct v4l2_rect *crop_r;
-
- mutex_lock(&s5k6aa->lock);
- crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
-
- if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- mf = &s5k6aa->preset->mbus_fmt;
- s5k6aa->apply_crop = 1;
- } else {
- mf = v4l2_subdev_get_try_format(fh, 0);
- }
- v4l_bound_align_image(&crop->rect.width, mf->width,
- S5K6AA_WIN_WIDTH_MAX, 1,
- &crop->rect.height, mf->height,
- S5K6AA_WIN_HEIGHT_MAX, 1, 0);
-
- max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1;
- max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1;
-
- crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x);
- crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y);
-
- *crop_r = crop->rect;
-
- mutex_unlock(&s5k6aa->lock);
-
- v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
- crop_r->left, crop_r->top, crop_r->width, crop_r->height);
-
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
- .enum_mbus_code = s5k6aa_enum_mbus_code,
- .enum_frame_size = s5k6aa_enum_frame_size,
- .enum_frame_interval = s5k6aa_enum_frame_interval,
- .get_fmt = s5k6aa_get_fmt,
- .set_fmt = s5k6aa_set_fmt,
- .get_crop = s5k6aa_get_crop,
- .set_crop = s5k6aa_set_crop,
-};
-
-static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
- .g_frame_interval = s5k6aa_g_frame_interval,
- .s_frame_interval = s5k6aa_s_frame_interval,
- .s_stream = s5k6aa_s_stream,
-};
-
-/*
- * V4L2 subdev controls
- */
-
-static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int idx, err = 0;
-
- v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
-
- mutex_lock(&s5k6aa->lock);
- /*
- * If the device is not powered up by the host driver do
- * not apply any controls to H/W at this time. Instead
- * the controls will be restored right after power-up.
- */
- if (s5k6aa->power == 0)
- goto unlock;
- idx = s5k6aa->preset->index;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTO_WHITE_BALANCE:
- err = s5k6aa_set_awb(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_BRIGHTNESS:
- err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
- break;
-
- case V4L2_CID_COLORFX:
- err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_CONTRAST:
- err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
- break;
-
- case V4L2_CID_EXPOSURE_AUTO:
- err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_HFLIP:
- err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
- if (err)
- break;
- err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- break;
-
- case V4L2_CID_POWER_LINE_FREQUENCY:
- err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
- break;
-
- case V4L2_CID_SATURATION:
- err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
- break;
-
- case V4L2_CID_SHARPNESS:
- err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
- break;
-
- case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
- err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
- if (err)
- break;
- err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
- break;
- }
-unlock:
- mutex_unlock(&s5k6aa->lock);
- return err;
-}
-
-static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
- .s_ctrl = s5k6aa_s_ctrl,
-};
-
-static int s5k6aa_log_status(struct v4l2_subdev *sd)
-{
- v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
- return 0;
-}
-
-#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001)
-#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002)
-#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003)
-
-static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
- {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_RED_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Red",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- }, {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_GREEN_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Green",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- }, {
- .ops = &s5k6aa_ctrl_ops,
- .id = V4L2_CID_BLUE_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain, Blue",
- .min = 0,
- .max = 256,
- .def = 127,
- .step = 1,
- },
-};
-
-static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
-{
- const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
- struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
- struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-
- int ret = v4l2_ctrl_handler_init(hdl, 16);
- if (ret)
- return ret;
- /* Auto white balance cluster */
- ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
- 0, 1, 1, 1);
- ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
- ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
- ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
- v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
-
- ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_cluster(2, &ctrls->hflip);
-
- ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
- V4L2_CID_EXPOSURE_AUTO,
- V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
- /* Exposure time: x 1 us */
- ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
- 0, 6000000U, 1, 100000U);
- /* Total gain: 256 <=> 1x */
- ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
- 0, 256, 1, 256);
- v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
-
- v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
- V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
-
- v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
- V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
-
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
- 0, 256, 1, 0);
-
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
-
- if (hdl->error) {
- ret = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return ret;
- }
-
- s5k6aa->sd.ctrl_handler = hdl;
- return 0;
-}
-
-/*
- * V4L2 subdev internal operations
- */
-static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
-
- format->colorspace = s5k6aa_formats[0].colorspace;
- format->code = s5k6aa_formats[0].code;
- format->width = S5K6AA_OUT_WIDTH_DEF;
- format->height = S5K6AA_OUT_HEIGHT_DEF;
- format->field = V4L2_FIELD_NONE;
-
- crop->width = S5K6AA_WIN_WIDTH_MAX;
- crop->height = S5K6AA_WIN_HEIGHT_MAX;
- crop->left = 0;
- crop->top = 0;
-
- return 0;
-}
-
-int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
- u16 api_ver = 0, fw_rev = 0;
-
- int ret = s5k6aa_set_ahb_address(client);
-
- if (!ret)
- ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
- if (!ret)
- ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
- if (ret) {
- v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
- return ret;
- }
-
- v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
- api_ver, fw_rev);
-
- return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
-}
-
-static int s5k6aa_registered(struct v4l2_subdev *sd)
-{
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
- int ret;
-
- mutex_lock(&s5k6aa->lock);
- ret = __s5k6aa_power_on(s5k6aa);
- if (!ret) {
- msleep(100);
- ret = s5k6aa_check_fw_revision(s5k6aa);
- __s5k6aa_power_off(s5k6aa);
- }
- mutex_unlock(&s5k6aa->lock);
-
- return ret;
-}
-
-static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
- .registered = s5k6aa_registered,
- .open = s5k6aa_open,
-};
-
-static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
- .s_power = s5k6aa_set_power,
- .log_status = s5k6aa_log_status,
-};
-
-static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
- .core = &s5k6aa_core_ops,
- .pad = &s5k6aa_pad_ops,
- .video = &s5k6aa_video_ops,
-};
-
-/*
- * GPIO setup
- */
-static int s5k6aa_configure_gpio(int nr, int val, const char *name)
-{
- unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- int ret;
-
- if (!gpio_is_valid(nr))
- return 0;
- ret = gpio_request_one(nr, flags, name);
- if (!ret)
- gpio_export(nr, 0);
- return ret;
-}
-
-static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) {
- if (!gpio_is_valid(s5k6aa->gpio[i].gpio))
- continue;
- gpio_free(s5k6aa->gpio[i].gpio);
- s5k6aa->gpio[i].gpio = -EINVAL;
- }
-}
-
-static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
- const struct s5k6aa_platform_data *pdata)
-{
- const struct s5k6aa_gpio *gpio = &pdata->gpio_stby;
- int ret;
-
- s5k6aa->gpio[STBY].gpio = -EINVAL;
- s5k6aa->gpio[RST].gpio = -EINVAL;
-
- ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY");
- if (ret) {
- s5k6aa_free_gpios(s5k6aa);
- return ret;
- }
- s5k6aa->gpio[STBY] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
-
- gpio = &pdata->gpio_reset;
- ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST");
- if (ret) {
- s5k6aa_free_gpios(s5k6aa);
- return ret;
- }
- s5k6aa->gpio[RST] = *gpio;
- if (gpio_is_valid(gpio->gpio))
- gpio_set_value(gpio->gpio, 0);
-
- return 0;
-}
-
-static int s5k6aa_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
- struct v4l2_subdev *sd;
- struct s5k6aa *s5k6aa;
- int i, ret;
-
- if (pdata == NULL) {
- dev_err(&client->dev, "Platform data not specified\n");
- return -EINVAL;
- }
-
- if (pdata->mclk_frequency == 0) {
- dev_err(&client->dev, "MCLK frequency not specified\n");
- return -EINVAL;
- }
-
- s5k6aa = kzalloc(sizeof(*s5k6aa), GFP_KERNEL);
- if (!s5k6aa)
- return -ENOMEM;
-
- mutex_init(&s5k6aa->lock);
-
- s5k6aa->mclk_frequency = pdata->mclk_frequency;
- s5k6aa->bus_type = pdata->bus_type;
- s5k6aa->mipi_lanes = pdata->nlanes;
- s5k6aa->s_power = pdata->set_power;
- s5k6aa->inv_hflip = pdata->horiz_flip;
- s5k6aa->inv_vflip = pdata->vert_flip;
-
- sd = &s5k6aa->sd;
- 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;
-
- s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0);
- if (ret)
- goto out_err1;
-
- ret = s5k6aa_configure_gpios(s5k6aa, pdata);
- if (ret)
- goto out_err2;
-
- for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
- s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
-
- ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
- s5k6aa->supplies);
- if (ret) {
- dev_err(&client->dev, "Failed to get regulators\n");
- goto out_err3;
- }
-
- ret = s5k6aa_initialize_ctrls(s5k6aa);
- if (ret)
- goto out_err4;
-
- s5k6aa_presets_data_init(s5k6aa);
-
- s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
- s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX;
- s5k6aa->ccd_rect.left = 0;
- s5k6aa->ccd_rect.top = 0;
-
- return 0;
-
-out_err4:
- regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
-out_err3:
- s5k6aa_free_gpios(s5k6aa);
-out_err2:
- media_entity_cleanup(&s5k6aa->sd.entity);
-out_err1:
- kfree(s5k6aa);
- return ret;
-}
-
-static int s5k6aa_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct s5k6aa *s5k6aa = to_s5k6aa(sd);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- media_entity_cleanup(&sd->entity);
- regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
- s5k6aa_free_gpios(s5k6aa);
- kfree(s5k6aa);
-
- return 0;
-}
-
-static const struct i2c_device_id s5k6aa_id[] = {
- { DRIVER_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
-
-
-static struct i2c_driver s5k6aa_i2c_driver = {
- .driver = {
- .name = DRIVER_NAME
- },
- .probe = s5k6aa_probe,
- .remove = s5k6aa_remove,
- .id_table = s5k6aa_id,
-};
-
-module_i2c_driver(s5k6aa_i2c_driver);
-
-MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
-MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
deleted file mode 100644
index 7c2200435206..000000000000
--- a/drivers/media/video/s5p-g2d/g2d.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * 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)
-
-static 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,
-};
-
-static 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,
-};
-
-static 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);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_M2M | 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 == NULL) /* No job currently running */
- return;
-
- ret = wait_event_timeout(dev->irq_queue,
- dev->curr == NULL,
- 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 == NULL);
-
- src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-
- BUG_ON(src == NULL);
- BUG_ON(dst == NULL);
-
- 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 = NULL;
- 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 = devm_kzalloc(&pdev->dev, 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);
-
- dev->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (dev->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
-
- 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");
- return -ENXIO;
- }
-
- 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 = devm_request_irq(&pdev->dev, 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 unprep_clk_gate;
- }
-
- 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;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- 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);
-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);
-
- 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);
- clk_unprepare(dev->gate);
- clk_put(dev->gate);
- clk_unprepare(dev->clk);
- clk_put(dev->clk);
- 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-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
deleted file mode 100644
index 813b801238d1..000000000000
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ /dev/null
@@ -1,1515 +0,0 @@
-/* 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;
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
- 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);
-}
-
-static 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:
- case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE:
- 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 = devm_kzalloc(&pdev->dev, 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);
-
- jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (jpeg->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
-
- /* interrupt service routine registration */
- jpeg->irq = ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- return ret;
- }
-
- ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
- dev_name(&pdev->dev), jpeg);
- if (ret) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
- return ret;
- }
-
- /* 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);
- return ret;
- }
- 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;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_encoder->flags);
-
- 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;
- /* Locking in file operations other than ioctl should be done by the driver,
- not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_decoder->flags);
-
- 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);
-
- 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);
-
- 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,
- },
-};
-
-module_platform_driver(s5p_jpeg_driver);
-
-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
deleted file mode 100644
index 9d0cd2b76f61..000000000000
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* 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
- * @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;
-
- 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
deleted file mode 100644
index f12f0fdbde7c..000000000000
--- a/drivers/media/video/s5p-jpeg/jpeg-hw.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/* 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
deleted file mode 100644
index 91f4dd5f86dd..000000000000
--- a/drivers/media/video/s5p-jpeg/jpeg-regs.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* 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
deleted file mode 100644
index 9bb68e7b5ae8..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc.c
+++ /dev/null
@@ -1,1223 +0,0 @@
-/*
- * Samsung S5P Multi Format Codec v 5.1
- *
- * 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/clk.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/workqueue.h>
-#include <media/videobuf2-core.h>
-#include "regs-mfc.h"
-#include "s5p_mfc_ctrl.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_dec.h"
-#include "s5p_mfc_enc.h"
-#include "s5p_mfc_intr.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_shm.h"
-
-#define S5P_MFC_NAME "s5p-mfc"
-#define S5P_MFC_DEC_NAME "s5p-mfc-dec"
-#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
-
-int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
-
-/* Helper functions for interrupt processing */
-/* Remove from hw execution round robin */
-static void clear_work_bit(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- spin_lock(&dev->condlock);
- clear_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock(&dev->condlock);
-}
-
-/* Wake up context wait_queue */
-static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
- unsigned int err)
-{
- ctx->int_cond = 1;
- ctx->int_type = reason;
- ctx->int_err = err;
- wake_up(&ctx->queue);
-}
-
-/* Wake up device wait_queue */
-static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
- unsigned int err)
-{
- dev->int_cond = 1;
- dev->int_type = reason;
- dev->int_err = err;
- wake_up(&dev->queue);
-}
-
-static void s5p_mfc_watchdog(unsigned long arg)
-{
- struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
-
- if (test_bit(0, &dev->hw_lock))
- atomic_inc(&dev->watchdog_cnt);
- if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
- /* This means that hw is busy and no interrupts were
- * generated by hw for the Nth time of running this
- * watchdog timer. This usually means a serious hw
- * error. Now it is time to kill all instances and
- * reset the MFC. */
- mfc_err("Time out during waiting for HW\n");
- queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
- }
- dev->watchdog_timer.expires = jiffies +
- msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
- add_timer(&dev->watchdog_timer);
-}
-
-static void s5p_mfc_watchdog_worker(struct work_struct *work)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx *ctx;
- unsigned long flags;
- int mutex_locked;
- int i, ret;
-
- dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
-
- mfc_err("Driver timeout error handling\n");
- /* Lock the mutex that protects open and release.
- * This is necessary as they may load and unload firmware. */
- mutex_locked = mutex_trylock(&dev->mfc_mutex);
- if (!mutex_locked)
- mfc_err("Error: some instance may be closing/opening\n");
- spin_lock_irqsave(&dev->irqlock, flags);
-
- s5p_mfc_clock_off();
-
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- ctx = dev->ctx[i];
- if (!ctx)
- continue;
- ctx->state = MFCINST_ERROR;
- s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
- s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
- clear_work_bit(ctx);
- wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
- }
- clear_bit(0, &dev->hw_lock);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- /* Double check if there is at least one instance running.
- * If no instance is in memory than no firmware should be present */
- if (dev->num_inst > 0) {
- ret = s5p_mfc_reload_firmware(dev);
- if (ret) {
- mfc_err("Failed to reload FW\n");
- goto unlock;
- }
- s5p_mfc_clock_on();
- ret = s5p_mfc_init_hw(dev);
- if (ret)
- mfc_err("Failed to reinit FW\n");
- }
-unlock:
- if (mutex_locked)
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (!vdev) {
- mfc_err("failed to get video_device");
- return MFCNODE_INVALID;
- }
- if (vdev->index == 0)
- return MFCNODE_DECODER;
- else if (vdev->index == 1)
- return MFCNODE_ENCODER;
- return MFCNODE_INVALID;
-}
-
-static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
-{
- mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
- mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
- mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
-}
-
-static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *dst_buf;
-
- ctx->state = MFCINST_FINISHED;
- ctx->sequence++;
- while (!list_empty(&ctx->dst_queue)) {
- dst_buf = list_entry(ctx->dst_queue.next,
- struct s5p_mfc_buf, list);
- mfc_debug(2, "Cleaning up buffer: %d\n",
- dst_buf->b->v4l2_buf.index);
- vb2_set_plane_payload(dst_buf->b, 0, 0);
- vb2_set_plane_payload(dst_buf->b, 1, 0);
- list_del(&dst_buf->list);
- ctx->dst_queue_cnt--;
- dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
-
- if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
- s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
- dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
- else
- dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
-
- ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index);
- vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE);
- }
-}
-
-static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *dst_buf, *src_buf;
- size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
- unsigned int frame_type = s5p_mfc_get_frame_type();
-
- /* Copy timestamp / timecode from decoded src to dst and set
- appropraite flags */
- src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
- if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
- memcpy(&dst_buf->b->v4l2_buf.timecode,
- &src_buf->b->v4l2_buf.timecode,
- sizeof(struct v4l2_timecode));
- memcpy(&dst_buf->b->v4l2_buf.timestamp,
- &src_buf->b->v4l2_buf.timestamp,
- sizeof(struct timeval));
- switch (frame_type) {
- case S5P_FIMV_DECODE_FRAME_I_FRAME:
- dst_buf->b->v4l2_buf.flags |=
- V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_DECODE_FRAME_P_FRAME:
- dst_buf->b->v4l2_buf.flags |=
- V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_DECODE_FRAME_B_FRAME:
- dst_buf->b->v4l2_buf.flags |=
- V4L2_BUF_FLAG_BFRAME;
- break;
- }
- break;
- }
- }
-}
-
-static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *dst_buf;
- size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
- unsigned int frame_type = s5p_mfc_get_frame_type();
- unsigned int index;
-
- /* If frame is same as previous then skip and do not dequeue */
- if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
- if (!ctx->after_packed_pb)
- ctx->sequence++;
- ctx->after_packed_pb = 0;
- return;
- }
- ctx->sequence++;
- /* The MFC returns address of the buffer, now we have to
- * check which videobuf does it correspond to */
- list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
- /* Check if this is the buffer we're looking for */
- if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) {
- list_del(&dst_buf->list);
- ctx->dst_queue_cnt--;
- dst_buf->b->v4l2_buf.sequence = ctx->sequence;
- if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
- s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
- dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
- else
- dst_buf->b->v4l2_buf.field =
- V4L2_FIELD_INTERLACED;
- vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size);
- vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size);
- clear_bit(dst_buf->b->v4l2_buf.index,
- &ctx->dec_dst_flag);
-
- vb2_buffer_done(dst_buf->b,
- err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
- index = dst_buf->b->v4l2_buf.index;
- break;
- }
- }
-}
-
-/* Handle frame decoding interrupt */
-static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int dst_frame_status;
- struct s5p_mfc_buf *src_buf;
- unsigned long flags;
- unsigned int res_change;
-
- unsigned int index;
-
- dst_frame_status = s5p_mfc_get_dspl_status()
- & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
- res_change = s5p_mfc_get_dspl_status()
- & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
- mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
- if (ctx->state == MFCINST_RES_CHANGE_INIT)
- ctx->state = MFCINST_RES_CHANGE_FLUSH;
- if (res_change) {
- ctx->state = MFCINST_RES_CHANGE_INIT;
- s5p_mfc_clear_int_flags(dev);
- wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- s5p_mfc_try_run(dev);
- return;
- }
- if (ctx->dpb_flush_flag)
- ctx->dpb_flush_flag = 0;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- /* All frames remaining in the buffer have been extracted */
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
- if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
- s5p_mfc_handle_frame_all_extracted(ctx);
- ctx->state = MFCINST_RES_CHANGE_END;
- goto leave_handle_frame;
- } else {
- s5p_mfc_handle_frame_all_extracted(ctx);
- }
- }
-
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
- s5p_mfc_handle_frame_copy_time(ctx);
-
- /* A frame has been decoded and is in the buffer */
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
- s5p_mfc_handle_frame_new(ctx, err);
- } else {
- mfc_debug(2, "No frame decode\n");
- }
- /* Mark source buffer as complete */
- if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
- && !list_empty(&ctx->src_queue)) {
- src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
- list);
- ctx->consumed_stream += s5p_mfc_get_consumed_stream();
- if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
- s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
- && ctx->consumed_stream + STUFF_BYTE <
- src_buf->b->v4l2_planes[0].bytesused) {
- /* Run MFC again on the same buffer */
- mfc_debug(2, "Running again the same buffer\n");
- ctx->after_packed_pb = 1;
- } else {
- index = src_buf->b->v4l2_buf.index;
- mfc_debug(2, "MFC needs next buffer\n");
- ctx->consumed_stream = 0;
- list_del(&src_buf->list);
- ctx->src_queue_cnt--;
- if (s5p_mfc_err_dec(err) > 0)
- vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
- else
- vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
- }
- }
-leave_handle_frame:
- spin_unlock_irqrestore(&dev->irqlock, flags);
- if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
- || ctx->dst_queue_cnt < ctx->dpb_count)
- clear_work_bit(ctx);
- s5p_mfc_clear_int_flags(dev);
- wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- s5p_mfc_try_run(dev);
-}
-
-/* Error handling for interrupt */
-static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev;
- unsigned long flags;
-
- /* If no context is available then all necessary
- * processing has been done. */
- if (ctx == NULL)
- return;
-
- dev = ctx->dev;
- mfc_err("Interrupt Error: %08x\n", err);
- s5p_mfc_clear_int_flags(dev);
- wake_up_dev(dev, reason, err);
-
- /* Error recovery is dependent on the state of context */
- switch (ctx->state) {
- case MFCINST_INIT:
- /* This error had to happen while acquireing instance */
- case MFCINST_GOT_INST:
- /* This error had to happen while parsing the header */
- case MFCINST_HEAD_PARSED:
- /* This error had to happen while setting dst buffers */
- case MFCINST_RETURN_INST:
- /* This error had to happen while releasing instance */
- clear_work_bit(ctx);
- wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- ctx->state = MFCINST_ERROR;
- break;
- case MFCINST_FINISHING:
- case MFCINST_FINISHED:
- case MFCINST_RUNNING:
- /* It is higly probable that an error occured
- * while decoding a frame */
- clear_work_bit(ctx);
- ctx->state = MFCINST_ERROR;
- /* Mark all dst buffers as having an error */
- spin_lock_irqsave(&dev->irqlock, flags);
- s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
- /* Mark all src buffers as having an error */
- s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- break;
- default:
- mfc_err("Encountered an error interrupt which had not been handled\n");
- break;
- }
- return;
-}
-
-/* Header parsing interrupt handling */
-static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev;
- unsigned int guard_width, guard_height;
-
- if (ctx == NULL)
- return;
- dev = ctx->dev;
- if (ctx->c_ops->post_seq_start) {
- if (ctx->c_ops->post_seq_start(ctx))
- mfc_err("post_seq_start() failed\n");
- } else {
- ctx->img_width = s5p_mfc_get_img_width();
- ctx->img_height = s5p_mfc_get_img_height();
-
- ctx->buf_width = ALIGN(ctx->img_width,
- S5P_FIMV_NV12MT_HALIGN);
- ctx->buf_height = ALIGN(ctx->img_height,
- S5P_FIMV_NV12MT_VALIGN);
- mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
- "buffer dimensions: %dx%d\n", ctx->img_width,
- ctx->img_height, ctx->buf_width,
- ctx->buf_height);
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
- ctx->luma_size = ALIGN(ctx->buf_width *
- ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN);
- ctx->chroma_size = ALIGN(ctx->buf_width *
- ALIGN((ctx->img_height >> 1),
- S5P_FIMV_NV12MT_VALIGN),
- S5P_FIMV_DEC_BUF_ALIGN);
- ctx->mv_size = ALIGN(ctx->buf_width *
- ALIGN((ctx->buf_height >> 2),
- S5P_FIMV_NV12MT_VALIGN),
- S5P_FIMV_DEC_BUF_ALIGN);
- } else {
- guard_width = ALIGN(ctx->img_width + 24,
- S5P_FIMV_NV12MT_HALIGN);
- guard_height = ALIGN(ctx->img_height + 16,
- S5P_FIMV_NV12MT_VALIGN);
- ctx->luma_size = ALIGN(guard_width *
- guard_height, S5P_FIMV_DEC_BUF_ALIGN);
- guard_width = ALIGN(ctx->img_width + 16,
- S5P_FIMV_NV12MT_HALIGN);
- guard_height = ALIGN((ctx->img_height >> 1) + 4,
- S5P_FIMV_NV12MT_VALIGN);
- ctx->chroma_size = ALIGN(guard_width *
- guard_height, S5P_FIMV_DEC_BUF_ALIGN);
- ctx->mv_size = 0;
- }
- ctx->dpb_count = s5p_mfc_get_dpb_count();
- if (ctx->img_width == 0 || ctx->img_height == 0)
- ctx->state = MFCINST_ERROR;
- else
- ctx->state = MFCINST_HEAD_PARSED;
- }
- s5p_mfc_clear_int_flags(dev);
- clear_work_bit(ctx);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- s5p_mfc_try_run(dev);
- wake_up_ctx(ctx, reason, err);
-}
-
-/* Header parsing interrupt handling */
-static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_buf *src_buf;
- struct s5p_mfc_dev *dev;
- unsigned long flags;
-
- if (ctx == NULL)
- return;
- dev = ctx->dev;
- s5p_mfc_clear_int_flags(dev);
- ctx->int_type = reason;
- ctx->int_err = err;
- ctx->int_cond = 1;
- spin_lock(&dev->condlock);
- clear_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock(&dev->condlock);
- if (err == 0) {
- ctx->state = MFCINST_RUNNING;
- if (!ctx->dpb_flush_flag) {
- spin_lock_irqsave(&dev->irqlock, flags);
- if (!list_empty(&ctx->src_queue)) {
- src_buf = list_entry(ctx->src_queue.next,
- struct s5p_mfc_buf, list);
- list_del(&src_buf->list);
- ctx->src_queue_cnt--;
- vb2_buffer_done(src_buf->b,
- VB2_BUF_STATE_DONE);
- }
- spin_unlock_irqrestore(&dev->irqlock, flags);
- } else {
- ctx->dpb_flush_flag = 0;
- }
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
-
- s5p_mfc_clock_off();
-
- wake_up(&ctx->queue);
- s5p_mfc_try_run(dev);
- } else {
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
-
- s5p_mfc_clock_off();
-
- wake_up(&ctx->queue);
- }
-}
-
-/* Interrupt processing */
-static irqreturn_t s5p_mfc_irq(int irq, void *priv)
-{
- struct s5p_mfc_dev *dev = priv;
- struct s5p_mfc_ctx *ctx;
- unsigned int reason;
- unsigned int err;
-
- mfc_debug_enter();
- /* Reset the timeout watchdog */
- atomic_set(&dev->watchdog_cnt, 0);
- ctx = dev->ctx[dev->curr_ctx];
- /* Get the reason of interrupt and the error code */
- reason = s5p_mfc_get_int_reason();
- err = s5p_mfc_get_int_err();
- mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
- switch (reason) {
- case S5P_FIMV_R2H_CMD_ERR_RET:
- /* An error has occured */
- if (ctx->state == MFCINST_RUNNING &&
- s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
- s5p_mfc_handle_frame(ctx, reason, err);
- else
- s5p_mfc_handle_error(ctx, reason, err);
- clear_bit(0, &dev->enter_suspend);
- break;
-
- case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
- case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
- if (ctx->c_ops->post_frame_start) {
- if (ctx->c_ops->post_frame_start(ctx))
- mfc_err("post_frame_start() failed\n");
- s5p_mfc_clear_int_flags(dev);
- wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
- s5p_mfc_clock_off();
- s5p_mfc_try_run(dev);
- } else {
- s5p_mfc_handle_frame(ctx, reason, err);
- }
- break;
-
- case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
- s5p_mfc_handle_seq_done(ctx, reason, err);
- break;
-
- case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
- ctx->inst_no = s5p_mfc_get_inst_no();
- ctx->state = MFCINST_GOT_INST;
- clear_work_bit(ctx);
- wake_up(&ctx->queue);
- goto irq_cleanup_hw;
-
- case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
- clear_work_bit(ctx);
- ctx->state = MFCINST_FREE;
- wake_up(&ctx->queue);
- goto irq_cleanup_hw;
-
- case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
- case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
- case S5P_FIMV_R2H_CMD_SLEEP_RET:
- case S5P_FIMV_R2H_CMD_WAKEUP_RET:
- if (ctx)
- clear_work_bit(ctx);
- s5p_mfc_clear_int_flags(dev);
- wake_up_dev(dev, reason, err);
- clear_bit(0, &dev->hw_lock);
- clear_bit(0, &dev->enter_suspend);
- break;
-
- case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
- s5p_mfc_handle_init_buffers(ctx, reason, err);
- break;
- default:
- mfc_debug(2, "Unknown int reason\n");
- s5p_mfc_clear_int_flags(dev);
- }
- mfc_debug_leave();
- return IRQ_HANDLED;
-irq_cleanup_hw:
- s5p_mfc_clear_int_flags(dev);
- ctx->int_type = reason;
- ctx->int_err = err;
- ctx->int_cond = 1;
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- mfc_err("Failed to unlock hw\n");
-
- s5p_mfc_clock_off();
-
- s5p_mfc_try_run(dev);
- mfc_debug(2, "Exit via irq_cleanup_hw\n");
- return IRQ_HANDLED;
-}
-
-/* Open an MFC node */
-static int s5p_mfc_open(struct file *file)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = NULL;
- struct vb2_queue *q;
- unsigned long flags;
- int ret = 0;
-
- mfc_debug_enter();
- dev->num_inst++; /* It is guarded by mfc_mutex in vfd */
- /* Allocate memory for context */
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
- if (!ctx) {
- mfc_err("Not enough memory\n");
- ret = -ENOMEM;
- goto err_alloc;
- }
- v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
- ctx->dev = dev;
- INIT_LIST_HEAD(&ctx->src_queue);
- INIT_LIST_HEAD(&ctx->dst_queue);
- ctx->src_queue_cnt = 0;
- ctx->dst_queue_cnt = 0;
- /* Get context number */
- ctx->num = 0;
- while (dev->ctx[ctx->num]) {
- ctx->num++;
- if (ctx->num >= MFC_NUM_CONTEXTS) {
- mfc_err("Too many open contexts\n");
- ret = -EBUSY;
- goto err_no_ctx;
- }
- }
- /* Mark context as idle */
- spin_lock_irqsave(&dev->condlock, flags);
- clear_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- dev->ctx[ctx->num] = ctx;
- if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
- ctx->type = MFCINST_DECODER;
- ctx->c_ops = get_dec_codec_ops();
- /* Setup ctrl handler */
- ret = s5p_mfc_dec_ctrls_setup(ctx);
- if (ret) {
- mfc_err("Failed to setup mfc controls\n");
- goto err_ctrls_setup;
- }
- } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
- ctx->type = MFCINST_ENCODER;
- ctx->c_ops = get_enc_codec_ops();
- /* only for encoder */
- INIT_LIST_HEAD(&ctx->ref_queue);
- ctx->ref_queue_cnt = 0;
- /* Setup ctrl handler */
- ret = s5p_mfc_enc_ctrls_setup(ctx);
- if (ret) {
- mfc_err("Failed to setup mfc controls\n");
- goto err_ctrls_setup;
- }
- } else {
- ret = -ENOENT;
- goto err_bad_node;
- }
- ctx->fh.ctrl_handler = &ctx->ctrl_handler;
- ctx->inst_no = -1;
- /* Load firmware if this is the first instance */
- if (dev->num_inst == 1) {
- dev->watchdog_timer.expires = jiffies +
- msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
- add_timer(&dev->watchdog_timer);
- ret = s5p_mfc_power_on();
- if (ret < 0) {
- mfc_err("power on failed\n");
- goto err_pwr_enable;
- }
- s5p_mfc_clock_on();
- ret = s5p_mfc_alloc_and_load_firmware(dev);
- if (ret)
- goto err_alloc_fw;
- /* Init the FW */
- ret = s5p_mfc_init_hw(dev);
- if (ret)
- goto err_init_hw;
- s5p_mfc_clock_off();
- }
- /* Init videobuf2 queue for CAPTURE */
- q = &ctx->vq_dst;
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- q->drv_priv = &ctx->fh;
- if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
- q->io_modes = VB2_MMAP;
- q->ops = get_dec_queue_ops();
- } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->ops = get_enc_queue_ops();
- } else {
- ret = -ENOENT;
- goto err_queue_init;
- }
- q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
- ret = vb2_queue_init(q);
- if (ret) {
- mfc_err("Failed to initialize videobuf2 queue(capture)\n");
- goto err_queue_init;
- }
- /* Init videobuf2 queue for OUTPUT */
- q = &ctx->vq_src;
- q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- q->io_modes = VB2_MMAP;
- q->drv_priv = &ctx->fh;
- if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
- q->io_modes = VB2_MMAP;
- q->ops = get_dec_queue_ops();
- } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->ops = get_enc_queue_ops();
- } else {
- ret = -ENOENT;
- goto err_queue_init;
- }
- q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
- ret = vb2_queue_init(q);
- if (ret) {
- mfc_err("Failed to initialize videobuf2 queue(output)\n");
- goto err_queue_init;
- }
- init_waitqueue_head(&ctx->queue);
- mfc_debug_leave();
- return ret;
- /* Deinit when failure occured */
-err_queue_init:
-err_init_hw:
- s5p_mfc_release_firmware(dev);
-err_alloc_fw:
- dev->ctx[ctx->num] = NULL;
- del_timer_sync(&dev->watchdog_timer);
- s5p_mfc_clock_off();
-err_pwr_enable:
- if (dev->num_inst == 1) {
- if (s5p_mfc_power_off() < 0)
- mfc_err("power off failed\n");
- s5p_mfc_release_firmware(dev);
- }
-err_ctrls_setup:
- s5p_mfc_dec_ctrls_delete(ctx);
-err_bad_node:
-err_no_ctx:
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- kfree(ctx);
-err_alloc:
- dev->num_inst--;
- mfc_debug_leave();
- return ret;
-}
-
-/* Release MFC context */
-static int s5p_mfc_release(struct file *file)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
-
- mfc_debug_enter();
- s5p_mfc_clock_on();
- vb2_queue_release(&ctx->vq_src);
- vb2_queue_release(&ctx->vq_dst);
- /* Mark context as idle */
- spin_lock_irqsave(&dev->condlock, flags);
- clear_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- /* If instance was initialised then
- * return instance and free reosurces */
- if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
- mfc_debug(2, "Has to free instance\n");
- ctx->state = MFCINST_RETURN_INST;
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_try_run(dev);
- /* Wait until instance is returned or timeout occured */
- if (s5p_mfc_wait_for_done_ctx
- (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
- s5p_mfc_clock_off();
- mfc_err("Err returning instance\n");
- }
- mfc_debug(2, "After free instance\n");
- /* Free resources */
- s5p_mfc_release_codec_buffers(ctx);
- s5p_mfc_release_instance_buffer(ctx);
- if (ctx->type == MFCINST_DECODER)
- s5p_mfc_release_dec_desc_buffer(ctx);
-
- ctx->inst_no = MFC_NO_INSTANCE_SET;
- }
- /* hardware locking scheme */
- if (dev->curr_ctx == ctx->num)
- clear_bit(0, &dev->hw_lock);
- dev->num_inst--;
- if (dev->num_inst == 0) {
- mfc_debug(2, "Last instance - release firmware\n");
- /* reset <-> F/W release */
- s5p_mfc_reset(dev);
- s5p_mfc_release_firmware(dev);
- del_timer_sync(&dev->watchdog_timer);
- if (s5p_mfc_power_off() < 0)
- mfc_err("Power off failed\n");
- }
- mfc_debug(2, "Shutting down clock\n");
- s5p_mfc_clock_off();
- dev->ctx[ctx->num] = NULL;
- s5p_mfc_dec_ctrls_delete(ctx);
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- kfree(ctx);
- mfc_debug_leave();
- return 0;
-}
-
-/* Poll */
-static unsigned int s5p_mfc_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
- struct s5p_mfc_dev *dev = ctx->dev;
- struct vb2_queue *src_q, *dst_q;
- struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
- unsigned int rc = 0;
- unsigned long flags;
-
- src_q = &ctx->vq_src;
- dst_q = &ctx->vq_dst;
- /*
- * There has to be at least one buffer queued on each queued_list, which
- * means either in driver already or waiting for driver to claim it
- * and start processing.
- */
- if ((!src_q->streaming || list_empty(&src_q->queued_list))
- && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
- rc = POLLERR;
- goto end;
- }
- mutex_unlock(&dev->mfc_mutex);
- poll_wait(file, &src_q->done_wq, wait);
- poll_wait(file, &dst_q->done_wq, wait);
- mutex_lock(&dev->mfc_mutex);
- spin_lock_irqsave(&src_q->done_lock, flags);
- if (!list_empty(&src_q->done_list))
- src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
- done_entry);
- if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
- || src_vb->state == VB2_BUF_STATE_ERROR))
- rc |= POLLOUT | POLLWRNORM;
- spin_unlock_irqrestore(&src_q->done_lock, flags);
- spin_lock_irqsave(&dst_q->done_lock, flags);
- if (!list_empty(&dst_q->done_list))
- dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
- done_entry);
- if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
- || dst_vb->state == VB2_BUF_STATE_ERROR))
- rc |= POLLIN | POLLRDNORM;
- spin_unlock_irqrestore(&dst_q->done_lock, flags);
-end:
- return rc;
-}
-
-/* Mmap */
-static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- int ret;
- if (offset < DST_QUEUE_OFF_BASE) {
- mfc_debug(2, "mmaping source\n");
- ret = vb2_mmap(&ctx->vq_src, vma);
- } else { /* capture */
- mfc_debug(2, "mmaping destination\n");
- vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
- ret = vb2_mmap(&ctx->vq_dst, vma);
- }
- return ret;
-}
-
-/* v4l2 ops */
-static const struct v4l2_file_operations s5p_mfc_fops = {
- .owner = THIS_MODULE,
- .open = s5p_mfc_open,
- .release = s5p_mfc_release,
- .poll = s5p_mfc_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = s5p_mfc_mmap,
-};
-
-static int match_child(struct device *dev, void *data)
-{
- if (!dev_name(dev))
- return 0;
- return !strcmp(dev_name(dev), (char *)data);
-}
-
-/* MFC probe function */
-static int s5p_mfc_probe(struct platform_device *pdev)
-{
- struct s5p_mfc_dev *dev;
- struct video_device *vfd;
- struct resource *res;
- int ret;
-
- pr_debug("%s++\n", __func__);
- dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
- if (!dev) {
- dev_err(&pdev->dev, "Not enough memory for MFC device\n");
- return -ENOMEM;
- }
-
- spin_lock_init(&dev->irqlock);
- spin_lock_init(&dev->condlock);
- dev->plat_dev = pdev;
- if (!dev->plat_dev) {
- dev_err(&pdev->dev, "No platform data specified\n");
- return -ENODEV;
- }
-
- ret = s5p_mfc_init_pm(dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get mfc clock source\n");
- return ret;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
- if (dev->regs_base == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get irq resource\n");
- ret = -ENOENT;
- goto err_res;
- }
- dev->irq = res->start;
- ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
- IRQF_DISABLED, pdev->name, dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
- goto err_res;
- }
-
- dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
- match_child);
- if (!dev->mem_dev_l) {
- mfc_err("Mem child (L) device get failed\n");
- ret = -ENODEV;
- goto err_res;
- }
- dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
- match_child);
- if (!dev->mem_dev_r) {
- mfc_err("Mem child (R) device get failed\n");
- ret = -ENODEV;
- goto err_res;
- }
-
- dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
- if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
- ret = PTR_ERR(dev->alloc_ctx[0]);
- goto err_res;
- }
- dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
- if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
- ret = PTR_ERR(dev->alloc_ctx[1]);
- goto err_mem_init_ctx_1;
- }
-
- mutex_init(&dev->mfc_mutex);
-
- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
- if (ret)
- goto err_v4l2_dev_reg;
- init_waitqueue_head(&dev->queue);
-
- /* decoder */
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
- ret = -ENOMEM;
- goto err_dec_alloc;
- }
- vfd->fops = &s5p_mfc_fops,
- vfd->ioctl_ops = get_dec_v4l2_ioctl_ops();
- vfd->release = video_device_release,
- vfd->lock = &dev->mfc_mutex;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- vfd->v4l2_dev = &dev->v4l2_dev;
- snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
- dev->vfd_dec = vfd;
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- video_device_release(vfd);
- goto err_dec_reg;
- }
- v4l2_info(&dev->v4l2_dev,
- "decoder registered as /dev/video%d\n", vfd->num);
- video_set_drvdata(vfd, dev);
-
- /* encoder */
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
- ret = -ENOMEM;
- goto err_enc_alloc;
- }
- vfd->fops = &s5p_mfc_fops,
- vfd->ioctl_ops = get_enc_v4l2_ioctl_ops();
- vfd->release = video_device_release,
- vfd->lock = &dev->mfc_mutex;
- /* This should not be necessary */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
- vfd->v4l2_dev = &dev->v4l2_dev;
- snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
- dev->vfd_enc = vfd;
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- video_device_release(vfd);
- goto err_enc_reg;
- }
- v4l2_info(&dev->v4l2_dev,
- "encoder registered as /dev/video%d\n", vfd->num);
- video_set_drvdata(vfd, dev);
- platform_set_drvdata(pdev, dev);
-
- dev->hw_lock = 0;
- dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
- INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
- atomic_set(&dev->watchdog_cnt, 0);
- init_timer(&dev->watchdog_timer);
- dev->watchdog_timer.data = (unsigned long)dev;
- dev->watchdog_timer.function = s5p_mfc_watchdog;
-
- pr_debug("%s--\n", __func__);
- return 0;
-
-/* Deinit MFC if probe had failed */
-err_enc_reg:
- video_device_release(dev->vfd_enc);
-err_enc_alloc:
- video_unregister_device(dev->vfd_dec);
-err_dec_reg:
- video_device_release(dev->vfd_dec);
-err_dec_alloc:
- v4l2_device_unregister(&dev->v4l2_dev);
-err_v4l2_dev_reg:
- vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
-err_mem_init_ctx_1:
- vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
-err_res:
- s5p_mfc_final_pm(dev);
-
- pr_debug("%s-- with error\n", __func__);
- return ret;
-
-}
-
-/* Remove the driver */
-static int __devexit s5p_mfc_remove(struct platform_device *pdev)
-{
- struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
-
- v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
-
- del_timer_sync(&dev->watchdog_timer);
- flush_workqueue(dev->watchdog_workqueue);
- destroy_workqueue(dev->watchdog_workqueue);
-
- video_unregister_device(dev->vfd_enc);
- video_unregister_device(dev->vfd_dec);
- v4l2_device_unregister(&dev->v4l2_dev);
- vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
- vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
-
- s5p_mfc_final_pm(dev);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int s5p_mfc_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
- int ret;
-
- if (m_dev->num_inst == 0)
- return 0;
- return s5p_mfc_sleep(m_dev);
- if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) {
- mfc_err("Error: going to suspend for a second time\n");
- return -EIO;
- }
-
- /* Check if we're processing then wait if it necessary. */
- while (test_and_set_bit(0, &m_dev->hw_lock) != 0) {
- /* Try and lock the HW */
- /* Wait on the interrupt waitqueue */
- ret = wait_event_interruptible_timeout(m_dev->queue,
- m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
- msecs_to_jiffies(MFC_INT_TIMEOUT));
-
- if (ret == 0) {
- mfc_err("Waiting for hardware to finish timed out\n");
- return -EIO;
- }
- }
- return 0;
-}
-
-static int s5p_mfc_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
-
- if (m_dev->num_inst == 0)
- return 0;
- return s5p_mfc_wakeup(m_dev);
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int s5p_mfc_runtime_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
-
- atomic_set(&m_dev->pm.power, 0);
- return 0;
-}
-
-static int s5p_mfc_runtime_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
- int pre_power;
-
- if (!m_dev->alloc_ctx)
- return 0;
- pre_power = atomic_read(&m_dev->pm.power);
- atomic_set(&m_dev->pm.power, 1);
- return 0;
-}
-#endif
-
-/* Power management */
-static const struct dev_pm_ops s5p_mfc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
- SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume,
- NULL)
-};
-
-static struct platform_driver s5p_mfc_driver = {
- .probe = s5p_mfc_probe,
- .remove = __devexit_p(s5p_mfc_remove),
- .driver = {
- .name = S5P_MFC_NAME,
- .owner = THIS_MODULE,
- .pm = &s5p_mfc_pm_ops
- },
-};
-
-module_platform_driver(s5p_mfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
-MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver");
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
deleted file mode 100644
index f0665ed1a529..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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 "regs-mfc.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-
-/* This function is used to send a command to the MFC */
-static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
- struct s5p_mfc_cmd_args *args)
-{
- int cur_cmd;
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
- /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
- do {
- if (time_after(jiffies, timeout)) {
- mfc_err("Timeout while waiting for hardware\n");
- return -EIO;
- }
- cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
- } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
- mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
- mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
- mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
- mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
- /* Issue the command */
- mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
- return 0;
-}
-
-/* Initialize the MFC */
-int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_cmd_args h2r_args;
-
- memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
- h2r_args.arg[0] = dev->fw_size;
- return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
-}
-
-/* Suspend the MFC hardware */
-int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_cmd_args h2r_args;
-
- memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
- return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
-}
-
-/* Wake up the MFC hardware */
-int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_cmd_args h2r_args;
-
- memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
- return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
-}
-
-
-int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_cmd_args h2r_args;
- int ret;
-
- /* Preparing decoding - getting instance number */
- mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
- dev->curr_ctx = ctx->num;
- memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
- h2r_args.arg[0] = ctx->codec_mode;
- h2r_args.arg[1] = 0; /* no crc & no pixelcache */
- h2r_args.arg[2] = ctx->ctx_ofs;
- h2r_args.arg[3] = ctx->ctx_size;
- ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
- &h2r_args);
- if (ret) {
- mfc_err("Failed to create a new instance\n");
- ctx->state = MFCINST_ERROR;
- }
- return ret;
-}
-
-int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_cmd_args h2r_args;
- int ret;
-
- if (ctx->state == MFCINST_FREE) {
- mfc_err("Instance already returned\n");
- ctx->state = MFCINST_ERROR;
- return -EINVAL;
- }
- /* Closing decoding instance */
- mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
- dev->curr_ctx = ctx->num;
- memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
- h2r_args.arg[0] = ctx->inst_no;
- ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
- &h2r_args);
- if (ret) {
- mfc_err("Failed to return an instance\n");
- ctx->state = MFCINST_ERROR;
- return -EINVAL;
- }
- return 0;
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
deleted file mode 100644
index 5ceebfe6131a..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_CMD_H_
-#define S5P_MFC_CMD_H_
-
-#include "s5p_mfc_common.h"
-
-#define MAX_H2R_ARG 4
-
-struct s5p_mfc_cmd_args {
- unsigned int arg[MAX_H2R_ARG];
-};
-
-int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
-int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
-int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
-int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
-
-#endif /* S5P_MFC_CMD_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
deleted file mode 100644
index 08a5cfeaa59e..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.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/firmware.h>
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include "regs-mfc.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_intr.h"
-#include "s5p_mfc_pm.h"
-
-static void *s5p_mfc_bitproc_buf;
-static size_t s5p_mfc_bitproc_phys;
-static unsigned char *s5p_mfc_bitproc_virt;
-
-/* Allocate and load firmware */
-int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
-{
- struct firmware *fw_blob;
- size_t bank2_base_phys;
- void *b_base;
- int err;
-
- /* Firmare has to be present as a separate file or compiled
- * into kernel. */
- mfc_debug_enter();
- err = request_firmware((const struct firmware **)&fw_blob,
- "s5p-mfc.fw", dev->v4l2_dev.dev);
- if (err != 0) {
- mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
- return -EINVAL;
- }
- dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN);
- if (s5p_mfc_bitproc_buf) {
- mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
- if (IS_ERR(s5p_mfc_bitproc_buf)) {
- s5p_mfc_bitproc_buf = NULL;
- mfc_err("Allocating bitprocessor buffer failed\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
- if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
- mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
- if (!s5p_mfc_bitproc_virt) {
- mfc_err("Bitprocessor memory remap failed\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- dev->bank1 = s5p_mfc_bitproc_phys;
- b_base = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER);
- if (IS_ERR(b_base)) {
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- mfc_err("Allocating bank2 base failed\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- bank2_base_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
- vb2_dma_contig_memops.put(b_base);
- if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
- mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- dev->bank2 = bank2_base_phys;
- memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
- wmb();
- release_firmware(fw_blob);
- mfc_debug_leave();
- return 0;
-}
-
-/* Reload firmware to MFC */
-int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
-{
- struct firmware *fw_blob;
- int err;
-
- /* Firmare has to be present as a separate file or compiled
- * into kernel. */
- mfc_debug_enter();
- err = request_firmware((const struct firmware **)&fw_blob,
- "s5p-mfc.fw", dev->v4l2_dev.dev);
- if (err != 0) {
- mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
- return -EINVAL;
- }
- if (fw_blob->size > dev->fw_size) {
- mfc_err("MFC firmware is too big to be loaded\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
- mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
- release_firmware(fw_blob);
- return -EINVAL;
- }
- memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
- wmb();
- release_firmware(fw_blob);
- mfc_debug_leave();
- return 0;
-}
-
-/* Release firmware memory */
-int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
-{
- /* Before calling this function one has to make sure
- * that MFC is no longer processing */
- if (!s5p_mfc_bitproc_buf)
- return -EINVAL;
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_virt = NULL;
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- return 0;
-}
-
-/* Reset the device */
-int s5p_mfc_reset(struct s5p_mfc_dev *dev)
-{
- unsigned int mc_status;
- unsigned long timeout;
-
- mfc_debug_enter();
- /* Stop procedure */
- /* reset RISC */
- mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
- /* All reset except for MC */
- mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
- mdelay(10);
-
- timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
- /* Check MC status */
- do {
- if (time_after(jiffies, timeout)) {
- mfc_err("Timeout while resetting MFC\n");
- return -EIO;
- }
-
- mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
-
- } while (mc_status & 0x3);
-
- mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
- mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
- mfc_debug_leave();
- return 0;
-}
-
-static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
-{
- mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
- mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
- mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
-}
-
-static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
-{
- mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
- mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
- mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
- mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
-}
-
-/* Initialize hardware */
-int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
-{
- unsigned int ver;
- int ret;
-
- mfc_debug_enter();
- if (!s5p_mfc_bitproc_buf)
- return -EINVAL;
-
- /* 0. MFC reset */
- mfc_debug(2, "MFC reset..\n");
- s5p_mfc_clock_on();
- ret = s5p_mfc_reset(dev);
- if (ret) {
- mfc_err("Failed to reset MFC - timeout\n");
- return ret;
- }
- mfc_debug(2, "Done MFC reset..\n");
- /* 1. Set DRAM base Addr */
- s5p_mfc_init_memctrl(dev);
- /* 2. Initialize registers of channel I/F */
- s5p_mfc_clear_cmds(dev);
- /* 3. Release reset signal to the RISC */
- s5p_mfc_clean_dev_int_flags(dev);
- mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
- mfc_debug(2, "Will now wait for completion of firmware transfer\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
- mfc_err("Failed to load firmware\n");
- s5p_mfc_reset(dev);
- s5p_mfc_clock_off();
- return -EIO;
- }
- s5p_mfc_clean_dev_int_flags(dev);
- /* 4. Initialize firmware */
- ret = s5p_mfc_sys_init_cmd(dev);
- if (ret) {
- mfc_err("Failed to send command to MFC - timeout\n");
- s5p_mfc_reset(dev);
- s5p_mfc_clock_off();
- return ret;
- }
- mfc_debug(2, "Ok, now will write a command to init the system\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
- mfc_err("Failed to load firmware\n");
- s5p_mfc_reset(dev);
- s5p_mfc_clock_off();
- return -EIO;
- }
- dev->int_cond = 0;
- if (dev->int_err != 0 || dev->int_type !=
- S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
- /* Failure. */
- mfc_err("Failed to init firmware - error: %d int: %d\n",
- dev->int_err, dev->int_type);
- s5p_mfc_reset(dev);
- s5p_mfc_clock_off();
- return -EIO;
- }
- ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
- mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
- (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
- s5p_mfc_clock_off();
- mfc_debug_leave();
- return 0;
-}
-
-
-int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- mfc_debug_enter();
- s5p_mfc_clock_on();
- s5p_mfc_clean_dev_int_flags(dev);
- ret = s5p_mfc_sleep_cmd(dev);
- if (ret) {
- mfc_err("Failed to send command to MFC - timeout\n");
- return ret;
- }
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
- mfc_err("Failed to sleep\n");
- return -EIO;
- }
- s5p_mfc_clock_off();
- dev->int_cond = 0;
- if (dev->int_err != 0 || dev->int_type !=
- S5P_FIMV_R2H_CMD_SLEEP_RET) {
- /* Failure. */
- mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
- dev->int_type);
- return -EIO;
- }
- mfc_debug_leave();
- return ret;
-}
-
-int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- mfc_debug_enter();
- /* 0. MFC reset */
- mfc_debug(2, "MFC reset..\n");
- s5p_mfc_clock_on();
- ret = s5p_mfc_reset(dev);
- if (ret) {
- mfc_err("Failed to reset MFC - timeout\n");
- return ret;
- }
- mfc_debug(2, "Done MFC reset..\n");
- /* 1. Set DRAM base Addr */
- s5p_mfc_init_memctrl(dev);
- /* 2. Initialize registers of channel I/F */
- s5p_mfc_clear_cmds(dev);
- s5p_mfc_clean_dev_int_flags(dev);
- /* 3. Initialize firmware */
- ret = s5p_mfc_wakeup_cmd(dev);
- if (ret) {
- mfc_err("Failed to send command to MFC - timeout\n");
- return ret;
- }
- /* 4. Release reset signal to the RISC */
- mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
- mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
- mfc_err("Failed to load firmware\n");
- return -EIO;
- }
- s5p_mfc_clock_off();
- dev->int_cond = 0;
- if (dev->int_err != 0 || dev->int_type !=
- S5P_FIMV_R2H_CMD_WAKEUP_RET) {
- /* Failure. */
- mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
- dev->int_type);
- return -EIO;
- }
- mfc_debug_leave();
- return 0;
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
deleted file mode 100644
index 61dc23b7ee5a..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_CTRL_H
-#define S5P_MFC_CTRL_H
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
-int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
-int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
-int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_reset(struct s5p_mfc_dev *dev);
-
-#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_debug.h b/drivers/media/video/s5p-mfc/s5p_mfc_debug.h
deleted file mode 100644
index ecb8616a492a..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_debug.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * drivers/media/video/samsung/mfc5/s5p_mfc_debug.h
- *
- * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
- * This file contains debug macros
- *
- * Kamil Debski, Copyright (c) 2011 Samsung Electronics
- * http://www.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 S5P_MFC_DEBUG_H_
-#define S5P_MFC_DEBUG_H_
-
-#define DEBUG
-
-#ifdef DEBUG
-extern int debug;
-
-#define mfc_debug(level, fmt, args...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define mfc_debug(level, fmt, args...)
-#endif
-
-#define mfc_debug_enter() mfc_debug(5, "enter")
-#define mfc_debug_leave() mfc_debug(5, "leave")
-
-#define mfc_err(fmt, args...) \
- do { \
- printk(KERN_ERR "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define mfc_info(fmt, args...) \
- do { \
- printk(KERN_INFO "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
deleted file mode 100644
index c5d567f87d77..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- * 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/clk.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#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/v4l2-ctrls.h>
-#include <media/videobuf2-core.h>
-#include "regs-mfc.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_dec.h"
-#include "s5p_mfc_intr.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_shm.h"
-
-static struct s5p_mfc_fmt formats[] = {
- {
- .name = "4:2:0 2 Planes 64x32 Tiles",
- .fourcc = V4L2_PIX_FMT_NV12MT,
- .codec_mode = S5P_FIMV_CODEC_NONE,
- .type = MFC_FMT_RAW,
- .num_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes",
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = S5P_FIMV_CODEC_NONE,
- .type = MFC_FMT_RAW,
- .num_planes = 2,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .codec_mode = S5P_FIMV_CODEC_H264_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "H263 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H263,
- .codec_mode = S5P_FIMV_CODEC_H263_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "MPEG1 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG1,
- .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "MPEG2 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG2,
- .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "MPEG4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "XviD Encoded Stream",
- .fourcc = V4L2_PIX_FMT_XVID,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "VC1 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
- .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
- {
- .name = "VC1 RCV Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
- .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
- .type = MFC_FMT_DEC,
- .num_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-/* Find selected format description */
-static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
-{
- unsigned int i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
- formats[i].type == t)
- return &formats[i];
- }
- return NULL;
-}
-
-static struct mfc_control controls[] = {
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Display Delay",
- .minimum = 0,
- .maximum = 16383,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 Display Delay Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mpeg4 Loop Filter Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Slice Interface Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Minimum number of cap bufs",
- .minimum = 1,
- .maximum = 32,
- .step = 1,
- .default_value = 1,
- .is_volatile = 1,
- },
-};
-
-#define NUM_CTRLS ARRAY_SIZE(controls)
-
-/* Check whether a context should be run on hardware */
-static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- /* Context is to parse header */
- if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
- return 1;
- /* Context is to decode a frame */
- if (ctx->src_queue_cnt >= 1 &&
- ctx->state == MFCINST_RUNNING &&
- ctx->dst_queue_cnt >= ctx->dpb_count)
- return 1;
- /* Context is to return last frame */
- if (ctx->state == MFCINST_FINISHING &&
- ctx->dst_queue_cnt >= ctx->dpb_count)
- return 1;
- /* Context is to set buffers */
- if (ctx->src_queue_cnt >= 1 &&
- ctx->state == MFCINST_HEAD_PARSED &&
- ctx->capture_state == QUEUE_BUFS_MMAPED)
- return 1;
- /* Resolution change */
- if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
- ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
- ctx->dst_queue_cnt >= ctx->dpb_count)
- return 1;
- if (ctx->state == MFCINST_RES_CHANGE_END &&
- ctx->src_queue_cnt >= 1)
- return 1;
- mfc_debug(2, "ctx is not ready\n");
- return 0;
-}
-
-static struct s5p_mfc_codec_ops decoder_codec_ops = {
- .pre_seq_start = NULL,
- .post_seq_start = NULL,
- .pre_frame_start = NULL,
- .post_frame_start = NULL,
-};
-
-/* Query capabilities of the device */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE;
- return 0;
-}
-
-/* Enumerate format */
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
-{
- struct s5p_mfc_fmt *fmt;
- int i, j = 0;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- if (mplane && formats[i].num_planes == 1)
- continue;
- else if (!mplane && formats[i].num_planes > 1)
- continue;
- if (out && formats[i].type != MFC_FMT_DEC)
- continue;
- else if (!out && formats[i].type != MFC_FMT_RAW)
- continue;
-
- if (j == f->index)
- break;
- ++j;
- }
- if (i == ARRAY_SIZE(formats))
- return -EINVAL;
- fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, false, false);
-}
-
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, false, true);
-}
-
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, true, true);
-}
-
-/* Get format */
-static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct v4l2_pix_format_mplane *pix_mp;
-
- mfc_debug_enter();
- pix_mp = &f->fmt.pix_mp;
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
- (ctx->state == MFCINST_GOT_INST || ctx->state ==
- MFCINST_RES_CHANGE_END)) {
- /* If the MFC is parsing the header,
- * so wait until it is finished */
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
- 0);
- }
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
- ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- /* This is run on CAPTURE (decode output) */
- /* Width and height are set to the dimensions
- of the movie, the buffer is bigger and
- further processing stages should crop to this
- rectangle. */
- pix_mp->width = ctx->buf_width;
- pix_mp->height = ctx->buf_height;
- pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->num_planes = 2;
- /* Set pixelformat to the format in which MFC
- outputs the decoded frame */
- pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
- pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
- pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
- pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /* This is run on OUTPUT
- The buffer contains compressed image
- so width and height have no meaning */
- pix_mp->width = 0;
- pix_mp->height = 0;
- pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
- pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
- pix_mp->pixelformat = ctx->src_fmt->fourcc;
- pix_mp->num_planes = ctx->src_fmt->num_planes;
- } else {
- mfc_err("Format could not be read\n");
- mfc_debug(2, "%s-- with error\n", __func__);
- return -EINVAL;
- }
- mfc_debug_leave();
- return 0;
-}
-
-/* Try format */
-static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_fmt *fmt;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_err("This node supports decoding only\n");
- return -EINVAL;
- }
- fmt = find_format(f, MFC_FMT_DEC);
- if (!fmt) {
- mfc_err("Unsupported format\n");
- return -EINVAL;
- }
- if (fmt->type != MFC_FMT_DEC) {
- mfc_err("\n");
- return -EINVAL;
- }
- return 0;
-}
-
-/* Set format */
-static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- int ret = 0;
- struct s5p_mfc_fmt *fmt;
- struct v4l2_pix_format_mplane *pix_mp;
-
- mfc_debug_enter();
- ret = vidioc_try_fmt(file, priv, f);
- pix_mp = &f->fmt.pix_mp;
- if (ret)
- return ret;
- if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
- v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto out;
- }
- fmt = find_format(f, MFC_FMT_DEC);
- if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
- mfc_err("Unknown codec\n");
- ret = -EINVAL;
- goto out;
- }
- if (fmt->type != MFC_FMT_DEC) {
- mfc_err("Wrong format selected, you should choose "
- "format for decoding\n");
- ret = -EINVAL;
- goto out;
- }
- ctx->src_fmt = fmt;
- ctx->codec_mode = fmt->codec_mode;
- mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
- pix_mp->height = 0;
- pix_mp->width = 0;
- if (pix_mp->plane_fmt[0].sizeimage)
- ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
- else
- pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
- DEF_CPB_SIZE;
- pix_mp->plane_fmt[0].bytesperline = 0;
- ctx->state = MFCINST_INIT;
-out:
- mfc_debug_leave();
- return ret;
-}
-
-/* Reqeust buffers */
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- int ret = 0;
- unsigned long flags;
-
- if (reqbufs->memory != V4L2_MEMORY_MMAP) {
- mfc_err("Only V4L2_MEMORY_MAP is supported\n");
- return -EINVAL;
- }
- if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /* Can only request buffers after an instance has been opened.*/
- if (ctx->state == MFCINST_INIT) {
- ctx->src_bufs_cnt = 0;
- if (reqbufs->count == 0) {
- mfc_debug(2, "Freeing buffers\n");
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- s5p_mfc_clock_off();
- return ret;
- }
- /* Decoding */
- if (ctx->output_state != QUEUE_FREE) {
- mfc_err("Bufs have already been requested\n");
- return -EINVAL;
- }
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- s5p_mfc_clock_off();
- if (ret) {
- mfc_err("vb2_reqbufs on output failed\n");
- return ret;
- }
- mfc_debug(2, "vb2_reqbufs: %d\n", ret);
- ctx->output_state = QUEUE_BUFS_REQUESTED;
- }
- } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ctx->dst_bufs_cnt = 0;
- if (reqbufs->count == 0) {
- mfc_debug(2, "Freeing buffers\n");
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return ret;
- }
- if (ctx->capture_state != QUEUE_FREE) {
- mfc_err("Bufs have already been requested\n");
- return -EINVAL;
- }
- ctx->capture_state = QUEUE_BUFS_REQUESTED;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- if (ret) {
- mfc_err("vb2_reqbufs on capture failed\n");
- return ret;
- }
- if (reqbufs->count < ctx->dpb_count) {
- mfc_err("Not enough buffers allocated\n");
- reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return -ENOMEM;
- }
- ctx->total_dpb_count = reqbufs->count;
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err("Failed to allocate decoding buffers\n");
- reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return -ENOMEM;
- }
- if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
- ctx->capture_state = QUEUE_BUFS_MMAPED;
- } else {
- mfc_err("Not all buffers passed to buf_init\n");
- reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_release_codec_buffers(ctx);
- s5p_mfc_clock_off();
- return -ENOMEM;
- }
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
- s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
- }
- return ret;
-}
-
-/* Query buffer */
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- int ret;
- int i;
-
- if (buf->memory != V4L2_MEMORY_MMAP) {
- mfc_err("Only mmaped buffers can be used\n");
- return -EINVAL;
- }
- mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
- if (ctx->state == MFCINST_INIT &&
- buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = vb2_querybuf(&ctx->vq_src, buf);
- } else if (ctx->state == MFCINST_RUNNING &&
- buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ret = vb2_querybuf(&ctx->vq_dst, buf);
- for (i = 0; i < buf->length; i++)
- buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
- } else {
- mfc_err("vidioc_querybuf called in an inappropriate state\n");
- ret = -EINVAL;
- }
- mfc_debug_leave();
- return ret;
-}
-
-/* Queue a buffer */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err("Call on QBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_qbuf(&ctx->vq_src, buf);
- else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_qbuf(&ctx->vq_dst, buf);
- return -EINVAL;
-}
-
-/* Dequeue a buffer */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err("Call on DQBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
- else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
- return -EINVAL;
-}
-
-/* Stream on */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- int ret = -EINVAL;
-
- mfc_debug_enter();
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-
- if (ctx->state == MFCINST_INIT) {
- ctx->dst_bufs_cnt = 0;
- ctx->src_bufs_cnt = 0;
- ctx->capture_state = QUEUE_FREE;
- ctx->output_state = QUEUE_FREE;
- s5p_mfc_alloc_instance_buffer(ctx);
- s5p_mfc_alloc_dec_temp_buffers(ctx);
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_try_run(dev);
-
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
- /* Error or timeout */
- mfc_err("Error getting instance from hardware\n");
- s5p_mfc_release_instance_buffer(ctx);
- s5p_mfc_release_dec_desc_buffer(ctx);
- return -EIO;
- }
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
- }
- ret = vb2_streamon(&ctx->vq_src, type);
- }
- else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- ret = vb2_streamon(&ctx->vq_dst, type);
- mfc_debug_leave();
- return ret;
-}
-
-/* Stream off, which equals to a pause */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_streamoff(&ctx->vq_src, type);
- else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_streamoff(&ctx->vq_dst, type);
- return -EINVAL;
-}
-
-/* Set controls - v4l2 control framework */
-static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
- ctx->display_delay = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
- ctx->display_delay_enable = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
- ctx->loop_filter_mpeg4 = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
- ctx->slice_interface = ctrl->val;
- break;
- default:
- mfc_err("Invalid control 0x%08x\n", ctrl->id);
- return -EINVAL;
- }
- return 0;
-}
-
-static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- switch (ctrl->id) {
- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
- if (ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- ctrl->val = ctx->dpb_count;
- break;
- } else if (ctx->state != MFCINST_INIT) {
- v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
- return -EINVAL;
- }
- /* Should wait for the header to be parsed */
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0);
- if (ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- ctrl->val = ctx->dpb_count;
- } else {
- v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
- return -EINVAL;
- }
- break;
- }
- return 0;
-}
-
-
-static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
- .s_ctrl = s5p_mfc_dec_s_ctrl,
- .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
-};
-
-/* Get cropping information */
-static int vidioc_g_crop(struct file *file, void *priv,
- struct v4l2_crop *cr)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- u32 left, right, top, bottom;
-
- if (ctx->state != MFCINST_HEAD_PARSED &&
- ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
- && ctx->state != MFCINST_FINISHED) {
- mfc_err("Cannont set crop\n");
- return -EINVAL;
- }
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
- left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
- right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
- left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
- top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
- bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
- top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
- cr->c.left = left;
- cr->c.top = top;
- cr->c.width = ctx->img_width - left - right;
- cr->c.height = ctx->img_height - top - bottom;
- mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
- "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
- cr->c.width, cr->c.height, right, bottom,
- ctx->buf_width, ctx->buf_height);
- } else {
- cr->c.left = 0;
- cr->c.top = 0;
- cr->c.width = ctx->img_width;
- cr->c.height = ctx->img_height;
- mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
- "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width,
- ctx->buf_height);
- }
- return 0;
-}
-
-/* v4l2_ioctl_ops */
-static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
- .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
- .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
- .vidioc_s_fmt_vid_out_mplane = 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,
-};
-
-static int s5p_mfc_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt, unsigned int *buf_count,
- unsigned int *plane_count, unsigned int psize[],
- void *allocators[])
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
-
- /* Video output for decoding (source)
- * this can be set after getting an instance */
- if (ctx->state == MFCINST_INIT &&
- vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /* A single plane is required for input */
- *plane_count = 1;
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
- /* Video capture for decoding (destination)
- * this can be set after the header was parsed */
- } else if (ctx->state == MFCINST_HEAD_PARSED &&
- vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- /* Output plane count is 2 - one for Y and one for CbCr */
- *plane_count = 2;
- /* Setup buffer count */
- if (*buf_count < ctx->dpb_count)
- *buf_count = ctx->dpb_count;
- if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
- *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
- } else {
- mfc_err("State seems invalid. State = %d, vq->type = %d\n",
- ctx->state, vq->type);
- return -EINVAL;
- }
- mfc_debug(2, "Buffer count=%d, plane count=%d\n",
- *buf_count, *plane_count);
- if (ctx->state == MFCINST_HEAD_PARSED &&
- vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- psize[0] = ctx->luma_size;
- psize[1] = ctx->chroma_size;
- allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
- allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- ctx->state == MFCINST_INIT) {
- psize[0] = ctx->dec_src_buf_size;
- allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
- } else {
- mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static void s5p_mfc_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_lock(&dev->mfc_mutex);
-}
-
-static int s5p_mfc_buf_init(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
- unsigned int i;
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (ctx->capture_state == QUEUE_BUFS_MMAPED)
- return 0;
- for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
- if (IS_ERR_OR_NULL(ERR_PTR(
- vb2_dma_contig_plane_dma_addr(vb, i)))) {
- mfc_err("Plane mem not allocated\n");
- return -EINVAL;
- }
- }
- if (vb2_plane_size(vb, 0) < ctx->luma_size ||
- vb2_plane_size(vb, 1) < ctx->chroma_size) {
- mfc_err("Plane buffer (CAPTURE) is too small\n");
- return -EINVAL;
- }
- i = vb->v4l2_buf.index;
- ctx->dst_bufs[i].b = vb;
- ctx->dst_bufs[i].cookie.raw.luma =
- vb2_dma_contig_plane_dma_addr(vb, 0);
- ctx->dst_bufs[i].cookie.raw.chroma =
- vb2_dma_contig_plane_dma_addr(vb, 1);
- ctx->dst_bufs_cnt++;
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (IS_ERR_OR_NULL(ERR_PTR(
- vb2_dma_contig_plane_dma_addr(vb, 0)))) {
- mfc_err("Plane memory not allocated\n");
- return -EINVAL;
- }
- if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
- mfc_err("Plane buffer (OUTPUT) is too small\n");
- return -EINVAL;
- }
-
- i = vb->v4l2_buf.index;
- ctx->src_bufs[i].b = vb;
- ctx->src_bufs[i].cookie.stream =
- vb2_dma_contig_plane_dma_addr(vb, 0);
- ctx->src_bufs_cnt++;
- } else {
- mfc_err("s5p_mfc_buf_init: unknown queue type\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
-
- v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
- if (ctx->state == MFCINST_FINISHING ||
- ctx->state == MFCINST_FINISHED)
- ctx->state = MFCINST_RUNNING;
- /* If context is ready then dev = work->data;schedule it to run */
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
- return 0;
-}
-
-static int s5p_mfc_stop_streaming(struct vb2_queue *q)
-{
- unsigned long flags;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- int aborted = 0;
-
- if ((ctx->state == MFCINST_FINISHING ||
- ctx->state == MFCINST_RUNNING) &&
- dev->curr_ctx == ctx->num && dev->hw_lock) {
- ctx->state = MFCINST_ABORT;
- s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
- aborted = 1;
- }
- spin_lock_irqsave(&dev->irqlock, flags);
- if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
- INIT_LIST_HEAD(&ctx->dst_queue);
- ctx->dst_queue_cnt = 0;
- ctx->dpb_flush_flag = 1;
- ctx->dec_dst_flag = 0;
- }
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
- INIT_LIST_HEAD(&ctx->src_queue);
- ctx->src_queue_cnt = 0;
- }
- if (aborted)
- ctx->state = MFCINST_RUNNING;
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return 0;
-}
-
-
-static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf;
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
- mfc_buf->used = 0;
- spin_lock_irqsave(&dev->irqlock, flags);
- list_add_tail(&mfc_buf->list, &ctx->src_queue);
- ctx->src_queue_cnt++;
- spin_unlock_irqrestore(&dev->irqlock, flags);
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
- mfc_buf->used = 0;
- /* Mark destination as available for use by MFC */
- spin_lock_irqsave(&dev->irqlock, flags);
- set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag);
- list_add_tail(&mfc_buf->list, &ctx->dst_queue);
- ctx->dst_queue_cnt++;
- spin_unlock_irqrestore(&dev->irqlock, flags);
- } else {
- mfc_err("Unsupported buffer type (%d)\n", vq->type);
- }
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
-}
-
-static struct vb2_ops s5p_mfc_dec_qops = {
- .queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = s5p_mfc_unlock,
- .wait_finish = s5p_mfc_lock,
- .buf_init = s5p_mfc_buf_init,
- .start_streaming = s5p_mfc_start_streaming,
- .stop_streaming = s5p_mfc_stop_streaming,
- .buf_queue = s5p_mfc_buf_queue,
-};
-
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
-{
- return &decoder_codec_ops;
-}
-
-struct vb2_ops *get_dec_queue_ops(void)
-{
- return &s5p_mfc_dec_qops;
-}
-
-const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
-{
- return &s5p_mfc_dec_ioctl_ops;
-}
-
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
- && V4L2_CTRL_DRIVER_PRIV(x))
-
-int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
-{
- struct v4l2_ctrl_config cfg;
- int i;
-
- v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
- if (ctx->ctrl_handler.error) {
- mfc_err("v4l2_ctrl_handler_init failed\n");
- return ctx->ctrl_handler.error;
- }
-
- for (i = 0; i < NUM_CTRLS; i++) {
- if (IS_MFC51_PRIV(controls[i].id)) {
- memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
- cfg.ops = &s5p_mfc_dec_ctrl_ops;
- cfg.id = controls[i].id;
- cfg.min = controls[i].minimum;
- cfg.max = controls[i].maximum;
- cfg.def = controls[i].default_value;
- cfg.name = controls[i].name;
- cfg.type = controls[i].type;
-
- cfg.step = controls[i].step;
- cfg.menu_skip_mask = 0;
-
- ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
- &cfg, NULL);
- } else {
- ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
- &s5p_mfc_dec_ctrl_ops,
- controls[i].id, controls[i].minimum,
- controls[i].maximum, controls[i].step,
- controls[i].default_value);
- }
- if (ctx->ctrl_handler.error) {
- mfc_err("Adding control (%d) failed\n", i);
- return ctx->ctrl_handler.error;
- }
- if (controls[i].is_volatile && ctx->ctrls[i])
- ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
- }
- return 0;
-}
-
-void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
-{
- int i;
-
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- for (i = 0; i < NUM_CTRLS; i++)
- ctx->ctrls[i] = NULL;
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.h b/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
deleted file mode 100644
index fb8b215db0e7..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_DEC_H_
-#define S5P_MFC_DEC_H_
-
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
-struct vb2_ops *get_dec_queue_ops(void);
-const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
-struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
-int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx);
-
-#endif /* S5P_MFC_DEC_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
deleted file mode 100644
index aa1c244cf66e..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+++ /dev/null
@@ -1,1834 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * Jeongtae Park <jtp.park@samsung.com>
- * 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/clk.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/version.h>
-#include <linux/videodev2.h>
-#include <linux/workqueue.h>
-#include <media/v4l2-ctrls.h>
-#include <media/videobuf2-core.h>
-#include "regs-mfc.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_enc.h"
-#include "s5p_mfc_intr.h"
-#include "s5p_mfc_opr.h"
-
-static struct s5p_mfc_fmt formats[] = {
- {
- .name = "4:2:0 2 Planes 64x32 Tiles",
- .fourcc = V4L2_PIX_FMT_NV12MT,
- .codec_mode = S5P_FIMV_CODEC_NONE,
- .type = MFC_FMT_RAW,
- .num_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes",
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = S5P_FIMV_CODEC_NONE,
- .type = MFC_FMT_RAW,
- .num_planes = 2,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .codec_mode = S5P_FIMV_CODEC_H264_ENC,
- .type = MFC_FMT_ENC,
- .num_planes = 1,
- },
- {
- .name = "MPEG4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
- .type = MFC_FMT_ENC,
- .num_planes = 1,
- },
- {
- .name = "H263 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H263,
- .codec_mode = S5P_FIMV_CODEC_H263_ENC,
- .type = MFC_FMT_ENC,
- .num_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
-{
- unsigned int i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
- formats[i].type == t)
- return &formats[i];
- }
- return NULL;
-}
-
-static struct mfc_control controls[] = {
- {
- .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
- .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 1900,
- .maximum = (1 << 30) - 1,
- .step = 1,
- .default_value = 1900,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Padding Control Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Padding Color YUV Value",
- .minimum = 0,
- .maximum = (1 << 25) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BITRATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 1,
- .maximum = (1 << 30) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Rate Control Reaction Coeff.",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Force frame type",
- .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
- .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
- .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
- .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
- .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Frame Skip Enable",
- .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
- .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
- .menu_skip_mask = 0,
- .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Fixed Target Bit Enable",
- .minimum = 0,
- .maximum = 1,
- .default_value = 0,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 2,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
- .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
- .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
- .menu_skip_mask = ~(
- (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
- (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
- (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
- ),
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
- .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
- .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
- .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
- .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
- .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = -6,
- .maximum = 6,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = -6,
- .maximum = 6,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
- .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
- .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The Number of Ref. Pic for P",
- .minimum = 1,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 I-Frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Minimum QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Maximum QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 P frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 B frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 I-Frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Minimum QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Maximum QP value",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 P frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 B frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 Dark Reg Adaptive RC",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 Smooth Reg Adaptive RC",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 Static Reg Adaptive RC",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 Activity Reg Adaptive RC",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
- .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
- .default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
- .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
- .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
- .menu_skip_mask = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
-};
-
-#define NUM_CTRLS ARRAY_SIZE(controls)
-static const char * const *mfc51_get_menu(u32 id)
-{
- static const char * const mfc51_video_frame_skip[] = {
- "Disabled",
- "Level Limit",
- "VBV/CPB Limit",
- NULL,
- };
- static const char * const mfc51_video_force_frame[] = {
- "Disabled",
- "I Frame",
- "Not Coded",
- NULL,
- };
- switch (id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
- return mfc51_video_frame_skip;
- case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- return mfc51_video_force_frame;
- }
- return NULL;
-}
-
-static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug(2, "src=%d, dst=%d, state=%d\n",
- ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
- /* context is ready to make header */
- if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
- return 1;
- /* context is ready to encode a frame */
- if (ctx->state == MFCINST_RUNNING &&
- ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
- return 1;
- /* context is ready to encode remain frames */
- if (ctx->state == MFCINST_FINISHING &&
- ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
- return 1;
- mfc_debug(2, "ctx is not ready\n");
- return 0;
-}
-
-static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *mb_entry;
- unsigned long mb_y_addr, mb_c_addr;
-
- /* move buffers in ref queue to src queue */
- while (!list_empty(&ctx->ref_queue)) {
- mb_entry = list_entry((&ctx->ref_queue)->next,
- struct s5p_mfc_buf, list);
- mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
- mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
- list_del(&mb_entry->list);
- ctx->ref_queue_cnt--;
- list_add_tail(&mb_entry->list, &ctx->src_queue);
- ctx->src_queue_cnt++;
- }
- mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
- ctx->src_queue_cnt, ctx->ref_queue_cnt);
- INIT_LIST_HEAD(&ctx->ref_queue);
- ctx->ref_queue_cnt = 0;
-}
-
-static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *dst_mb;
- unsigned long dst_addr;
- unsigned int dst_size;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
- dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
- dst_size = vb2_plane_size(dst_mb->b, 0);
- s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return 0;
-}
-
-static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- struct s5p_mfc_buf *dst_mb;
- unsigned long flags;
-
- if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
- spin_lock_irqsave(&dev->irqlock, flags);
- dst_mb = list_entry(ctx->dst_queue.next,
- struct s5p_mfc_buf, list);
- list_del(&dst_mb->list);
- ctx->dst_queue_cnt--;
- vb2_set_plane_payload(dst_mb->b, 0,
- s5p_mfc_get_enc_strm_size());
- vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- }
- ctx->state = MFCINST_RUNNING;
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
- return 0;
-}
-
-static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *dst_mb;
- struct s5p_mfc_buf *src_mb;
- unsigned long flags;
- unsigned long src_y_addr, src_c_addr, dst_addr;
- unsigned int dst_size;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
- src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
- s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
- spin_unlock_irqrestore(&dev->irqlock, flags);
-
- spin_lock_irqsave(&dev->irqlock, flags);
- dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
- dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
- dst_size = vb2_plane_size(dst_mb->b, 0);
- s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
-
- return 0;
-}
-
-static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *mb_entry;
- unsigned long enc_y_addr, enc_c_addr;
- unsigned long mb_y_addr, mb_c_addr;
- int slice_type;
- unsigned int strm_size;
- unsigned long flags;
-
- slice_type = s5p_mfc_get_enc_slice_type();
- strm_size = s5p_mfc_get_enc_strm_size();
- mfc_debug(2, "Encoded slice type: %d", slice_type);
- mfc_debug(2, "Encoded stream size: %d", strm_size);
- mfc_debug(2, "Display order: %d",
- mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
- spin_lock_irqsave(&dev->irqlock, flags);
- if (slice_type >= 0) {
- s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
- list_for_each_entry(mb_entry, &ctx->src_queue, list) {
- mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
- mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
- if ((enc_y_addr == mb_y_addr) &&
- (enc_c_addr == mb_c_addr)) {
- list_del(&mb_entry->list);
- ctx->src_queue_cnt--;
- vb2_buffer_done(mb_entry->b,
- VB2_BUF_STATE_DONE);
- break;
- }
- }
- list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
- mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
- mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
- if ((enc_y_addr == mb_y_addr) &&
- (enc_c_addr == mb_c_addr)) {
- list_del(&mb_entry->list);
- ctx->ref_queue_cnt--;
- vb2_buffer_done(mb_entry->b,
- VB2_BUF_STATE_DONE);
- break;
- }
- }
- }
- if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
- mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
- list);
- if (mb_entry->used) {
- list_del(&mb_entry->list);
- ctx->src_queue_cnt--;
- list_add_tail(&mb_entry->list, &ctx->ref_queue);
- ctx->ref_queue_cnt++;
- }
- mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
- ctx->src_queue_cnt, ctx->ref_queue_cnt);
- }
- if (strm_size > 0) {
- /* at least one more dest. buffers exist always */
- mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
- list);
- list_del(&mb_entry->list);
- ctx->dst_queue_cnt--;
- switch (slice_type) {
- case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
- mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
- mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
- mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
- break;
- }
- vb2_set_plane_payload(mb_entry->b, 0, strm_size);
- vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE);
- }
- spin_unlock_irqrestore(&dev->irqlock, flags);
- if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
- spin_lock(&dev->condlock);
- clear_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock(&dev->condlock);
- }
- return 0;
-}
-
-static struct s5p_mfc_codec_ops encoder_codec_ops = {
- .pre_seq_start = enc_pre_seq_start,
- .post_seq_start = enc_post_seq_start,
- .pre_frame_start = enc_pre_frame_start,
- .post_frame_start = enc_post_frame_start,
-};
-
-/* Query capabilities of the device */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE;
- return 0;
-}
-
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
-{
- struct s5p_mfc_fmt *fmt;
- int i, j = 0;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- if (mplane && formats[i].num_planes == 1)
- continue;
- else if (!mplane && formats[i].num_planes > 1)
- continue;
- if (out && formats[i].type != MFC_FMT_RAW)
- continue;
- else if (!out && formats[i].type != MFC_FMT_ENC)
- continue;
- if (j == f->index) {
- fmt = &formats[i];
- strlcpy(f->description, fmt->name,
- sizeof(f->description));
- f->pixelformat = fmt->fourcc;
- return 0;
- }
- ++j;
- }
- return -EINVAL;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, false, false);
-}
-
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, false, true);
-}
-
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- return vidioc_enum_fmt(f, true, true);
-}
-
-static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- /* This is run on output (encoder dest) */
- pix_fmt_mp->width = 0;
- pix_fmt_mp->height = 0;
- pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
- pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
-
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
- pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /* This is run on capture (encoder src) */
- pix_fmt_mp->width = ctx->img_width;
- pix_fmt_mp->height = ctx->img_height;
-
- pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
- pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
-
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
- pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
- pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
- } else {
- mfc_err("invalid buf type\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_fmt *fmt;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- fmt = find_format(f, MFC_FMT_ENC);
- if (!fmt) {
- mfc_err("failed to try output format\n");
- return -EINVAL;
- }
-
- if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
- mfc_err("must be set encoding output size\n");
- return -EINVAL;
- }
-
- pix_fmt_mp->plane_fmt[0].bytesperline =
- pix_fmt_mp->plane_fmt[0].sizeimage;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- fmt = find_format(f, MFC_FMT_RAW);
- if (!fmt) {
- mfc_err("failed to try output format\n");
- return -EINVAL;
- }
-
- if (fmt->num_planes != pix_fmt_mp->num_planes) {
- mfc_err("failed to try output format\n");
- return -EINVAL;
- }
- v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
- &pix_fmt_mp->height, 4, 1080, 1, 0);
- } else {
- mfc_err("invalid buf type\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct s5p_mfc_fmt *fmt;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- unsigned long flags;
- int ret = 0;
-
- ret = vidioc_try_fmt(file, priv, f);
- if (ret)
- return ret;
- if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
- v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto out;
- }
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- fmt = find_format(f, MFC_FMT_ENC);
- if (!fmt) {
- mfc_err("failed to set capture format\n");
- return -EINVAL;
- }
- ctx->state = MFCINST_INIT;
- ctx->dst_fmt = fmt;
- ctx->codec_mode = ctx->dst_fmt->codec_mode;
- ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
- pix_fmt_mp->plane_fmt[0].bytesperline = 0;
- ctx->dst_bufs_cnt = 0;
- ctx->capture_state = QUEUE_FREE;
- s5p_mfc_alloc_instance_buffer(ctx);
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_try_run(dev);
- if (s5p_mfc_wait_for_done_ctx(ctx, \
- S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
- /* Error or timeout */
- mfc_err("Error getting instance from hardware\n");
- s5p_mfc_release_instance_buffer(ctx);
- ret = -EIO;
- goto out;
- }
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- fmt = find_format(f, MFC_FMT_RAW);
- if (!fmt) {
- mfc_err("failed to set output format\n");
- return -EINVAL;
- }
- if (fmt->num_planes != pix_fmt_mp->num_planes) {
- mfc_err("failed to set output format\n");
- ret = -EINVAL;
- goto out;
- }
- ctx->src_fmt = fmt;
- ctx->img_width = pix_fmt_mp->width;
- ctx->img_height = pix_fmt_mp->height;
- mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
- mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
- pix_fmt_mp->width, pix_fmt_mp->height,
- ctx->img_width, ctx->img_height);
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
- ctx->buf_width = ALIGN(ctx->img_width,
- S5P_FIMV_NV12M_HALIGN);
- ctx->luma_size = ALIGN(ctx->img_width,
- S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height,
- S5P_FIMV_NV12M_LVALIGN);
- ctx->chroma_size = ALIGN(ctx->img_width,
- S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height
- >> 1), S5P_FIMV_NV12M_CVALIGN);
-
- ctx->luma_size = ALIGN(ctx->luma_size,
- S5P_FIMV_NV12M_SALIGN);
- ctx->chroma_size = ALIGN(ctx->chroma_size,
- S5P_FIMV_NV12M_SALIGN);
-
- pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
- pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
- pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
-
- } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
- ctx->buf_width = ALIGN(ctx->img_width,
- S5P_FIMV_NV12MT_HALIGN);
- ctx->luma_size = ALIGN(ctx->img_width,
- S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height,
- S5P_FIMV_NV12MT_VALIGN);
- ctx->chroma_size = ALIGN(ctx->img_width,
- S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height
- >> 1), S5P_FIMV_NV12MT_VALIGN);
- ctx->luma_size = ALIGN(ctx->luma_size,
- S5P_FIMV_NV12MT_SALIGN);
- ctx->chroma_size = ALIGN(ctx->chroma_size,
- S5P_FIMV_NV12MT_SALIGN);
-
- pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
- pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
- pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
- }
- ctx->src_bufs_cnt = 0;
- ctx->output_state = QUEUE_FREE;
- } else {
- mfc_err("invalid buf type\n");
- return -EINVAL;
- }
-out:
- mfc_debug_leave();
- return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- int ret = 0;
-
- /* if memory is not mmp or userptr return error */
- if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
- (reqbufs->memory != V4L2_MEMORY_USERPTR))
- return -EINVAL;
- if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (ctx->capture_state != QUEUE_FREE) {
- mfc_err("invalid capture state: %d\n",
- ctx->capture_state);
- return -EINVAL;
- }
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- if (ret != 0) {
- mfc_err("error in vb2_reqbufs() for E(D)\n");
- return ret;
- }
- ctx->capture_state = QUEUE_BUFS_REQUESTED;
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err("Failed to allocate encoding buffers\n");
- reqbufs->count = 0;
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- return -ENOMEM;
- }
- } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (ctx->output_state != QUEUE_FREE) {
- mfc_err("invalid output state: %d\n",
- ctx->output_state);
- return -EINVAL;
- }
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- if (ret != 0) {
- mfc_err("error in vb2_reqbufs() for E(S)\n");
- return ret;
- }
- ctx->output_state = QUEUE_BUFS_REQUESTED;
- } else {
- mfc_err("invalid buf type\n");
- return -EINVAL;
- }
- return ret;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- int ret = 0;
-
- /* if memory is not mmp or userptr return error */
- if ((buf->memory != V4L2_MEMORY_MMAP) &&
- (buf->memory != V4L2_MEMORY_USERPTR))
- return -EINVAL;
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (ctx->state != MFCINST_GOT_INST) {
- mfc_err("invalid context state: %d\n", ctx->state);
- return -EINVAL;
- }
- ret = vb2_querybuf(&ctx->vq_dst, buf);
- if (ret != 0) {
- mfc_err("error in vb2_querybuf() for E(D)\n");
- return ret;
- }
- buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
- } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = vb2_querybuf(&ctx->vq_src, buf);
- if (ret != 0) {
- mfc_err("error in vb2_querybuf() for E(S)\n");
- return ret;
- }
- } else {
- mfc_err("invalid buf type\n");
- return -EINVAL;
- }
- return ret;
-}
-
-/* Queue a buffer */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err("Call on QBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_qbuf(&ctx->vq_src, buf);
- else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_qbuf(&ctx->vq_dst, buf);
- return -EINVAL;
-}
-
-/* Dequeue a buffer */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err("Call on DQBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
- else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
- return -EINVAL;
-}
-
-/* Stream on */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_streamon(&ctx->vq_src, type);
- else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_streamon(&ctx->vq_dst, type);
- return -EINVAL;
-}
-
-/* Stream off, which equals to a pause */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_streamoff(&ctx->vq_src, type);
- else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_streamoff(&ctx->vq_dst, type);
- return -EINVAL;
-}
-
-static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
- };
- return t[lvl];
-}
-
-static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
- };
- return t[lvl];
-}
-
-static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
- };
- return t[sar];
-}
-
-static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- p->gop_size = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
- p->slice_mode = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
- p->slice_mb = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
- p->slice_bit = ctrl->val * 8;
- break;
- case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
- p->intra_refresh_mb = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
- p->pad = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
- p->pad_luma = (ctrl->val >> 16) & 0xff;
- p->pad_cb = (ctrl->val >> 8) & 0xff;
- p->pad_cr = (ctrl->val >> 0) & 0xff;
- break;
- case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
- p->rc_frame = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- p->rc_bitrate = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
- p->rc_reaction_coeff = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- ctx->force_frame_type = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
- p->vbv_size = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
- p->codec.h264.cpb_size = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
- p->seq_hdr_mode = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
- p->frame_skip_mode = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
- p->fixed_target_bit = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- p->num_b_frame = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- switch (ctrl->val) {
- case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
- p->codec.h264.profile =
- S5P_FIMV_ENC_PROFILE_H264_MAIN;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
- p->codec.h264.profile =
- S5P_FIMV_ENC_PROFILE_H264_HIGH;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
- p->codec.h264.profile =
- S5P_FIMV_ENC_PROFILE_H264_BASELINE;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- p->codec.h264.level_v4l2 = ctrl->val;
- p->codec.h264.level = h264_level(ctrl->val);
- if (p->codec.h264.level < 0) {
- mfc_err("Level number is wrong\n");
- ret = p->codec.h264.level;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- p->codec.mpeg4.level_v4l2 = ctrl->val;
- p->codec.mpeg4.level = mpeg4_level(ctrl->val);
- if (p->codec.mpeg4.level < 0) {
- mfc_err("Level number is wrong\n");
- ret = p->codec.mpeg4.level;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- p->codec.h264.loop_filter_mode = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
- p->codec.h264.loop_filter_alpha = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
- p->codec.h264.loop_filter_beta = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
- p->codec.h264.entropy_mode = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
- p->codec.h264.num_ref_pic_4p = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
- p->codec.h264._8x8_transform = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
- p->codec.h264.rc_mb = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
- p->codec.h264.rc_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
- p->codec.h264.rc_min_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
- p->codec.h264.rc_max_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
- p->codec.h264.rc_p_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
- p->codec.h264.rc_b_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
- case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
- p->codec.mpeg4.rc_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
- p->codec.mpeg4.rc_min_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
- p->codec.mpeg4.rc_max_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
- case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
- p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
- case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
- p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
- p->codec.h264.rc_mb_dark = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
- p->codec.h264.rc_mb_smooth = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
- p->codec.h264.rc_mb_static = ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
- p->codec.h264.rc_mb_activity = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
- p->codec.h264.vui_sar = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
- p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
- p->codec.h264.vui_ext_sar_width = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
- p->codec.h264.vui_ext_sar_height = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- p->codec.h264.open_gop = !ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
- p->codec.h264.open_gop_size = ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
- switch (ctrl->val) {
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
- p->codec.mpeg4.profile =
- S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
- p->codec.mpeg4.profile =
- S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
- p->codec.mpeg4.quarter_pixel = ctrl->val;
- break;
- default:
- v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
- ctrl->id, ctrl->val);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
- .s_ctrl = s5p_mfc_enc_s_ctrl,
-};
-
-static int vidioc_s_parm(struct file *file, void *priv,
- struct v4l2_streamparm *a)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ctx->enc_params.rc_framerate_num =
- a->parm.output.timeperframe.denominator;
- ctx->enc_params.rc_framerate_denom =
- a->parm.output.timeperframe.numerator;
- } else {
- mfc_err("Setting FPS is only possible for the output queue\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
- struct v4l2_streamparm *a)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-
- if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- a->parm.output.timeperframe.denominator =
- ctx->enc_params.rc_framerate_num;
- a->parm.output.timeperframe.numerator =
- ctx->enc_params.rc_framerate_denom;
- } else {
- mfc_err("Setting FPS is only possible for the output queue\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
- .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
- .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
- .vidioc_s_fmt_vid_out_mplane = 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_s_parm = vidioc_s_parm,
- .vidioc_g_parm = vidioc_g_parm,
-};
-
-static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
-{
- int i;
-
- if (!fmt)
- return -EINVAL;
- if (fmt->num_planes != vb->num_planes) {
- mfc_err("invalid plane number for the format\n");
- return -EINVAL;
- }
- for (i = 0; i < fmt->num_planes; i++) {
- if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
- mfc_err("failed to get plane cookie\n");
- return -EINVAL;
- }
- mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
- vb->v4l2_buf.index, i,
- vb2_dma_contig_plane_dma_addr(vb, i));
- }
- return 0;
-}
-
-static int s5p_mfc_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *buf_count, unsigned int *plane_count,
- unsigned int psize[], void *allocators[])
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
-
- if (ctx->state != MFCINST_GOT_INST) {
- mfc_err("inavlid state: %d\n", ctx->state);
- return -EINVAL;
- }
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (ctx->dst_fmt)
- *plane_count = ctx->dst_fmt->num_planes;
- else
- *plane_count = MFC_ENC_CAP_PLANE_COUNT;
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
- psize[0] = ctx->enc_dst_buf_size;
- allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (ctx->src_fmt)
- *plane_count = ctx->src_fmt->num_planes;
- else
- *plane_count = MFC_ENC_OUT_PLANE_COUNT;
-
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
- psize[0] = ctx->luma_size;
- psize[1] = ctx->chroma_size;
- allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
- allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
- } else {
- mfc_err("inavlid queue type: %d\n", vq->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static void s5p_mfc_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_lock(&dev->mfc_mutex);
-}
-
-static int s5p_mfc_buf_init(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
- unsigned int i;
- int ret;
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ret = check_vb_with_fmt(ctx->dst_fmt, vb);
- if (ret < 0)
- return ret;
- i = vb->v4l2_buf.index;
- ctx->dst_bufs[i].b = vb;
- ctx->dst_bufs[i].cookie.stream =
- vb2_dma_contig_plane_dma_addr(vb, 0);
- ctx->dst_bufs_cnt++;
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = check_vb_with_fmt(ctx->src_fmt, vb);
- if (ret < 0)
- return ret;
- i = vb->v4l2_buf.index;
- ctx->src_bufs[i].b = vb;
- ctx->src_bufs[i].cookie.raw.luma =
- vb2_dma_contig_plane_dma_addr(vb, 0);
- ctx->src_bufs[i].cookie.raw.chroma =
- vb2_dma_contig_plane_dma_addr(vb, 1);
- ctx->src_bufs_cnt++;
- } else {
- mfc_err("inavlid queue type: %d\n", vq->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
- int ret;
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ret = check_vb_with_fmt(ctx->dst_fmt, vb);
- if (ret < 0)
- return ret;
- mfc_debug(2, "plane size: %ld, dst size: %d\n",
- vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
- if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
- mfc_err("plane size is too small for capture\n");
- return -EINVAL;
- }
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = check_vb_with_fmt(ctx->src_fmt, vb);
- if (ret < 0)
- return ret;
- mfc_debug(2, "plane size: %ld, luma size: %d\n",
- vb2_plane_size(vb, 0), ctx->luma_size);
- mfc_debug(2, "plane size: %ld, chroma size: %d\n",
- vb2_plane_size(vb, 1), ctx->chroma_size);
- if (vb2_plane_size(vb, 0) < ctx->luma_size ||
- vb2_plane_size(vb, 1) < ctx->chroma_size) {
- mfc_err("plane size is too small for output\n");
- return -EINVAL;
- }
- } else {
- mfc_err("inavlid queue type: %d\n", vq->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
-
- v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
- /* If context is ready then dev = work->data;schedule it to run */
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
- return 0;
-}
-
-static int s5p_mfc_stop_streaming(struct vb2_queue *q)
-{
- unsigned long flags;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- if ((ctx->state == MFCINST_FINISHING ||
- ctx->state == MFCINST_RUNNING) &&
- dev->curr_ctx == ctx->num && dev->hw_lock) {
- ctx->state = MFCINST_ABORT;
- s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET,
- 0);
- }
- ctx->state = MFCINST_FINISHED;
- spin_lock_irqsave(&dev->irqlock, flags);
- if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
- INIT_LIST_HEAD(&ctx->dst_queue);
- ctx->dst_queue_cnt = 0;
- }
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- cleanup_ref_queue(ctx);
- s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
- INIT_LIST_HEAD(&ctx->src_queue);
- ctx->src_queue_cnt = 0;
- }
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return 0;
-}
-
-static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf;
-
- if (ctx->state == MFCINST_ERROR) {
- vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
- cleanup_ref_queue(ctx);
- return;
- }
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
- mfc_buf->used = 0;
- /* Mark destination as available for use by MFC */
- spin_lock_irqsave(&dev->irqlock, flags);
- list_add_tail(&mfc_buf->list, &ctx->dst_queue);
- ctx->dst_queue_cnt++;
- spin_unlock_irqrestore(&dev->irqlock, flags);
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
- mfc_buf->used = 0;
- spin_lock_irqsave(&dev->irqlock, flags);
- if (vb->v4l2_planes[0].bytesused == 0) {
- mfc_debug(1, "change state to FINISHING\n");
- ctx->state = MFCINST_FINISHING;
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
- cleanup_ref_queue(ctx);
- } else {
- list_add_tail(&mfc_buf->list, &ctx->src_queue);
- ctx->src_queue_cnt++;
- }
- spin_unlock_irqrestore(&dev->irqlock, flags);
- } else {
- mfc_err("unsupported buffer type (%d)\n", vq->type);
- }
- if (s5p_mfc_ctx_ready(ctx)) {
- spin_lock_irqsave(&dev->condlock, flags);
- set_bit(ctx->num, &dev->ctx_work_bits);
- spin_unlock_irqrestore(&dev->condlock, flags);
- }
- s5p_mfc_try_run(dev);
-}
-
-static struct vb2_ops s5p_mfc_enc_qops = {
- .queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = s5p_mfc_unlock,
- .wait_finish = s5p_mfc_lock,
- .buf_init = s5p_mfc_buf_init,
- .buf_prepare = s5p_mfc_buf_prepare,
- .start_streaming = s5p_mfc_start_streaming,
- .stop_streaming = s5p_mfc_stop_streaming,
- .buf_queue = s5p_mfc_buf_queue,
-};
-
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
-{
- return &encoder_codec_ops;
-}
-
-struct vb2_ops *get_enc_queue_ops(void)
-{
- return &s5p_mfc_enc_qops;
-}
-
-const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
-{
- return &s5p_mfc_enc_ioctl_ops;
-}
-
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
- && V4L2_CTRL_DRIVER_PRIV(x))
-
-int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
-{
- struct v4l2_ctrl_config cfg;
- int i;
-
- v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
- if (ctx->ctrl_handler.error) {
- mfc_err("v4l2_ctrl_handler_init failed\n");
- return ctx->ctrl_handler.error;
- }
- for (i = 0; i < NUM_CTRLS; i++) {
- if (IS_MFC51_PRIV(controls[i].id)) {
- memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
- cfg.ops = &s5p_mfc_enc_ctrl_ops;
- cfg.id = controls[i].id;
- cfg.min = controls[i].minimum;
- cfg.max = controls[i].maximum;
- cfg.def = controls[i].default_value;
- cfg.name = controls[i].name;
- cfg.type = controls[i].type;
- cfg.flags = 0;
-
- if (cfg.type == V4L2_CTRL_TYPE_MENU) {
- cfg.step = 0;
- cfg.menu_skip_mask = cfg.menu_skip_mask;
- cfg.qmenu = mfc51_get_menu(cfg.id);
- } else {
- cfg.step = controls[i].step;
- cfg.menu_skip_mask = 0;
- }
- ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
- &cfg, NULL);
- } else {
- if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
- ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
- &ctx->ctrl_handler,
- &s5p_mfc_enc_ctrl_ops, controls[i].id,
- controls[i].maximum, 0,
- controls[i].default_value);
- } else {
- ctx->ctrls[i] = v4l2_ctrl_new_std(
- &ctx->ctrl_handler,
- &s5p_mfc_enc_ctrl_ops, controls[i].id,
- controls[i].minimum,
- controls[i].maximum, controls[i].step,
- controls[i].default_value);
- }
- }
- if (ctx->ctrl_handler.error) {
- mfc_err("Adding control (%d) failed\n", i);
- return ctx->ctrl_handler.error;
- }
- if (controls[i].is_volatile && ctx->ctrls[i])
- ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
- }
- return 0;
-}
-
-void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
-{
- int i;
-
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- for (i = 0; i < NUM_CTRLS; i++)
- ctx->ctrls[i] = NULL;
-}
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.h b/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
deleted file mode 100644
index 405bdd3ee083..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_ENC_H_
-#define S5P_MFC_ENC_H_
-
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
-struct vb2_ops *get_enc_queue_ops(void);
-const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
-struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
-int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx);
-
-#endif /* S5P_MFC_ENC_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.c b/drivers/media/video/s5p-mfc/s5p_mfc_intr.c
deleted file mode 100644
index 8f2f8bf4da7f..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_intr.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * drivers/media/video/samsung/mfc5/s5p_mfc_intr.c
- *
- * C file for Samsung MFC (Multi Function Codec - FIMV) driver
- * This file contains functions used to wait for command completion.
- *
- * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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/delay.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include "regs-mfc.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_intr.h"
-
-int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
-{
- int ret;
-
- ret = wait_event_interruptible_timeout(dev->queue,
- (dev->int_cond && (dev->int_type == command
- || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
- msecs_to_jiffies(MFC_INT_TIMEOUT));
- if (ret == 0) {
- mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n",
- dev->int_type, command);
- return 1;
- } else if (ret == -ERESTARTSYS) {
- mfc_err("Interrupted by a signal\n");
- return 1;
- }
- mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n",
- dev->int_type, command);
- if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
- return 1;
- return 0;
-}
-
-void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
-{
- dev->int_cond = 0;
- dev->int_type = 0;
- dev->int_err = 0;
-}
-
-int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
- int command, int interrupt)
-{
- int ret;
-
- if (interrupt) {
- ret = wait_event_interruptible_timeout(ctx->queue,
- (ctx->int_cond && (ctx->int_type == command
- || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
- msecs_to_jiffies(MFC_INT_TIMEOUT));
- } else {
- ret = wait_event_timeout(ctx->queue,
- (ctx->int_cond && (ctx->int_type == command
- || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
- msecs_to_jiffies(MFC_INT_TIMEOUT));
- }
- if (ret == 0) {
- mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
- ctx->int_type, command);
- return 1;
- } else if (ret == -ERESTARTSYS) {
- mfc_err("Interrupted by a signal\n");
- return 1;
- }
- mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
- ctx->int_type, command);
- if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
- return 1;
- return 0;
-}
-
-void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
-{
- ctx->int_cond = 0;
- ctx->int_type = 0;
- ctx->int_err = 0;
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.h b/drivers/media/video/s5p-mfc/s5p_mfc_intr.h
deleted file mode 100644
index 122d7732f745..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_intr.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * drivers/media/video/samsung/mfc5/s5p_mfc_intr.h
- *
- * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
- * It contains waiting functions declarations.
- *
- * Kamil Debski, Copyright (C) 2011 Samsung Electronics
- * http://www.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 S5P_MFC_INTR_H_
-#define S5P_MFC_INTR_H_
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
- int command, int interrupt);
-int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
-void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
-
-#endif /* S5P_MFC_INTR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
deleted file mode 100644
index e6217cbfa4a3..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-/*
- * drivers/media/video/samsung/mfc5/s5p_mfc_opr.c
- *
- * Samsung MFC (Multi Function Codec - FIMV) driver
- * This file contains hw related functions.
- *
- * Kamil Debski, Copyright (c) 2011 Samsung Electronics
- * http://www.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 "regs-mfc.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_ctrl.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_intr.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_shm.h"
-#include <asm/cacheflush.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/firmware.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-
-#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT)
-#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
-
-/* Allocate temporary buffers for decoding */
-int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
-{
- void *desc_virt;
- struct s5p_mfc_dev *dev = ctx->dev;
-
- ctx->desc_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
- if (IS_ERR_VALUE((int)ctx->desc_buf)) {
- ctx->desc_buf = NULL;
- mfc_err("Allocating DESC buffer failed\n");
- return -ENOMEM;
- }
- ctx->desc_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf);
- BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf);
- if (desc_virt == NULL) {
- vb2_dma_contig_memops.put(ctx->desc_buf);
- ctx->desc_phys = 0;
- ctx->desc_buf = NULL;
- mfc_err("Remapping DESC buffer failed\n");
- return -ENOMEM;
- }
- memset(desc_virt, 0, DESC_BUF_SIZE);
- wmb();
- return 0;
-}
-
-/* Release temporary buffers for decoding */
-void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->desc_phys) {
- vb2_dma_contig_memops.put(ctx->desc_buf);
- ctx->desc_phys = 0;
- ctx->desc_buf = NULL;
- }
-}
-
-/* Allocate codec buffers */
-int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int enc_ref_y_size = 0;
- unsigned int enc_ref_c_size = 0;
- unsigned int guard_width, guard_height;
-
- if (ctx->type == MFCINST_DECODER) {
- mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
- ctx->luma_size, ctx->chroma_size, ctx->mv_size);
- mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
- } else if (ctx->type == MFCINST_ENCODER) {
- enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
- * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
- enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
-
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
- enc_ref_c_size = ALIGN(ctx->img_width,
- S5P_FIMV_NV12MT_HALIGN)
- * ALIGN(ctx->img_height >> 1,
- S5P_FIMV_NV12MT_VALIGN);
- enc_ref_c_size = ALIGN(enc_ref_c_size,
- S5P_FIMV_NV12MT_SALIGN);
- } else {
- guard_width = ALIGN(ctx->img_width + 16,
- S5P_FIMV_NV12MT_HALIGN);
- guard_height = ALIGN((ctx->img_height >> 1) + 4,
- S5P_FIMV_NV12MT_VALIGN);
- enc_ref_c_size = ALIGN(guard_width * guard_height,
- S5P_FIMV_NV12MT_SALIGN);
- }
- mfc_debug(2, "recon luma size: %d chroma size: %d\n",
- enc_ref_y_size, enc_ref_c_size);
- } else {
- return -EINVAL;
- }
- /* Codecs have different memory requirements */
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- ctx->bank1_size =
- ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
- S5P_FIMV_DEC_VERT_NB_MV_SIZE,
- S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
- break;
- case S5P_FIMV_CODEC_MPEG4_DEC:
- ctx->bank1_size =
- ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
- S5P_FIMV_DEC_UPNB_MV_SIZE +
- S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
- S5P_FIMV_DEC_STX_PARSER_SIZE +
- S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
- S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
- break;
- case S5P_FIMV_CODEC_VC1RCV_DEC:
- case S5P_FIMV_CODEC_VC1_DEC:
- ctx->bank1_size =
- ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
- S5P_FIMV_DEC_UPNB_MV_SIZE +
- S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
- S5P_FIMV_DEC_NB_DCAC_SIZE +
- 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
- S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
- break;
- case S5P_FIMV_CODEC_MPEG2_DEC:
- ctx->bank1_size = 0;
- ctx->bank2_size = 0;
- break;
- case S5P_FIMV_CODEC_H263_DEC:
- ctx->bank1_size =
- ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
- S5P_FIMV_DEC_UPNB_MV_SIZE +
- S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
- S5P_FIMV_DEC_NB_DCAC_SIZE,
- S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
- break;
- case S5P_FIMV_CODEC_H264_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
- S5P_FIMV_ENC_UPMV_SIZE +
- S5P_FIMV_ENC_COLFLG_SIZE +
- S5P_FIMV_ENC_INTRAMD_SIZE +
- S5P_FIMV_ENC_NBORINFO_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
- (enc_ref_c_size * 4) +
- S5P_FIMV_ENC_INTRAPRED_SIZE;
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
- S5P_FIMV_ENC_UPMV_SIZE +
- S5P_FIMV_ENC_COLFLG_SIZE +
- S5P_FIMV_ENC_ACDCCOEF_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
- (enc_ref_c_size * 4);
- break;
- case S5P_FIMV_CODEC_H263_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
- S5P_FIMV_ENC_UPMV_SIZE +
- S5P_FIMV_ENC_ACDCCOEF_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
- (enc_ref_c_size * 4);
- break;
- default:
- break;
- }
- /* Allocate only if memory from bank 1 is necessary */
- if (ctx->bank1_size > 0) {
- ctx->bank1_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
- if (IS_ERR(ctx->bank1_buf)) {
- ctx->bank1_buf = NULL;
- printk(KERN_ERR
- "Buf alloc for decoding failed (port A)\n");
- return -ENOMEM;
- }
- ctx->bank1_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
- BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- }
- /* Allocate only if memory from bank 2 is necessary */
- if (ctx->bank2_size > 0) {
- ctx->bank2_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
- if (IS_ERR(ctx->bank2_buf)) {
- ctx->bank2_buf = NULL;
- mfc_err("Buf alloc for decoding failed (port B)\n");
- return -ENOMEM;
- }
- ctx->bank2_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
- BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
- }
- return 0;
-}
-
-/* Release buffers allocated for codec */
-void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->bank1_buf) {
- vb2_dma_contig_memops.put(ctx->bank1_buf);
- ctx->bank1_buf = NULL;
- ctx->bank1_phys = 0;
- ctx->bank1_size = 0;
- }
- if (ctx->bank2_buf) {
- vb2_dma_contig_memops.put(ctx->bank2_buf);
- ctx->bank2_buf = NULL;
- ctx->bank2_phys = 0;
- ctx->bank2_size = 0;
- }
-}
-
-/* Allocate memory for instance data buffer */
-int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
-{
- void *context_virt;
- struct s5p_mfc_dev *dev = ctx->dev;
-
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
- ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
- ctx->ctx_size = MFC_H264_CTX_BUF_SIZE;
- else
- ctx->ctx_size = MFC_CTX_BUF_SIZE;
- ctx->ctx_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size);
- if (IS_ERR(ctx->ctx_buf)) {
- mfc_err("Allocating context buffer failed\n");
- ctx->ctx_phys = 0;
- ctx->ctx_buf = NULL;
- return -ENOMEM;
- }
- ctx->ctx_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf);
- BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- ctx->ctx_ofs = OFFSETA(ctx->ctx_phys);
- context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf);
- if (context_virt == NULL) {
- mfc_err("Remapping instance buffer failed\n");
- vb2_dma_contig_memops.put(ctx->ctx_buf);
- ctx->ctx_phys = 0;
- ctx->ctx_buf = NULL;
- return -ENOMEM;
- }
- /* Zero content of the allocated memory */
- memset(context_virt, 0, ctx->ctx_size);
- wmb();
- if (s5p_mfc_init_shm(ctx) < 0) {
- vb2_dma_contig_memops.put(ctx->ctx_buf);
- ctx->ctx_phys = 0;
- ctx->ctx_buf = NULL;
- return -ENOMEM;
- }
- return 0;
-}
-
-/* Release instance buffer */
-void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->ctx_buf) {
- vb2_dma_contig_memops.put(ctx->ctx_buf);
- ctx->ctx_phys = 0;
- ctx->ctx_buf = NULL;
- }
- if (ctx->shm_alloc) {
- vb2_dma_contig_memops.put(ctx->shm_alloc);
- ctx->shm_alloc = NULL;
- ctx->shm = NULL;
- }
-}
-
-/* Set registers for decoding temporary buffers */
-void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR);
- mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE);
-}
-
-/* Set registers for shared buffer */
-static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
-}
-
-/* Set registers for decoding stream buffer */
-int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
- unsigned int start_num_byte, unsigned int buf_size)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
- mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE);
- mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
- s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM);
- return 0;
-}
-
-/* Set decoding frame buffer */
-int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
-{
- unsigned int frame_size, i;
- unsigned int frame_size_ch, frame_size_mv;
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int dpb;
- size_t buf_addr1, buf_addr2;
- int buf_size1, buf_size2;
-
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
- buf_addr2 = ctx->bank2_phys;
- buf_size2 = ctx->bank2_size;
- dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
- ~S5P_FIMV_DPB_COUNT_MASK;
- mfc_write(dev, ctx->total_dpb_count | dpb,
- S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
- s5p_mfc_set_shared_buffer(ctx);
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_H264_VERT_NB_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
- buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
- buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
- break;
- case S5P_FIMV_CODEC_MPEG4_DEC:
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
- buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
- buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
- buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
- buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
- buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- break;
- case S5P_FIMV_CODEC_H263_DEC:
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
- buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
- buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
- buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
- break;
- case S5P_FIMV_CODEC_VC1_DEC:
- case S5P_FIMV_CODEC_VC1RCV_DEC:
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
- buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
- buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
- buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
- buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
- buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
- buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
- buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
- break;
- case S5P_FIMV_CODEC_MPEG2_DEC:
- break;
- default:
- mfc_err("Unknown codec for decoding (%x)\n",
- ctx->codec_mode);
- return -EINVAL;
- break;
- }
- frame_size = ctx->luma_size;
- frame_size_ch = ctx->chroma_size;
- frame_size_mv = ctx->mv_size;
- mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
- frame_size_mv);
- for (i = 0; i < ctx->total_dpb_count; i++) {
- /* Bank2 */
- mfc_debug(2, "Luma %d: %x\n", i,
- ctx->dst_bufs[i].cookie.raw.luma);
- mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
- S5P_FIMV_DEC_LUMA_ADR + i * 4);
- mfc_debug(2, "\tChroma %d: %x\n", i,
- ctx->dst_bufs[i].cookie.raw.chroma);
- mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
- S5P_FIMV_DEC_CHROMA_ADR + i * 4);
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
- mfc_debug(2, "\tBuf2: %x, size: %d\n",
- buf_addr2, buf_size2);
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_H264_MV_ADR + i * 4);
- buf_addr2 += frame_size_mv;
- buf_size2 -= frame_size_mv;
- }
- }
- mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
- mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
- buf_size1, buf_size2, ctx->total_dpb_count);
- if (buf_size1 < 0 || buf_size2 < 0) {
- mfc_debug(2, "Not enough memory has been allocated\n");
- return -ENOMEM;
- }
- s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
- s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
- s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE);
- mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK)
- << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
- S5P_FIMV_SI_CH0_INST_ID);
- return 0;
-}
-
-/* Set registers for encoding stream buffer */
-int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long addr, unsigned int size)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
- mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
- return 0;
-}
-
-void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long y_addr, unsigned long c_addr)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
- mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
-}
-
-void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long *y_addr, unsigned long *c_addr)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR)
- << MFC_OFFSET_SHIFT);
- *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR)
- << MFC_OFFSET_SHIFT);
-}
-
-/* Set encoding ref & codec buffer */
-int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- size_t buf_addr1, buf_addr2;
- size_t buf_size1, buf_size2;
- unsigned int enc_ref_y_size, enc_ref_c_size;
- unsigned int guard_width, guard_height;
- int i;
-
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
- buf_addr2 = ctx->bank2_phys;
- buf_size2 = ctx->bank2_size;
- enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
- * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
- enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
- enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
- * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
- enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
- } else {
- guard_width = ALIGN(ctx->img_width + 16,
- S5P_FIMV_NV12MT_HALIGN);
- guard_height = ALIGN((ctx->img_height >> 1) + 4,
- S5P_FIMV_NV12MT_VALIGN);
- enc_ref_c_size = ALIGN(guard_width * guard_height,
- S5P_FIMV_NV12MT_SALIGN);
- }
- mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_ENC:
- for (i = 0; i < 2; i++) {
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
- buf_addr1 += enc_ref_y_size;
- buf_size1 -= enc_ref_y_size;
-
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
- buf_addr2 += enc_ref_y_size;
- buf_size2 -= enc_ref_y_size;
- }
- for (i = 0; i < 4; i++) {
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
- buf_addr2 += enc_ref_c_size;
- buf_size2 -= enc_ref_c_size;
- }
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
- buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
- buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_H264_COZERO_FLAG_ADR);
- buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
- buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_H264_UP_INTRA_MD_ADR);
- buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
- buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_H264_UP_INTRA_PRED_ADR);
- buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
- buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_H264_NBOR_INFO_ADR);
- buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
- buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
- mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
- buf_size1, buf_size2);
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- for (i = 0; i < 2; i++) {
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
- buf_addr1 += enc_ref_y_size;
- buf_size1 -= enc_ref_y_size;
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
- buf_addr2 += enc_ref_y_size;
- buf_size2 -= enc_ref_y_size;
- }
- for (i = 0; i < 4; i++) {
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
- buf_addr2 += enc_ref_c_size;
- buf_size2 -= enc_ref_c_size;
- }
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
- buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
- buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
- buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
- buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_MPEG4_ACDC_COEF_ADR);
- buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
- buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
- mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
- buf_size1, buf_size2);
- break;
- case S5P_FIMV_CODEC_H263_ENC:
- for (i = 0; i < 2; i++) {
- mfc_write(dev, OFFSETA(buf_addr1),
- S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
- buf_addr1 += enc_ref_y_size;
- buf_size1 -= enc_ref_y_size;
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
- buf_addr2 += enc_ref_y_size;
- buf_size2 -= enc_ref_y_size;
- }
- for (i = 0; i < 4; i++) {
- mfc_write(dev, OFFSETB(buf_addr2),
- S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
- buf_addr2 += enc_ref_c_size;
- buf_size2 -= enc_ref_c_size;
- }
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
- buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
- buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
- mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
- buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
- buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
- mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
- buf_size1, buf_size2);
- break;
- default:
- mfc_err("Unknown codec set for encoding: %d\n",
- ctx->codec_mode);
- return -EINVAL;
- }
- return 0;
-}
-
-static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- unsigned int reg;
- unsigned int shm;
-
- /* width */
- mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
- /* height */
- mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
- /* pictype : enable, IDR period */
- reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- reg |= (1 << 18);
- reg &= ~(0xFFFF);
- reg |= p->gop_size;
- mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
- /* multi-slice control */
- /* multi-slice MB number or bit size */
- mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
- if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
- mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
- } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
- mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
- } else {
- mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
- mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT);
- }
- /* cyclic intra refresh */
- mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
- /* memory structure cur. frame */
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
- mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
- else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
- mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
- /* padding control & value */
- reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
- if (p->pad) {
- /** enable */
- reg |= (1 << 31);
- /** cr value */
- reg &= ~(0xFF << 16);
- reg |= (p->pad_cr << 16);
- /** cb value */
- reg &= ~(0xFF << 8);
- reg |= (p->pad_cb << 8);
- /** y value */
- reg &= ~(0xFF);
- reg |= (p->pad_luma);
- } else {
- /** disable & all value clear */
- reg = 0;
- }
- mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL);
- /* rate control config. */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
- /** frame-level rate control */
- reg &= ~(0x1 << 9);
- reg |= (p->rc_frame << 9);
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
- /* bit rate */
- if (p->rc_frame)
- mfc_write(dev, p->rc_bitrate,
- S5P_FIMV_ENC_RC_BIT_RATE);
- else
- mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
- /* reaction coefficient */
- if (p->rc_frame)
- mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
- shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
- /* seq header ctrl */
- shm &= ~(0x1 << 3);
- shm |= (p->seq_hdr_mode << 3);
- /* frame skip mode */
- shm &= ~(0x3 << 1);
- shm |= (p->frame_skip_mode << 1);
- s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
- /* fixed target bit */
- s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
- return 0;
-}
-
-static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
- unsigned int reg;
- unsigned int shm;
-
- s5p_mfc_set_enc_params(ctx);
- /* pictype : number of B */
- reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- /* num_b_frame - 0 ~ 2 */
- reg &= ~(0x3 << 16);
- reg |= (p->num_b_frame << 16);
- mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- /* profile & level */
- reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
- /* level */
- reg &= ~(0xFF << 8);
- reg |= (p_264->level << 8);
- /* profile - 0 ~ 2 */
- reg &= ~(0x3F);
- reg |= p_264->profile;
- mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
- /* interlace */
- mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT);
- /* height */
- if (p->interlace)
- mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
- /* loopfilter ctrl */
- mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
- /* loopfilter alpha offset */
- if (p_264->loop_filter_alpha < 0) {
- reg = 0x10;
- reg |= (0xFF - p_264->loop_filter_alpha) + 1;
- } else {
- reg = 0x00;
- reg |= (p_264->loop_filter_alpha & 0xF);
- }
- mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF);
- /* loopfilter beta offset */
- if (p_264->loop_filter_beta < 0) {
- reg = 0x10;
- reg |= (0xFF - p_264->loop_filter_beta) + 1;
- } else {
- reg = 0x00;
- reg |= (p_264->loop_filter_beta & 0xF);
- }
- mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF);
- /* entropy coding mode */
- if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
- mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE);
- else
- mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE);
- /* number of ref. picture */
- reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF);
- /* num of ref. pictures of P */
- reg &= ~(0x3 << 5);
- reg |= (p_264->num_ref_pic_4p << 5);
- /* max number of ref. pictures */
- reg &= ~(0x1F);
- reg |= p_264->max_ref_pic;
- mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
- /* 8x8 transform enable */
- mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
- /* rate control config. */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
- /* macroblock level rate control */
- reg &= ~(0x1 << 8);
- reg |= (p_264->rc_mb << 8);
- /* frame QP */
- reg &= ~(0x3F);
- reg |= p_264->rc_frame_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_denom)
- mfc_write(dev, p->rc_framerate_num * 1000
- / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
- else
- mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
- /* max & min value of QP */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
- /* max QP */
- reg &= ~(0x3F << 8);
- reg |= (p_264->rc_max_qp << 8);
- /* min QP */
- reg &= ~(0x3F);
- reg |= p_264->rc_min_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
- /* macroblock adaptive scaling features */
- if (p_264->rc_mb) {
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL);
- /* dark region */
- reg &= ~(0x1 << 3);
- reg |= (p_264->rc_mb_dark << 3);
- /* smooth region */
- reg &= ~(0x1 << 2);
- reg |= (p_264->rc_mb_smooth << 2);
- /* static region */
- reg &= ~(0x1 << 1);
- reg |= (p_264->rc_mb_static << 1);
- /* high activity region */
- reg &= ~(0x1);
- reg |= p_264->rc_mb_activity;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL);
- }
- if (!p->rc_frame &&
- !p_264->rc_mb) {
- shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
- shm &= ~(0xFFF);
- shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
- shm |= (p_264->rc_p_frame_qp & 0x3F);
- s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
- }
- /* extended encoder ctrl */
- shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
- /* AR VUI control */
- shm &= ~(0x1 << 15);
- shm |= (p_264->vui_sar << 1);
- s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
- if (p_264->vui_sar) {
- /* aspect ration IDC */
- shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC);
- shm &= ~(0xFF);
- shm |= p_264->vui_sar_idc;
- s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC);
- if (p_264->vui_sar_idc == 0xFF) {
- /* sample AR info */
- shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR);
- shm &= ~(0xFFFFFFFF);
- shm |= p_264->vui_ext_sar_width << 16;
- shm |= p_264->vui_ext_sar_height;
- s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR);
- }
- }
- /* intra picture period for H.264 */
- shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD);
- /* control */
- shm &= ~(0x1 << 16);
- shm |= (p_264->open_gop << 16);
- /* value */
- if (p_264->open_gop) {
- shm &= ~(0xFFFF);
- shm |= p_264->open_gop_size;
- }
- s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD);
- /* extended encoder ctrl */
- shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
- /* vbv buffer size */
- if (p->frame_skip_mode ==
- V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- shm &= ~(0xFFFF << 16);
- shm |= (p_264->cpb_size << 16);
- }
- s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
- return 0;
-}
-
-static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
- unsigned int reg;
- unsigned int shm;
- unsigned int framerate;
-
- s5p_mfc_set_enc_params(ctx);
- /* pictype : number of B */
- reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- /* num_b_frame - 0 ~ 2 */
- reg &= ~(0x3 << 16);
- reg |= (p->num_b_frame << 16);
- mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
- /* profile & level */
- reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
- /* level */
- reg &= ~(0xFF << 8);
- reg |= (p_mpeg4->level << 8);
- /* profile - 0 ~ 2 */
- reg &= ~(0x3F);
- reg |= p_mpeg4->profile;
- mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
- /* quarter_pixel */
- mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
- /* qp */
- if (!p->rc_frame) {
- shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
- shm &= ~(0xFFF);
- shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
- shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
- s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
- }
- /* frame rate */
- if (p->rc_frame) {
- if (p->rc_framerate_denom > 0) {
- framerate = p->rc_framerate_num * 1000 /
- p->rc_framerate_denom;
- mfc_write(dev, framerate,
- S5P_FIMV_ENC_RC_FRAME_RATE);
- shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING);
- shm &= ~(0xFFFFFFFF);
- shm |= (1 << 31);
- shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
- shm |= (p->rc_framerate_denom & 0xFFFF);
- s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING);
- }
- } else {
- mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
- }
- /* rate control config. */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
- /* frame QP */
- reg &= ~(0x3F);
- reg |= p_mpeg4->rc_frame_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
- /* max & min value of QP */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
- /* max QP */
- reg &= ~(0x3F << 8);
- reg |= (p_mpeg4->rc_max_qp << 8);
- /* min QP */
- reg &= ~(0x3F);
- reg |= p_mpeg4->rc_min_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
- /* extended encoder ctrl */
- shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
- /* vbv buffer size */
- if (p->frame_skip_mode ==
- V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- shm &= ~(0xFFFF << 16);
- shm |= (p->vbv_size << 16);
- }
- s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
- return 0;
-}
-
-static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &ctx->enc_params;
- struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
- unsigned int reg;
- unsigned int shm;
-
- s5p_mfc_set_enc_params(ctx);
- /* qp */
- if (!p->rc_frame) {
- shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
- shm &= ~(0xFFF);
- shm |= (p_h263->rc_p_frame_qp & 0x3F);
- s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
- }
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_denom)
- mfc_write(dev, p->rc_framerate_num * 1000
- / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
- else
- mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
- /* rate control config. */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
- /* frame QP */
- reg &= ~(0x3F);
- reg |= p_h263->rc_frame_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
- /* max & min value of QP */
- reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
- /* max QP */
- reg &= ~(0x3F << 8);
- reg |= (p_h263->rc_max_qp << 8);
- /* min QP */
- reg &= ~(0x3F);
- reg |= p_h263->rc_min_qp;
- mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
- /* extended encoder ctrl */
- shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
- /* vbv buffer size */
- if (p->frame_skip_mode ==
- V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- shm &= ~(0xFFFF << 16);
- shm |= (p->vbv_size << 16);
- }
- s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
- return 0;
-}
-
-/* Initialize decoding */
-int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- s5p_mfc_set_shared_buffer(ctx);
- /* Setup loop filter, for decoding this is only valid for MPEG4 */
- if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
- mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
- else
- mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL);
- mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) <<
- S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable <<
- S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay &
- S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
- S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
- mfc_write(dev,
- ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
- | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
- return 0;
-}
-
-static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int dpb;
-
- if (flush)
- dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (
- S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
- else
- dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
- ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
- mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
-}
-
-/* Decode a single frame */
-int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_decode_arg last_frame)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF);
- s5p_mfc_set_shared_buffer(ctx);
- s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
- /* Issue different commands to instance basing on whether it
- * is the last frame or not. */
- switch (last_frame) {
- case MFC_DEC_FRAME:
- mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
- S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
- break;
- case MFC_DEC_LAST_FRAME:
- mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
- S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
- break;
- case MFC_DEC_RES_CHANGE:
- mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC &
- S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
- S5P_FIMV_SI_CH0_INST_ID);
- break;
- }
- mfc_debug(2, "Decoding a usual frame\n");
- return 0;
-}
-
-int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
- s5p_mfc_set_enc_params_h264(ctx);
- else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
- s5p_mfc_set_enc_params_mpeg4(ctx);
- else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
- s5p_mfc_set_enc_params_h263(ctx);
- else {
- mfc_err("Unknown codec for encoding (%x)\n",
- ctx->codec_mode);
- return -EINVAL;
- }
- s5p_mfc_set_shared_buffer(ctx);
- mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) |
- (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
- return 0;
-}
-
-/* Encode a single frame */
-int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- /* memory structure cur. frame */
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
- mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
- else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
- mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
- s5p_mfc_set_shared_buffer(ctx);
- mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) |
- (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
- return 0;
-}
-
-static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
- unsigned long flags;
- int new_ctx;
- int cnt;
-
- spin_lock_irqsave(&dev->condlock, flags);
- new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
- cnt = 0;
- while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
- new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
- if (++cnt > MFC_NUM_CONTEXTS) {
- /* No contexts to run */
- spin_unlock_irqrestore(&dev->condlock, flags);
- return -EAGAIN;
- }
- }
- spin_unlock_irqrestore(&dev->condlock, flags);
- return new_ctx;
-}
-
-static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE);
-}
-
-static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *temp_vb;
- unsigned long flags;
- unsigned int index;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- /* Frames are being decoded */
- if (list_empty(&ctx->src_queue)) {
- mfc_debug(2, "No src buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return -EAGAIN;
- }
- /* Get the next source buffer */
- temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- temp_vb->used = 1;
- s5p_mfc_set_dec_stream_buffer(ctx,
- vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream,
- temp_vb->b->v4l2_planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- index = temp_vb->b->v4l2_buf.index;
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
- last_frame = MFC_DEC_LAST_FRAME;
- mfc_debug(2, "Setting ctx->state to FINISHING\n");
- ctx->state = MFCINST_FINISHING;
- }
- s5p_mfc_decode_one_frame(ctx, last_frame);
- return 0;
-}
-
-static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *dst_mb;
- struct s5p_mfc_buf *src_mb;
- unsigned long src_y_addr, src_c_addr, dst_addr;
- unsigned int dst_size;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- if (list_empty(&ctx->src_queue)) {
- mfc_debug(2, "no src buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return -EAGAIN;
- }
- if (list_empty(&ctx->dst_queue)) {
- mfc_debug(2, "no dst buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return -EAGAIN;
- }
- src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- src_mb->used = 1;
- src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
- src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
- s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
- dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
- dst_mb->used = 1;
- dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
- dst_size = vb2_plane_size(dst_mb->b, 0);
- s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_encode_one_frame(ctx);
- return 0;
-}
-
-static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *temp_vb;
-
- /* Initializing decoding - parsing header */
- spin_lock_irqsave(&dev->irqlock, flags);
- mfc_debug(2, "Preparing to init decoding\n");
- temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- s5p_mfc_set_dec_desc_buffer(ctx);
- mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
- s5p_mfc_set_dec_stream_buffer(ctx,
- vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
- 0, temp_vb->b->v4l2_planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_init_decode(ctx);
-}
-
-static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *dst_mb;
- unsigned long dst_addr;
- unsigned int dst_size;
-
- s5p_mfc_set_enc_ref_buffer(ctx);
- spin_lock_irqsave(&dev->irqlock, flags);
- dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
- dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
- dst_size = vb2_plane_size(dst_mb->b, 0);
- s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_init_encode(ctx);
-}
-
-static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
- struct s5p_mfc_buf *temp_vb;
- int ret;
-
- /*
- * Header was parsed now starting processing
- * First set the output frame buffers
- */
- if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
- mfc_err("It seems that not all destionation buffers were "
- "mmaped\nMFC requires that all destination are mmaped "
- "before starting processing\n");
- return -EAGAIN;
- }
- spin_lock_irqsave(&dev->irqlock, flags);
- if (list_empty(&ctx->src_queue)) {
- mfc_err("Header has been deallocated in the middle of"
- " initialization\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return -EIO;
- }
- temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
- s5p_mfc_set_dec_stream_buffer(ctx,
- vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
- 0, temp_vb->b->v4l2_planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_set_dec_frame_buffer(ctx);
- if (ret) {
- mfc_err("Failed to alloc frame mem\n");
- ctx->state = MFCINST_ERROR;
- }
- return ret;
-}
-
-/* Try running an operation on hardware */
-void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx *ctx;
- int new_ctx;
- unsigned int ret = 0;
-
- if (test_bit(0, &dev->enter_suspend)) {
- mfc_debug(1, "Entering suspend so do not schedule any jobs\n");
- return;
- }
- /* Check whether hardware is not running */
- if (test_and_set_bit(0, &dev->hw_lock) != 0) {
- /* This is perfectly ok, the scheduled ctx should wait */
- mfc_debug(1, "Couldn't lock HW\n");
- return;
- }
- /* Choose the context to run */
- new_ctx = s5p_mfc_get_new_ctx(dev);
- if (new_ctx < 0) {
- /* No contexts to run */
- if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
- mfc_err("Failed to unlock hardware\n");
- return;
- }
- mfc_debug(1, "No ctx is scheduled to be run\n");
- return;
- }
- ctx = dev->ctx[new_ctx];
- /* Got context to run in ctx */
- /*
- * Last frame has already been sent to MFC.
- * Now obtaining frames from MFC buffer
- */
- s5p_mfc_clock_on();
- if (ctx->type == MFCINST_DECODER) {
- s5p_mfc_set_dec_desc_buffer(ctx);
- switch (ctx->state) {
- case MFCINST_FINISHING:
- s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME);
- break;
- case MFCINST_RUNNING:
- ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
- break;
- case MFCINST_INIT:
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_open_inst_cmd(ctx);
- break;
- case MFCINST_RETURN_INST:
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_close_inst_cmd(ctx);
- break;
- case MFCINST_GOT_INST:
- s5p_mfc_run_init_dec(ctx);
- break;
- case MFCINST_HEAD_PARSED:
- ret = s5p_mfc_run_init_dec_buffers(ctx);
- mfc_debug(1, "head parsed\n");
- break;
- case MFCINST_RES_CHANGE_INIT:
- s5p_mfc_run_res_change(ctx);
- break;
- case MFCINST_RES_CHANGE_FLUSH:
- s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
- break;
- case MFCINST_RES_CHANGE_END:
- mfc_debug(2, "Finished remaining frames after resolution change\n");
- ctx->capture_state = QUEUE_FREE;
- mfc_debug(2, "Will re-init the codec\n");
- s5p_mfc_run_init_dec(ctx);
- break;
- default:
- ret = -EAGAIN;
- }
- } else if (ctx->type == MFCINST_ENCODER) {
- switch (ctx->state) {
- case MFCINST_FINISHING:
- case MFCINST_RUNNING:
- ret = s5p_mfc_run_enc_frame(ctx);
- break;
- case MFCINST_INIT:
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_open_inst_cmd(ctx);
- break;
- case MFCINST_RETURN_INST:
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_close_inst_cmd(ctx);
- break;
- case MFCINST_GOT_INST:
- s5p_mfc_run_init_enc(ctx);
- break;
- default:
- ret = -EAGAIN;
- }
- } else {
- mfc_err("Invalid context type: %d\n", ctx->type);
- ret = -EAGAIN;
- }
-
- if (ret) {
- /* Free hardware lock */
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- mfc_err("Failed to unlock hardware\n");
-
- /* This is in deed imporant, as no operation has been
- * scheduled, reduce the clock count as no one will
- * ever do this, because no interrupt related to this try_run
- * will ever come from hardware. */
- s5p_mfc_clock_off();
- }
-}
-
-
-void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
-{
- struct s5p_mfc_buf *b;
- int i;
-
- while (!list_empty(lh)) {
- b = list_entry(lh->next, struct s5p_mfc_buf, list);
- for (i = 0; i < b->b->num_planes; i++)
- vb2_set_plane_payload(b->b, i, 0);
- vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR);
- list_del(&b->list);
- }
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
deleted file mode 100644
index 5932d1c782c5..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * drivers/media/video/samsung/mfc5/s5p_mfc_opr.h
- *
- * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
- * Contains declarations of hw related functions.
- *
- * Kamil Debski, Copyright (C) 2011 Samsung Electronics
- * http://www.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 S5P_MFC_OPR_H_
-#define S5P_MFC_OPR_H_
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
-
-/* Decoding functions */
-int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
- unsigned int start_num_byte,
- unsigned int buf_size);
-
-/* Encoding functions */
-void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long y_addr, unsigned long c_addr);
-int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long addr, unsigned int size);
-void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- unsigned long *y_addr, unsigned long *c_addr);
-int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
-
-int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_decode_arg last_frame);
-int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
-
-/* Memory allocation */
-int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
-
-void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
-void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
-
-#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \
- S5P_FIMV_SI_DISPLAY_Y_ADR) << \
- MFC_OFFSET_SHIFT)
-#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \
- S5P_FIMV_SI_DECODE_Y_ADR) << \
- MFC_OFFSET_SHIFT)
-#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \
- S5P_FIMV_SI_DISPLAY_STATUS)
-#define s5p_mfc_get_dec_status() readl(dev->regs_base + \
- S5P_FIMV_SI_DECODE_STATUS)
-#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \
- S5P_FIMV_DECODE_FRAME_TYPE) \
- & S5P_FIMV_DECODE_FRAME_MASK)
-#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \
- S5P_FIMV_SI_CONSUMED_BYTES)
-#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \
- S5P_FIMV_RISC2HOST_CMD) & \
- S5P_FIMV_RISC2HOST_CMD_MASK)
-#define s5p_mfc_get_int_err() readl(dev->regs_base + \
- S5P_FIMV_RISC2HOST_ARG2)
-#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
- S5P_FIMV_ERR_DEC_SHIFT)
-#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
- S5P_FIMV_ERR_DSPL_SHIFT)
-#define s5p_mfc_get_img_width() readl(dev->regs_base + \
- S5P_FIMV_SI_HRESOL)
-#define s5p_mfc_get_img_height() readl(dev->regs_base + \
- S5P_FIMV_SI_VRESOL)
-#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \
- S5P_FIMV_SI_BUF_NUMBER)
-#define s5p_mfc_get_inst_no() readl(dev->regs_base + \
- S5P_FIMV_RISC2HOST_ARG1)
-#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \
- S5P_FIMV_ENC_SI_STRM_SIZE)
-#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \
- S5P_FIMV_ENC_SI_SLICE_TYPE)
-
-#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
deleted file mode 100644
index 738a607be43c..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.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/clk.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#ifdef CONFIG_PM_RUNTIME
-#include <linux/pm_runtime.h>
-#endif
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-#include "s5p_mfc_pm.h"
-
-#define MFC_CLKNAME "sclk_mfc"
-#define MFC_GATE_CLK_NAME "mfc"
-
-#define CLK_DEBUG
-
-static struct s5p_mfc_pm *pm;
-static struct s5p_mfc_dev *p_dev;
-
-#ifdef CLK_DEBUG
-atomic_t clk_ref;
-#endif
-
-int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
-{
- int ret = 0;
-
- pm = &dev->pm;
- p_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 = 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 = 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;
- pm_runtime_enable(pm->device);
-#endif
-#ifdef CLK_DEBUG
- 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;
-}
-
-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);
-#endif
-}
-
-int s5p_mfc_clock_on(void)
-{
- int ret;
-#ifdef CLK_DEBUG
- atomic_inc(&clk_ref);
- mfc_debug(3, "+ %d", atomic_read(&clk_ref));
-#endif
- ret = clk_enable(pm->clock_gate);
- return ret;
-}
-
-void s5p_mfc_clock_off(void)
-{
-#ifdef CLK_DEBUG
- atomic_dec(&clk_ref);
- mfc_debug(3, "- %d", atomic_read(&clk_ref));
-#endif
- clk_disable(pm->clock_gate);
-}
-
-int s5p_mfc_power_on(void)
-{
-#ifdef CONFIG_PM_RUNTIME
- return pm_runtime_get_sync(pm->device);
-#else
- atomic_set(&pm->power, 1);
- return 0;
-#endif
-}
-
-int s5p_mfc_power_off(void)
-{
-#ifdef CONFIG_PM_RUNTIME
- return pm_runtime_put_sync(pm->device);
-#else
- atomic_set(&pm->power, 0);
- return 0;
-#endif
-}
-
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.h b/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
deleted file mode 100644
index 5107914f27e4..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
- *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_PM_H_
-#define S5P_MFC_PM_H_
-
-int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
-void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_clock_on(void);
-void s5p_mfc_clock_off(void);
-int s5p_mfc_power_on(void);
-int s5p_mfc_power_off(void);
-
-#endif /* S5P_MFC_PM_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.c b/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
deleted file mode 100644
index 91fdbac8c37a..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifdef CONFIG_ARCH_EXYNOS4
-#include <linux/dma-mapping.h>
-#endif
-#include <linux/io.h>
-#include "s5p_mfc_common.h"
-#include "s5p_mfc_debug.h"
-
-int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
-
- ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx,
- SHARED_BUF_SIZE);
- if (IS_ERR(ctx->shm_alloc)) {
- mfc_err("failed to allocate shared memory\n");
- return PTR_ERR(ctx->shm_alloc);
- }
- /* shm_ofs only keeps the offset from base (port a) */
- ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc)
- - dev->bank1;
- BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc);
- if (!ctx->shm) {
- vb2_dma_contig_memops.put(ctx->shm_alloc);
- ctx->shm_ofs = 0;
- ctx->shm_alloc = NULL;
- mfc_err("failed to virt addr of shared memory\n");
- return -ENOMEM;
- }
- memset((void *)ctx->shm, 0, SHARED_BUF_SIZE);
- wmb();
- return 0;
-}
-
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
deleted file mode 100644
index cf962a466276..000000000000
--- a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.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.
- */
-
-#ifndef S5P_MFC_SHM_H_
-#define S5P_MFC_SHM_H_
-
-enum MFC_SHM_OFS {
- EXTENEDED_DECODE_STATUS = 0x00, /* D */
- SET_FRAME_TAG = 0x04, /* D */
- GET_FRAME_TAG_TOP = 0x08, /* D */
- GET_FRAME_TAG_BOT = 0x0C, /* D */
- PIC_TIME_TOP = 0x10, /* D */
- PIC_TIME_BOT = 0x14, /* D */
- START_BYTE_NUM = 0x18, /* D */
-
- CROP_INFO_H = 0x20, /* D */
- CROP_INFO_V = 0x24, /* D */
- EXT_ENC_CONTROL = 0x28, /* E */
- ENC_PARAM_CHANGE = 0x2C, /* E */
- RC_VOP_TIMING = 0x30, /* E, MPEG4 */
- HEC_PERIOD = 0x34, /* E, MPEG4 */
- METADATA_ENABLE = 0x38, /* C */
- METADATA_STATUS = 0x3C, /* C */
- METADATA_DISPLAY_INDEX = 0x40, /* C */
- EXT_METADATA_START_ADDR = 0x44, /* C */
- PUT_EXTRADATA = 0x48, /* C */
- EXTRADATA_ADDR = 0x4C, /* C */
-
- ALLOC_LUMA_DPB_SIZE = 0x64, /* D */
- ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */
- ALLOC_MV_SIZE = 0x6C, /* D */
- P_B_FRAME_QP = 0x70, /* E */
- SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on
- ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
- EXTENDED_SAR = 0x78, /* E, H.264, depned on
- ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
- DISP_PIC_PROFILE = 0x7C, /* D */
- FLUSH_CMD_TYPE = 0x80, /* C */
- FLUSH_CMD_INBUF1 = 0x84, /* C */
- FLUSH_CMD_INBUF2 = 0x88, /* C */
- FLUSH_CMD_OUTBUF = 0x8C, /* E */
- NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8)
- depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
- NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0)
- depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
- NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504)
- depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
- H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */
- RC_CONTROL_CONFIG = 0xA0, /* E */
- BATCH_INPUT_ADDR = 0xA4, /* E */
- BATCH_OUTPUT_ADDR = 0xA8, /* E */
- BATCH_OUTPUT_SIZE = 0xAC, /* E */
- MIN_LUMA_DPB_SIZE = 0xB0, /* D */
- DEVICE_FORMAT_ID = 0xB4, /* C */
- H264_POC_TYPE = 0xB8, /* D */
- MIN_CHROMA_DPB_SIZE = 0xBC, /* D */
- DISP_PIC_FRAME_TYPE = 0xC0, /* D */
- FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */
- ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */
- EXTENDED_PAR = 0xCC, /* D, MPEG4 */
- DBG_HISTORY_INPUT0 = 0xD0, /* C */
- DBG_HISTORY_INPUT1 = 0xD4, /* C */
- DBG_HISTORY_OUTPUT = 0xD8, /* C */
- HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */
-};
-
-int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
-
-#define s5p_mfc_write_shm(ctx, x, ofs) \
- do { \
- writel(x, (ctx->shm + ofs)); \
- wmb(); \
- } while (0)
-
-static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
-{
- rmb();
- return readl(ctx->shm + ofs);
-}
-
-#endif /* S5P_MFC_SHM_H_ */
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
deleted file mode 100644
index f248b2856720..000000000000
--- a/drivers/media/video/s5p-tv/Kconfig
+++ /dev/null
@@ -1,86 +0,0 @@
-# drivers/media/video/s5p-tv/Kconfig
-#
-# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
-# http://www.samsung.com/
-# Tomasz Stanislawski <t.stanislaws@samsung.com>
-#
-# Licensed under GPL
-
-config VIDEO_SAMSUNG_S5P_TV
- bool "Samsung TV driver for S5P platform (experimental)"
- depends on PLAT_S5P && PM_RUNTIME
- depends on EXPERIMENTAL
- default n
- ---help---
- Say Y here to enable selecting the TV output devices for
- Samsung S5P platform.
-
-if VIDEO_SAMSUNG_S5P_TV
-
-config VIDEO_SAMSUNG_S5P_HDMI
- tristate "Samsung HDMI Driver"
- depends on VIDEO_V4L2
- depends on VIDEO_SAMSUNG_S5P_TV
- select VIDEO_SAMSUNG_S5P_HDMIPHY
- help
- Say Y here if you want support for the HDMI output
- interface in S5P Samsung SoC. The driver can be compiled
- as module. It is an auxiliary driver, that exposes a V4L2
- subdev for use by other drivers. This driver requires
- hdmiphy driver to work correctly.
-
-config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
- bool "Enable debug for HDMI Driver"
- depends on VIDEO_SAMSUNG_S5P_HDMI
- default n
- help
- Enables debugging for HDMI driver.
-
-config VIDEO_SAMSUNG_S5P_HDMIPHY
- tristate "Samsung HDMIPHY Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && I2C
- depends on VIDEO_SAMSUNG_S5P_TV
- help
- Say Y here if you want support for the physical HDMI
- 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_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
- depends on VIDEO_SAMSUNG_S5P_TV
- help
- Say Y here if you want support for the analog TV output
- interface in S5P Samsung SoC. The driver can be compiled
- as module. It is an auxiliary driver, that exposes a V4L2
- subdev for use by other drivers. This driver requires
- hdmiphy driver to work correctly.
-
-config VIDEO_SAMSUNG_S5P_MIXER
- tristate "Samsung Mixer and Video Processor Driver"
- depends on VIDEO_DEV && VIDEO_V4L2
- depends on VIDEO_SAMSUNG_S5P_TV
- select VIDEOBUF2_DMA_CONTIG
- help
- Say Y here if you want support for the Mixer in Samsung S5P SoCs.
- This device produce image data to one of output interfaces.
-
-config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
- bool "Enable debug for Mixer Driver"
- depends on VIDEO_SAMSUNG_S5P_MIXER
- default n
- help
- Enables debugging for Mixer driver.
-
-endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
deleted file mode 100644
index f49e756a2fde..000000000000
--- a/drivers/media/video/s5p-tv/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# drivers/media/video/samsung/tvout/Makefile
-#
-# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
-# http://www.samsung.com/
-# Tomasz Stanislawski <t.stanislaws@samsung.com>
-#
-# Licensed under GPL
-
-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
-s5p-sdo-y += sdo_drv.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
-s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
-
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
deleted file mode 100644
index 20cb6eef2979..000000000000
--- a/drivers/media/video/s5p-tv/hdmi_drv.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * Samsung HDMI interface driver
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *
- * 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 Foundiation. either version 2 of the License,
- * or (at your option) any later version
- */
-
-#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <media/v4l2-subdev.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/bug.h>
-#include <linux/pm_runtime.h>
-#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>
-
-#include "regs-hdmi.h"
-
-MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
-MODULE_DESCRIPTION("Samsung HDMI");
-MODULE_LICENSE("GPL");
-
-/* default preset configured on probe */
-#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
-
-struct hdmi_pulse {
- u32 beg;
- u32 end;
-};
-
-struct hdmi_timings {
- struct hdmi_pulse hact;
- u32 hsyn_pol; /* 0 - high, 1 - low */
- struct hdmi_pulse hsyn;
- u32 interlaced;
- struct hdmi_pulse vact[2];
- u32 vsyn_pol; /* 0 - high, 1 - low */
- u32 vsyn_off;
- struct hdmi_pulse vsyn[2];
-};
-
-struct hdmi_resources {
- struct clk *hdmi;
- struct clk *sclk_hdmi;
- struct clk *sclk_pixel;
- struct clk *sclk_hdmiphy;
- struct clk *hdmiphy;
- struct regulator_bulk_data *regul_bulk;
- int regul_count;
-};
-
-struct hdmi_device {
- /** base address of HDMI registers */
- void __iomem *regs;
- /** HDMI interrupt */
- unsigned int irq;
- /** pointer to device parent */
- struct device *dev;
- /** subdev generated by HDMI device */
- struct v4l2_subdev sd;
- /** V4L2 device structure */
- 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_timings *cur_conf;
- /** flag indicating that timings are dirty */
- int cur_conf_dirty;
- /** current preset */
- u32 cur_preset;
- /** other resources */
- struct hdmi_resources res;
-};
-
-static struct platform_device_id hdmi_driver_types[] = {
- {
- .name = "s5pv210-hdmi",
- }, {
- .name = "exynos4-hdmi",
- }, {
- /* end node */
- }
-};
-
-static const struct v4l2_subdev_ops hdmi_sd_ops;
-
-static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct hdmi_device, sd);
-}
-
-static inline
-void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
-{
- writel(value, hdev->regs + reg_id);
-}
-
-static inline
-void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
-{
- u32 old = readl(hdev->regs + reg_id);
- value = (value & mask) | (old & ~mask);
- writel(value, hdev->regs + reg_id);
-}
-
-static inline
-void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
-{
- writeb(value, hdev->regs + reg_id);
-}
-
-static inline
-void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value)
-{
- switch (n) {
- default:
- writeb(value >> 24, hdev->regs + reg_id + 12);
- case 3:
- writeb(value >> 16, hdev->regs + reg_id + 8);
- case 2:
- writeb(value >> 8, hdev->regs + reg_id + 4);
- case 1:
- writeb(value >> 0, hdev->regs + reg_id + 0);
- }
-}
-
-static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
-{
- return readl(hdev->regs + reg_id);
-}
-
-static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
-{
- struct hdmi_device *hdev = dev_data;
- u32 intc_flag;
-
- (void)irq;
- intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
- /* clearing flags for HPD plug/unplug */
- if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
- printk(KERN_INFO "unplugged\n");
- hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
- HDMI_INTC_FLAG_HPD_UNPLUG);
- }
- if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
- printk(KERN_INFO "plugged\n");
- hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
- HDMI_INTC_FLAG_HPD_PLUG);
- }
-
- return IRQ_HANDLED;
-}
-
-static void hdmi_reg_init(struct hdmi_device *hdev)
-{
- /* enable HPD interrupts */
- hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
- HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
- /* choose DVI mode */
- hdmi_write_mask(hdev, HDMI_MODE_SEL,
- HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
- hdmi_write_mask(hdev, HDMI_CON_2, ~0,
- HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN);
- /* disable bluescreen */
- hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
- /* choose bluescreen (fecal) color */
- hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
- hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
- hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
-}
-
-static void hdmi_timing_apply(struct hdmi_device *hdev,
- const struct hdmi_timings *t)
-{
- /* setting core registers */
- hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
- hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
- (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
- hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
- hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
- (t->vact[0].beg << 11) | t->vact[0].end);
- hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
- (t->vsyn[0].beg << 12) | t->vsyn[0].end);
- if (t->interlaced) {
- u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
-
- hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1);
- hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
- (t->hact.end << 12) | t->vact[1].end);
- hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
- (t->vact[1].end << 11) | t->vact[1].beg);
- hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
- (t->vsyn[1].beg << 12) | t->vsyn[1].end);
- hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
- (vsyn_trans << 12) | vsyn_trans);
- } else {
- hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
- hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
- (t->hact.end << 12) | t->vact[0].end);
- }
-
- /* Timing generator registers */
- hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
- hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
- hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
- hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
- hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
- hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
- t->vact[0].end - t->vact[0].beg);
- hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
- hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
- if (t->interlaced) {
- hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
- hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
- hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
- hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
- hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
- hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
- hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
- } else {
- hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
- hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
- }
-}
-
-static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
-{
- struct device *dev = hdmi_dev->dev;
- const struct hdmi_timings *conf = hdmi_dev->cur_conf;
- struct v4l2_dv_preset preset;
- int ret;
-
- dev_dbg(dev, "%s\n", __func__);
-
- /* skip if conf is already synchronized with HW */
- if (!hdmi_dev->cur_conf_dirty)
- return 0;
-
- /* reset hdmiphy */
- hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
- mdelay(10);
- hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
- mdelay(10);
-
- /* configure presets */
- preset.preset = hdmi_dev->cur_preset;
- ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
- if (ret) {
- dev_err(dev, "failed to set preset (%u)\n", preset.preset);
- return ret;
- }
-
- /* resetting HDMI core */
- hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
- mdelay(10);
- hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
- mdelay(10);
-
- hdmi_reg_init(hdmi_dev);
-
- /* setting core registers */
- hdmi_timing_apply(hdmi_dev, conf);
-
- hdmi_dev->cur_conf_dirty = 0;
-
- return 0;
-}
-
-static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
-{
-#define DUMPREG(reg_id) \
- dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
- readl(hdev->regs + reg_id))
-
- dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
- DUMPREG(HDMI_INTC_FLAG);
- DUMPREG(HDMI_INTC_CON);
- DUMPREG(HDMI_HPD_STATUS);
- DUMPREG(HDMI_PHY_RSTOUT);
- DUMPREG(HDMI_PHY_VPLL);
- DUMPREG(HDMI_PHY_CMU);
- DUMPREG(HDMI_CORE_RSTOUT);
-
- dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
- DUMPREG(HDMI_CON_0);
- DUMPREG(HDMI_CON_1);
- DUMPREG(HDMI_CON_2);
- DUMPREG(HDMI_SYS_STATUS);
- DUMPREG(HDMI_PHY_STATUS);
- DUMPREG(HDMI_STATUS_EN);
- DUMPREG(HDMI_HPD);
- DUMPREG(HDMI_MODE_SEL);
- DUMPREG(HDMI_HPD_GEN);
- DUMPREG(HDMI_DC_CONTROL);
- DUMPREG(HDMI_VIDEO_PATTERN_GEN);
-
- dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
- DUMPREG(HDMI_H_BLANK_0);
- DUMPREG(HDMI_H_BLANK_1);
- DUMPREG(HDMI_V_BLANK_0);
- DUMPREG(HDMI_V_BLANK_1);
- DUMPREG(HDMI_V_BLANK_2);
- DUMPREG(HDMI_H_V_LINE_0);
- DUMPREG(HDMI_H_V_LINE_1);
- DUMPREG(HDMI_H_V_LINE_2);
- DUMPREG(HDMI_VSYNC_POL);
- DUMPREG(HDMI_INT_PRO_MODE);
- DUMPREG(HDMI_V_BLANK_F_0);
- DUMPREG(HDMI_V_BLANK_F_1);
- DUMPREG(HDMI_V_BLANK_F_2);
- DUMPREG(HDMI_H_SYNC_GEN_0);
- DUMPREG(HDMI_H_SYNC_GEN_1);
- DUMPREG(HDMI_H_SYNC_GEN_2);
- DUMPREG(HDMI_V_SYNC_GEN_1_0);
- DUMPREG(HDMI_V_SYNC_GEN_1_1);
- DUMPREG(HDMI_V_SYNC_GEN_1_2);
- DUMPREG(HDMI_V_SYNC_GEN_2_0);
- DUMPREG(HDMI_V_SYNC_GEN_2_1);
- DUMPREG(HDMI_V_SYNC_GEN_2_2);
- DUMPREG(HDMI_V_SYNC_GEN_3_0);
- DUMPREG(HDMI_V_SYNC_GEN_3_1);
- DUMPREG(HDMI_V_SYNC_GEN_3_2);
-
- dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
- DUMPREG(HDMI_TG_CMD);
- DUMPREG(HDMI_TG_H_FSZ_L);
- DUMPREG(HDMI_TG_H_FSZ_H);
- DUMPREG(HDMI_TG_HACT_ST_L);
- DUMPREG(HDMI_TG_HACT_ST_H);
- DUMPREG(HDMI_TG_HACT_SZ_L);
- DUMPREG(HDMI_TG_HACT_SZ_H);
- DUMPREG(HDMI_TG_V_FSZ_L);
- DUMPREG(HDMI_TG_V_FSZ_H);
- DUMPREG(HDMI_TG_VSYNC_L);
- DUMPREG(HDMI_TG_VSYNC_H);
- DUMPREG(HDMI_TG_VSYNC2_L);
- DUMPREG(HDMI_TG_VSYNC2_H);
- DUMPREG(HDMI_TG_VACT_ST_L);
- DUMPREG(HDMI_TG_VACT_ST_H);
- DUMPREG(HDMI_TG_VACT_SZ_L);
- DUMPREG(HDMI_TG_VACT_SZ_H);
- DUMPREG(HDMI_TG_FIELD_CHG_L);
- DUMPREG(HDMI_TG_FIELD_CHG_H);
- DUMPREG(HDMI_TG_VACT_ST2_L);
- DUMPREG(HDMI_TG_VACT_ST2_H);
- DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
- DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
- DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
- DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
- DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
- DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
- DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
- DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
-#undef DUMPREG
-}
-
-static const struct hdmi_timings hdmi_timings_480p = {
- .hact = { .beg = 138, .end = 858 },
- .hsyn_pol = 1,
- .hsyn = { .beg = 16, .end = 16 + 62 },
- .interlaced = 0,
- .vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
- .vsyn_pol = 1,
- .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
-};
-
-static const struct hdmi_timings hdmi_timings_576p50 = {
- .hact = { .beg = 144, .end = 864 },
- .hsyn_pol = 1,
- .hsyn = { .beg = 12, .end = 12 + 64 },
- .interlaced = 0,
- .vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
- .vsyn_pol = 1,
- .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
-};
-
-static const struct hdmi_timings hdmi_timings_720p60 = {
- .hact = { .beg = 370, .end = 1650 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 110, .end = 110 + 40 },
- .interlaced = 0,
- .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
- .vsyn_pol = 0,
- .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
-};
-
-static const struct hdmi_timings hdmi_timings_720p50 = {
- .hact = { .beg = 700, .end = 1980 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 440, .end = 440 + 40 },
- .interlaced = 0,
- .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
- .vsyn_pol = 0,
- .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
-};
-
-static const struct hdmi_timings hdmi_timings_1080p24 = {
- .hact = { .beg = 830, .end = 2750 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 638, .end = 638 + 44 },
- .interlaced = 0,
- .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
- .vsyn_pol = 0,
- .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
-};
-
-static const struct hdmi_timings hdmi_timings_1080p60 = {
- .hact = { .beg = 280, .end = 2200 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 88, .end = 88 + 44 },
- .interlaced = 0,
- .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
- .vsyn_pol = 0,
- .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
-};
-
-static const struct hdmi_timings hdmi_timings_1080i60 = {
- .hact = { .beg = 280, .end = 2200 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 88, .end = 88 + 44 },
- .interlaced = 1,
- .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
- .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
- .vsyn_pol = 0,
- .vsyn_off = 1100,
- .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
- .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
-};
-
-static const struct hdmi_timings hdmi_timings_1080i50 = {
- .hact = { .beg = 720, .end = 2640 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 528, .end = 528 + 44 },
- .interlaced = 1,
- .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
- .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
- .vsyn_pol = 0,
- .vsyn_off = 1320,
- .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
- .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
-};
-
-static const struct hdmi_timings hdmi_timings_1080p50 = {
- .hact = { .beg = 720, .end = 2640 },
- .hsyn_pol = 0,
- .hsyn = { .beg = 528, .end = 528 + 44 },
- .interlaced = 0,
- .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
- .vsyn_pol = 0,
- .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
-};
-
-static const struct {
- u32 preset;
- const struct hdmi_timings *timings;
-} hdmi_timings[] = {
- { V4L2_DV_480P59_94, &hdmi_timings_480p },
- { V4L2_DV_576P50, &hdmi_timings_576p50 },
- { V4L2_DV_720P50, &hdmi_timings_720p50 },
- { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
- { V4L2_DV_720P60, &hdmi_timings_720p60 },
- { V4L2_DV_1080P24, &hdmi_timings_1080p24 },
- { V4L2_DV_1080P30, &hdmi_timings_1080p60 },
- { V4L2_DV_1080P50, &hdmi_timings_1080p50 },
- { V4L2_DV_1080I50, &hdmi_timings_1080i50 },
- { V4L2_DV_1080I60, &hdmi_timings_1080i60 },
- { V4L2_DV_1080P60, &hdmi_timings_1080p60 },
-};
-
-static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
- if (hdmi_timings[i].preset == preset)
- return hdmi_timings[i].timings;
- return NULL;
-}
-
-static int hdmi_streamon(struct hdmi_device *hdev)
-{
- struct device *dev = hdev->dev;
- struct hdmi_resources *res = &hdev->res;
- int ret, tries;
-
- dev_dbg(dev, "%s\n", __func__);
-
- ret = hdmi_conf_apply(hdev);
- if (ret)
- return ret;
-
- ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
- if (ret)
- return ret;
-
- /* waiting for HDMIPHY's PLL to get to steady state */
- for (tries = 100; tries; --tries) {
- u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
- if (val & HDMI_PHY_STATUS_READY)
- break;
- mdelay(1);
- }
- /* steady state not achieved */
- 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, "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;
- }
-
- /* hdmiphy clock is used for HDMI in streaming mode */
- clk_disable(res->sclk_hdmi);
- clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
- clk_enable(res->sclk_hdmi);
-
- /* enable HDMI and timing generator */
- hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
- hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
- hdmi_dumpregs(hdev, "streamon");
- return 0;
-}
-
-static int hdmi_streamoff(struct hdmi_device *hdev)
-{
- struct device *dev = hdev->dev;
- struct hdmi_resources *res = &hdev->res;
-
- dev_dbg(dev, "%s\n", __func__);
-
- hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
- hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
-
- /* pixel(vpll) clock is used for HDMI in config mode */
- clk_disable(res->sclk_hdmi);
- 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");
- return 0;
-}
-
-static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- struct device *dev = hdev->dev;
-
- dev_dbg(dev, "%s(%d)\n", __func__, enable);
- if (enable)
- return hdmi_streamon(hdev);
- return hdmi_streamoff(hdev);
-}
-
-static void hdmi_resource_poweron(struct hdmi_resources *res)
-{
- /* turn HDMI power on */
- regulator_bulk_enable(res->regul_count, res->regul_bulk);
- /* power-on hdmi physical interface */
- clk_enable(res->hdmiphy);
- /* use VPP as parent clock; HDMIPHY is not working yet */
- clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
- /* turn clocks on */
- clk_enable(res->sclk_hdmi);
-}
-
-static void hdmi_resource_poweroff(struct hdmi_resources *res)
-{
- /* turn clocks off */
- clk_disable(res->sclk_hdmi);
- /* power-off hdmiphy */
- clk_disable(res->hdmiphy);
- /* turn HDMI power off */
- regulator_bulk_disable(res->regul_count, res->regul_bulk);
-}
-
-static int hdmi_s_power(struct v4l2_subdev *sd, int on)
-{
- struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- int ret;
-
- if (on)
- ret = pm_runtime_get_sync(hdev->dev);
- else
- ret = pm_runtime_put_sync(hdev->dev);
- /* only values < 0 indicate errors */
- return IS_ERR_VALUE(ret) ? ret : 0;
-}
-
-static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
-{
- struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- struct device *dev = hdev->dev;
- const struct hdmi_timings *conf;
-
- conf = hdmi_preset2timings(preset->preset);
- if (conf == NULL) {
- dev_err(dev, "preset (%u) not supported\n", preset->preset);
- return -EINVAL;
- }
- hdev->cur_conf = conf;
- hdev->cur_conf_dirty = 1;
- hdev->cur_preset = preset->preset;
- return 0;
-}
-
-static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
-{
- memset(preset, 0, sizeof(*preset));
- preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
- return 0;
-}
-
-static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
-{
- struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- const struct hdmi_timings *t = hdev->cur_conf;
-
- dev_dbg(hdev->dev, "%s\n", __func__);
- if (!hdev->cur_conf)
- return -EINVAL;
- memset(fmt, 0, sizeof *fmt);
- fmt->width = t->hact.end - t->hact.beg;
- fmt->height = t->vact[0].end - t->vact[0].beg;
- fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- if (t->interlaced) {
- fmt->field = V4L2_FIELD_INTERLACED;
- fmt->height *= 2;
- } else {
- fmt->field = V4L2_FIELD_NONE;
- }
- return 0;
-}
-
-static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
- struct v4l2_dv_enum_preset *preset)
-{
- if (preset->index >= ARRAY_SIZE(hdmi_timings))
- return -EINVAL;
- return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
- preset);
-}
-
-static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
- .s_power = hdmi_s_power,
-};
-
-static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
- .s_dv_preset = hdmi_s_dv_preset,
- .g_dv_preset = hdmi_g_dv_preset,
- .enum_dv_presets = hdmi_enum_dv_presets,
- .g_mbus_fmt = hdmi_g_mbus_fmt,
- .s_stream = hdmi_s_stream,
-};
-
-static const struct v4l2_subdev_ops hdmi_sd_ops = {
- .core = &hdmi_sd_core_ops,
- .video = &hdmi_sd_video_ops,
-};
-
-static int hdmi_runtime_suspend(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(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);
- /* flag that device context is lost */
- hdev->cur_conf_dirty = 1;
- return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- int ret = 0;
-
- dev_dbg(dev, "%s\n", __func__);
-
- hdmi_resource_poweron(&hdev->res);
-
- /* 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;
-
-fail:
- hdmi_resource_poweroff(&hdev->res);
- dev_err(dev, "poweron failed\n");
-
- return ret;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
- .runtime_suspend = hdmi_runtime_suspend,
- .runtime_resume = hdmi_runtime_resume,
-};
-
-static void hdmi_resources_cleanup(struct hdmi_device *hdev)
-{
- struct hdmi_resources *res = &hdev->res;
-
- dev_dbg(hdev->dev, "HDMI resource cleanup\n");
- /* put clocks, power */
- if (res->regul_count)
- regulator_bulk_free(res->regul_count, res->regul_bulk);
- /* kfree is NULL-safe */
- kfree(res->regul_bulk);
- if (!IS_ERR_OR_NULL(res->hdmiphy))
- clk_put(res->hdmiphy);
- if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
- clk_put(res->sclk_hdmiphy);
- if (!IS_ERR_OR_NULL(res->sclk_pixel))
- clk_put(res->sclk_pixel);
- if (!IS_ERR_OR_NULL(res->sclk_hdmi))
- clk_put(res->sclk_hdmi);
- if (!IS_ERR_OR_NULL(res->hdmi))
- clk_put(res->hdmi);
- memset(res, 0, sizeof *res);
-}
-
-static int hdmi_resources_init(struct hdmi_device *hdev)
-{
- struct device *dev = hdev->dev;
- struct hdmi_resources *res = &hdev->res;
- static char *supply[] = {
- "hdmi-en",
- "vdd",
- "vdd_osc",
- "vdd_pll",
- };
- int i, ret;
-
- dev_dbg(dev, "HDMI resource init\n");
-
- memset(res, 0, sizeof *res);
- /* get clocks, power */
-
- res->hdmi = clk_get(dev, "hdmi");
- if (IS_ERR_OR_NULL(res->hdmi)) {
- dev_err(dev, "failed to get clock 'hdmi'\n");
- goto fail;
- }
- res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
- dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
- goto fail;
- }
- res->sclk_pixel = clk_get(dev, "sclk_pixel");
- if (IS_ERR_OR_NULL(res->sclk_pixel)) {
- dev_err(dev, "failed to get clock 'sclk_pixel'\n");
- goto fail;
- }
- res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
- if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
- dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
- goto fail;
- }
- res->hdmiphy = clk_get(dev, "hdmiphy");
- if (IS_ERR_OR_NULL(res->hdmiphy)) {
- dev_err(dev, "failed to get clock 'hdmiphy'\n");
- goto fail;
- }
- 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;
- }
- for (i = 0; i < ARRAY_SIZE(supply); ++i) {
- res->regul_bulk[i].supply = supply[i];
- res->regul_bulk[i].consumer = NULL;
- }
-
- ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
- if (ret) {
- dev_err(dev, "failed to get regulators\n");
- goto fail;
- }
- res->regul_count = ARRAY_SIZE(supply);
-
- return 0;
-fail:
- dev_err(dev, "HDMI resource init - failed\n");
- hdmi_resources_cleanup(hdev);
- return -ENODEV;
-}
-
-static int __devinit hdmi_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct resource *res;
- struct i2c_adapter *adapter;
- struct v4l2_subdev *sd;
- struct hdmi_device *hdmi_dev = NULL;
- struct s5p_hdmi_platform_data *pdata = dev->platform_data;
- int ret;
-
- dev_dbg(dev, "probe start\n");
-
- 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;
- goto fail;
- }
-
- hdmi_dev->dev = dev;
-
- ret = hdmi_resources_init(hdmi_dev);
- if (ret)
- goto fail;
-
- /* mapping HDMI registers */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(dev, "get memory resource failed.\n");
- ret = -ENXIO;
- goto fail_init;
- }
-
- 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_init;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(dev, "get interrupt resource failed.\n");
- ret = -ENXIO;
- goto fail_init;
- }
-
- 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_init;
- }
- hdmi_dev->irq = res->start;
-
- /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
- strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
- sizeof(hdmi_dev->v4l2_dev.name));
- /* passing NULL owner prevents driver from erasing drvdata */
- ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
- if (ret) {
- dev_err(dev, "could not register v4l2 device.\n");
- goto fail_init;
- }
-
- /* 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,
- adapter, pdata->hdmiphy_info, NULL);
- /* on failure or not adapter is no longer useful */
- 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);
-
- sd = &hdmi_dev->sd;
- v4l2_subdev_init(sd, &hdmi_sd_ops);
- sd->owner = THIS_MODULE;
-
- strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
- hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
- /* FIXME: missing fail preset is not supported */
- hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
- hdmi_dev->cur_conf_dirty = 1;
-
- /* storing subdev for call that have only access to struct device */
- dev_set_drvdata(dev, sd);
-
- dev_info(dev, "probe successful\n");
-
- return 0;
-
-fail_vdev:
- v4l2_device_unregister(&hdmi_dev->v4l2_dev);
-
-fail_init:
- hdmi_resources_cleanup(hdmi_dev);
-
-fail:
- dev_err(dev, "probe failed\n");
- return ret;
-}
-
-static int __devexit hdmi_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
-
- pm_runtime_disable(dev);
- clk_disable(hdmi_dev->res.hdmi);
- v4l2_device_unregister(&hdmi_dev->v4l2_dev);
- disable_irq(hdmi_dev->irq);
- hdmi_resources_cleanup(hdmi_dev);
- dev_info(dev, "remove successful\n");
-
- return 0;
-}
-
-static struct platform_driver hdmi_driver __refdata = {
- .probe = hdmi_probe,
- .remove = __devexit_p(hdmi_remove),
- .id_table = hdmi_driver_types,
- .driver = {
- .name = "s5p-hdmi",
- .owner = THIS_MODULE,
- .pm = &hdmi_pm_ops,
- }
-};
-
-module_platform_driver(hdmi_driver);
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
deleted file mode 100644
index edca06592883..000000000000
--- a/drivers/media/video/s5p-tv/mixer_drv.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Samsung TV Mixer driver
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *
- * 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 Foundiation. either version 2 of the License,
- * or (at your option) any later version
- */
-
-#include "mixer.h"
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/fb.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-
-MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
-MODULE_DESCRIPTION("Samsung MIXER");
-MODULE_LICENSE("GPL");
-
-/* --------- DRIVER PARAMETERS ---------- */
-
-static struct mxr_output_conf mxr_output_conf[] = {
- {
- .output_name = "S5P HDMI connector",
- .module_name = "s5p-hdmi",
- .cookie = 1,
- },
- {
- .output_name = "S5P SDO connector",
- .module_name = "s5p-sdo",
- .cookie = 0,
- },
-};
-
-void mxr_get_mbus_fmt(struct mxr_device *mdev,
- struct v4l2_mbus_framefmt *mbus_fmt)
-{
- struct v4l2_subdev *sd;
- int ret;
-
- mutex_lock(&mdev->mutex);
- sd = to_outsd(mdev);
- ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
- WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
- mutex_unlock(&mdev->mutex);
-}
-
-void mxr_streamer_get(struct mxr_device *mdev)
-{
- mutex_lock(&mdev->mutex);
- ++mdev->n_streamer;
- mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
- if (mdev->n_streamer == 1) {
- struct v4l2_subdev *sd = to_outsd(mdev);
- struct v4l2_mbus_framefmt mbus_fmt;
- struct mxr_resources *res = &mdev->res;
- int ret;
-
- if (to_output(mdev)->cookie == 0)
- clk_set_parent(res->sclk_mixer, res->sclk_dac);
- else
- clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
- mxr_reg_s_output(mdev, to_output(mdev)->cookie);
-
- ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
- WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
- ret = v4l2_subdev_call(sd, video, s_stream, 1);
- WARN(ret, "starting stream failed for output %s\n", sd->name);
-
- mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
- mxr_reg_streamon(mdev);
- ret = mxr_reg_wait4vsync(mdev);
- WARN(ret, "failed to get vsync (%d) from output\n", ret);
- }
- mutex_unlock(&mdev->mutex);
- mxr_reg_dump(mdev);
- /* FIXME: what to do when streaming fails? */
-}
-
-void mxr_streamer_put(struct mxr_device *mdev)
-{
- mutex_lock(&mdev->mutex);
- --mdev->n_streamer;
- mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
- if (mdev->n_streamer == 0) {
- int ret;
- struct v4l2_subdev *sd = to_outsd(mdev);
-
- mxr_reg_streamoff(mdev);
- /* vsync applies Mixer setup */
- ret = mxr_reg_wait4vsync(mdev);
- WARN(ret, "failed to get vsync (%d) from output\n", ret);
- ret = v4l2_subdev_call(sd, video, s_stream, 0);
- WARN(ret, "stopping stream failed for output %s\n", sd->name);
- }
- WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
- mdev->n_streamer);
- mutex_unlock(&mdev->mutex);
- mxr_reg_dump(mdev);
-}
-
-void mxr_output_get(struct mxr_device *mdev)
-{
- mutex_lock(&mdev->mutex);
- ++mdev->n_output;
- mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
- /* turn on auxiliary driver */
- if (mdev->n_output == 1)
- v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
- mutex_unlock(&mdev->mutex);
-}
-
-void mxr_output_put(struct mxr_device *mdev)
-{
- mutex_lock(&mdev->mutex);
- --mdev->n_output;
- mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
- /* turn on auxiliary driver */
- if (mdev->n_output == 0)
- v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
- WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
- mdev->n_output);
- mutex_unlock(&mdev->mutex);
-}
-
-int mxr_power_get(struct mxr_device *mdev)
-{
- int ret = pm_runtime_get_sync(mdev->dev);
-
- /* returning 1 means that power is already enabled,
- * so zero success be returned */
- if (IS_ERR_VALUE(ret))
- return ret;
- return 0;
-}
-
-void mxr_power_put(struct mxr_device *mdev)
-{
- pm_runtime_put_sync(mdev->dev);
-}
-
-/* --------- RESOURCE MANAGEMENT -------------*/
-
-static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
- struct platform_device *pdev)
-{
- struct resource *res;
- int ret;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
- if (res == NULL) {
- mxr_err(mdev, "get memory resource failed.\n");
- ret = -ENXIO;
- goto fail;
- }
-
- mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
- if (mdev->res.mxr_regs == NULL) {
- mxr_err(mdev, "register mapping failed.\n");
- ret = -ENXIO;
- goto fail;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
- if (res == NULL) {
- mxr_err(mdev, "get memory resource failed.\n");
- ret = -ENXIO;
- goto fail_mxr_regs;
- }
-
- mdev->res.vp_regs = ioremap(res->start, resource_size(res));
- if (mdev->res.vp_regs == NULL) {
- mxr_err(mdev, "register mapping failed.\n");
- ret = -ENXIO;
- goto fail_mxr_regs;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
- if (res == NULL) {
- mxr_err(mdev, "get interrupt resource failed.\n");
- ret = -ENXIO;
- goto fail_vp_regs;
- }
-
- ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
- if (ret) {
- mxr_err(mdev, "request interrupt failed.\n");
- goto fail_vp_regs;
- }
- mdev->res.irq = res->start;
-
- return 0;
-
-fail_vp_regs:
- iounmap(mdev->res.vp_regs);
-
-fail_mxr_regs:
- iounmap(mdev->res.mxr_regs);
-
-fail:
- return ret;
-}
-
-static void mxr_release_plat_resources(struct mxr_device *mdev)
-{
- free_irq(mdev->res.irq, mdev);
- iounmap(mdev->res.vp_regs);
- iounmap(mdev->res.mxr_regs);
-}
-
-static void mxr_release_clocks(struct mxr_device *mdev)
-{
- struct mxr_resources *res = &mdev->res;
-
- if (!IS_ERR_OR_NULL(res->sclk_dac))
- clk_put(res->sclk_dac);
- if (!IS_ERR_OR_NULL(res->sclk_hdmi))
- clk_put(res->sclk_hdmi);
- if (!IS_ERR_OR_NULL(res->sclk_mixer))
- clk_put(res->sclk_mixer);
- if (!IS_ERR_OR_NULL(res->vp))
- clk_put(res->vp);
- if (!IS_ERR_OR_NULL(res->mixer))
- clk_put(res->mixer);
-}
-
-static int mxr_acquire_clocks(struct mxr_device *mdev)
-{
- struct mxr_resources *res = &mdev->res;
- struct device *dev = mdev->dev;
-
- res->mixer = clk_get(dev, "mixer");
- if (IS_ERR_OR_NULL(res->mixer)) {
- mxr_err(mdev, "failed to get clock 'mixer'\n");
- goto fail;
- }
- res->vp = clk_get(dev, "vp");
- if (IS_ERR_OR_NULL(res->vp)) {
- mxr_err(mdev, "failed to get clock 'vp'\n");
- goto fail;
- }
- res->sclk_mixer = clk_get(dev, "sclk_mixer");
- if (IS_ERR_OR_NULL(res->sclk_mixer)) {
- mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
- goto fail;
- }
- res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
- mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
- goto fail;
- }
- res->sclk_dac = clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(res->sclk_dac)) {
- mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
- goto fail;
- }
-
- return 0;
-fail:
- mxr_release_clocks(mdev);
- return -ENODEV;
-}
-
-static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
- struct platform_device *pdev)
-{
- int ret;
- ret = mxr_acquire_plat_resources(mdev, pdev);
-
- if (ret)
- goto fail;
-
- ret = mxr_acquire_clocks(mdev);
- if (ret)
- goto fail_plat;
-
- mxr_info(mdev, "resources acquired\n");
- return 0;
-
-fail_plat:
- mxr_release_plat_resources(mdev);
-fail:
- mxr_err(mdev, "resources acquire failed\n");
- return ret;
-}
-
-static void mxr_release_resources(struct mxr_device *mdev)
-{
- mxr_release_clocks(mdev);
- mxr_release_plat_resources(mdev);
- memset(&mdev->res, 0, sizeof mdev->res);
-}
-
-static void mxr_release_layers(struct mxr_device *mdev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
- if (mdev->layer[i])
- mxr_layer_release(mdev->layer[i]);
-}
-
-static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
- struct mxr_platform_data *pdata)
-{
- mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
- mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
- mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
-
- if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
- mxr_err(mdev, "failed to acquire layers\n");
- goto fail;
- }
-
- return 0;
-
-fail:
- mxr_release_layers(mdev);
- return -ENODEV;
-}
-
-/* ---------- POWER MANAGEMENT ----------- */
-
-static int mxr_runtime_resume(struct device *dev)
-{
- struct mxr_device *mdev = to_mdev(dev);
- struct mxr_resources *res = &mdev->res;
-
- mxr_dbg(mdev, "resume - start\n");
- mutex_lock(&mdev->mutex);
- /* turn clocks on */
- clk_enable(res->mixer);
- clk_enable(res->vp);
- clk_enable(res->sclk_mixer);
- /* apply default configuration */
- mxr_reg_reset(mdev);
- mxr_dbg(mdev, "resume - finished\n");
-
- mutex_unlock(&mdev->mutex);
- return 0;
-}
-
-static int mxr_runtime_suspend(struct device *dev)
-{
- struct mxr_device *mdev = to_mdev(dev);
- struct mxr_resources *res = &mdev->res;
- mxr_dbg(mdev, "suspend - start\n");
- mutex_lock(&mdev->mutex);
- /* turn clocks off */
- clk_disable(res->sclk_mixer);
- clk_disable(res->vp);
- clk_disable(res->mixer);
- mutex_unlock(&mdev->mutex);
- mxr_dbg(mdev, "suspend - finished\n");
- return 0;
-}
-
-static const struct dev_pm_ops mxr_pm_ops = {
- .runtime_suspend = mxr_runtime_suspend,
- .runtime_resume = mxr_runtime_resume,
-};
-
-/* --------- DRIVER INITIALIZATION ---------- */
-
-static int __devinit mxr_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mxr_platform_data *pdata = dev->platform_data;
- struct mxr_device *mdev;
- int ret;
-
- /* mdev does not exist yet so no mxr_dbg is used */
- dev_info(dev, "probe start\n");
-
- mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
- if (!mdev) {
- mxr_err(mdev, "not enough memory.\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- /* setup pointer to master device */
- mdev->dev = dev;
-
- mutex_init(&mdev->mutex);
- spin_lock_init(&mdev->reg_slock);
- init_waitqueue_head(&mdev->event_queue);
-
- /* acquire resources: regs, irqs, clocks, regulators */
- ret = mxr_acquire_resources(mdev, pdev);
- if (ret)
- goto fail_mem;
-
- /* configure resources for video output */
- ret = mxr_acquire_video(mdev, mxr_output_conf,
- ARRAY_SIZE(mxr_output_conf));
- if (ret)
- goto fail_resources;
-
- /* configure layers */
- ret = mxr_acquire_layers(mdev, pdata);
- if (ret)
- goto fail_video;
-
- pm_runtime_enable(dev);
-
- mxr_info(mdev, "probe successful\n");
- return 0;
-
-fail_video:
- mxr_release_video(mdev);
-
-fail_resources:
- mxr_release_resources(mdev);
-
-fail_mem:
- kfree(mdev);
-
-fail:
- dev_info(dev, "probe failed\n");
- return ret;
-}
-
-static int __devexit mxr_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mxr_device *mdev = to_mdev(dev);
-
- pm_runtime_disable(dev);
-
- mxr_release_layers(mdev);
- mxr_release_video(mdev);
- mxr_release_resources(mdev);
-
- kfree(mdev);
-
- dev_info(dev, "remove successful\n");
- return 0;
-}
-
-static struct platform_driver mxr_driver __refdata = {
- .probe = mxr_probe,
- .remove = __devexit_p(mxr_remove),
- .driver = {
- .name = MXR_DRIVER_NAME,
- .owner = THIS_MODULE,
- .pm = &mxr_pm_ops,
- }
-};
-
-static int __init mxr_init(void)
-{
- int i, ret;
- static const char banner[] __initconst = KERN_INFO
- "Samsung TV Mixer driver, "
- "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
- printk(banner);
-
- /* Loading auxiliary modules */
- for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
- request_module(mxr_output_conf[i].module_name);
-
- ret = platform_driver_register(&mxr_driver);
- if (ret != 0) {
- printk(KERN_ERR "registration of MIXER driver failed\n");
- return -ENXIO;
- }
-
- return 0;
-}
-module_init(mxr_init);
-
-static void __exit mxr_exit(void)
-{
- platform_driver_unregister(&mxr_driver);
-}
-module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
deleted file mode 100644
index 6c74b05d1f95..000000000000
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Samsung TV Mixer driver
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *
- * 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 "mixer.h"
-
-#include <media/v4l2-ioctl.h>
-#include <linux/videodev2.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/timer.h>
-#include <media/videobuf2-dma-contig.h>
-
-static int find_reg_callback(struct device *dev, void *p)
-{
- struct v4l2_subdev **sd = p;
-
- *sd = dev_get_drvdata(dev);
- /* non-zero value stops iteration */
- return 1;
-}
-
-static struct v4l2_subdev *find_and_register_subdev(
- struct mxr_device *mdev, char *module_name)
-{
- struct device_driver *drv;
- struct v4l2_subdev *sd = NULL;
- int ret;
-
- /* TODO: add waiting until probe is finished */
- drv = driver_find(module_name, &platform_bus_type);
- if (!drv) {
- mxr_warn(mdev, "module %s is missing\n", module_name);
- return NULL;
- }
- /* driver refcnt is increased, it is safe to iterate over devices */
- ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
- /* ret == 0 means that find_reg_callback was never executed */
- if (sd == NULL) {
- mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
- goto done;
- }
- /* v4l2_device_register_subdev detects if sd is NULL */
- ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
- if (ret) {
- mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
- sd = NULL;
- }
-
-done:
- return sd;
-}
-
-int __devinit mxr_acquire_video(struct mxr_device *mdev,
- struct mxr_output_conf *output_conf, int output_count)
-{
- struct device *dev = mdev->dev;
- struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
- int i;
- int ret = 0;
- struct v4l2_subdev *sd;
-
- strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
- /* prepare context for V4L2 device */
- ret = v4l2_device_register(dev, v4l2_dev);
- if (ret) {
- mxr_err(mdev, "could not register v4l2 device.\n");
- goto fail;
- }
-
- mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
- if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
- mxr_err(mdev, "could not acquire vb2 allocator\n");
- goto fail_v4l2_dev;
- }
-
- /* registering outputs */
- mdev->output_cnt = 0;
- for (i = 0; i < output_count; ++i) {
- struct mxr_output_conf *conf = &output_conf[i];
- struct mxr_output *out;
-
- sd = find_and_register_subdev(mdev, conf->module_name);
- /* trying to register next output */
- if (sd == NULL)
- continue;
- out = kzalloc(sizeof *out, GFP_KERNEL);
- if (out == NULL) {
- mxr_err(mdev, "no memory for '%s'\n",
- conf->output_name);
- ret = -ENOMEM;
- /* registered subdevs are removed in fail_v4l2_dev */
- goto fail_output;
- }
- strlcpy(out->name, conf->output_name, sizeof(out->name));
- out->sd = sd;
- out->cookie = conf->cookie;
- mdev->output[mdev->output_cnt++] = out;
- mxr_info(mdev, "added output '%s' from module '%s'\n",
- conf->output_name, conf->module_name);
- /* checking if maximal number of outputs is reached */
- if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
- break;
- }
-
- if (mdev->output_cnt == 0) {
- mxr_err(mdev, "failed to register any output\n");
- ret = -ENODEV;
- /* skipping fail_output because there is nothing to free */
- goto fail_vb2_allocator;
- }
-
- return 0;
-
-fail_output:
- /* kfree is NULL-safe */
- for (i = 0; i < mdev->output_cnt; ++i)
- kfree(mdev->output[i]);
- memset(mdev->output, 0, sizeof mdev->output);
-
-fail_vb2_allocator:
- /* freeing allocator context */
- vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
-
-fail_v4l2_dev:
- /* NOTE: automatically unregister all subdevs */
- v4l2_device_unregister(v4l2_dev);
-
-fail:
- return ret;
-}
-
-void mxr_release_video(struct mxr_device *mdev)
-{
- int i;
-
- /* kfree is NULL-safe */
- for (i = 0; i < mdev->output_cnt; ++i)
- kfree(mdev->output[i]);
-
- vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
- v4l2_device_unregister(&mdev->v4l2_dev);
-}
-
-static int mxr_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-
- strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
- strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
- sprintf(cap->bus_info, "%d", layer->idx);
- cap->version = KERNEL_VERSION(0, 1, 0);
- cap->capabilities = V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
-
- return 0;
-}
-
-static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
-{
- 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)
-{
- struct mxr_device *mdev = layer->mdev;
- struct v4l2_mbus_framefmt mbus_fmt;
-
- memset(&layer->geo, 0, sizeof layer->geo);
-
- 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.width = layer->geo.dst.full_width;
- layer->geo.dst.height = layer->geo.dst.full_height;
- layer->geo.dst.field = mbus_fmt.field;
-
- layer->geo.src.full_width = mbus_fmt.width;
- layer->geo.src.full_height = mbus_fmt.height;
- layer->geo.src.width = layer->geo.src.full_width;
- layer->geo.src.height = layer->geo.src.full_height;
-
- mxr_geometry_dump(mdev, &layer->geo);
- layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
- mxr_geometry_dump(mdev, &layer->geo);
-}
-
-static void mxr_layer_update_output(struct mxr_layer *layer)
-{
- 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);
-static const struct mxr_format *find_format_by_index(
- struct mxr_layer *layer, unsigned long index);
-
-static int mxr_enum_fmt(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- const struct mxr_format *fmt;
-
- mxr_dbg(mdev, "%s\n", __func__);
- fmt = find_format_by_index(layer, f->index);
- if (fmt == NULL)
- return -EINVAL;
-
- strlcpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
-
- return 0;
-}
-
-static unsigned int divup(unsigned int divident, unsigned int divisor)
-{
- return (divident + divisor - 1) / divisor;
-}
-
-unsigned long mxr_get_plane_size(const struct mxr_block *blk,
- unsigned int width, unsigned int height)
-{
- unsigned int bl_width = divup(width, blk->width);
- unsigned int bl_height = divup(height, blk->height);
-
- return bl_width * bl_height * blk->size;
-}
-
-static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
- const struct mxr_format *fmt, u32 width, u32 height)
-{
- 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
- + fmt->plane2subframe[i];
- const struct mxr_block *blk = &fmt->plane[i];
- u32 bl_width = divup(width, blk->width);
- u32 bl_height = divup(height, blk->height);
- u32 sizeimage = bl_width * bl_height * blk->size;
- u16 bytesperline = bl_width * blk->size / blk->height;
-
- plane->sizeimage += sizeimage;
- plane->bytesperline = max(plane->bytesperline, bytesperline);
- }
-}
-
-static int mxr_g_fmt(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-
- pix->width = layer->geo.src.full_width;
- pix->height = layer->geo.src.full_height;
- pix->field = V4L2_FIELD_NONE;
- pix->pixelformat = layer->fmt->fourcc;
- pix->colorspace = layer->fmt->colorspace;
- mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
-
- 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;
- /* 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_g_selection(struct file *file, void *fh,
- struct v4l2_selection *s)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_geometry *geo = &layer->geo;
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-
- 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:
- 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:
- 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;
- }
-
- return 0;
-}
-
-/* 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_geometry *geo = &layer->geo;
- struct mxr_crop *target = NULL;
- enum mxr_geometry_stage stage;
- struct mxr_geometry tmp;
- struct v4l2_rect res;
-
- 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;
-
- 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:
- target = &geo->src;
- stage = MXR_GEOMETRY_CROP;
- break;
- case V4L2_SEL_TGT_COMPOSE:
- 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,
- struct v4l2_dv_enum_preset *preset)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- /* lock protects from changing sd_out */
- mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
- mutex_unlock(&mdev->mutex);
-
- return ret ? -EINVAL : 0;
-}
-
-static int mxr_s_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- /* lock protects from changing sd_out */
- mutex_lock(&mdev->mutex);
-
- /* preset change cannot be done while there is an entity
- * dependant on output configuration
- */
- if (mdev->n_output > 0) {
- mutex_unlock(&mdev->mutex);
- return -EBUSY;
- }
-
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
-
- mutex_unlock(&mdev->mutex);
-
- mxr_layer_update_output(layer);
-
- /* any failure should return EINVAL according to V4L2 doc */
- return ret ? -EINVAL : 0;
-}
-
-static int mxr_g_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- /* lock protects from changing sd_out */
- mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
- mutex_unlock(&mdev->mutex);
-
- return ret ? -EINVAL : 0;
-}
-
-static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- /* lock protects from changing sd_out */
- mutex_lock(&mdev->mutex);
-
- /* standard change cannot be done while there is an entity
- * dependant on output configuration
- */
- if (mdev->n_output > 0) {
- mutex_unlock(&mdev->mutex);
- return -EBUSY;
- }
-
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
-
- mutex_unlock(&mdev->mutex);
-
- mxr_layer_update_output(layer);
-
- return ret ? -EINVAL : 0;
-}
-
-static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- /* lock protects from changing sd_out */
- mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
- mutex_unlock(&mdev->mutex);
-
- return ret ? -EINVAL : 0;
-}
-
-static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- struct mxr_output *out;
- struct v4l2_subdev *sd;
-
- if (a->index >= mdev->output_cnt)
- return -EINVAL;
- out = mdev->output[a->index];
- BUG_ON(out == NULL);
- sd = out->sd;
- strlcpy(a->name, out->name, sizeof(a->name));
-
- /* try to obtain supported tv norms */
- v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
- a->capabilities = 0;
- if (sd->ops->video && sd->ops->video->s_dv_preset)
- a->capabilities |= V4L2_OUT_CAP_PRESETS;
- if (sd->ops->video && sd->ops->video->s_std_output)
- a->capabilities |= V4L2_OUT_CAP_STD;
- a->type = V4L2_OUTPUT_TYPE_ANALOG;
-
- return 0;
-}
-
-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;
-
- if (i >= mdev->output_cnt || mdev->output[i] == NULL)
- return -EINVAL;
-
- mutex_lock(&mdev->mutex);
- if (mdev->n_output > 0) {
- 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);
-
- return 0;
-}
-
-static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
-
- mutex_lock(&mdev->mutex);
- *p = mdev->current_output;
- mutex_unlock(&mdev->mutex);
-
- return 0;
-}
-
-static int mxr_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- return vb2_reqbufs(&layer->vb_queue, p);
-}
-
-static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- return vb2_querybuf(&layer->vb_queue, p);
-}
-
-static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
- return vb2_qbuf(&layer->vb_queue, p);
-}
-
-static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
-}
-
-static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- return vb2_streamon(&layer->vb_queue, i);
-}
-
-static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- return vb2_streamoff(&layer->vb_queue, i);
-}
-
-static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
- .vidioc_querycap = mxr_querycap,
- /* format handling */
- .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
- .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
- .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
- /* buffer control */
- .vidioc_reqbufs = mxr_reqbufs,
- .vidioc_querybuf = mxr_querybuf,
- .vidioc_qbuf = mxr_qbuf,
- .vidioc_dqbuf = mxr_dqbuf,
- /* Streaming control */
- .vidioc_streamon = mxr_streamon,
- .vidioc_streamoff = mxr_streamoff,
- /* Preset functions */
- .vidioc_enum_dv_presets = mxr_enum_dv_presets,
- .vidioc_s_dv_preset = mxr_s_dv_preset,
- .vidioc_g_dv_preset = mxr_g_dv_preset,
- /* analog TV standard functions */
- .vidioc_s_std = mxr_s_std,
- .vidioc_g_std = mxr_g_std,
- /* Output handling */
- .vidioc_enum_output = mxr_enum_output,
- .vidioc_s_output = mxr_s_output,
- .vidioc_g_output = mxr_g_output,
- /* selection ioctls */
- .vidioc_g_selection = mxr_g_selection,
- .vidioc_s_selection = mxr_s_selection,
-};
-
-static int mxr_video_open(struct file *file)
-{
- struct mxr_layer *layer = video_drvdata(file);
- struct mxr_device *mdev = layer->mdev;
- int ret = 0;
-
- mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
- /* assure device probe is finished */
- wait_for_device_probe();
- /* creating context for file descriptor */
- ret = v4l2_fh_open(file);
- if (ret) {
- mxr_err(mdev, "v4l2_fh_open failed\n");
- return ret;
- }
-
- /* leaving if layer is already initialized */
- if (!v4l2_fh_is_singular_file(file))
- return 0;
-
- /* FIXME: should power be enabled on open? */
- ret = mxr_power_get(mdev);
- if (ret) {
- mxr_err(mdev, "power on failed\n");
- goto fail_fh_open;
- }
-
- ret = vb2_queue_init(&layer->vb_queue);
- if (ret != 0) {
- mxr_err(mdev, "failed to initialize vb2 queue\n");
- goto fail_power;
- }
- /* set default format, first on the list */
- layer->fmt = layer->fmt_array[0];
- /* setup default geometry */
- mxr_layer_default_geo(layer);
-
- return 0;
-
-fail_power:
- mxr_power_put(mdev);
-
-fail_fh_open:
- v4l2_fh_release(file);
-
- return ret;
-}
-
-static unsigned int
-mxr_video_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-
- return vb2_poll(&layer->vb_queue, file, wait);
-}
-
-static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-
- return vb2_mmap(&layer->vb_queue, vma);
-}
-
-static int mxr_video_release(struct file *file)
-{
- struct mxr_layer *layer = video_drvdata(file);
-
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- if (v4l2_fh_is_singular_file(file)) {
- vb2_queue_release(&layer->vb_queue);
- mxr_power_put(layer->mdev);
- }
- v4l2_fh_release(file);
- return 0;
-}
-
-static const struct v4l2_file_operations mxr_fops = {
- .owner = THIS_MODULE,
- .open = mxr_video_open,
- .poll = mxr_video_poll,
- .mmap = mxr_video_mmap,
- .release = mxr_video_release,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
- unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[],
- void *alloc_ctxs[])
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
- const struct mxr_format *fmt = layer->fmt;
- int i;
- struct mxr_device *mdev = layer->mdev;
- struct v4l2_plane_pix_format planes[3];
-
- mxr_dbg(mdev, "%s\n", __func__);
- /* checking if format was configured */
- if (fmt == NULL)
- return -EINVAL;
- mxr_dbg(mdev, "fmt = %s\n", fmt->name);
- mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
- layer->geo.src.full_height);
-
- *nplanes = fmt->num_subframes;
- for (i = 0; i < fmt->num_subframes; ++i) {
- alloc_ctxs[i] = layer->mdev->alloc_ctx;
- sizes[i] = planes[i].sizeimage;
- mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
- }
-
- if (*nbuffers == 0)
- *nbuffers = 1;
-
- return 0;
-}
-
-static void buf_queue(struct vb2_buffer *vb)
-{
- struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
- struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
- struct mxr_device *mdev = layer->mdev;
- unsigned long flags;
-
- spin_lock_irqsave(&layer->enq_slock, flags);
- list_add_tail(&buffer->list, &layer->enq_list);
- spin_unlock_irqrestore(&layer->enq_slock, flags);
-
- mxr_dbg(mdev, "queuing buffer\n");
-}
-
-static void wait_lock(struct vb2_queue *vq)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
-
- mxr_dbg(layer->mdev, "%s\n", __func__);
- mutex_lock(&layer->mutex);
-}
-
-static void wait_unlock(struct vb2_queue *vq)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
-
- mxr_dbg(layer->mdev, "%s\n", __func__);
- mutex_unlock(&layer->mutex);
-}
-
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
- struct mxr_device *mdev = layer->mdev;
- unsigned long flags;
-
- mxr_dbg(mdev, "%s\n", __func__);
-
- if (count == 0) {
- mxr_dbg(mdev, "no output buffers queued\n");
- return -EINVAL;
- }
-
- /* block any changes in output configuration */
- mxr_output_get(mdev);
-
- mxr_layer_update_output(layer);
- layer->ops.format_set(layer);
- /* enabling layer in hardware */
- spin_lock_irqsave(&layer->enq_slock, flags);
- layer->state = MXR_LAYER_STREAMING;
- spin_unlock_irqrestore(&layer->enq_slock, flags);
-
- layer->ops.stream_set(layer, MXR_ENABLE);
- mxr_streamer_get(mdev);
-
- return 0;
-}
-
-static void mxr_watchdog(unsigned long arg)
-{
- struct mxr_layer *layer = (struct mxr_layer *) arg;
- struct mxr_device *mdev = layer->mdev;
- unsigned long flags;
-
- mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
-
- spin_lock_irqsave(&layer->enq_slock, flags);
-
- if (layer->update_buf == layer->shadow_buf)
- layer->update_buf = NULL;
- if (layer->update_buf) {
- vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
- layer->update_buf = NULL;
- }
- if (layer->shadow_buf) {
- vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
- layer->shadow_buf = NULL;
- }
- spin_unlock_irqrestore(&layer->enq_slock, flags);
-}
-
-static int stop_streaming(struct vb2_queue *vq)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
- struct mxr_device *mdev = layer->mdev;
- unsigned long flags;
- struct timer_list watchdog;
- struct mxr_buffer *buf, *buf_tmp;
-
- mxr_dbg(mdev, "%s\n", __func__);
-
- spin_lock_irqsave(&layer->enq_slock, flags);
-
- /* reset list */
- layer->state = MXR_LAYER_STREAMING_FINISH;
-
- /* set all buffer to be done */
- list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
- list_del(&buf->list);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
- }
-
- spin_unlock_irqrestore(&layer->enq_slock, flags);
-
- /* give 1 seconds to complete to complete last buffers */
- setup_timer_on_stack(&watchdog, mxr_watchdog,
- (unsigned long)layer);
- mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
-
- /* wait until all buffers are goes to done state */
- vb2_wait_for_all_buffers(vq);
-
- /* stop timer if all synchronization is done */
- del_timer_sync(&watchdog);
- destroy_timer_on_stack(&watchdog);
-
- /* stopping hardware */
- spin_lock_irqsave(&layer->enq_slock, flags);
- layer->state = MXR_LAYER_IDLE;
- spin_unlock_irqrestore(&layer->enq_slock, flags);
-
- /* disabling layer in hardware */
- layer->ops.stream_set(layer, MXR_DISABLE);
- /* remove one streamer */
- mxr_streamer_put(mdev);
- /* allow changes in output configuration */
- mxr_output_put(mdev);
- return 0;
-}
-
-static struct vb2_ops mxr_video_qops = {
- .queue_setup = queue_setup,
- .buf_queue = buf_queue,
- .wait_prepare = wait_unlock,
- .wait_finish = wait_lock,
- .start_streaming = start_streaming,
- .stop_streaming = stop_streaming,
-};
-
-/* FIXME: try to put this functions to mxr_base_layer_create */
-int mxr_base_layer_register(struct mxr_layer *layer)
-{
- struct mxr_device *mdev = layer->mdev;
- int ret;
-
- ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
- if (ret)
- mxr_err(mdev, "failed to register video device\n");
- else
- mxr_info(mdev, "registered layer %s as /dev/video%d\n",
- layer->vfd.name, layer->vfd.num);
- return ret;
-}
-
-void mxr_base_layer_unregister(struct mxr_layer *layer)
-{
- video_unregister_device(&layer->vfd);
-}
-
-void mxr_layer_release(struct mxr_layer *layer)
-{
- if (layer->ops.release)
- layer->ops.release(layer);
-}
-
-void mxr_base_layer_release(struct mxr_layer *layer)
-{
- kfree(layer);
-}
-
-static void mxr_vfd_release(struct video_device *vdev)
-{
- printk(KERN_INFO "video device release\n");
-}
-
-struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
- int idx, char *name, struct mxr_layer_ops *ops)
-{
- struct mxr_layer *layer;
-
- layer = kzalloc(sizeof *layer, GFP_KERNEL);
- if (layer == NULL) {
- mxr_err(mdev, "not enough memory for layer.\n");
- goto fail;
- }
-
- layer->mdev = mdev;
- layer->idx = idx;
- layer->ops = *ops;
-
- spin_lock_init(&layer->enq_slock);
- INIT_LIST_HEAD(&layer->enq_list);
- mutex_init(&layer->mutex);
-
- layer->vfd = (struct video_device) {
- .minor = -1,
- .release = mxr_vfd_release,
- .fops = &mxr_fops,
- .ioctl_ops = &mxr_ioctl_ops,
- };
- strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
- /* let framework control PRIORITY */
- set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
-
- video_set_drvdata(&layer->vfd, layer);
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &layer->vfd.flags);
- layer->vfd.lock = &layer->mutex;
- layer->vfd.v4l2_dev = &mdev->v4l2_dev;
-
- layer->vb_queue = (struct vb2_queue) {
- .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .io_modes = VB2_MMAP | VB2_USERPTR,
- .drv_priv = layer,
- .buf_struct_size = sizeof(struct mxr_buffer),
- .ops = &mxr_video_qops,
- .mem_ops = &vb2_dma_contig_memops,
- };
-
- return layer;
-
-fail:
- return NULL;
-}
-
-static const struct mxr_format *find_format_by_fourcc(
- struct mxr_layer *layer, unsigned long fourcc)
-{
- int i;
-
- for (i = 0; i < layer->fmt_array_size; ++i)
- if (layer->fmt_array[i]->fourcc == fourcc)
- return layer->fmt_array[i];
- return NULL;
-}
-
-static const struct mxr_format *find_format_by_index(
- struct mxr_layer *layer, unsigned long index)
-{
- if (index >= layer->fmt_array_size)
- return NULL;
- return layer->fmt_array[index];
-}
-
diff --git a/drivers/media/video/s5p-tv/regs-sdo.h b/drivers/media/video/s5p-tv/regs-sdo.h
deleted file mode 100644
index 7f7c2b8ac140..000000000000
--- a/drivers/media/video/s5p-tv/regs-sdo.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* drivers/media/video/s5p-tv/regs-sdo.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * SDO register description file
- *
- * 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 SAMSUNG_REGS_SDO_H
-#define SAMSUNG_REGS_SDO_H
-
-/*
- * Register part
- */
-
-#define SDO_CLKCON 0x0000
-#define SDO_CONFIG 0x0008
-#define SDO_VBI 0x0014
-#define SDO_DAC 0x003C
-#define SDO_CCCON 0x0180
-#define SDO_IRQ 0x0280
-#define SDO_IRQMASK 0x0284
-#define SDO_VERSION 0x03D8
-
-/*
- * Bit definition part
- */
-
-/* SDO Clock Control Register (SDO_CLKCON) */
-#define SDO_TVOUT_SW_RESET (1 << 4)
-#define SDO_TVOUT_CLOCK_READY (1 << 1)
-#define SDO_TVOUT_CLOCK_ON (1 << 0)
-
-/* SDO Video Standard Configuration Register (SDO_CONFIG) */
-#define SDO_PROGRESSIVE (1 << 4)
-#define SDO_NTSC_M 0
-#define SDO_PAL_M 1
-#define SDO_PAL_BGHID 2
-#define SDO_PAL_N 3
-#define SDO_PAL_NC 4
-#define SDO_NTSC_443 8
-#define SDO_PAL_60 9
-#define SDO_STANDARD_MASK 0xf
-
-/* SDO VBI Configuration Register (SDO_VBI) */
-#define SDO_CVBS_WSS_INS (1 << 14)
-#define SDO_CVBS_CLOSED_CAPTION_MASK (3 << 12)
-
-/* SDO DAC Configuration Register (SDO_DAC) */
-#define SDO_POWER_ON_DAC (1 << 0)
-
-/* SDO Color Compensation On/Off Control (SDO_CCCON) */
-#define SDO_COMPENSATION_BHS_ADJ_OFF (1 << 4)
-#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
-
-/* SDO Interrupt Request Register (SDO_IRQ) */
-#define SDO_VSYNC_IRQ_PEND (1 << 0)
-
-#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
deleted file mode 100644
index f6bca2c20e89..000000000000
--- a/drivers/media/video/s5p-tv/sdo_drv.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Samsung Standard Definition Output (SDO) driver
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *
- * 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 Foundiation. either version 2 of the License,
- * or (at your option) any later version
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-
-#include <media/v4l2-subdev.h>
-
-#include "regs-sdo.h"
-
-MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
-MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
-MODULE_LICENSE("GPL");
-
-#define SDO_DEFAULT_STD V4L2_STD_PAL
-
-struct sdo_format {
- v4l2_std_id id;
- /* all modes are 720 pixels wide */
- unsigned int height;
- unsigned int cookie;
-};
-
-struct sdo_device {
- /** pointer to device parent */
- struct device *dev;
- /** base address of SDO registers */
- void __iomem *regs;
- /** SDO interrupt */
- unsigned int irq;
- /** DAC source clock */
- struct clk *sclk_dac;
- /** DAC clock */
- struct clk *dac;
- /** DAC physical interface */
- struct clk *dacphy;
- /** clock for control of VPLL */
- struct clk *fout_vpll;
- /** regulator for SDO IP power */
- struct regulator *vdac;
- /** regulator for SDO plug detection */
- struct regulator *vdet;
- /** subdev used as device interface */
- struct v4l2_subdev sd;
- /** current format */
- const struct sdo_format *fmt;
-};
-
-static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct sdo_device, sd);
-}
-
-static inline
-void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
-{
- u32 old = readl(sdev->regs + reg_id);
- value = (value & mask) | (old & ~mask);
- writel(value, sdev->regs + reg_id);
-}
-
-static inline
-void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
-{
- writel(value, sdev->regs + reg_id);
-}
-
-static inline
-u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
-{
- return readl(sdev->regs + reg_id);
-}
-
-static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
-{
- struct sdo_device *sdev = dev_data;
-
- /* clear interrupt */
- sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
- return IRQ_HANDLED;
-}
-
-static void sdo_reg_debug(struct sdo_device *sdev)
-{
-#define DBGREG(reg_id) \
- dev_info(sdev->dev, #reg_id " = %08x\n", \
- sdo_read(sdev, reg_id))
-
- DBGREG(SDO_CLKCON);
- DBGREG(SDO_CONFIG);
- DBGREG(SDO_VBI);
- DBGREG(SDO_DAC);
- DBGREG(SDO_IRQ);
- DBGREG(SDO_IRQMASK);
- DBGREG(SDO_VERSION);
-}
-
-static const struct sdo_format sdo_format[] = {
- { V4L2_STD_PAL_N, .height = 576, .cookie = SDO_PAL_N },
- { V4L2_STD_PAL_Nc, .height = 576, .cookie = SDO_PAL_NC },
- { V4L2_STD_PAL_M, .height = 480, .cookie = SDO_PAL_M },
- { V4L2_STD_PAL_60, .height = 480, .cookie = SDO_PAL_60 },
- { V4L2_STD_NTSC_443, .height = 480, .cookie = SDO_NTSC_443 },
- { V4L2_STD_PAL, .height = 576, .cookie = SDO_PAL_BGHID },
- { V4L2_STD_NTSC_M, .height = 480, .cookie = SDO_NTSC_M },
-};
-
-static const struct sdo_format *sdo_find_format(v4l2_std_id id)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
- if (sdo_format[i].id & id)
- return &sdo_format[i];
- return NULL;
-}
-
-static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
-{
- *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
- V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
- V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
- return 0;
-}
-
-static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
-{
- struct sdo_device *sdev = sd_to_sdev(sd);
- const struct sdo_format *fmt;
- fmt = sdo_find_format(std);
- if (fmt == NULL)
- return -EINVAL;
- sdev->fmt = fmt;
- return 0;
-}
-
-static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
-{
- *std = sd_to_sdev(sd)->fmt->id;
- return 0;
-}
-
-static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
-{
- struct sdo_device *sdev = sd_to_sdev(sd);
-
- if (!sdev->fmt)
- return -ENXIO;
- /* all modes are 720 pixels wide */
- fmt->width = 720;
- fmt->height = sdev->fmt->height;
- fmt->code = V4L2_MBUS_FMT_FIXED;
- fmt->field = V4L2_FIELD_INTERLACED;
- fmt->colorspace = V4L2_COLORSPACE_JPEG;
- return 0;
-}
-
-static int sdo_s_power(struct v4l2_subdev *sd, int on)
-{
- struct sdo_device *sdev = sd_to_sdev(sd);
- struct device *dev = sdev->dev;
- int ret;
-
- dev_info(dev, "sdo_s_power(%d)\n", on);
-
- if (on)
- ret = pm_runtime_get_sync(dev);
- else
- ret = pm_runtime_put_sync(dev);
-
- /* only values < 0 indicate errors */
- return IS_ERR_VALUE(ret) ? ret : 0;
-}
-
-static int sdo_streamon(struct sdo_device *sdev)
-{
- /* set proper clock for Timing Generator */
- clk_set_rate(sdev->fout_vpll, 54000000);
- dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
- clk_get_rate(sdev->fout_vpll));
- /* enable clock in SDO */
- sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
- clk_enable(sdev->dacphy);
- /* enable DAC */
- sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
- sdo_reg_debug(sdev);
- return 0;
-}
-
-static int sdo_streamoff(struct sdo_device *sdev)
-{
- int tries;
-
- sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
- clk_disable(sdev->dacphy);
- sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
- for (tries = 100; tries; --tries) {
- if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
- break;
- mdelay(1);
- }
- if (tries == 0)
- dev_err(sdev->dev, "failed to stop streaming\n");
- return tries ? 0 : -EIO;
-}
-
-static int sdo_s_stream(struct v4l2_subdev *sd, int on)
-{
- struct sdo_device *sdev = sd_to_sdev(sd);
- return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
-}
-
-static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
- .s_power = sdo_s_power,
-};
-
-static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
- .s_std_output = sdo_s_std_output,
- .g_std_output = sdo_g_std_output,
- .g_tvnorms_output = sdo_g_tvnorms_output,
- .g_mbus_fmt = sdo_g_mbus_fmt,
- .s_stream = sdo_s_stream,
-};
-
-static const struct v4l2_subdev_ops sdo_sd_ops = {
- .core = &sdo_sd_core_ops,
- .video = &sdo_sd_video_ops,
-};
-
-static int sdo_runtime_suspend(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct sdo_device *sdev = sd_to_sdev(sd);
-
- dev_info(dev, "suspend\n");
- regulator_disable(sdev->vdet);
- regulator_disable(sdev->vdac);
- clk_disable(sdev->sclk_dac);
- return 0;
-}
-
-static int sdo_runtime_resume(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct sdo_device *sdev = sd_to_sdev(sd);
-
- dev_info(dev, "resume\n");
- clk_enable(sdev->sclk_dac);
- regulator_enable(sdev->vdac);
- regulator_enable(sdev->vdet);
-
- /* software reset */
- sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
- mdelay(10);
- sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
-
- /* setting TV mode */
- sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
- /* XXX: forcing interlaced mode using undocumented bit */
- sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
- /* turn all VBI off */
- sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
- SDO_CVBS_CLOSED_CAPTION_MASK);
- /* turn all post processing off */
- sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
- SDO_COMPENSATION_CVBS_COMP_OFF);
- sdo_reg_debug(sdev);
- return 0;
-}
-
-static const struct dev_pm_ops sdo_pm_ops = {
- .runtime_suspend = sdo_runtime_suspend,
- .runtime_resume = sdo_runtime_resume,
-};
-
-static int __devinit sdo_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct sdo_device *sdev;
- struct resource *res;
- int ret = 0;
- struct clk *sclk_vpll;
-
- dev_info(dev, "probe start\n");
- sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
- if (!sdev) {
- dev_err(dev, "not enough memory.\n");
- ret = -ENOMEM;
- goto fail;
- }
- sdev->dev = dev;
-
- /* mapping registers */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(dev, "get memory resource failed.\n");
- ret = -ENXIO;
- goto fail;
- }
-
- 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;
- }
-
- /* acquiring interrupt */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(dev, "get interrupt resource failed.\n");
- ret = -ENXIO;
- goto fail;
- }
- 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;
- }
- sdev->irq = res->start;
-
- /* acquire clocks */
- sdev->sclk_dac = clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
- dev_err(dev, "failed to get clock 'sclk_dac'\n");
- ret = -ENXIO;
- goto fail;
- }
- sdev->dac = clk_get(dev, "dac");
- if (IS_ERR_OR_NULL(sdev->dac)) {
- dev_err(dev, "failed to get clock 'dac'\n");
- ret = -ENXIO;
- goto fail_sclk_dac;
- }
- sdev->dacphy = clk_get(dev, "dacphy");
- if (IS_ERR_OR_NULL(sdev->dacphy)) {
- dev_err(dev, "failed to get clock 'dacphy'\n");
- ret = -ENXIO;
- goto fail_dac;
- }
- sclk_vpll = clk_get(dev, "sclk_vpll");
- if (IS_ERR_OR_NULL(sclk_vpll)) {
- dev_err(dev, "failed to get clock 'sclk_vpll'\n");
- ret = -ENXIO;
- goto fail_dacphy;
- }
- clk_set_parent(sdev->sclk_dac, sclk_vpll);
- clk_put(sclk_vpll);
- sdev->fout_vpll = clk_get(dev, "fout_vpll");
- if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
- dev_err(dev, "failed to get clock 'fout_vpll'\n");
- goto fail_dacphy;
- }
- dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
-
- /* acquire regulator */
- sdev->vdac = regulator_get(dev, "vdd33a_dac");
- if (IS_ERR_OR_NULL(sdev->vdac)) {
- dev_err(dev, "failed to get regulator 'vdac'\n");
- goto fail_fout_vpll;
- }
- sdev->vdet = regulator_get(dev, "vdet");
- if (IS_ERR_OR_NULL(sdev->vdet)) {
- dev_err(dev, "failed to get regulator 'vdet'\n");
- goto fail_vdac;
- }
-
- /* enable gate for dac clock, because mixer uses it */
- clk_enable(sdev->dac);
-
- /* configure power management */
- pm_runtime_enable(dev);
-
- /* configuration of interface subdevice */
- v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
- sdev->sd.owner = THIS_MODULE;
- strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
-
- /* set default format */
- sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
- BUG_ON(sdev->fmt == NULL);
-
- /* keeping subdev in device's private for use by other drivers */
- dev_set_drvdata(dev, &sdev->sd);
-
- dev_info(dev, "probe succeeded\n");
- return 0;
-
-fail_vdac:
- regulator_put(sdev->vdac);
-fail_fout_vpll:
- clk_put(sdev->fout_vpll);
-fail_dacphy:
- clk_put(sdev->dacphy);
-fail_dac:
- clk_put(sdev->dac);
-fail_sclk_dac:
- clk_put(sdev->sclk_dac);
-fail:
- dev_info(dev, "probe failed\n");
- return ret;
-}
-
-static int __devexit sdo_remove(struct platform_device *pdev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
- struct sdo_device *sdev = sd_to_sdev(sd);
-
- pm_runtime_disable(&pdev->dev);
- clk_disable(sdev->dac);
- regulator_put(sdev->vdet);
- regulator_put(sdev->vdac);
- clk_put(sdev->fout_vpll);
- clk_put(sdev->dacphy);
- clk_put(sdev->dac);
- clk_put(sdev->sclk_dac);
-
- dev_info(&pdev->dev, "remove successful\n");
- return 0;
-}
-
-static struct platform_driver sdo_driver __refdata = {
- .probe = sdo_probe,
- .remove = __devexit_p(sdo_remove),
- .driver = {
- .name = "s5p-sdo",
- .owner = THIS_MODULE,
- .pm = &sdo_pm_ops,
- }
-};
-
-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
deleted file mode 100644
index 6d348f90237a..000000000000
--- a/drivers/media/video/s5p-tv/sii9234_drv.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * 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,
-};
-
-module_i2c_driver(sii9234_driver);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
deleted file mode 100644
index 39c90b08eea8..000000000000
--- a/drivers/media/video/saa7127.c
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * saa7127 - Philips SAA7127/SAA7129 video encoder driver
- *
- * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
- *
- * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
- *
- * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
- * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
- *
- * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
- *
- * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
- *
- * This driver is designed for the Hauppauge 250/350 Linux driver
- * from the ivtv Project
- *
- * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
- *
- * Dual output support:
- * Copyright (C) 2004 Eric Varsanyi
- *
- * NTSC Tuning and 7.5 IRE Setup
- * Copyright (C) 2004 Chris Kennedy <c@groovy.org>
- *
- * VBI additions & cleanup:
- * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * Note: the saa7126 is identical to the saa7127, and the saa7128 is
- * identical to the saa7129, except that the saa7126 and saa7128 have
- * macrovision anti-taping support. This driver will almost certainly
- * work fine for those chips, except of course for the missing anti-taping
- * support.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/saa7127.h>
-
-static int debug;
-static int test_image;
-
-MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
-MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
-MODULE_LICENSE("GPL");
-module_param(debug, int, 0644);
-module_param(test_image, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
-MODULE_PARM_DESC(test_image, "test_image (0-1)");
-
-
-/*
- * SAA7127 registers
- */
-
-#define SAA7127_REG_STATUS 0x00
-#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
-#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
-#define SAA7127_REG_BURST_START 0x28
-#define SAA7127_REG_BURST_END 0x29
-#define SAA7127_REG_COPYGEN_0 0x2a
-#define SAA7127_REG_COPYGEN_1 0x2b
-#define SAA7127_REG_COPYGEN_2 0x2c
-#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
-#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
-#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
-#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
-#define SAA7129_REG_FADE_KEY_COL2 0x4f
-#define SAA7127_REG_CHROMA_PHASE 0x5a
-#define SAA7127_REG_GAINU 0x5b
-#define SAA7127_REG_GAINV 0x5c
-#define SAA7127_REG_BLACK_LEVEL 0x5d
-#define SAA7127_REG_BLANKING_LEVEL 0x5e
-#define SAA7127_REG_VBI_BLANKING 0x5f
-#define SAA7127_REG_DAC_CONTROL 0x61
-#define SAA7127_REG_BURST_AMP 0x62
-#define SAA7127_REG_SUBC3 0x63
-#define SAA7127_REG_SUBC2 0x64
-#define SAA7127_REG_SUBC1 0x65
-#define SAA7127_REG_SUBC0 0x66
-#define SAA7127_REG_LINE_21_ODD_0 0x67
-#define SAA7127_REG_LINE_21_ODD_1 0x68
-#define SAA7127_REG_LINE_21_EVEN_0 0x69
-#define SAA7127_REG_LINE_21_EVEN_1 0x6a
-#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
-#define SAA7127_REG_VTRIG 0x6c
-#define SAA7127_REG_HTRIG_HI 0x6d
-#define SAA7127_REG_MULTI 0x6e
-#define SAA7127_REG_CLOSED_CAPTION 0x6f
-#define SAA7127_REG_RCV2_OUTPUT_START 0x70
-#define SAA7127_REG_RCV2_OUTPUT_END 0x71
-#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
-#define SAA7127_REG_TTX_REQUEST_H_START 0x73
-#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
-#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
-#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
-#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
-#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
-#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
-#define SAA7127_REG_FIRST_ACTIVE 0x7a
-#define SAA7127_REG_LAST_ACTIVE 0x7b
-#define SAA7127_REG_MSB_VERTICAL 0x7c
-#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
-#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
-
-/*
- **********************************************************************
- *
- * Arrays with configuration parameters for the SAA7127
- *
- **********************************************************************
- */
-
-struct i2c_reg_value {
- unsigned char reg;
- unsigned char value;
-};
-
-static const struct i2c_reg_value saa7129_init_config_extra[] = {
- { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
- { SAA7127_REG_VTRIG, 0xfa },
- { 0, 0 }
-};
-
-static const struct i2c_reg_value saa7127_init_config_common[] = {
- { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
- { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
- { SAA7127_REG_COPYGEN_0, 0x77 },
- { SAA7127_REG_COPYGEN_1, 0x41 },
- { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */
- { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf },
- { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
- { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
- { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */
- { SAA7127_REG_LINE_21_ODD_0, 0x77 },
- { SAA7127_REG_LINE_21_ODD_1, 0x41 },
- { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
- { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
- { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
- { SAA7127_REG_VTRIG, 0xf9 },
- { SAA7127_REG_HTRIG_HI, 0x00 },
- { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
- { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
- { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
- { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
- { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
- { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
- { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
- { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
- { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
- { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
- { SAA7127_REG_FIRST_ACTIVE, 0x1a },
- { SAA7127_REG_LAST_ACTIVE, 0x01 },
- { SAA7127_REG_MSB_VERTICAL, 0xc0 },
- { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
- { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
- { 0, 0 }
-};
-
-#define SAA7127_60HZ_DAC_CONTROL 0x15
-static const struct i2c_reg_value saa7127_init_config_60hz[] = {
- { SAA7127_REG_BURST_START, 0x19 },
- /* BURST_END is also used as a chip ID in saa7127_probe */
- { SAA7127_REG_BURST_END, 0x1d },
- { SAA7127_REG_CHROMA_PHASE, 0xa3 },
- { SAA7127_REG_GAINU, 0x98 },
- { SAA7127_REG_GAINV, 0xd3 },
- { SAA7127_REG_BLACK_LEVEL, 0x39 },
- { SAA7127_REG_BLANKING_LEVEL, 0x2e },
- { SAA7127_REG_VBI_BLANKING, 0x2e },
- { SAA7127_REG_DAC_CONTROL, 0x15 },
- { SAA7127_REG_BURST_AMP, 0x4d },
- { SAA7127_REG_SUBC3, 0x1f },
- { SAA7127_REG_SUBC2, 0x7c },
- { SAA7127_REG_SUBC1, 0xf0 },
- { SAA7127_REG_SUBC0, 0x21 },
- { SAA7127_REG_MULTI, 0x90 },
- { SAA7127_REG_CLOSED_CAPTION, 0x11 },
- { 0, 0 }
-};
-
-#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
-static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
- { SAA7127_REG_BURST_START, 0x21 },
- /* BURST_END is also used as a chip ID in saa7127_probe */
- { SAA7127_REG_BURST_END, 0x1d },
- { SAA7127_REG_CHROMA_PHASE, 0x3f },
- { SAA7127_REG_GAINU, 0x7d },
- { SAA7127_REG_GAINV, 0xaf },
- { SAA7127_REG_BLACK_LEVEL, 0x33 },
- { SAA7127_REG_BLANKING_LEVEL, 0x35 },
- { SAA7127_REG_VBI_BLANKING, 0x35 },
- { SAA7127_REG_DAC_CONTROL, 0x02 },
- { SAA7127_REG_BURST_AMP, 0x2f },
- { SAA7127_REG_SUBC3, 0xcb },
- { SAA7127_REG_SUBC2, 0x8a },
- { SAA7127_REG_SUBC1, 0x09 },
- { SAA7127_REG_SUBC0, 0x2a },
- { SAA7127_REG_MULTI, 0xa0 },
- { SAA7127_REG_CLOSED_CAPTION, 0x00 },
- { 0, 0 }
-};
-
-#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
-static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
- { SAA7127_REG_BURST_START, 0x21 },
- /* BURST_END is also used as a chip ID in saa7127_probe */
- { SAA7127_REG_BURST_END, 0x1d },
- { SAA7127_REG_CHROMA_PHASE, 0x3f },
- { SAA7127_REG_GAINU, 0x6a },
- { SAA7127_REG_GAINV, 0x81 },
- { SAA7127_REG_BLACK_LEVEL, 0x33 },
- { SAA7127_REG_BLANKING_LEVEL, 0x35 },
- { SAA7127_REG_VBI_BLANKING, 0x35 },
- { SAA7127_REG_DAC_CONTROL, 0x08 },
- { SAA7127_REG_BURST_AMP, 0x2f },
- { SAA7127_REG_SUBC3, 0xb2 },
- { SAA7127_REG_SUBC2, 0x3b },
- { SAA7127_REG_SUBC1, 0xa3 },
- { SAA7127_REG_SUBC0, 0x28 },
- { SAA7127_REG_MULTI, 0x90 },
- { SAA7127_REG_CLOSED_CAPTION, 0x00 },
- { 0, 0 }
-};
-
-/*
- **********************************************************************
- *
- * Encoder Struct, holds the configuration state of the encoder
- *
- **********************************************************************
- */
-
-struct saa7127_state {
- struct v4l2_subdev sd;
- v4l2_std_id std;
- u32 ident;
- enum saa7127_input_type input_type;
- enum saa7127_output_type output_type;
- int video_enable;
- int wss_enable;
- u16 wss_mode;
- int cc_enable;
- u16 cc_data;
- int xds_enable;
- u16 xds_data;
- int vps_enable;
- u8 vps_data[5];
- u8 reg_2d;
- u8 reg_3a;
- u8 reg_3a_cb; /* colorbar bit */
- u8 reg_61;
-};
-
-static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct saa7127_state, sd);
-}
-
-static const char * const output_strs[] =
-{
- "S-Video + Composite",
- "Composite",
- "S-Video",
- "RGB",
- "YUV C",
- "YUV V"
-};
-
-static const char * const wss_strs[] = {
- "invalid",
- "letterbox 14:9 center",
- "letterbox 14:9 top",
- "invalid",
- "letterbox 16:9 top",
- "invalid",
- "invalid",
- "16:9 full format anamorphic",
- "4:3 full format",
- "invalid",
- "invalid",
- "letterbox 16:9 center",
- "invalid",
- "letterbox >16:9 center",
- "14:9 full format center",
- "invalid",
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int i;
-
- for (i = 0; i < 3; i++) {
- if (i2c_smbus_write_byte_data(client, reg, val) == 0)
- return 0;
- }
- v4l2_err(sd, "I2C Write Problem\n");
- return -1;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_write_inittab(struct v4l2_subdev *sd,
- const struct i2c_reg_value *regs)
-{
- while (regs->reg != 0) {
- saa7127_write(sd, regs->reg, regs->value);
- regs++;
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
-{
- struct saa7127_state *state = to_state(sd);
- int enable = (data->line != 0);
-
- if (enable && (data->field != 0 || data->line != 16))
- return -EINVAL;
- if (state->vps_enable != enable) {
- v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
- saa7127_write(sd, 0x54, enable << 7);
- state->vps_enable = enable;
- }
- if (!enable)
- return 0;
-
- state->vps_data[0] = data->data[2];
- state->vps_data[1] = data->data[8];
- state->vps_data[2] = data->data[9];
- state->vps_data[3] = data->data[10];
- state->vps_data[4] = data->data[11];
- v4l2_dbg(1, debug, sd, "Set VPS data %02x %02x %02x %02x %02x\n",
- state->vps_data[0], state->vps_data[1],
- state->vps_data[2], state->vps_data[3],
- state->vps_data[4]);
- saa7127_write(sd, 0x55, state->vps_data[0]);
- saa7127_write(sd, 0x56, state->vps_data[1]);
- saa7127_write(sd, 0x57, state->vps_data[2]);
- saa7127_write(sd, 0x58, state->vps_data[3]);
- saa7127_write(sd, 0x59, state->vps_data[4]);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
-{
- struct saa7127_state *state = to_state(sd);
- u16 cc = data->data[1] << 8 | data->data[0];
- int enable = (data->line != 0);
-
- if (enable && (data->field != 0 || data->line != 21))
- return -EINVAL;
- if (state->cc_enable != enable) {
- v4l2_dbg(1, debug, sd,
- "Turn CC %s\n", enable ? "on" : "off");
- saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
- (state->xds_enable << 7) | (enable << 6) | 0x11);
- state->cc_enable = enable;
- }
- if (!enable)
- return 0;
-
- v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
- saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
- saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
- state->cc_data = cc;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
-{
- struct saa7127_state *state = to_state(sd);
- u16 xds = data->data[1] << 8 | data->data[0];
- int enable = (data->line != 0);
-
- if (enable && (data->field != 1 || data->line != 21))
- return -EINVAL;
- if (state->xds_enable != enable) {
- v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
- saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
- (enable << 7) | (state->cc_enable << 6) | 0x11);
- state->xds_enable = enable;
- }
- if (!enable)
- return 0;
-
- v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
- saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
- saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
- state->xds_data = xds;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
-{
- struct saa7127_state *state = to_state(sd);
- int enable = (data->line != 0);
-
- if (enable && (data->field != 0 || data->line != 23))
- return -EINVAL;
- if (state->wss_enable != enable) {
- v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
- saa7127_write(sd, 0x27, enable << 7);
- state->wss_enable = enable;
- }
- if (!enable)
- return 0;
-
- saa7127_write(sd, 0x26, data->data[0]);
- saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
- v4l2_dbg(1, debug, sd,
- "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
- state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
-{
- struct saa7127_state *state = to_state(sd);
-
- if (enable) {
- v4l2_dbg(1, debug, sd, "Enable Video Output\n");
- saa7127_write(sd, 0x2d, state->reg_2d);
- saa7127_write(sd, 0x61, state->reg_61);
- } else {
- v4l2_dbg(1, debug, sd, "Disable Video Output\n");
- saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
- saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
- }
- state->video_enable = enable;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
-{
- struct saa7127_state *state = to_state(sd);
- const struct i2c_reg_value *inittab;
-
- if (std & V4L2_STD_525_60) {
- v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
- inittab = saa7127_init_config_60hz;
- state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
-
- } else if (state->ident == V4L2_IDENT_SAA7129 &&
- (std & V4L2_STD_SECAM) &&
- !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
-
- /* If and only if SECAM, with a SAA712[89] */
- v4l2_dbg(1, debug, sd,
- "Selecting 50 Hz SECAM video Standard\n");
- inittab = saa7127_init_config_50hz_secam;
- state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
-
- } else {
- v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
- inittab = saa7127_init_config_50hz_pal;
- state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
- }
-
- /* Write Table */
- saa7127_write_inittab(sd, inittab);
- state->std = std;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
-{
- struct saa7127_state *state = to_state(sd);
-
- switch (output) {
- case SAA7127_OUTPUT_TYPE_RGB:
- state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */
- state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
- break;
-
- case SAA7127_OUTPUT_TYPE_COMPOSITE:
- if (state->ident == V4L2_IDENT_SAA7129)
- state->reg_2d = 0x20; /* CVBS only */
- else
- state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
- state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
- break;
-
- case SAA7127_OUTPUT_TYPE_SVIDEO:
- if (state->ident == V4L2_IDENT_SAA7129)
- state->reg_2d = 0x18; /* Y + C */
- else
- state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */
- state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
- break;
-
- case SAA7127_OUTPUT_TYPE_YUV_V:
- state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */
- state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
- break;
-
- case SAA7127_OUTPUT_TYPE_YUV_C:
- state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */
- state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
- break;
-
- case SAA7127_OUTPUT_TYPE_BOTH:
- if (state->ident == V4L2_IDENT_SAA7129)
- state->reg_2d = 0x38;
- else
- state->reg_2d = 0xbf;
- state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
- break;
-
- default:
- return -EINVAL;
- }
- v4l2_dbg(1, debug, sd,
- "Selecting %s output type\n", output_strs[output]);
-
- /* Configure Encoder */
- saa7127_write(sd, 0x2d, state->reg_2d);
- saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
- state->output_type = output;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
-{
- struct saa7127_state *state = to_state(sd);
-
- switch (input) {
- case SAA7127_INPUT_TYPE_NORMAL: /* avia */
- v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
- state->reg_3a_cb = 0;
- break;
-
- case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
- v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
- state->reg_3a_cb = 0x80;
- break;
-
- default:
- return -EINVAL;
- }
- saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
- state->input_type = input;
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
-{
- struct saa7127_state *state = to_state(sd);
-
- if (state->std == std)
- return 0;
- return saa7127_set_std(sd, std);
-}
-
-static int saa7127_s_routing(struct v4l2_subdev *sd,
- u32 input, u32 output, u32 config)
-{
- struct saa7127_state *state = to_state(sd);
- int rc = 0;
-
- if (state->input_type != input)
- rc = saa7127_set_input_type(sd, input);
- if (rc == 0 && state->output_type != output)
- rc = saa7127_set_output_type(sd, output);
- return rc;
-}
-
-static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct saa7127_state *state = to_state(sd);
-
- if (state->video_enable == enable)
- return 0;
- return saa7127_set_video_enable(sd, enable);
-}
-
-static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
-{
- struct saa7127_state *state = to_state(sd);
-
- memset(fmt, 0, sizeof(*fmt));
- if (state->vps_enable)
- fmt->service_lines[0][16] = V4L2_SLICED_VPS;
- if (state->wss_enable)
- fmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
- if (state->cc_enable) {
- fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
- fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
- }
- fmt->service_set =
- (state->vps_enable ? V4L2_SLICED_VPS : 0) |
- (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
- (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
- return 0;
-}
-
-static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
-{
- switch (data->id) {
- case V4L2_SLICED_WSS_625:
- return saa7127_set_wss(sd, data);
- case V4L2_SLICED_VPS:
- return saa7127_set_vps(sd, data);
- case V4L2_SLICED_CAPTION_525:
- if (data->field == 0)
- return saa7127_set_cc(sd, data);
- return saa7127_set_xds(sd, data);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int saa7127_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 = saa7127_read(sd, reg->reg & 0xff);
- reg->size = 1;
- return 0;
-}
-
-static int saa7127_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;
- saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
- return 0;
-}
-#endif
-
-static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
- struct saa7127_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
-}
-
-static int saa7127_log_status(struct v4l2_subdev *sd)
-{
- struct saa7127_state *state = to_state(sd);
-
- v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
- v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal");
- v4l2_info(sd, "Output: %s\n", state->video_enable ?
- output_strs[state->output_type] : "disabled");
- v4l2_info(sd, "WSS: %s\n", state->wss_enable ?
- wss_strs[state->wss_mode] : "disabled");
- v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
- v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled");
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops saa7127_core_ops = {
- .log_status = saa7127_log_status,
- .g_chip_ident = saa7127_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = saa7127_g_register,
- .s_register = saa7127_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_video_ops saa7127_video_ops = {
- .s_std_output = saa7127_s_std_output,
- .s_routing = saa7127_s_routing,
- .s_stream = saa7127_s_stream,
-};
-
-static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = {
- .s_vbi_data = saa7127_s_vbi_data,
- .g_sliced_fmt = saa7127_g_sliced_fmt,
-};
-
-static const struct v4l2_subdev_ops saa7127_ops = {
- .core = &saa7127_core_ops,
- .video = &saa7127_video_ops,
- .vbi = &saa7127_vbi_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct saa7127_state *state;
- struct v4l2_subdev *sd;
- struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
- v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
- client->addr << 1);
-
- state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
-
- sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
-
- /* First test register 0: Bits 5-7 are a version ID (should be 0),
- and bit 2 should also be 0.
- This is rather general, so the second test is more specific and
- looks at the 'ending point of burst in clock cycles' which is
- 0x1d after a reset and not expected to ever change. */
- if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
- (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
- v4l2_dbg(1, debug, sd, "saa7127 not found\n");
- kfree(state);
- return -ENODEV;
- }
-
- if (id->driver_data) { /* Chip type is already known */
- state->ident = id->driver_data;
- } else { /* Needs detection */
- int read_result;
-
- /* Detect if it's an saa7129 */
- read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
- saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
- if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
- saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
- read_result);
- state->ident = V4L2_IDENT_SAA7129;
- strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
- } else {
- state->ident = V4L2_IDENT_SAA7127;
- strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
- }
- }
-
- v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
- client->addr << 1, client->adapter->name);
-
- v4l2_dbg(1, debug, sd, "Configuring encoder\n");
- saa7127_write_inittab(sd, saa7127_init_config_common);
- saa7127_set_std(sd, V4L2_STD_NTSC);
- saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
- saa7127_set_vps(sd, &vbi);
- saa7127_set_wss(sd, &vbi);
- saa7127_set_cc(sd, &vbi);
- saa7127_set_xds(sd, &vbi);
- if (test_image == 1)
- /* The Encoder has an internal Colorbar generator */
- /* This can be used for debugging */
- saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
- else
- saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
- saa7127_set_video_enable(sd, 1);
-
- if (state->ident == V4L2_IDENT_SAA7129)
- saa7127_write_inittab(sd, saa7129_init_config_extra);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- /* Turn off TV output */
- saa7127_set_video_enable(sd, 0);
- kfree(to_state(sd));
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_device_id saa7127_id[] = {
- { "saa7127_auto", 0 }, /* auto-detection */
- { "saa7126", V4L2_IDENT_SAA7127 },
- { "saa7127", V4L2_IDENT_SAA7127 },
- { "saa7128", V4L2_IDENT_SAA7129 },
- { "saa7129", V4L2_IDENT_SAA7129 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, saa7127_id);
-
-static struct i2c_driver saa7127_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "saa7127",
- },
- .probe = saa7127_probe,
- .remove = saa7127_remove,
- .id_table = saa7127_id,
-};
-
-module_i2c_driver(saa7127_driver);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
deleted file mode 100644
index 39fc0187a747..000000000000
--- a/drivers/media/video/saa7134/Kconfig
+++ /dev/null
@@ -1,64 +0,0 @@
-config VIDEO_SAA7134
- tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C
- select VIDEOBUF_DMA_SG
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select CRC32
- select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- This is a video4linux driver for Philips SAA713x based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7134.
-
-config VIDEO_SAA7134_ALSA
- tristate "Philips SAA7134 DMA audio support"
- depends on VIDEO_SAA7134 && SND
- select SND_PCM
- ---help---
- This is a video4linux driver for direct (DMA) audio in
- Philips SAA713x based TV cards using ALSA
-
- To compile this driver as a module, choose M here: the
- module will be called saa7134-alsa.
-
-config VIDEO_SAA7134_RC
- bool "Philips SAA7134 Remote Controller support"
- depends on RC_CORE
- depends on VIDEO_SAA7134
- depends on !(RC_CORE=m && VIDEO_SAA7134=y)
- default y
- ---help---
- Enables Remote Controller support on saa7134 driver.
-
-config VIDEO_SAA7134_DVB
- tristate "DVB/ATSC Support for saa7134 based TV cards"
- depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEOBUF_DVB
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_TDA1004X if !DVB_FE_CUSTOMISE
- select DVB_NXT200X if !DVB_FE_CUSTOMISE
- select DVB_TDA10086 if !DVB_FE_CUSTOMISE
- select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select DVB_ISL6405 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
- select DVB_ZL10036 if !DVB_FE_CUSTOMISE
- select DVB_MT312 if !DVB_FE_CUSTOMISE
- select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
- select DVB_TDA10048 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
- select DVB_ZL10039 if !DVB_FE_CUSTOMISE
- ---help---
- This adds support for DVB cards based on the
- Philips saa7134 chip.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7134-dvb.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
deleted file mode 100644
index da3899329f52..000000000000
--- a/drivers/media/video/saa7134/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-
-saa7134-y := saa7134-cards.o saa7134-core.o saa7134-i2c.o
-saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
-saa7134-y += saa7134-video.o
-saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
-
-obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
-
-obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
-
-obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
-
-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/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
deleted file mode 100644
index cc7f3d6ee966..000000000000
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ /dev/null
@@ -1,1936 +0,0 @@
-/*
- *
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * Extended 3 / 2005 by Hartmut Hackmann to support various
- * cards with the tda10046 DVB-T channel decoder
- *
- * 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/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/suspend.h>
-
-#include "saa7134-reg.h"
-#include "saa7134.h"
-#include <media/v4l2-common.h>
-#include "dvb-pll.h"
-#include <dvb_frontend.h>
-
-#include "mt352.h"
-#include "mt352_priv.h" /* FIXME */
-#include "tda1004x.h"
-#include "nxt200x.h"
-#include "tuner-xc2028.h"
-#include "xc5000.h"
-
-#include "tda10086.h"
-#include "tda826x.h"
-#include "tda827x.h"
-#include "isl6421.h"
-#include "isl6405.h"
-#include "lnbp21.h"
-#include "tuner-simple.h"
-#include "tda10048.h"
-#include "tda18271.h"
-#include "lgdt3305.h"
-#include "tda8290.h"
-#include "mb86a20s.h"
-#include "lgs8gxx.h"
-
-#include "zl10353.h"
-#include "qt1010.h"
-
-#include "zl10036.h"
-#include "zl10039.h"
-#include "mt312.h"
-#include "s5h1411.h"
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static unsigned int antenna_pwr;
-
-module_param(antenna_pwr, int, 0444);
-MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
-
-static int use_frontend;
-module_param(use_frontend, int, 0644);
-MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(fmt, arg...) do { if (debug) \
- printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
-
-/* Print a warning */
-#define wprintk(fmt, arg...) \
- printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
-
-/* ------------------------------------------------------------------
- * mt352 based DVB-T cards
- */
-
-static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
-{
- u32 ok;
-
- if (!on) {
- saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
- saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
- return 0;
- }
-
- saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
- saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
- udelay(10);
-
- saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28));
- saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
- udelay(10);
- saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
- udelay(10);
- ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
- dprintk("%s %s\n", __func__, ok ? "on" : "off");
-
- if (!ok)
- saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
- return ok;
-}
-
-static int mt352_pinnacle_init(struct dvb_frontend* fe)
-{
- static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
- static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 };
- static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f };
- static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d };
- static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
- struct saa7134_dev *dev= fe->dvb->priv;
-
- dprintk("%s called\n", __func__);
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
- mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
-
- mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg));
- mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg));
- mt352_write(fe, irq_cfg, sizeof(irq_cfg));
-
- return 0;
-}
-
-static int mt352_aver777_init(struct dvb_frontend* fe)
-{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
- return 0;
-}
-
-static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
-{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0xe };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
-
- mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
- mt352_write(fe, reset, sizeof(reset));
- mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
- mt352_write(fe, agc_cfg, sizeof(agc_cfg));
- mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
- return 0;
-}
-
-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)};
-
- struct saa7134_dev *dev = fe->dvb->priv;
- struct v4l2_frequency f;
-
- /* set frequency (mt2050) */
- f.tuner = 0;
- f.type = V4L2_TUNER_DIGITAL_TV;
- 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);
- saa_call_all(dev, tuner, s_frequency, &f);
- msg.buf = on;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &msg, 1);
-
- pinnacle_antenna_pwr(dev, antenna_pwr);
-
- /* mt352 setup */
- return mt352_pinnacle_init(fe);
-}
-
-static struct mt352_config pinnacle_300i = {
- .demod_address = 0x3c >> 1,
- .adc_clock = 20333,
- .if2 = 36150,
- .no_tuner = 1,
- .demod_init = mt352_pinnacle_init,
-};
-
-static struct mt352_config avermedia_777 = {
- .demod_address = 0xf,
- .demod_init = mt352_aver777_init,
-};
-
-static struct mt352_config avermedia_xc3028_mt352_dev = {
- .demod_address = (0x1e >> 1),
- .no_tuner = 1,
- .demod_init = mt352_avermedia_xc3028_init,
-};
-
-static struct tda18271_std_map mb86a20s_tda18271_std_map = {
- .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
- .if_lvl = 7, .rfagc_top = 0x37, },
-};
-
-static struct tda18271_config kworld_tda18271_config = {
- .std_map = &mb86a20s_tda18271_std_map,
- .gate = TDA18271_GATE_DIGITAL,
- .config = 3, /* Use tuner callback for AGC */
-
-};
-
-static const struct mb86a20s_config kworld_mb86a20s_config = {
- .demod_address = 0x10,
-};
-
-static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
-
- unsigned char initmsg[] = {0x45, 0x97};
- unsigned char msg_enable[] = {0x45, 0xc1};
- unsigned char msg_disable[] = {0x45, 0x81};
- struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
-
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
- wprintk("could not access the I2C gate\n");
- return -EIO;
- }
- if (enable)
- msg.buf = msg_enable;
- else
- msg.buf = msg_disable;
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
- wprintk("could not access the I2C gate\n");
- return -EIO;
- }
- msleep(20);
- return 0;
-}
-
-/* ==================================================================
- * tda1004x based DVB-T cards, helper functions
- */
-
-static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
- const struct firmware **fw, char *name)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- return request_firmware(fw, name, &dev->pci->dev);
-}
-
-/* ------------------------------------------------------------------
- * these tuners are tu1216, td1316(a)
- */
-
-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;
- u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
- sizeof(tuner_buf) };
- int tuner_frequency = 0;
- u8 band, cp, filter;
-
- /* determine charge pump */
- tuner_frequency = c->frequency + 36166000;
- if (tuner_frequency < 87000000)
- return -EINVAL;
- else if (tuner_frequency < 130000000)
- cp = 3;
- else if (tuner_frequency < 160000000)
- cp = 5;
- else if (tuner_frequency < 200000000)
- cp = 6;
- else if (tuner_frequency < 290000000)
- cp = 3;
- else if (tuner_frequency < 420000000)
- cp = 5;
- else if (tuner_frequency < 480000000)
- cp = 6;
- else if (tuner_frequency < 620000000)
- cp = 3;
- else if (tuner_frequency < 830000000)
- cp = 5;
- else if (tuner_frequency < 895000000)
- cp = 7;
- else
- return -EINVAL;
-
- /* determine band */
- if (c->frequency < 49000000)
- return -EINVAL;
- else if (c->frequency < 161000000)
- band = 1;
- else if (c->frequency < 444000000)
- band = 2;
- else if (c->frequency < 861000000)
- band = 4;
- else
- return -EINVAL;
-
- /* setup PLL filter */
- switch (c->bandwidth_hz) {
- case 6000000:
- filter = 0;
- break;
-
- case 7000000:
- filter = 0;
- break;
-
- case 8000000:
- filter = 1;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* calculate divisor
- * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
- */
- tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
-
- /* setup tuner buffer */
- tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
- tuner_buf[1] = tuner_frequency & 0xff;
- tuner_buf[2] = 0xca;
- tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
- wprintk("could not write to tuner at addr: 0x%02x\n",
- addr << 1);
- return -EIO;
- }
- msleep(1);
- return 0;
-}
-
-static int philips_tu1216_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
-
- /* setup PLL configuration */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static struct tda1004x_config philips_tu1216_60_config = {
- .demod_address = 0x8,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_4M,
- .agc_config = TDA10046_AGC_DEFAULT,
- .if_freq = TDA10046_FREQ_3617,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config philips_tu1216_61_config = {
-
- .demod_address = 0x8,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_4M,
- .agc_config = TDA10046_AGC_DEFAULT,
- .if_freq = TDA10046_FREQ_3617,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-/* ------------------------------------------------------------------ */
-
-static int philips_td1316_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
- struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
-
- /* setup PLL configuration */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
-{
- return philips_tda6651_pll_set(fe);
-}
-
-static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
- struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
-
- /* switch the tuner to analog mode */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int philips_europa_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- static u8 msg[] = { 0x00, 0x40};
- struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
-
-
- if (philips_td1316_tuner_init(fe))
- return -EIO;
- msleep(1);
- if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
-static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
-
- static u8 msg[] = { 0x00, 0x14 };
- struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
-
- if (philips_td1316_tuner_sleep(fe))
- return -EIO;
-
- /* switch the board to analog mode */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
- return 0;
-}
-
-static int philips_europa_demod_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
-
- if (dev->original_demod_sleep)
- dev->original_demod_sleep(fe);
- fe->ops.i2c_gate_ctrl(fe, 1);
- return 0;
-}
-
-static struct tda1004x_config philips_europa_config = {
-
- .demod_address = 0x8,
- .invert = 0,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_4M,
- .agc_config = TDA10046_AGC_IFO_AUTO_POS,
- .if_freq = TDA10046_FREQ_052,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config medion_cardbus = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_IFO_AUTO_NEG,
- .if_freq = TDA10046_FREQ_3613,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config technotrend_budget_t3000_config = {
- .demod_address = 0x8,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_4M,
- .agc_config = TDA10046_AGC_DEFAULT,
- .if_freq = TDA10046_FREQ_3617,
- .tuner_address = 0x63,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-/* ------------------------------------------------------------------
- * tda 1004x based cards with philips silicon tuner
- */
-
-static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
-{
- struct tda1004x_state *state = fe->demodulator_priv;
-
- u8 addr = state->config->i2c_gate;
- static u8 tda8290_close[] = { 0x21, 0xc0};
- static u8 tda8290_open[] = { 0x21, 0x80};
- struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
- if (enable) {
- tda8290_msg.buf = tda8290_close;
- } else {
- tda8290_msg.buf = tda8290_open;
- }
- if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) {
- struct saa7134_dev *dev = fe->dvb->priv;
- wprintk("could not access tda8290 I2C gate\n");
- return -EIO;
- }
- msleep(20);
- return 0;
-}
-
-static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
-
- switch (state->config->antenna_switch) {
- case 0: break;
- case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n");
- saa7134_set_gpio(dev, 21, 0);
- break;
- case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
- saa7134_set_gpio(dev, 21, 1);
- break;
- }
- return 0;
-}
-
-static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
-
- switch (state->config->antenna_switch) {
- case 0: break;
- case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
- saa7134_set_gpio(dev, 21, 1);
- break;
- case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n");
- saa7134_set_gpio(dev, 21, 0);
- break;
- }
- return 0;
-}
-
-static int configure_tda827x_fe(struct saa7134_dev *dev,
- struct tda1004x_config *cdec_conf,
- struct tda827x_config *tuner_conf)
-{
- struct videobuf_dvb_frontend *fe0;
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
-
- fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (cdec_conf->i2c_gate)
- fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
- if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
- cdec_conf->tuner_address,
- &dev->i2c_adap, tuner_conf))
- return 0;
-
- wprintk("no tda827x tuner found at addr: %02x\n",
- cdec_conf->tuner_address);
- }
- return -EINVAL;
-}
-
-/* ------------------------------------------------------------------ */
-
-static struct tda827x_config tda827x_cfg_0 = {
- .init = philips_tda827x_tuner_init,
- .sleep = philips_tda827x_tuner_sleep,
- .config = 0,
- .switch_addr = 0
-};
-
-static struct tda827x_config tda827x_cfg_1 = {
- .init = philips_tda827x_tuner_init,
- .sleep = philips_tda827x_tuner_sleep,
- .config = 1,
- .switch_addr = 0x4b
-};
-
-static struct tda827x_config tda827x_cfg_2 = {
- .init = philips_tda827x_tuner_init,
- .sleep = philips_tda827x_tuner_sleep,
- .config = 2,
- .switch_addr = 0x4b
-};
-
-static struct tda827x_config tda827x_cfg_2_sw42 = {
- .init = philips_tda827x_tuner_init,
- .sleep = philips_tda827x_tuner_sleep,
- .config = 2,
- .switch_addr = 0x42
-};
-
-/* ------------------------------------------------------------------ */
-
-static struct tda1004x_config tda827x_lifeview_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config philips_tiger_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config cinergy_ht_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config cinergy_ht_pci_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config philips_tiger_s_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config pinnacle_pctv_310i_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config hauppauge_hvr_1110_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config asus_p7131_dual_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 2,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config lifeview_trio_config = {
- .demod_address = 0x09,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP00_I,
- .if_freq = TDA10046_FREQ_045,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config tevion_dvbt220rf_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config md8800_dvbt_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x60,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config asus_p7131_4871_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 2,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config asus_p7131_hybrid_lna_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 2,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config kworld_dvb_t_210_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch= 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config avermedia_super_007_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x60,
- .antenna_switch= 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP01_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x42,
- .tuner_address = 0x61,
- .antenna_switch = 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config asus_tiger_3in1_config = {
- .demod_address = 0x0b,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch = 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct tda1004x_config asus_ps3_100_config = {
- .demod_address = 0x0b,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP11_I,
- .if_freq = TDA10046_FREQ_045,
- .i2c_gate = 0x4b,
- .tuner_address = 0x61,
- .antenna_switch = 1,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-/* ------------------------------------------------------------------
- * special case: this card uses saa713x GPIO22 for the mode switch
- */
-
-static int ads_duo_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- philips_tda827x_tuner_init(fe);
- /* route TDA8275a AGC input to the channel decoder */
- saa7134_set_gpio(dev, 22, 1);
- return 0;
-}
-
-static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- /* route TDA8275a AGC input to the analog IF chip*/
- saa7134_set_gpio(dev, 22, 0);
- philips_tda827x_tuner_sleep(fe);
- return 0;
-}
-
-static struct tda827x_config ads_duo_cfg = {
- .init = ads_duo_tuner_init,
- .sleep = ads_duo_tuner_sleep,
- .config = 0
-};
-
-static struct tda1004x_config ads_tech_duo_config = {
- .demod_address = 0x08,
- .invert = 1,
- .invert_oclk = 0,
- .xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
- .gpio_config = TDA10046_GP00_I,
- .if_freq = TDA10046_FREQ_045,
- .tuner_address = 0x61,
- .request_firmware = philips_tda1004x_request_firmware
-};
-
-static struct zl10353_config behold_h6_config = {
- .demod_address = 0x1e>>1,
- .no_tuner = 1,
- .parallel_ts = 1,
- .disable_i2c_gate_ctrl = 1,
-};
-
-static struct xc5000_config behold_x7_tunerconfig = {
- .i2c_address = 0xc2>>1,
- .if_khz = 4560,
- .radio_input = XC5000_RADIO_FM1,
-};
-
-static struct zl10353_config behold_x7_config = {
- .demod_address = 0x1e>>1,
- .if2 = 45600,
- .no_tuner = 1,
- .parallel_ts = 1,
- .disable_i2c_gate_ctrl = 1,
-};
-
-static struct zl10353_config videomate_t750_zl10353_config = {
- .demod_address = 0x0f,
- .no_tuner = 1,
- .parallel_ts = 1,
- .disable_i2c_gate_ctrl = 1,
-};
-
-static struct qt1010_config videomate_t750_qt1010_config = {
- .i2c_address = 0x62
-};
-
-
-/* ==================================================================
- * tda10086 based DVB-S cards, helper functions
- */
-
-static struct tda10086_config flydvbs = {
- .demod_address = 0x0e,
- .invert = 0,
- .diseqc_tone = 0,
- .xtal_freq = TDA10086_XTAL_16M,
-};
-
-static struct tda10086_config sd1878_4m = {
- .demod_address = 0x0e,
- .invert = 0,
- .diseqc_tone = 0,
- .xtal_freq = TDA10086_XTAL_4M,
-};
-
-/* ------------------------------------------------------------------
- * special case: lnb supply is connected to the gated i2c
- */
-
-static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- int res = -EIO;
- struct saa7134_dev *dev = fe->dvb->priv;
- if (fe->ops.i2c_gate_ctrl) {
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (dev->original_set_voltage)
- res = dev->original_set_voltage(fe, voltage);
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- return res;
-};
-
-static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
-{
- int res = -EIO;
- struct saa7134_dev *dev = fe->dvb->priv;
- if (fe->ops.i2c_gate_ctrl) {
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (dev->original_set_high_voltage)
- res = dev->original_set_high_voltage(fe, arg);
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- return res;
-};
-
-static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- u8 wbuf[2] = { 0x1f, 00 };
- u8 rbuf;
- struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
- { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
-
- if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
- return -EIO;
- /* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
- if (voltage == SEC_VOLTAGE_18)
- wbuf[1] = rbuf | 0x10;
- else
- wbuf[1] = rbuf & 0xef;
- msg[0].len = 2;
- i2c_transfer(&dev->i2c_adap, msg, 1);
- return 0;
-}
-
-static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__);
- return -EIO;
-}
-
-/* ==================================================================
- * nxt200x based ATSC cards, helper functions
- */
-
-static struct nxt200x_config avertvhda180 = {
- .demod_address = 0x0a,
-};
-
-static struct nxt200x_config kworldatsc110 = {
- .demod_address = 0x0a,
-};
-
-/* ------------------------------------------------------------------ */
-
-static struct mt312_config avertv_a700_mt312 = {
- .demod_address = 0x0e,
- .voltage_inverted = 1,
-};
-
-static struct zl10036_config avertv_a700_tuner = {
- .tuner_address = 0x60,
-};
-
-static struct mt312_config zl10313_compro_s350_config = {
- .demod_address = 0x0e,
-};
-
-static struct lgdt3305_config hcw_lgdt3305_config = {
- .i2c_addr = 0x0e,
- .mpeg_mode = LGDT3305_MPEG_SERIAL,
- .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
- .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
- .deny_i2c_rptr = 1,
- .spectral_inversion = 1,
- .qam_if_khz = 4000,
- .vsb_if_khz = 3250,
-};
-
-static struct tda10048_config hcw_tda10048_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_SERIAL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_200,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3500,
- .dtv8_if_freq_khz = TDA10048_IF_4000,
- .clk_freq_khz = TDA10048_CLK_16000,
- .disable_gate_access = 1,
-};
-
-static struct tda18271_std_map hauppauge_tda18271_std_map = {
- .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
- .if_lvl = 1, .rfagc_top = 0x58, },
- .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
- .if_lvl = 1, .rfagc_top = 0x58, },
-};
-
-static struct tda18271_config hcw_tda18271_config = {
- .std_map = &hauppauge_tda18271_std_map,
- .gate = TDA18271_GATE_ANALOG,
- .config = 3,
- .output_opt = TDA18271_OUTPUT_LT_OFF,
-};
-
-static struct tda829x_config tda829x_no_probe = {
- .probe_tuner = TDA829X_DONT_PROBE,
-};
-
-static struct tda10048_config zolid_tda10048_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_PARALLEL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_200,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3500,
- .dtv8_if_freq_khz = TDA10048_IF_4000,
- .clk_freq_khz = TDA10048_CLK_16000,
- .disable_gate_access = 1,
-};
-
-static struct tda18271_config zolid_tda18271_config = {
- .gate = TDA18271_GATE_ANALOG,
-};
-
-static struct tda10048_config dtv1000s_tda10048_config = {
- .demod_address = 0x10 >> 1,
- .output_mode = TDA10048_PARALLEL_OUTPUT,
- .fwbulkwritelen = TDA10048_BULKWRITE_200,
- .inversion = TDA10048_INVERSION_ON,
- .dtv6_if_freq_khz = TDA10048_IF_3300,
- .dtv7_if_freq_khz = TDA10048_IF_3800,
- .dtv8_if_freq_khz = TDA10048_IF_4300,
- .clk_freq_khz = TDA10048_CLK_16000,
- .disable_gate_access = 1,
-};
-
-static struct tda18271_std_map dtv1000s_tda18271_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 dtv1000s_tda18271_config = {
- .std_map = &dtv1000s_tda18271_std_map,
- .gate = TDA18271_GATE_ANALOG,
-};
-
-static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
- .prod = LGS8GXX_PROD_LGS8G75,
- .demod_address = 0x1d,
- .serial_ts = 0,
- .ts_clk_pol = 1,
- .ts_clk_gated = 0,
- .if_clk_freq = 30400, /* 30.4 MHz */
- .if_freq = 4000, /* 4.00 MHz */
- .if_neg_center = 0,
- .ext_adc = 0,
- .adc_signed = 1,
- .adc_vpp = 3, /* 2.0 Vpp */
- .if_neg_edge = 1,
-};
-
-static struct tda18271_config prohdtv_pro2_tda18271_config = {
- .gate = TDA18271_GATE_ANALOG,
- .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
- */
-
-static int dvb_init(struct saa7134_dev *dev)
-{
- int ret;
- int attach_xc3028 = 0;
- struct videobuf_dvb_frontend *fe0;
-
- /* FIXME: add support for multi-frontend */
- mutex_init(&dev->frontends.lock);
- INIT_LIST_HEAD(&dev->frontends.felist);
-
- printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
- fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
- if (!fe0) {
- printk(KERN_ERR "%s() failed to alloc\n", __func__);
- return -ENOMEM;
- }
-
- /* init struct videobuf_dvb */
- dev->ts.nr_bufs = 32;
- dev->ts.nr_packets = 32*4;
- fe0->dvb.name = dev->name;
- videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_ALTERNATE,
- sizeof(struct saa7134_buf),
- dev, NULL);
-
- switch (dev->board) {
- case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
- dprintk("pinnacle 300i dvb setup\n");
- fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
- }
- break;
- case SAA7134_BOARD_AVERMEDIA_777:
- case SAA7134_BOARD_AVERMEDIA_A16AR:
- dprintk("avertv 777 dvb setup\n");
- fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0x61,
- TUNER_PHILIPS_TD1316);
- }
- break;
- case SAA7134_BOARD_AVERMEDIA_A16D:
- dprintk("AverMedia A16D dvb setup\n");
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &avermedia_xc3028_mt352_dev,
- &dev->i2c_adap);
- attach_xc3028 = 1;
- break;
- case SAA7134_BOARD_MD7134:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &medion_cardbus,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &dev->i2c_adap, medion_cardbus.tuner_address,
- TUNER_PHILIPS_FMD1216ME_MK3);
- }
- break;
- case SAA7134_BOARD_PHILIPS_TOUGH:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &philips_tu1216_60_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
- fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
- }
- break;
- case SAA7134_BOARD_FLYDVBTDUO:
- case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
- if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_PHILIPS_EUROPA:
- case SAA7134_BOARD_VIDEOMATE_DVBT_300:
- case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &philips_europa_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
- fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
- fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
- fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
- }
- break;
- case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &technotrend_budget_t3000_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
- fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
- fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
- fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
- }
- break;
- case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &philips_tu1216_61_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
- fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
- }
- break;
- case SAA7134_BOARD_KWORLD_DVBT_210:
- if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_HAUPPAUGE_HVR1120:
- fe0->dvb.frontend = dvb_attach(tda10048_attach,
- &hcw_tda10048_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,
- &hcw_tda18271_config);
- }
- break;
- case SAA7134_BOARD_PHILIPS_TIGER:
- if (configure_tda827x_fe(dev, &philips_tiger_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_PINNACLE_PCTV_310i:
- if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
- &tda827x_cfg_1) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_HAUPPAUGE_HVR1110:
- if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
- &tda827x_cfg_1) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_HAUPPAUGE_HVR1150:
- fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
- &hcw_lgdt3305_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- 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,
- &hcw_tda18271_config);
- }
- break;
- case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_FLYDVBT_LR301:
- if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_FLYDVB_TRIO:
- if (!use_frontend) { /* terrestrial */
- if (configure_tda827x_fe(dev, &lifeview_trio_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- } else { /* satellite */
- fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
- &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
- goto detach_frontend;
- }
- if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
- 0x08, 0, 0) == NULL) {
- wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
- goto detach_frontend;
- }
- }
- }
- break;
- case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
- case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &ads_tech_duo_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
- ads_tech_duo_config.tuner_address, &dev->i2c_adap,
- &ads_duo_cfg) == NULL) {
- wprintk("no tda827x tuner found at addr: %02x\n",
- ads_tech_duo_config.tuner_address);
- goto detach_frontend;
- }
- } else
- wprintk("failed to attach tda10046\n");
- break;
- case SAA7134_BOARD_TEVION_DVBT_220RF:
- if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_MEDION_MD8800_QUADRO:
- if (!use_frontend) { /* terrestrial */
- if (configure_tda827x_fe(dev, &md8800_dvbt_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- } else { /* satellite */
- fe0->dvb.frontend = dvb_attach(tda10086_attach,
- &flydvbs, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- struct dvb_frontend *fe = fe0->dvb.frontend;
- u8 dev_id = dev->eedata[2];
- u8 data = 0xc4;
- struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
-
- if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: Medion Quadro, no tda826x "
- "found !\n", __func__);
- goto detach_frontend;
- }
- if (dev_id != 0x08) {
- /* we need to open the i2c gate (we know it exists) */
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL) {
- wprintk("%s: Medion Quadro, no ISL6405 "
- "found !\n", __func__);
- goto detach_frontend;
- }
- if (dev_id == 0x07) {
- /* fire up the 2nd section of the LNB supply since
- we can't do this from the other section */
- msg.buf = &data;
- i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
- fe->ops.i2c_gate_ctrl(fe, 0);
- dev->original_set_voltage = fe->ops.set_voltage;
- fe->ops.set_voltage = md8800_set_voltage;
- dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
- fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
- } else {
- fe->ops.set_voltage = md8800_set_voltage2;
- fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
- }
- }
- }
- break;
- case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
- fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
- &dev->i2c_adap);
- if (fe0->dvb.frontend)
- dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
- NULL, DVB_PLL_TDHU2);
- break;
- case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
- case SAA7134_BOARD_KWORLD_ATSC110:
- fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
- &dev->i2c_adap);
- if (fe0->dvb.frontend)
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &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);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: No tda826x found!\n", __func__);
- goto detach_frontend;
- }
- if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0x08, 0, 0) == NULL) {
- wprintk("%s: No ISL6421 found!\n", __func__);
- goto detach_frontend;
- }
- }
- break;
- case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &medion_cardbus,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
- fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &dev->i2c_adap, medion_cardbus.tuner_address,
- TUNER_PHILIPS_FMD1216ME_MK3);
- }
- break;
- case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
- fe0->dvb.frontend = dvb_attach(tda10046_attach,
- &philips_europa_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
- fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
- }
- break;
- case SAA7134_BOARD_CINERGY_HT_PCMCIA:
- if (configure_tda827x_fe(dev, &cinergy_ht_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_CINERGY_HT_PCI:
- if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_PHILIPS_TIGER_S:
- if (configure_tda827x_fe(dev, &philips_tiger_s_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_ASUS_P7131_4871:
- if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- if (configure_tda827x_fe(dev, &avermedia_super_007_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
- if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
- &tda827x_cfg_2_sw42) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_PHILIPS_SNAKE:
- fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: No tda826x found!\n", __func__);
- goto detach_frontend;
- }
- if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0, 0) == NULL) {
- wprintk("%s: No lnbp21 found!\n", __func__);
- goto detach_frontend;
- }
- }
- break;
- case SAA7134_BOARD_CREATIX_CTX953:
- if (configure_tda827x_fe(dev, &md8800_dvbt_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
- if (configure_tda827x_fe(dev, &philips_tiger_s_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
- dprintk("AverMedia E506R dvb setup\n");
- saa7134_set_gpio(dev, 25, 0);
- msleep(10);
- saa7134_set_gpio(dev, 25, 1);
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &avermedia_xc3028_mt352_dev,
- &dev->i2c_adap);
- attach_xc3028 = 1;
- break;
- case SAA7134_BOARD_MD7134_BRIDGE_2:
- fe0->dvb.frontend = dvb_attach(tda10086_attach,
- &sd1878_4m, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- struct dvb_frontend *fe;
- if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
- &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
- wprintk("%s: MD7134 DVB-S, no SD1878 "
- "found !\n", __func__);
- goto detach_frontend;
- }
- /* we need to open the i2c gate (we know it exists) */
- fe = fe0->dvb.frontend;
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL) {
- wprintk("%s: MD7134 DVB-S, no ISL6405 "
- "found !\n", __func__);
- goto detach_frontend;
- }
- fe->ops.i2c_gate_ctrl(fe, 0);
- dev->original_set_voltage = fe->ops.set_voltage;
- fe->ops.set_voltage = md8800_set_voltage;
- dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
- fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
- }
- break;
- case SAA7134_BOARD_AVERMEDIA_M103:
- saa7134_set_gpio(dev, 25, 0);
- msleep(10);
- saa7134_set_gpio(dev, 25, 1);
- fe0->dvb.frontend = dvb_attach(mt352_attach,
- &avermedia_xc3028_mt352_dev,
- &dev->i2c_adap);
- attach_xc3028 = 1;
- break;
- case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
- if (!use_frontend) { /* terrestrial */
- if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- } else { /* satellite */
- fe0->dvb.frontend = dvb_attach(tda10086_attach,
- &flydvbs, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda826x_attach,
- fe0->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: Asus Tiger 3in1, no "
- "tda826x found!\n", __func__);
- goto detach_frontend;
- }
- if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0, 0) == NULL) {
- wprintk("%s: Asus Tiger 3in1, no lnbp21"
- " found!\n", __func__);
- goto detach_frontend;
- }
- }
- }
- break;
- case SAA7134_BOARD_ASUSTeK_PS3_100:
- if (!use_frontend) { /* terrestrial */
- if (configure_tda827x_fe(dev, &asus_ps3_100_config,
- &tda827x_cfg_2) < 0)
- goto detach_frontend;
- } else { /* satellite */
- fe0->dvb.frontend = dvb_attach(tda10086_attach,
- &flydvbs, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(tda826x_attach,
- fe0->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL) {
- wprintk("%s: Asus My Cinema PS3-100, no "
- "tda826x found!\n", __func__);
- goto detach_frontend;
- }
- if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0, 0) == NULL) {
- wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
- " found!\n", __func__);
- goto detach_frontend;
- }
- }
- }
- break;
- case SAA7134_BOARD_ASUSTeK_TIGER:
- if (configure_tda827x_fe(dev, &philips_tiger_config,
- &tda827x_cfg_0) < 0)
- goto detach_frontend;
- break;
- case SAA7134_BOARD_BEHOLD_H6:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &behold_h6_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216MEX_MK3);
- }
- break;
- case SAA7134_BOARD_BEHOLD_X7:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &behold_x7_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &dev->i2c_adap, &behold_x7_tunerconfig);
- }
- break;
- case SAA7134_BOARD_BEHOLD_H7:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &behold_x7_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &dev->i2c_adap, &behold_x7_tunerconfig);
- }
- break;
- case SAA7134_BOARD_AVERMEDIA_A700_PRO:
- case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
- /* Zarlink ZL10313 */
- fe0->dvb.frontend = dvb_attach(mt312_attach,
- &avertv_a700_mt312, &dev->i2c_adap);
- if (fe0->dvb.frontend) {
- if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
- &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
- wprintk("%s: No zl10036 found!\n",
- __func__);
- }
- }
- break;
- case SAA7134_BOARD_VIDEOMATE_S350:
- fe0->dvb.frontend = dvb_attach(mt312_attach,
- &zl10313_compro_s350_config, &dev->i2c_adap);
- if (fe0->dvb.frontend)
- if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_adap) == NULL)
- wprintk("%s: No zl10039 found!\n",
- __func__);
-
- break;
- case SAA7134_BOARD_VIDEOMATE_T750:
- fe0->dvb.frontend = dvb_attach(zl10353_attach,
- &videomate_t750_zl10353_config,
- &dev->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (dvb_attach(qt1010_attach,
- fe0->dvb.frontend,
- &dev->i2c_adap,
- &videomate_t750_qt1010_config) == NULL)
- wprintk("error attaching QT1010\n");
- }
- break;
- case SAA7134_BOARD_ZOLID_HYBRID_PCI:
- fe0->dvb.frontend = dvb_attach(tda10048_attach,
- &zolid_tda10048_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,
- &zolid_tda18271_config);
- }
- break;
- case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
- fe0->dvb.frontend = dvb_attach(tda10048_attach,
- &dtv1000s_tda10048_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,
- &dtv1000s_tda18271_config);
- }
- break;
- case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
- /* Switch to digital mode */
- saa7134_tuner_callback(dev, 0,
- TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
- fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
- &kworld_mb86a20s_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_tda18271_config);
- fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
- }
-
- /* mb86a20s need to use the I2C gateway */
- break;
- case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
- fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
- &prohdtv_pro2_lgs8g75_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,
- &prohdtv_pro2_tda18271_config);
- }
- break;
- default:
- wprintk("Huh? unknown DVB card?\n");
- break;
- }
-
- if (attach_xc3028) {
- struct dvb_frontend *fe;
- struct xc2028_config cfg = {
- .i2c_adap = &dev->i2c_adap,
- .i2c_addr = 0x61,
- };
-
- if (!fe0->dvb.frontend)
- goto detach_frontend;
-
- fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
- if (!fe) {
- printk(KERN_ERR "%s/2: xc3028 attach failed\n",
- dev->name);
- goto detach_frontend;
- }
- }
-
- if (NULL == fe0->dvb.frontend) {
- printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
- goto detach_frontend;
- }
- /* define general-purpose callback pointer */
- fe0->dvb.frontend->callback = saa7134_tuner_callback;
-
- /* register everything else */
- ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
- &dev->pci->dev, adapter_nr, 0, NULL);
-
- /* this sequence is necessary to make the tda1004x load its firmware
- * and to enter analog mode of hybrid boards
- */
- if (!ret) {
- if (fe0->dvb.frontend->ops.init)
- fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
- if (fe0->dvb.frontend->ops.sleep)
- fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
- if (fe0->dvb.frontend->ops.tuner_ops.sleep)
- fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
- }
- return ret;
-
-detach_frontend:
- videobuf_dvb_dealloc_frontends(&dev->frontends);
- return -EINVAL;
-}
-
-static int dvb_fini(struct saa7134_dev *dev)
-{
- struct videobuf_dvb_frontend *fe0;
-
- /* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
- if (!fe0)
- return -EINVAL;
-
- /* FIXME: I suspect that this code is bogus, since the entry for
- Pinnacle 300I DVB-T PAL already defines the proper init to allow
- the detection of mt2032 (TDA9887_PORT2_INACTIVE)
- */
- if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
- struct v4l2_priv_tun_config tda9887_cfg;
- static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &on;
-
- /* otherwise we don't detect the tuner on next insmod */
- saa_call_all(dev, tuner, s_config, &tda9887_cfg);
- } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
- if ((dev->eedata[2] == 0x07) && use_frontend) {
- /* turn off the 2nd lnb supply */
- u8 data = 0x80;
- struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
- struct dvb_frontend *fe;
- fe = fe0->dvb.frontend;
- if (fe->ops.i2c_gate_ctrl) {
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &msg, 1);
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- }
- }
- videobuf_dvb_unregister_bus(&dev->frontends);
- return 0;
-}
-
-static struct saa7134_mpeg_ops dvb_ops = {
- .type = SAA7134_MPEG_DVB,
- .init = dvb_init,
- .fini = dvb_fini,
-};
-
-static int __init dvb_register(void)
-{
- return saa7134_ts_register(&dvb_ops);
-}
-
-static void __exit dvb_unregister(void)
-{
- saa7134_ts_unregister(&dvb_ops);
-}
-
-module_init(dvb_register);
-module_exit(dvb_unregister);
-
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
deleted file mode 100644
index 05c6e217d8a7..000000000000
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- *
- * handle saa7134 IR remotes via linux kernel input layer.
- *
- * 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
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-#include "saa7134-reg.h"
-#include "saa7134.h"
-
-#define MODULE_NAME "saa7134"
-
-static unsigned int disable_ir;
-module_param(disable_ir, int, 0444);
-MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
-
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
-
-static int pinnacle_remote;
-module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
-MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
-
-#define dprintk(fmt, arg...) if (ir_debug) \
- printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
-#define i2cdprintk(fmt, arg...) if (ir_debug) \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
-
-/* Helper function for raw decoding at GPIO16 or GPIO18 */
-static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
-
-/* -------------------- GPIO generic keycode builder -------------------- */
-
-static int build_key(struct saa7134_dev *dev)
-{
- struct saa7134_card_ir *ir = dev->remote;
- u32 gpio, data;
-
- /* here comes the additional handshake steps for some cards */
- switch (dev->board) {
- case SAA7134_BOARD_GOTVIEW_7135:
- saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
- saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
- break;
- }
- /* 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);
- if (ir->polling) {
- if (ir->last_gpio == gpio)
- return 0;
- ir->last_gpio = gpio;
- }
-
- data = ir_extract_bits(gpio, ir->mask_keycode);
- dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
- gpio, ir->mask_keycode, data);
-
- switch (dev->board) {
- case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
- if (data == ir->mask_keycode)
- rc_keyup(ir->dev);
- else
- rc_keydown_notimeout(ir->dev, data, 0);
- return 0;
- }
-
- if (ir->polling) {
- if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
- (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
- } else {
- rc_keyup(ir->dev);
- }
- }
- else { /* IRQ driven mode - handle key press and release in one go */
- if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
- (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
- rc_keyup(ir->dev);
- }
- }
-
- return 0;
-}
-
-/* --------------------- Chip specific I2C key builders ----------------- */
-
-static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- int gpio;
- int attempt = 0;
- unsigned char b;
-
- /* We need this to access GPI Used by the saa_readl macro. */
- struct saa7134_dev *dev = ir->c->adapter->algo_data;
-
- if (dev == NULL) {
- i2cdprintk("get_key_flydvb_trio: "
- "ir->c->adapter->algo_data is NULL!\n");
- return -EIO;
- }
-
- /* rising SAA7134_GPIGPRESCAN 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);
-
- if (0x40000 & ~gpio)
- return 0; /* No button press */
-
- /* No button press - only before first key pressed */
- if (b == 0xFF)
- return 0;
-
- /* poll IR chip */
- /* weak up the IR chip */
- b = 0;
-
- while (1 != i2c_master_send(ir->c, &b, 1)) {
- if ((attempt++) < 10) {
- /*
- * wait a bit for next attempt -
- * I don't know how make it better
- */
- msleep(10);
- continue;
- }
- i2cdprintk("send wake up byte to pic16C505 (IR chip)"
- "failed %dx\n", attempt);
- return -EIO;
- }
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
-
- *ir_key = b;
- *ir_raw = b;
- return 1;
-}
-
-static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
-{
- unsigned char b;
- 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_msi_tvanywhere_plus: "
- "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&0x40 is pulsed low when a button is pressed. Don't do
- I2C receive if gpio&0x40 is not low. */
-
- if (gpio & 0x40)
- 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_msi_tvanywhere_plus: Key = 0x%02X\n", b);
- *ir_key = b;
- *ir_raw = b;
- 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;
-
- /* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
-
- /* no button press */
- if (b==0)
- return 0;
-
- /* repeating */
- if (b & 0x80)
- return 1;
-
- *ir_key = b;
- *ir_raw = b;
- return 1;
-}
-
-static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- unsigned char buf[5];
-
- /* poll IR chip */
- if (5 != i2c_master_recv(ir->c, buf, 5))
- return -EIO;
-
- /* Check if some key were pressed */
- if (!(buf[0] & 0x80))
- return 0;
-
- /*
- * 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;
-}
-
-
-static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- unsigned char data[12];
- u32 gpio;
-
- struct saa7134_dev *dev = ir->c->adapter->algo_data;
-
- /* 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);
-
- if (0x400000 & ~gpio)
- return 0; /* No button press */
-
- ir->c->addr = 0x5a >> 1;
-
- if (12 != i2c_master_recv(ir->c, data, 12)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
-
- if (data[9] != (unsigned char)(~data[8]))
- return 0;
-
- *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
- *ir_key = *ir_raw;
-
- return 1;
-}
-
-/* Common (grey or coloured) pinnacle PCTV remote handling
- *
- */
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
- int parity_offset, int marker, int code_modulo)
-{
- unsigned char b[4];
- unsigned int start = 0,parity = 0,code = 0;
-
- /* poll IR chip */
- if (4 != i2c_master_recv(ir->c, b, 4)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
-
- for (start = 0; start < ARRAY_SIZE(b); start++) {
- if (b[start] == marker) {
- code=b[(start+parity_offset + 1) % 4];
- parity=b[(start+parity_offset) % 4];
- }
- }
-
- /* Empty Request */
- if (parity == 0)
- return 0;
-
- /* Repeating... */
- if (ir->old == parity)
- return 0;
-
- ir->old = parity;
-
- /* drop special codes when a key is held down a long time for the grey controller
- In this case, the second bit of the code is asserted */
- if (marker == 0xfe && (code & 0x40))
- return 0;
-
- code %= code_modulo;
-
- *ir_raw = code;
- *ir_key = code;
-
- i2cdprintk("Pinnacle PCTV key %02x\n", code);
-
- return 1;
-}
-
-/* The grey pinnacle PCTV remote
- *
- * There are one issue with this remote:
- * - I2c packet does not change when the same key is pressed quickly. The workaround
- * is to hold down each key for about half a second, so that another code is generated
- * in the i2c packet, and the function can distinguish key presses.
- *
- * Sylvain Pasche <sylvain.pasche@gmail.com>
- */
-static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-
- return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
-}
-
-
-/* The new pinnacle PCTV remote (with the colored buttons)
- *
- * Ricardo Cerqueira <v4l@cerqueira.org>
- */
-static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
-
- return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
-}
-
-void saa7134_input_irq(struct saa7134_dev *dev)
-{
- struct saa7134_card_ir *ir;
-
- if (!dev || !dev->remote)
- return;
-
- ir = dev->remote;
- if (!ir->running)
- return;
-
- if (!ir->polling && !ir->raw_decode) {
- build_key(dev);
- } else if (ir->raw_decode) {
- saa7134_raw_decode_irq(dev);
- }
-}
-
-static void saa7134_input_timer(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *)data;
- struct saa7134_card_ir *ir = dev->remote;
-
- build_key(dev);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
-}
-
-static void ir_raw_decode_timer_end(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *)data;
- struct saa7134_card_ir *ir = dev->remote;
-
- ir_raw_event_handle(dev->remote->dev);
-
- ir->active = false;
-}
-
-static int __saa7134_ir_start(void *priv)
-{
- struct saa7134_dev *dev = priv;
- struct saa7134_card_ir *ir;
-
- if (!dev || !dev->remote)
- return -EINVAL;
-
- ir = dev->remote;
- if (ir->running)
- return 0;
-
- /* Moved here from saa7134_input_init1() because the latter
- * is not called on device resume */
- switch (dev->board) {
- case SAA7134_BOARD_MD2819:
- case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
- case SAA7134_BOARD_AVERMEDIA_305:
- case SAA7134_BOARD_AVERMEDIA_307:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
- case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
- case SAA7134_BOARD_AVERMEDIA_M102:
- case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
- /* Without this we won't receive key up events */
- saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
- saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
- break;
- case SAA7134_BOARD_AVERMEDIA_777:
- case SAA7134_BOARD_AVERMEDIA_A16AR:
- /* Without this we won't receive key up events */
- saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
- saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
- break;
- case SAA7134_BOARD_AVERMEDIA_A16D:
- /* Without this we won't receive key up events */
- saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
- saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
- break;
- case SAA7134_BOARD_GOTVIEW_7135:
- saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
- break;
- }
-
- ir->running = true;
- ir->active = false;
-
- if (ir->polling) {
- setup_timer(&ir->timer, saa7134_input_timer,
- (unsigned long)dev);
- ir->timer.expires = jiffies + HZ;
- add_timer(&ir->timer);
- } else if (ir->raw_decode) {
- /* set timer_end for code completion */
- setup_timer(&ir->timer, ir_raw_decode_timer_end,
- (unsigned long)dev);
- }
-
- return 0;
-}
-
-static void __saa7134_ir_stop(void *priv)
-{
- struct saa7134_dev *dev = priv;
- struct saa7134_card_ir *ir;
-
- if (!dev || !dev->remote)
- return;
-
- ir = dev->remote;
- if (!ir->running)
- return;
-
- if (ir->polling || ir->raw_decode)
- del_timer_sync(&ir->timer);
-
- ir->active = false;
- ir->running = false;
-
- return;
-}
-
-int saa7134_ir_start(struct saa7134_dev *dev)
-{
- if (dev->remote->users)
- return __saa7134_ir_start(dev);
-
- return 0;
-}
-
-void saa7134_ir_stop(struct saa7134_dev *dev)
-{
- if (dev->remote->users)
- __saa7134_ir_stop(dev);
-}
-
-static int saa7134_ir_open(struct rc_dev *rc)
-{
- struct saa7134_dev *dev = rc->priv;
-
- dev->remote->users++;
- return __saa7134_ir_start(dev);
-}
-
-static void saa7134_ir_close(struct rc_dev *rc)
-{
- struct saa7134_dev *dev = rc->priv;
-
- dev->remote->users--;
- if (!dev->remote->users)
- __saa7134_ir_stop(dev);
-}
-
-int saa7134_input_init1(struct saa7134_dev *dev)
-{
- struct saa7134_card_ir *ir;
- struct rc_dev *rc;
- char *ir_codes = NULL;
- u32 mask_keycode = 0;
- u32 mask_keydown = 0;
- u32 mask_keyup = 0;
- unsigned polling = 0;
- bool raw_decode = false;
- int err;
-
- if (dev->has_remote != SAA7134_REMOTE_GPIO)
- return -ENODEV;
- if (disable_ir)
- return -ENODEV;
-
- /* detect & configure */
- switch (dev->board) {
- case SAA7134_BOARD_FLYVIDEO2000:
- case SAA7134_BOARD_FLYVIDEO3000:
- case SAA7134_BOARD_FLYTVPLATINUM_FM:
- case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
- case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
- ir_codes = RC_MAP_FLYVIDEO;
- mask_keycode = 0xEC00000;
- mask_keydown = 0x0040000;
- break;
- case SAA7134_BOARD_CINERGY400:
- case SAA7134_BOARD_CINERGY600:
- case SAA7134_BOARD_CINERGY600_MK3:
- ir_codes = RC_MAP_CINERGY;
- mask_keycode = 0x00003f;
- mask_keyup = 0x040000;
- break;
- case SAA7134_BOARD_ECS_TVP3XP:
- case SAA7134_BOARD_ECS_TVP3XP_4CB5:
- ir_codes = RC_MAP_EZTV;
- mask_keycode = 0x00017c;
- mask_keyup = 0x000002;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_KWORLD_XPERT:
- case SAA7134_BOARD_AVACSSMARTTV:
- ir_codes = RC_MAP_PIXELVIEW;
- mask_keycode = 0x00001F;
- mask_keyup = 0x000020;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_MD2819:
- case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
- case SAA7134_BOARD_AVERMEDIA_305:
- case SAA7134_BOARD_AVERMEDIA_307:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
- case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
- case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
- case SAA7134_BOARD_AVERMEDIA_M102:
- case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
- ir_codes = RC_MAP_AVERMEDIA;
- mask_keycode = 0x0007C8;
- mask_keydown = 0x000010;
- polling = 50; // ms
- /* GPIO stuff moved to __saa7134_ir_start() */
- break;
- case SAA7134_BOARD_AVERMEDIA_M135A:
- ir_codes = RC_MAP_AVERMEDIA_M135A;
- mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- case SAA7134_BOARD_AVERMEDIA_M733A:
- ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
- mask_keydown = 0x0040000;
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- case SAA7134_BOARD_AVERMEDIA_777:
- case SAA7134_BOARD_AVERMEDIA_A16AR:
- ir_codes = RC_MAP_AVERMEDIA;
- mask_keycode = 0x02F200;
- mask_keydown = 0x000400;
- polling = 50; // ms
- /* GPIO stuff moved to __saa7134_ir_start() */
- break;
- case SAA7134_BOARD_AVERMEDIA_A16D:
- ir_codes = RC_MAP_AVERMEDIA_A16D;
- mask_keycode = 0x02F200;
- mask_keydown = 0x000400;
- polling = 50; /* ms */
- /* GPIO stuff moved to __saa7134_ir_start() */
- break;
- case SAA7134_BOARD_KWORLD_TERMINATOR:
- ir_codes = RC_MAP_PIXELVIEW;
- mask_keycode = 0x00001f;
- mask_keyup = 0x000060;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_MANLI_MTV001:
- case SAA7134_BOARD_MANLI_MTV002:
- ir_codes = RC_MAP_MANLI;
- mask_keycode = 0x001f00;
- mask_keyup = 0x004000;
- polling = 50; /* ms */
- break;
- case SAA7134_BOARD_BEHOLD_409FM:
- case SAA7134_BOARD_BEHOLD_401:
- case SAA7134_BOARD_BEHOLD_403:
- case SAA7134_BOARD_BEHOLD_403FM:
- case SAA7134_BOARD_BEHOLD_405:
- case SAA7134_BOARD_BEHOLD_405FM:
- case SAA7134_BOARD_BEHOLD_407:
- case SAA7134_BOARD_BEHOLD_407FM:
- case SAA7134_BOARD_BEHOLD_409:
- case SAA7134_BOARD_BEHOLD_505FM:
- case SAA7134_BOARD_BEHOLD_505RDS_MK5:
- case SAA7134_BOARD_BEHOLD_505RDS_MK3:
- case SAA7134_BOARD_BEHOLD_507_9FM:
- case SAA7134_BOARD_BEHOLD_507RDS_MK3:
- case SAA7134_BOARD_BEHOLD_507RDS_MK5:
- ir_codes = RC_MAP_MANLI;
- mask_keycode = 0x003f00;
- mask_keyup = 0x004000;
- polling = 50; /* ms */
- break;
- case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
- ir_codes = RC_MAP_BEHOLD_COLUMBUS;
- mask_keycode = 0x003f00;
- mask_keyup = 0x004000;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
- ir_codes = RC_MAP_PCTV_SEDNA;
- mask_keycode = 0x001f00;
- mask_keyup = 0x004000;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_GOTVIEW_7135:
- ir_codes = RC_MAP_GOTVIEW7135;
- mask_keycode = 0x0003CC;
- mask_keydown = 0x000010;
- polling = 5; /* ms */
- /* GPIO stuff moved to __saa7134_ir_start() */
- break;
- case SAA7134_BOARD_VIDEOMATE_TV_PVR:
- case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
- case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
- ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
- mask_keycode = 0x00003F;
- mask_keyup = 0x400000;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_PROTEUS_2309:
- ir_codes = RC_MAP_PROTEUS_2309;
- mask_keycode = 0x00007F;
- mask_keyup = 0x000080;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_VIDEOMATE_DVBT_300:
- case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
- mask_keycode = 0x003F00;
- mask_keyup = 0x040000;
- break;
- case SAA7134_BOARD_FLYDVBS_LR300:
- case SAA7134_BOARD_FLYDVBT_LR301:
- case SAA7134_BOARD_FLYDVBTDUO:
- ir_codes = RC_MAP_FLYDVB;
- mask_keycode = 0x0001F00;
- mask_keydown = 0x0040000;
- break;
- case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
- ir_codes = RC_MAP_ASUS_PC39;
- mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- case SAA7134_BOARD_ASUSTeK_PS3_100:
- ir_codes = RC_MAP_ASUS_PS3_100;
- mask_keydown = 0x0040000;
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- case SAA7134_BOARD_ENCORE_ENLTV:
- case SAA7134_BOARD_ENCORE_ENLTV_FM:
- ir_codes = RC_MAP_ENCORE_ENLTV;
- mask_keycode = 0x00007f;
- mask_keyup = 0x040000;
- polling = 50; // ms
- break;
- case SAA7134_BOARD_ENCORE_ENLTV_FM53:
- case SAA7134_BOARD_ENCORE_ENLTV_FM3:
- ir_codes = RC_MAP_ENCORE_ENLTV_FM53;
- mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- case SAA7134_BOARD_10MOONSTVMASTER3:
- ir_codes = RC_MAP_ENCORE_ENLTV;
- mask_keycode = 0x5f80000;
- mask_keyup = 0x8000000;
- polling = 50; //ms
- break;
- case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
- ir_codes = RC_MAP_GENIUS_TVGO_A11MCE;
- mask_keycode = 0xff;
- mask_keydown = 0xf00000;
- polling = 50; /* ms */
- break;
- case SAA7134_BOARD_REAL_ANGEL_220:
- ir_codes = RC_MAP_REAL_AUDIO_220_32_KEYS;
- mask_keycode = 0x3f00;
- mask_keyup = 0x4000;
- polling = 50; /* ms */
- break;
- case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
- ir_codes = RC_MAP_KWORLD_PLUS_TV_ANALOG;
- mask_keycode = 0x7f;
- polling = 40; /* ms */
- break;
- case SAA7134_BOARD_VIDEOMATE_S350:
- ir_codes = RC_MAP_VIDEOMATE_S350;
- mask_keycode = 0x003f00;
- mask_keydown = 0x040000;
- break;
- case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
- ir_codes = RC_MAP_WINFAST;
- mask_keycode = 0x5f00;
- mask_keyup = 0x020000;
- polling = 50; /* ms */
- break;
- case SAA7134_BOARD_VIDEOMATE_M1F:
- ir_codes = RC_MAP_VIDEOMATE_K100;
- mask_keycode = 0x0ff00;
- mask_keyup = 0x040000;
- break;
- case SAA7134_BOARD_HAUPPAUGE_HVR1150:
- case SAA7134_BOARD_HAUPPAUGE_HVR1120:
- ir_codes = RC_MAP_HAUPPAUGE;
- mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
- mask_keyup = 0x0040000;
- mask_keycode = 0xffff;
- raw_decode = true;
- break;
- }
- if (NULL == ir_codes) {
- printk("%s: Oops: IR config error [card=%d]\n",
- dev->name, dev->board);
- return -ENODEV;
- }
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- rc = rc_allocate_device();
- if (!ir || !rc) {
- err = -ENOMEM;
- goto err_out_free;
- }
-
- ir->dev = rc;
- dev->remote = ir;
-
- /* init hardware-specific stuff */
- ir->mask_keycode = mask_keycode;
- ir->mask_keydown = mask_keydown;
- ir->mask_keyup = mask_keyup;
- ir->polling = polling;
- ir->raw_decode = raw_decode;
-
- /* init input device */
- snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
- saa7134_boards[dev->board].name);
- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
- pci_name(dev->pci));
-
- rc->priv = dev;
- rc->open = saa7134_ir_open;
- rc->close = saa7134_ir_close;
- if (raw_decode)
- rc->driver_type = RC_DRIVER_IR_RAW;
-
- rc->input_name = ir->name;
- rc->input_phys = ir->phys;
- rc->input_id.bustype = BUS_PCI;
- rc->input_id.version = 1;
- if (dev->pci->subsystem_vendor) {
- rc->input_id.vendor = dev->pci->subsystem_vendor;
- rc->input_id.product = dev->pci->subsystem_device;
- } else {
- rc->input_id.vendor = dev->pci->vendor;
- rc->input_id.product = dev->pci->device;
- }
- rc->dev.parent = &dev->pci->dev;
- rc->map_name = ir_codes;
- rc->driver_name = MODULE_NAME;
-
- err = rc_register_device(rc);
- if (err)
- goto err_out_free;
-
- return 0;
-
-err_out_free:
- rc_free_device(rc);
- dev->remote = NULL;
- kfree(ir);
- return err;
-}
-
-void saa7134_input_fini(struct saa7134_dev *dev)
-{
- if (NULL == dev->remote)
- return;
-
- saa7134_ir_stop(dev);
- rc_unregister_device(dev->remote->dev);
- kfree(dev->remote);
- dev->remote = NULL;
-}
-
-void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
-{
- struct i2c_board_info info;
- struct i2c_msg msg_msi = {
- .addr = 0x50,
- .flags = I2C_M_RD,
- .len = 0,
- .buf = NULL,
- };
- int rc;
-
- if (disable_ir) {
- dprintk("IR has been disabled, not probing for i2c remote\n");
- return;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- memset(&dev->init_data, 0, sizeof(dev->init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-
- switch (dev->board) {
- case SAA7134_BOARD_PINNACLE_PCTV_110i:
- case SAA7134_BOARD_PINNACLE_PCTV_310i:
- dev->init_data.name = "Pinnacle PCTV";
- if (pinnacle_remote == 0) {
- dev->init_data.get_key = get_key_pinnacle_color;
- dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR;
- info.addr = 0x47;
- } else {
- dev->init_data.get_key = get_key_pinnacle_grey;
- dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
- info.addr = 0x47;
- }
- break;
- case SAA7134_BOARD_UPMOST_PURPLE_TV:
- dev->init_data.name = "Purple TV";
- dev->init_data.get_key = get_key_purpletv;
- dev->init_data.ir_codes = RC_MAP_PURPLETV;
- info.addr = 0x7a;
- break;
- case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
- dev->init_data.name = "MSI TV@nywhere Plus";
- dev->init_data.get_key = get_key_msi_tvanywhere_plus;
- dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
- /*
- * MSI TV@nyware Plus requires more frequent polling
- * otherwise it will miss some keypresses
- */
- dev->init_data.polling_interval = 50;
- 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_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;
- dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
- info.addr = 0x71;
- break;
- case SAA7134_BOARD_BEHOLD_607FM_MK3:
- case SAA7134_BOARD_BEHOLD_607FM_MK5:
- case SAA7134_BOARD_BEHOLD_609FM_MK3:
- case SAA7134_BOARD_BEHOLD_609FM_MK5:
- case SAA7134_BOARD_BEHOLD_607RDS_MK3:
- case SAA7134_BOARD_BEHOLD_607RDS_MK5:
- case SAA7134_BOARD_BEHOLD_609RDS_MK3:
- case SAA7134_BOARD_BEHOLD_609RDS_MK5:
- case SAA7134_BOARD_BEHOLD_M6:
- case SAA7134_BOARD_BEHOLD_M63:
- case SAA7134_BOARD_BEHOLD_M6_EXTRA:
- case SAA7134_BOARD_BEHOLD_H6:
- case SAA7134_BOARD_BEHOLD_X7:
- case SAA7134_BOARD_BEHOLD_H7:
- case SAA7134_BOARD_BEHOLD_A7:
- dev->init_data.name = "BeholdTV";
- dev->init_data.get_key = get_key_beholdm6xx;
- dev->init_data.ir_codes = RC_MAP_BEHOLD;
- dev->init_data.type = RC_TYPE_NEC;
- info.addr = 0x2d;
- break;
- case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
- case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
- info.addr = 0x40;
- break;
- case SAA7134_BOARD_FLYDVB_TRIO:
- dev->init_data.name = "FlyDVB Trio";
- dev->init_data.get_key = get_key_flydvb_trio;
- dev->init_data.ir_codes = RC_MAP_FLYDVB;
- info.addr = 0x0b;
- break;
- default:
- dprintk("No I2C IR support for board %x\n", dev->board);
- return;
- }
-
- if (dev->init_data.name)
- info.platform_data = &dev->init_data;
- i2c_new_device(&dev->i2c_adap, &info);
-}
-
-static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
-{
- struct saa7134_card_ir *ir = dev->remote;
- unsigned long timeout;
- int space;
-
- /* Generate initial event */
- saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
- ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
-
- /*
- * Wait 15 ms from the start of the first IR event before processing
- * the event. This time is enough for NEC protocol. May need adjustments
- * to work with other protocols.
- */
- if (!ir->active) {
- timeout = jiffies + msecs_to_jiffies(15);
- mod_timer(&ir->timer, timeout);
- ir->active = true;
- }
-
- return 1;
-}
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
deleted file mode 100644
index 89c8333736a2..000000000000
--- a/drivers/media/video/saa7134/saa7134.h
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- *
- * v4l2 device driver for philips saa7134 based TV cards
- *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
- *
- * 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.
- */
-
-#define SAA7134_VERSION "0, 2, 17"
-
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/kdev_t.h>
-#include <linux/input.h>
-#include <linux/notifier.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <media/tuner.h>
-#include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/videobuf-dma-sg.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
-#include <media/videobuf-dvb.h>
-#endif
-
-#define UNSET (-1U)
-
-/* ----------------------------------------------------------- */
-/* enums */
-
-enum saa7134_tvaudio_mode {
- TVAUDIO_FM_MONO = 1,
- TVAUDIO_FM_BG_STEREO = 2,
- TVAUDIO_FM_SAT_STEREO = 3,
- TVAUDIO_FM_K_STEREO = 4,
- TVAUDIO_NICAM_AM = 5,
- TVAUDIO_NICAM_FM = 6,
-};
-
-enum saa7134_audio_in {
- TV = 1,
- LINE1 = 2,
- LINE2 = 3,
- LINE2_LEFT,
-};
-
-enum saa7134_video_out {
- CCIR656 = 1,
-};
-
-/* ----------------------------------------------------------- */
-/* static data */
-
-struct saa7134_tvnorm {
- char *name;
- v4l2_std_id id;
-
- /* video decoder */
- unsigned int sync_control;
- unsigned int luma_control;
- unsigned int chroma_ctrl1;
- unsigned int chroma_gain;
- unsigned int chroma_ctrl2;
- unsigned int vgate_misc;
-
- /* video scaler */
- unsigned int h_start;
- unsigned int h_stop;
- unsigned int video_v_start;
- unsigned int video_v_stop;
- unsigned int vbi_v_start_0;
- unsigned int vbi_v_stop_0;
- unsigned int src_timing;
- unsigned int vbi_v_start_1;
-};
-
-struct saa7134_tvaudio {
- char *name;
- v4l2_std_id std;
- enum saa7134_tvaudio_mode mode;
- int carr1;
- int carr2;
-};
-
-struct saa7134_format {
- char *name;
- unsigned int fourcc;
- unsigned int depth;
- unsigned int pm;
- unsigned int vshift; /* vertical downsampling (for planar yuv) */
- unsigned int hshift; /* horizontal downsampling (for planar yuv) */
- unsigned int bswap:1;
- unsigned int wswap:1;
- unsigned int yuv:1;
- unsigned int planar:1;
- unsigned int uvswap:1;
-};
-
-struct saa7134_card_ir {
- struct rc_dev *dev;
-
- char name[32];
- char phys[32];
- unsigned users;
-
- u32 polling;
- u32 last_gpio;
- u32 mask_keycode, mask_keydown, mask_keyup;
-
- bool running;
- bool active;
-
- struct timer_list timer;
-
- /* IR core raw decoding */
- u32 raw_decode;
-};
-
-/* ----------------------------------------------------------- */
-/* card configuration */
-
-#define SAA7134_BOARD_NOAUTO UNSET
-#define SAA7134_BOARD_UNKNOWN 0
-#define SAA7134_BOARD_PROTEUS_PRO 1
-#define SAA7134_BOARD_FLYVIDEO3000 2
-#define SAA7134_BOARD_FLYVIDEO2000 3
-#define SAA7134_BOARD_EMPRESS 4
-#define SAA7134_BOARD_MONSTERTV 5
-#define SAA7134_BOARD_MD9717 6
-#define SAA7134_BOARD_TVSTATION_RDS 7
-#define SAA7134_BOARD_CINERGY400 8
-#define SAA7134_BOARD_MD5044 9
-#define SAA7134_BOARD_KWORLD 10
-#define SAA7134_BOARD_CINERGY600 11
-#define SAA7134_BOARD_MD7134 12
-#define SAA7134_BOARD_TYPHOON_90031 13
-#define SAA7134_BOARD_ELSA 14
-#define SAA7134_BOARD_ELSA_500TV 15
-#define SAA7134_BOARD_ASUSTeK_TVFM7134 16
-#define SAA7134_BOARD_VA1000POWER 17
-#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18
-#define SAA7134_BOARD_VIDEOMATE_TV 19
-#define SAA7134_BOARD_CRONOS_PLUS 20
-#define SAA7134_BOARD_10MOONSTVMASTER 21
-#define SAA7134_BOARD_MD2819 22
-#define SAA7134_BOARD_BMK_MPEX_TUNER 23
-#define SAA7134_BOARD_TVSTATION_DVR 24
-#define SAA7134_BOARD_ASUSTEK_TVFM7133 25
-#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26
-#define SAA7134_BOARD_MANLI_MTV002 27
-#define SAA7134_BOARD_MANLI_MTV001 28
-#define SAA7134_BOARD_TG3000TV 29
-#define SAA7134_BOARD_ECS_TVP3XP 30
-#define SAA7134_BOARD_ECS_TVP3XP_4CB5 31
-#define SAA7134_BOARD_AVACSSMARTTV 32
-#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
-#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
-#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
-#define SAA7134_BOARD_UPMOST_PURPLE_TV 36
-#define SAA7134_BOARD_ITEMS_MTV005 37
-#define SAA7134_BOARD_CINERGY200 38
-#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
-#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
-#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
-#define SAA7134_BOARD_SABRENT_SBTTVFM 42
-#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
-#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
-#define SAA7134_BOARD_AVERMEDIA_STUDIO_307 45
-#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
-#define SAA7134_BOARD_CINERGY400_CARDBUS 47
-#define SAA7134_BOARD_CINERGY600_MK3 48
-#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
-#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
-#define SAA7134_BOARD_PROVIDEO_PV952 51
-#define SAA7134_BOARD_AVERMEDIA_305 52
-#define SAA7134_BOARD_ASUSTeK_TVFM7135 53
-#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
-#define SAA7134_BOARD_FLYDVBTDUO 55
-#define SAA7134_BOARD_AVERMEDIA_307 56
-#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
-#define SAA7134_BOARD_ADS_INSTANT_TV 58
-#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
-#define SAA7134_BOARD_FLYDVBT_DUO_CARDBUS 60
-#define SAA7134_BOARD_PHILIPS_TOUGH 61
-#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62
-#define SAA7134_BOARD_KWORLD_XPERT 63
-#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
-#define SAA7134_BOARD_KWORLD_TERMINATOR 65
-#define SAA7134_BOARD_YUAN_TUN900 66
-#define SAA7134_BOARD_BEHOLD_409FM 67
-#define SAA7134_BOARD_GOTVIEW_7135 68
-#define SAA7134_BOARD_PHILIPS_EUROPA 69
-#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
-#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
-#define SAA7134_BOARD_RTD_VFG7350 72
-#define SAA7134_BOARD_RTD_VFG7330 73
-#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
-#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
-#define SAA7134_BOARD_MONSTERTV_MOBILE 76
-#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
-#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
-#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
-#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
-#define SAA7134_BOARD_PHILIPS_TIGER 81
-#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
-#define SAA7134_BOARD_CINERGY250PCI 83
-#define SAA7134_BOARD_FLYDVB_TRIO 84
-#define SAA7134_BOARD_AVERMEDIA_777 85
-#define SAA7134_BOARD_FLYDVBT_LR301 86
-#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
-#define SAA7134_BOARD_TEVION_DVBT_220RF 88
-#define SAA7134_BOARD_ELSA_700TV 89
-#define SAA7134_BOARD_KWORLD_ATSC110 90
-#define SAA7134_BOARD_AVERMEDIA_A169_B 91
-#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
-#define SAA7134_BOARD_MD7134_BRIDGE_2 93
-#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
-#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
-#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
-#define SAA7134_BOARD_FLYDVBS_LR300 97
-#define SAA7134_BOARD_PROTEUS_2309 98
-#define SAA7134_BOARD_AVERMEDIA_A16AR 99
-#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
-#define SAA7134_BOARD_PINNACLE_PCTV_310i 101
-#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
-#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
-#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
-#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
-#define SAA7134_BOARD_ENCORE_ENLTV 106
-#define SAA7134_BOARD_ENCORE_ENLTV_FM 107
-#define SAA7134_BOARD_CINERGY_HT_PCI 108
-#define SAA7134_BOARD_PHILIPS_TIGER_S 109
-#define SAA7134_BOARD_AVERMEDIA_M102 110
-#define SAA7134_BOARD_ASUS_P7131_4871 111
-#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112
-#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
-#define SAA7134_BOARD_KWORLD_DVBT_210 114
-#define SAA7134_BOARD_SABRENT_TV_PCB05 115
-#define SAA7134_BOARD_10MOONSTVMASTER3 116
-#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
-#define SAA7134_BOARD_BEHOLD_401 118
-#define SAA7134_BOARD_BEHOLD_403 119
-#define SAA7134_BOARD_BEHOLD_403FM 120
-#define SAA7134_BOARD_BEHOLD_405 121
-#define SAA7134_BOARD_BEHOLD_405FM 122
-#define SAA7134_BOARD_BEHOLD_407 123
-#define SAA7134_BOARD_BEHOLD_407FM 124
-#define SAA7134_BOARD_BEHOLD_409 125
-#define SAA7134_BOARD_BEHOLD_505FM 126
-#define SAA7134_BOARD_BEHOLD_507_9FM 127
-#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
-#define SAA7134_BOARD_BEHOLD_607FM_MK3 129
-#define SAA7134_BOARD_BEHOLD_M6 130
-#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
-#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
-#define SAA7134_BOARD_PHILIPS_SNAKE 133
-#define SAA7134_BOARD_CREATIX_CTX953 134
-#define SAA7134_BOARD_MSI_TVANYWHERE_AD11 135
-#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
-#define SAA7134_BOARD_AVERMEDIA_A16D 137
-#define SAA7134_BOARD_AVERMEDIA_M115 138
-#define SAA7134_BOARD_VIDEOMATE_T750 139
-#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
-#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
-#define SAA7134_BOARD_BEHOLD_H6 142
-#define SAA7134_BOARD_BEHOLD_M63 143
-#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144
-#define SAA7134_BOARD_AVERMEDIA_M103 145
-#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
-#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1 147
-#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
-#define SAA7134_BOARD_AVERMEDIA_M135A 149
-#define SAA7134_BOARD_REAL_ANGEL_220 150
-#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151
-#define SAA7134_BOARD_ASUSTeK_TIGER 152
-#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
-#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
-#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155
-#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156
-#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
-#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
-#define SAA7134_BOARD_BEHOLD_505RDS_MK5 159
-#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160
-#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161
-#define SAA7134_BOARD_BEHOLD_607FM_MK5 162
-#define SAA7134_BOARD_BEHOLD_609FM_MK3 163
-#define SAA7134_BOARD_BEHOLD_609FM_MK5 164
-#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165
-#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166
-#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167
-#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168
-#define SAA7134_BOARD_VIDEOMATE_S350 169
-#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
-#define SAA7134_BOARD_BEHOLD_X7 171
-#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
-#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173
-#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174
-#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
-#define SAA7134_BOARD_BEHOLD_505RDS_MK3 176
-#define SAA7134_BOARD_HAWELL_HW_404M7 177
-#define SAA7134_BOARD_BEHOLD_H7 178
-#define SAA7134_BOARD_BEHOLD_A7 179
-#define SAA7134_BOARD_AVERMEDIA_M733A 180
-#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
-#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
-#define SAA7134_BOARD_VIDEOMATE_M1F 183
-#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184
-#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_BOARD_ASUSTeK_PS3_100 190
-
-#define SAA7134_MAXBOARDS 32
-#define SAA7134_INPUT_MAX 8
-
-/* ----------------------------------------------------------- */
-/* Since we support 2 remote types, lets tell them apart */
-
-#define SAA7134_REMOTE_GPIO 1
-#define SAA7134_REMOTE_I2C 2
-
-/* ----------------------------------------------------------- */
-/* Video Output Port Register Initialization Options */
-
-#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0)
-#define SET_CLOCK_NOT_DELAYED (1 << 1)
-#define SET_CLOCK_INVERTED (1 << 2)
-#define SET_VSYNC_OFF (1 << 3)
-
-struct saa7134_input {
- char *name;
- unsigned int vmux;
- enum saa7134_audio_in amux;
- unsigned int gpio;
- unsigned int tv:1;
-};
-
-enum saa7134_mpeg_type {
- SAA7134_MPEG_UNUSED,
- SAA7134_MPEG_EMPRESS,
- SAA7134_MPEG_DVB,
-};
-
-enum saa7134_mpeg_ts_type {
- SAA7134_MPEG_TS_PARALLEL = 0,
- SAA7134_MPEG_TS_SERIAL,
-};
-
-struct saa7134_board {
- char *name;
- unsigned int audio_clock;
-
- /* input switching */
- unsigned int gpiomask;
- struct saa7134_input inputs[SAA7134_INPUT_MAX];
- struct saa7134_input radio;
- struct saa7134_input mute;
-
- /* i2c chip info */
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
- unsigned char empress_addr;
- unsigned char rds_addr;
-
- unsigned int tda9887_conf;
- unsigned int tuner_config;
-
- /* peripheral I/O */
- enum saa7134_video_out video_out;
- enum saa7134_mpeg_type mpeg;
- enum saa7134_mpeg_ts_type ts_type;
- unsigned int vid_port_opts;
- unsigned int ts_force_val:1;
-};
-
-#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
-#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
-#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
-#define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg)
-#define card(dev) (saa7134_boards[dev->board])
-#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
-
-/* ----------------------------------------------------------- */
-/* device / file handle status */
-
-#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
-#define RESOURCE_VBI 4
-
-#define INTERLACE_AUTO 0
-#define INTERLACE_ON 1
-#define INTERLACE_OFF 2
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
-#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */
-
-struct saa7134_dev;
-struct saa7134_dma;
-
-/* saa7134 page table */
-struct saa7134_pgtable {
- unsigned int size;
- __le32 *cpu;
- dma_addr_t dma;
-};
-
-/* tvaudio thread status */
-struct saa7134_thread {
- struct task_struct *thread;
- unsigned int scan1;
- unsigned int scan2;
- unsigned int mode;
- unsigned int stopped;
-};
-
-/* buffer for one video/vbi/ts frame */
-struct saa7134_buf {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
-
- /* saa7134 specific */
- struct saa7134_format *fmt;
- unsigned int top_seen;
- int (*activate)(struct saa7134_dev *dev,
- struct saa7134_buf *buf,
- struct saa7134_buf *next);
-
- /* page tables */
- struct saa7134_pgtable *pt;
-};
-
-struct saa7134_dmaqueue {
- struct saa7134_dev *dev;
- struct saa7134_buf *curr;
- struct list_head queue;
- struct timer_list timeout;
- unsigned int need_two;
-};
-
-/* video filehandle status */
-struct saa7134_fh {
- struct saa7134_dev *dev;
- unsigned int radio;
- enum v4l2_buf_type type;
- unsigned int resources;
- enum v4l2_priority prio;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip clips[8];
- unsigned int nclips;
-
- /* video capture */
- struct saa7134_format *fmt;
- unsigned int width,height;
- struct videobuf_queue cap;
- struct saa7134_pgtable pt_cap;
-
- /* vbi capture */
- struct videobuf_queue vbi;
- struct saa7134_pgtable pt_vbi;
-};
-
-/* dmasound dsp status */
-struct saa7134_dmasound {
- struct mutex lock;
- int minor_mixer;
- int minor_dsp;
- unsigned int users_dsp;
-
- /* mixer */
- enum saa7134_audio_in input;
- unsigned int count;
- unsigned int line1;
- unsigned int line2;
-
- /* dsp */
- unsigned int afmt;
- unsigned int rate;
- unsigned int channels;
- unsigned int recording_on;
- unsigned int dma_running;
- unsigned int blocks;
- unsigned int blksize;
- unsigned int bufsize;
- struct saa7134_pgtable pt;
- struct videobuf_dmabuf dma;
- unsigned int dma_blk;
- unsigned int read_offset;
- unsigned int read_count;
- void * priv_data;
- struct snd_pcm_substream *substream;
-};
-
-/* ts/mpeg status */
-struct saa7134_ts {
- /* TS capture */
- struct saa7134_pgtable pt_ts;
- int nr_packets;
- int nr_bufs;
-};
-
-/* ts/mpeg ops */
-struct saa7134_mpeg_ops {
- enum saa7134_mpeg_type type;
- struct list_head next;
- int (*init)(struct saa7134_dev *dev);
- int (*fini)(struct saa7134_dev *dev);
- void (*signal_change)(struct saa7134_dev *dev);
-};
-
-/* global device status */
-struct saa7134_dev {
- struct list_head devlist;
- struct mutex lock;
- spinlock_t slock;
- struct v4l2_prio_state prio;
- struct v4l2_device v4l2_dev;
- /* workstruct for loading modules */
- struct work_struct request_module_wk;
-
- /* insmod option/autodetected */
- int autodetected;
-
- /* various device info */
- unsigned int resources;
- struct video_device *video_dev;
- struct video_device *radio_dev;
- struct video_device *vbi_dev;
- struct saa7134_dmasound dmasound;
-
- /* infrared remote */
- int has_remote;
- struct saa7134_card_ir *remote;
-
- /* pci i/o */
- char name[32];
- int nr;
- struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
- __u32 __iomem *lmmio;
- __u8 __iomem *bmmio;
-
- /* config info */
- unsigned int board;
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
-
- unsigned int tda9887_conf;
- unsigned int gpio_value;
-
- /* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
- unsigned char eedata[256];
- int has_rds;
-
- /* video overlay */
- struct v4l2_framebuffer ovbuf;
- struct saa7134_format *ovfmt;
- unsigned int ovenable;
- enum v4l2_field ovfield;
-
- /* video+ts+vbi capture */
- struct saa7134_dmaqueue video_q;
- struct saa7134_dmaqueue vbi_q;
- unsigned int video_fieldcount;
- unsigned int vbi_fieldcount;
-
- /* various v4l controls */
- struct saa7134_tvnorm *tvnorm; /* video */
- struct saa7134_tvaudio *tvaudio;
- unsigned int ctl_input;
- int ctl_bright;
- int ctl_contrast;
- int ctl_hue;
- int ctl_saturation;
- int ctl_freq;
- int ctl_mute; /* audio */
- int ctl_volume;
- int ctl_invert; /* private */
- int ctl_mirror;
- int ctl_y_odd;
- int ctl_y_even;
- int ctl_automute;
-
- /* crop */
- struct v4l2_rect crop_bounds;
- struct v4l2_rect crop_defrect;
- struct v4l2_rect crop_current;
-
- /* other global state info */
- unsigned int automute;
- struct saa7134_thread thread;
- struct saa7134_input *input;
- struct saa7134_input *hw_input;
- unsigned int hw_mute;
- int last_carrier;
- int nosignal;
- unsigned int insuspend;
-
- /* I2C keyboard data */
- struct IR_i2c_init_data init_data;
-
- /* SAA7134_MPEG_* */
- struct saa7134_ts ts;
- struct saa7134_dmaqueue ts_q;
- int ts_started;
- struct saa7134_mpeg_ops *mops;
-
- /* SAA7134_MPEG_EMPRESS only */
- struct video_device *empress_dev;
- struct videobuf_queue empress_tsq;
- atomic_t empress_users;
- struct work_struct empress_workqueue;
- int empress_started;
-
-#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
- /* SAA7134_MPEG_DVB only */
- struct videobuf_dvb_frontends frontends;
- int (*original_demod_sleep)(struct dvb_frontend *fe);
- int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
- int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
-#endif
- void (*gate_ctrl)(struct saa7134_dev *dev, int open);
-};
-
-/* ----------------------------------------------------------- */
-
-#define saa_readl(reg) readl(dev->lmmio + (reg))
-#define saa_writel(reg,value) writel((value), dev->lmmio + (reg));
-#define saa_andorl(reg,mask,value) \
- writel((readl(dev->lmmio+(reg)) & ~(mask)) |\
- ((value) & (mask)), dev->lmmio+(reg))
-#define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit))
-#define saa_clearl(reg,bit) saa_andorl((reg),(bit),0)
-
-#define saa_readb(reg) readb(dev->bmmio + (reg))
-#define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg));
-#define saa_andorb(reg,mask,value) \
- writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\
- ((value) & (mask)), dev->bmmio+(reg))
-#define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit))
-#define saa_clearb(reg,bit) saa_andorb((reg),(bit),0)
-
-#define saa_wait(us) { udelay(us); }
-
-#define SAA7134_NORMS (\
- V4L2_STD_PAL | V4L2_STD_PAL_N | \
- V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
- V4L2_STD_NTSC | V4L2_STD_PAL_M | \
- V4L2_STD_PAL_60)
-
-#define GRP_EMPRESS (1)
-#define saa_call_all(dev, o, f, args...) do { \
- if (dev->gate_ctrl) \
- dev->gate_ctrl(dev, 1); \
- v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \
- if (dev->gate_ctrl) \
- dev->gate_ctrl(dev, 0); \
-} while (0)
-
-#define saa_call_empress(dev, o, f, args...) ({ \
- long _rc; \
- if (dev->gate_ctrl) \
- dev->gate_ctrl(dev, 1); \
- _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \
- GRP_EMPRESS, o, f , ##args); \
- if (dev->gate_ctrl) \
- dev->gate_ctrl(dev, 0); \
- _rc; \
-})
-
-/* ----------------------------------------------------------- */
-/* saa7134-core.c */
-
-extern struct list_head saa7134_devlist;
-extern struct mutex saa7134_devlist_lock;
-extern int saa7134_no_overlay;
-
-void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
-void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
-
-#define SAA7134_PGTABLE_SIZE 4096
-
-int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
-int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
- struct scatterlist *list, unsigned int length,
- unsigned int startpage);
-void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
-
-int saa7134_buffer_count(unsigned int size, unsigned int count);
-int saa7134_buffer_startpage(struct saa7134_buf *buf);
-unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
-
-int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
- struct saa7134_buf *buf);
-void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
- unsigned int state);
-void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
-void saa7134_buffer_timeout(unsigned long data);
-void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
-
-int saa7134_set_dmabits(struct saa7134_dev *dev);
-
-extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
-extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
-
-
-/* ----------------------------------------------------------- */
-/* saa7134-cards.c */
-
-extern struct saa7134_board saa7134_boards[];
-extern const unsigned int saa7134_bcount;
-extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
-
-extern int saa7134_board_init1(struct saa7134_dev *dev);
-extern int saa7134_board_init2(struct saa7134_dev *dev);
-int saa7134_tuner_callback(void *priv, int component, int command, int arg);
-
-
-/* ----------------------------------------------------------- */
-/* saa7134-i2c.c */
-
-int saa7134_i2c_register(struct saa7134_dev *dev);
-int saa7134_i2c_unregister(struct saa7134_dev *dev);
-
-
-/* ----------------------------------------------------------- */
-/* saa7134-video.c */
-
-extern unsigned int video_debug;
-extern struct video_device saa7134_video_template;
-extern struct video_device saa7134_radio_template;
-
-int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
-int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
-int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
-int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id);
-
-int saa7134_videoport_init(struct saa7134_dev *dev);
-void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
-
-int saa7134_video_init1(struct saa7134_dev *dev);
-int saa7134_video_init2(struct saa7134_dev *dev);
-void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
-void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
-
-
-/* ----------------------------------------------------------- */
-/* saa7134-ts.c */
-
-#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
-
-extern struct videobuf_queue_ops saa7134_ts_qops;
-
-int saa7134_ts_init1(struct saa7134_dev *dev);
-int saa7134_ts_fini(struct saa7134_dev *dev);
-void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
-
-int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
-void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
-
-int saa7134_ts_init_hw(struct saa7134_dev *dev);
-
-int saa7134_ts_start(struct saa7134_dev *dev);
-int saa7134_ts_stop(struct saa7134_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* saa7134-vbi.c */
-
-extern struct videobuf_queue_ops saa7134_vbi_qops;
-extern struct video_device saa7134_vbi_template;
-
-int saa7134_vbi_init1(struct saa7134_dev *dev);
-int saa7134_vbi_fini(struct saa7134_dev *dev);
-void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status);
-
-
-/* ----------------------------------------------------------- */
-/* saa7134-tvaudio.c */
-
-int saa7134_tvaudio_rx2mode(u32 rx);
-
-void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
-void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
- struct saa7134_input *in);
-void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
-int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
-
-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);
-
-void saa7134_enable_i2s(struct saa7134_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* saa7134-oss.c */
-
-extern const struct file_operations saa7134_dsp_fops;
-extern const struct file_operations saa7134_mixer_fops;
-
-int saa7134_oss_init1(struct saa7134_dev *dev);
-int saa7134_oss_fini(struct saa7134_dev *dev);
-void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
-
-/* ----------------------------------------------------------- */
-/* saa7134-input.c */
-
-#if defined(CONFIG_VIDEO_SAA7134_RC)
-int saa7134_input_init1(struct saa7134_dev *dev);
-void saa7134_input_fini(struct saa7134_dev *dev);
-void saa7134_input_irq(struct saa7134_dev *dev);
-void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
-int saa7134_ir_start(struct saa7134_dev *dev);
-void saa7134_ir_stop(struct saa7134_dev *dev);
-#else
-#define saa7134_input_init1(dev) ((void)0)
-#define saa7134_input_fini(dev) ((void)0)
-#define saa7134_input_irq(dev) ((void)0)
-#define saa7134_probe_i2c_ir(dev) ((void)0)
-#define saa7134_ir_start(dev) ((void)0)
-#define saa7134_ir_stop(dev) ((void)0)
-#endif
diff --git a/drivers/media/video/saa7164/Kconfig b/drivers/media/video/saa7164/Kconfig
deleted file mode 100644
index 353263725172..000000000000
--- a/drivers/media/video/saa7164/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config VIDEO_SAA7164
- tristate "NXP SAA7164 support"
- depends on DVB_CORE && PCI && I2C
- select I2C_ALGOBIT
- select FW_LOADER
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEOBUF_DVB
- select DVB_TDA10048 if !DVB_FE_CUSTOMISE
- select DVB_S5H1411 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
- ---help---
- This is a video4linux driver for NXP SAA7164 based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7164
-
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile
deleted file mode 100644
index 068443af30c8..000000000000
--- a/drivers/media/video/saa7164/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
- saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \
- saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o
-
-obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
-
-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-api.c b/drivers/media/video/saa7164/saa7164-api.c
deleted file mode 100644
index c8799fdaae67..000000000000
--- a/drivers/media/video/saa7164/saa7164-api.c
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- * Driver for the NXP SAA7164 PCIe bridge
- *
- * Copyright (c) 2010 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 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/wait.h>
-#include <linux/slab.h>
-
-#include "saa7164.h"
-
-int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
-{
- int ret;
-
- if (!(saa_debug & DBGLVL_CPU))
- return 0;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- i->deviceinst = 0;
- i->devicespec = 0;
- i->mode = 0;
- i->status = 0;
-
- ret = saa7164_cmd_send(dev, 0, GET_CUR,
- GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
-
- return ret;
-}
-
-int saa7164_api_collect_debug(struct saa7164_dev *dev)
-{
- struct tmComResDebugGetData d;
- u8 more = 255;
- int ret;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- while (more--) {
-
- memset(&d, 0, sizeof(d));
-
- ret = saa7164_cmd_send(dev, 0, GET_CUR,
- GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n",
- __func__, ret);
-
- if (d.dwResult != SAA_OK)
- break;
-
- printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr,
- d.ucDebugData);
- }
-
- return 0;
-}
-
-int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
-{
- struct tmComResDebugSetLevel lvl;
- int ret;
-
- dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level);
-
- /* Retrieve current state */
- ret = saa7164_cmd_send(dev, 0, GET_CUR,
- SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
-
- lvl.dwDebugLevel = level;
-
- /* set new state */
- ret = saa7164_cmd_send(dev, 0, SET_CUR,
- SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_set_vbi_format(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResProbeCommit fmt, rsp;
- int ret;
-
- dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__,
- port->nr, port->hwcfg.unitid);
-
- fmt.bmHint = 0;
- fmt.bFormatIndex = 1;
- fmt.bFrameIndex = 1;
-
- /* Probe, see if it can support this format */
- ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
- SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret);
-
- /* See of the format change was successful */
- ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
- GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret);
- } else {
- /* Compare requested vs received, should be same */
- if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) {
- dprintk(DBGLVL_API, "SET/PROBE Verified\n");
-
- /* Ask the device to select the negotiated format */
- ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
- SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() commit error, ret = 0x%x\n",
- __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
- GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n",
- __func__, ret);
-
- if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) {
- printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n",
- __func__, ret);
- } else
- dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
-
- dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
- dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n",
- rsp.bFormatIndex);
- dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n",
- rsp.bFrameIndex);
- } else
- printk(KERN_ERR "%s() compare failed\n", __func__);
- }
-
- if (ret == SAA_OK)
- dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr);
-
- return ret;
-}
-
-int saa7164_api_set_gop_size(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResEncVideoGopStructure gs;
- int ret;
-
- dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
- gs.ucRefFrameDist = port->encoder_params.refdist;
- gs.ucGOPSize = port->encoder_params.gop_size;
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_VIDEO_GOP_STRUCTURE_CONTROL,
- sizeof(gs), &gs);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_set_encoder(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResEncVideoBitRate vb;
- struct tmComResEncAudioBitRate ab;
- int ret;
-
- dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
- port->hwcfg.sourceid);
-
- if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
- port->encoder_profile = EU_PROFILE_PS_DVD;
- else
- port->encoder_profile = EU_PROFILE_TS_HQ;
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Resolution */
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Establish video bitrates */
- if (port->encoder_params.bitrate_mode ==
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
- vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
- else
- vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
- vb.dwVideoBitRate = port->encoder_params.bitrate;
- vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_VIDEO_BIT_RATE_CONTROL,
- sizeof(struct tmComResEncVideoBitRate),
- &vb);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Establish audio bitrates */
- ab.ucAudioBitRateMode = 0;
- ab.dwAudioBitRate = 384000;
- ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_AUDIO_BIT_RATE_CONTROL,
- sizeof(struct tmComResEncAudioBitRate),
- &ab);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
- ret);
-
- saa7164_api_set_aspect_ratio(port);
- saa7164_api_set_gop_size(port);
-
- return ret;
-}
-
-int saa7164_api_get_encoder(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResEncVideoBitRate v;
- struct tmComResEncAudioBitRate a;
- struct tmComResEncVideoInputAspectRatio ar;
- int ret;
-
- dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
- port->hwcfg.sourceid);
-
- port->encoder_profile = 0;
- port->video_format = 0;
- port->video_resolution = 0;
- port->audio_format = 0;
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8),
- &port->video_resolution);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Aspect Ratio */
- ar.width = 0;
- ar.height = 0;
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_VIDEO_INPUT_ASPECT_CONTROL,
- sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile);
- dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format);
- dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format);
- dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
- dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n",
- v.ucVideoBitRateMode);
- dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n",
- v.dwVideoBitRate);
- dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n",
- v.dwVideoBitRatePeak);
- dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n",
- a.ucAudioBitRateMode);
- dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n",
- a.dwAudioBitRate);
- dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n",
- a.dwAudioBitRatePeak);
- dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n",
- ar.width, ar.height);
-
- return ret;
-}
-
-int saa7164_api_set_aspect_ratio(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResEncVideoInputAspectRatio ar;
- int ret;
-
- dprintk(DBGLVL_ENC, "%s(%d)\n", __func__,
- port->encoder_params.ctl_aspect);
-
- switch (port->encoder_params.ctl_aspect) {
- case V4L2_MPEG_VIDEO_ASPECT_1x1:
- ar.width = 1;
- ar.height = 1;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_4x3:
- ar.width = 4;
- ar.height = 3;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_16x9:
- ar.width = 16;
- ar.height = 9;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_221x100:
- ar.width = 221;
- ar.height = 100;
- break;
- default:
- BUG();
- }
-
- dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__,
- port->encoder_params.ctl_aspect,
- ar.width, ar.height);
-
- /* Aspect Ratio */
- ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_VIDEO_INPUT_ASPECT_CONTROL,
- sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl)
-{
- struct saa7164_dev *dev = port->dev;
- int ret;
- u16 val;
-
- if (ctl == PU_BRIGHTNESS_CONTROL)
- val = port->ctl_brightness;
- else
- if (ctl == PU_CONTRAST_CONTROL)
- val = port->ctl_contrast;
- else
- if (ctl == PU_HUE_CONTROL)
- val = port->ctl_hue;
- else
- if (ctl == PU_SATURATION_CONTROL)
- val = port->ctl_saturation;
- else
- if (ctl == PU_SHARPNESS_CONTROL)
- val = port->ctl_sharpness;
- else
- return -EINVAL;
-
- dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n",
- __func__, port->encunit.vsourceid, ctl, val);
-
- ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR,
- ctl, sizeof(u16), &val);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl)
-{
- struct saa7164_dev *dev = port->dev;
- int ret;
- u16 val;
-
- ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR,
- ctl, sizeof(u16), &val);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- return ret;
- }
-
- dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n",
- __func__, ctl, val);
-
- if (ctl == PU_BRIGHTNESS_CONTROL)
- port->ctl_brightness = val;
- else
- if (ctl == PU_CONTRAST_CONTROL)
- port->ctl_contrast = val;
- else
- if (ctl == PU_HUE_CONTROL)
- port->ctl_hue = val;
- else
- if (ctl == PU_SATURATION_CONTROL)
- port->ctl_saturation = val;
- else
- if (ctl == PU_SHARPNESS_CONTROL)
- port->ctl_sharpness = val;
-
- return ret;
-}
-
-int saa7164_api_set_videomux(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 };
- int ret;
-
- dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n",
- __func__, port->mux_input, inputs[port->mux_input - 1]);
-
- /* Audio Mute */
- ret = saa7164_api_audio_mute(port, 1);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Video Mux */
- ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR,
- SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Audio Mux */
- ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
- SU_INPUT_SELECT_CONTROL, sizeof(u8),
- &inputs[port->mux_input - 1]);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Audio UnMute */
- ret = saa7164_api_audio_mute(port, 0);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_audio_mute(struct saa7164_port *port, int mute)
-{
- struct saa7164_dev *dev = port->dev;
- u8 v = mute;
- int ret;
-
- dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute);
-
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
- MUTE_CONTROL, sizeof(u8), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-/* 0 = silence, 0xff = full */
-int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
-{
- struct saa7164_dev *dev = port->dev;
- s16 v, min, max;
- int ret;
-
- dprintk(DBGLVL_API, "%s(%d)\n", __func__, level);
-
- /* Obtain the min/max ranges */
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN,
- VOLUME_CONTROL, sizeof(u16), &min);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX,
- VOLUME_CONTROL, sizeof(u16), &max);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
- (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
- level, min, max, v);
-
- v = level;
- if (v < min)
- v = min;
- if (v > max)
- v = max;
-
- /* Left */
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
- (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Right */
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
- (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
- (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
- level, min, max, v);
-
- return ret;
-}
-
-int saa7164_api_set_audio_std(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResAudioDefaults lvl;
- struct tmComResTunerStandard tvaudio;
- int ret;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- /* Establish default levels */
- lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT;
- lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT;
- lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT;
- lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT;
- lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
- lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
- ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
- AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults),
- &lvl);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- /* Manually select the appropriate TV audio standard */
- if (port->encodernorm.id & V4L2_STD_NTSC) {
- tvaudio.std = TU_STANDARD_NTSC_M;
- tvaudio.country = 1;
- } else {
- tvaudio.std = TU_STANDARD_PAL_I;
- tvaudio.country = 44;
- }
-
- ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
- TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n",
- __func__, ret);
- return ret;
-}
-
-int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
-{
- struct saa7164_dev *dev = port->dev;
- struct tmComResTunerStandardAuto p;
- int ret;
-
- dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect);
-
- /* Disable TV Audio autodetect if not already set (buggy) */
- if (autodetect)
- p.mode = TU_STANDARD_AUTO;
- else
- p.mode = TU_STANDARD_MANUAL;
- ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
- TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
- if (ret != SAA_OK)
- printk(KERN_ERR
- "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n",
- __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_get_videomux(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- int ret;
-
- ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR,
- SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_ENC, "%s() v_mux=%d\n",
- __func__, port->mux_input);
-
- return ret;
-}
-
-int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
-{
- struct saa7164_dev *dev = port->dev;
-
- u16 len = 0;
- u8 buf[256];
- int ret;
- u8 mas;
-
- dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__,
- port->nr, port->type, val);
-
- if (port->nr == 0)
- mas = 0xd0;
- else
- mas = 0xe0;
-
- memset(buf, 0, sizeof(buf));
-
- buf[0x00] = 0x04;
- buf[0x01] = 0x00;
- buf[0x02] = 0x00;
- buf[0x03] = 0x00;
-
- buf[0x04] = 0x04;
- buf[0x05] = 0x00;
- buf[0x06] = 0x00;
- buf[0x07] = 0x00;
-
- buf[0x08] = reg;
- buf[0x09] = 0x26;
- buf[0x0a] = mas;
- buf[0x0b] = 0xb0;
-
- buf[0x0c] = val;
- buf[0x0d] = 0x00;
- buf[0x0e] = 0x00;
- buf[0x0f] = 0x00;
-
- ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN,
- EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
- return -EIO;
- }
-
- ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR,
- EXU_REGISTER_ACCESS_CONTROL, len, &buf);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
-#if 0
- saa7164_dumphex16(dev, buf, 16);
-#endif
- return ret == SAA_OK ? 0 : -EIO;
-}
-
-/* Disable the IF block AGC controls */
-int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
-{
- struct saa7164_dev *dev = port->dev;
- int ret = 0;
- u8 agc_disable;
-
- dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
-
- if (std & V4L2_STD_NTSC) {
- dprintk(DBGLVL_API, " NTSC\n");
- saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_I) {
- dprintk(DBGLVL_API, " PAL-I\n");
- saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_M) {
- dprintk(DBGLVL_API, " PAL-M\n");
- saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_N) {
- dprintk(DBGLVL_API, " PAL-N\n");
- saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_Nc) {
- dprintk(DBGLVL_API, " PAL-Nc\n");
- saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_B) {
- dprintk(DBGLVL_API, " PAL-B\n");
- saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_PAL_DK) {
- dprintk(DBGLVL_API, " PAL-DK\n");
- saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */
- agc_disable = 0;
- } else if (std & V4L2_STD_SECAM_L) {
- dprintk(DBGLVL_API, " SECAM-L\n");
- saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */
- agc_disable = 0;
- } else {
- /* Unknown standard, assume DTV */
- dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
- /* Undefinded Video Standard */
- saa7164_api_set_dif(port, 0x00, 0x80);
- agc_disable = 1;
- }
-
- saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */
- saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */
- saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */
- saa7164_api_set_dif(port, 0x04, 0x01); /* Active */
- msleep(100);
- saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
- msleep(100);
-
- return ret;
-}
-
-/* Ensure the dif is in the correct state for the operating mode
- * (analog / dtv). We only configure the diff through the analog encoder
- * so when we're in digital mode we need to find the appropriate encoder
- * and use it to configure the DIF.
- */
-int saa7164_api_initialize_dif(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct saa7164_port *p = NULL;
- int ret = -EINVAL;
- u32 std = 0;
-
- dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__,
- port->nr, port->type);
-
- if (port->type == SAA7164_MPEG_ENCODER) {
- /* Pick any analog standard to init the diff.
- * we'll come back during encoder_init'
- * and set the correct standard if requried.
- */
- std = V4L2_STD_NTSC;
- } else
- if (port->type == SAA7164_MPEG_DVB) {
- if (port->nr == SAA7164_PORT_TS1)
- p = &dev->ports[SAA7164_PORT_ENC1];
- else
- p = &dev->ports[SAA7164_PORT_ENC2];
- } else
- if (port->type == SAA7164_MPEG_VBI) {
- std = V4L2_STD_NTSC;
- if (port->nr == SAA7164_PORT_VBI1)
- p = &dev->ports[SAA7164_PORT_ENC1];
- else
- p = &dev->ports[SAA7164_PORT_ENC2];
- } else
- BUG();
-
- if (p)
- ret = saa7164_api_configure_dif(p, std);
-
- return ret;
-}
-
-int saa7164_api_transition_port(struct saa7164_port *port, u8 mode)
-{
- struct saa7164_dev *dev = port->dev;
-
- int ret;
-
- dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n",
- __func__, port->nr, port->hwcfg.unitid, mode);
-
- ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
- SAA_STATE_CONTROL, sizeof(mode), &mode);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n",
- __func__, port->nr, port->hwcfg.unitid, ret);
-
- return ret;
-}
-
-int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version)
-{
- int ret;
-
- ret = saa7164_cmd_send(dev, 0, GET_CUR,
- GET_FW_VERSION_CONTROL, sizeof(u32), version);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
-{
- u8 reg[] = { 0x0f, 0x00 };
-
- if (buflen < 128)
- return -ENOMEM;
-
- /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
- /* TODO: Pull the details from the boards struct */
- return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
- &reg[0], 128, buf);
-}
-
-int saa7164_api_configure_port_vbi(struct saa7164_dev *dev,
- struct saa7164_port *port)
-{
- struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc;
-
- dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
- dprintk(DBGLVL_API, " VideoStandard = 0x%x\n", fmt->VideoStandard);
- dprintk(DBGLVL_API, " StartLine = %d\n", fmt->StartLine);
- dprintk(DBGLVL_API, " EndLine = %d\n", fmt->EndLine);
- dprintk(DBGLVL_API, " FieldRate = %d\n", fmt->FieldRate);
- dprintk(DBGLVL_API, " bNumLines = %d\n", fmt->bNumLines);
-
- /* Cache the hardware configuration in the port */
-
- port->bufcounter = port->hwcfg.BARLocation;
- port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
- port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
- port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
- port->bufptr32l = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
- port->bufptr32h = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- port->bufptr64 = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
- port->hwcfg.BARLocation);
-
- dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n",
- port->nr);
-
- return 0;
-}
-
-int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
- struct saa7164_port *port,
- struct tmComResTSFormatDescrHeader *tsfmt)
-{
- dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
- dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset);
- dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength);
- dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength);
- dprintk(DBGLVL_API, " bguid = (....)\n");
-
- /* Cache the hardware configuration in the port */
-
- port->bufcounter = port->hwcfg.BARLocation;
- port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
- port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
- port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
- port->bufptr32l = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
- port->bufptr32h = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- port->bufptr64 = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
- port->hwcfg.BARLocation);
-
- dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n",
- port->nr);
-
- return 0;
-}
-
-int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
- struct saa7164_port *port,
- struct tmComResPSFormatDescrHeader *fmt)
-{
- dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
- dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength);
- dprintk(DBGLVL_API, " wPackLength= 0x%x\n", fmt->wPackLength);
- dprintk(DBGLVL_API, " bPackDataType= 0x%x\n", fmt->bPackDataType);
-
- /* Cache the hardware configuration in the port */
- /* TODO: CHECK THIS in the port config */
- port->bufcounter = port->hwcfg.BARLocation;
- port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
- port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
- port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
- port->bufptr32l = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
- port->bufptr32h = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- port->bufptr64 = port->hwcfg.BARLocation +
- (4 * sizeof(u32)) +
- (sizeof(u32) * port->hwcfg.buffercount);
- dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
- port->hwcfg.BARLocation);
-
- dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n",
- port->nr);
-
- return 0;
-}
-
-int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
-{
- struct saa7164_port *tsport = NULL;
- struct saa7164_port *encport = NULL;
- struct saa7164_port *vbiport = NULL;
- u32 idx, next_offset;
- int i;
- struct tmComResDescrHeader *hdr, *t;
- struct tmComResExtDevDescrHeader *exthdr;
- struct tmComResPathDescrHeader *pathhdr;
- struct tmComResAntTermDescrHeader *anttermhdr;
- struct tmComResTunerDescrHeader *tunerunithdr;
- struct tmComResDMATermDescrHeader *vcoutputtermhdr;
- struct tmComResTSFormatDescrHeader *tsfmt;
- struct tmComResPSFormatDescrHeader *psfmt;
- struct tmComResSelDescrHeader *psel;
- struct tmComResProcDescrHeader *pdh;
- struct tmComResAFeatureDescrHeader *afd;
- struct tmComResEncoderDescrHeader *edh;
- struct tmComResVBIFormatDescrHeader *vbifmt;
- u32 currpath = 0;
-
- dprintk(DBGLVL_API,
- "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n",
- __func__, len, (u32)sizeof(struct tmComResDescrHeader));
-
- for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) {
-
- hdr = (struct tmComResDescrHeader *)(buf + idx);
-
- if (hdr->type != CS_INTERFACE)
- return SAA_ERR_NOT_SUPPORTED;
-
- dprintk(DBGLVL_API, "@ 0x%x =\n", idx);
- switch (hdr->subtype) {
- case GENERAL_REQUEST:
- dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
- break;
- case VC_TUNER_PATH:
- dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
- pathhdr = (struct tmComResPathDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " pathid = 0x%x\n",
- pathhdr->pathid);
- currpath = pathhdr->pathid;
- break;
- case VC_INPUT_TERMINAL:
- dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
- anttermhdr =
- (struct tmComResAntTermDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " terminalid = 0x%x\n",
- anttermhdr->terminalid);
- dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
- anttermhdr->terminaltype);
- switch (anttermhdr->terminaltype) {
- case ITT_ANTENNA:
- dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
- break;
- case LINE_CONNECTOR:
- dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
- break;
- case SPDIF_CONNECTOR:
- dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
- break;
- case COMPOSITE_CONNECTOR:
- dprintk(DBGLVL_API,
- " = COMPOSITE_CONNECTOR\n");
- break;
- case SVIDEO_CONNECTOR:
- dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
- break;
- case COMPONENT_CONNECTOR:
- dprintk(DBGLVL_API,
- " = COMPONENT_CONNECTOR\n");
- break;
- case STANDARD_DMA:
- dprintk(DBGLVL_API, " = STANDARD_DMA\n");
- break;
- default:
- dprintk(DBGLVL_API, " = undefined (0x%x)\n",
- anttermhdr->terminaltype);
- }
- dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
- anttermhdr->assocterminal);
- dprintk(DBGLVL_API, " iterminal = 0x%x\n",
- anttermhdr->iterminal);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- anttermhdr->controlsize);
- break;
- case VC_OUTPUT_TERMINAL:
- dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
- vcoutputtermhdr =
- (struct tmComResDMATermDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- vcoutputtermhdr->unitid);
- dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
- vcoutputtermhdr->terminaltype);
- switch (vcoutputtermhdr->terminaltype) {
- case ITT_ANTENNA:
- dprintk(DBGLVL_API, " = ITT_ANTENNA\n");
- break;
- case LINE_CONNECTOR:
- dprintk(DBGLVL_API, " = LINE_CONNECTOR\n");
- break;
- case SPDIF_CONNECTOR:
- dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n");
- break;
- case COMPOSITE_CONNECTOR:
- dprintk(DBGLVL_API,
- " = COMPOSITE_CONNECTOR\n");
- break;
- case SVIDEO_CONNECTOR:
- dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n");
- break;
- case COMPONENT_CONNECTOR:
- dprintk(DBGLVL_API,
- " = COMPONENT_CONNECTOR\n");
- break;
- case STANDARD_DMA:
- dprintk(DBGLVL_API, " = STANDARD_DMA\n");
- break;
- default:
- dprintk(DBGLVL_API, " = undefined (0x%x)\n",
- vcoutputtermhdr->terminaltype);
- }
- dprintk(DBGLVL_API, " assocterminal= 0x%x\n",
- vcoutputtermhdr->assocterminal);
- dprintk(DBGLVL_API, " sourceid = 0x%x\n",
- vcoutputtermhdr->sourceid);
- dprintk(DBGLVL_API, " iterminal = 0x%x\n",
- vcoutputtermhdr->iterminal);
- dprintk(DBGLVL_API, " BARLocation = 0x%x\n",
- vcoutputtermhdr->BARLocation);
- dprintk(DBGLVL_API, " flags = 0x%x\n",
- vcoutputtermhdr->flags);
- dprintk(DBGLVL_API, " interruptid = 0x%x\n",
- vcoutputtermhdr->interruptid);
- dprintk(DBGLVL_API, " buffercount = 0x%x\n",
- vcoutputtermhdr->buffercount);
- dprintk(DBGLVL_API, " metadatasize = 0x%x\n",
- vcoutputtermhdr->metadatasize);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- vcoutputtermhdr->controlsize);
- dprintk(DBGLVL_API, " numformats = 0x%x\n",
- vcoutputtermhdr->numformats);
-
- t = (struct tmComResDescrHeader *)
- ((struct tmComResDMATermDescrHeader *)(buf + idx));
- next_offset = idx + (vcoutputtermhdr->len);
- for (i = 0; i < vcoutputtermhdr->numformats; i++) {
- t = (struct tmComResDescrHeader *)
- (buf + next_offset);
- switch (t->subtype) {
- case VS_FORMAT_MPEG2TS:
- tsfmt =
- (struct tmComResTSFormatDescrHeader *)t;
- if (currpath == 1)
- tsport = &dev->ports[SAA7164_PORT_TS1];
- else
- tsport = &dev->ports[SAA7164_PORT_TS2];
- memcpy(&tsport->hwcfg, vcoutputtermhdr,
- sizeof(*vcoutputtermhdr));
- saa7164_api_configure_port_mpeg2ts(dev,
- tsport, tsfmt);
- break;
- case VS_FORMAT_MPEG2PS:
- psfmt =
- (struct tmComResPSFormatDescrHeader *)t;
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->hwcfg, vcoutputtermhdr,
- sizeof(*vcoutputtermhdr));
- saa7164_api_configure_port_mpeg2ps(dev,
- encport, psfmt);
- break;
- case VS_FORMAT_VBI:
- vbifmt =
- (struct tmComResVBIFormatDescrHeader *)t;
- if (currpath == 1)
- vbiport = &dev->ports[SAA7164_PORT_VBI1];
- else
- vbiport = &dev->ports[SAA7164_PORT_VBI2];
- memcpy(&vbiport->hwcfg, vcoutputtermhdr,
- sizeof(*vcoutputtermhdr));
- memcpy(&vbiport->vbi_fmt_ntsc, vbifmt,
- sizeof(*vbifmt));
- saa7164_api_configure_port_vbi(dev,
- vbiport);
- break;
- case VS_FORMAT_RDS:
- dprintk(DBGLVL_API,
- " = VS_FORMAT_RDS\n");
- break;
- case VS_FORMAT_UNCOMPRESSED:
- dprintk(DBGLVL_API,
- " = VS_FORMAT_UNCOMPRESSED\n");
- break;
- case VS_FORMAT_TYPE:
- dprintk(DBGLVL_API,
- " = VS_FORMAT_TYPE\n");
- break;
- default:
- dprintk(DBGLVL_API,
- " = undefined (0x%x)\n",
- t->subtype);
- }
- next_offset += t->len;
- }
-
- break;
- case TUNER_UNIT:
- dprintk(DBGLVL_API, " TUNER_UNIT\n");
- tunerunithdr =
- (struct tmComResTunerDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- tunerunithdr->unitid);
- dprintk(DBGLVL_API, " sourceid = 0x%x\n",
- tunerunithdr->sourceid);
- dprintk(DBGLVL_API, " iunit = 0x%x\n",
- tunerunithdr->iunit);
- dprintk(DBGLVL_API, " tuningstandards = 0x%x\n",
- tunerunithdr->tuningstandards);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- tunerunithdr->controlsize);
- dprintk(DBGLVL_API, " controls = 0x%x\n",
- tunerunithdr->controls);
-
- if (tunerunithdr->unitid == tunerunithdr->iunit) {
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->tunerunit, tunerunithdr,
- sizeof(struct tmComResTunerDescrHeader));
- dprintk(DBGLVL_API,
- " (becomes dev->enc[%d] tuner)\n",
- encport->nr);
- }
- break;
- case VC_SELECTOR_UNIT:
- psel = (struct tmComResSelDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- psel->unitid);
- dprintk(DBGLVL_API, " nrinpins = 0x%x\n",
- psel->nrinpins);
- dprintk(DBGLVL_API, " sourceid = 0x%x\n",
- psel->sourceid);
- break;
- case VC_PROCESSING_UNIT:
- pdh = (struct tmComResProcDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- pdh->unitid);
- dprintk(DBGLVL_API, " sourceid = 0x%x\n",
- pdh->sourceid);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- pdh->controlsize);
- if (pdh->controlsize == 0x04) {
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->vidproc, pdh,
- sizeof(struct tmComResProcDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
- encport->nr);
- }
- break;
- case FEATURE_UNIT:
- afd = (struct tmComResAFeatureDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " FEATURE_UNIT\n");
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- afd->unitid);
- dprintk(DBGLVL_API, " sourceid = 0x%x\n",
- afd->sourceid);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- afd->controlsize);
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->audfeat, afd,
- sizeof(struct tmComResAFeatureDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
- encport->nr);
- break;
- case ENCODER_UNIT:
- edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " ENCODER_UNIT\n");
- dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype);
- dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid);
- dprintk(DBGLVL_API, " vsourceid = 0x%x\n",
- edh->vsourceid);
- dprintk(DBGLVL_API, " asourceid = 0x%x\n",
- edh->asourceid);
- dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit);
- if (edh->iunit == edh->unitid) {
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->encunit, edh,
- sizeof(struct tmComResEncoderDescrHeader));
- dprintk(DBGLVL_API,
- " (becomes dev->enc[%d])\n",
- encport->nr);
- }
- break;
- case EXTENSION_UNIT:
- dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
- exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx);
- dprintk(DBGLVL_API, " unitid = 0x%x\n",
- exthdr->unitid);
- dprintk(DBGLVL_API, " deviceid = 0x%x\n",
- exthdr->deviceid);
- dprintk(DBGLVL_API, " devicetype = 0x%x\n",
- exthdr->devicetype);
- if (exthdr->devicetype & 0x1)
- dprintk(DBGLVL_API, " = Decoder Device\n");
- if (exthdr->devicetype & 0x2)
- dprintk(DBGLVL_API, " = GPIO Source\n");
- if (exthdr->devicetype & 0x4)
- dprintk(DBGLVL_API, " = Video Decoder\n");
- if (exthdr->devicetype & 0x8)
- dprintk(DBGLVL_API, " = Audio Decoder\n");
- if (exthdr->devicetype & 0x20)
- dprintk(DBGLVL_API, " = Crossbar\n");
- if (exthdr->devicetype & 0x40)
- dprintk(DBGLVL_API, " = Tuner\n");
- if (exthdr->devicetype & 0x80)
- dprintk(DBGLVL_API, " = IF PLL\n");
- if (exthdr->devicetype & 0x100)
- dprintk(DBGLVL_API, " = Demodulator\n");
- if (exthdr->devicetype & 0x200)
- dprintk(DBGLVL_API, " = RDS Decoder\n");
- if (exthdr->devicetype & 0x400)
- dprintk(DBGLVL_API, " = Encoder\n");
- if (exthdr->devicetype & 0x800)
- dprintk(DBGLVL_API, " = IR Decoder\n");
- if (exthdr->devicetype & 0x1000)
- dprintk(DBGLVL_API, " = EEPROM\n");
- if (exthdr->devicetype & 0x2000)
- dprintk(DBGLVL_API,
- " = VBI Decoder\n");
- if (exthdr->devicetype & 0x10000)
- dprintk(DBGLVL_API,
- " = Streaming Device\n");
- if (exthdr->devicetype & 0x20000)
- dprintk(DBGLVL_API,
- " = DRM Device\n");
- if (exthdr->devicetype & 0x40000000)
- dprintk(DBGLVL_API,
- " = Generic Device\n");
- if (exthdr->devicetype & 0x80000000)
- dprintk(DBGLVL_API,
- " = Config Space Device\n");
- dprintk(DBGLVL_API, " numgpiopins = 0x%x\n",
- exthdr->numgpiopins);
- dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n",
- exthdr->numgpiogroups);
- dprintk(DBGLVL_API, " controlsize = 0x%x\n",
- exthdr->controlsize);
- if (exthdr->devicetype & 0x80) {
- if (currpath == 1)
- encport = &dev->ports[SAA7164_PORT_ENC1];
- else
- encport = &dev->ports[SAA7164_PORT_ENC2];
- memcpy(&encport->ifunit, exthdr,
- sizeof(struct tmComResExtDevDescrHeader));
- dprintk(DBGLVL_API,
- " (becomes dev->enc[%d])\n",
- encport->nr);
- }
- break;
- case PVC_INFRARED_UNIT:
- dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
- break;
- case DRM_UNIT:
- dprintk(DBGLVL_API, " DRM_UNIT\n");
- break;
- default:
- dprintk(DBGLVL_API, "default %d\n", hdr->subtype);
- }
-
- dprintk(DBGLVL_API, " 1.%x\n", hdr->len);
- dprintk(DBGLVL_API, " 2.%x\n", hdr->type);
- dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype);
- dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid);
-
- idx += hdr->len;
- }
-
- return 0;
-}
-
-int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
-{
- int ret;
- u32 buflen = 0;
- u8 *buf;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- /* Get the total descriptor length */
- ret = saa7164_cmd_send(dev, 0, GET_LEN,
- GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
-
- dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n",
- __func__, buflen);
-
- /* Allocate enough storage for all of the descs */
- buf = kzalloc(buflen, GFP_KERNEL);
- if (!buf)
- return SAA_ERR_NO_RESOURCES;
-
- /* Retrieve them */
- ret = saa7164_cmd_send(dev, 0, GET_CUR,
- GET_DESCRIPTORS_CONTROL, buflen, buf);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- goto out;
- }
-
- if (saa_debug & DBGLVL_API)
- saa7164_dumphex16(dev, buf, (buflen/16)*16);
-
- saa7164_api_dump_subdevs(dev, buf, buflen);
-
-out:
- kfree(buf);
- return ret;
-}
-
-int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
- u32 datalen, u8 *data)
-{
- struct saa7164_dev *dev = bus->dev;
- u16 len = 0;
- int unitid;
- u8 buf[256];
- int ret;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- if (reglen > 4)
- return -EIO;
-
- /* Prepare the send buffer */
- /* Bytes 00-03 source register length
- * 04-07 source bytes to read
- * 08... register address
- */
- memset(buf, 0, sizeof(buf));
- memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen);
- *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
- *((u32 *)(buf + 1 * sizeof(u32))) = datalen;
-
- unitid = saa7164_i2caddr_to_unitid(bus, addr);
- if (unitid < 0) {
- printk(KERN_ERR
- "%s() error, cannot translate regaddr 0x%x to unitid\n",
- __func__, addr);
- return -EIO;
- }
-
- ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
- EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
- return -EIO;
- }
-
- dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
-
- if (saa_debug & DBGLVL_I2C)
- saa7164_dumphex16(dev, buf, 2 * 16);
-
- ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
- EXU_REGISTER_ACCESS_CONTROL, len, &buf);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
- else {
- if (saa_debug & DBGLVL_I2C)
- saa7164_dumphex16(dev, buf, sizeof(buf));
- memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
- }
-
- return ret == SAA_OK ? 0 : -EIO;
-}
-
-/* For a given 8 bit i2c address device, write the buffer */
-int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
- u8 *data)
-{
- struct saa7164_dev *dev = bus->dev;
- u16 len = 0;
- int unitid;
- int reglen;
- u8 buf[256];
- int ret;
-
- dprintk(DBGLVL_API, "%s()\n", __func__);
-
- if ((datalen == 0) || (datalen > 232))
- return -EIO;
-
- memset(buf, 0, sizeof(buf));
-
- unitid = saa7164_i2caddr_to_unitid(bus, addr);
- if (unitid < 0) {
- printk(KERN_ERR
- "%s() error, cannot translate regaddr 0x%x to unitid\n",
- __func__, addr);
- return -EIO;
- }
-
- reglen = saa7164_i2caddr_to_reglen(bus, addr);
- if (reglen < 0) {
- printk(KERN_ERR
- "%s() error, cannot translate regaddr to reglen\n",
- __func__);
- return -EIO;
- }
-
- ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN,
- EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
- return -EIO;
- }
-
- dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
-
- /* Prepare the send buffer */
- /* Bytes 00-03 dest register length
- * 04-07 dest bytes to write
- * 08... register address
- */
- *((u32 *)(buf + 0 * sizeof(u32))) = reglen;
- *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen;
- memcpy((buf + 2 * sizeof(u32)), data, datalen);
-
- if (saa_debug & DBGLVL_I2C)
- saa7164_dumphex16(dev, buf, sizeof(buf));
-
- ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
- EXU_REGISTER_ACCESS_CONTROL, len, &buf);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
-
- return ret == SAA_OK ? 0 : -EIO;
-}
-
-int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
- u8 pin, u8 state)
-{
- int ret;
- struct tmComResGPIO t;
-
- dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
- __func__, unitid, pin, state);
-
- if ((pin > 7) || (state > 2))
- return SAA_ERR_BAD_PARAMETER;
-
- t.pin = pin;
- t.state = state;
-
- ret = saa7164_cmd_send(dev, unitid, SET_CUR,
- EXU_GPIO_CONTROL, sizeof(t), &t);
- if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n",
- __func__, ret);
-
- return ret;
-}
-
-int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid,
- u8 pin)
-{
- return saa7164_api_modify_gpio(dev, unitid, pin, 1);
-}
-
-int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
- u8 pin)
-{
- return saa7164_api_modify_gpio(dev, unitid, pin, 0);
-}
-
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
deleted file mode 100644
index 3b7d7b4e3034..000000000000
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ /dev/null
@@ -1,1526 +0,0 @@
-/*
- * Driver for the NXP SAA7164 PCIe bridge
- *
- * Copyright (c) 2010 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 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/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kmod.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <asm/div64.h>
-
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif
-#include "saa7164.h"
-
-MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>");
-MODULE_LICENSE("GPL");
-
-/*
- * 1 Basic
- * 2
- * 4 i2c
- * 8 api
- * 16 cmd
- * 32 bus
- */
-
-unsigned int saa_debug;
-module_param_named(debug, saa_debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-unsigned int fw_debug;
-module_param(fw_debug, int, 0644);
-MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
-
-unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
-module_param(encoder_buffers, int, 0644);
-MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64");
-
-unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS;
-module_param(vbi_buffers, int, 0644);
-MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64");
-
-unsigned int waitsecs = 10;
-module_param(waitsecs, int, 0644);
-MODULE_PARM_DESC(waitsecs, "timeout on firmware messages");
-
-static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
-module_param_array(card, int, NULL, 0444);
-MODULE_PARM_DESC(card, "card type");
-
-unsigned int print_histogram = 64;
-module_param(print_histogram, int, 0644);
-MODULE_PARM_DESC(print_histogram, "print histogram values once");
-
-unsigned int crc_checking = 1;
-module_param(crc_checking, int, 0644);
-MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
-
-unsigned int guard_checking = 1;
-module_param(guard_checking, int, 0644);
-MODULE_PARM_DESC(guard_checking,
- "enable dma sanity checking for buffer overruns");
-
-static unsigned int saa7164_devcount;
-
-static DEFINE_MUTEX(devlist);
-LIST_HEAD(saa7164_devlist);
-
-#define INT_SIZE 16
-
-void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len)
-{
- int i;
- u8 tmp[16];
- memset(&tmp[0], 0xff, sizeof(tmp));
-
- printk(KERN_INFO "--------------------> "
- "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
- for (i = 0; i < len; i += 16) {
- if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) {
- printk(KERN_INFO " [0x%08x] "
- "%02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
- *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
- *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
- *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
- *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
- }
- }
-}
-
-static void saa7164_pack_verifier(struct saa7164_buffer *buf)
-{
- u8 *p = (u8 *)buf->cpu;
- int i;
-
- for (i = 0; i < buf->actual_size; i += 2048) {
-
- if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
- (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
- printk(KERN_ERR "No pack at 0x%x\n", i);
-#if 0
- saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
-#endif
- }
- }
-}
-
-#define FIXED_VIDEO_PID 0xf1
-#define FIXED_AUDIO_PID 0xf2
-
-static void saa7164_ts_verifier(struct saa7164_buffer *buf)
-{
- struct saa7164_port *port = buf->port;
- u32 i;
- u8 cc, a;
- u16 pid;
- u8 __iomem *bufcpu = (u8 *)buf->cpu;
-
- port->sync_errors = 0;
- port->v_cc_errors = 0;
- port->a_cc_errors = 0;
-
- for (i = 0; i < buf->actual_size; i += 188) {
- if (*(bufcpu + i) != 0x47)
- port->sync_errors++;
-
- /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
- pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
- cc = *(bufcpu + i + 3) & 0x0f;
-
- if (pid == FIXED_VIDEO_PID) {
- a = ((port->last_v_cc + 1) & 0x0f);
- if (a != cc) {
- printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
- port->last_v_cc, cc, i);
- port->v_cc_errors++;
- }
-
- port->last_v_cc = cc;
- } else
- if (pid == FIXED_AUDIO_PID) {
- a = ((port->last_a_cc + 1) & 0x0f);
- if (a != cc) {
- printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
- port->last_a_cc, cc, i);
- port->a_cc_errors++;
- }
-
- port->last_a_cc = cc;
- }
-
- }
-
- /* Only report errors if we've been through this function atleast
- * once already and the cached cc values are primed. First time through
- * always generates errors.
- */
- if (port->v_cc_errors && (port->done_first_interrupt > 1))
- printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
-
- if (port->a_cc_errors && (port->done_first_interrupt > 1))
- printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors);
-
- if (port->sync_errors && (port->done_first_interrupt > 1))
- printk(KERN_ERR "sync_errors = %d\n", port->sync_errors);
-
- if (port->done_first_interrupt == 1)
- port->done_first_interrupt++;
-}
-
-static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
-{
- int i;
-
- memset(hg, 0, sizeof(struct saa7164_histogram));
- strcpy(hg->name, name);
-
- /* First 30ms x 1ms */
- for (i = 0; i < 30; i++)
- hg->counter1[0 + i].val = i;
-
- /* 30 - 200ms x 10ms */
- for (i = 0; i < 18; i++)
- hg->counter1[30 + i].val = 30 + (i * 10);
-
- /* 200 - 2000ms x 100ms */
- for (i = 0; i < 15; i++)
- hg->counter1[48 + i].val = 200 + (i * 200);
-
- /* Catch all massive value (2secs) */
- hg->counter1[55].val = 2000;
-
- /* Catch all massive value (4secs) */
- hg->counter1[56].val = 4000;
-
- /* Catch all massive value (8secs) */
- hg->counter1[57].val = 8000;
-
- /* Catch all massive value (15secs) */
- hg->counter1[58].val = 15000;
-
- /* Catch all massive value (30secs) */
- hg->counter1[59].val = 30000;
-
- /* Catch all massive value (60secs) */
- hg->counter1[60].val = 60000;
-
- /* Catch all massive value (5mins) */
- hg->counter1[61].val = 300000;
-
- /* Catch all massive value (15mins) */
- hg->counter1[62].val = 900000;
-
- /* Catch all massive values (1hr) */
- hg->counter1[63].val = 3600000;
-}
-
-void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
-{
- int i;
- for (i = 0; i < 64; i++) {
- if (val <= hg->counter1[i].val) {
- hg->counter1[i].count++;
- hg->counter1[i].update_time = jiffies;
- break;
- }
- }
-}
-
-static void saa7164_histogram_print(struct saa7164_port *port,
- struct saa7164_histogram *hg)
-{
- u32 entries = 0;
- int i;
-
- printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name);
- for (i = 0; i < 64; i++) {
- if (hg->counter1[i].count == 0)
- continue;
-
- printk(KERN_ERR " %4d %12d %Ld\n",
- hg->counter1[i].val,
- hg->counter1[i].count,
- hg->counter1[i].update_time);
-
- entries++;
- }
- printk(KERN_ERR "Total: %d\n", entries);
-}
-
-static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
-{
- struct saa7164_dev *dev = port->dev;
- struct saa7164_buffer *buf = NULL;
- struct saa7164_user_buffer *ubuf = NULL;
- struct list_head *c, *n;
- int i = 0;
- u8 __iomem *p;
-
- mutex_lock(&port->dmaqueue_lock);
- list_for_each_safe(c, n, &port->dmaqueue.list) {
-
- buf = list_entry(c, struct saa7164_buffer, list);
- if (i++ > port->hwcfg.buffercount) {
- printk(KERN_ERR "%s() illegal i count %d\n",
- __func__, i);
- break;
- }
-
- if (buf->idx == bufnr) {
-
- /* Found the buffer, deal with it */
- dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr);
-
- if (crc_checking) {
- /* Throw a new checksum on the dma buffer */
- buf->crc = crc32(0, buf->cpu, buf->actual_size);
- }
-
- if (guard_checking) {
- p = (u8 *)buf->cpu;
- if ((*(p + buf->actual_size + 0) != 0xff) ||
- (*(p + buf->actual_size + 1) != 0xff) ||
- (*(p + buf->actual_size + 2) != 0xff) ||
- (*(p + buf->actual_size + 3) != 0xff) ||
- (*(p + buf->actual_size + 0x10) != 0xff) ||
- (*(p + buf->actual_size + 0x11) != 0xff) ||
- (*(p + buf->actual_size + 0x12) != 0xff) ||
- (*(p + buf->actual_size + 0x13) != 0xff)) {
- printk(KERN_ERR "%s() buf %p guard buffer breach\n",
- __func__, buf);
-#if 0
- saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
-#endif
- }
- }
-
- if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) {
- /* Validate the incoming buffer content */
- if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
- saa7164_ts_verifier(buf);
- else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
- saa7164_pack_verifier(buf);
- }
-
- /* find a free user buffer and clone to it */
- if (!list_empty(&port->list_buf_free.list)) {
-
- /* Pull the first buffer from the used list */
- ubuf = list_first_entry(&port->list_buf_free.list,
- struct saa7164_user_buffer, list);
-
- if (buf->actual_size <= ubuf->actual_size) {
-
- memcpy_fromio(ubuf->data, buf->cpu,
- ubuf->actual_size);
-
- if (crc_checking) {
- /* Throw a new checksum on the read buffer */
- ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size);
- }
-
- /* Requeue the buffer on the free list */
- ubuf->pos = 0;
-
- list_move_tail(&ubuf->list,
- &port->list_buf_used.list);
-
- /* Flag any userland waiters */
- wake_up_interruptible(&port->wait_read);
-
- } else {
- printk(KERN_ERR "buf %p bufsize fails match\n", buf);
- }
-
- } else
- printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
-
- /* Ensure offset into buffer remains 0, fill buffer
- * with known bad data. We check for this data at a later point
- * in time. */
- saa7164_buffer_zero_offsets(port, bufnr);
- memset_io(buf->cpu, 0xff, buf->pci_size);
- if (crc_checking) {
- /* Throw yet aanother new checksum on the dma buffer */
- buf->crc = crc32(0, buf->cpu, buf->actual_size);
- }
-
- break;
- }
- }
- mutex_unlock(&port->dmaqueue_lock);
-}
-
-static void saa7164_work_enchandler(struct work_struct *w)
-{
- struct saa7164_port *port =
- container_of(w, struct saa7164_port, workenc);
- struct saa7164_dev *dev = port->dev;
-
- u32 wp, mcb, rp, cnt = 0;
-
- port->last_svc_msecs_diff = port->last_svc_msecs;
- port->last_svc_msecs = jiffies_to_msecs(jiffies);
-
- port->last_svc_msecs_diff = port->last_svc_msecs -
- port->last_svc_msecs_diff;
-
- saa7164_histogram_update(&port->svc_interval,
- port->last_svc_msecs_diff);
-
- port->last_irq_svc_msecs_diff = port->last_svc_msecs -
- port->last_irq_msecs;
-
- saa7164_histogram_update(&port->irq_svc_interval,
- port->last_irq_svc_msecs_diff);
-
- dprintk(DBGLVL_IRQ,
- "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
- __func__,
- port->last_svc_msecs_diff,
- port->last_irq_svc_msecs_diff,
- port->last_svc_wp,
- port->last_svc_rp
- );
-
- /* Current write position */
- wp = saa7164_readl(port->bufcounter);
- if (wp > (port->hwcfg.buffercount - 1)) {
- printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
- return;
- }
-
- /* Most current complete buffer */
- if (wp == 0)
- mcb = (port->hwcfg.buffercount - 1);
- else
- mcb = wp - 1;
-
- while (1) {
- if (port->done_first_interrupt == 0) {
- port->done_first_interrupt++;
- rp = mcb;
- } else
- rp = (port->last_svc_rp + 1) % 8;
-
- if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
- printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
- break;
- }
-
- saa7164_work_enchandler_helper(port, rp);
- port->last_svc_rp = rp;
- cnt++;
-
- if (rp == mcb)
- break;
- }
-
- /* TODO: Convert this into a /proc/saa7164 style readable file */
- if (print_histogram == port->nr) {
- saa7164_histogram_print(port, &port->irq_interval);
- saa7164_histogram_print(port, &port->svc_interval);
- saa7164_histogram_print(port, &port->irq_svc_interval);
- saa7164_histogram_print(port, &port->read_interval);
- saa7164_histogram_print(port, &port->poll_interval);
- /* TODO: fix this to preserve any previous state */
- print_histogram = 64 + port->nr;
- }
-}
-
-static void saa7164_work_vbihandler(struct work_struct *w)
-{
- struct saa7164_port *port =
- container_of(w, struct saa7164_port, workenc);
- struct saa7164_dev *dev = port->dev;
-
- u32 wp, mcb, rp, cnt = 0;
-
- port->last_svc_msecs_diff = port->last_svc_msecs;
- port->last_svc_msecs = jiffies_to_msecs(jiffies);
- port->last_svc_msecs_diff = port->last_svc_msecs -
- port->last_svc_msecs_diff;
-
- saa7164_histogram_update(&port->svc_interval,
- port->last_svc_msecs_diff);
-
- port->last_irq_svc_msecs_diff = port->last_svc_msecs -
- port->last_irq_msecs;
-
- saa7164_histogram_update(&port->irq_svc_interval,
- port->last_irq_svc_msecs_diff);
-
- dprintk(DBGLVL_IRQ,
- "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
- __func__,
- port->last_svc_msecs_diff,
- port->last_irq_svc_msecs_diff,
- port->last_svc_wp,
- port->last_svc_rp
- );
-
- /* Current write position */
- wp = saa7164_readl(port->bufcounter);
- if (wp > (port->hwcfg.buffercount - 1)) {
- printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
- return;
- }
-
- /* Most current complete buffer */
- if (wp == 0)
- mcb = (port->hwcfg.buffercount - 1);
- else
- mcb = wp - 1;
-
- while (1) {
- if (port->done_first_interrupt == 0) {
- port->done_first_interrupt++;
- rp = mcb;
- } else
- rp = (port->last_svc_rp + 1) % 8;
-
- if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
- printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
- break;
- }
-
- saa7164_work_enchandler_helper(port, rp);
- port->last_svc_rp = rp;
- cnt++;
-
- if (rp == mcb)
- break;
- }
-
- /* TODO: Convert this into a /proc/saa7164 style readable file */
- if (print_histogram == port->nr) {
- saa7164_histogram_print(port, &port->irq_interval);
- saa7164_histogram_print(port, &port->svc_interval);
- saa7164_histogram_print(port, &port->irq_svc_interval);
- saa7164_histogram_print(port, &port->read_interval);
- saa7164_histogram_print(port, &port->poll_interval);
- /* TODO: fix this to preserve any previous state */
- print_histogram = 64 + port->nr;
- }
-}
-
-static void saa7164_work_cmdhandler(struct work_struct *w)
-{
- struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
-
- /* Wake up any complete commands */
- saa7164_irq_dequeue(dev);
-}
-
-static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
-{
- struct saa7164_port *port = buf->port;
-
- /* Feed the transport payload into the kernel demux */
- dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
- SAA7164_TS_NUMBER_OF_LINES);
-
-}
-
-static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
-
- /* Store old time */
- port->last_irq_msecs_diff = port->last_irq_msecs;
-
- /* Collect new stats */
- port->last_irq_msecs = jiffies_to_msecs(jiffies);
-
- /* Calculate stats */
- port->last_irq_msecs_diff = port->last_irq_msecs -
- port->last_irq_msecs_diff;
-
- saa7164_histogram_update(&port->irq_interval,
- port->last_irq_msecs_diff);
-
- dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
- port->last_irq_msecs_diff);
-
- /* Tis calls the vbi irq handler */
- schedule_work(&port->workenc);
- return 0;
-}
-
-static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
-
- /* Store old time */
- port->last_irq_msecs_diff = port->last_irq_msecs;
-
- /* Collect new stats */
- port->last_irq_msecs = jiffies_to_msecs(jiffies);
-
- /* Calculate stats */
- port->last_irq_msecs_diff = port->last_irq_msecs -
- port->last_irq_msecs_diff;
-
- saa7164_histogram_update(&port->irq_interval,
- port->last_irq_msecs_diff);
-
- dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
- port->last_irq_msecs_diff);
-
- schedule_work(&port->workenc);
- return 0;
-}
-
-static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
-{
- struct saa7164_dev *dev = port->dev;
- struct saa7164_buffer *buf;
- struct list_head *c, *n;
- int wp, i = 0, rp;
-
- /* Find the current write point from the hardware */
- wp = saa7164_readl(port->bufcounter);
- if (wp > (port->hwcfg.buffercount - 1))
- BUG();
-
- /* Find the previous buffer to the current write point */
- if (wp == 0)
- rp = (port->hwcfg.buffercount - 1);
- else
- rp = wp - 1;
-
- /* Lookup the WP in the buffer list */
- /* TODO: turn this into a worker thread */
- list_for_each_safe(c, n, &port->dmaqueue.list) {
- buf = list_entry(c, struct saa7164_buffer, list);
- if (i++ > port->hwcfg.buffercount)
- BUG();
-
- if (buf->idx == rp) {
- /* Found the buffer, deal with it */
- dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
- __func__, wp, rp);
- saa7164_buffer_deliver(buf);
- break;
- }
-
- }
- return 0;
-}
-
-/* Primary IRQ handler and dispatch mechanism */
-static irqreturn_t saa7164_irq(int irq, void *dev_id)
-{
- struct saa7164_dev *dev = dev_id;
- struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
- struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
- struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
- struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
- struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
- struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
-
- u32 intid, intstat[INT_SIZE/4];
- int i, handled = 0, bit;
-
- if (dev == NULL) {
- printk(KERN_ERR "%s() No device specified\n", __func__);
- handled = 0;
- goto out;
- }
-
- /* Check that the hardware is accessible. If the status bytes are
- * 0xFF then the device is not accessible, the the IRQ belongs
- * to another driver.
- * 4 x u32 interrupt registers.
- */
- for (i = 0; i < INT_SIZE/4; i++) {
-
- /* TODO: Convert into saa7164_readl() */
- /* Read the 4 hardware interrupt registers */
- intstat[i] = saa7164_readl(dev->int_status + (i * 4));
-
- if (intstat[i])
- handled = 1;
- }
- if (handled == 0)
- goto out;
-
- /* For each of the HW interrupt registers */
- for (i = 0; i < INT_SIZE/4; i++) {
-
- if (intstat[i]) {
- /* Each function of the board has it's own interruptid.
- * Find the function that triggered then call
- * it's handler.
- */
- for (bit = 0; bit < 32; bit++) {
-
- if (((intstat[i] >> bit) & 0x00000001) == 0)
- continue;
-
- /* Calculate the interrupt id (0x00 to 0x7f) */
-
- intid = (i * 32) + bit;
- if (intid == dev->intfdesc.bInterruptId) {
- /* A response to an cmd/api call */
- schedule_work(&dev->workcmd);
- } else if (intid == porta->hwcfg.interruptid) {
-
- /* Transport path 1 */
- saa7164_irq_ts(porta);
-
- } else if (intid == portb->hwcfg.interruptid) {
-
- /* Transport path 2 */
- saa7164_irq_ts(portb);
-
- } else if (intid == portc->hwcfg.interruptid) {
-
- /* Encoder path 1 */
- saa7164_irq_encoder(portc);
-
- } else if (intid == portd->hwcfg.interruptid) {
-
- /* Encoder path 2 */
- saa7164_irq_encoder(portd);
-
- } else if (intid == porte->hwcfg.interruptid) {
-
- /* VBI path 1 */
- saa7164_irq_vbi(porte);
-
- } else if (intid == portf->hwcfg.interruptid) {
-
- /* VBI path 2 */
- saa7164_irq_vbi(portf);
-
- } else {
- /* Find the function */
- dprintk(DBGLVL_IRQ,
- "%s() unhandled interrupt "
- "reg 0x%x bit 0x%x "
- "intid = 0x%x\n",
- __func__, i, bit, intid);
- }
- }
-
- /* Ack it */
- saa7164_writel(dev->int_ack + (i * 4), intstat[i]);
-
- }
- }
-out:
- return IRQ_RETVAL(handled);
-}
-
-void saa7164_getfirmwarestatus(struct saa7164_dev *dev)
-{
- struct saa7164_fw_status *s = &dev->fw_status;
-
- dev->fw_status.status = saa7164_readl(SAA_DEVICE_SYSINIT_STATUS);
- dev->fw_status.mode = saa7164_readl(SAA_DEVICE_SYSINIT_MODE);
- dev->fw_status.spec = saa7164_readl(SAA_DEVICE_SYSINIT_SPEC);
- dev->fw_status.inst = saa7164_readl(SAA_DEVICE_SYSINIT_INST);
- dev->fw_status.cpuload = saa7164_readl(SAA_DEVICE_SYSINIT_CPULOAD);
- dev->fw_status.remainheap =
- saa7164_readl(SAA_DEVICE_SYSINIT_REMAINHEAP);
-
- dprintk(1, "Firmware status:\n");
- dprintk(1, " .status = 0x%08x\n", s->status);
- dprintk(1, " .mode = 0x%08x\n", s->mode);
- dprintk(1, " .spec = 0x%08x\n", s->spec);
- dprintk(1, " .inst = 0x%08x\n", s->inst);
- dprintk(1, " .cpuload = 0x%08x\n", s->cpuload);
- dprintk(1, " .remainheap = 0x%08x\n", s->remainheap);
-}
-
-u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev)
-{
- u32 reg;
-
- reg = saa7164_readl(SAA_DEVICE_VERSION);
- dprintk(1, "Device running firmware version %d.%d.%d.%d (0x%x)\n",
- (reg & 0x0000fc00) >> 10,
- (reg & 0x000003e0) >> 5,
- (reg & 0x0000001f),
- (reg & 0xffff0000) >> 16,
- reg);
-
- return reg;
-}
-
-/* TODO: Debugging func, remove */
-void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len)
-{
- int i;
-
- printk(KERN_INFO "--------------------> "
- "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
- for (i = 0; i < len; i += 16)
- printk(KERN_INFO " [0x%08x] "
- "%02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
- *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
- *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
- *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
- *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
-}
-
-/* TODO: Debugging func, remove */
-void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
-{
- int i;
-
- dprintk(1, "--------------------> "
- "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
- for (i = 0; i < 0x100; i += 16)
- dprintk(1, "region0[0x%08x] = "
- "%02x %02x %02x %02x %02x %02x %02x %02x"
- " %02x %02x %02x %02x %02x %02x %02x %02x\n", i,
- (u8)saa7164_readb(addr + i + 0),
- (u8)saa7164_readb(addr + i + 1),
- (u8)saa7164_readb(addr + i + 2),
- (u8)saa7164_readb(addr + i + 3),
- (u8)saa7164_readb(addr + i + 4),
- (u8)saa7164_readb(addr + i + 5),
- (u8)saa7164_readb(addr + i + 6),
- (u8)saa7164_readb(addr + i + 7),
- (u8)saa7164_readb(addr + i + 8),
- (u8)saa7164_readb(addr + i + 9),
- (u8)saa7164_readb(addr + i + 10),
- (u8)saa7164_readb(addr + i + 11),
- (u8)saa7164_readb(addr + i + 12),
- (u8)saa7164_readb(addr + i + 13),
- (u8)saa7164_readb(addr + i + 14),
- (u8)saa7164_readb(addr + i + 15)
- );
-}
-
-static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
-{
- dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
- &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr));
-
- dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength);
- dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType);
- dprintk(1, " .bDescriptorSubtype = 0x%x\n",
- dev->hwdesc.bDescriptorSubtype);
-
- dprintk(1, " .bcdSpecVersion = 0x%x\n", dev->hwdesc.bcdSpecVersion);
- dprintk(1, " .dwClockFrequency = 0x%x\n", dev->hwdesc.dwClockFrequency);
- dprintk(1, " .dwClockUpdateRes = 0x%x\n", dev->hwdesc.dwClockUpdateRes);
- dprintk(1, " .bCapabilities = 0x%x\n", dev->hwdesc.bCapabilities);
- dprintk(1, " .dwDeviceRegistersLocation = 0x%x\n",
- dev->hwdesc.dwDeviceRegistersLocation);
-
- dprintk(1, " .dwHostMemoryRegion = 0x%x\n",
- dev->hwdesc.dwHostMemoryRegion);
-
- dprintk(1, " .dwHostMemoryRegionSize = 0x%x\n",
- dev->hwdesc.dwHostMemoryRegionSize);
-
- dprintk(1, " .dwHostHibernatMemRegion = 0x%x\n",
- dev->hwdesc.dwHostHibernatMemRegion);
-
- dprintk(1, " .dwHostHibernatMemRegionSize = 0x%x\n",
- dev->hwdesc.dwHostHibernatMemRegionSize);
-}
-
-static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
-{
- dprintk(1, "@0x%p intfdesc "
- "sizeof(struct tmComResInterfaceDescr) = %d bytes\n",
- &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr));
-
- dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength);
- dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType);
- dprintk(1, " .bDescriptorSubtype = 0x%x\n",
- dev->intfdesc.bDescriptorSubtype);
-
- dprintk(1, " .bFlags = 0x%x\n", dev->intfdesc.bFlags);
- dprintk(1, " .bInterfaceType = 0x%x\n", dev->intfdesc.bInterfaceType);
- dprintk(1, " .bInterfaceId = 0x%x\n", dev->intfdesc.bInterfaceId);
- dprintk(1, " .bBaseInterface = 0x%x\n", dev->intfdesc.bBaseInterface);
- dprintk(1, " .bInterruptId = 0x%x\n", dev->intfdesc.bInterruptId);
- dprintk(1, " .bDebugInterruptId = 0x%x\n",
- dev->intfdesc.bDebugInterruptId);
-
- dprintk(1, " .BARLocation = 0x%x\n", dev->intfdesc.BARLocation);
-}
-
-static void saa7164_dump_busdesc(struct saa7164_dev *dev)
-{
- dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n",
- &dev->busdesc, (u32)sizeof(struct tmComResBusDescr));
-
- dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing);
- dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing);
- dprintk(1, " .CommandWrite = 0x%x\n", dev->busdesc.CommandWrite);
- dprintk(1, " .CommandRead = 0x%x\n", dev->busdesc.CommandRead);
- dprintk(1, " .ResponseWrite = 0x%x\n", dev->busdesc.ResponseWrite);
- dprintk(1, " .ResponseRead = 0x%x\n", dev->busdesc.ResponseRead);
-}
-
-/* Much of the hardware configuration and PCI registers are configured
- * dynamically depending on firmware. We have to cache some initial
- * structures then use these to locate other important structures
- * from PCI space.
- */
-static void saa7164_get_descriptors(struct saa7164_dev *dev)
-{
- memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
- memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr),
- sizeof(struct tmComResInterfaceDescr));
- memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
- sizeof(struct tmComResBusDescr));
-
- if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) {
- printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n");
- printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength,
- (u32)sizeof(struct tmComResHWDescr));
- } else
- saa7164_dump_hwdesc(dev);
-
- if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
- printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
- printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
- (u32)sizeof(struct tmComResInterfaceDescr));
- } else
- saa7164_dump_intfdesc(dev);
-
- saa7164_dump_busdesc(dev);
-}
-
-static int saa7164_pci_quirks(struct saa7164_dev *dev)
-{
- return 0;
-}
-
-static int get_resources(struct saa7164_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, 2),
- pci_resource_len(dev->pci, 2), dev->name))
- return 0;
- }
-
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n",
- dev->name,
- (u64)pci_resource_start(dev->pci, 0),
- (u64)pci_resource_start(dev->pci, 2));
-
- return -EBUSY;
-}
-
-static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
-{
- struct saa7164_port *port = NULL;
-
- if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
- BUG();
-
- port = &dev->ports[portnr];
-
- port->dev = dev;
- port->nr = portnr;
-
- if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2))
- port->type = SAA7164_MPEG_DVB;
- else
- if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) {
- port->type = SAA7164_MPEG_ENCODER;
-
- /* We need a deferred interrupt handler for cmd handling */
- INIT_WORK(&port->workenc, saa7164_work_enchandler);
- } else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
- port->type = SAA7164_MPEG_VBI;
-
- /* We need a deferred interrupt handler for cmd handling */
- INIT_WORK(&port->workenc, saa7164_work_vbihandler);
- } else
- BUG();
-
- /* Init all the critical resources */
- mutex_init(&port->dvb.lock);
- INIT_LIST_HEAD(&port->dmaqueue.list);
- mutex_init(&port->dmaqueue_lock);
-
- INIT_LIST_HEAD(&port->list_buf_used.list);
- INIT_LIST_HEAD(&port->list_buf_free.list);
- init_waitqueue_head(&port->wait_read);
-
-
- saa7164_histogram_reset(&port->irq_interval, "irq intervals");
- saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
- saa7164_histogram_reset(&port->irq_svc_interval,
- "irq to deferred intervals");
- saa7164_histogram_reset(&port->read_interval,
- "encoder/vbi read() intervals");
- saa7164_histogram_reset(&port->poll_interval,
- "encoder/vbi poll() intervals");
-
- return 0;
-}
-
-static int saa7164_dev_setup(struct saa7164_dev *dev)
-{
- int i;
-
- mutex_init(&dev->lock);
- atomic_inc(&dev->refcount);
- dev->nr = saa7164_devcount++;
-
- snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
-
- mutex_lock(&devlist);
- list_add_tail(&dev->devlist, &saa7164_devlist);
- mutex_unlock(&devlist);
-
- /* board config */
- dev->board = UNSET;
- if (card[dev->nr] < saa7164_bcount)
- dev->board = card[dev->nr];
-
- for (i = 0; UNSET == dev->board && i < saa7164_idcount; i++)
- if (dev->pci->subsystem_vendor == saa7164_subids[i].subvendor &&
- dev->pci->subsystem_device ==
- saa7164_subids[i].subdevice)
- dev->board = saa7164_subids[i].card;
-
- if (UNSET == dev->board) {
- dev->board = SAA7164_BOARD_UNKNOWN;
- saa7164_card_list(dev);
- }
-
- dev->pci_bus = dev->pci->bus->number;
- dev->pci_slot = PCI_SLOT(dev->pci->devfn);
-
- /* I2C Defaults / setup */
- dev->i2c_bus[0].dev = dev;
- dev->i2c_bus[0].nr = 0;
- dev->i2c_bus[1].dev = dev;
- dev->i2c_bus[1].nr = 1;
- dev->i2c_bus[2].dev = dev;
- dev->i2c_bus[2].nr = 2;
-
- /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */
- saa7164_port_init(dev, SAA7164_PORT_TS1);
- saa7164_port_init(dev, SAA7164_PORT_TS2);
- saa7164_port_init(dev, SAA7164_PORT_ENC1);
- saa7164_port_init(dev, SAA7164_PORT_ENC2);
- saa7164_port_init(dev, SAA7164_PORT_VBI1);
- saa7164_port_init(dev, SAA7164_PORT_VBI2);
-
- if (get_resources(dev) < 0) {
- printk(KERN_ERR "CORE %s No more PCIe resources for "
- "subsystem: %04x:%04x\n",
- dev->name, dev->pci->subsystem_vendor,
- dev->pci->subsystem_device);
-
- saa7164_devcount--;
- return -ENODEV;
- }
-
- /* PCI/e allocations */
- dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
- pci_resource_len(dev->pci, 0));
-
- dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2),
- pci_resource_len(dev->pci, 2));
-
- dev->bmmio = (u8 __iomem *)dev->lmmio;
- dev->bmmio2 = (u8 __iomem *)dev->lmmio2;
-
- /* Inerrupt and ack register locations offset of bmmio */
- dev->int_status = 0x183000 + 0xf80;
- dev->int_ack = 0x183000 + 0xf90;
-
- printk(KERN_INFO
- "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- dev->name, dev->pci->subsystem_vendor,
- dev->pci->subsystem_device, saa7164_boards[dev->board].name,
- dev->board, card[dev->nr] == dev->board ?
- "insmod option" : "autodetected");
-
- saa7164_pci_quirks(dev);
-
- return 0;
-}
-
-static void saa7164_dev_unregister(struct saa7164_dev *dev)
-{
- dprintk(1, "%s()\n", __func__);
-
- release_mem_region(pci_resource_start(dev->pci, 0),
- pci_resource_len(dev->pci, 0));
-
- release_mem_region(pci_resource_start(dev->pci, 2),
- pci_resource_len(dev->pci, 2));
-
- if (!atomic_dec_and_test(&dev->refcount))
- return;
-
- iounmap(dev->lmmio);
- iounmap(dev->lmmio2);
-
- return;
-}
-
-#ifdef CONFIG_PROC_FS
-static int saa7164_proc_show(struct seq_file *m, void *v)
-{
- struct saa7164_dev *dev;
- struct tmComResBusInfo *b;
- struct list_head *list;
- int i, c;
-
- if (saa7164_devcount == 0)
- return 0;
-
- list_for_each(list, &saa7164_devlist) {
- dev = list_entry(list, struct saa7164_dev, devlist);
- seq_printf(m, "%s = %p\n", dev->name, dev);
-
- /* Lock the bus from any other access */
- b = &dev->bus;
- mutex_lock(&b->lock);
-
- seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n",
- b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
-
- seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n",
- b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
-
- seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n",
- b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
-
- seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n",
- b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
- c = 0;
- seq_printf(m, "\n Set Ring:\n");
- seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
- for (i = 0; i < b->m_dwSizeSetRing; i++) {
- if (c == 0)
- seq_printf(m, " %04x:", i);
-
- seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
-
- if (++c == 16) {
- seq_printf(m, "\n");
- c = 0;
- }
- }
-
- c = 0;
- seq_printf(m, "\n Get Ring:\n");
- seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
- for (i = 0; i < b->m_dwSizeGetRing; i++) {
- if (c == 0)
- seq_printf(m, " %04x:", i);
-
- seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
-
- if (++c == 16) {
- seq_printf(m, "\n");
- c = 0;
- }
- }
-
- mutex_unlock(&b->lock);
-
- }
-
- return 0;
-}
-
-static int saa7164_proc_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, saa7164_proc_show, NULL);
-}
-
-static const struct file_operations saa7164_proc_fops = {
- .open = saa7164_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int saa7164_proc_create(void)
-{
- struct proc_dir_entry *pe;
-
- pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops);
- if (!pe)
- return -ENOMEM;
-
- return 0;
-}
-#endif
-
-static int saa7164_thread_function(void *data)
-{
- struct saa7164_dev *dev = data;
- struct tmFwInfoStruct fwinfo;
- u64 last_poll_time = 0;
-
- dprintk(DBGLVL_THR, "thread started\n");
-
- set_freezable();
-
- while (1) {
- msleep_interruptible(100);
- if (kthread_should_stop())
- break;
- try_to_freeze();
-
- dprintk(DBGLVL_THR, "thread running\n");
-
- /* Dump the firmware debug message to console */
- /* Polling this costs us 1-2% of the arm CPU */
- /* convert this into a respnde to interrupt 0x7a */
- saa7164_api_collect_debug(dev);
-
- /* Monitor CPU load every 1 second */
- if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
- saa7164_api_get_load_info(dev, &fwinfo);
- last_poll_time = jiffies_to_msecs(jiffies);
- }
-
- }
-
- dprintk(DBGLVL_THR, "thread exiting\n");
- return 0;
-}
-
-static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- struct saa7164_dev *dev;
- int err, i;
- u32 version;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (NULL == dev)
- return -ENOMEM;
-
- /* pci init */
- dev->pci = pci_dev;
- if (pci_enable_device(pci_dev)) {
- err = -EIO;
- goto fail_free;
- }
-
- if (saa7164_dev_setup(dev) < 0) {
- err = -EINVAL;
- goto fail_free;
- }
-
- /* print pci info */
- dev->pci_rev = pci_dev->revision;
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
- "latency: %d, mmio: 0x%llx\n", dev->name,
- pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
- dev->pci_lat,
- (unsigned long long)pci_resource_start(pci_dev, 0));
-
- pci_set_master(pci_dev);
- /* TODO */
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
- printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
- err = -EIO;
- goto fail_irq;
- }
-
- err = request_irq(pci_dev->irq, saa7164_irq,
- IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
- if (err < 0) {
- printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
- pci_dev->irq);
- err = -EIO;
- goto fail_irq;
- }
-
- pci_set_drvdata(pci_dev, dev);
-
- /* Init the internal command list */
- for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
- dev->cmds[i].seqno = i;
- dev->cmds[i].inuse = 0;
- mutex_init(&dev->cmds[i].lock);
- init_waitqueue_head(&dev->cmds[i].wait);
- }
-
- /* We need a deferred interrupt handler for cmd handling */
- INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler);
-
- /* Only load the firmware if we know the board */
- if (dev->board != SAA7164_BOARD_UNKNOWN) {
-
- err = saa7164_downloadfirmware(dev);
- if (err < 0) {
- printk(KERN_ERR
- "Failed to boot firmware, no features "
- "registered\n");
- goto fail_fw;
- }
-
- saa7164_get_descriptors(dev);
- saa7164_dumpregs(dev, 0);
- saa7164_getcurrentfirmwareversion(dev);
- saa7164_getfirmwarestatus(dev);
- err = saa7164_bus_setup(dev);
- if (err < 0)
- printk(KERN_ERR
- "Failed to setup the bus, will continue\n");
- saa7164_bus_dump(dev);
-
- /* Ping the running firmware via the command bus and get the
- * firmware version, this checks the bus is running OK.
- */
- version = 0;
- if (saa7164_api_get_fw_version(dev, &version) == SAA_OK)
- dprintk(1, "Bus is operating correctly using "
- "version %d.%d.%d.%d (0x%x)\n",
- (version & 0x0000fc00) >> 10,
- (version & 0x000003e0) >> 5,
- (version & 0x0000001f),
- (version & 0xffff0000) >> 16,
- version);
- else
- printk(KERN_ERR
- "Failed to communicate with the firmware\n");
-
- /* Bring up the I2C buses */
- saa7164_i2c_register(&dev->i2c_bus[0]);
- saa7164_i2c_register(&dev->i2c_bus[1]);
- saa7164_i2c_register(&dev->i2c_bus[2]);
- saa7164_gpio_setup(dev);
- saa7164_card_setup(dev);
-
- /* Parse the dynamic device configuration, find various
- * media endpoints (MPEG, WMV, PS, TS) and cache their
- * configuration details into the driver, so we can
- * reference them later during simething_register() func,
- * interrupt handlers, deferred work handlers etc.
- */
- saa7164_api_enum_subdevs(dev);
-
- /* Begin to create the video sub-systems and register funcs */
- if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) {
- if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
- printk(KERN_ERR "%s() Failed to register "
- "dvb adapters on porta\n",
- __func__);
- }
- }
-
- if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) {
- if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
- printk(KERN_ERR"%s() Failed to register "
- "dvb adapters on portb\n",
- __func__);
- }
- }
-
- if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) {
- if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
- printk(KERN_ERR"%s() Failed to register "
- "mpeg encoder\n", __func__);
- }
- }
-
- if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) {
- if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
- printk(KERN_ERR"%s() Failed to register "
- "mpeg encoder\n", __func__);
- }
- }
-
- if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) {
- if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
- printk(KERN_ERR"%s() Failed to register "
- "vbi device\n", __func__);
- }
- }
-
- if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) {
- if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
- printk(KERN_ERR"%s() Failed to register "
- "vbi device\n", __func__);
- }
- }
- saa7164_api_set_debug(dev, fw_debug);
-
- if (fw_debug) {
- dev->kthread = kthread_run(saa7164_thread_function, dev,
- "saa7164 debug");
- if (!dev->kthread)
- printk(KERN_ERR "%s() Failed to create "
- "debug kernel thread\n", __func__);
- }
-
- } /* != BOARD_UNKNOWN */
- else
- printk(KERN_ERR "%s() Unsupported board detected, "
- "registering without firmware\n", __func__);
-
- dprintk(1, "%s() parameter debug = %d\n", __func__, saa_debug);
- dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs);
-
-fail_fw:
- return 0;
-
-fail_irq:
- saa7164_dev_unregister(dev);
-fail_free:
- kfree(dev);
- return err;
-}
-
-static void saa7164_shutdown(struct saa7164_dev *dev)
-{
- dprintk(1, "%s()\n", __func__);
-}
-
-static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
-{
- struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
-
- if (dev->board != SAA7164_BOARD_UNKNOWN) {
- if (fw_debug && dev->kthread) {
- kthread_stop(dev->kthread);
- dev->kthread = NULL;
- }
- if (dev->firmwareloaded)
- saa7164_api_set_debug(dev, 0x00);
- }
-
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
- &dev->ports[SAA7164_PORT_ENC1].irq_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
- &dev->ports[SAA7164_PORT_ENC1].svc_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
- &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
- &dev->ports[SAA7164_PORT_ENC1].read_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
- &dev->ports[SAA7164_PORT_ENC1].poll_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1],
- &dev->ports[SAA7164_PORT_VBI1].read_interval);
- saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2],
- &dev->ports[SAA7164_PORT_VBI2].poll_interval);
-
- saa7164_shutdown(dev);
-
- if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
- saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]);
-
- if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB)
- saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]);
-
- if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER)
- saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]);
-
- if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER)
- saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]);
-
- if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI)
- saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]);
-
- if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI)
- saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]);
-
- saa7164_i2c_unregister(&dev->i2c_bus[0]);
- saa7164_i2c_unregister(&dev->i2c_bus[1]);
- saa7164_i2c_unregister(&dev->i2c_bus[2]);
-
- pci_disable_device(pci_dev);
-
- /* unregister stuff */
- free_irq(pci_dev->irq, dev);
- pci_set_drvdata(pci_dev, NULL);
-
- mutex_lock(&devlist);
- list_del(&dev->devlist);
- mutex_unlock(&devlist);
-
- saa7164_dev_unregister(dev);
- kfree(dev);
-}
-
-static struct pci_device_id saa7164_pci_tbl[] = {
- {
- /* SAA7164 */
- .vendor = 0x1131,
- .device = 0x7164,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- }, {
- /* --- end of list --- */
- }
-};
-MODULE_DEVICE_TABLE(pci, saa7164_pci_tbl);
-
-static struct pci_driver saa7164_pci_driver = {
- .name = "saa7164",
- .id_table = saa7164_pci_tbl,
- .probe = saa7164_initdev,
- .remove = __devexit_p(saa7164_finidev),
- /* TODO */
- .suspend = NULL,
- .resume = NULL,
-};
-
-static int __init saa7164_init(void)
-{
- printk(KERN_INFO "saa7164 driver loaded\n");
-
-#ifdef CONFIG_PROC_FS
- saa7164_proc_create();
-#endif
- return pci_register_driver(&saa7164_pci_driver);
-}
-
-static void __exit saa7164_fini(void)
-{
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("saa7164", NULL);
-#endif
- pci_unregister_driver(&saa7164_pci_driver);
-}
-
-module_init(saa7164_init);
-module_exit(saa7164_fini);
-
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
deleted file mode 100644
index 35219b9b0fbc..000000000000
--- a/drivers/media/video/saa7164/saa7164.h
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Driver for the NXP SAA7164 PCIe bridge
- *
- * Copyright (c) 2010 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 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.
- */
-
-/*
- Driver architecture
- *******************
-
- saa7164_core.c/buffer.c/cards.c/i2c.c/dvb.c
- | : Standard Linux driver framework for creating
- | : exposing and managing interfaces to the rest
- | : of the kernel or userland. Also uses _fw.c to load
- | : firmware direct into the PCIe bus, bypassing layers.
- V
- saa7164_api..() : Translate kernel specific functions/features
- | : into command buffers.
- V
- saa7164_cmd..() : Manages the flow of command packets on/off,
- | : the bus. Deal with bus errors, timeouts etc.
- V
- saa7164_bus..() : Manage a read/write memory ring buffer in the
- | : PCIe Address space.
- |
- | saa7164_fw...() : Load any frimware
- | | : direct into the device
- V V
- <- ----------------- PCIe address space -------------------- ->
-*/
-
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-#include <linux/crc32.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-#include <media/tuner.h>
-#include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
-#include <dvb_demux.h>
-#include <dvb_frontend.h>
-#include <dvb_net.h>
-#include <dvbdev.h>
-#include <dmxdev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-
-#include "saa7164-reg.h"
-#include "saa7164-types.h"
-
-#define SAA7164_MAXBOARDS 8
-
-#define UNSET (-1U)
-#define SAA7164_BOARD_NOAUTO UNSET
-#define SAA7164_BOARD_UNKNOWN 0
-#define SAA7164_BOARD_UNKNOWN_REV2 1
-#define SAA7164_BOARD_UNKNOWN_REV3 2
-#define SAA7164_BOARD_HAUPPAUGE_HVR2250 3
-#define SAA7164_BOARD_HAUPPAUGE_HVR2200 4
-#define SAA7164_BOARD_HAUPPAUGE_HVR2200_2 5
-#define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6
-#define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7
-#define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8
-#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9
-#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10
-
-#define SAA7164_MAX_UNITS 8
-#define SAA7164_TS_NUMBER_OF_LINES 312
-#define SAA7164_PS_NUMBER_OF_LINES 256
-#define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */
-#define SAA7164_MAX_ENCODER_BUFFERS 64 /* max 5secs of latency at 6Mbps */
-#define SAA7164_MAX_VBI_BUFFERS 64
-
-/* Port related defines */
-#define SAA7164_PORT_TS1 (0)
-#define SAA7164_PORT_TS2 (SAA7164_PORT_TS1 + 1)
-#define SAA7164_PORT_ENC1 (SAA7164_PORT_TS2 + 1)
-#define SAA7164_PORT_ENC2 (SAA7164_PORT_ENC1 + 1)
-#define SAA7164_PORT_VBI1 (SAA7164_PORT_ENC2 + 1)
-#define SAA7164_PORT_VBI2 (SAA7164_PORT_VBI1 + 1)
-#define SAA7164_MAX_PORTS (SAA7164_PORT_VBI2 + 1)
-
-#define DBGLVL_FW 4
-#define DBGLVL_DVB 8
-#define DBGLVL_I2C 16
-#define DBGLVL_API 32
-#define DBGLVL_CMD 64
-#define DBGLVL_BUS 128
-#define DBGLVL_IRQ 256
-#define DBGLVL_BUF 512
-#define DBGLVL_ENC 1024
-#define DBGLVL_VBI 2048
-#define DBGLVL_THR 4096
-#define DBGLVL_CPU 8192
-
-#define SAA7164_NORMS \
- (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443)
-
-enum port_t {
- SAA7164_MPEG_UNDEFINED = 0,
- SAA7164_MPEG_DVB,
- SAA7164_MPEG_ENCODER,
- SAA7164_MPEG_VBI,
-};
-
-enum saa7164_i2c_bus_nr {
- SAA7164_I2C_BUS_0 = 0,
- SAA7164_I2C_BUS_1,
- SAA7164_I2C_BUS_2,
-};
-
-enum saa7164_buffer_flags {
- SAA7164_BUFFER_UNDEFINED = 0,
- SAA7164_BUFFER_FREE,
- SAA7164_BUFFER_BUSY,
- SAA7164_BUFFER_FULL
-};
-
-enum saa7164_unit_type {
- SAA7164_UNIT_UNDEFINED = 0,
- SAA7164_UNIT_DIGITAL_DEMODULATOR,
- SAA7164_UNIT_ANALOG_DEMODULATOR,
- SAA7164_UNIT_TUNER,
- SAA7164_UNIT_EEPROM,
- SAA7164_UNIT_ZILOG_IRBLASTER,
- SAA7164_UNIT_ENCODER,
-};
-
-/* The PCIe bridge doesn't grant direct access to i2c.
- * Instead, you address i2c devices using a uniqely
- * allocated 'unitid' value via a messaging API. This
- * is a problem. The kernel and existing demod/tuner
- * drivers expect to talk 'i2c', so we have to maintain
- * a translation layer, and a series of functions to
- * convert i2c bus + device address into a unit id.
- */
-struct saa7164_unit {
- enum saa7164_unit_type type;
- u8 id;
- char *name;
- enum saa7164_i2c_bus_nr i2c_bus_nr;
- u8 i2c_bus_addr;
- u8 i2c_reg_len;
-};
-
-struct saa7164_board {
- char *name;
- enum port_t porta, portb, portc,
- portd, porte, portf;
- enum {
- SAA7164_CHIP_UNDEFINED = 0,
- SAA7164_CHIP_REV2,
- SAA7164_CHIP_REV3,
- } chiprev;
- struct saa7164_unit unit[SAA7164_MAX_UNITS];
-};
-
-struct saa7164_subid {
- u16 subvendor;
- u16 subdevice;
- u32 card;
-};
-
-struct saa7164_encoder_fh {
- struct saa7164_port *port;
- atomic_t v4l_reading;
-};
-
-struct saa7164_vbi_fh {
- struct saa7164_port *port;
- atomic_t v4l_reading;
-};
-
-struct saa7164_histogram_bucket {
- u32 val;
- u32 count;
- u64 update_time;
-};
-
-struct saa7164_histogram {
- char name[32];
- struct saa7164_histogram_bucket counter1[64];
-};
-
-struct saa7164_user_buffer {
- struct list_head list;
-
- /* Attributes */
- u8 *data;
- u32 pos;
- u32 actual_size;
-
- u32 crc;
-};
-
-struct saa7164_fw_status {
-
- /* RISC Core details */
- u32 status;
- u32 mode;
- u32 spec;
- u32 inst;
- u32 cpuload;
- u32 remainheap;
-
- /* Firmware version */
- u32 version;
- u32 major;
- u32 sub;
- u32 rel;
- u32 buildnr;
-};
-
-struct saa7164_dvb {
- struct mutex lock;
- struct dvb_adapter adapter;
- struct dvb_frontend *frontend;
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dmx_frontend fe_hw;
- struct dmx_frontend fe_mem;
- struct dvb_net net;
- int feeding;
-};
-
-struct saa7164_i2c {
- struct saa7164_dev *dev;
-
- enum saa7164_i2c_bus_nr nr;
-
- /* I2C I/O */
- struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
- u32 i2c_rc;
-};
-
-struct saa7164_ctrl {
- struct v4l2_queryctrl v;
-};
-
-struct saa7164_tvnorm {
- char *name;
- v4l2_std_id id;
-};
-
-struct saa7164_encoder_params {
- struct saa7164_tvnorm encodernorm;
- u32 height;
- u32 width;
- u32 is_50hz;
- u32 bitrate; /* bps */
- u32 bitrate_peak; /* bps */
- u32 bitrate_mode;
- u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
-
- u32 audio_sampling_freq;
- u32 ctl_mute;
- u32 ctl_aspect;
- u32 refdist;
- u32 gop_size;
-};
-
-struct saa7164_vbi_params {
- struct saa7164_tvnorm encodernorm;
- u32 height;
- u32 width;
- u32 is_50hz;
- u32 bitrate; /* bps */
- u32 bitrate_peak; /* bps */
- u32 bitrate_mode;
- u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
-
- u32 audio_sampling_freq;
- u32 ctl_mute;
- u32 ctl_aspect;
- u32 refdist;
- u32 gop_size;
-};
-
-struct saa7164_port;
-
-struct saa7164_buffer {
- struct list_head list;
-
- /* Note of which h/w buffer list index position we occupy */
- int idx;
-
- struct saa7164_port *port;
-
- /* Hardware Specific */
- /* PCI Memory allocations */
- enum saa7164_buffer_flags flags; /* Free, Busy, Full */
-
- /* A block of page align PCI memory */
- u32 pci_size; /* PCI allocation size in bytes */
- u64 __iomem *cpu; /* Virtual address */
- dma_addr_t dma; /* Physical address */
- u32 crc; /* Checksum for the entire buffer data */
-
- /* A page table that splits the block into a number of entries */
- u32 pt_size; /* PCI allocation size in bytes */
- u64 __iomem *pt_cpu; /* Virtual address */
- dma_addr_t pt_dma; /* Physical address */
-
- /* Encoder fops */
- u32 pos;
- u32 actual_size;
-};
-
-struct saa7164_port {
-
- struct saa7164_dev *dev;
- enum port_t type;
- int nr;
-
- /* --- Generic port attributes --- */
-
- /* HW stream parameters */
- struct tmHWStreamParameters hw_streamingparams;
-
- /* DMA configuration values, is seeded during initialization */
- struct tmComResDMATermDescrHeader hwcfg;
-
- /* hardware specific registers */
- u32 bufcounter;
- u32 pitch;
- u32 bufsize;
- u32 bufoffset;
- u32 bufptr32l;
- u32 bufptr32h;
- u64 bufptr64;
-
- u32 numpte; /* Number of entries in array, only valid in head */
-
- struct mutex dmaqueue_lock;
- struct saa7164_buffer dmaqueue;
-
- u64 last_irq_msecs, last_svc_msecs;
- u64 last_irq_msecs_diff, last_svc_msecs_diff;
- u32 last_svc_wp;
- u32 last_svc_rp;
- u64 last_irq_svc_msecs_diff;
- u64 last_read_msecs, last_read_msecs_diff;
- u64 last_poll_msecs, last_poll_msecs_diff;
-
- struct saa7164_histogram irq_interval;
- struct saa7164_histogram svc_interval;
- struct saa7164_histogram irq_svc_interval;
- struct saa7164_histogram read_interval;
- struct saa7164_histogram poll_interval;
-
- /* --- DVB Transport Specific --- */
- struct saa7164_dvb dvb;
-
- /* --- Encoder/V4L related attributes --- */
- /* Encoder */
- /* Defaults established in saa7164-encoder.c */
- struct saa7164_tvnorm encodernorm;
- u32 height;
- u32 width;
- u32 freq;
- u32 ts_packet_size;
- u32 ts_packet_count;
- u8 mux_input;
- u8 encoder_profile;
- u8 video_format;
- u8 audio_format;
- u8 video_resolution;
- u16 ctl_brightness;
- u16 ctl_contrast;
- u16 ctl_hue;
- u16 ctl_saturation;
- u16 ctl_sharpness;
- s8 ctl_volume;
-
- struct tmComResAFeatureDescrHeader audfeat;
- struct tmComResEncoderDescrHeader encunit;
- struct tmComResProcDescrHeader vidproc;
- struct tmComResExtDevDescrHeader ifunit;
- struct tmComResTunerDescrHeader tunerunit;
-
- struct work_struct workenc;
-
- /* V4L Encoder Video */
- struct saa7164_encoder_params encoder_params;
- struct video_device *v4l_device;
- atomic_t v4l_reader_count;
-
- struct saa7164_buffer list_buf_used;
- struct saa7164_buffer list_buf_free;
- wait_queue_head_t wait_read;
-
- /* V4L VBI */
- struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc;
- struct saa7164_vbi_params vbi_params;
-
- /* Debug */
- u32 sync_errors;
- u32 v_cc_errors;
- u32 a_cc_errors;
- u8 last_v_cc;
- u8 last_a_cc;
- u32 done_first_interrupt;
-};
-
-struct saa7164_dev {
- struct list_head devlist;
- atomic_t refcount;
-
- /* pci stuff */
- struct pci_dev *pci;
- unsigned char pci_rev, pci_lat;
- int pci_bus, pci_slot;
- u32 __iomem *lmmio;
- u8 __iomem *bmmio;
- u32 __iomem *lmmio2;
- u8 __iomem *bmmio2;
- int pci_irqmask;
-
- /* board details */
- int nr;
- int hwrevision;
- u32 board;
- char name[16];
-
- /* firmware status */
- struct saa7164_fw_status fw_status;
- u32 firmwareloaded;
-
- struct tmComResHWDescr hwdesc;
- struct tmComResInterfaceDescr intfdesc;
- struct tmComResBusDescr busdesc;
-
- struct tmComResBusInfo bus;
-
- /* Interrupt status and ack registers */
- u32 int_status;
- u32 int_ack;
-
- struct cmd cmds[SAA_CMD_MAX_MSG_UNITS];
- struct mutex lock;
-
- /* I2c related */
- struct saa7164_i2c i2c_bus[3];
-
- /* Transport related */
- struct saa7164_port ports[SAA7164_MAX_PORTS];
-
- /* Deferred command/api interrupts handling */
- struct work_struct workcmd;
-
- /* A kernel thread to monitor the firmware log, used
- * only in debug mode.
- */
- struct task_struct *kthread;
-
-};
-
-extern struct list_head saa7164_devlist;
-extern unsigned int waitsecs;
-extern unsigned int encoder_buffers;
-extern unsigned int vbi_buffers;
-
-/* ----------------------------------------------------------- */
-/* saa7164-core.c */
-void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
-void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len);
-void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
-u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
-void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
-
-/* ----------------------------------------------------------- */
-/* saa7164-fw.c */
-int saa7164_downloadfirmware(struct saa7164_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* saa7164-i2c.c */
-extern int saa7164_i2c_register(struct saa7164_i2c *bus);
-extern int saa7164_i2c_unregister(struct saa7164_i2c *bus);
-extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
- unsigned int cmd, void *arg);
-
-/* ----------------------------------------------------------- */
-/* saa7164-bus.c */
-int saa7164_bus_setup(struct saa7164_dev *dev);
-void saa7164_bus_dump(struct saa7164_dev *dev);
-int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
- void *buf);
-int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
- void *buf, int peekonly);
-
-/* ----------------------------------------------------------- */
-/* saa7164-cmd.c */
-int saa7164_cmd_send(struct saa7164_dev *dev,
- u8 id, enum tmComResCmd command, u16 controlselector,
- u16 size, void *buf);
-void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
-int saa7164_irq_dequeue(struct saa7164_dev *dev);
-
-/* ----------------------------------------------------------- */
-/* saa7164-api.c */
-int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version);
-int saa7164_api_enum_subdevs(struct saa7164_dev *dev);
-int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
- u32 datalen, u8 *data);
-int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr,
- u32 datalen, u8 *data);
-int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr,
- u32 datalen, u8 *data);
-int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen);
-int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
-int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
-int saa7164_api_transition_port(struct saa7164_port *port, u8 mode);
-int saa7164_api_initialize_dif(struct saa7164_port *port);
-int saa7164_api_configure_dif(struct saa7164_port *port, u32 std);
-int saa7164_api_set_encoder(struct saa7164_port *port);
-int saa7164_api_get_encoder(struct saa7164_port *port);
-int saa7164_api_set_aspect_ratio(struct saa7164_port *port);
-int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl);
-int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl);
-int saa7164_api_set_videomux(struct saa7164_port *port);
-int saa7164_api_audio_mute(struct saa7164_port *port, int mute);
-int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level);
-int saa7164_api_set_audio_std(struct saa7164_port *port);
-int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect);
-int saa7164_api_get_videomux(struct saa7164_port *port);
-int saa7164_api_set_vbi_format(struct saa7164_port *port);
-int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
-int saa7164_api_collect_debug(struct saa7164_dev *dev);
-int saa7164_api_get_load_info(struct saa7164_dev *dev,
- struct tmFwInfoStruct *i);
-
-/* ----------------------------------------------------------- */
-/* saa7164-cards.c */
-extern struct saa7164_board saa7164_boards[];
-extern const unsigned int saa7164_bcount;
-
-extern struct saa7164_subid saa7164_subids[];
-extern const unsigned int saa7164_idcount;
-
-extern void saa7164_card_list(struct saa7164_dev *dev);
-extern void saa7164_gpio_setup(struct saa7164_dev *dev);
-extern void saa7164_card_setup(struct saa7164_dev *dev);
-
-extern int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr);
-extern int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr);
-extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid);
-
-/* ----------------------------------------------------------- */
-/* saa7164-dvb.c */
-extern int saa7164_dvb_register(struct saa7164_port *port);
-extern int saa7164_dvb_unregister(struct saa7164_port *port);
-
-/* ----------------------------------------------------------- */
-/* saa7164-buffer.c */
-extern struct saa7164_buffer *saa7164_buffer_alloc(
- struct saa7164_port *port, u32 len);
-extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
-extern void saa7164_buffer_display(struct saa7164_buffer *buf);
-extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
-extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
-extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
- struct saa7164_dev *dev, u32 len);
-extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf);
-extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i);
-
-/* ----------------------------------------------------------- */
-/* saa7164-encoder.c */
-int saa7164_encoder_register(struct saa7164_port *port);
-void saa7164_encoder_unregister(struct saa7164_port *port);
-
-/* ----------------------------------------------------------- */
-/* saa7164-vbi.c */
-int saa7164_vbi_register(struct saa7164_port *port);
-void saa7164_vbi_unregister(struct saa7164_port *port);
-
-/* ----------------------------------------------------------- */
-
-extern unsigned int crc_checking;
-
-extern unsigned int saa_debug;
-#define dprintk(level, fmt, arg...)\
- do { if (saa_debug & level)\
- printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
- } while (0)
-
-#define log_warn(fmt, arg...)\
- do { \
- printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\
- } while (0)
-
-#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
-#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
-
-#define saa7164_readb(reg) readl(dev->bmmio + (reg))
-#define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg))
-
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
deleted file mode 100644
index 8fd1874382c6..000000000000
--- a/drivers/media/video/sh_vou.c
+++ /dev/null
@@ -1,1497 +0,0 @@
-/*
- * SuperH Video Output Unit (VOU) driver
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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/dma-mapping.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/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/sh_vou.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mediabus.h>
-#include <media/videobuf-dma-contig.h>
-
-/* Mirror addresses are not available for all registers */
-#define VOUER 0
-#define VOUCR 4
-#define VOUSTR 8
-#define VOUVCR 0xc
-#define VOUISR 0x10
-#define VOUBCR 0x14
-#define VOUDPR 0x18
-#define VOUDSR 0x1c
-#define VOUVPR 0x20
-#define VOUIR 0x24
-#define VOUSRR 0x28
-#define VOUMSR 0x2c
-#define VOUHIR 0x30
-#define VOUDFR 0x34
-#define VOUAD1R 0x38
-#define VOUAD2R 0x3c
-#define VOUAIR 0x40
-#define VOUSWR 0x44
-#define VOURCR 0x48
-#define VOURPR 0x50
-
-enum sh_vou_status {
- SH_VOU_IDLE,
- SH_VOU_INITIALISING,
- SH_VOU_RUNNING,
-};
-
-#define VOU_MAX_IMAGE_WIDTH 720
-#define VOU_MAX_IMAGE_HEIGHT 576
-
-struct sh_vou_device {
- struct v4l2_device v4l2_dev;
- struct video_device *vdev;
- atomic_t use_count;
- struct sh_vou_pdata *pdata;
- spinlock_t lock;
- void __iomem *base;
- /* State information */
- struct v4l2_pix_format pix;
- struct v4l2_rect rect;
- struct list_head queue;
- v4l2_std_id std;
- int pix_idx;
- struct videobuf_buffer *active;
- enum sh_vou_status status;
- struct mutex fop_lock;
-};
-
-struct sh_vou_file {
- struct videobuf_queue vbq;
-};
-
-/* Register access routines for sides A, B and mirror addresses */
-static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value)
-{
- __raw_writel(value, vou_dev->base + reg);
-}
-
-static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value)
-{
- __raw_writel(value, vou_dev->base + reg);
- __raw_writel(value, vou_dev->base + reg + 0x1000);
-}
-
-static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value)
-{
- __raw_writel(value, vou_dev->base + reg + 0x2000);
-}
-
-static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg)
-{
- return __raw_readl(vou_dev->base + reg);
-}
-
-static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value, u32 mask)
-{
- u32 old = __raw_readl(vou_dev->base + reg);
-
- value = (value & mask) | (old & ~mask);
- __raw_writel(value, vou_dev->base + reg);
-}
-
-static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value, u32 mask)
-{
- sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask);
-}
-
-static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
- u32 value, u32 mask)
-{
- sh_vou_reg_a_set(vou_dev, reg, value, mask);
- sh_vou_reg_b_set(vou_dev, reg, value, mask);
-}
-
-struct sh_vou_fmt {
- u32 pfmt;
- char *desc;
- unsigned char bpp;
- unsigned char rgb;
- unsigned char yf;
- unsigned char pkf;
-};
-
-/* Further pixel formats can be added */
-static struct sh_vou_fmt vou_fmt[] = {
- {
- .pfmt = V4L2_PIX_FMT_NV12,
- .bpp = 12,
- .desc = "YVU420 planar",
- .yf = 0,
- .rgb = 0,
- },
- {
- .pfmt = V4L2_PIX_FMT_NV16,
- .bpp = 16,
- .desc = "YVYU planar",
- .yf = 1,
- .rgb = 0,
- },
- {
- .pfmt = V4L2_PIX_FMT_RGB24,
- .bpp = 24,
- .desc = "RGB24",
- .pkf = 2,
- .rgb = 1,
- },
- {
- .pfmt = V4L2_PIX_FMT_RGB565,
- .bpp = 16,
- .desc = "RGB565",
- .pkf = 3,
- .rgb = 1,
- },
- {
- .pfmt = V4L2_PIX_FMT_RGB565X,
- .bpp = 16,
- .desc = "RGB565 byteswapped",
- .pkf = 3,
- .rgb = 1,
- },
-};
-
-static void sh_vou_schedule_next(struct sh_vou_device *vou_dev,
- struct videobuf_buffer *vb)
-{
- dma_addr_t addr1, addr2;
-
- addr1 = videobuf_to_dma_contig(vb);
- switch (vou_dev->pix.pixelformat) {
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV16:
- addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height;
- break;
- default:
- addr2 = 0;
- }
-
- sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1);
- sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2);
-}
-
-static void sh_vou_stream_start(struct sh_vou_device *vou_dev,
- struct videobuf_buffer *vb)
-{
- unsigned int row_coeff;
-#ifdef __LITTLE_ENDIAN
- u32 dataswap = 7;
-#else
- u32 dataswap = 0;
-#endif
-
- switch (vou_dev->pix.pixelformat) {
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV16:
- row_coeff = 1;
- break;
- case V4L2_PIX_FMT_RGB565:
- dataswap ^= 1;
- case V4L2_PIX_FMT_RGB565X:
- row_coeff = 2;
- break;
- case V4L2_PIX_FMT_RGB24:
- row_coeff = 3;
- break;
- }
-
- sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap);
- sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff);
- sh_vou_schedule_next(vou_dev, vb);
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- BUG_ON(in_interrupt());
-
- /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
- videobuf_waiton(vq, vb, 0, 0);
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-/* Locking: caller holds fop_lock mutex */
-static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct video_device *vdev = vq->priv_data;
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width *
- vou_dev->pix.height / 8;
-
- if (*count < 2)
- *count = 2;
-
- /* Taking into account maximum frame size, *count will stay >= 2 */
- if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
- *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
-
- dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
-
- return 0;
-}
-
-/* Locking: caller holds fop_lock mutex */
-static int sh_vou_buf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct video_device *vdev = vq->priv_data;
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct v4l2_pix_format *pix = &vou_dev->pix;
- int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
- int ret;
-
- dev_dbg(vq->dev, "%s()\n", __func__);
-
- if (vb->width != pix->width ||
- vb->height != pix->height ||
- vb->field != pix->field) {
- vb->width = pix->width;
- vb->height = pix->height;
- vb->field = field;
- if (vb->state != VIDEOBUF_NEEDS_INIT)
- free_buffer(vq, vb);
- }
-
- vb->size = vb->height * bytes_per_line;
- if (vb->baddr && vb->bsize < vb->size) {
- /* User buffer too small */
- dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
- vb->bsize, vb->baddr);
- return -EINVAL;
- }
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret < 0) {
- dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n",
- vb->memory, ret);
- return ret;
- }
- vb->state = VIDEOBUF_PREPARED;
- }
-
- dev_dbg(vq->dev,
- "%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
- __func__, vou_dev->pix_idx, bytes_per_line,
- videobuf_to_dma_contig(vb), vb->memory, vb->state);
-
- return 0;
-}
-
-/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
-static void sh_vou_buf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct video_device *vdev = vq->priv_data;
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- dev_dbg(vq->dev, "%s()\n", __func__);
-
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &vou_dev->queue);
-
- if (vou_dev->status == SH_VOU_RUNNING) {
- return;
- } else if (!vou_dev->active) {
- vou_dev->active = vb;
- /* Start from side A: we use mirror addresses, so, set B */
- sh_vou_reg_a_write(vou_dev, VOURPR, 1);
- dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
- sh_vou_reg_a_read(vou_dev, VOUSTR));
- sh_vou_schedule_next(vou_dev, vb);
- /* Only activate VOU after the second buffer */
- } else if (vou_dev->active->queue.next == &vb->queue) {
- /* Second buffer - initialise register side B */
- sh_vou_reg_a_write(vou_dev, VOURPR, 0);
- sh_vou_stream_start(vou_dev, vb);
-
- /* Register side switching with frame VSYNC */
- sh_vou_reg_a_write(vou_dev, VOURCR, 5);
- dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
- sh_vou_reg_a_read(vou_dev, VOUSTR));
-
- /* Enable End-of-Frame (VSYNC) interrupts */
- sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
- /* Two buffers on the queue - activate the hardware */
-
- vou_dev->status = SH_VOU_RUNNING;
- sh_vou_reg_a_write(vou_dev, VOUER, 0x107);
- }
-}
-
-static void sh_vou_buf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct video_device *vdev = vq->priv_data;
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- unsigned long flags;
-
- dev_dbg(vq->dev, "%s()\n", __func__);
-
- spin_lock_irqsave(&vou_dev->lock, flags);
-
- if (vou_dev->active == vb) {
- /* disable output */
- sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
- /* ...but the current frame will complete */
- sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
- vou_dev->active = NULL;
- }
-
- if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) {
- vb->state = VIDEOBUF_ERROR;
- list_del(&vb->queue);
- }
-
- spin_unlock_irqrestore(&vou_dev->lock, flags);
-
- free_buffer(vq, vb);
-}
-
-static struct videobuf_queue_ops sh_vou_video_qops = {
- .buf_setup = sh_vou_buf_setup,
- .buf_prepare = sh_vou_buf_prepare,
- .buf_queue = sh_vou_buf_queue,
- .buf_release = sh_vou_buf_release,
-};
-
-/* Video IOCTLs */
-static int sh_vou_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- return 0;
-}
-
-/* Enumerate formats, that the device can accept from the user */
-static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmt)
-{
- struct sh_vou_file *vou_file = priv;
-
- if (fmt->index >= ARRAY_SIZE(vou_fmt))
- return -EINVAL;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strlcpy(fmt->description, vou_fmt[fmt->index].desc,
- sizeof(fmt->description));
- fmt->pixelformat = vou_fmt[fmt->index].pfmt;
-
- return 0;
-}
-
-static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- fmt->fmt.pix = vou_dev->pix;
-
- return 0;
-}
-
-static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4};
-static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1};
-static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3};
-static const unsigned char vou_scale_v_num[] = {1, 2, 4};
-static const unsigned char vou_scale_v_den[] = {1, 1, 1};
-static const unsigned char vou_scale_v_fld[] = {0, 1};
-
-static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
- int pix_idx, int w_idx, int h_idx)
-{
- struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
- unsigned int black_left, black_top, width_max, height_max,
- frame_in_height, frame_out_height, frame_out_top;
- struct v4l2_rect *rect = &vou_dev->rect;
- struct v4l2_pix_format *pix = &vou_dev->pix;
- u32 vouvcr = 0, dsr_h, dsr_v;
-
- if (vou_dev->std & V4L2_STD_525_60) {
- width_max = 858;
- height_max = 262;
- } else {
- width_max = 864;
- height_max = 312;
- }
-
- frame_in_height = pix->height / 2;
- frame_out_height = rect->height / 2;
- frame_out_top = rect->top / 2;
-
- /*
- * Cropping scheme: max useful image is 720x480, and the total video
- * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts
- * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock,
- * of which the first 33 / 25 clocks HSYNC must be held active. This
- * has to be configured in CR[HW]. 1 pixel equals 2 clock periods.
- * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives
- * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area,
- * beyond DSR, specified on the left and top by the VPR register "black
- * pixels" and out-of-image area (DPR) "background pixels." We fix VPR
- * at 138 / 144 : 20, because that's the HSYNC timing, that our first
- * client requires, and that's exactly what leaves us 720 pixels for the
- * image; we leave VPR[VVP] at default 20 for now, because the client
- * doesn't seem to have any special requirements for it. Otherwise we
- * could also set it to max - 240 = 22 / 72. Thus VPR depends only on
- * the selected standard, and DPR and DSR are selected according to
- * cropping. Q: how does the client detect the first valid line? Does
- * HSYNC stay inactive during invalid (black) lines?
- */
- black_left = width_max - VOU_MAX_IMAGE_WIDTH;
- black_top = 20;
-
- dsr_h = rect->width + rect->left;
- dsr_v = frame_out_height + frame_out_top;
-
- dev_dbg(vou_dev->v4l2_dev.dev,
- "image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n",
- pix->width, frame_in_height, black_left, black_top,
- rect->left, frame_out_top, dsr_h, dsr_v);
-
- /* VOUISR height - half of a frame height in frame mode */
- sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height);
- sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top);
- sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top);
- sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v);
-
- /*
- * if necessary, we could set VOUHIR to
- * max(black_left + dsr_h, width_max) here
- */
-
- if (w_idx)
- vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4);
- if (h_idx)
- vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
-
- /* To produce a colour bar for testing set bit 23 of VOUVCR */
- sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
- sh_vou_reg_ab_write(vou_dev, VOUDFR,
- fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16));
-}
-
-struct sh_vou_geometry {
- struct v4l2_rect output;
- unsigned int in_width;
- unsigned int in_height;
- int scale_idx_h;
- int scale_idx_v;
-};
-
-/*
- * Find input geometry, that we can use to produce output, closest to the
- * requested rectangle, using VOU scaling
- */
-static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
-{
- /* The compiler cannot know, that best and idx will indeed be set */
- unsigned int best_err = UINT_MAX, best = 0, img_height_max;
- int i, idx = 0;
-
- if (std & V4L2_STD_525_60)
- img_height_max = 480;
- else
- img_height_max = 576;
-
- /* Image width must be a multiple of 4 */
- v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &geo->in_height, 0, img_height_max, 1, 0);
-
- /* Select scales to come as close as possible to the output image */
- for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
- unsigned int err;
- unsigned int found = geo->output.width * vou_scale_h_den[i] /
- vou_scale_h_num[i];
-
- if (found > VOU_MAX_IMAGE_WIDTH)
- /* scales increase */
- break;
-
- err = abs(found - geo->in_width);
- if (err < best_err) {
- best_err = err;
- idx = i;
- best = found;
- }
- if (!err)
- break;
- }
-
- geo->in_width = best;
- geo->scale_idx_h = idx;
-
- best_err = UINT_MAX;
-
- /* This loop can be replaced with one division */
- for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) {
- unsigned int err;
- unsigned int found = geo->output.height * vou_scale_v_den[i] /
- vou_scale_v_num[i];
-
- if (found > img_height_max)
- /* scales increase */
- break;
-
- err = abs(found - geo->in_height);
- if (err < best_err) {
- best_err = err;
- idx = i;
- best = found;
- }
- if (!err)
- break;
- }
-
- geo->in_height = best;
- geo->scale_idx_v = idx;
-}
-
-/*
- * Find output geometry, that we can produce, using VOU scaling, closest to
- * the requested rectangle
- */
-static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
-{
- unsigned int best_err = UINT_MAX, best, width_max, height_max,
- img_height_max;
- int i, idx;
-
- if (std & V4L2_STD_525_60) {
- width_max = 858;
- height_max = 262 * 2;
- img_height_max = 480;
- } else {
- width_max = 864;
- height_max = 312 * 2;
- img_height_max = 576;
- }
-
- /* Select scales to come as close as possible to the output image */
- for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) {
- unsigned int err;
- unsigned int found = geo->in_width * vou_scale_h_num[i] /
- vou_scale_h_den[i];
-
- if (found > VOU_MAX_IMAGE_WIDTH)
- /* scales increase */
- break;
-
- err = abs(found - geo->output.width);
- if (err < best_err) {
- best_err = err;
- idx = i;
- best = found;
- }
- if (!err)
- break;
- }
-
- geo->output.width = best;
- geo->scale_idx_h = idx;
- if (geo->output.left + best > width_max)
- geo->output.left = width_max - best;
-
- pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width,
- vou_scale_h_num[idx], vou_scale_h_den[idx], best);
-
- best_err = UINT_MAX;
-
- /* This loop can be replaced with one division */
- for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) {
- unsigned int err;
- unsigned int found = geo->in_height * vou_scale_v_num[i] /
- vou_scale_v_den[i];
-
- if (found > img_height_max)
- /* scales increase */
- break;
-
- err = abs(found - geo->output.height);
- if (err < best_err) {
- best_err = err;
- idx = i;
- best = found;
- }
- if (!err)
- break;
- }
-
- geo->output.height = best;
- geo->scale_idx_v = idx;
- if (geo->output.top + best > height_max)
- geo->output.top = height_max - best;
-
- pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height,
- vou_scale_v_num[idx], vou_scale_v_den[idx], best);
-}
-
-static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- unsigned int img_height_max;
- int pix_idx;
- struct sh_vou_geometry geo;
- struct v4l2_mbus_framefmt mbfmt = {
- /* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .field = V4L2_FIELD_INTERLACED,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- };
- int ret;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
- vou_dev->rect.width, vou_dev->rect.height,
- pix->width, pix->height);
-
- if (pix->field == V4L2_FIELD_ANY)
- pix->field = V4L2_FIELD_NONE;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
- pix->field != V4L2_FIELD_NONE)
- return -EINVAL;
-
- for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++)
- if (vou_fmt[pix_idx].pfmt == pix->pixelformat)
- break;
-
- if (pix_idx == ARRAY_SIZE(vou_fmt))
- return -EINVAL;
-
- if (vou_dev->std & V4L2_STD_525_60)
- img_height_max = 480;
- else
- img_height_max = 576;
-
- /* Image width must be a multiple of 4 */
- v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &pix->height, 0, img_height_max, 1, 0);
-
- geo.in_width = pix->width;
- geo.in_height = pix->height;
- geo.output = vou_dev->rect;
-
- vou_adjust_output(&geo, vou_dev->std);
-
- mbfmt.width = geo.output.width;
- mbfmt.height = geo.output.height;
- ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_mbus_fmt, &mbfmt);
- /* Must be implemented, so, don't check for -ENOIOCTLCMD */
- if (ret < 0)
- return ret;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__,
- geo.output.width, geo.output.height, mbfmt.width, mbfmt.height);
-
- /* Sanity checks */
- if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > img_height_max ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
- return -EIO;
-
- if (mbfmt.width != geo.output.width ||
- mbfmt.height != geo.output.height) {
- geo.output.width = mbfmt.width;
- geo.output.height = mbfmt.height;
-
- vou_adjust_input(&geo, vou_dev->std);
- }
-
- /* We tried to preserve output rectangle, but it could have changed */
- vou_dev->rect = geo.output;
- pix->width = geo.in_width;
- pix->height = geo.in_height;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__,
- pix->width, pix->height);
-
- vou_dev->pix_idx = pix_idx;
-
- vou_dev->pix = *pix;
-
- sh_vou_configure_geometry(vou_dev, pix_idx,
- geo.scale_idx_h, geo.scale_idx_v);
-
- return 0;
-}
-
-static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *fmt)
-{
- struct sh_vou_file *vou_file = priv;
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- int i;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- pix->field = V4L2_FIELD_NONE;
-
- v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
- &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
-
- for (i = 0; ARRAY_SIZE(vou_fmt); i++)
- if (vou_fmt[i].pfmt == pix->pixelformat)
- return 0;
-
- pix->pixelformat = vou_fmt[0].pfmt;
-
- return 0;
-}
-
-static int sh_vou_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
-
- return videobuf_reqbufs(&vou_file->vbq, req);
-}
-
-static int sh_vou_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- return videobuf_querybuf(&vou_file->vbq, b);
-}
-
-static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- return videobuf_qbuf(&vou_file->vbq, b);
-}
-
-static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
-}
-
-static int sh_vou_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct sh_vou_file *vou_file = priv;
- int ret;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
- video, s_stream, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
-
- /* This calls our .buf_queue() (== sh_vou_buf_queue) */
- return videobuf_streamon(&vou_file->vbq);
-}
-
-static int sh_vou_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- /*
- * This calls buf_release from host driver's videobuf_queue_ops for all
- * remaining buffers. When the last buffer is freed, stop streaming
- */
- videobuf_streamoff(&vou_file->vbq);
- v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0);
-
- return 0;
-}
-
-static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
-{
- switch (bus_fmt) {
- default:
- pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n",
- __func__, bus_fmt);
- case SH_VOU_BUS_8BIT:
- return 1;
- case SH_VOU_BUS_16BIT:
- return 0;
- case SH_VOU_BUS_BT656:
- return 3;
- }
-}
-
-static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- int ret;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
-
- if (*std_id & ~vdev->tvnorms)
- return -EINVAL;
-
- ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_std_output, *std_id);
- /* Shall we continue, if the subdev doesn't support .s_std_output()? */
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
-
- if (*std_id & V4L2_STD_525_60)
- sh_vou_reg_ab_set(vou_dev, VOUCR,
- sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
- else
- sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
-
- vou_dev->std = *std_id;
-
- return 0;
-}
-
-static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
-
- *std = vou_dev->std;
-
- return 0;
-}
-
-static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
-
- a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- a->c = vou_dev->rect;
-
- return 0;
-}
-
-/* Assume a dull encoder, do all the work ourselves. */
-static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct v4l2_rect *rect = &a->c;
- struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
- struct v4l2_pix_format *pix = &vou_dev->pix;
- struct sh_vou_geometry geo;
- struct v4l2_mbus_framefmt mbfmt = {
- /* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
- .field = V4L2_FIELD_INTERLACED,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- };
- unsigned int img_height_max;
- int ret;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
- rect->width, rect->height, rect->left, rect->top);
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
-
- if (vou_dev->std & V4L2_STD_525_60)
- img_height_max = 480;
- else
- img_height_max = 576;
-
- v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
- &rect->height, 0, img_height_max, 1, 0);
-
- if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
- rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
-
- if (rect->height + rect->top > img_height_max)
- rect->top = img_height_max - rect->height;
-
- geo.output = *rect;
- geo.in_width = pix->width;
- geo.in_height = pix->height;
-
- /* Configure the encoder one-to-one, position at 0, ignore errors */
- sd_crop.c.width = geo.output.width;
- sd_crop.c.height = geo.output.height;
- /*
- * We first issue a S_CROP, so that the subsequent S_FMT delivers the
- * final encoder configuration.
- */
- v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_crop, &sd_crop);
- mbfmt.width = geo.output.width;
- mbfmt.height = geo.output.height;
- ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_mbus_fmt, &mbfmt);
- /* Must be implemented, so, don't check for -ENOIOCTLCMD */
- if (ret < 0)
- return ret;
-
- /* Sanity checks */
- if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > img_height_max ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
- return -EIO;
-
- geo.output.width = mbfmt.width;
- geo.output.height = mbfmt.height;
-
- /*
- * No down-scaling. According to the API, current call has precedence:
- * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
- */
- vou_adjust_input(&geo, vou_dev->std);
-
- /* We tried to preserve output rectangle, but it could have changed */
- vou_dev->rect = geo.output;
- pix->width = geo.in_width;
- pix->height = geo.in_height;
-
- sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx,
- geo.scale_idx_h, geo.scale_idx_v);
-
- return 0;
-}
-
-/*
- * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle
- * is the initial register values, height takes the interlaced format into
- * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can
- * actually only meaningfully contain values <= 720 and <= 240 respectively, and
- * not <= 864 and <= 312.
- */
-static int sh_vou_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *a)
-{
- struct sh_vou_file *vou_file = priv;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = VOU_MAX_IMAGE_WIDTH;
- a->bounds.height = VOU_MAX_IMAGE_HEIGHT;
- /* Default = max, set VOUDPR = 0, which is not hardware default */
- a->defrect.left = 0;
- a->defrect.top = 0;
- a->defrect.width = VOU_MAX_IMAGE_WIDTH;
- a->defrect.height = VOU_MAX_IMAGE_HEIGHT;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static irqreturn_t sh_vou_isr(int irq, void *dev_id)
-{
- struct sh_vou_device *vou_dev = dev_id;
- static unsigned long j;
- struct videobuf_buffer *vb;
- static int cnt;
- static int side;
- u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
- u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
-
- if (!(irq_status & 0x300)) {
- if (printk_timed_ratelimit(&j, 500))
- dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n",
- irq_status);
- return IRQ_NONE;
- }
-
- spin_lock(&vou_dev->lock);
- if (!vou_dev->active || list_empty(&vou_dev->queue)) {
- if (printk_timed_ratelimit(&j, 500))
- dev_warn(vou_dev->v4l2_dev.dev,
- "IRQ without active buffer: %x!\n", irq_status);
- /* Just ack: buf_release will disable further interrupts */
- sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300);
- spin_unlock(&vou_dev->lock);
- return IRQ_HANDLED;
- }
-
- masked = ~(0x300 & irq_status) & irq_status & 0x30304;
- dev_dbg(vou_dev->v4l2_dev.dev,
- "IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n",
- irq_status, masked, vou_status, cnt);
-
- cnt++;
- side = vou_status & 0x10000;
-
- /* Clear only set interrupts */
- sh_vou_reg_a_write(vou_dev, VOUIR, masked);
-
- vb = vou_dev->active;
- list_del(&vb->queue);
-
- vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
- wake_up(&vb->done);
-
- if (list_empty(&vou_dev->queue)) {
- /* Stop VOU */
- dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n",
- __func__, cnt);
- sh_vou_reg_a_set(vou_dev, VOUER, 0, 1);
- vou_dev->active = NULL;
- vou_dev->status = SH_VOU_INITIALISING;
- /* Disable End-of-Frame (VSYNC) interrupts */
- sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000);
- spin_unlock(&vou_dev->lock);
- return IRQ_HANDLED;
- }
-
- vou_dev->active = list_entry(vou_dev->queue.next,
- struct videobuf_buffer, queue);
-
- if (vou_dev->active->queue.next != &vou_dev->queue) {
- struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next,
- struct videobuf_buffer, queue);
- sh_vou_schedule_next(vou_dev, new);
- }
-
- spin_unlock(&vou_dev->lock);
-
- return IRQ_HANDLED;
-}
-
-static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
-{
- struct sh_vou_pdata *pdata = vou_dev->pdata;
- u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29;
- int i = 100;
-
- /* Disable all IRQs */
- sh_vou_reg_a_write(vou_dev, VOUIR, 0);
-
- /* Reset VOU interfaces - registers unaffected */
- sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101);
- while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101))
- udelay(1);
-
- if (!i)
- return -ETIMEDOUT;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i);
-
- if (pdata->flags & SH_VOU_PCLK_FALLING)
- voucr |= 1 << 28;
- if (pdata->flags & SH_VOU_HSYNC_LOW)
- voucr |= 1 << 27;
- if (pdata->flags & SH_VOU_VSYNC_LOW)
- voucr |= 1 << 26;
- sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000);
-
- /* Manual register side switching at first */
- sh_vou_reg_a_write(vou_dev, VOURCR, 4);
- /* Default - fixed HSYNC length, can be made configurable is required */
- sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000);
-
- return 0;
-}
-
-/* File operations */
-static int sh_vou_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
- GFP_KERNEL);
-
- if (!vou_file)
- return -ENOMEM;
-
- dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
-
- file->private_data = vou_file;
-
- if (atomic_inc_return(&vou_dev->use_count) == 1) {
- int ret;
- /* First open */
- vou_dev->status = SH_VOU_INITIALISING;
- pm_runtime_get_sync(vdev->v4l2_dev->dev);
- ret = sh_vou_hw_init(vou_dev);
- if (ret < 0) {
- atomic_dec(&vou_dev->use_count);
- pm_runtime_put(vdev->v4l2_dev->dev);
- vou_dev->status = SH_VOU_IDLE;
- return ret;
- }
- }
-
- videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops,
- vou_dev->v4l2_dev.dev, &vou_dev->lock,
- V4L2_BUF_TYPE_VIDEO_OUTPUT,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), vdev,
- &vou_dev->fop_lock);
-
- return 0;
-}
-
-static int sh_vou_release(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct sh_vou_file *vou_file = file->private_data;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- if (!atomic_dec_return(&vou_dev->use_count)) {
- /* Last close */
- vou_dev->status = SH_VOU_IDLE;
- sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
- pm_runtime_put(vdev->v4l2_dev->dev);
- }
-
- file->private_data = NULL;
- kfree(vou_file);
-
- return 0;
-}
-
-static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct sh_vou_file *vou_file = file->private_data;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- return videobuf_mmap_mapper(&vou_file->vbq, vma);
-}
-
-static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
-{
- struct sh_vou_file *vou_file = file->private_data;
-
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
-
- return videobuf_poll_stream(file, &vou_file->vbq, wait);
-}
-
-static int sh_vou_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *id)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int sh_vou_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
-}
-
-static int sh_vou_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
-
- return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
-}
-#endif
-
-/* sh_vou display ioctl operations */
-static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
- .vidioc_querycap = sh_vou_querycap,
- .vidioc_enum_fmt_vid_out = sh_vou_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out,
- .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out,
- .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out,
- .vidioc_reqbufs = sh_vou_reqbufs,
- .vidioc_querybuf = sh_vou_querybuf,
- .vidioc_qbuf = sh_vou_qbuf,
- .vidioc_dqbuf = sh_vou_dqbuf,
- .vidioc_streamon = sh_vou_streamon,
- .vidioc_streamoff = sh_vou_streamoff,
- .vidioc_s_std = sh_vou_s_std,
- .vidioc_g_std = sh_vou_g_std,
- .vidioc_cropcap = sh_vou_cropcap,
- .vidioc_g_crop = sh_vou_g_crop,
- .vidioc_s_crop = sh_vou_s_crop,
- .vidioc_g_chip_ident = sh_vou_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = sh_vou_g_register,
- .vidioc_s_register = sh_vou_s_register,
-#endif
-};
-
-static const struct v4l2_file_operations sh_vou_fops = {
- .owner = THIS_MODULE,
- .open = sh_vou_open,
- .release = sh_vou_release,
- .unlocked_ioctl = video_ioctl2,
- .mmap = sh_vou_mmap,
- .poll = sh_vou_poll,
-};
-
-static const struct video_device sh_vou_video_template = {
- .name = "sh_vou",
- .fops = &sh_vou_fops,
- .ioctl_ops = &sh_vou_ioctl_ops,
- .tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-static int __devinit sh_vou_probe(struct platform_device *pdev)
-{
- struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
- struct v4l2_rect *rect;
- struct v4l2_pix_format *pix;
- struct i2c_adapter *i2c_adap;
- struct video_device *vdev;
- struct sh_vou_device *vou_dev;
- struct resource *reg_res, *region;
- struct v4l2_subdev *subdev;
- int irq, ret;
-
- reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
-
- if (!vou_pdata || !reg_res || irq <= 0) {
- dev_err(&pdev->dev, "Insufficient VOU platform information.\n");
- return -ENODEV;
- }
-
- vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL);
- if (!vou_dev)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&vou_dev->queue);
- spin_lock_init(&vou_dev->lock);
- mutex_init(&vou_dev->fop_lock);
- atomic_set(&vou_dev->use_count, 0);
- vou_dev->pdata = vou_pdata;
- vou_dev->status = SH_VOU_IDLE;
-
- rect = &vou_dev->rect;
- pix = &vou_dev->pix;
-
- /* Fill in defaults */
- vou_dev->std = sh_vou_video_template.current_norm;
- rect->left = 0;
- rect->top = 0;
- rect->width = VOU_MAX_IMAGE_WIDTH;
- rect->height = 480;
- pix->width = VOU_MAX_IMAGE_WIDTH;
- pix->height = 480;
- pix->pixelformat = V4L2_PIX_FMT_YVYU;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2;
- pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480;
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- region = request_mem_region(reg_res->start, resource_size(reg_res),
- pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "VOU region already claimed\n");
- ret = -EBUSY;
- goto ereqmemreg;
- }
-
- vou_dev->base = ioremap(reg_res->start, resource_size(reg_res));
- if (!vou_dev->base) {
- ret = -ENOMEM;
- goto emap;
- }
-
- ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev);
- if (ret < 0)
- goto ereqirq;
-
- ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Error registering v4l2 device\n");
- goto ev4l2devreg;
- }
-
- /* Allocate memory for video device */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- ret = -ENOMEM;
- goto evdevalloc;
- }
-
- *vdev = sh_vou_video_template;
- if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT)
- vdev->tvnorms |= V4L2_STD_PAL;
- vdev->v4l2_dev = &vou_dev->v4l2_dev;
- vdev->release = video_device_release;
- vdev->lock = &vou_dev->fop_lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
-
- vou_dev->vdev = vdev;
- video_set_drvdata(vdev, vou_dev);
-
- pm_runtime_enable(&pdev->dev);
- pm_runtime_resume(&pdev->dev);
-
- i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap);
- if (!i2c_adap) {
- ret = -ENODEV;
- goto ei2cgadap;
- }
-
- ret = sh_vou_hw_init(vou_dev);
- if (ret < 0)
- goto ereset;
-
- subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- vou_pdata->board_info, NULL);
- if (!subdev) {
- ret = -ENOMEM;
- goto ei2cnd;
- }
-
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0)
- goto evregdev;
-
- return 0;
-
-evregdev:
-ei2cnd:
-ereset:
- i2c_put_adapter(i2c_adap);
-ei2cgadap:
- video_device_release(vdev);
- pm_runtime_disable(&pdev->dev);
-evdevalloc:
- v4l2_device_unregister(&vou_dev->v4l2_dev);
-ev4l2devreg:
- free_irq(irq, vou_dev);
-ereqirq:
- iounmap(vou_dev->base);
-emap:
- release_mem_region(reg_res->start, resource_size(reg_res));
-ereqmemreg:
- kfree(vou_dev);
- return ret;
-}
-
-static int __devexit sh_vou_remove(struct platform_device *pdev)
-{
- int irq = platform_get_irq(pdev, 0);
- struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
- struct sh_vou_device *vou_dev = container_of(v4l2_dev,
- struct sh_vou_device, v4l2_dev);
- struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
- struct v4l2_subdev, list);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct resource *reg_res;
-
- if (irq > 0)
- free_irq(irq, vou_dev);
- pm_runtime_disable(&pdev->dev);
- video_unregister_device(vou_dev->vdev);
- i2c_put_adapter(client->adapter);
- v4l2_device_unregister(&vou_dev->v4l2_dev);
- iounmap(vou_dev->base);
- reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (reg_res)
- release_mem_region(reg_res->start, resource_size(reg_res));
- kfree(vou_dev);
- return 0;
-}
-
-static struct platform_driver __refdata sh_vou = {
- .remove = __devexit_p(sh_vou_remove),
- .driver = {
- .name = "sh-vou",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sh_vou_init(void)
-{
- return platform_driver_probe(&sh_vou, sh_vou_probe);
-}
-
-static void __exit sh_vou_exit(void)
-{
- platform_driver_unregister(&sh_vou);
-}
-
-module_init(sh_vou_init);
-module_exit(sh_vou_exit);
-
-MODULE_DESCRIPTION("SuperH VOU driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.1.0");
-MODULE_ALIAS("platform:sh-vou");
diff --git a/drivers/media/video/smiapp-pll.c b/drivers/media/video/smiapp-pll.c
deleted file mode 100644
index a2e41a21dc65..000000000000
--- a/drivers/media/video/smiapp-pll.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * drivers/media/video/smiapp-pll.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/gcd.h>
-#include <linux/lcm.h>
-#include <linux/module.h>
-
-#include "smiapp-pll.h"
-
-/* Return an even number or one. */
-static inline uint32_t clk_div_even(uint32_t a)
-{
- return max_t(uint32_t, 1, a & ~1);
-}
-
-/* Return an even number or one. */
-static inline uint32_t clk_div_even_up(uint32_t a)
-{
- if (a == 1)
- return 1;
- return (a + 1) & ~1;
-}
-
-static inline uint32_t is_one_or_even(uint32_t a)
-{
- if (a == 1)
- return 1;
- if (a & 1)
- return 0;
-
- return 1;
-}
-
-static int bounds_check(struct device *dev, uint32_t val,
- uint32_t min, uint32_t max, char *str)
-{
- if (val >= min && val <= max)
- return 0;
-
- dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
-
- return -EINVAL;
-}
-
-static void print_pll(struct device *dev, struct smiapp_pll *pll)
-{
- dev_dbg(dev, "pre_pll_clk_div\t%d\n", pll->pre_pll_clk_div);
- dev_dbg(dev, "pll_multiplier \t%d\n", pll->pll_multiplier);
- if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
- dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
- dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
- }
- dev_dbg(dev, "vt_sys_clk_div \t%d\n", pll->vt_sys_clk_div);
- dev_dbg(dev, "vt_pix_clk_div \t%d\n", pll->vt_pix_clk_div);
-
- dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
- dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
- dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
- if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
- dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
- pll->op_sys_clk_freq_hz);
- dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
- pll->op_pix_clk_freq_hz);
- }
- dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
- dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
-}
-
-int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
- struct smiapp_pll *pll)
-{
- uint32_t sys_div;
- uint32_t best_pix_div = INT_MAX >> 1;
- uint32_t vt_op_binning_div;
- uint32_t lane_op_clock_ratio;
- uint32_t mul, div;
- uint32_t more_mul_min, more_mul_max;
- uint32_t more_mul_factor;
- uint32_t min_vt_div, max_vt_div, vt_div;
- uint32_t min_sys_div, max_sys_div;
- unsigned int i;
- int rval;
-
- if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
- lane_op_clock_ratio = pll->lanes;
- else
- lane_op_clock_ratio = 1;
- dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
-
- dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
- pll->binning_vertical);
-
- /* CSI transfers 2 bits per clock per lane; thus times 2 */
- pll->pll_op_clk_freq_hz = pll->link_freq * 2
- * (pll->lanes / lane_op_clock_ratio);
-
- /* Figure out limits for pre-pll divider based on extclk */
- dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
- limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
- limits->max_pre_pll_clk_div =
- min_t(uint16_t, limits->max_pre_pll_clk_div,
- clk_div_even(pll->ext_clk_freq_hz /
- limits->min_pll_ip_freq_hz));
- limits->min_pre_pll_clk_div =
- max_t(uint16_t, limits->min_pre_pll_clk_div,
- clk_div_even_up(
- DIV_ROUND_UP(pll->ext_clk_freq_hz,
- limits->max_pll_ip_freq_hz)));
- dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
- limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
-
- i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
- mul = div_u64(pll->pll_op_clk_freq_hz, i);
- div = pll->ext_clk_freq_hz / i;
- dev_dbg(dev, "mul %d / div %d\n", mul, div);
-
- limits->min_pre_pll_clk_div =
- max_t(uint16_t, limits->min_pre_pll_clk_div,
- clk_div_even_up(
- DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
- limits->max_pll_op_freq_hz)));
- dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
- limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
-
- if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
- dev_err(dev, "unable to compute pre_pll divisor\n");
- return -EINVAL;
- }
-
- pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
-
- /*
- * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
- * too high.
- */
- dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
-
- /* Don't go above max pll multiplier. */
- more_mul_max = limits->max_pll_multiplier / mul;
- dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
- more_mul_max);
- /* Don't go above max pll op frequency. */
- more_mul_max =
- min_t(int,
- more_mul_max,
- limits->max_pll_op_freq_hz
- / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
- dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
- more_mul_max);
- /* Don't go above the division capability of op sys clock divider. */
- more_mul_max = min(more_mul_max,
- limits->max_op_sys_clk_div * pll->pre_pll_clk_div
- / div);
- dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
- more_mul_max);
- /* Ensure we won't go above min_pll_multiplier. */
- more_mul_max = min(more_mul_max,
- DIV_ROUND_UP(limits->max_pll_multiplier, mul));
- dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
- more_mul_max);
-
- /* Ensure we won't go below min_pll_op_freq_hz. */
- more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
- pll->ext_clk_freq_hz / pll->pre_pll_clk_div
- * mul);
- dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
- more_mul_min);
- /* Ensure we won't go below min_pll_multiplier. */
- more_mul_min = max(more_mul_min,
- DIV_ROUND_UP(limits->min_pll_multiplier, mul));
- dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
- more_mul_min);
-
- if (more_mul_min > more_mul_max) {
- dev_warn(dev,
- "unable to compute more_mul_min and more_mul_max");
- return -EINVAL;
- }
-
- more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
- dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
- more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div);
- dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
- more_mul_factor);
- i = roundup(more_mul_min, more_mul_factor);
- if (!is_one_or_even(i))
- i <<= 1;
-
- dev_dbg(dev, "final more_mul: %d\n", i);
- if (i > more_mul_max) {
- dev_warn(dev, "final more_mul is bad, max %d", more_mul_max);
- return -EINVAL;
- }
-
- pll->pll_multiplier = mul * i;
- pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
- dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
-
- pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
- / pll->pre_pll_clk_div;
-
- pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
- * pll->pll_multiplier;
-
- /* Derive pll_op_clk_freq_hz. */
- pll->op_sys_clk_freq_hz =
- pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
-
- pll->op_pix_clk_div = pll->bits_per_pixel;
- dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
-
- pll->op_pix_clk_freq_hz =
- pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
-
- /*
- * Some sensors perform analogue binning and some do this
- * digitally. The ones doing this digitally can be roughly be
- * found out using this formula. The ones doing this digitally
- * should run at higher clock rate, so smaller divisor is used
- * on video timing side.
- */
- if (limits->min_line_length_pck_bin > limits->min_line_length_pck
- / pll->binning_horizontal)
- vt_op_binning_div = pll->binning_horizontal;
- else
- vt_op_binning_div = 1;
- dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
-
- /*
- * Profile 2 supports vt_pix_clk_div E [4, 10]
- *
- * Horizontal binning can be used as a base for difference in
- * divisors. One must make sure that horizontal blanking is
- * enough to accommodate the CSI-2 sync codes.
- *
- * Take scaling factor into account as well.
- *
- * Find absolute limits for the factor of vt divider.
- */
- dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
- min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
- * pll->scale_n,
- lane_op_clock_ratio * vt_op_binning_div
- * pll->scale_m);
-
- /* Find smallest and biggest allowed vt divisor. */
- dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
- min_vt_div = max(min_vt_div,
- DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
- limits->max_vt_pix_clk_freq_hz));
- dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
- min_vt_div);
- min_vt_div = max_t(uint32_t, min_vt_div,
- limits->min_vt_pix_clk_div
- * limits->min_vt_sys_clk_div);
- dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
-
- max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div;
- dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
- max_vt_div = min(max_vt_div,
- DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
- limits->min_vt_pix_clk_freq_hz));
- dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
- max_vt_div);
-
- /*
- * Find limitsits for sys_clk_div. Not all values are possible
- * with all values of pix_clk_div.
- */
- min_sys_div = limits->min_vt_sys_clk_div;
- dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
- min_sys_div = max(min_sys_div,
- DIV_ROUND_UP(min_vt_div,
- limits->max_vt_pix_clk_div));
- dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
- min_sys_div = max(min_sys_div,
- pll->pll_op_clk_freq_hz
- / limits->max_vt_sys_clk_freq_hz);
- dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
- min_sys_div = clk_div_even_up(min_sys_div);
- dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
-
- max_sys_div = limits->max_vt_sys_clk_div;
- dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
- max_sys_div = min(max_sys_div,
- DIV_ROUND_UP(max_vt_div,
- limits->min_vt_pix_clk_div));
- dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
- max_sys_div = min(max_sys_div,
- DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
- limits->min_vt_pix_clk_freq_hz));
- dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
-
- /*
- * Find pix_div such that a legal pix_div * sys_div results
- * into a value which is not smaller than div, the desired
- * divisor.
- */
- for (vt_div = min_vt_div; vt_div <= max_vt_div;
- vt_div += 2 - (vt_div & 1)) {
- for (sys_div = min_sys_div;
- sys_div <= max_sys_div;
- sys_div += 2 - (sys_div & 1)) {
- int pix_div = DIV_ROUND_UP(vt_div, sys_div);
-
- if (pix_div < limits->min_vt_pix_clk_div
- || pix_div > limits->max_vt_pix_clk_div) {
- dev_dbg(dev,
- "pix_div %d too small or too big (%d--%d)\n",
- pix_div,
- limits->min_vt_pix_clk_div,
- limits->max_vt_pix_clk_div);
- continue;
- }
-
- /* Check if this one is better. */
- if (pix_div * sys_div
- <= roundup(min_vt_div, best_pix_div))
- best_pix_div = pix_div;
- }
- if (best_pix_div < INT_MAX >> 1)
- break;
- }
-
- pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
- pll->vt_pix_clk_div = best_pix_div;
-
- pll->vt_sys_clk_freq_hz =
- pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
- pll->vt_pix_clk_freq_hz =
- pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
-
- pll->pixel_rate_csi =
- pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
-
- print_pll(dev, pll);
-
- rval = bounds_check(dev, pll->pre_pll_clk_div,
- limits->min_pre_pll_clk_div,
- limits->max_pre_pll_clk_div, "pre_pll_clk_div");
- if (!rval)
- rval = bounds_check(
- dev, pll->pll_ip_clk_freq_hz,
- limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz,
- "pll_ip_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->pll_multiplier,
- limits->min_pll_multiplier, limits->max_pll_multiplier,
- "pll_multiplier");
- if (!rval)
- rval = bounds_check(
- dev, pll->pll_op_clk_freq_hz,
- limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
- "pll_op_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_sys_clk_div,
- limits->min_op_sys_clk_div, limits->max_op_sys_clk_div,
- "op_sys_clk_div");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_pix_clk_div,
- limits->min_op_pix_clk_div, limits->max_op_pix_clk_div,
- "op_pix_clk_div");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_sys_clk_freq_hz,
- limits->min_op_sys_clk_freq_hz,
- limits->max_op_sys_clk_freq_hz,
- "op_sys_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_pix_clk_freq_hz,
- limits->min_op_pix_clk_freq_hz,
- limits->max_op_pix_clk_freq_hz,
- "op_pix_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->vt_sys_clk_freq_hz,
- limits->min_vt_sys_clk_freq_hz,
- limits->max_vt_sys_clk_freq_hz,
- "vt_sys_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->vt_pix_clk_freq_hz,
- limits->min_vt_pix_clk_freq_hz,
- limits->max_vt_pix_clk_freq_hz,
- "vt_pix_clk_freq_hz");
-
- return rval;
-}
-EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
-MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp-pll.h b/drivers/media/video/smiapp-pll.h
deleted file mode 100644
index 9eab63f23afb..000000000000
--- a/drivers/media/video/smiapp-pll.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * drivers/media/video/smiapp-pll.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 SMIAPP_PLL_H
-#define SMIAPP_PLL_H
-
-#include <linux/device.h>
-
-struct smiapp_pll {
- uint8_t lanes;
- uint8_t binning_horizontal;
- uint8_t binning_vertical;
- uint8_t scale_m;
- uint8_t scale_n;
- uint8_t bits_per_pixel;
- uint16_t flags;
- uint32_t link_freq;
-
- uint16_t pre_pll_clk_div;
- uint16_t pll_multiplier;
- uint16_t op_sys_clk_div;
- uint16_t op_pix_clk_div;
- uint16_t vt_sys_clk_div;
- uint16_t vt_pix_clk_div;
-
- uint32_t ext_clk_freq_hz;
- uint32_t pll_ip_clk_freq_hz;
- uint32_t pll_op_clk_freq_hz;
- uint32_t op_sys_clk_freq_hz;
- uint32_t op_pix_clk_freq_hz;
- uint32_t vt_sys_clk_freq_hz;
- uint32_t vt_pix_clk_freq_hz;
-
- uint32_t pixel_rate_csi;
-};
-
-struct smiapp_pll_limits {
- /* Strict PLL limits */
- uint32_t min_ext_clk_freq_hz;
- uint32_t max_ext_clk_freq_hz;
- uint16_t min_pre_pll_clk_div;
- uint16_t max_pre_pll_clk_div;
- uint32_t min_pll_ip_freq_hz;
- uint32_t max_pll_ip_freq_hz;
- uint16_t min_pll_multiplier;
- uint16_t max_pll_multiplier;
- uint32_t min_pll_op_freq_hz;
- uint32_t max_pll_op_freq_hz;
-
- uint16_t min_vt_sys_clk_div;
- uint16_t max_vt_sys_clk_div;
- uint32_t min_vt_sys_clk_freq_hz;
- uint32_t max_vt_sys_clk_freq_hz;
- uint16_t min_vt_pix_clk_div;
- uint16_t max_vt_pix_clk_div;
- uint32_t min_vt_pix_clk_freq_hz;
- uint32_t max_vt_pix_clk_freq_hz;
-
- uint16_t min_op_sys_clk_div;
- uint16_t max_op_sys_clk_div;
- uint32_t min_op_sys_clk_freq_hz;
- uint32_t max_op_sys_clk_freq_hz;
- uint16_t min_op_pix_clk_div;
- uint16_t max_op_pix_clk_div;
- uint32_t min_op_pix_clk_freq_hz;
- uint32_t max_op_pix_clk_freq_hz;
-
- /* Other relevant limits */
- uint32_t min_line_length_pck_bin;
- uint32_t min_line_length_pck;
-};
-
-/* op pix clock is for all lanes in total normally */
-#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
-#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1)
-
-struct device;
-
-int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
- struct smiapp_pll *pll);
-
-#endif /* SMIAPP_PLL_H */
diff --git a/drivers/media/video/smiapp/Makefile b/drivers/media/video/smiapp/Makefile
deleted file mode 100644
index 36b0cfa2c541..000000000000
--- a/drivers/media/video/smiapp/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-smiapp-objs += smiapp-core.o smiapp-regs.o \
- smiapp-quirk.o smiapp-limits.o
-obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o
-
-ccflags-y += -Idrivers/media/video
diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c
deleted file mode 100644
index bfd47c106134..000000000000
--- a/drivers/media/video/smiapp/smiapp-core.c
+++ /dev/null
@@ -1,2895 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-core.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2010--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
- *
- * Based on smiapp driver by Vimarsh Zutshi
- * Based on jt8ev1.c by Vimarsh Zutshi
- * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.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/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <linux/v4l2-mediabus.h>
-#include <media/v4l2-device.h>
-
-#include "smiapp.h"
-
-#define SMIAPP_ALIGN_DIM(dim, flags) \
- ((flags) & V4L2_SEL_FLAG_GE \
- ? ALIGN((dim), 2) \
- : (dim) & ~1)
-
-/*
- * smiapp_module_idents - supported camera modules
- */
-static const struct smiapp_module_ident smiapp_module_idents[] = {
- SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
- SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
- SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
- SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
- SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
- SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
- SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
- SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
- SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
- SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
- SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
-};
-
-/*
- *
- * Dynamic Capability Identification
- *
- */
-
-static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
- unsigned int i;
- int rval;
- int line_count = 0;
- int embedded_start = -1, embedded_end = -1;
- int image_start = 0;
-
- rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
- &fmt_model_type);
- if (rval)
- return rval;
-
- rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
- &fmt_model_subtype);
- if (rval)
- return rval;
-
- ncol_desc = (fmt_model_subtype
- & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
- >> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
- nrow_desc = fmt_model_subtype
- & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK;
-
- dev_dbg(&client->dev, "format_model_type %s\n",
- fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
- ? "2 byte" :
- fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
- ? "4 byte" : "is simply bad");
-
- for (i = 0; i < ncol_desc + nrow_desc; i++) {
- u32 desc;
- u32 pixelcode;
- u32 pixels;
- char *which;
- char *what;
-
- if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
- &desc);
- if (rval)
- return rval;
-
- pixelcode =
- (desc
- & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
- >> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
- pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
- } else if (fmt_model_type
- == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
- &desc);
- if (rval)
- return rval;
-
- pixelcode =
- (desc
- & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
- >> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
- pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
- } else {
- dev_dbg(&client->dev,
- "invalid frame format model type %d\n",
- fmt_model_type);
- return -EINVAL;
- }
-
- if (i < ncol_desc)
- which = "columns";
- else
- which = "rows";
-
- switch (pixelcode) {
- case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
- what = "embedded";
- break;
- case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
- what = "dummy";
- break;
- case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
- what = "black";
- break;
- case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
- what = "dark";
- break;
- case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
- what = "visible";
- break;
- default:
- what = "invalid";
- dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
- break;
- }
-
- dev_dbg(&client->dev, "%s pixels: %d %s\n",
- what, pixels, which);
-
- if (i < ncol_desc)
- continue;
-
- /* Handle row descriptors */
- if (pixelcode
- == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
- embedded_start = line_count;
- } else {
- if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
- || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
- image_start = line_count;
- if (embedded_start != -1 && embedded_end == -1)
- embedded_end = line_count;
- }
- line_count += pixels;
- }
-
- if (embedded_start == -1 || embedded_end == -1) {
- embedded_start = 0;
- embedded_end = 0;
- }
-
- dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
- embedded_start, embedded_end);
- dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
-
- return 0;
-}
-
-static int smiapp_pll_configure(struct smiapp_sensor *sensor)
-{
- struct smiapp_pll *pll = &sensor->pll;
- int rval;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
- if (rval < 0)
- return rval;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
- if (rval < 0)
- return rval;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
- if (rval < 0)
- return rval;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
- if (rval < 0)
- return rval;
-
- /* Lane op clock ratio does not apply here. */
- rval = smiapp_write(
- sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
- DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
- if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
- return rval;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
- if (rval < 0)
- return rval;
-
- return smiapp_write(
- sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
-}
-
-static int smiapp_pll_update(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct smiapp_pll_limits lim = {
- .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
- .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
- .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
- .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
- .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
- .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
- .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
- .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
-
- .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
- .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
- .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
- .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
- .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
- .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
- .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
- .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
-
- .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
- .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
- .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
- .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
- .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
- .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
- .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
- .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
-
- .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
- .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
- };
- struct smiapp_pll *pll = &sensor->pll;
- int rval;
-
- memset(&sensor->pll, 0, sizeof(sensor->pll));
-
- pll->lanes = sensor->platform_data->lanes;
- pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
-
- if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
- /*
- * Fill in operational clock divisors limits from the
- * video timing ones. On profile 0 sensors the
- * requirements regarding them are essentially the
- * same as on VT ones.
- */
- lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
- lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
- lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
- lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
- lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
- lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
- lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
- lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
- /* Profile 0 sensors have no separate OP clock branch. */
- pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
- }
-
- if (smiapp_needs_quirk(sensor,
- SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
- pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
-
- pll->binning_horizontal = sensor->binning_horizontal;
- pll->binning_vertical = sensor->binning_vertical;
- pll->link_freq =
- sensor->link_freq->qmenu_int[sensor->link_freq->val];
- pll->scale_m = sensor->scale_m;
- pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
- pll->bits_per_pixel = sensor->csi_format->compressed;
-
- rval = smiapp_pll_calculate(&client->dev, &lim, pll);
- if (rval < 0)
- return rval;
-
- sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
- sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
-
- return 0;
-}
-
-
-/*
- *
- * V4L2 Controls handling
- *
- */
-
-static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
-{
- struct v4l2_ctrl *ctrl = sensor->exposure;
- int max;
-
- max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
- + sensor->vblank->val
- - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
-
- ctrl->maximum = max;
- if (ctrl->default_value > max)
- ctrl->default_value = max;
- if (ctrl->val > max)
- ctrl->val = max;
- if (ctrl->cur.val > max)
- ctrl->cur.val = max;
-}
-
-/*
- * Order matters.
- *
- * 1. Bits-per-pixel, descending.
- * 2. Bits-per-pixel compressed, descending.
- * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
- * orders must be defined.
- */
-static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
- { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
-};
-
-const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
-
-#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \
- - (unsigned long)smiapp_csi_data_formats) \
- / sizeof(*smiapp_csi_data_formats))
-
-static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int flip = 0;
-
- if (sensor->hflip) {
- if (sensor->hflip->val)
- flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
-
- if (sensor->vflip->val)
- flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
- }
-
- flip ^= sensor->hvflip_inv_mask;
-
- dev_dbg(&client->dev, "flip %d\n", flip);
- return sensor->default_pixel_order ^ flip;
-}
-
-static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int csi_format_idx =
- to_csi_format_idx(sensor->csi_format) & ~3;
- unsigned int internal_csi_format_idx =
- to_csi_format_idx(sensor->internal_csi_format) & ~3;
- unsigned int pixel_order = smiapp_pixel_order(sensor);
-
- sensor->mbus_frame_fmts =
- sensor->default_mbus_frame_fmts << pixel_order;
- sensor->csi_format =
- &smiapp_csi_data_formats[csi_format_idx + pixel_order];
- sensor->internal_csi_format =
- &smiapp_csi_data_formats[internal_csi_format_idx
- + pixel_order];
-
- BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
- >= ARRAY_SIZE(smiapp_csi_data_formats));
- BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
-
- dev_dbg(&client->dev, "new pixel order %s\n",
- pixel_order_str[pixel_order]);
-}
-
-static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct smiapp_sensor *sensor =
- container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
- ->sensor;
- u32 orient = 0;
- int exposure;
- int rval;
-
- switch (ctrl->id) {
- case V4L2_CID_ANALOGUE_GAIN:
- return smiapp_write(
- sensor,
- SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
-
- case V4L2_CID_EXPOSURE:
- return smiapp_write(
- sensor,
- SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
-
- case V4L2_CID_HFLIP:
- case V4L2_CID_VFLIP:
- if (sensor->streaming)
- return -EBUSY;
-
- if (sensor->hflip->val)
- orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
-
- if (sensor->vflip->val)
- orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
-
- orient ^= sensor->hvflip_inv_mask;
- rval = smiapp_write(sensor,
- SMIAPP_REG_U8_IMAGE_ORIENTATION,
- orient);
- if (rval < 0)
- return rval;
-
- smiapp_update_mbus_formats(sensor);
-
- return 0;
-
- case V4L2_CID_VBLANK:
- exposure = sensor->exposure->val;
-
- __smiapp_update_exposure_limits(sensor);
-
- if (exposure > sensor->exposure->maximum) {
- sensor->exposure->val =
- sensor->exposure->maximum;
- rval = smiapp_set_ctrl(
- sensor->exposure);
- if (rval < 0)
- return rval;
- }
-
- return smiapp_write(
- sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
- + ctrl->val);
-
- case V4L2_CID_HBLANK:
- return smiapp_write(
- sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
- + ctrl->val);
-
- case V4L2_CID_LINK_FREQ:
- if (sensor->streaming)
- return -EBUSY;
-
- return smiapp_pll_update(sensor);
-
- default:
- return -EINVAL;
- }
-}
-
-static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
- .s_ctrl = smiapp_set_ctrl,
-};
-
-static int smiapp_init_controls(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int max;
- int rval;
-
- rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
- if (rval)
- return rval;
- sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
-
- sensor->analog_gain = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_ANALOGUE_GAIN,
- sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
- sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
- max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
- sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
-
- /* Exposure limits will be updated soon, use just something here. */
- sensor->exposure = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_EXPOSURE, 0, 0, 1, 0);
-
- sensor->hflip = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- sensor->vflip = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
-
- sensor->vblank = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_VBLANK, 0, 1, 1, 0);
-
- if (sensor->vblank)
- sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
-
- sensor->hblank = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_HBLANK, 0, 1, 1, 0);
-
- if (sensor->hblank)
- sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
-
- sensor->pixel_rate_parray = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
-
- if (sensor->pixel_array->ctrl_handler.error) {
- dev_err(&client->dev,
- "pixel array controls initialization failed (%d)\n",
- sensor->pixel_array->ctrl_handler.error);
- rval = sensor->pixel_array->ctrl_handler.error;
- goto error;
- }
-
- sensor->pixel_array->sd.ctrl_handler =
- &sensor->pixel_array->ctrl_handler;
-
- v4l2_ctrl_cluster(2, &sensor->hflip);
-
- rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
- if (rval)
- goto error;
- sensor->src->ctrl_handler.lock = &sensor->mutex;
-
- for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
-
- sensor->link_freq = v4l2_ctrl_new_int_menu(
- &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_LINK_FREQ, max, 0,
- sensor->platform_data->op_sys_clock);
-
- sensor->pixel_rate_csi = v4l2_ctrl_new_std(
- &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
-
- if (sensor->src->ctrl_handler.error) {
- dev_err(&client->dev,
- "src controls initialization failed (%d)\n",
- sensor->src->ctrl_handler.error);
- rval = sensor->src->ctrl_handler.error;
- goto error;
- }
-
- sensor->src->sd.ctrl_handler =
- &sensor->src->ctrl_handler;
-
- return 0;
-
-error:
- v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
- v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
-
- return rval;
-}
-
-static void smiapp_free_controls(struct smiapp_sensor *sensor)
-{
- unsigned int i;
-
- for (i = 0; i < sensor->ssds_used; i++)
- v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
-}
-
-static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
- unsigned int n)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int i;
- u32 val;
- int rval;
-
- for (i = 0; i < n; i++) {
- rval = smiapp_read(
- sensor, smiapp_reg_limits[limit[i]].addr, &val);
- if (rval)
- return rval;
- sensor->limits[limit[i]] = val;
- dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
- smiapp_reg_limits[limit[i]].addr,
- smiapp_reg_limits[limit[i]].what, val, val);
- }
-
- return 0;
-}
-
-static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
-{
- unsigned int i;
- int rval;
-
- for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
- rval = smiapp_get_limits(sensor, &i, 1);
- if (rval < 0)
- return rval;
- }
-
- if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
- smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
-
- return 0;
-}
-
-static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- static u32 const limits[] = {
- SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
- SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
- SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
- SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
- SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
- SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
- SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
- };
- static u32 const limits_replace[] = {
- SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
- SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
- SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
- SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
- SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
- SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
- SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
- };
- unsigned int i;
- int rval;
-
- if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
- SMIAPP_BINNING_CAPABILITY_NO) {
- for (i = 0; i < ARRAY_SIZE(limits); i++)
- sensor->limits[limits[i]] =
- sensor->limits[limits_replace[i]];
-
- return 0;
- }
-
- rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
- if (rval < 0)
- return rval;
-
- /*
- * Sanity check whether the binning limits are valid. If not,
- * use the non-binning ones.
- */
- if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]
- && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]
- && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN])
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(limits); i++) {
- dev_dbg(&client->dev,
- "replace limit 0x%8.8x \"%s\" = %d, 0x%x\n",
- smiapp_reg_limits[limits[i]].addr,
- smiapp_reg_limits[limits[i]].what,
- sensor->limits[limits_replace[i]],
- sensor->limits[limits_replace[i]]);
- sensor->limits[limits[i]] =
- sensor->limits[limits_replace[i]];
- }
-
- return 0;
-}
-
-static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int type, n;
- unsigned int i, pixel_order;
- int rval;
-
- rval = smiapp_read(
- sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
- if (rval)
- return rval;
-
- dev_dbg(&client->dev, "data_format_model_type %d\n", type);
-
- rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER,
- &pixel_order);
- if (rval)
- return rval;
-
- if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
- dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
- return -EINVAL;
- }
-
- dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
- pixel_order_str[pixel_order]);
-
- switch (type) {
- case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
- n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
- break;
- case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
- n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
- break;
- default:
- return -EINVAL;
- }
-
- sensor->default_pixel_order = pixel_order;
- sensor->mbus_frame_fmts = 0;
-
- for (i = 0; i < n; i++) {
- unsigned int fmt, j;
-
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
- if (rval)
- return rval;
-
- dev_dbg(&client->dev, "bpp %d, compressed %d\n",
- fmt >> 8, (u8)fmt);
-
- for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
- const struct smiapp_csi_data_format *f =
- &smiapp_csi_data_formats[j];
-
- if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
- continue;
-
- if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
- continue;
-
- dev_dbg(&client->dev, "jolly good! %d\n", j);
-
- sensor->default_mbus_frame_fmts |= 1 << j;
- if (!sensor->csi_format) {
- sensor->csi_format = f;
- sensor->internal_csi_format = f;
- }
- }
- }
-
- if (!sensor->csi_format) {
- dev_err(&client->dev, "no supported mbus code found\n");
- return -EINVAL;
- }
-
- smiapp_update_mbus_formats(sensor);
-
- return 0;
-}
-
-static void smiapp_update_blanking(struct smiapp_sensor *sensor)
-{
- struct v4l2_ctrl *vblank = sensor->vblank;
- struct v4l2_ctrl *hblank = sensor->hblank;
-
- vblank->minimum =
- max_t(int,
- sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
- sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
- vblank->maximum =
- sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
-
- vblank->val = clamp_t(int, vblank->val,
- vblank->minimum, vblank->maximum);
- vblank->default_value = vblank->minimum;
- vblank->val = vblank->val;
- vblank->cur.val = vblank->val;
-
- hblank->minimum =
- max_t(int,
- sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
- sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
- hblank->maximum =
- sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
-
- hblank->val = clamp_t(int, hblank->val,
- hblank->minimum, hblank->maximum);
- hblank->default_value = hblank->minimum;
- hblank->val = hblank->val;
- hblank->cur.val = hblank->val;
-
- __smiapp_update_exposure_limits(sensor);
-}
-
-static int smiapp_update_mode(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int binning_mode;
- int rval;
-
- dev_dbg(&client->dev, "frame size: %dx%d\n",
- sensor->src->crop[SMIAPP_PAD_SRC].width,
- sensor->src->crop[SMIAPP_PAD_SRC].height);
- dev_dbg(&client->dev, "csi format width: %d\n",
- sensor->csi_format->width);
-
- /* Binning has to be set up here; it affects limits */
- if (sensor->binning_horizontal == 1 &&
- sensor->binning_vertical == 1) {
- binning_mode = 0;
- } else {
- u8 binning_type =
- (sensor->binning_horizontal << 4)
- | sensor->binning_vertical;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
- if (rval < 0)
- return rval;
-
- binning_mode = 1;
- }
- rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
- if (rval < 0)
- return rval;
-
- /* Get updated limits due to binning */
- rval = smiapp_get_limits_binning(sensor);
- if (rval < 0)
- return rval;
-
- rval = smiapp_pll_update(sensor);
- if (rval < 0)
- return rval;
-
- /* Output from pixel array, including blanking */
- smiapp_update_blanking(sensor);
-
- dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
- dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
-
- dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
- sensor->pll.vt_pix_clk_freq_hz /
- ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
- + sensor->hblank->val) *
- (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
- + sensor->vblank->val) / 100));
-
- return 0;
-}
-
-/*
- *
- * SMIA++ NVM handling
- *
- */
-static int smiapp_read_nvm(struct smiapp_sensor *sensor,
- unsigned char *nvm)
-{
- u32 i, s, p, np, v;
- int rval = 0, rval2;
-
- np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
- for (p = 0; p < np; p++) {
- rval = smiapp_write(
- sensor,
- SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
- if (rval)
- goto out;
-
- rval = smiapp_write(sensor,
- SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
- SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
- SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
- if (rval)
- goto out;
-
- for (i = 0; i < 1000; i++) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
-
- if (rval)
- goto out;
-
- if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
- break;
-
- if (--i == 0) {
- rval = -ETIMEDOUT;
- goto out;
- }
-
- }
-
- for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
- &v);
- if (rval)
- goto out;
-
- *nvm++ = v;
- }
- }
-
-out:
- rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
- if (rval < 0)
- return rval;
- else
- return rval2;
-}
-
-/*
- *
- * SMIA++ CCI address control
- *
- */
-static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int rval;
- u32 val;
-
- client->addr = sensor->platform_data->i2c_addr_dfl;
-
- rval = smiapp_write(sensor,
- SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
- sensor->platform_data->i2c_addr_alt << 1);
- if (rval)
- return rval;
-
- client->addr = sensor->platform_data->i2c_addr_alt;
-
- /* verify addr change went ok */
- rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
- if (rval)
- return rval;
-
- if (val != sensor->platform_data->i2c_addr_alt << 1)
- return -ENODEV;
-
- return 0;
-}
-
-/*
- *
- * SMIA++ Mode Control
- *
- */
-static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
-{
- struct smiapp_flash_strobe_parms *strobe_setup;
- unsigned int ext_freq = sensor->platform_data->ext_clk;
- u32 tmp;
- u32 strobe_adjustment;
- u32 strobe_width_high_rs;
- int rval;
-
- strobe_setup = sensor->platform_data->strobe_setup;
-
- /*
- * How to calculate registers related to strobe length. Please
- * do not change, or if you do at least know what you're
- * doing. :-)
- *
- * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
- *
- * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
- * / EXTCLK freq [Hz]) * flash_strobe_adjustment
- *
- * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
- * flash_strobe_adjustment E N, [1 - 0xff]
- *
- * The formula above is written as below to keep it on one
- * line:
- *
- * l / 10^6 = w / e * a
- *
- * Let's mark w * a by x:
- *
- * x = w * a
- *
- * Thus, we get:
- *
- * x = l * e / 10^6
- *
- * The strobe width must be at least as long as requested,
- * thus rounding upwards is needed.
- *
- * x = (l * e + 10^6 - 1) / 10^6
- * -----------------------------
- *
- * Maximum possible accuracy is wanted at all times. Thus keep
- * a as small as possible.
- *
- * Calculate a, assuming maximum w, with rounding upwards:
- *
- * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
- * -------------------------------------
- *
- * Thus, we also get w, with that a, with rounding upwards:
- *
- * w = (x + a - 1) / a
- * -------------------
- *
- * To get limits:
- *
- * x E [1, (2^16 - 1) * (2^8 - 1)]
- *
- * Substituting maximum x to the original formula (with rounding),
- * the maximum l is thus
- *
- * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
- *
- * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
- * --------------------------------------------------
- *
- * flash_strobe_length must be clamped between 1 and
- * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
- *
- * Then,
- *
- * flash_strobe_adjustment = ((flash_strobe_length *
- * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
- *
- * tFlash_strobe_width_ctrl = ((flash_strobe_length *
- * EXTCLK freq + 10^6 - 1) / 10^6 +
- * flash_strobe_adjustment - 1) / flash_strobe_adjustment
- */
- tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
- 1000000 + 1, ext_freq);
- strobe_setup->strobe_width_high_us =
- clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
-
- tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
- 1000000 - 1), 1000000ULL);
- strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
- strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
- strobe_adjustment;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS,
- strobe_setup->mode);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
- strobe_adjustment);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
- strobe_width_high_rs);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
- strobe_setup->strobe_delay);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
- strobe_setup->stobe_start_point);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
- strobe_setup->trigger);
-
-out:
- sensor->platform_data->strobe_setup->trigger = 0;
-
- return rval;
-}
-
-/* -----------------------------------------------------------------------------
- * Power management
- */
-
-static int smiapp_power_on(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int sleep;
- int rval;
-
- rval = regulator_enable(sensor->vana);
- if (rval) {
- dev_err(&client->dev, "failed to enable vana regulator\n");
- return rval;
- }
- usleep_range(1000, 1000);
-
- if (sensor->platform_data->set_xclk)
- rval = sensor->platform_data->set_xclk(
- &sensor->src->sd, sensor->platform_data->ext_clk);
- else
- rval = clk_enable(sensor->ext_clk);
- if (rval < 0) {
- dev_dbg(&client->dev, "failed to set xclk\n");
- goto out_xclk_fail;
- }
- usleep_range(1000, 1000);
-
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_set_value(sensor->platform_data->xshutdown, 1);
-
- sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
- usleep_range(sleep, sleep);
-
- /*
- * Failures to respond to the address change command have been noticed.
- * Those failures seem to be caused by the sensor requiring a longer
- * boot time than advertised. An additional 10ms delay seems to work
- * around the issue, but the SMIA++ I2C write retry hack makes the delay
- * unnecessary. The failures need to be investigated to find a proper
- * fix, and a delay will likely need to be added here if the I2C write
- * retry hack is reverted before the root cause of the boot time issue
- * is found.
- */
-
- if (sensor->platform_data->i2c_addr_alt) {
- rval = smiapp_change_cci_addr(sensor);
- if (rval) {
- dev_err(&client->dev, "cci address change error\n");
- goto out_cci_addr_fail;
- }
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET,
- SMIAPP_SOFTWARE_RESET);
- if (rval < 0) {
- dev_err(&client->dev, "software reset failed\n");
- goto out_cci_addr_fail;
- }
-
- if (sensor->platform_data->i2c_addr_alt) {
- rval = smiapp_change_cci_addr(sensor);
- if (rval) {
- dev_err(&client->dev, "cci address change error\n");
- goto out_cci_addr_fail;
- }
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE,
- SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
- if (rval) {
- dev_err(&client->dev, "compression mode set failed\n");
- goto out_cci_addr_fail;
- }
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
- sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
- if (rval) {
- dev_err(&client->dev, "extclk frequency set failed\n");
- goto out_cci_addr_fail;
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE,
- sensor->platform_data->lanes - 1);
- if (rval) {
- dev_err(&client->dev, "csi lane mode set failed\n");
- goto out_cci_addr_fail;
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
- SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
- if (rval) {
- dev_err(&client->dev, "fast standby set failed\n");
- goto out_cci_addr_fail;
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
- sensor->platform_data->csi_signalling_mode);
- if (rval) {
- dev_err(&client->dev, "csi signalling mode set failed\n");
- goto out_cci_addr_fail;
- }
-
- /* DPHY control done by sensor based on requested link rate */
- rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
- SMIAPP_DPHY_CTRL_UI);
- if (rval < 0)
- return rval;
-
- rval = smiapp_call_quirk(sensor, post_poweron);
- if (rval) {
- dev_err(&client->dev, "post_poweron quirks failed\n");
- goto out_cci_addr_fail;
- }
-
- /* Are we still initialising...? If yes, return here. */
- if (!sensor->pixel_array)
- return 0;
-
- rval = v4l2_ctrl_handler_setup(
- &sensor->pixel_array->ctrl_handler);
- if (rval)
- goto out_cci_addr_fail;
-
- rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
- if (rval)
- goto out_cci_addr_fail;
-
- mutex_lock(&sensor->mutex);
- rval = smiapp_update_mode(sensor);
- mutex_unlock(&sensor->mutex);
- if (rval < 0)
- goto out_cci_addr_fail;
-
- return 0;
-
-out_cci_addr_fail:
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_set_value(sensor->platform_data->xshutdown, 0);
- if (sensor->platform_data->set_xclk)
- sensor->platform_data->set_xclk(&sensor->src->sd, 0);
- else
- clk_disable(sensor->ext_clk);
-
-out_xclk_fail:
- regulator_disable(sensor->vana);
- return rval;
-}
-
-static void smiapp_power_off(struct smiapp_sensor *sensor)
-{
- /*
- * Currently power/clock to lens are enable/disabled separately
- * but they are essentially the same signals. So if the sensor is
- * powered off while the lens is powered on the sensor does not
- * really see a power off and next time the cci address change
- * will fail. So do a soft reset explicitly here.
- */
- if (sensor->platform_data->i2c_addr_alt)
- smiapp_write(sensor,
- SMIAPP_REG_U8_SOFTWARE_RESET,
- SMIAPP_SOFTWARE_RESET);
-
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_set_value(sensor->platform_data->xshutdown, 0);
- if (sensor->platform_data->set_xclk)
- sensor->platform_data->set_xclk(&sensor->src->sd, 0);
- else
- clk_disable(sensor->ext_clk);
- usleep_range(5000, 5000);
- regulator_disable(sensor->vana);
- sensor->streaming = 0;
-}
-
-static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int ret = 0;
-
- mutex_lock(&sensor->power_mutex);
-
- /*
- * If the power count is modified from 0 to != 0 or from != 0
- * to 0, update the power state.
- */
- if (!sensor->power_count == !on)
- goto out;
-
- if (on) {
- /* Power on and perform initialisation. */
- ret = smiapp_power_on(sensor);
- if (ret < 0)
- goto out;
- } else {
- smiapp_power_off(sensor);
- }
-
- /* Update the power count. */
- sensor->power_count += on ? 1 : -1;
- WARN_ON(sensor->power_count < 0);
-
-out:
- mutex_unlock(&sensor->power_mutex);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * Video stream management
- */
-
-static int smiapp_start_streaming(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int rval;
-
- mutex_lock(&sensor->mutex);
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT,
- (sensor->csi_format->width << 8) |
- sensor->csi_format->compressed);
- if (rval)
- goto out;
-
- rval = smiapp_pll_configure(sensor);
- if (rval)
- goto out;
-
- /* Analog crop start coordinates */
- rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
- if (rval < 0)
- goto out;
-
- /* Analog crop end coordinates */
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_X_ADDR_END,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
- + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_Y_ADDR_END,
- sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
- + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
- if (rval < 0)
- goto out;
-
- /*
- * Output from pixel array, including blanking, is set using
- * controls below. No need to set here.
- */
-
- /* Digital crop */
- if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
- == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
- sensor->scaler->crop[SMIAPP_PAD_SINK].left);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
- sensor->scaler->crop[SMIAPP_PAD_SINK].top);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
- sensor->scaler->crop[SMIAPP_PAD_SINK].width);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(
- sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
- sensor->scaler->crop[SMIAPP_PAD_SINK].height);
- if (rval < 0)
- goto out;
- }
-
- /* Scaling */
- if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- != SMIAPP_SCALING_CAPABILITY_NONE) {
- rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
- sensor->scaling_mode);
- if (rval < 0)
- goto out;
-
- rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M,
- sensor->scale_m);
- if (rval < 0)
- goto out;
- }
-
- /* Output size from sensor */
- rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE,
- sensor->src->crop[SMIAPP_PAD_SRC].width);
- if (rval < 0)
- goto out;
- rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
- sensor->src->crop[SMIAPP_PAD_SRC].height);
- if (rval < 0)
- goto out;
-
- if ((sensor->flash_capability &
- (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
- SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
- sensor->platform_data->strobe_setup != NULL &&
- sensor->platform_data->strobe_setup->trigger != 0) {
- rval = smiapp_setup_flash_strobe(sensor);
- if (rval)
- goto out;
- }
-
- rval = smiapp_call_quirk(sensor, pre_streamon);
- if (rval) {
- dev_err(&client->dev, "pre_streamon quirks failed\n");
- goto out;
- }
-
- rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
- SMIAPP_MODE_SELECT_STREAMING);
-
-out:
- mutex_unlock(&sensor->mutex);
-
- return rval;
-}
-
-static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int rval;
-
- mutex_lock(&sensor->mutex);
- rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
- SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
- if (rval)
- goto out;
-
- rval = smiapp_call_quirk(sensor, post_streamoff);
- if (rval)
- dev_err(&client->dev, "post_streamoff quirks failed\n");
-
-out:
- mutex_unlock(&sensor->mutex);
- return rval;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev video operations
- */
-
-static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int rval;
-
- if (sensor->streaming == enable)
- return 0;
-
- if (enable) {
- sensor->streaming = 1;
- rval = smiapp_start_streaming(sensor);
- if (rval < 0)
- sensor->streaming = 0;
- } else {
- rval = smiapp_stop_streaming(sensor);
- sensor->streaming = 0;
- }
-
- return rval;
-}
-
-static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- unsigned int i;
- int idx = -1;
- int rval = -EINVAL;
-
- mutex_lock(&sensor->mutex);
-
- dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
- subdev->name, code->pad, code->index);
-
- if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
- if (code->index)
- goto out;
-
- code->code = sensor->internal_csi_format->code;
- rval = 0;
- goto out;
- }
-
- for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
- if (sensor->mbus_frame_fmts & (1 << i))
- idx++;
-
- if (idx == code->index) {
- code->code = smiapp_csi_data_formats[i].code;
- dev_err(&client->dev, "found index %d, i %d, code %x\n",
- code->index, i, code->code);
- rval = 0;
- break;
- }
- }
-
-out:
- mutex_unlock(&sensor->mutex);
-
- return rval;
-}
-
-static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
- unsigned int pad)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
-
- if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
- return sensor->csi_format->code;
- else
- return sensor->internal_csi_format->code;
-}
-
-static int __smiapp_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
- } else {
- struct v4l2_rect *r;
-
- if (fmt->pad == ssd->source_pad)
- r = &ssd->crop[ssd->source_pad];
- else
- r = &ssd->sink_fmt;
-
- fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
- fmt->format.width = r->width;
- fmt->format.height = r->height;
- }
-
- return 0;
-}
-
-static int smiapp_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int rval;
-
- mutex_lock(&sensor->mutex);
- rval = __smiapp_get_format(subdev, fh, fmt);
- mutex_unlock(&sensor->mutex);
-
- return rval;
-}
-
-static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_rect **crops,
- struct v4l2_rect **comps, int which)
-{
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- unsigned int i;
-
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- if (crops)
- for (i = 0; i < subdev->entity.num_pads; i++)
- crops[i] = &ssd->crop[i];
- if (comps)
- *comps = &ssd->compose;
- } else {
- if (crops) {
- for (i = 0; i < subdev->entity.num_pads; i++) {
- crops[i] = v4l2_subdev_get_try_crop(fh, i);
- BUG_ON(!crops[i]);
- }
- }
- if (comps) {
- *comps = v4l2_subdev_get_try_compose(fh,
- SMIAPP_PAD_SINK);
- BUG_ON(!*comps);
- }
- }
-}
-
-/* Changes require propagation only on sink pad. */
-static void smiapp_propagate(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh, int which,
- int target)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *comp, *crops[SMIAPP_PADS];
-
- smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
-
- switch (target) {
- case V4L2_SEL_TGT_CROP:
- comp->width = crops[SMIAPP_PAD_SINK]->width;
- comp->height = crops[SMIAPP_PAD_SINK]->height;
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- if (ssd == sensor->scaler) {
- sensor->scale_m =
- sensor->limits[
- SMIAPP_LIMIT_SCALER_N_MIN];
- sensor->scaling_mode =
- SMIAPP_SCALING_MODE_NONE;
- } else if (ssd == sensor->binner) {
- sensor->binning_horizontal = 1;
- sensor->binning_vertical = 1;
- }
- }
- /* Fall through */
- case V4L2_SEL_TGT_COMPOSE:
- *crops[SMIAPP_PAD_SRC] = *comp;
- break;
- default:
- BUG();
- }
-}
-
-static const struct smiapp_csi_data_format
-*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
-{
- const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
- if (sensor->mbus_frame_fmts & (1 << i)
- && smiapp_csi_data_formats[i].code == code)
- return &smiapp_csi_data_formats[i];
- }
-
- return csi_format;
-}
-
-static int smiapp_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *crops[SMIAPP_PADS];
-
- mutex_lock(&sensor->mutex);
-
- /*
- * Media bus code is changeable on src subdev's source pad. On
- * other source pads we just get format here.
- */
- if (fmt->pad == ssd->source_pad) {
- u32 code = fmt->format.code;
- int rval = __smiapp_get_format(subdev, fh, fmt);
-
- if (!rval && subdev == &sensor->src->sd) {
- const struct smiapp_csi_data_format *csi_format =
- smiapp_validate_csi_data_format(sensor, code);
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- sensor->csi_format = csi_format;
- fmt->format.code = csi_format->code;
- }
-
- mutex_unlock(&sensor->mutex);
- return rval;
- }
-
- /* Sink pad. Width and height are changeable here. */
- fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
- fmt->format.width &= ~1;
- fmt->format.height &= ~1;
-
- fmt->format.width =
- clamp(fmt->format.width,
- sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
- sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
- fmt->format.height =
- clamp(fmt->format.height,
- sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
- sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
-
- smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
-
- crops[ssd->sink_pad]->left = 0;
- crops[ssd->sink_pad]->top = 0;
- crops[ssd->sink_pad]->width = fmt->format.width;
- crops[ssd->sink_pad]->height = fmt->format.height;
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- ssd->sink_fmt = *crops[ssd->sink_pad];
- smiapp_propagate(subdev, fh, fmt->which,
- V4L2_SEL_TGT_CROP);
-
- mutex_unlock(&sensor->mutex);
-
- return 0;
-}
-
-/*
- * Calculate goodness of scaled image size compared to expected image
- * size and flags provided.
- */
-#define SCALING_GOODNESS 100000
-#define SCALING_GOODNESS_EXTREME 100000000
-static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
- int h, int ask_h, u32 flags)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- int val = 0;
-
- w &= ~1;
- ask_w &= ~1;
- h &= ~1;
- ask_h &= ~1;
-
- if (flags & V4L2_SEL_FLAG_GE) {
- if (w < ask_w)
- val -= SCALING_GOODNESS;
- if (h < ask_h)
- val -= SCALING_GOODNESS;
- }
-
- if (flags & V4L2_SEL_FLAG_LE) {
- if (w > ask_w)
- val -= SCALING_GOODNESS;
- if (h > ask_h)
- val -= SCALING_GOODNESS;
- }
-
- val -= abs(w - ask_w);
- val -= abs(h - ask_h);
-
- if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
- val -= SCALING_GOODNESS_EXTREME;
-
- dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
- w, ask_h, h, ask_h, val);
-
- return val;
-}
-
-static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel,
- struct v4l2_rect **crops,
- struct v4l2_rect *comp)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- unsigned int i;
- unsigned int binh = 1, binv = 1;
- unsigned int best = scaling_goodness(
- subdev,
- crops[SMIAPP_PAD_SINK]->width, sel->r.width,
- crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
-
- for (i = 0; i < sensor->nbinning_subtypes; i++) {
- int this = scaling_goodness(
- subdev,
- crops[SMIAPP_PAD_SINK]->width
- / sensor->binning_subtypes[i].horizontal,
- sel->r.width,
- crops[SMIAPP_PAD_SINK]->height
- / sensor->binning_subtypes[i].vertical,
- sel->r.height, sel->flags);
-
- if (this > best) {
- binh = sensor->binning_subtypes[i].horizontal;
- binv = sensor->binning_subtypes[i].vertical;
- best = this;
- }
- }
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- sensor->binning_vertical = binv;
- sensor->binning_horizontal = binh;
- }
-
- sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
- sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
-}
-
-/*
- * Calculate best scaling ratio and mode for given output resolution.
- *
- * Try all of these: horizontal ratio, vertical ratio and smallest
- * size possible (horizontally).
- *
- * Also try whether horizontal scaler or full scaler gives a better
- * result.
- */
-static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel,
- struct v4l2_rect **crops,
- struct v4l2_rect *comp)
-{
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- u32 min, max, a, b, max_m;
- u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
- int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
- u32 try[4];
- u32 ntry = 0;
- unsigned int i;
- int best = INT_MIN;
-
- sel->r.width = min_t(unsigned int, sel->r.width,
- crops[SMIAPP_PAD_SINK]->width);
- sel->r.height = min_t(unsigned int, sel->r.height,
- crops[SMIAPP_PAD_SINK]->height);
-
- a = crops[SMIAPP_PAD_SINK]->width
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
- b = crops[SMIAPP_PAD_SINK]->height
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
- max_m = crops[SMIAPP_PAD_SINK]->width
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
- / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
-
- a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
- max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
- b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
- max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
- max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
- max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
-
- dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
-
- min = min(max_m, min(a, b));
- max = min(max_m, max(a, b));
-
- try[ntry] = min;
- ntry++;
- if (min != max) {
- try[ntry] = max;
- ntry++;
- }
- if (max != max_m) {
- try[ntry] = min + 1;
- ntry++;
- if (min != max) {
- try[ntry] = max + 1;
- ntry++;
- }
- }
-
- for (i = 0; i < ntry; i++) {
- int this = scaling_goodness(
- subdev,
- crops[SMIAPP_PAD_SINK]->width
- / try[i]
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
- sel->r.width,
- crops[SMIAPP_PAD_SINK]->height,
- sel->r.height,
- sel->flags);
-
- dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
-
- if (this > best) {
- scale_m = try[i];
- mode = SMIAPP_SCALING_MODE_HORIZONTAL;
- best = this;
- }
-
- if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
- continue;
-
- this = scaling_goodness(
- subdev, crops[SMIAPP_PAD_SINK]->width
- / try[i]
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
- sel->r.width,
- crops[SMIAPP_PAD_SINK]->height
- / try[i]
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
- sel->r.height,
- sel->flags);
-
- if (this > best) {
- scale_m = try[i];
- mode = SMIAPP_SCALING_MODE_BOTH;
- best = this;
- }
- }
-
- sel->r.width =
- (crops[SMIAPP_PAD_SINK]->width
- / scale_m
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
- if (mode == SMIAPP_SCALING_MODE_BOTH)
- sel->r.height =
- (crops[SMIAPP_PAD_SINK]->height
- / scale_m
- * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
- & ~1;
- else
- sel->r.height = crops[SMIAPP_PAD_SINK]->height;
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- sensor->scale_m = scale_m;
- sensor->scaling_mode = mode;
- }
-}
-/* We're only called on source pads. This function sets scaling. */
-static int smiapp_set_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *comp, *crops[SMIAPP_PADS];
-
- smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
-
- sel->r.top = 0;
- sel->r.left = 0;
-
- if (ssd == sensor->binner)
- smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
- else
- smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
-
- *comp = sel->r;
- smiapp_propagate(subdev, fh, sel->which,
- V4L2_SEL_TGT_COMPOSE);
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return smiapp_update_mode(sensor);
-
- return 0;
-}
-
-static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
-
- /* We only implement crop in three places. */
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP:
- case V4L2_SEL_TGT_CROP_BOUNDS:
- if (ssd == sensor->pixel_array
- && sel->pad == SMIAPP_PA_PAD_SRC)
- return 0;
- if (ssd == sensor->src
- && sel->pad == SMIAPP_PAD_SRC)
- return 0;
- if (ssd == sensor->scaler
- && sel->pad == SMIAPP_PAD_SINK
- && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
- == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
- return 0;
- return -EINVAL;
- case V4L2_SEL_TGT_COMPOSE:
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- if (sel->pad == ssd->source_pad)
- return -EINVAL;
- if (ssd == sensor->binner)
- return 0;
- if (ssd == sensor->scaler
- && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- != SMIAPP_SCALING_CAPABILITY_NONE)
- return 0;
- /* Fall through */
- default:
- return -EINVAL;
- }
-}
-
-static int smiapp_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
- struct v4l2_rect _r;
-
- smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- if (sel->pad == ssd->sink_pad)
- src_size = &ssd->sink_fmt;
- else
- src_size = &ssd->compose;
- } else {
- if (sel->pad == ssd->sink_pad) {
- _r.left = 0;
- _r.top = 0;
- _r.width = v4l2_subdev_get_try_format(fh, sel->pad)
- ->width;
- _r.height = v4l2_subdev_get_try_format(fh, sel->pad)
- ->height;
- src_size = &_r;
- } else {
- src_size =
- v4l2_subdev_get_try_compose(
- fh, ssd->sink_pad);
- }
- }
-
- if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
- sel->r.left = 0;
- sel->r.top = 0;
- }
-
- sel->r.width = min(sel->r.width, src_size->width);
- sel->r.height = min(sel->r.height, src_size->height);
-
- sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
- sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
-
- *crops[sel->pad] = sel->r;
-
- if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
- smiapp_propagate(subdev, fh, sel->which,
- V4L2_SEL_TGT_CROP);
-
- return 0;
-}
-
-static int __smiapp_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *comp, *crops[SMIAPP_PADS];
- struct v4l2_rect sink_fmt;
- int ret;
-
- ret = __smiapp_sel_supported(subdev, sel);
- if (ret)
- return ret;
-
- smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
-
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- sink_fmt = ssd->sink_fmt;
- } else {
- struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(fh, ssd->sink_pad);
-
- sink_fmt.left = 0;
- sink_fmt.top = 0;
- sink_fmt.width = fmt->width;
- sink_fmt.height = fmt->height;
- }
-
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP_BOUNDS:
- if (ssd == sensor->pixel_array) {
- sel->r.width =
- sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- sel->r.height =
- sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- } else if (sel->pad == ssd->sink_pad) {
- sel->r = sink_fmt;
- } else {
- sel->r = *comp;
- }
- break;
- case V4L2_SEL_TGT_CROP:
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- sel->r = *crops[sel->pad];
- break;
- case V4L2_SEL_TGT_COMPOSE:
- sel->r = *comp;
- break;
- }
-
- return 0;
-}
-
-static int smiapp_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int rval;
-
- mutex_lock(&sensor->mutex);
- rval = __smiapp_get_selection(subdev, fh, sel);
- mutex_unlock(&sensor->mutex);
-
- return rval;
-}
-static int smiapp_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_selection *sel)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int ret;
-
- ret = __smiapp_sel_supported(subdev, sel);
- if (ret)
- return ret;
-
- mutex_lock(&sensor->mutex);
-
- sel->r.left = max(0, sel->r.left & ~1);
- sel->r.top = max(0, sel->r.top & ~1);
- sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
- sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
-
- sel->r.width = max_t(unsigned int,
- sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
- sel->r.width);
- sel->r.height = max_t(unsigned int,
- sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
- sel->r.height);
-
- switch (sel->target) {
- case V4L2_SEL_TGT_CROP:
- ret = smiapp_set_crop(subdev, fh, sel);
- break;
- case V4L2_SEL_TGT_COMPOSE:
- ret = smiapp_set_compose(subdev, fh, sel);
- break;
- default:
- BUG();
- }
-
- mutex_unlock(&sensor->mutex);
- return ret;
-}
-
-static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
-
- *frames = sensor->frame_skip;
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * sysfs attributes
- */
-
-static ssize_t
-smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- unsigned int nbytes;
-
- if (!sensor->dev_init_done)
- return -EBUSY;
-
- if (!sensor->nvm_size) {
- /* NVM not read yet - read it now */
- sensor->nvm_size = sensor->platform_data->nvm_size;
- if (smiapp_set_power(subdev, 1) < 0)
- return -ENODEV;
- if (smiapp_read_nvm(sensor, sensor->nvm)) {
- dev_err(&client->dev, "nvm read failed\n");
- return -ENODEV;
- }
- smiapp_set_power(subdev, 0);
- }
- /*
- * NVM is still way below a PAGE_SIZE, so we can safely
- * assume this for now.
- */
- nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
- memcpy(buf, sensor->nvm, nbytes);
-
- return nbytes;
-}
-static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev core operations
- */
-
-static int smiapp_identify_module(struct v4l2_subdev *subdev)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct smiapp_module_info *minfo = &sensor->minfo;
- unsigned int i;
- int rval = 0;
-
- minfo->name = SMIAPP_NAME;
-
- /* Module info */
- rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
- &minfo->manufacturer_id);
- if (!rval)
- rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID,
- &minfo->model_id);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
- &minfo->revision_number_major);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
- &minfo->revision_number_minor);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_MODULE_DATE_YEAR,
- &minfo->module_year);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_MODULE_DATE_MONTH,
- &minfo->module_month);
- if (!rval)
- rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY,
- &minfo->module_day);
-
- /* Sensor info */
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
- &minfo->sensor_manufacturer_id);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U16_SENSOR_MODEL_ID,
- &minfo->sensor_model_id);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
- &minfo->sensor_revision_number);
- if (!rval)
- rval = smiapp_read_8only(sensor,
- SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
- &minfo->sensor_firmware_version);
-
- /* SMIA */
- if (!rval)
- rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
- &minfo->smia_version);
- if (!rval)
- rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
- &minfo->smiapp_version);
-
- if (rval) {
- dev_err(&client->dev, "sensor detection failed\n");
- return -ENODEV;
- }
-
- dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
- minfo->manufacturer_id, minfo->model_id);
-
- dev_dbg(&client->dev,
- "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
- minfo->revision_number_major, minfo->revision_number_minor,
- minfo->module_year, minfo->module_month, minfo->module_day);
-
- dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
- minfo->sensor_manufacturer_id, minfo->sensor_model_id);
-
- dev_dbg(&client->dev,
- "sensor revision 0x%2.2x firmware version 0x%2.2x\n",
- minfo->sensor_revision_number, minfo->sensor_firmware_version);
-
- dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
- minfo->smia_version, minfo->smiapp_version);
-
- /*
- * Some modules have bad data in the lvalues below. Hope the
- * rvalues have better stuff. The lvalues are module
- * parameters whereas the rvalues are sensor parameters.
- */
- if (!minfo->manufacturer_id && !minfo->model_id) {
- minfo->manufacturer_id = minfo->sensor_manufacturer_id;
- minfo->model_id = minfo->sensor_model_id;
- minfo->revision_number_major = minfo->sensor_revision_number;
- }
-
- for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
- if (smiapp_module_idents[i].manufacturer_id
- != minfo->manufacturer_id)
- continue;
- if (smiapp_module_idents[i].model_id != minfo->model_id)
- continue;
- if (smiapp_module_idents[i].flags
- & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
- if (smiapp_module_idents[i].revision_number_major
- < minfo->revision_number_major)
- continue;
- } else {
- if (smiapp_module_idents[i].revision_number_major
- != minfo->revision_number_major)
- continue;
- }
-
- minfo->name = smiapp_module_idents[i].name;
- minfo->quirk = smiapp_module_idents[i].quirk;
- break;
- }
-
- if (i >= ARRAY_SIZE(smiapp_module_idents))
- dev_warn(&client->dev,
- "no quirks for this module; let's hope it's fully compliant\n");
-
- dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
- minfo->name, minfo->manufacturer_id, minfo->model_id,
- minfo->revision_number_major);
-
- strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
-
- return 0;
-}
-
-static const struct v4l2_subdev_ops smiapp_ops;
-static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
-static const struct media_entity_operations smiapp_entity_ops;
-
-static int smiapp_registered(struct v4l2_subdev *subdev)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- struct smiapp_subdev *last = NULL;
- u32 tmp;
- unsigned int i;
- int rval;
-
- sensor->vana = regulator_get(&client->dev, "VANA");
- if (IS_ERR(sensor->vana)) {
- dev_err(&client->dev, "could not get regulator for vana\n");
- return -ENODEV;
- }
-
- if (!sensor->platform_data->set_xclk) {
- sensor->ext_clk = clk_get(&client->dev,
- sensor->platform_data->ext_clk_name);
- if (IS_ERR(sensor->ext_clk)) {
- dev_err(&client->dev, "could not get clock %s\n",
- sensor->platform_data->ext_clk_name);
- rval = -ENODEV;
- goto out_clk_get;
- }
-
- rval = clk_set_rate(sensor->ext_clk,
- sensor->platform_data->ext_clk);
- if (rval < 0) {
- dev_err(&client->dev,
- "unable to set clock %s freq to %u\n",
- sensor->platform_data->ext_clk_name,
- sensor->platform_data->ext_clk);
- rval = -ENODEV;
- goto out_clk_set_rate;
- }
- }
-
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
- if (gpio_request_one(sensor->platform_data->xshutdown, 0,
- "SMIA++ xshutdown") != 0) {
- dev_err(&client->dev,
- "unable to acquire reset gpio %d\n",
- sensor->platform_data->xshutdown);
- rval = -ENODEV;
- goto out_clk_set_rate;
- }
- }
-
- rval = smiapp_power_on(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_smiapp_power_on;
- }
-
- rval = smiapp_identify_module(subdev);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
- rval = smiapp_get_all_limits(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
- /*
- * Handle Sensor Module orientation on the board.
- *
- * The application of H-FLIP and V-FLIP on the sensor is modified by
- * the sensor orientation on the board.
- *
- * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
- * both H-FLIP and V-FLIP for normal operation which also implies
- * that a set/unset operation for user space HFLIP and VFLIP v4l2
- * controls will need to be internally inverted.
- *
- * Rotation also changes the bayer pattern.
- */
- if (sensor->platform_data->module_board_orient ==
- SMIAPP_MODULE_BOARD_ORIENT_180)
- sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
- SMIAPP_IMAGE_ORIENTATION_VFLIP;
-
- rval = smiapp_get_mbus_formats(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
- if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
- u32 val;
-
- rval = smiapp_read(sensor,
- SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
- if (rval < 0) {
- rval = -ENODEV;
- goto out_power_off;
- }
- sensor->nbinning_subtypes = min_t(u8, val,
- SMIAPP_BINNING_SUBTYPES);
-
- for (i = 0; i < sensor->nbinning_subtypes; i++) {
- rval = smiapp_read(
- sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
- if (rval < 0) {
- rval = -ENODEV;
- goto out_power_off;
- }
- sensor->binning_subtypes[i] =
- *(struct smiapp_binning_subtype *)&val;
-
- dev_dbg(&client->dev, "binning %xx%x\n",
- sensor->binning_subtypes[i].horizontal,
- sensor->binning_subtypes[i].vertical);
- }
- }
- sensor->binning_horizontal = 1;
- sensor->binning_vertical = 1;
-
- /* SMIA++ NVM initialization - it will be read from the sensor
- * when it is first requested by userspace.
- */
- if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
- sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
- GFP_KERNEL);
- if (sensor->nvm == NULL) {
- dev_err(&client->dev, "nvm buf allocation failed\n");
- rval = -ENOMEM;
- goto out_power_off;
- }
-
- if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
- dev_err(&client->dev, "sysfs nvm entry failed\n");
- rval = -EBUSY;
- goto out_power_off;
- }
- }
-
- rval = smiapp_call_quirk(sensor, limits);
- if (rval) {
- dev_err(&client->dev, "limits quirks failed\n");
- goto out_nvm_release;
- }
-
- /* We consider this as profile 0 sensor if any of these are zero. */
- if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
- } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- != SMIAPP_SCALING_CAPABILITY_NONE) {
- if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
- else
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
- sensor->scaler = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
- == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
- sensor->scaler = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- }
- sensor->binner = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
-
- sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
-
- for (i = 0; i < SMIAPP_SUBDEVS; i++) {
- struct {
- struct smiapp_subdev *ssd;
- char *name;
- } const __this[] = {
- { sensor->scaler, "scaler", },
- { sensor->binner, "binner", },
- { sensor->pixel_array, "pixel array", },
- }, *_this = &__this[i];
- struct smiapp_subdev *this = _this->ssd;
-
- if (!this)
- continue;
-
- if (this != sensor->src)
- v4l2_subdev_init(&this->sd, &smiapp_ops);
-
- this->sensor = sensor;
-
- if (this == sensor->pixel_array) {
- this->npads = 1;
- } else {
- this->npads = 2;
- this->source_pad = 1;
- }
-
- snprintf(this->sd.name,
- sizeof(this->sd.name), "%s %s",
- sensor->minfo.name, _this->name);
-
- this->sink_fmt.width =
- sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- this->sink_fmt.height =
- sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- this->compose.width = this->sink_fmt.width;
- this->compose.height = this->sink_fmt.height;
- this->crop[this->source_pad] = this->compose;
- this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
- if (this != sensor->pixel_array) {
- this->crop[this->sink_pad] = this->compose;
- this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
- }
-
- this->sd.entity.ops = &smiapp_entity_ops;
-
- if (last == NULL) {
- last = this;
- continue;
- }
-
- this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- this->sd.internal_ops = &smiapp_internal_ops;
- this->sd.owner = NULL;
- v4l2_set_subdevdata(&this->sd, client);
-
- rval = media_entity_init(&this->sd.entity,
- this->npads, this->pads, 0);
- if (rval) {
- dev_err(&client->dev,
- "media_entity_init failed\n");
- goto out_nvm_release;
- }
-
- rval = media_entity_create_link(&this->sd.entity,
- this->source_pad,
- &last->sd.entity,
- last->sink_pad,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (rval) {
- dev_err(&client->dev,
- "media_entity_create_link failed\n");
- goto out_nvm_release;
- }
-
- rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
- &this->sd);
- if (rval) {
- dev_err(&client->dev,
- "v4l2_device_register_subdev failed\n");
- goto out_nvm_release;
- }
-
- last = this;
- }
-
- dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
-
- sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
-
- /* final steps */
- smiapp_read_frame_fmt(sensor);
- rval = smiapp_init_controls(sensor);
- if (rval < 0)
- goto out_nvm_release;
-
- rval = smiapp_update_mode(sensor);
- if (rval) {
- dev_err(&client->dev, "update mode failed\n");
- goto out_nvm_release;
- }
-
- sensor->streaming = false;
- sensor->dev_init_done = true;
-
- /* check flash capability */
- rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
- sensor->flash_capability = tmp;
- if (rval)
- goto out_nvm_release;
-
- smiapp_power_off(sensor);
-
- return 0;
-
-out_nvm_release:
- device_remove_file(&client->dev, &dev_attr_nvm);
-
-out_power_off:
- kfree(sensor->nvm);
- sensor->nvm = NULL;
- smiapp_power_off(sensor);
-
-out_smiapp_power_on:
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_free(sensor->platform_data->xshutdown);
-
-out_clk_set_rate:
- clk_put(sensor->ext_clk);
- sensor->ext_clk = NULL;
-
-out_clk_get:
- regulator_put(sensor->vana);
- sensor->vana = NULL;
- return rval;
-}
-
-static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
- struct smiapp_sensor *sensor = ssd->sensor;
- u32 mbus_code =
- smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
- unsigned int i;
-
- mutex_lock(&sensor->mutex);
-
- for (i = 0; i < ssd->npads; i++) {
- struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(fh, i);
- struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
- struct v4l2_rect *try_comp;
-
- try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- try_fmt->code = mbus_code;
-
- try_crop->top = 0;
- try_crop->left = 0;
- try_crop->width = try_fmt->width;
- try_crop->height = try_fmt->height;
-
- if (ssd != sensor->pixel_array)
- continue;
-
- try_comp = v4l2_subdev_get_try_compose(fh, i);
- *try_comp = *try_crop;
- }
-
- mutex_unlock(&sensor->mutex);
-
- return smiapp_set_power(sd, 1);
-}
-
-static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- return smiapp_set_power(sd, 0);
-}
-
-static const struct v4l2_subdev_video_ops smiapp_video_ops = {
- .s_stream = smiapp_set_stream,
-};
-
-static const struct v4l2_subdev_core_ops smiapp_core_ops = {
- .s_power = smiapp_set_power,
-};
-
-static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
- .enum_mbus_code = smiapp_enum_mbus_code,
- .get_fmt = smiapp_get_format,
- .set_fmt = smiapp_set_format,
- .get_selection = smiapp_get_selection,
- .set_selection = smiapp_set_selection,
-};
-
-static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
- .g_skip_frames = smiapp_get_skip_frames,
-};
-
-static const struct v4l2_subdev_ops smiapp_ops = {
- .core = &smiapp_core_ops,
- .video = &smiapp_video_ops,
- .pad = &smiapp_pad_ops,
- .sensor = &smiapp_sensor_ops,
-};
-
-static const struct media_entity_operations smiapp_entity_ops = {
- .link_validate = v4l2_subdev_link_validate,
-};
-
-static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
- .registered = smiapp_registered,
- .open = smiapp_open,
- .close = smiapp_close,
-};
-
-static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
- .open = smiapp_open,
- .close = smiapp_close,
-};
-
-/* -----------------------------------------------------------------------------
- * I2C Driver
- */
-
-#ifdef CONFIG_PM
-
-static int smiapp_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- bool streaming;
-
- BUG_ON(mutex_is_locked(&sensor->mutex));
-
- if (sensor->power_count == 0)
- return 0;
-
- if (sensor->streaming)
- smiapp_stop_streaming(sensor);
-
- streaming = sensor->streaming;
-
- smiapp_power_off(sensor);
-
- /* save state for resume */
- sensor->streaming = streaming;
-
- return 0;
-}
-
-static int smiapp_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int rval;
-
- if (sensor->power_count == 0)
- return 0;
-
- rval = smiapp_power_on(sensor);
- if (rval)
- return rval;
-
- if (sensor->streaming)
- rval = smiapp_start_streaming(sensor);
-
- return rval;
-}
-
-#else
-
-#define smiapp_suspend NULL
-#define smiapp_resume NULL
-
-#endif /* CONFIG_PM */
-
-static int smiapp_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
-{
- struct smiapp_sensor *sensor;
- int rval;
-
- if (client->dev.platform_data == NULL)
- return -ENODEV;
-
- sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
- if (sensor == NULL)
- return -ENOMEM;
-
- sensor->platform_data = client->dev.platform_data;
- mutex_init(&sensor->mutex);
- mutex_init(&sensor->power_mutex);
- sensor->src = &sensor->ssds[sensor->ssds_used];
-
- v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
- sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
- sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- sensor->src->sensor = sensor;
-
- sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
- rval = media_entity_init(&sensor->src->sd.entity, 2,
- sensor->src->pads, 0);
- if (rval < 0)
- kfree(sensor);
-
- return rval;
-}
-
-static int __exit smiapp_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *subdev = i2c_get_clientdata(client);
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- unsigned int i;
-
- if (sensor->power_count) {
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_set_value(sensor->platform_data->xshutdown, 0);
- if (sensor->platform_data->set_xclk)
- sensor->platform_data->set_xclk(&sensor->src->sd, 0);
- else
- clk_disable(sensor->ext_clk);
- sensor->power_count = 0;
- }
-
- if (sensor->nvm) {
- device_remove_file(&client->dev, &dev_attr_nvm);
- kfree(sensor->nvm);
- }
-
- for (i = 0; i < sensor->ssds_used; i++) {
- media_entity_cleanup(&sensor->ssds[i].sd.entity);
- v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
- }
- smiapp_free_controls(sensor);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
- gpio_free(sensor->platform_data->xshutdown);
- if (sensor->ext_clk)
- clk_put(sensor->ext_clk);
- if (sensor->vana)
- regulator_put(sensor->vana);
-
- kfree(sensor);
-
- return 0;
-}
-
-static const struct i2c_device_id smiapp_id_table[] = {
- { SMIAPP_NAME, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
-
-static const struct dev_pm_ops smiapp_pm_ops = {
- .suspend = smiapp_suspend,
- .resume = smiapp_resume,
-};
-
-static struct i2c_driver smiapp_i2c_driver = {
- .driver = {
- .name = SMIAPP_NAME,
- .pm = &smiapp_pm_ops,
- },
- .probe = smiapp_probe,
- .remove = __exit_p(smiapp_remove),
- .id_table = smiapp_id_table,
-};
-
-module_i2c_driver(smiapp_i2c_driver);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
-MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp/smiapp-limits.c b/drivers/media/video/smiapp/smiapp-limits.c
deleted file mode 100644
index 0800e095724e..000000000000
--- a/drivers/media/video/smiapp/smiapp-limits.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-limits.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 "smiapp.h"
-
-struct smiapp_reg_limits smiapp_reg_limits[] = {
- { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
- { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
- { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
- { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
- { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
- { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
- { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
- { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
- { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
- { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
- { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
- { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
- { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
- { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
- { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
- { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
- { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
- { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
- { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
- { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
- { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
- { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
- { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
- { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
- { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
- { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
- { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
- { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
- { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
- { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
- { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
- { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
- { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
- { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
- { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
- { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
- { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
- { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
- { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
- { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
- { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
- { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
- { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
- { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
- { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
- { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
- { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
- { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
- { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
- { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
- { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
- { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
- { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
- { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
- { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
- { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
- { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
- { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
- { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
- { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
- { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
- { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
- { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
- { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
- { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
- { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
- { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
- { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
- { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
- { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
- { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
- { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
- { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
- { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
- { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
- { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
- { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
- { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
- { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
- { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
- { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
- { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
- { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
- { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
- { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
- { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
- { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
- { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
- { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
- { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
- { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
- { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
- { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
- { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
- { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
- { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
- { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
- { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
- { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
- { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
- { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
- { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
- { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
- { 0, NULL },
-};
diff --git a/drivers/media/video/smiapp/smiapp-limits.h b/drivers/media/video/smiapp/smiapp-limits.h
deleted file mode 100644
index 7f4836bb78db..000000000000
--- a/drivers/media/video/smiapp/smiapp-limits.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-limits.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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
- *
- */
-
-#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0
-#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN 1
-#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX 2
-#define SMIAPP_LIMIT_THS_ZERO_MIN 3
-#define SMIAPP_LIMIT_TCLK_TRAIL_MIN 4
-#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY 5
-#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN 6
-#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN 7
-#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN 8
-#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN 9
-#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY 10
-#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN 11
-#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX 12
-#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ 13
-#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ 14
-#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV 15
-#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV 16
-#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ 17
-#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ 18
-#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER 19
-#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER 20
-#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ 21
-#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ 22
-#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV 23
-#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV 24
-#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ 25
-#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ 26
-#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ 27
-#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ 28
-#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV 29
-#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV 30
-#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES 31
-#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES 32
-#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK 33
-#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK 34
-#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK 35
-#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES 36
-#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE 37
-#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV 38
-#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV 39
-#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ 40
-#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ 41
-#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV 42
-#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV 43
-#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ 44
-#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ 45
-#define SMIAPP_LIMIT_X_ADDR_MIN 46
-#define SMIAPP_LIMIT_Y_ADDR_MIN 47
-#define SMIAPP_LIMIT_X_ADDR_MAX 48
-#define SMIAPP_LIMIT_Y_ADDR_MAX 49
-#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE 50
-#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE 51
-#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE 52
-#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE 53
-#define SMIAPP_LIMIT_MIN_EVEN_INC 54
-#define SMIAPP_LIMIT_MAX_EVEN_INC 55
-#define SMIAPP_LIMIT_MIN_ODD_INC 56
-#define SMIAPP_LIMIT_MAX_ODD_INC 57
-#define SMIAPP_LIMIT_SCALING_CAPABILITY 58
-#define SMIAPP_LIMIT_SCALER_M_MIN 59
-#define SMIAPP_LIMIT_SCALER_M_MAX 60
-#define SMIAPP_LIMIT_SCALER_N_MIN 61
-#define SMIAPP_LIMIT_SCALER_N_MAX 62
-#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY 63
-#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY 64
-#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY 65
-#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY 66
-#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY 67
-#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY 68
-#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY 69
-#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY 70
-#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY 71
-#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS 72
-#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS 73
-#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS 74
-#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS 75
-#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY 76
-#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN 77
-#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN 78
-#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN 79
-#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN 80
-#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN 81
-#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN 82
-#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 83
-#define SMIAPP_LIMIT_BINNING_CAPABILITY 84
-#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY 85
-#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY 86
-#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY 87
-#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY 88
-#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY 89
-#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY 90
-#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY 91
-#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2 92
-#define SMIAPP_LIMIT_EDOF_CAPABILITY 93
-#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY 94
-#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY 95
-#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY 96
-#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN 97
-#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY 98
-#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY 99
-#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1 100
-#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2 101
-#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP 102
-#define SMIAPP_LIMIT_LAST 103
diff --git a/drivers/media/video/smiapp/smiapp-quirk.c b/drivers/media/video/smiapp/smiapp-quirk.c
deleted file mode 100644
index 55e87950dcea..000000000000
--- a/drivers/media/video/smiapp/smiapp-quirk.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-quirk.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/delay.h>
-
-#include "smiapp.h"
-
-static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
-{
- return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
-}
-
-static int smiapp_write_8s(struct smiapp_sensor *sensor,
- struct smiapp_reg_8 *regs, int len)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int rval;
-
- for (; len > 0; len--, regs++) {
- rval = smiapp_write_8(sensor, regs->reg, regs->val);
- if (rval < 0) {
- dev_err(&client->dev,
- "error %d writing reg 0x%4.4x, val 0x%2.2x",
- rval, regs->reg, regs->val);
- return rval;
- }
- }
-
- return 0;
-}
-
-void smiapp_replace_limit(struct smiapp_sensor *sensor,
- u32 limit, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-
- dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
- smiapp_reg_limits[limit].addr,
- smiapp_reg_limits[limit].what, val, val);
- sensor->limits[limit] = val;
-}
-
-int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
- u32 reg, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int i;
-
- for (i = 0; smiapp_reg_limits[i].addr; i++) {
- if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
- continue;
-
- smiapp_replace_limit(sensor, i, val);
-
- return 0;
- }
-
- dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
-
- return -EINVAL;
-}
-
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- const struct smia_reg *sreg;
-
- if (!sensor->minfo.quirk)
- return false;
-
- sreg = sensor->minfo.quirk->regs;
-
- if (!sreg)
- return false;
-
- while (sreg->type) {
- u16 type = reg >> 16;
- u16 reg16 = reg;
-
- if (sreg->type != type || sreg->reg != reg16) {
- sreg++;
- continue;
- }
-
- switch ((u8)type) {
- case SMIA_REG_8BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_16BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_32BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
- reg, sreg->val);
- break;
- }
-
- *val = sreg->val;
-
- return true;
- }
-
- return false;
-}
-
-static int jt8ew9_limits(struct smiapp_sensor *sensor)
-{
- if (sensor->minfo.revision_number_major < 0x03)
- sensor->frame_skip = 1;
-
- /* Below 24 gain doesn't have effect at all, */
- /* but ~59 is needed for full dynamic range */
- smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
- smiapp_replace_limit(
- sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
-
- return 0;
-}
-
-static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
-{
- struct smiapp_reg_8 regs[] = {
- { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
- { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
- { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
- { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
- { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
- { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
- { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
- { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
- { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
- { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
- { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
- { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
- { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
- { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
- { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
- { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
- { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
- { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
- /* Taken from v03. No idea what the rest are. */
- { 0x32e0, 0x05 },
- { 0x32e1, 0x05 },
- { 0x32e2, 0x04 },
- { 0x32e5, 0x04 },
- { 0x32e6, 0x04 },
-
- };
-
- return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
-}
-
-const struct smiapp_quirk smiapp_jt8ew9_quirk = {
- .limits = jt8ew9_limits,
- .post_poweron = jt8ew9_post_poweron,
-};
-
-static int imx125es_post_poweron(struct smiapp_sensor *sensor)
-{
- /* Taken from v02. No idea what the other two are. */
- struct smiapp_reg_8 regs[] = {
- /*
- * 0x3302: clk during frame blanking:
- * 0x00 - HS mode, 0x01 - LP11
- */
- { 0x3302, 0x01 },
- { 0x302d, 0x00 },
- { 0x3b08, 0x8c },
- };
-
- return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
-}
-
-const struct smiapp_quirk smiapp_imx125es_quirk = {
- .post_poweron = imx125es_post_poweron,
-};
-
-static int jt8ev1_limits(struct smiapp_sensor *sensor)
-{
- smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
- smiapp_replace_limit(sensor,
- SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
-
- return 0;
-}
-
-static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- int rval;
-
- struct smiapp_reg_8 regs[] = {
- { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
- { 0x30a3, 0xd0 }, /* FLASH STROBE enable */
- { 0x3237, 0x00 }, /* For control of pulse timing for ADC */
- { 0x3238, 0x43 },
- { 0x3301, 0x06 }, /* For analog bias for sensor */
- { 0x3302, 0x06 },
- { 0x3304, 0x00 },
- { 0x3305, 0x88 },
- { 0x332a, 0x14 },
- { 0x332c, 0x6b },
- { 0x3336, 0x01 },
- { 0x333f, 0x1f },
- { 0x3355, 0x00 },
- { 0x3356, 0x20 },
- { 0x33bf, 0x20 }, /* Adjust the FBC speed */
- { 0x33c9, 0x20 },
- { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
- { 0x33cf, 0xec }, /* For Black sun */
- { 0x3328, 0x80 }, /* Ugh. No idea what's this. */
- };
-
- struct smiapp_reg_8 regs_96[] = {
- { 0x30ae, 0x00 }, /* For control of ADC clock */
- { 0x30af, 0xd0 },
- { 0x30b0, 0x01 },
- };
-
- rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
- if (rval < 0)
- return rval;
-
- switch (sensor->platform_data->ext_clk) {
- case 9600000:
- return smiapp_write_8s(sensor, regs_96,
- ARRAY_SIZE(regs_96));
- default:
- dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
- sensor->platform_data->ext_clk);
- return 0;
- }
-}
-
-static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
-{
- return smiapp_write_8(sensor, 0x3328, 0x00);
-}
-
-static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
-{
- int rval;
-
- /* Workaround: allows fast standby to work properly */
- rval = smiapp_write_8(sensor, 0x3205, 0x04);
- if (rval < 0)
- return rval;
-
- /* Wait for 1 ms + one line => 2 ms is likely enough */
- usleep_range(2000, 2000);
-
- /* Restore it */
- rval = smiapp_write_8(sensor, 0x3205, 0x00);
- if (rval < 0)
- return rval;
-
- return smiapp_write_8(sensor, 0x3328, 0x80);
-}
-
-const struct smiapp_quirk smiapp_jt8ev1_quirk = {
- .limits = jt8ev1_limits,
- .post_poweron = jt8ev1_post_poweron,
- .pre_streamon = jt8ev1_pre_streamon,
- .post_streamoff = jt8ev1_post_streamoff,
- .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
-};
-
-static int tcm8500md_limits(struct smiapp_sensor *sensor)
-{
- smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
-
- return 0;
-}
-
-const struct smiapp_quirk smiapp_tcm8500md_quirk = {
- .limits = tcm8500md_limits,
-};
diff --git a/drivers/media/video/smiapp/smiapp-quirk.h b/drivers/media/video/smiapp/smiapp-quirk.h
deleted file mode 100644
index f4dcaabaefe7..000000000000
--- a/drivers/media/video/smiapp/smiapp-quirk.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-quirk.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_QUIRK__
-#define __SMIAPP_QUIRK__
-
-struct smiapp_sensor;
-
-/**
- * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
- *
- * @limits: Replace sensor->limits with values which can't be read from
- * sensor registers. Called the first time the sensor is powered up.
- * @post_poweron: Called always after the sensor has been fully powered on.
- * @pre_streamon: Called just before streaming is enabled.
- * @post_streamon: Called right after stopping streaming.
- */
-struct smiapp_quirk {
- int (*limits)(struct smiapp_sensor *sensor);
- int (*post_poweron)(struct smiapp_sensor *sensor);
- int (*pre_streamon)(struct smiapp_sensor *sensor);
- int (*post_streamoff)(struct smiapp_sensor *sensor);
- const struct smia_reg *regs;
- unsigned long flags;
-};
-
-/* op pix clock is for all lanes in total normally */
-#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
-#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 1)
-
-struct smiapp_reg_8 {
- u16 reg;
- u8 val;
-};
-
-void smiapp_replace_limit(struct smiapp_sensor *sensor,
- u32 limit, u32 val);
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val);
-
-#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
- { \
- .type = (_reg >> 16), \
- .reg = (u16)_reg, \
- .val = _val, \
- }
-
-#define smiapp_call_quirk(_sensor, _quirk, ...) \
- (_sensor->minfo.quirk && \
- _sensor->minfo.quirk->_quirk ? \
- _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
-
-#define smiapp_needs_quirk(_sensor, _quirk) \
- (_sensor->minfo.quirk ? \
- _sensor->minfo.quirk->flags & _quirk : 0)
-
-extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
-extern const struct smiapp_quirk smiapp_imx125es_quirk;
-extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
-extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
-
-#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/video/smiapp/smiapp-reg-defs.h b/drivers/media/video/smiapp/smiapp-reg-defs.h
deleted file mode 100644
index a089eb8161e1..000000000000
--- a/drivers/media/video/smiapp/smiapp-reg-defs.h
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-reg-defs.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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
- *
- */
-#define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r))
-#define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r))
-#define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r))
-
-#define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r))
-
-#define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000)
-#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002)
-#define SMIAPP_REG_U8_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0003)
-#define SMIAPP_REG_U8_SMIA_VERSION SMIAPP_REG_MK_U8(0x0004)
-#define SMIAPP_REG_U8_FRAME_COUNT SMIAPP_REG_MK_U8(0x0005)
-#define SMIAPP_REG_U8_PIXEL_ORDER SMIAPP_REG_MK_U8(0x0006)
-#define SMIAPP_REG_U16_DATA_PEDESTAL SMIAPP_REG_MK_U16(0x0008)
-#define SMIAPP_REG_U8_PIXEL_DEPTH SMIAPP_REG_MK_U8(0x000c)
-#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR SMIAPP_REG_MK_U8(0x0010)
-#define SMIAPP_REG_U8_SMIAPP_VERSION SMIAPP_REG_MK_U8(0x0011)
-#define SMIAPP_REG_U8_MODULE_DATE_YEAR SMIAPP_REG_MK_U8(0x0012)
-#define SMIAPP_REG_U8_MODULE_DATE_MONTH SMIAPP_REG_MK_U8(0x0013)
-#define SMIAPP_REG_U8_MODULE_DATE_DAY SMIAPP_REG_MK_U8(0x0014)
-#define SMIAPP_REG_U8_MODULE_DATE_PHASE SMIAPP_REG_MK_U8(0x0015)
-#define SMIAPP_REG_U16_SENSOR_MODEL_ID SMIAPP_REG_MK_U16(0x0016)
-#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER SMIAPP_REG_MK_U8(0x0018)
-#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0019)
-#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION SMIAPP_REG_MK_U8(0x001a)
-#define SMIAPP_REG_U32_SERIAL_NUMBER SMIAPP_REG_MK_U32(0x001c)
-#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x0040)
-#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x0041)
-#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
-#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x0080)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN SMIAPP_REG_MK_U16(0x0084)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX SMIAPP_REG_MK_U16(0x0086)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP SMIAPP_REG_MK_U16(0x0088)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE SMIAPP_REG_MK_U16(0x008a)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 SMIAPP_REG_MK_U16(0x008c)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 SMIAPP_REG_MK_U16(0x008e)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 SMIAPP_REG_MK_U16(0x0090)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 SMIAPP_REG_MK_U16(0x0092)
-#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x00c0)
-#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x00c1)
-#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1))
-#define SMIAPP_REG_U8_MODE_SELECT SMIAPP_REG_MK_U8(0x0100)
-#define SMIAPP_REG_U8_IMAGE_ORIENTATION SMIAPP_REG_MK_U8(0x0101)
-#define SMIAPP_REG_U8_SOFTWARE_RESET SMIAPP_REG_MK_U8(0x0103)
-#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD SMIAPP_REG_MK_U8(0x0104)
-#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES SMIAPP_REG_MK_U8(0x0105)
-#define SMIAPP_REG_U8_FAST_STANDBY_CTRL SMIAPP_REG_MK_U8(0x0106)
-#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0107)
-#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL SMIAPP_REG_MK_U8(0x0108)
-#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0109)
-#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER SMIAPP_REG_MK_U8(0x0110)
-#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE SMIAPP_REG_MK_U8(0x0111)
-#define SMIAPP_REG_U16_CSI_DATA_FORMAT SMIAPP_REG_MK_U16(0x0112)
-#define SMIAPP_REG_U8_CSI_LANE_MODE SMIAPP_REG_MK_U8(0x0114)
-#define SMIAPP_REG_U8_CSI2_10_TO_8_DT SMIAPP_REG_MK_U8(0x0115)
-#define SMIAPP_REG_U8_CSI2_10_TO_7_DT SMIAPP_REG_MK_U8(0x0116)
-#define SMIAPP_REG_U8_CSI2_10_TO_6_DT SMIAPP_REG_MK_U8(0x0117)
-#define SMIAPP_REG_U8_CSI2_12_TO_8_DT SMIAPP_REG_MK_U8(0x0118)
-#define SMIAPP_REG_U8_CSI2_12_TO_7_DT SMIAPP_REG_MK_U8(0x0119)
-#define SMIAPP_REG_U8_CSI2_12_TO_6_DT SMIAPP_REG_MK_U8(0x011a)
-#define SMIAPP_REG_U8_CSI2_14_TO_10_DT SMIAPP_REG_MK_U8(0x011b)
-#define SMIAPP_REG_U8_CSI2_14_TO_8_DT SMIAPP_REG_MK_U8(0x011c)
-#define SMIAPP_REG_U8_CSI2_16_TO_10_DT SMIAPP_REG_MK_U8(0x011d)
-#define SMIAPP_REG_U8_CSI2_16_TO_8_DT SMIAPP_REG_MK_U8(0x011e)
-#define SMIAPP_REG_U8_GAIN_MODE SMIAPP_REG_MK_U8(0x0120)
-#define SMIAPP_REG_U16_VANA_VOLTAGE SMIAPP_REG_MK_U16(0x0130)
-#define SMIAPP_REG_U16_VDIG_VOLTAGE SMIAPP_REG_MK_U16(0x0132)
-#define SMIAPP_REG_U16_VIO_VOLTAGE SMIAPP_REG_MK_U16(0x0134)
-#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ SMIAPP_REG_MK_U16(0x0136)
-#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL SMIAPP_REG_MK_U8(0x0138)
-#define SMIAPP_REG_U8_TEMP_SENSOR_MODE SMIAPP_REG_MK_U8(0x0139)
-#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT SMIAPP_REG_MK_U8(0x013a)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0200)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0202)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL SMIAPP_REG_MK_U16(0x0204)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR SMIAPP_REG_MK_U16(0x0206)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED SMIAPP_REG_MK_U16(0x0208)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE SMIAPP_REG_MK_U16(0x020a)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB SMIAPP_REG_MK_U16(0x020c)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR SMIAPP_REG_MK_U16(0x020e)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_RED SMIAPP_REG_MK_U16(0x0210)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE SMIAPP_REG_MK_U16(0x0212)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB SMIAPP_REG_MK_U16(0x0214)
-#define SMIAPP_REG_U16_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0300)
-#define SMIAPP_REG_U16_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x0302)
-#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x0304)
-#define SMIAPP_REG_U16_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x0306)
-#define SMIAPP_REG_U16_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0308)
-#define SMIAPP_REG_U16_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x030a)
-#define SMIAPP_REG_U16_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x0340)
-#define SMIAPP_REG_U16_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x0342)
-#define SMIAPP_REG_U16_X_ADDR_START SMIAPP_REG_MK_U16(0x0344)
-#define SMIAPP_REG_U16_Y_ADDR_START SMIAPP_REG_MK_U16(0x0346)
-#define SMIAPP_REG_U16_X_ADDR_END SMIAPP_REG_MK_U16(0x0348)
-#define SMIAPP_REG_U16_Y_ADDR_END SMIAPP_REG_MK_U16(0x034a)
-#define SMIAPP_REG_U16_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034c)
-#define SMIAPP_REG_U16_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034e)
-#define SMIAPP_REG_U16_X_EVEN_INC SMIAPP_REG_MK_U16(0x0380)
-#define SMIAPP_REG_U16_X_ODD_INC SMIAPP_REG_MK_U16(0x0382)
-#define SMIAPP_REG_U16_Y_EVEN_INC SMIAPP_REG_MK_U16(0x0384)
-#define SMIAPP_REG_U16_Y_ODD_INC SMIAPP_REG_MK_U16(0x0386)
-#define SMIAPP_REG_U16_SCALING_MODE SMIAPP_REG_MK_U16(0x0400)
-#define SMIAPP_REG_U16_SPATIAL_SAMPLING SMIAPP_REG_MK_U16(0x0402)
-#define SMIAPP_REG_U16_SCALE_M SMIAPP_REG_MK_U16(0x0404)
-#define SMIAPP_REG_U16_SCALE_N SMIAPP_REG_MK_U16(0x0406)
-#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET SMIAPP_REG_MK_U16(0x0408)
-#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET SMIAPP_REG_MK_U16(0x040a)
-#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH SMIAPP_REG_MK_U16(0x040c)
-#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT SMIAPP_REG_MK_U16(0x040e)
-#define SMIAPP_REG_U16_COMPRESSION_MODE SMIAPP_REG_MK_U16(0x0500)
-#define SMIAPP_REG_U16_TEST_PATTERN_MODE SMIAPP_REG_MK_U16(0x0600)
-#define SMIAPP_REG_U16_TEST_DATA_RED SMIAPP_REG_MK_U16(0x0602)
-#define SMIAPP_REG_U16_TEST_DATA_GREENR SMIAPP_REG_MK_U16(0x0604)
-#define SMIAPP_REG_U16_TEST_DATA_BLUE SMIAPP_REG_MK_U16(0x0606)
-#define SMIAPP_REG_U16_TEST_DATA_GREENB SMIAPP_REG_MK_U16(0x0608)
-#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060a)
-#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x060c)
-#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060e)
-#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x0610)
-#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS SMIAPP_REG_MK_U16(0x0700)
-#define SMIAPP_REG_U8_TCLK_POST SMIAPP_REG_MK_U8(0x0800)
-#define SMIAPP_REG_U8_THS_PREPARE SMIAPP_REG_MK_U8(0x0801)
-#define SMIAPP_REG_U8_THS_ZERO_MIN SMIAPP_REG_MK_U8(0x0802)
-#define SMIAPP_REG_U8_THS_TRAIL SMIAPP_REG_MK_U8(0x0803)
-#define SMIAPP_REG_U8_TCLK_TRAIL_MIN SMIAPP_REG_MK_U8(0x0804)
-#define SMIAPP_REG_U8_TCLK_PREPARE SMIAPP_REG_MK_U8(0x0805)
-#define SMIAPP_REG_U8_TCLK_ZERO SMIAPP_REG_MK_U8(0x0806)
-#define SMIAPP_REG_U8_TLPX SMIAPP_REG_MK_U8(0x0807)
-#define SMIAPP_REG_U8_DPHY_CTRL SMIAPP_REG_MK_U8(0x0808)
-#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS SMIAPP_REG_MK_U32(0x0820)
-#define SMIAPP_REG_U8_BINNING_MODE SMIAPP_REG_MK_U8(0x0900)
-#define SMIAPP_REG_U8_BINNING_TYPE SMIAPP_REG_MK_U8(0x0901)
-#define SMIAPP_REG_U8_BINNING_WEIGHTING SMIAPP_REG_MK_U8(0x0902)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL SMIAPP_REG_MK_U8(0x0a00)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS SMIAPP_REG_MK_U8(0x0a01)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a02)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 SMIAPP_REG_MK_U8(0x0a04)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 SMIAPP_REG_MK_U8(0x0a05)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 SMIAPP_REG_MK_U8(0x0a06)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 SMIAPP_REG_MK_U8(0x0a07)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 SMIAPP_REG_MK_U8(0x0a08)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 SMIAPP_REG_MK_U8(0x0a09)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 SMIAPP_REG_MK_U8(0x0a10)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 SMIAPP_REG_MK_U8(0x0a11)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 SMIAPP_REG_MK_U8(0x0a12)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 SMIAPP_REG_MK_U8(0x0a13)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 SMIAPP_REG_MK_U8(0x0a14)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 SMIAPP_REG_MK_U8(0x0a15)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 SMIAPP_REG_MK_U8(0x0a16)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 SMIAPP_REG_MK_U8(0x0a17)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 SMIAPP_REG_MK_U8(0x0a18)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 SMIAPP_REG_MK_U8(0x0a19)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 SMIAPP_REG_MK_U8(0x0a1a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 SMIAPP_REG_MK_U8(0x0a1b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 SMIAPP_REG_MK_U8(0x0a1c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 SMIAPP_REG_MK_U8(0x0a1d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 SMIAPP_REG_MK_U8(0x0a1e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 SMIAPP_REG_MK_U8(0x0a1f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 SMIAPP_REG_MK_U8(0x0a20)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 SMIAPP_REG_MK_U8(0x0a21)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 SMIAPP_REG_MK_U8(0x0a22)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 SMIAPP_REG_MK_U8(0x0a23)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 SMIAPP_REG_MK_U8(0x0a24)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 SMIAPP_REG_MK_U8(0x0a25)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 SMIAPP_REG_MK_U8(0x0a26)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 SMIAPP_REG_MK_U8(0x0a27)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 SMIAPP_REG_MK_U8(0x0a28)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 SMIAPP_REG_MK_U8(0x0a29)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 SMIAPP_REG_MK_U8(0x0a2a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 SMIAPP_REG_MK_U8(0x0a2b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 SMIAPP_REG_MK_U8(0x0a2c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 SMIAPP_REG_MK_U8(0x0a2d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 SMIAPP_REG_MK_U8(0x0a2e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 SMIAPP_REG_MK_U8(0x0a2f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 SMIAPP_REG_MK_U8(0x0a30)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 SMIAPP_REG_MK_U8(0x0a31)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 SMIAPP_REG_MK_U8(0x0a32)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 SMIAPP_REG_MK_U8(0x0a33)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 SMIAPP_REG_MK_U8(0x0a34)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 SMIAPP_REG_MK_U8(0x0a35)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 SMIAPP_REG_MK_U8(0x0a36)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 SMIAPP_REG_MK_U8(0x0a37)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 SMIAPP_REG_MK_U8(0x0a38)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 SMIAPP_REG_MK_U8(0x0a39)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 SMIAPP_REG_MK_U8(0x0a3a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 SMIAPP_REG_MK_U8(0x0a3b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 SMIAPP_REG_MK_U8(0x0a3c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 SMIAPP_REG_MK_U8(0x0a3d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 SMIAPP_REG_MK_U8(0x0a3e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 SMIAPP_REG_MK_U8(0x0a3f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 SMIAPP_REG_MK_U8(0x0a40)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 SMIAPP_REG_MK_U8(0x0a41)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 SMIAPP_REG_MK_U8(0x0a42)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 SMIAPP_REG_MK_U8(0x0a43)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL SMIAPP_REG_MK_U8(0x0a44)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS SMIAPP_REG_MK_U8(0x0a45)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a46)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 SMIAPP_REG_MK_U8(0x0a48)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 SMIAPP_REG_MK_U8(0x0a49)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 SMIAPP_REG_MK_U8(0x0a4a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 SMIAPP_REG_MK_U8(0x0a4b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 SMIAPP_REG_MK_U8(0x0a4c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 SMIAPP_REG_MK_U8(0x0a4d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 SMIAPP_REG_MK_U8(0x0a4e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 SMIAPP_REG_MK_U8(0x0a4f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 SMIAPP_REG_MK_U8(0x0a50)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 SMIAPP_REG_MK_U8(0x0a51)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 SMIAPP_REG_MK_U8(0x0a52)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 SMIAPP_REG_MK_U8(0x0a53)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 SMIAPP_REG_MK_U8(0x0a54)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 SMIAPP_REG_MK_U8(0x0a55)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 SMIAPP_REG_MK_U8(0x0a56)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 SMIAPP_REG_MK_U8(0x0a57)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 SMIAPP_REG_MK_U8(0x0a58)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 SMIAPP_REG_MK_U8(0x0a59)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 SMIAPP_REG_MK_U8(0x0a5a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 SMIAPP_REG_MK_U8(0x0a5b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 SMIAPP_REG_MK_U8(0x0a5c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 SMIAPP_REG_MK_U8(0x0a5d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 SMIAPP_REG_MK_U8(0x0a5e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 SMIAPP_REG_MK_U8(0x0a5f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 SMIAPP_REG_MK_U8(0x0a60)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 SMIAPP_REG_MK_U8(0x0a61)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 SMIAPP_REG_MK_U8(0x0a62)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 SMIAPP_REG_MK_U8(0x0a63)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 SMIAPP_REG_MK_U8(0x0a64)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 SMIAPP_REG_MK_U8(0x0a65)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 SMIAPP_REG_MK_U8(0x0a66)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 SMIAPP_REG_MK_U8(0x0a67)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 SMIAPP_REG_MK_U8(0x0a68)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 SMIAPP_REG_MK_U8(0x0a69)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 SMIAPP_REG_MK_U8(0x0a6a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 SMIAPP_REG_MK_U8(0x0a6b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 SMIAPP_REG_MK_U8(0x0a6c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 SMIAPP_REG_MK_U8(0x0a6d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 SMIAPP_REG_MK_U8(0x0a6e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 SMIAPP_REG_MK_U8(0x0a6f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 SMIAPP_REG_MK_U8(0x0a70)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 SMIAPP_REG_MK_U8(0x0a71)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 SMIAPP_REG_MK_U8(0x0a72)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 SMIAPP_REG_MK_U8(0x0a73)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 SMIAPP_REG_MK_U8(0x0a74)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 SMIAPP_REG_MK_U8(0x0a75)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 SMIAPP_REG_MK_U8(0x0a76)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 SMIAPP_REG_MK_U8(0x0a77)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 SMIAPP_REG_MK_U8(0x0a78)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 SMIAPP_REG_MK_U8(0x0a79)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 SMIAPP_REG_MK_U8(0x0a7a)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 SMIAPP_REG_MK_U8(0x0a7b)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 SMIAPP_REG_MK_U8(0x0a7c)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 SMIAPP_REG_MK_U8(0x0a7d)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 SMIAPP_REG_MK_U8(0x0a7e)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 SMIAPP_REG_MK_U8(0x0a7f)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 SMIAPP_REG_MK_U8(0x0a80)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 SMIAPP_REG_MK_U8(0x0a81)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 SMIAPP_REG_MK_U8(0x0a82)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 SMIAPP_REG_MK_U8(0x0a83)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 SMIAPP_REG_MK_U8(0x0a84)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 SMIAPP_REG_MK_U8(0x0a85)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 SMIAPP_REG_MK_U8(0x0a86)
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 SMIAPP_REG_MK_U8(0x0a87)
-#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b00)
-#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL SMIAPP_REG_MK_U8(0x0b01)
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE SMIAPP_REG_MK_U8(0x0b02)
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT SMIAPP_REG_MK_U8(0x0b03)
-#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b04)
-#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b05)
-#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b06)
-#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b07)
-#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b08)
-#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b09)
-#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0a)
-#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b0b)
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b0c)
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT SMIAPP_REG_MK_U8(0x0b0d)
-#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0e)
-#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b0f)
-#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b10)
-#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b11)
-#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b12)
-#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b13)
-#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b14)
-#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b15)
-#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b16)
-#define SMIAPP_REG_U8_EDOF_MODE SMIAPP_REG_MK_U8(0x0b80)
-#define SMIAPP_REG_U8_SHARPNESS SMIAPP_REG_MK_U8(0x0b83)
-#define SMIAPP_REG_U8_DENOISING SMIAPP_REG_MK_U8(0x0b84)
-#define SMIAPP_REG_U8_MODULE_SPECIFIC SMIAPP_REG_MK_U8(0x0b85)
-#define SMIAPP_REG_U16_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x0b86)
-#define SMIAPP_REG_U16_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x0b88)
-#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL SMIAPP_REG_MK_U8(0x0b8a)
-#define SMIAPP_REG_U16_COLOUR_TEMPERATURE SMIAPP_REG_MK_U16(0x0b8c)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR SMIAPP_REG_MK_U16(0x0b8e)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED SMIAPP_REG_MK_U16(0x0b90)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE SMIAPP_REG_MK_U16(0x0b92)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB SMIAPP_REG_MK_U16(0x0b94)
-#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE SMIAPP_REG_MK_U8(0x0bc0)
-#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING SMIAPP_REG_MK_U16(0x0bc2)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START SMIAPP_REG_MK_U16(0x0bc4)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START SMIAPP_REG_MK_U16(0x0bc6)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH SMIAPP_REG_MK_U16(0x0bc8)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT SMIAPP_REG_MK_U16(0x0bca)
-#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 SMIAPP_REG_MK_U8(0x0c00)
-#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 SMIAPP_REG_MK_U8(0x0c01)
-#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 SMIAPP_REG_MK_U8(0x0c02)
-#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 SMIAPP_REG_MK_U8(0x0c03)
-#define SMIAPP_REG_U16_TRDY_CTRL SMIAPP_REG_MK_U16(0x0c04)
-#define SMIAPP_REG_U16_TRDOUT_CTRL SMIAPP_REG_MK_U16(0x0c06)
-#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c08)
-#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c0a)
-#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c0c)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c0e)
-#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL SMIAPP_REG_MK_U16(0x0c10)
-#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT SMIAPP_REG_MK_U8(0x0c12)
-#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c14)
-#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL SMIAPP_REG_MK_U16(0x0c16)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c18)
-#define SMIAPP_REG_U8_FLASH_MODE_RS SMIAPP_REG_MK_U8(0x0c1a)
-#define SMIAPP_REG_U8_FLASH_TRIGGER_RS SMIAPP_REG_MK_U8(0x0c1b)
-#define SMIAPP_REG_U8_FLASH_STATUS SMIAPP_REG_MK_U8(0x0c1c)
-#define SMIAPP_REG_U8_SA_STROBE_MODE SMIAPP_REG_MK_U8(0x0c1d)
-#define SMIAPP_REG_U16_SA_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c1e)
-#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c20)
-#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c22)
-#define SMIAPP_REG_U8_SA_STROBE_TRIGGER SMIAPP_REG_MK_U8(0x0c24)
-#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS SMIAPP_REG_MK_U8(0x0c25)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c26)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL SMIAPP_REG_MK_U16(0x0c28)
-#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL SMIAPP_REG_MK_U8(0x0c2a)
-#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL SMIAPP_REG_MK_U8(0x0c2b)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c2c)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL SMIAPP_REG_MK_U16(0x0c2e)
-#define SMIAPP_REG_U8_LOW_LEVEL_CTRL SMIAPP_REG_MK_U8(0x0c80)
-#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT SMIAPP_REG_MK_U16(0x0c82)
-#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c84)
-#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c86)
-#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c88)
-#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8a)
-#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c8c)
-#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8e)
-#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL SMIAPP_REG_MK_U8(0x0d00)
-#define SMIAPP_REG_U8_OPERATION_MODE SMIAPP_REG_MK_U8(0x0d01)
-#define SMIAPP_REG_U8_ACT_STATE1 SMIAPP_REG_MK_U8(0x0d02)
-#define SMIAPP_REG_U8_ACT_STATE2 SMIAPP_REG_MK_U8(0x0d03)
-#define SMIAPP_REG_U16_FOCUS_CHANGE SMIAPP_REG_MK_U16(0x0d80)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL SMIAPP_REG_MK_U16(0x0d82)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 SMIAPP_REG_MK_U16(0x0d84)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 SMIAPP_REG_MK_U16(0x0d86)
-#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 SMIAPP_REG_MK_U8(0x0d88)
-#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 SMIAPP_REG_MK_U8(0x0d89)
-#define SMIAPP_REG_U8_POSITION SMIAPP_REG_MK_U8(0x0d8a)
-#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL SMIAPP_REG_MK_U8(0x0e00)
-#define SMIAPP_REG_U8_BRACKETING_LUT_MODE SMIAPP_REG_MK_U8(0x0e01)
-#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL SMIAPP_REG_MK_U8(0x0e02)
-#define SMIAPP_REG_U8_LUT_PARAMETERS_START SMIAPP_REG_MK_U8(0x0e10)
-#define SMIAPP_REG_U8_LUT_PARAMETERS_END SMIAPP_REG_MK_U8(0x0eff)
-#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY SMIAPP_REG_MK_U16(0x1000)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1004)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x1006)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1008)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x100a)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x1080)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN SMIAPP_REG_MK_U16(0x1084)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX SMIAPP_REG_MK_U16(0x1086)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE SMIAPP_REG_MK_U16(0x1088)
-#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1100)
-#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1104)
-#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x1108)
-#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x110a)
-#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x110c)
-#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x1110)
-#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1114)
-#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1116)
-#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x1118)
-#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x111c)
-#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1120)
-#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1122)
-#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1124)
-#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1128)
-#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x112c)
-#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1130)
-#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1134)
-#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1136)
-#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1140)
-#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1142)
-#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1144)
-#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1146)
-#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK SMIAPP_REG_MK_U16(0x1148)
-#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES SMIAPP_REG_MK_U16(0x114a)
-#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE SMIAPP_REG_MK_U8(0x114c)
-#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1160)
-#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1162)
-#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1164)
-#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1168)
-#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116c)
-#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116e)
-#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1170)
-#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1174)
-#define SMIAPP_REG_U16_X_ADDR_MIN SMIAPP_REG_MK_U16(0x1180)
-#define SMIAPP_REG_U16_Y_ADDR_MIN SMIAPP_REG_MK_U16(0x1182)
-#define SMIAPP_REG_U16_X_ADDR_MAX SMIAPP_REG_MK_U16(0x1184)
-#define SMIAPP_REG_U16_Y_ADDR_MAX SMIAPP_REG_MK_U16(0x1186)
-#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x1188)
-#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118a)
-#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118c)
-#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118e)
-#define SMIAPP_REG_U16_MIN_EVEN_INC SMIAPP_REG_MK_U16(0x11c0)
-#define SMIAPP_REG_U16_MAX_EVEN_INC SMIAPP_REG_MK_U16(0x11c2)
-#define SMIAPP_REG_U16_MIN_ODD_INC SMIAPP_REG_MK_U16(0x11c4)
-#define SMIAPP_REG_U16_MAX_ODD_INC SMIAPP_REG_MK_U16(0x11c6)
-#define SMIAPP_REG_U16_SCALING_CAPABILITY SMIAPP_REG_MK_U16(0x1200)
-#define SMIAPP_REG_U16_SCALER_M_MIN SMIAPP_REG_MK_U16(0x1204)
-#define SMIAPP_REG_U16_SCALER_M_MAX SMIAPP_REG_MK_U16(0x1206)
-#define SMIAPP_REG_U16_SCALER_N_MIN SMIAPP_REG_MK_U16(0x1208)
-#define SMIAPP_REG_U16_SCALER_N_MAX SMIAPP_REG_MK_U16(0x120a)
-#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY SMIAPP_REG_MK_U16(0x120c)
-#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY SMIAPP_REG_MK_U8(0x120e)
-#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY SMIAPP_REG_MK_U16(0x1300)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED SMIAPP_REG_MK_U16(0x1400)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED SMIAPP_REG_MK_U16(0x1402)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED SMIAPP_REG_MK_U16(0x1404)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN SMIAPP_REG_MK_U16(0x1406)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN SMIAPP_REG_MK_U16(0x1408)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN SMIAPP_REG_MK_U16(0x140a)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE SMIAPP_REG_MK_U16(0x140c)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE SMIAPP_REG_MK_U16(0x140e)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE SMIAPP_REG_MK_U16(0x1410)
-#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS SMIAPP_REG_MK_U16(0x1500)
-#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY SMIAPP_REG_MK_U8(0x1502)
-#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY SMIAPP_REG_MK_U8(0x1600)
-#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1601)
-#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1602)
-#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY SMIAPP_REG_MK_U8(0x1603)
-#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY SMIAPP_REG_MK_U8(0x1604)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1608)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x160c)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1610)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1614)
-#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY SMIAPP_REG_MK_U8(0x1618)
-#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1700)
-#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1702)
-#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1704)
-#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1706)
-#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN SMIAPP_REG_MK_U16(0x1708)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN SMIAPP_REG_MK_U16(0x170a)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN SMIAPP_REG_MK_U16(0x170c)
-#define SMIAPP_REG_U8_BINNING_CAPABILITY SMIAPP_REG_MK_U8(0x1710)
-#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY SMIAPP_REG_MK_U8(0x1711)
-#define SMIAPP_REG_U8_BINNING_SUBTYPES SMIAPP_REG_MK_U8(0x1712)
-#define SMIAPP_REG_U8_BINNING_TYPE_n(n) SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY SMIAPP_REG_MK_U8(0x1800)
-#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1900)
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY SMIAPP_REG_MK_U8(0x1901)
-#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY SMIAPP_REG_MK_U8(0x1902)
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1903)
-#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY SMIAPP_REG_MK_U16(0x1904)
-#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 SMIAPP_REG_MK_U16(0x1906)
-#define SMIAPP_REG_U8_EDOF_CAPABILITY SMIAPP_REG_MK_U8(0x1980)
-#define SMIAPP_REG_U8_ESTIMATION_FRAMES SMIAPP_REG_MK_U8(0x1981)
-#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ SMIAPP_REG_MK_U8(0x1982)
-#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ SMIAPP_REG_MK_U8(0x1983)
-#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ SMIAPP_REG_MK_U8(0x1984)
-#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ SMIAPP_REG_MK_U8(0x1985)
-#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ SMIAPP_REG_MK_U8(0x1986)
-#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY SMIAPP_REG_MK_U8(0x1987)
-#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM SMIAPP_REG_MK_U8(0x1988)
-#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x19c0)
-#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY SMIAPP_REG_MK_U8(0x19c1)
-#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x19c2)
-#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x19c4)
-#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN SMIAPP_REG_MK_U16(0x1a00)
-#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1a02)
-#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR SMIAPP_REG_MK_U16(0x1b02)
-#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY SMIAPP_REG_MK_U8(0x1b04)
-#define SMIAPP_REG_U16_ACTUATOR_TYPE SMIAPP_REG_MK_U16(0x1b40)
-#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS SMIAPP_REG_MK_U8(0x1b42)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS SMIAPP_REG_MK_U16(0x1b44)
-#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 SMIAPP_REG_MK_U8(0x1c00)
-#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 SMIAPP_REG_MK_U8(0x1c01)
-#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE SMIAPP_REG_MK_U8(0x1c02)
diff --git a/drivers/media/video/smiapp/smiapp-reg.h b/drivers/media/video/smiapp/smiapp-reg.h
deleted file mode 100644
index d0167aa17534..000000000000
--- a/drivers/media/video/smiapp/smiapp-reg.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-reg.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_REG_H_
-#define __SMIAPP_REG_H_
-
-#include "smiapp-reg-defs.h"
-
-/* Bits for above register */
-#define SMIAPP_IMAGE_ORIENTATION_HFLIP (1 << 0)
-#define SMIAPP_IMAGE_ORIENTATION_VFLIP (1 << 1)
-
-#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN (1 << 0)
-#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN (0 << 1)
-#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN (1 << 1)
-#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR (1 << 2)
-#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY (1 << 0)
-#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY (1 << 1)
-#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA (1 << 2)
-#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE (1 << 3)
-
-#define SMIAPP_SOFTWARE_RESET (1 << 0)
-
-#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE (1 << 0)
-#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE (1 << 1)
-
-#define SMIAPP_DPHY_CTRL_AUTOMATIC 0
-/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
-#define SMIAPP_DPHY_CTRL_UI 1
-#define SMIAPP_DPHY_CTRL_REGISTER 2
-
-#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1
-#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2
-
-#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0
-#define SMIAPP_MODE_SELECT_STREAMING 1
-
-#define SMIAPP_SCALING_MODE_NONE 0
-#define SMIAPP_SCALING_MODE_HORIZONTAL 1
-#define SMIAPP_SCALING_MODE_BOTH 2
-
-#define SMIAPP_SCALING_CAPABILITY_NONE 0
-#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1
-#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */
-
-/* digital crop right before scaler */
-#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0
-#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1
-
-#define SMIAPP_BINNING_CAPABILITY_NO 0
-#define SMIAPP_BINNING_CAPABILITY_YES 1
-
-/* Maximum number of binning subtypes */
-#define SMIAPP_BINNING_SUBTYPES 253
-
-#define SMIAPP_PIXEL_ORDER_GRBG 0
-#define SMIAPP_PIXEL_ORDER_RGGB 1
-#define SMIAPP_PIXEL_ORDER_BGGR 2
-#define SMIAPP_PIXEL_ORDER_GBRG 3
-
-#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1
-#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2
-#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8
-#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16
-
-#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01
-#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02
-#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f
-#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0
-#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4
-
-#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000
-#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12
-#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff
-
-#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000
-#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28
-#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff
-
-#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1
-#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2
-#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3
-#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4
-#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5
-
-#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0
-#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1
-
-/* Scaling N factor */
-#define SMIAPP_SCALE_N 16
-
-/* Image statistics registers */
-/* Registers 0x2000 to 0x2fff are reserved for future
- * use for statistics features.
- */
-
-/* Manufacturer Specific Registers: 0x3000 to 0x3fff
- * The manufacturer specifies these as a black box.
- */
-
-#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/video/smiapp/smiapp-regs.c b/drivers/media/video/smiapp/smiapp-regs.c
deleted file mode 100644
index b1812b17a407..000000000000
--- a/drivers/media/video/smiapp/smiapp-regs.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp-regs.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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/delay.h>
-#include <linux/i2c.h>
-
-#include "smiapp.h"
-#include "smiapp-regs.h"
-
-static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
- uint32_t phloat)
-{
- int32_t exp;
- uint64_t man;
-
- if (phloat >= 0x80000000) {
- dev_err(&client->dev, "this is a negative number\n");
- return 0;
- }
-
- if (phloat == 0x7f800000)
- return ~0; /* Inf. */
-
- if ((phloat & 0x7f800000) == 0x7f800000) {
- dev_err(&client->dev, "NaN or other special number\n");
- return 0;
- }
-
- /* Valid cases begin here */
- if (phloat == 0)
- return 0; /* Valid zero */
-
- if (phloat > 0x4f800000)
- return ~0; /* larger than 4294967295 */
-
- /*
- * Unbias exponent (note how phloat is now guaranteed to
- * have 0 in the high bit)
- */
- exp = ((int32_t)phloat >> 23) - 127;
-
- /* Extract mantissa, add missing '1' bit and it's in MHz */
- man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
-
- if (exp < 0)
- man >>= -exp;
- else
- man <<= exp;
-
- man >>= 23; /* Remove mantissa bias */
-
- return man & 0xffffffff;
-}
-
-
-/*
- * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
- u16 len, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct i2c_msg msg;
- unsigned char data[4];
- u16 offset = reg;
- int r;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = 2;
- msg.buf = data;
-
- /* high byte goes out first */
- data[0] = (u8) (offset >> 8);
- data[1] = (u8) offset;
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r != 1) {
- if (r >= 0)
- r = -EBUSY;
- goto err;
- }
-
- msg.len = len;
- msg.flags = I2C_M_RD;
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r != 1) {
- if (r >= 0)
- r = -EBUSY;
- goto err;
- }
-
- *val = 0;
- /* high byte comes first */
- switch (len) {
- case SMIA_REG_32BIT:
- *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
- data[3];
- break;
- case SMIA_REG_16BIT:
- *val = (data[0] << 8) + data[1];
- break;
- case SMIA_REG_8BIT:
- *val = data[0];
- break;
- default:
- BUG();
- }
-
- return 0;
-
-err:
- dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
-
- return r;
-}
-
-/* Read a register using 8-bit access only. */
-static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg,
- u16 len, u32 *val)
-{
- unsigned int i;
- int rval;
-
- *val = 0;
-
- for (i = 0; i < len; i++) {
- u32 val8;
-
- rval = ____smiapp_read(sensor, reg + i, 1, &val8);
- if (rval < 0)
- return rval;
- *val |= val8 << ((len - i - 1) << 3);
- }
-
- return 0;
-}
-
-/*
- * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
- bool only8)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int len = (u8)(reg >> 16);
- int rval;
-
- if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
- && len != SMIA_REG_32BIT)
- return -EINVAL;
-
- if (smiapp_quirk_reg(sensor, reg, val))
- goto found_quirk;
-
- if (len == SMIA_REG_8BIT && !only8)
- rval = ____smiapp_read(sensor, (u16)reg, len, val);
- else
- rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
- if (rval < 0)
- return rval;
-
-found_quirk:
- if (reg & SMIA_REG_FLAG_FLOAT)
- *val = float_to_u32_mul_1000000(client, *val);
-
- return 0;
-}
-
-int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
-{
- return __smiapp_read(
- sensor, reg, val,
- smiapp_needs_quirk(sensor,
- SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
-}
-
-int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
-{
- return __smiapp_read(sensor, reg, val, true);
-}
-
-/*
- * Write to a 8/16-bit register.
- * Returns zero if successful, or non-zero otherwise.
- */
-int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct i2c_msg msg;
- unsigned char data[6];
- unsigned int retries;
- unsigned int flags = reg >> 24;
- unsigned int len = (u8)(reg >> 16);
- u16 offset = reg;
- int r;
-
- if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
- len != SMIA_REG_32BIT) || flags)
- return -EINVAL;
-
- msg.addr = client->addr;
- msg.flags = 0; /* Write */
- msg.len = 2 + len;
- msg.buf = data;
-
- /* high byte goes out first */
- data[0] = (u8) (reg >> 8);
- data[1] = (u8) (reg & 0xff);
-
- switch (len) {
- case SMIA_REG_8BIT:
- data[2] = val;
- break;
- case SMIA_REG_16BIT:
- data[2] = val >> 8;
- data[3] = val;
- break;
- case SMIA_REG_32BIT:
- data[2] = val >> 24;
- data[3] = val >> 16;
- data[4] = val >> 8;
- data[5] = val;
- break;
- default:
- BUG();
- }
-
- for (retries = 0; retries < 5; retries++) {
- /*
- * Due to unknown reason sensor stops responding. This
- * loop is a temporaty solution until the root cause
- * is found.
- */
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r == 1) {
- if (retries)
- dev_err(&client->dev,
- "sensor i2c stall encountered. "
- "retries: %d\n", retries);
- return 0;
- }
-
- usleep_range(2000, 2000);
- }
-
- dev_err(&client->dev,
- "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
-
- return r;
-}
diff --git a/drivers/media/video/smiapp/smiapp.h b/drivers/media/video/smiapp/smiapp.h
deleted file mode 100644
index 587f7f11238d..000000000000
--- a/drivers/media/video/smiapp/smiapp.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * drivers/media/video/smiapp/smiapp.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2010--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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 __SMIAPP_PRIV_H_
-#define __SMIAPP_PRIV_H_
-
-#include <linux/mutex.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-subdev.h>
-#include <media/smiapp.h>
-
-#include "smiapp-pll.h"
-#include "smiapp-reg.h"
-#include "smiapp-regs.h"
-#include "smiapp-quirk.h"
-
-/*
- * Standard SMIA++ constants
- */
-#define SMIA_VERSION_1 10
-#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */
-#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */
-#define SMIAPP_VERSION_1 10
-
-#define SMIAPP_PROFILE_0 0
-#define SMIAPP_PROFILE_1 1
-#define SMIAPP_PROFILE_2 2
-
-#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */
-
-#define SMIAPP_RESET_DELAY_CLOCKS 2400
-#define SMIAPP_RESET_DELAY(clk) \
- (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \
- + (clk) / 1000 - 1) / ((clk) / 1000))
-
-#include "smiapp-limits.h"
-
-struct smiapp_quirk;
-
-#define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0)
-
-struct smiapp_module_ident {
- u8 manufacturer_id;
- u16 model_id;
- u8 revision_number_major;
-
- u8 flags;
-
- char *name;
- const struct smiapp_quirk *quirk;
-};
-
-struct smiapp_module_info {
- u32 manufacturer_id;
- u32 model_id;
- u32 revision_number_major;
- u32 revision_number_minor;
-
- u32 module_year;
- u32 module_month;
- u32 module_day;
-
- u32 sensor_manufacturer_id;
- u32 sensor_model_id;
- u32 sensor_revision_number;
- u32 sensor_firmware_version;
-
- u32 smia_version;
- u32 smiapp_version;
-
- u32 smiapp_profile;
-
- char *name;
- const struct smiapp_quirk *quirk;
-};
-
-#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \
- { .manufacturer_id = manufacturer, \
- .model_id = model, \
- .revision_number_major = rev, \
- .flags = fl, \
- .name = _name, \
- .quirk = _quirk, }
-
-#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \
- { .manufacturer_id = manufacturer, \
- .model_id = model, \
- .revision_number_major = rev, \
- .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
- .name = _name, \
- .quirk = _quirk, }
-
-#define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \
- { .manufacturer_id = manufacturer, \
- .model_id = model, \
- .revision_number_major = rev, \
- .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
- .name = _name, }
-
-#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \
- { .manufacturer_id = manufacturer, \
- .model_id = model, \
- .revision_number_major = rev, \
- .flags = 0, \
- .name = _name, \
- .quirk = _quirk, }
-
-#define SMIAPP_IDENT(manufacturer, model, rev, _name) \
- { .manufacturer_id = manufacturer, \
- .model_id = model, \
- .revision_number_major = rev, \
- .flags = 0, \
- .name = _name, }
-
-struct smiapp_reg_limits {
- u32 addr;
- char *what;
-};
-
-extern struct smiapp_reg_limits smiapp_reg_limits[];
-
-struct smiapp_csi_data_format {
- u32 code;
- u8 width;
- u8 compressed;
- u8 pixel_order;
-};
-
-#define SMIAPP_SUBDEVS 3
-
-#define SMIAPP_PA_PAD_SRC 0
-#define SMIAPP_PAD_SINK 0
-#define SMIAPP_PAD_SRC 1
-#define SMIAPP_PADS 2
-
-struct smiapp_binning_subtype {
- u8 horizontal:4;
- u8 vertical:4;
-} __packed;
-
-struct smiapp_subdev {
- struct v4l2_subdev sd;
- struct media_pad pads[2];
- struct v4l2_rect sink_fmt;
- struct v4l2_rect crop[2];
- struct v4l2_rect compose; /* compose on sink */
- unsigned short sink_pad;
- unsigned short source_pad;
- int npads;
- struct smiapp_sensor *sensor;
- struct v4l2_ctrl_handler ctrl_handler;
-};
-
-/*
- * struct smiapp_sensor - Main device structure
- */
-struct smiapp_sensor {
- /*
- * "mutex" is used to serialise access to all fields here
- * except v4l2_ctrls at the end of the struct. "mutex" is also
- * used to serialise access to file handle specific
- * information. The exception to this rule is the power_mutex
- * below.
- */
- struct mutex mutex;
- /*
- * power_mutex is used to serialise power management related
- * activities. Acquiring "mutex" at that time isn't necessary
- * since there are no other users anyway.
- */
- struct mutex power_mutex;
- struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
- u32 ssds_used;
- struct smiapp_subdev *src;
- struct smiapp_subdev *binner;
- struct smiapp_subdev *scaler;
- struct smiapp_subdev *pixel_array;
- struct smiapp_platform_data *platform_data;
- struct regulator *vana;
- struct clk *ext_clk;
- u32 limits[SMIAPP_LIMIT_LAST];
- u8 nbinning_subtypes;
- struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
- u32 mbus_frame_fmts;
- const struct smiapp_csi_data_format *csi_format;
- const struct smiapp_csi_data_format *internal_csi_format;
- u32 default_mbus_frame_fmts;
- int default_pixel_order;
-
- u8 binning_horizontal;
- u8 binning_vertical;
-
- u8 scale_m;
- u8 scaling_mode;
-
- u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
- u8 flash_capability;
- u8 frame_skip;
-
- int power_count;
-
- bool streaming;
- bool dev_init_done;
-
- u8 *nvm; /* nvm memory buffer */
- unsigned int nvm_size; /* bytes */
-
- struct smiapp_module_info minfo;
-
- struct smiapp_pll pll;
-
- /* Pixel array controls */
- struct v4l2_ctrl *analog_gain;
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *hflip;
- struct v4l2_ctrl *vflip;
- struct v4l2_ctrl *vblank;
- struct v4l2_ctrl *hblank;
- struct v4l2_ctrl *pixel_rate_parray;
- /* src controls */
- struct v4l2_ctrl *link_freq;
- struct v4l2_ctrl *pixel_rate_csi;
-};
-
-#define to_smiapp_subdev(_sd) \
- container_of(_sd, struct smiapp_subdev, sd)
-
-#define to_smiapp_sensor(_sd) \
- (to_smiapp_subdev(_sd)->sensor)
-
-#endif /* __SMIAPP_PRIV_H_ */
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
deleted file mode 100644
index 1bde255e45df..000000000000
--- a/drivers/media/video/soc_camera.c
+++ /dev/null
@@ -1,1546 +0,0 @@
-/*
- * camera image capture (abstract) bus driver
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * This driver provides an interface between platform-specific camera
- * busses and camera devices. It should be used if the camera is
- * connected not over a "proper" bus like PCI or USB, but over a
- * special bus, like, for example, the Quick Capture interface on PXA270
- * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
- * It can handle multiple cameras and / or multiple busses, which can
- * be used, e.g., in stereo-vision applications.
- *
- * 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/device.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/vmalloc.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include <media/videobuf2-core.h>
-#include <media/soc_mediabus.h>
-
-/* Default to VGA resolution */
-#define DEFAULT_WIDTH 640
-#define DEFAULT_HEIGHT 480
-
-#define is_streaming(ici, icd) \
- (((ici)->ops->init_videobuf) ? \
- (icd)->vb_vidq.streaming : \
- vb2_is_streaming(&(icd)->vb2_vidq))
-
-static LIST_HEAD(hosts);
-static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
-
-static int soc_camera_power_on(struct soc_camera_device *icd,
- struct soc_camera_link *icl)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int ret = regulator_bulk_enable(icl->num_regulators,
- icl->regulators);
- if (ret < 0) {
- dev_err(icd->pdev, "Cannot enable regulators\n");
- return ret;
- }
-
- if (icl->power) {
- ret = icl->power(icd->control, 1);
- if (ret < 0) {
- dev_err(icd->pdev,
- "Platform failed to power-on the camera.\n");
- goto elinkpwr;
- }
- }
-
- ret = v4l2_subdev_call(sd, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
- goto esdpwr;
-
- return 0;
-
-esdpwr:
- if (icl->power)
- icl->power(icd->control, 0);
-elinkpwr:
- regulator_bulk_disable(icl->num_regulators,
- icl->regulators);
- return ret;
-}
-
-static int soc_camera_power_off(struct soc_camera_device *icd,
- struct soc_camera_link *icl)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int ret = v4l2_subdev_call(sd, core, s_power, 0);
-
- if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
- return ret;
-
- if (icl->power) {
- ret = icl->power(icd->control, 0);
- if (ret < 0) {
- dev_err(icd->pdev,
- "Platform failed to power-off the camera.\n");
- return ret;
- }
- }
-
- ret = regulator_bulk_disable(icl->num_regulators,
- icl->regulators);
- if (ret < 0)
- dev_err(icd->pdev, "Cannot disable regulators\n");
-
- return ret;
-}
-
-const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
- struct soc_camera_device *icd, unsigned int fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < icd->num_user_formats; i++)
- if (icd->user_formats[i].host_fmt->fourcc == fourcc)
- return icd->user_formats + i;
- return NULL;
-}
-EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
-
-/**
- * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
- * @icl: camera platform parameters
- * @cfg: media bus configuration
- * @return: resulting flags
- */
-unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
- const struct v4l2_mbus_config *cfg)
-{
- unsigned long f, flags = cfg->flags;
-
- /* If only one of the two polarities is supported, switch to the opposite */
- if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
- f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW);
- if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW)
- flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW;
- }
-
- if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
- f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW);
- if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW)
- flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW;
- }
-
- if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
- f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING);
- if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING)
- flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
- }
-
- return flags;
-}
-EXPORT_SYMBOL(soc_camera_apply_board_flags);
-
-#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
- ((x) >> 24) & 0xff
-
-static int soc_camera_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- const struct soc_camera_format_xlate *xlate;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int ret;
-
- dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
- pixfmtstr(pix->pixelformat), pix->width, pix->height);
-
- if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
- !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
- pix->bytesperline = 0;
- pix->sizeimage = 0;
- }
-
- ret = ici->ops->try_fmt(icd, f);
- if (ret < 0)
- return ret;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate)
- return -EINVAL;
-
- ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt);
- if (ret < 0)
- return ret;
-
- pix->bytesperline = max_t(u32, pix->bytesperline, ret);
-
- ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline,
- pix->height);
- if (ret < 0)
- return ret;
-
- pix->sizeimage = max_t(u32, pix->sizeimage, ret);
-
- return 0;
-}
-
-static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct soc_camera_device *icd = file->private_data;
-
- WARN_ON(priv != file->private_data);
-
- /* Only single-plane capture is supported so far */
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- /* limit format to hardware capabilities */
- return soc_camera_try_fmt(icd, f);
-}
-
-static int soc_camera_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- if (inp->index != 0)
- return -EINVAL;
-
- /* default is camera */
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_UNKNOWN;
- strcpy(inp->name, "Camera");
-
- return 0;
-}
-
-static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
-{
- if (i > 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, core, s_std, *a);
-}
-
-static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, core, g_std, a);
-}
-
-static int soc_camera_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- return ici->ops->enum_framesizes(icd, fsize);
-}
-
-static int soc_camera_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- int ret;
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- if (icd->streamer && icd->streamer != file)
- return -EBUSY;
-
- if (ici->ops->init_videobuf) {
- ret = videobuf_reqbufs(&icd->vb_vidq, p);
- if (ret < 0)
- return ret;
-
- ret = ici->ops->reqbufs(icd, p);
- } else {
- ret = vb2_reqbufs(&icd->vb2_vidq, p);
- }
-
- if (!ret && !icd->streamer)
- icd->streamer = file;
-
- return ret;
-}
-
-static int soc_camera_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- if (ici->ops->init_videobuf)
- return videobuf_querybuf(&icd->vb_vidq, p);
- else
- return vb2_querybuf(&icd->vb2_vidq, p);
-}
-
-static int soc_camera_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- if (icd->streamer != file)
- return -EBUSY;
-
- if (ici->ops->init_videobuf)
- return videobuf_qbuf(&icd->vb_vidq, p);
- else
- return vb2_qbuf(&icd->vb2_vidq, p);
-}
-
-static int soc_camera_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- if (icd->streamer != file)
- return -EBUSY;
-
- if (ici->ops->init_videobuf)
- return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
- else
- return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK);
-}
-
-static int soc_camera_create_bufs(struct file *file, void *priv,
- struct v4l2_create_buffers *create)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- /* videobuf2 only */
- if (ici->ops->init_videobuf)
- return -EINVAL;
- else
- return vb2_create_bufs(&icd->vb2_vidq, create);
-}
-
-static int soc_camera_prepare_buf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- /* videobuf2 only */
- if (ici->ops->init_videobuf)
- return -EINVAL;
- else
- return vb2_prepare_buf(&icd->vb2_vidq, b);
-}
-
-/* Always entered with .video_lock held */
-static int soc_camera_init_user_formats(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);
- unsigned int i, fmts = 0, raw_fmts = 0;
- int ret;
- enum v4l2_mbus_pixelcode code;
-
- while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
- raw_fmts++;
-
- if (!ici->ops->get_formats)
- /*
- * Fallback mode - the host will have to serve all
- * sensor-provided formats one-to-one to the user
- */
- fmts = raw_fmts;
- else
- /*
- * First pass - only count formats this host-sensor
- * configuration can provide
- */
- for (i = 0; i < raw_fmts; i++) {
- ret = ici->ops->get_formats(icd, i, NULL);
- if (ret < 0)
- return ret;
- fmts += ret;
- }
-
- if (!fmts)
- return -ENXIO;
-
- icd->user_formats =
- vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
- if (!icd->user_formats)
- return -ENOMEM;
-
- dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
-
- /* Second pass - actually fill data formats */
- fmts = 0;
- for (i = 0; i < raw_fmts; i++)
- if (!ici->ops->get_formats) {
- v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
- icd->user_formats[fmts].host_fmt =
- soc_mbus_get_fmtdesc(code);
- if (icd->user_formats[fmts].host_fmt)
- icd->user_formats[fmts++].code = code;
- } else {
- ret = ici->ops->get_formats(icd, i,
- &icd->user_formats[fmts]);
- if (ret < 0)
- goto egfmt;
- fmts += ret;
- }
-
- icd->num_user_formats = fmts;
- icd->current_fmt = &icd->user_formats[0];
-
- return 0;
-
-egfmt:
- vfree(icd->user_formats);
- return ret;
-}
-
-/* Always entered with .video_lock held */
-static void soc_camera_free_user_formats(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- if (ici->ops->put_formats)
- ici->ops->put_formats(icd);
- icd->current_fmt = NULL;
- icd->num_user_formats = 0;
- vfree(icd->user_formats);
- icd->user_formats = NULL;
-}
-
-/* Called with .vb_lock held, or from the first open(2), see comment there */
-static int soc_camera_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int ret;
-
- dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
- pixfmtstr(pix->pixelformat), pix->width, pix->height);
-
- /* We always call try_fmt() before set_fmt() or set_crop() */
- ret = soc_camera_try_fmt(icd, f);
- if (ret < 0)
- return ret;
-
- ret = ici->ops->set_fmt(icd, f);
- if (ret < 0) {
- return ret;
- } else if (!icd->current_fmt ||
- icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
- dev_err(icd->pdev,
- "Host driver hasn't set up current format correctly!\n");
- return -EINVAL;
- }
-
- icd->user_width = pix->width;
- icd->user_height = pix->height;
- icd->bytesperline = pix->bytesperline;
- icd->sizeimage = pix->sizeimage;
- icd->colorspace = pix->colorspace;
- icd->field = pix->field;
- if (ici->ops->init_videobuf)
- icd->vb_vidq.field = pix->field;
-
- dev_dbg(icd->pdev, "set width: %d height: %d\n",
- icd->user_width, icd->user_height);
-
- /* set physical bus parameters */
- return ici->ops->set_bus_param(icd);
-}
-
-static int soc_camera_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
- struct soc_camera_link *icl = to_soc_camera_link(icd);
- struct soc_camera_host *ici;
- int ret;
-
- if (!to_soc_camera_control(icd))
- /* No device driver attached */
- return -ENODEV;
-
- ici = to_soc_camera_host(icd->parent);
-
- if (!try_module_get(ici->ops->owner)) {
- dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
- return -EINVAL;
- }
-
- icd->use_count++;
-
- /* Now we really have to activate the camera */
- if (icd->use_count == 1) {
- /* Restore parameters before the last close() per V4L2 API */
- struct v4l2_format f = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .fmt.pix = {
- .width = icd->user_width,
- .height = icd->user_height,
- .field = icd->field,
- .colorspace = icd->colorspace,
- .pixelformat =
- icd->current_fmt->host_fmt->fourcc,
- },
- };
-
- /* The camera could have been already on, try to reset */
- if (icl->reset)
- icl->reset(icd->pdev);
-
- /* Don't mess with the host during probe */
- mutex_lock(&ici->host_lock);
- ret = ici->ops->add(icd);
- mutex_unlock(&ici->host_lock);
- if (ret < 0) {
- dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
- 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)
- goto eresume;
-
- /*
- * Try to configure with default parameters. Notice: this is the
- * very first open, so, we cannot race against other calls,
- * apart from someone else calling open() simultaneously, but
- * .video_lock is protecting us against it.
- */
- ret = soc_camera_set_fmt(icd, &f);
- if (ret < 0)
- goto esfmt;
-
- if (ici->ops->init_videobuf) {
- ici->ops->init_videobuf(&icd->vb_vidq, icd);
- } else {
- ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd);
- if (ret < 0)
- goto einitvb;
- }
- v4l2_ctrl_handler_setup(&icd->ctrl_handler);
- }
-
- file->private_data = icd;
- dev_dbg(icd->pdev, "camera device open\n");
-
- return 0;
-
- /*
- * First four errors are entered with the .video_lock held
- * and use_count == 1
- */
-einitvb:
-esfmt:
- pm_runtime_disable(&icd->vdev->dev);
-eresume:
- soc_camera_power_off(icd, icl);
-epower:
- ici->ops->remove(icd);
-eiciadd:
- icd->use_count--;
- module_put(ici->ops->owner);
-
- return ret;
-}
-
-static int soc_camera_close(struct file *file)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- icd->use_count--;
- if (!icd->use_count) {
- struct soc_camera_link *icl = to_soc_camera_link(icd);
-
- pm_runtime_suspend(&icd->vdev->dev);
- pm_runtime_disable(&icd->vdev->dev);
-
- if (ici->ops->init_videobuf2)
- vb2_queue_release(&icd->vb2_vidq);
- ici->ops->remove(icd);
-
- soc_camera_power_off(icd, icl);
- }
-
- if (icd->streamer == file)
- icd->streamer = NULL;
-
- module_put(ici->ops->owner);
-
- dev_dbg(icd->pdev, "camera device close\n");
-
- return 0;
-}
-
-static ssize_t soc_camera_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct soc_camera_device *icd = file->private_data;
- int err = -EINVAL;
-
- dev_err(icd->pdev, "camera device read not implemented\n");
-
- return err;
-}
-
-static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- int err;
-
- dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
-
- if (icd->streamer != file)
- return -EBUSY;
-
- if (ici->ops->init_videobuf)
- err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
- else
- err = vb2_mmap(&icd->vb2_vidq, vma);
-
- dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
- err);
-
- return err;
-}
-
-static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- if (icd->streamer != file)
- return -EBUSY;
-
- if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
- dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
- return POLLERR;
- }
-
- return ici->ops->poll(file, pt);
-}
-
-void soc_camera_lock(struct vb2_queue *vq)
-{
- struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- mutex_lock(&icd->video_lock);
-}
-EXPORT_SYMBOL(soc_camera_lock);
-
-void soc_camera_unlock(struct vb2_queue *vq)
-{
- struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- mutex_unlock(&icd->video_lock);
-}
-EXPORT_SYMBOL(soc_camera_unlock);
-
-static struct v4l2_file_operations soc_camera_fops = {
- .owner = THIS_MODULE,
- .open = soc_camera_open,
- .release = soc_camera_close,
- .unlocked_ioctl = video_ioctl2,
- .read = soc_camera_read,
- .mmap = soc_camera_mmap,
- .poll = soc_camera_poll,
-};
-
-static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct soc_camera_device *icd = file->private_data;
- int ret;
-
- WARN_ON(priv != file->private_data);
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type);
- return -EINVAL;
- }
-
- if (icd->streamer && icd->streamer != file)
- return -EBUSY;
-
- if (is_streaming(to_soc_camera_host(icd->parent), icd)) {
- dev_err(icd->pdev, "S_FMT denied: queue initialised\n");
- return -EBUSY;
- }
-
- ret = soc_camera_set_fmt(icd, f);
-
- if (!ret && !icd->streamer)
- icd->streamer = file;
-
- return ret;
-}
-
-static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct soc_camera_device *icd = file->private_data;
- const struct soc_mbus_pixelfmt *format;
-
- WARN_ON(priv != file->private_data);
-
- if (f->index >= icd->num_user_formats)
- return -EINVAL;
-
- format = icd->user_formats[f->index].host_fmt;
-
- if (format->name)
- strlcpy(f->description, format->name, sizeof(f->description));
- f->pixelformat = format->fourcc;
- return 0;
-}
-
-static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- WARN_ON(priv != file->private_data);
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- pix->width = icd->user_width;
- pix->height = icd->user_height;
- pix->bytesperline = icd->bytesperline;
- pix->sizeimage = icd->sizeimage;
- pix->field = icd->field;
- pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
- pix->colorspace = icd->colorspace;
- dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n",
- icd->current_fmt->host_fmt->fourcc);
- return 0;
-}
-
-static int soc_camera_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
- return ici->ops->querycap(ici, cap);
-}
-
-static int soc_camera_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int ret;
-
- WARN_ON(priv != file->private_data);
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (icd->streamer != file)
- return -EBUSY;
-
- /* This calls buf_queue from host driver's videobuf_queue_ops */
- if (ici->ops->init_videobuf)
- ret = videobuf_streamon(&icd->vb_vidq);
- else
- ret = vb2_streamon(&icd->vb2_vidq, i);
-
- if (!ret)
- v4l2_subdev_call(sd, video, s_stream, 1);
-
- return ret;
-}
-
-static int soc_camera_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- WARN_ON(priv != file->private_data);
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (icd->streamer != file)
- return -EBUSY;
-
- /*
- * This calls buf_release from host driver's videobuf_queue_ops for all
- * remaining buffers. When the last buffer is freed, stop capture
- */
- if (ici->ops->init_videobuf)
- videobuf_streamoff(&icd->vb_vidq);
- else
- vb2_streamoff(&icd->vb2_vidq, i);
-
- v4l2_subdev_call(sd, video, s_stream, 0);
-
- return 0;
-}
-
-static int soc_camera_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- return ici->ops->cropcap(icd, a);
-}
-
-static int soc_camera_g_crop(struct file *file, void *fh,
- struct v4l2_crop *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- int ret;
-
- ret = ici->ops->get_crop(icd, a);
-
- return ret;
-}
-
-/*
- * According to the V4L2 API, drivers shall not update the struct v4l2_crop
- * argument with the actual geometry, instead, the user shall use G_CROP to
- * retrieve it.
- */
-static int soc_camera_s_crop(struct file *file, void *fh,
- struct v4l2_crop *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct v4l2_rect *rect = &a->c;
- struct v4l2_crop current_crop;
- int ret;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
- rect->width, rect->height, rect->left, rect->top);
-
- /* If get_crop fails, we'll let host and / or client drivers decide */
- ret = ici->ops->get_crop(icd, &current_crop);
-
- /* Prohibit window size change with initialised buffers */
- if (ret < 0) {
- dev_err(icd->pdev,
- "S_CROP denied: getting current crop failed\n");
- } else if ((a->c.width == current_crop.c.width &&
- a->c.height == current_crop.c.height) ||
- !is_streaming(ici, icd)) {
- /* same size or not streaming - use .set_crop() */
- ret = ici->ops->set_crop(icd, a);
- } else if (ici->ops->set_livecrop) {
- ret = ici->ops->set_livecrop(icd, a);
- } else {
- dev_err(icd->pdev,
- "S_CROP denied: queue initialised and sizes differ\n");
- ret = -EBUSY;
- }
-
- return ret;
-}
-
-static int soc_camera_g_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- if (ici->ops->get_parm)
- return ici->ops->get_parm(icd, a);
-
- return -ENOIOCTLCMD;
-}
-
-static int soc_camera_s_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a)
-{
- struct soc_camera_device *icd = file->private_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-
- if (ici->ops->set_parm)
- return ici->ops->set_parm(icd, a);
-
- return -ENOIOCTLCMD;
-}
-
-static int soc_camera_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *id)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, core, g_chip_ident, id);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int soc_camera_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, core, g_register, reg);
-}
-
-static int soc_camera_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct soc_camera_device *icd = file->private_data;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, core, s_register, reg);
-}
-#endif
-
-static int soc_camera_probe(struct soc_camera_device *icd);
-
-/* So far this function cannot fail */
-static void scan_add_host(struct soc_camera_host *ici)
-{
- struct soc_camera_device *icd;
-
- mutex_lock(&ici->host_lock);
-
- list_for_each_entry(icd, &devices, list) {
- if (icd->iface == ici->nr) {
- int ret;
-
- icd->parent = ici->v4l2_dev.dev;
- ret = soc_camera_probe(icd);
- }
- }
-
- mutex_unlock(&ici->host_lock);
-}
-
-#ifdef CONFIG_I2C_BOARDINFO
-static int soc_camera_init_i2c(struct soc_camera_device *icd,
- struct soc_camera_link *icl)
-{
- struct i2c_client *client;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
- struct v4l2_subdev *subdev;
-
- if (!adap) {
- dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
- icl->i2c_adapter_id);
- goto ei2cga;
- }
-
- icl->board_info->platform_data = icl;
-
- subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- icl->board_info, NULL);
- if (!subdev)
- goto ei2cnd;
-
- client = v4l2_get_subdevdata(subdev);
-
- /* Use to_i2c_client(dev) to recover the i2c client */
- icd->control = &client->dev;
-
- return 0;
-ei2cnd:
- i2c_put_adapter(adap);
-ei2cga:
- return -ENODEV;
-}
-
-static void soc_camera_free_i2c(struct soc_camera_device *icd)
-{
- struct i2c_client *client =
- to_i2c_client(to_soc_camera_control(icd));
- struct i2c_adapter *adap = client->adapter;
-
- icd->control = NULL;
- v4l2_device_unregister_subdev(i2c_get_clientdata(client));
- i2c_unregister_device(client);
- i2c_put_adapter(adap);
-}
-#else
-#define soc_camera_init_i2c(icd, icl) (-ENODEV)
-#define soc_camera_free_i2c(icd) do {} while (0)
-#endif
-
-static int soc_camera_video_start(struct soc_camera_device *icd);
-static int video_dev_create(struct soc_camera_device *icd);
-/* Called during host-driver probe */
-static int soc_camera_probe(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct soc_camera_link *icl = to_soc_camera_link(icd);
- struct device *control = NULL;
- struct v4l2_subdev *sd;
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
-
- /*
- * Currently the subdev with the largest number of controls (13) is
- * ov6550. So let's pick 16 as a hint for the control handler. Note
- * that this is a hint only: too large and you waste some memory, too
- * small and there is a (very) small performance hit when looking up
- * controls in the internal hash.
- */
- ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
- if (ret < 0)
- return ret;
-
- ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
- icl->regulators);
- 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
- * again after initialisation, even though it shouldn't be needed, we
- * don't do any IO here.
- */
- ret = soc_camera_power_on(icd, icl);
- if (ret < 0)
- goto epower;
-
- /* Must have icd->vdev before registering the device */
- ret = video_dev_create(icd);
- if (ret < 0)
- goto evdc;
-
- /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
- if (icl->board_info) {
- ret = soc_camera_init_i2c(icd, icl);
- if (ret < 0)
- goto eadddev;
- } else if (!icl->add_device || !icl->del_device) {
- ret = -EINVAL;
- goto eadddev;
- } else {
- if (icl->module_name)
- ret = request_module(icl->module_name);
-
- ret = icl->add_device(icd);
- if (ret < 0)
- goto eadddev;
-
- /*
- * FIXME: this is racy, have to use driver-binding notification,
- * when it is available
- */
- control = to_soc_camera_control(icd);
- if (!control || !control->driver || !dev_get_drvdata(control) ||
- !try_module_get(control->driver->owner)) {
- icl->del_device(icd);
- ret = -ENODEV;
- goto enodrv;
- }
- }
-
- sd = soc_camera_to_subdev(icd);
- sd->grp_id = soc_camera_grp_id(icd);
- v4l2_set_subdev_hostdata(sd, icd);
-
- if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler))
- goto ectrl;
-
- /* At this point client .probe() should have run already */
- ret = soc_camera_init_user_formats(icd);
- if (ret < 0)
- goto eiufmt;
-
- icd->field = V4L2_FIELD_ANY;
-
- /*
- * ..._video_start() will create a device node, video_register_device()
- * itself is protected against concurrent open() calls, but we also have
- * to protect our data.
- */
- mutex_lock(&icd->video_lock);
-
- ret = soc_camera_video_start(icd);
- if (ret < 0)
- goto evidstart;
-
- ret = v4l2_subdev_call(sd, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- goto esdpwr;
-
- /* Try to improve our guess of a reasonable window format */
- if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
- icd->user_width = mf.width;
- icd->user_height = mf.height;
- icd->colorspace = mf.colorspace;
- icd->field = mf.field;
- }
-
- ici->ops->remove(icd);
-
- soc_camera_power_off(icd, icl);
-
- mutex_unlock(&icd->video_lock);
-
- return 0;
-
-esdpwr:
- video_unregister_device(icd->vdev);
-evidstart:
- mutex_unlock(&icd->video_lock);
- soc_camera_free_user_formats(icd);
-eiufmt:
-ectrl:
- if (icl->board_info) {
- soc_camera_free_i2c(icd);
- } else {
- icl->del_device(icd);
- module_put(control->driver->owner);
- }
-enodrv:
-eadddev:
- video_device_release(icd->vdev);
- icd->vdev = NULL;
-evdc:
- 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);
- return ret;
-}
-
-/*
- * This is called on device_unregister, which only means we have to disconnect
- * from the host, but not remove ourselves from the device list
- */
-static int soc_camera_remove(struct soc_camera_device *icd)
-{
- struct soc_camera_link *icl = to_soc_camera_link(icd);
- struct video_device *vdev = icd->vdev;
-
- BUG_ON(!icd->parent);
-
- v4l2_ctrl_handler_free(&icd->ctrl_handler);
- if (vdev) {
- video_unregister_device(vdev);
- icd->vdev = NULL;
- }
-
- if (icl->board_info) {
- soc_camera_free_i2c(icd);
- } else {
- struct device_driver *drv = to_soc_camera_control(icd)->driver;
- if (drv) {
- icl->del_device(icd);
- module_put(drv->owner);
- }
- }
- soc_camera_free_user_formats(icd);
-
- regulator_bulk_free(icl->num_regulators, icl->regulators);
-
- return 0;
-}
-
-static int default_cropcap(struct soc_camera_device *icd,
- struct v4l2_cropcap *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, cropcap, a);
-}
-
-static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, g_crop, a);
-}
-
-static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, s_crop, a);
-}
-
-static int default_g_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, g_parm, parm);
-}
-
-static int default_s_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, s_parm, parm);
-}
-
-static int default_enum_framesizes(struct soc_camera_device *icd,
- struct v4l2_frmsizeenum *fsize)
-{
- int ret;
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate;
- __u32 pixfmt = fsize->pixel_format;
- struct v4l2_frmsizeenum fsize_mbus = *fsize;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (!xlate)
- return -EINVAL;
- /* map xlate-code to pixel_format, sensor only handle xlate-code*/
- fsize_mbus.pixel_format = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
- if (ret < 0)
- return ret;
-
- *fsize = fsize_mbus;
- fsize->pixel_format = pixfmt;
-
- return 0;
-}
-
-int soc_camera_host_register(struct soc_camera_host *ici)
-{
- struct soc_camera_host *ix;
- int ret;
-
- if (!ici || !ici->ops ||
- !ici->ops->try_fmt ||
- !ici->ops->set_fmt ||
- !ici->ops->set_bus_param ||
- !ici->ops->querycap ||
- ((!ici->ops->init_videobuf ||
- !ici->ops->reqbufs) &&
- !ici->ops->init_videobuf2) ||
- !ici->ops->add ||
- !ici->ops->remove ||
- !ici->ops->poll ||
- !ici->v4l2_dev.dev)
- return -EINVAL;
-
- if (!ici->ops->set_crop)
- ici->ops->set_crop = default_s_crop;
- if (!ici->ops->get_crop)
- ici->ops->get_crop = default_g_crop;
- if (!ici->ops->cropcap)
- ici->ops->cropcap = default_cropcap;
- if (!ici->ops->set_parm)
- ici->ops->set_parm = default_s_parm;
- if (!ici->ops->get_parm)
- ici->ops->get_parm = default_g_parm;
- if (!ici->ops->enum_framesizes)
- ici->ops->enum_framesizes = default_enum_framesizes;
-
- mutex_lock(&list_lock);
- list_for_each_entry(ix, &hosts, list) {
- if (ix->nr == ici->nr) {
- ret = -EBUSY;
- goto edevreg;
- }
- }
-
- ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
- if (ret < 0)
- goto edevreg;
-
- list_add_tail(&ici->list, &hosts);
- mutex_unlock(&list_lock);
-
- mutex_init(&ici->host_lock);
- scan_add_host(ici);
-
- return 0;
-
-edevreg:
- mutex_unlock(&list_lock);
- return ret;
-}
-EXPORT_SYMBOL(soc_camera_host_register);
-
-/* Unregister all clients! */
-void soc_camera_host_unregister(struct soc_camera_host *ici)
-{
- struct soc_camera_device *icd;
-
- mutex_lock(&list_lock);
-
- list_del(&ici->list);
- list_for_each_entry(icd, &devices, list)
- if (icd->iface == ici->nr && to_soc_camera_control(icd))
- soc_camera_remove(icd);
-
- mutex_unlock(&list_lock);
-
- v4l2_device_unregister(&ici->v4l2_dev);
-}
-EXPORT_SYMBOL(soc_camera_host_unregister);
-
-/* Image capture device */
-static int soc_camera_device_register(struct soc_camera_device *icd)
-{
- struct soc_camera_device *ix;
- int num = -1, i;
-
- for (i = 0; i < 256 && num < 0; i++) {
- num = i;
- /* Check if this index is available on this interface */
- list_for_each_entry(ix, &devices, list) {
- if (ix->iface == icd->iface && ix->devnum == i) {
- num = -1;
- break;
- }
- }
- }
-
- if (num < 0)
- /*
- * ok, we have 256 cameras on this host...
- * man, stay reasonable...
- */
- return -ENOMEM;
-
- icd->devnum = num;
- icd->use_count = 0;
- icd->host_priv = NULL;
- mutex_init(&icd->video_lock);
-
- list_add_tail(&icd->list, &devices);
-
- return 0;
-}
-
-static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
- .vidioc_querycap = soc_camera_querycap,
- .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
- .vidioc_enum_input = soc_camera_enum_input,
- .vidioc_g_input = soc_camera_g_input,
- .vidioc_s_input = soc_camera_s_input,
- .vidioc_s_std = soc_camera_s_std,
- .vidioc_g_std = soc_camera_g_std,
- .vidioc_enum_framesizes = soc_camera_enum_framesizes,
- .vidioc_reqbufs = soc_camera_reqbufs,
- .vidioc_querybuf = soc_camera_querybuf,
- .vidioc_qbuf = soc_camera_qbuf,
- .vidioc_dqbuf = soc_camera_dqbuf,
- .vidioc_create_bufs = soc_camera_create_bufs,
- .vidioc_prepare_buf = soc_camera_prepare_buf,
- .vidioc_streamon = soc_camera_streamon,
- .vidioc_streamoff = soc_camera_streamoff,
- .vidioc_cropcap = soc_camera_cropcap,
- .vidioc_g_crop = soc_camera_g_crop,
- .vidioc_s_crop = soc_camera_s_crop,
- .vidioc_g_parm = soc_camera_g_parm,
- .vidioc_s_parm = soc_camera_s_parm,
- .vidioc_g_chip_ident = soc_camera_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = soc_camera_g_register,
- .vidioc_s_register = soc_camera_s_register,
-#endif
-};
-
-static int video_dev_create(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct video_device *vdev = video_device_alloc();
-
- if (!vdev)
- return -ENOMEM;
-
- strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
-
- vdev->parent = icd->pdev;
- vdev->current_norm = V4L2_STD_UNKNOWN;
- vdev->fops = &soc_camera_fops;
- vdev->ioctl_ops = &soc_camera_ioctl_ops;
- vdev->release = video_device_release;
- vdev->tvnorms = V4L2_STD_UNKNOWN;
- vdev->ctrl_handler = &icd->ctrl_handler;
- vdev->lock = &icd->video_lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
-
- icd->vdev = vdev;
-
- return 0;
-}
-
-/*
- * Called from soc_camera_probe() above (with .video_lock held???)
- */
-static int soc_camera_video_start(struct soc_camera_device *icd)
-{
- const struct device_type *type = icd->vdev->dev.type;
- int ret;
-
- if (!icd->parent)
- return -ENODEV;
-
- ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
- return ret;
- }
-
- /* Restore device type, possibly set by the subdevice driver */
- icd->vdev->dev.type = type;
-
- return 0;
-}
-
-static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
-{
- struct soc_camera_link *icl = pdev->dev.platform_data;
- struct soc_camera_device *icd;
- int ret;
-
- if (!icl)
- return -EINVAL;
-
- icd = kzalloc(sizeof(*icd), GFP_KERNEL);
- if (!icd)
- return -ENOMEM;
-
- icd->iface = icl->bus_id;
- icd->link = icl;
- icd->pdev = &pdev->dev;
- platform_set_drvdata(pdev, icd);
-
- ret = soc_camera_device_register(icd);
- if (ret < 0)
- goto escdevreg;
-
- icd->user_width = DEFAULT_WIDTH;
- icd->user_height = DEFAULT_HEIGHT;
-
- return 0;
-
-escdevreg:
- kfree(icd);
-
- return ret;
-}
-
-/*
- * Only called on rmmod for each platform device, since they are not
- * hot-pluggable. Now we know, that all our users - hosts and devices have
- * been unloaded already
- */
-static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
-{
- struct soc_camera_device *icd = platform_get_drvdata(pdev);
-
- if (!icd)
- return -EINVAL;
-
- list_del(&icd->list);
-
- kfree(icd);
-
- return 0;
-}
-
-static struct platform_driver __refdata soc_camera_pdrv = {
- .probe = soc_camera_pdrv_probe,
- .remove = __devexit_p(soc_camera_pdrv_remove),
- .driver = {
- .name = "soc-camera-pdrv",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init soc_camera_init(void)
-{
- return platform_driver_register(&soc_camera_pdrv);
-}
-
-static void __exit soc_camera_exit(void)
-{
- platform_driver_unregister(&soc_camera_pdrv);
-}
-
-module_init(soc_camera_init);
-module_exit(soc_camera_exit);
-
-MODULE_DESCRIPTION("Image capture bus driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:soc-camera-pdrv");
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
deleted file mode 100644
index f59ccade07c8..000000000000
--- a/drivers/media/video/soc_camera_platform.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Generic Platform Camera Driver
- *
- * Copyright (C) 2008 Magnus Damm
- * Based on mt9m001 driver,
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-subdev.h>
-#include <media/soc_camera.h>
-#include <media/soc_camera_platform.h>
-
-struct soc_camera_platform_priv {
- struct v4l2_subdev subdev;
-};
-
-static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
-{
- struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
- return container_of(subdev, struct soc_camera_platform_priv, subdev);
-}
-
-static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
- return p->set_capture(p, enable);
-}
-
-static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- mf->width = p->format.width;
- mf->height = p->format.height;
- mf->code = p->format.code;
- mf->colorspace = p->format.colorspace;
- mf->field = p->format.field;
-
- return 0;
-}
-
-static struct v4l2_subdev_core_ops platform_subdev_core_ops;
-
-static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- if (index)
- return -EINVAL;
-
- *code = p->format.code;
- return 0;
-}
-
-static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
- struct v4l2_crop *a)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = p->format.width;
- a->c.height = p->format.height;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
- struct v4l2_cropcap *a)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = p->format.width;
- a->bounds.height = p->format.height;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
-
- cfg->flags = p->mbus_param;
- cfg->type = p->mbus_type;
-
- return 0;
-}
-
-static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
- .s_stream = soc_camera_platform_s_stream,
- .enum_mbus_fmt = soc_camera_platform_enum_fmt,
- .cropcap = soc_camera_platform_cropcap,
- .g_crop = soc_camera_platform_g_crop,
- .try_mbus_fmt = soc_camera_platform_fill_fmt,
- .g_mbus_fmt = soc_camera_platform_fill_fmt,
- .s_mbus_fmt = soc_camera_platform_fill_fmt,
- .g_mbus_config = soc_camera_platform_g_mbus_config,
-};
-
-static struct v4l2_subdev_ops platform_subdev_ops = {
- .core = &platform_subdev_core_ops,
- .video = &platform_subdev_video_ops,
-};
-
-static int soc_camera_platform_probe(struct platform_device *pdev)
-{
- struct soc_camera_host *ici;
- struct soc_camera_platform_priv *priv;
- struct soc_camera_platform_info *p = pdev->dev.platform_data;
- struct soc_camera_device *icd;
- int ret;
-
- if (!p)
- return -EINVAL;
-
- if (!p->icd) {
- dev_err(&pdev->dev,
- "Platform has not set soc_camera_device pointer!\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- icd = p->icd;
-
- /* soc-camera convention: control's drvdata points to the subdev */
- platform_set_drvdata(pdev, &priv->subdev);
- /* Set the control device reference */
- icd->control = &pdev->dev;
-
- ici = to_soc_camera_host(icd->parent);
-
- v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
- v4l2_set_subdevdata(&priv->subdev, p);
- strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
-
- ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
- if (ret)
- goto evdrs;
-
- return ret;
-
-evdrs:
- platform_set_drvdata(pdev, NULL);
- kfree(priv);
- return ret;
-}
-
-static int soc_camera_platform_remove(struct platform_device *pdev)
-{
- struct soc_camera_platform_priv *priv = get_priv(pdev);
- struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev);
-
- p->icd->control = NULL;
- v4l2_device_unregister_subdev(&priv->subdev);
- platform_set_drvdata(pdev, NULL);
- kfree(priv);
- return 0;
-}
-
-static struct platform_driver soc_camera_platform_driver = {
- .driver = {
- .name = "soc_camera_platform",
- .owner = THIS_MODULE,
- },
- .probe = soc_camera_platform_probe,
- .remove = soc_camera_platform_remove,
-};
-
-module_platform_driver(soc_camera_platform_driver);
-
-MODULE_DESCRIPTION("SoC Camera Platform driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:soc_camera_platform");
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
deleted file mode 100644
index 462caa44ae00..000000000000
--- a/drivers/media/video/tcm825x.c
+++ /dev/null
@@ -1,937 +0,0 @@
-/*
- * drivers/media/video/tcm825x.c
- *
- * TCM825X camera sensor driver.
- *
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from David Cohen <david.cohen@indt.org.br>
- *
- * This driver was based on ov9640 sensor driver from MontaVista
- *
- * 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/i2c.h>
-#include <linux/module.h>
-#include <media/v4l2-int-device.h>
-
-#include "tcm825x.h"
-
-/*
- * The sensor has two fps modes: the lower one just gives half the fps
- * at the same xclk than the high one.
- */
-#define MAX_FPS 30
-#define MIN_FPS 8
-#define MAX_HALF_FPS (MAX_FPS / 2)
-#define HIGH_FPS_MODE_LOWER_LIMIT 14
-#define DEFAULT_FPS MAX_HALF_FPS
-
-struct tcm825x_sensor {
- const struct tcm825x_platform_data *platform_data;
- struct v4l2_int_device *v4l2_int_device;
- struct i2c_client *i2c_client;
- struct v4l2_pix_format pix;
- struct v4l2_fract timeperframe;
-};
-
-/* list of image formats supported by TCM825X sensor */
-static const struct v4l2_fmtdesc tcm825x_formats[] = {
- {
- .description = "YUYV (YUV 4:2:2), packed",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- }, {
- /* Note: V4L2 defines RGB565 as:
- *
- * Byte 0 Byte 1
- * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
- *
- * We interpret RGB565 as:
- *
- * Byte 0 Byte 1
- * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
- */
- .description = "RGB565, le",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- },
-};
-
-#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
-
-/*
- * TCM825X register configuration for all combinations of pixel format and
- * image size
- */
-static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
-static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
-static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
-static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
-static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
-static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
-
-static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
-static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
-
-/* Our own specific controls */
-#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
-#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
-#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
-#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
-#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
-#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
-
-/* Video controls */
-static struct vcontrol {
- struct v4l2_queryctrl qc;
- u16 reg;
- u16 start_bit;
-} video_control[] = {
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 63,
- .step = 1,
- },
- .reg = TCM825X_AG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- },
- .reg = TCM825X_MRG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- },
- .reg = TCM825X_MBG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto White Balance",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_AWBSW,
- .start_bit = 7,
- },
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure Time",
- .minimum = 0,
- .maximum = 0x1fff,
- .step = 1,
- },
- .reg = TCM825X_ESRSPD_U,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror Image",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_H_INV,
- .start_bit = 6,
- },
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_V_INV,
- .start_bit = 7,
- },
- /* Private controls */
- {
- {
- .id = V4L2_CID_ALC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Luminance Control",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_ALCSW,
- .start_bit = 7,
- },
- {
- {
- .id = V4L2_CID_H_EDGE_EN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Horizontal Edge Enhancement",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- },
- .reg = TCM825X_HDTG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_V_EDGE_EN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical Edge Enhancement",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- },
- .reg = TCM825X_VDTG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_LENS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Lens Shading Compensation",
- .minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- },
- .reg = TCM825X_LENS,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_MAX_EXPOSURE_TIME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Maximum Exposure Time",
- .minimum = 0,
- .maximum = 0x3,
- .step = 1,
- },
- .reg = TCM825X_ESRLIM,
- .start_bit = 5,
- },
-};
-
-
-static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
-{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
-
-static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
-{ &yuv422, &rgb565 };
-
-/*
- * Read a value from a register in an TCM825X sensor device. The value is
- * returned in 'val'.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_read_reg(struct i2c_client *client, int reg)
-{
- int err;
- struct i2c_msg msg[2];
- u8 reg_buf, data_buf = 0;
-
- if (!client->adapter)
- return -ENODEV;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = &reg_buf;
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 1;
- msg[1].buf = &data_buf;
-
- reg_buf = reg;
-
- err = i2c_transfer(client->adapter, msg, 2);
- if (err < 0)
- return err;
- return data_buf;
-}
-
-/*
- * Write a value to a register in an TCM825X sensor device.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
-{
- int err;
- struct i2c_msg msg[1];
- unsigned char data[2];
-
- if (!client->adapter)
- return -ENODEV;
-
- msg->addr = client->addr;
- msg->flags = 0;
- msg->len = 2;
- msg->buf = data;
- data[0] = reg;
- data[1] = val;
- err = i2c_transfer(client->adapter, msg, 1);
- if (err >= 0)
- return 0;
- return err;
-}
-
-static int __tcm825x_write_reg_mask(struct i2c_client *client,
- u8 reg, u8 val, u8 mask)
-{
- int rc;
-
- /* need to do read - modify - write */
- rc = tcm825x_read_reg(client, reg);
- if (rc < 0)
- return rc;
-
- rc &= (~mask); /* Clear the masked bits */
- val &= mask; /* Enforce mask on value */
- val |= rc;
-
- /* write the new value to the register */
- rc = tcm825x_write_reg(client, reg, val);
- if (rc)
- return rc;
-
- return 0;
-}
-
-#define tcm825x_write_reg_mask(client, regmask, val) \
- __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
- TCM825X_MASK((regmask)))
-
-
-/*
- * Initialize a list of TCM825X registers.
- * The list of registers is terminated by the pair of values
- * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_write_default_regs(struct i2c_client *client,
- const struct tcm825x_reg *reglist)
-{
- int err;
- const struct tcm825x_reg *next = reglist;
-
- while (!((next->reg == TCM825X_REG_TERM)
- && (next->val == TCM825X_VAL_TERM))) {
- err = tcm825x_write_reg(client, next->reg, next->val);
- if (err) {
- dev_err(&client->dev, "register writing failed\n");
- return err;
- }
- next++;
- }
-
- return 0;
-}
-
-static struct vcontrol *find_vctrl(int id)
-{
- int i;
-
- if (id < V4L2_CID_BASE)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(video_control); i++)
- if (video_control[i].qc.id == id)
- return &video_control[i];
-
- return NULL;
-}
-
-/*
- * Find the best match for a requested image capture size. The best match
- * is chosen as the nearest match that has the same number or fewer pixels
- * as the requested size, or the smallest image size if the requested size
- * has fewer pixels than the smallest image.
- */
-static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
- unsigned int width,
- unsigned int height)
-{
- enum image_size isize;
- unsigned long pixels = width * height;
- struct tcm825x_sensor *sensor = s->priv;
-
- for (isize = subQCIF; isize < VGA; isize++) {
- if (tcm825x_sizes[isize + 1].height
- * tcm825x_sizes[isize + 1].width > pixels) {
- dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
-
- return isize;
- }
- }
-
- dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
-
- return VGA;
-}
-
-/*
- * Configure the TCM825X for current image size, pixel format, and
- * frame period. fper is the frame period (in seconds) expressed as a
- * fraction. Returns zero if successful, or non-zero otherwise. The
- * actual frame period is returned in fper.
- */
-static int tcm825x_configure(struct v4l2_int_device *s)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_pix_format *pix = &sensor->pix;
- enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
- struct v4l2_fract *fper = &sensor->timeperframe;
- enum pixel_format pfmt;
- int err;
- u32 tgt_fps;
- u8 val;
-
- /* common register initialization */
- err = tcm825x_write_default_regs(
- sensor->i2c_client, sensor->platform_data->default_regs());
- if (err)
- return err;
-
- /* configure image size */
- val = tcm825x_siz_reg[isize]->val;
- dev_dbg(&sensor->i2c_client->dev,
- "configuring image size %d\n", isize);
- err = tcm825x_write_reg_mask(sensor->i2c_client,
- tcm825x_siz_reg[isize]->reg, val);
- if (err)
- return err;
-
- /* configure pixel format */
- switch (pix->pixelformat) {
- default:
- case V4L2_PIX_FMT_RGB565:
- pfmt = RGB565;
- break;
- case V4L2_PIX_FMT_UYVY:
- pfmt = YUV422;
- break;
- }
-
- dev_dbg(&sensor->i2c_client->dev,
- "configuring pixel format %d\n", pfmt);
- val = tcm825x_fmt_reg[pfmt]->val;
-
- err = tcm825x_write_reg_mask(sensor->i2c_client,
- tcm825x_fmt_reg[pfmt]->reg, val);
- if (err)
- return err;
-
- /*
- * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
- * set. Frame rate will be halved from the normal.
- */
- tgt_fps = fper->denominator / fper->numerator;
- if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
- val = tcm825x_read_reg(sensor->i2c_client, 0x02);
- val |= 0x80;
- tcm825x_write_reg(sensor->i2c_client, 0x02, val);
- }
-
- return 0;
-}
-
-static int ioctl_queryctrl(struct v4l2_int_device *s,
- struct v4l2_queryctrl *qc)
-{
- struct vcontrol *control;
-
- control = find_vctrl(qc->id);
-
- if (control == NULL)
- return -EINVAL;
-
- *qc = control->qc;
-
- return 0;
-}
-
-static int ioctl_g_ctrl(struct v4l2_int_device *s,
- struct v4l2_control *vc)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
- int val, r;
- struct vcontrol *lvc;
-
- /* exposure time is special, spread across 2 registers */
- if (vc->id == V4L2_CID_EXPOSURE) {
- int val_lower, val_upper;
-
- val_upper = tcm825x_read_reg(client,
- TCM825X_ADDR(TCM825X_ESRSPD_U));
- if (val_upper < 0)
- return val_upper;
- val_lower = tcm825x_read_reg(client,
- TCM825X_ADDR(TCM825X_ESRSPD_L));
- if (val_lower < 0)
- return val_lower;
-
- vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
- return 0;
- }
-
- lvc = find_vctrl(vc->id);
- if (lvc == NULL)
- return -EINVAL;
-
- r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
- if (r < 0)
- return r;
- val = r & TCM825X_MASK(lvc->reg);
- val >>= lvc->start_bit;
-
- if (val < 0)
- return val;
-
- if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
- val ^= sensor->platform_data->is_upside_down();
-
- vc->value = val;
- return 0;
-}
-
-static int ioctl_s_ctrl(struct v4l2_int_device *s,
- struct v4l2_control *vc)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
- struct vcontrol *lvc;
- int val = vc->value;
-
- /* exposure time is special, spread across 2 registers */
- if (vc->id == V4L2_CID_EXPOSURE) {
- int val_lower, val_upper;
- val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
- val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
-
- if (tcm825x_write_reg_mask(client,
- TCM825X_ESRSPD_U, val_upper))
- return -EIO;
-
- if (tcm825x_write_reg_mask(client,
- TCM825X_ESRSPD_L, val_lower))
- return -EIO;
-
- return 0;
- }
-
- lvc = find_vctrl(vc->id);
- if (lvc == NULL)
- return -EINVAL;
-
- if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
- val ^= sensor->platform_data->is_upside_down();
-
- val = val << lvc->start_bit;
- if (tcm825x_write_reg_mask(client, lvc->reg, val))
- return -EIO;
-
- return 0;
-}
-
-static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_fmtdesc *fmt)
-{
- int index = fmt->index;
-
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index >= TCM825X_NUM_CAPTURE_FORMATS)
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- }
-
- fmt->flags = tcm825x_formats[index].flags;
- strlcpy(fmt->description, tcm825x_formats[index].description,
- sizeof(fmt->description));
- fmt->pixelformat = tcm825x_formats[index].pixelformat;
-
- return 0;
-}
-
-static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
- enum image_size isize;
- int ifmt;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- isize = tcm825x_find_size(s, pix->width, pix->height);
- dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
- isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
-
- pix->width = tcm825x_sizes[isize].width;
- pix->height = tcm825x_sizes[isize].height;
-
- for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
- if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
- break;
-
- if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
- ifmt = 0; /* Default = YUV 4:2:2 */
-
- pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
- pix->sizeimage = pix->bytesperline * pix->height;
- pix->priv = 0;
- dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
- pix->pixelformat);
-
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_UYVY:
- default:
- pix->colorspace = V4L2_COLORSPACE_JPEG;
- break;
- case V4L2_PIX_FMT_RGB565:
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- }
-
- return 0;
-}
-
-static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int rval;
-
- rval = ioctl_try_fmt_cap(s, f);
- if (rval)
- return rval;
-
- rval = tcm825x_configure(s);
-
- sensor->pix = *pix;
-
- return rval;
-}
-
-static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- f->fmt.pix = sensor->pix;
-
- return 0;
-}
-
-static int ioctl_g_parm(struct v4l2_int_device *s,
- struct v4l2_streamparm *a)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_captureparm *cparm = &a->parm.capture;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(a, 0, sizeof(*a));
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- cparm->capability = V4L2_CAP_TIMEPERFRAME;
- cparm->timeperframe = sensor->timeperframe;
-
- return 0;
-}
-
-static int ioctl_s_parm(struct v4l2_int_device *s,
- struct v4l2_streamparm *a)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
- u32 tgt_fps; /* target frames per secound */
- int rval;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if ((timeperframe->numerator == 0)
- || (timeperframe->denominator == 0)) {
- timeperframe->denominator = DEFAULT_FPS;
- timeperframe->numerator = 1;
- }
-
- tgt_fps = timeperframe->denominator / timeperframe->numerator;
-
- if (tgt_fps > MAX_FPS) {
- timeperframe->denominator = MAX_FPS;
- timeperframe->numerator = 1;
- } else if (tgt_fps < MIN_FPS) {
- timeperframe->denominator = MIN_FPS;
- timeperframe->numerator = 1;
- }
-
- sensor->timeperframe = *timeperframe;
-
- rval = tcm825x_configure(s);
-
- return rval;
-}
-
-static int ioctl_s_power(struct v4l2_int_device *s, int on)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- return sensor->platform_data->power_set(on);
-}
-
-/*
- * Given the image capture format in pix, the nominal frame period in
- * timeperframe, calculate the required xclk frequency.
- *
- * TCM825X input frequency characteristics are:
- * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
- */
-
-static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_fract *timeperframe = &sensor->timeperframe;
- u32 tgt_xclk; /* target xclk */
- u32 tgt_fps; /* target frames per secound */
- int rval;
-
- rval = sensor->platform_data->ifparm(p);
- if (rval)
- return rval;
-
- tgt_fps = timeperframe->denominator / timeperframe->numerator;
-
- tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
- (2457 * tgt_fps) / MAX_HALF_FPS :
- (2457 * tgt_fps) / MAX_FPS;
- tgt_xclk *= 10000;
-
- tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
- tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
-
- p->u.bt656.clock_curr = tgt_xclk;
-
- return 0;
-}
-
-static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
-}
-
-static int ioctl_reset(struct v4l2_int_device *s)
-{
- return -EBUSY;
-}
-
-static int ioctl_init(struct v4l2_int_device *s)
-{
- return tcm825x_configure(s);
-}
-
-static int ioctl_dev_exit(struct v4l2_int_device *s)
-{
- return 0;
-}
-
-static int ioctl_dev_init(struct v4l2_int_device *s)
-{
- struct tcm825x_sensor *sensor = s->priv;
- int r;
-
- r = tcm825x_read_reg(sensor->i2c_client, 0x01);
- if (r < 0)
- return r;
- if (r == 0) {
- dev_err(&sensor->i2c_client->dev, "device not detected\n");
- return -EIO;
- }
- return 0;
-}
-
-static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
- { vidioc_int_dev_init_num,
- (v4l2_int_ioctl_func *)ioctl_dev_init },
- { vidioc_int_dev_exit_num,
- (v4l2_int_ioctl_func *)ioctl_dev_exit },
- { vidioc_int_s_power_num,
- (v4l2_int_ioctl_func *)ioctl_s_power },
- { vidioc_int_g_ifparm_num,
- (v4l2_int_ioctl_func *)ioctl_g_ifparm },
- { vidioc_int_g_needs_reset_num,
- (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
- { vidioc_int_reset_num,
- (v4l2_int_ioctl_func *)ioctl_reset },
- { vidioc_int_init_num,
- (v4l2_int_ioctl_func *)ioctl_init },
- { vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
- { vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
- { vidioc_int_g_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
- { vidioc_int_s_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
- { vidioc_int_g_parm_num,
- (v4l2_int_ioctl_func *)ioctl_g_parm },
- { vidioc_int_s_parm_num,
- (v4l2_int_ioctl_func *)ioctl_s_parm },
- { vidioc_int_queryctrl_num,
- (v4l2_int_ioctl_func *)ioctl_queryctrl },
- { vidioc_int_g_ctrl_num,
- (v4l2_int_ioctl_func *)ioctl_g_ctrl },
- { vidioc_int_s_ctrl_num,
- (v4l2_int_ioctl_func *)ioctl_s_ctrl },
-};
-
-static struct v4l2_int_slave tcm825x_slave = {
- .ioctls = tcm825x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
-};
-
-static struct tcm825x_sensor tcm825x;
-
-static struct v4l2_int_device tcm825x_int_device = {
- .module = THIS_MODULE,
- .name = TCM825X_NAME,
- .priv = &tcm825x,
- .type = v4l2_int_type_slave,
- .u = {
- .slave = &tcm825x_slave,
- },
-};
-
-static int tcm825x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct tcm825x_sensor *sensor = &tcm825x;
-
- if (i2c_get_clientdata(client))
- return -EBUSY;
-
- sensor->platform_data = client->dev.platform_data;
-
- if (sensor->platform_data == NULL
- || !sensor->platform_data->is_okay())
- return -ENODEV;
-
- sensor->v4l2_int_device = &tcm825x_int_device;
-
- sensor->i2c_client = client;
- i2c_set_clientdata(client, sensor);
-
- /* Make the default capture format QVGA RGB565 */
- sensor->pix.width = tcm825x_sizes[QVGA].width;
- sensor->pix.height = tcm825x_sizes[QVGA].height;
- sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
-
- return v4l2_int_device_register(sensor->v4l2_int_device);
-}
-
-static int tcm825x_remove(struct i2c_client *client)
-{
- struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
-
- if (!client->adapter)
- return -ENODEV; /* our client isn't attached */
-
- v4l2_int_device_unregister(sensor->v4l2_int_device);
-
- return 0;
-}
-
-static const struct i2c_device_id tcm825x_id[] = {
- { "tcm825x", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tcm825x_id);
-
-static struct i2c_driver tcm825x_i2c_driver = {
- .driver = {
- .name = TCM825X_NAME,
- },
- .probe = tcm825x_probe,
- .remove = tcm825x_remove,
- .id_table = tcm825x_id,
-};
-
-static struct tcm825x_sensor tcm825x = {
- .timeperframe = {
- .numerator = 1,
- .denominator = DEFAULT_FPS,
- },
-};
-
-static int __init tcm825x_init(void)
-{
- int rval;
-
- rval = i2c_add_driver(&tcm825x_i2c_driver);
- if (rval)
- printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
- __func__);
-
- return rval;
-}
-
-static void __exit tcm825x_exit(void)
-{
- i2c_del_driver(&tcm825x_i2c_driver);
-}
-
-/*
- * FIXME: Menelaus isn't ready (?) at module_init stage, so use
- * late_initcall for now.
- */
-late_initcall(tcm825x_init);
-module_exit(tcm825x_exit);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
-MODULE_DESCRIPTION("TCM825x camera sensor driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
deleted file mode 100644
index 5b7e69682368..000000000000
--- a/drivers/media/video/tcm825x.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * drivers/media/video/tcm825x.h
- *
- * Register definitions for the TCM825X CameraChip.
- *
- * Author: David Cohen (david.cohen@indt.org.br)
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file was based on ov9640.h from MontaVista
- */
-
-#ifndef TCM825X_H
-#define TCM825X_H
-
-#include <linux/videodev2.h>
-
-#include <media/v4l2-int-device.h>
-
-#define TCM825X_NAME "tcm825x"
-
-#define TCM825X_MASK(x) x & 0x00ff
-#define TCM825X_ADDR(x) (x & 0xff00) >> 8
-
-/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
-#define TCM825X_I2C_ADDR 0x3d
-
-/*
- * define register offsets for the TCM825X sensor chip
- * OFFSET(8 bits) + MASK(8 bits)
- * MASK bit 4 and 3 are used when the register uses more than one address
- */
-#define TCM825X_FPS 0x0280
-#define TCM825X_ACF 0x0240
-#define TCM825X_DOUTBUF 0x020C
-#define TCM825X_DCLKP 0x0202
-#define TCM825X_ACFDET 0x0201
-#define TCM825X_DOUTSW 0x0380
-#define TCM825X_DATAHZ 0x0340
-#define TCM825X_PICSIZ 0x033c
-#define TCM825X_PICFMT 0x0302
-#define TCM825X_V_INV 0x0480
-#define TCM825X_H_INV 0x0440
-#define TCM825X_ESRLSW 0x0430
-#define TCM825X_V_LENGTH 0x040F
-#define TCM825X_ALCSW 0x0580
-#define TCM825X_ESRLIM 0x0560
-#define TCM825X_ESRSPD_U 0x051F
-#define TCM825X_ESRSPD_L 0x06FF
-#define TCM825X_AG 0x07FF
-#define TCM825X_ESRSPD2 0x06FF
-#define TCM825X_ALCMODE 0x0830
-#define TCM825X_ALCH 0x080F
-#define TCM825X_ALCL 0x09FF
-#define TCM825X_AWBSW 0x0A80
-#define TCM825X_MRG 0x0BFF
-#define TCM825X_MBG 0x0CFF
-#define TCM825X_GAMSW 0x0D80
-#define TCM825X_HDTG 0x0EFF
-#define TCM825X_VDTG 0x0FFF
-#define TCM825X_HDTCORE 0x10F0
-#define TCM825X_VDTCORE 0x100F
-#define TCM825X_CONT 0x11FF
-#define TCM825X_BRIGHT 0x12FF
-#define TCM825X_VHUE 0x137F
-#define TCM825X_UHUE 0x147F
-#define TCM825X_VGAIN 0x153F
-#define TCM825X_UGAIN 0x163F
-#define TCM825X_UVCORE 0x170F
-#define TCM825X_SATU 0x187F
-#define TCM825X_MHMODE 0x1980
-#define TCM825X_MHLPFSEL 0x1940
-#define TCM825X_YMODE 0x1930
-#define TCM825X_MIXHG 0x1907
-#define TCM825X_LENS 0x1A3F
-#define TCM825X_AGLIM 0x1BE0
-#define TCM825X_LENSRPOL 0x1B10
-#define TCM825X_LENSRGAIN 0x1B0F
-#define TCM825X_ES100S 0x1CFF
-#define TCM825X_ES120S 0x1DFF
-#define TCM825X_DMASK 0x1EC0
-#define TCM825X_CODESW 0x1E20
-#define TCM825X_CODESEL 0x1E10
-#define TCM825X_TESPIC 0x1E04
-#define TCM825X_PICSEL 0x1E03
-#define TCM825X_HNUM 0x20FF
-#define TCM825X_VOUTPH 0x287F
-#define TCM825X_ESROUT 0x327F
-#define TCM825X_ESROUT2 0x33FF
-#define TCM825X_AGOUT 0x34FF
-#define TCM825X_DGOUT 0x353F
-#define TCM825X_AGSLOW1 0x39C0
-#define TCM825X_FLLSMODE 0x3930
-#define TCM825X_FLLSLIM 0x390F
-#define TCM825X_DETSEL 0x3AF0
-#define TCM825X_ACDETNC 0x3A0F
-#define TCM825X_AGSLOW2 0x3BC0
-#define TCM825X_DG 0x3B3F
-#define TCM825X_REJHLEV 0x3CFF
-#define TCM825X_ALCLOCK 0x3D80
-#define TCM825X_FPSLNKSW 0x3D40
-#define TCM825X_ALCSPD 0x3D30
-#define TCM825X_REJH 0x3D03
-#define TCM825X_SHESRSW 0x3E80
-#define TCM825X_ESLIMSEL 0x3E40
-#define TCM825X_SHESRSPD 0x3E30
-#define TCM825X_ELSTEP 0x3E0C
-#define TCM825X_ELSTART 0x3E03
-#define TCM825X_AGMIN 0x3FFF
-#define TCM825X_PREGRG 0x423F
-#define TCM825X_PREGBG 0x433F
-#define TCM825X_PRERG 0x443F
-#define TCM825X_PREBG 0x453F
-#define TCM825X_MSKBR 0x477F
-#define TCM825X_MSKGR 0x487F
-#define TCM825X_MSKRB 0x497F
-#define TCM825X_MSKGB 0x4A7F
-#define TCM825X_MSKRG 0x4B7F
-#define TCM825X_MSKBG 0x4C7F
-#define TCM825X_HDTCSW 0x4D80
-#define TCM825X_VDTCSW 0x4D40
-#define TCM825X_DTCYL 0x4D3F
-#define TCM825X_HDTPSW 0x4E80
-#define TCM825X_VDTPSW 0x4E40
-#define TCM825X_DTCGAIN 0x4E3F
-#define TCM825X_DTLLIMSW 0x4F10
-#define TCM825X_DTLYLIM 0x4F0F
-#define TCM825X_YLCUTLMSK 0x5080
-#define TCM825X_YLCUTL 0x503F
-#define TCM825X_YLCUTHMSK 0x5180
-#define TCM825X_YLCUTH 0x513F
-#define TCM825X_UVSKNC 0x527F
-#define TCM825X_UVLJ 0x537F
-#define TCM825X_WBGMIN 0x54FF
-#define TCM825X_WBGMAX 0x55FF
-#define TCM825X_WBSPDUP 0x5603
-#define TCM825X_ALLAREA 0x5820
-#define TCM825X_WBLOCK 0x5810
-#define TCM825X_WB2SP 0x580F
-#define TCM825X_KIZUSW 0x5920
-#define TCM825X_PBRSW 0x5910
-#define TCM825X_ABCSW 0x5903
-#define TCM825X_PBDLV 0x5AFF
-#define TCM825X_PBC1LV 0x5BFF
-
-#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
-
-#define TCM825X_BYTES_PER_PIXEL 2
-
-#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
-#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
-
-/* define a structure for tcm825x register initialization values */
-struct tcm825x_reg {
- u8 val;
- u16 reg;
-};
-
-enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
-enum pixel_format { YUV422 = 0, RGB565 };
-#define NUM_IMAGE_SIZES 6
-#define NUM_PIXEL_FORMATS 2
-
-#define TCM825X_XCLK_MIN 11900000
-#define TCM825X_XCLK_MAX 25000000
-
-struct capture_size {
- unsigned long width;
- unsigned long height;
-};
-
-struct tcm825x_platform_data {
- /* Is the sensor usable? Doesn't yet mean it's there, but you
- * can try! */
- int (*is_okay)(void);
- /* Set power state, zero is off, non-zero is on. */
- int (*power_set)(int power);
- /* Default registers written after power-on or reset. */
- const struct tcm825x_reg *(*default_regs)(void);
- int (*needs_reset)(struct v4l2_int_device *s, void *buf,
- struct v4l2_pix_format *fmt);
- int (*ifparm)(struct v4l2_ifparm *p);
- int (*is_upside_down)(void);
-};
-
-/* Array of image sizes supported by TCM825X. These must be ordered from
- * smallest image size to largest.
- */
-static const struct capture_size tcm825x_sizes[] = {
- { 128, 96 }, /* subQCIF */
- { 160, 120 }, /* QQVGA */
- { 176, 144 }, /* QCIF */
- { 320, 240 }, /* QVGA */
- { 352, 288 }, /* CIF */
- { 640, 480 }, /* VGA */
-};
-
-#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile
deleted file mode 100644
index ea09b9af2d30..000000000000
--- a/drivers/media/video/tlg2300/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
-
-obj-$(CONFIG_VIDEO_TLG2300) += poseidon.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
-
diff --git a/drivers/media/video/tm6000/Makefile b/drivers/media/video/tm6000/Makefile
deleted file mode 100644
index 395515b4a888..000000000000
--- a/drivers/media/video/tm6000/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-tm6000-y := tm6000-cards.o \
- tm6000-core.o \
- tm6000-i2c.o \
- tm6000-video.o \
- tm6000-stds.o \
- tm6000-input.o
-
-obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
-obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
-obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-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
diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c
deleted file mode 100644
index bd07ec707956..000000000000
--- a/drivers/media/video/tm6000/tm6000-alsa.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- *
- * Support for audio capture for tm5600/6000/6010
- * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * Based on cx88-alsa.c
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <linux/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-#undef dprintk
-
-#define dprintk(level, fmt, arg...) do { \
- if (debug >= level) \
- printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
- } while (0)
-
-/****************************************************************************
- Module global static vars
- ****************************************************************************/
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-
-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.");
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
-
-
-/****************************************************************************
- Module macros
- ****************************************************************************/
-
-MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
- "{{Trident,tm6000},"
- "{{Trident,tm6010}");
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-/****************************************************************************
- Module specific funtions
- ****************************************************************************/
-
-/*
- * BOARD Specific: Sets audio DMA
- */
-
-static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
-{
- struct tm6000_core *core = chip->core;
-
- dprintk(1, "Starting audio DMA\n");
-
- /* Enables audio */
- tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
-
- tm6000_set_audio_bitrate(core, 48000);
-
- return 0;
-}
-
-/*
- * BOARD Specific: Resets audio DMA
- */
-static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
-{
- struct tm6000_core *core = chip->core;
-
- dprintk(1, "Stopping audio DMA\n");
-
- /* Disables audio */
- tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
-
- return 0;
-}
-
-static void dsp_buffer_free(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- dprintk(2, "Freeing buffer\n");
-
- vfree(substream->runtime->dma_area);
- substream->runtime->dma_area = NULL;
- substream->runtime->dma_bytes = 0;
-}
-
-static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- dprintk(2, "Allocating buffer\n");
-
- if (substream->runtime->dma_area) {
- if (substream->runtime->dma_bytes > size)
- return 0;
-
- dsp_buffer_free(substream);
- }
-
- substream->runtime->dma_area = vmalloc(size);
- if (!substream->runtime->dma_area)
- return -ENOMEM;
-
- substream->runtime->dma_bytes = size;
-
- return 0;
-}
-
-
-/****************************************************************************
- ALSA PCM Interface
- ****************************************************************************/
-
-/*
- * Digital hardware definition
- */
-#define DEFAULT_FIFO_SIZE 4096
-
-static struct snd_pcm_hardware snd_tm6000_digital_hw = {
- .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 | 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 = 2,
- .periods_max = 98,
- .buffer_bytes_max = 62720 * 8,
-};
-
-/*
- * audio pcm capture open callback
- */
-static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- err = snd_pcm_hw_constraint_pow2(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0)
- goto _error;
-
- chip->substream = substream;
-
- runtime->hw = snd_tm6000_digital_hw;
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-
- return 0;
-_error:
- dprintk(1, "Error opening PCM!\n");
- return err;
-}
-
-/*
- * audio close callback
- */
-static int snd_tm6000_close(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct tm6000_core *core = chip->core;
-
- if (atomic_read(&core->stream_started) > 0) {
- atomic_set(&core->stream_started, 0);
- schedule_work(&core->wq_trigger);
- }
-
- return 0;
-}
-
-static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
-{
- struct snd_tm6000_card *chip = core->adev;
- struct snd_pcm_substream *substream = chip->substream;
- struct snd_pcm_runtime *runtime;
- int period_elapsed = 0;
- unsigned int stride, buf_pos;
- int length;
-
- if (atomic_read(&core->stream_started) == 0)
- return 0;
-
- if (!size || !substream) {
- dprintk(1, "substream was NULL\n");
- return -EINVAL;
- }
-
- runtime = substream->runtime;
- if (!runtime || !runtime->dma_area) {
- dprintk(1, "runtime was NULL\n");
- return -EINVAL;
- }
-
- buf_pos = chip->buf_pos;
- stride = runtime->frame_bits >> 3;
-
- if (stride == 0) {
- dprintk(1, "stride is zero\n");
- return -EINVAL;
- }
-
- length = size / stride;
- if (length == 0) {
- dprintk(1, "%s: length was zero\n", __func__);
- return -EINVAL;
- }
-
- dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
- runtime->dma_area, buf_pos,
- (unsigned int)runtime->buffer_size, stride);
-
- if (buf_pos + length >= runtime->buffer_size) {
- unsigned int cnt = runtime->buffer_size - buf_pos;
- memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
- memcpy(runtime->dma_area, buf + cnt * stride,
- length * stride - cnt * stride);
- } else
- memcpy(runtime->dma_area + buf_pos * stride, buf,
- length * stride);
-
- snd_pcm_stream_lock(substream);
-
- chip->buf_pos += length;
- if (chip->buf_pos >= runtime->buffer_size)
- chip->buf_pos -= runtime->buffer_size;
-
- chip->period_pos += length;
- if (chip->period_pos >= runtime->period_size) {
- chip->period_pos -= runtime->period_size;
- period_elapsed = 1;
- }
-
- snd_pcm_stream_unlock(substream);
-
- if (period_elapsed)
- snd_pcm_period_elapsed(substream);
-
- return 0;
-}
-
-/*
- * hw_params callback
- */
-static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int size, rc;
-
- size = params_period_bytes(hw_params) * params_periods(hw_params);
-
- rc = dsp_buffer_alloc(substream, size);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/*
- * hw free callback
- */
-static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct tm6000_core *core = chip->core;
-
- if (atomic_read(&core->stream_started) > 0) {
- atomic_set(&core->stream_started, 0);
- schedule_work(&core->wq_trigger);
- }
-
- dsp_buffer_free(substream);
- return 0;
-}
-
-/*
- * prepare callback
- */
-static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- chip->buf_pos = 0;
- chip->period_pos = 0;
-
- return 0;
-}
-
-
-/*
- * trigger callback
- */
-static void audio_trigger(struct work_struct *work)
-{
- struct tm6000_core *core = container_of(work, struct tm6000_core,
- wq_trigger);
- struct snd_tm6000_card *chip = core->adev;
-
- if (atomic_read(&core->stream_started)) {
- dprintk(1, "starting capture");
- _tm6000_start_audio_dma(chip);
- } else {
- dprintk(1, "stopping capture");
- _tm6000_stop_audio_dma(chip);
- }
-}
-
-static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct tm6000_core *core = chip->core;
- 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;
- default:
- err = -EINVAL;
- break;
- }
- schedule_work(&core->wq_trigger);
-
- return err;
-}
-/*
- * pointer callback
- */
-static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(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
- */
-static struct snd_pcm_ops snd_tm6000_pcm_ops = {
- .open = snd_tm6000_pcm_open,
- .close = snd_tm6000_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_tm6000_hw_params,
- .hw_free = snd_tm6000_hw_free,
- .prepare = snd_tm6000_prepare,
- .trigger = snd_tm6000_card_trigger,
- .pointer = snd_tm6000_pointer,
- .page = snd_pcm_get_vmalloc_page,
-};
-
-/*
- * create a PCM device
- */
-
-/* FIXME: Control interface - How to control volume/mute? */
-
-/****************************************************************************
- Basic Flow for Sound Devices
- ****************************************************************************/
-
-/*
- * Alsa Constructor - Component probe
- */
-static int tm6000_audio_init(struct tm6000_core *dev)
-{
- struct snd_card *card;
- struct snd_tm6000_card *chip;
- int rc;
- static int devnr;
- char component[14];
- struct snd_pcm *pcm;
-
- if (!dev)
- return 0;
-
- if (devnr >= SNDRV_CARDS)
- return -ENODEV;
-
- if (!enable[devnr])
- return -ENOENT;
-
- rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
- if (rc < 0) {
- snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
- return rc;
- }
- strcpy(card->driver, "tm6000-alsa");
- strcpy(card->shortname, "TM5600/60x0");
- sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
- dev->udev->bus->busnum, dev->udev->devnum);
-
- sprintf(component, "USB%04x:%04x",
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct));
- snd_component_add(card, component);
- snd_card_set_dev(card, &dev->udev->dev);
-
- chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
- if (!chip) {
- rc = -ENOMEM;
- goto error;
- }
-
- chip->core = dev;
- chip->card = card;
- dev->adev = chip;
- spin_lock_init(&chip->reg_lock);
-
- rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
- if (rc < 0)
- goto error_chip;
-
- pcm->info_flags = 0;
- pcm->private_data = chip;
- strcpy(pcm->name, "Trident TM5600/60x0");
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
- INIT_WORK(&dev->wq_trigger, audio_trigger);
- rc = snd_card_register(card);
- if (rc < 0)
- goto error_chip;
-
- dprintk(1, "Registered audio driver for %s\n", card->longname);
-
- return 0;
-
-error_chip:
- kfree(chip);
- dev->adev = NULL;
-error:
- snd_card_free(card);
- return rc;
-}
-
-static int tm6000_audio_fini(struct tm6000_core *dev)
-{
- struct snd_tm6000_card *chip = dev->adev;
-
- if (!dev)
- return 0;
-
- if (!chip)
- return 0;
-
- if (!chip->card)
- return 0;
-
- snd_card_free(chip->card);
- chip->card = NULL;
- kfree(chip);
- dev->adev = NULL;
-
- return 0;
-}
-
-static struct tm6000_ops audio_ops = {
- .type = TM6000_AUDIO,
- .name = "TM6000 Audio Extension",
- .init = tm6000_audio_init,
- .fini = tm6000_audio_fini,
- .fillbuf = tm6000_fillbuf,
-};
-
-static int __init tm6000_alsa_register(void)
-{
- return tm6000_register_extension(&audio_ops);
-}
-
-static void __exit tm6000_alsa_unregister(void)
-{
- tm6000_unregister_extension(&audio_ops);
-}
-
-module_init(tm6000_alsa_register);
-module_exit(tm6000_alsa_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
deleted file mode 100644
index e80b7e190471..000000000000
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2
- *
- * This program is distributed 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/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <linux/input.h>
-#include <linux/usb.h>
-
-#include <media/rc-core.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-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)");
-
-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(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;
-};
-
-struct tm6000_IR {
- struct tm6000_core *dev;
- struct rc_dev *rc;
- char name[32];
- char phys[32];
-
- /* poll expernal decoder */
- int polling;
- struct delayed_work work;
- u8 wait:1;
- u8 pwled:2;
- u8 submit_urb:1;
- u16 key_addr;
- struct urb *int_urb;
-
- /* IR device properties */
- u64 rc_type;
-};
-
-void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
-{
- struct tm6000_IR *ir = dev->ir;
-
- 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;
- 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:
- leader = 900; /* ms */
- pulse = 700; /* ms - the actual value would be 562 */
- break;
- default:
- 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;
-}
-
-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;
-
- 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;
-
- if (ir_debug)
- print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
- DUMP_PREFIX_OFFSET,16, 1,
- buf, urb->actual_length, false);
-
- 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);
-
- 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 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)
- return;
-
- dprintk(3, "%s\n",__func__);
-
- 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;
-
- if (rc > 1)
- poll_result.rc_data = buf[0] | buf[1] << 8;
- else
- poll_result.rc_data = buf[0];
-
- /* Check if something was read */
- if ((poll_result.rc_data & 0xff) == 0xff) {
- if (!ir->pwled) {
- tm6000_flash_led(dev, 1);
- ir->pwled = 1;
- }
- return;
- }
-
- 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_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 rc;
-
- dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb,
- ir->pwled);
-
- if (ir->submit_urb) {
- dprintk(3, "Resubmit urb\n");
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
-
- 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;
- }
-
- /* 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;
- }
-}
-
-static int tm6000_ir_start(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
-
- dprintk(2, "%s\n",__func__);
-
- schedule_delayed_work(&ir->work, 0);
-
- return 0;
-}
-
-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);
-}
-
-static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
-{
- struct tm6000_IR *ir = rc->priv;
-
- 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->rc_type = rc_type;
-
- tm6000_ir_config(ir);
- /* TODO */
- return 0;
-}
-
-static int __tm6000_ir_int_start(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
- struct tm6000_core *dev = ir->dev;
- int pipe, size;
- int err = -ENOMEM;
-
- if (!ir)
- return -ENODEV;
-
- dprintk(2, "%s\n",__func__);
-
- ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!ir->int_urb)
- return -ENOMEM;
-
- pipe = usb_rcvintpipe(dev->udev,
- dev->int_in.endp->desc.bEndpointAddress
- & USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
- dprintk(1, "IR max size: %d\n", size);
-
- 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(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);
-
- ir->submit_urb = 1;
- schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
-
- return 0;
-}
-
-static void __tm6000_ir_int_stop(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
-
- 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;
-}
-
-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)
-{
- struct tm6000_IR *ir;
- struct rc_dev *rc;
- int err = -ENOMEM;
-
- if (!enable_ir)
- return -ENODEV;
-
- if (!dev->caps.has_remote)
- return 0;
-
- if (!dev->ir_codes)
- return 0;
-
- 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 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;
- 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;
-
- snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
- dev->name);
-
- usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
- strlcat(ir->phys, "/input0", sizeof(ir->phys));
-
- tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
-
- rc->input_name = ir->name;
- rc->input_phys = ir->phys;
- rc->input_id.bustype = BUS_USB;
- rc->input_id.version = 1;
- rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
- rc->map_name = dev->ir_codes;
- rc->driver_name = "tm6000";
- rc->dev.parent = &dev->udev->dev;
-
- /* ir register */
- err = rc_register_device(rc);
- if (err)
- goto out;
-
- return 0;
-
-out:
- dev->ir = NULL;
- rc_free_device(rc);
- kfree(ir);
- return err;
-}
-
-int tm6000_ir_fini(struct tm6000_core *dev)
-{
- struct tm6000_IR *ir = dev->ir;
-
- /* skip detach on non attached board */
-
- if (!ir)
- return 0;
-
- dprintk(2, "%s\n",__func__);
-
- if (!ir->polling)
- __tm6000_ir_int_stop(ir->rc);
-
- tm6000_ir_stop(ir->rc);
-
- /* Turn off the led */
- tm6000_flash_led(dev, 0);
- ir->pwled = 0;
-
- rc_unregister_device(ir->rc);
-
- kfree(ir);
- dev->ir = NULL;
-
- return 0;
-}
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
deleted file mode 100644
index f7034df94e0a..000000000000
--- a/drivers/media/video/tm6000/tm6000-video.c
+++ /dev/null
@@ -1,1818 +0,0 @@
-/*
- * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- * - Fixed module load/unload
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2
- *
- * This program is distributed 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/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
-#include <media/tuner.h>
-#include <linux/interrupt.h>
-#include <linux/kthread.h>
-#include <linux/highmem.h>
-#include <linux/freezer.h>
-
-#include "tm6000-regs.h"
-#include "tm6000.h"
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
-
-/* Limits minimum and default number of buffers */
-#define TM6000_MIN_BUF 4
-#define TM6000_DEF_BUF 8
-
-#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
-
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
-
-/* Debug level */
-int tm6000_debug;
-EXPORT_SYMBOL_GPL(tm6000_debug);
-
-static const struct v4l2_queryctrl no_ctrl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-/* supported controls */
-static struct v4l2_queryctrl tm6000_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 54,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 119,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 112,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 0x1,
- .default_value = 0,
- .flags = 0,
- },
- /* --- audio --- */
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = -15,
- .maximum = 15,
- .step = 1,
- .default_value = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
-
-static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
-static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
-
-static struct tm6000_fmt format[] = {
- {
- .name = "4:2:2, packed, YVY2",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- }, {
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- }, {
- .name = "A/V + VBI mux packet",
- .fourcc = V4L2_PIX_FMT_TM6000,
- .depth = 16,
- }
-};
-
-static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
-{
- unsigned int i;
-
- for (i = 0; i < CTRLS; i++)
- if (tm6000_qctrl[i].id == id)
- return tm6000_qctrl+i;
- return NULL;
-}
-
-/* ------------------------------------------------------------------
- * DMA and thread functions
- * ------------------------------------------------------------------
- */
-
-#define norm_maxw(a) 720
-#define norm_maxh(a) 576
-
-#define norm_minw(a) norm_maxw(a)
-#define norm_minh(a) norm_maxh(a)
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
- struct tm6000_buffer **buf)
-{
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-
- if (list_empty(&dma_q->active)) {
- dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
- *buf = NULL;
- return;
- }
-
- *buf = list_entry(dma_q->active.next,
- struct tm6000_buffer, vb.queue);
-}
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct tm6000_core *dev,
- struct tm6000_dmaqueue *dma_q,
- struct tm6000_buffer *buf)
-{
- /* Advice that buffer was filled */
- dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_streams(u8 *data, unsigned long len,
- struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- u8 *ptr = data, *endp = data+len;
- unsigned long header = 0;
- int rc = 0;
- unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
- struct tm6000_buffer *vbuf = NULL;
- char *voutp = NULL;
- unsigned int linewidth;
-
- if (!dev->radio) {
- /* get video buffer */
- get_next_buf(dma_q, &vbuf);
-
- if (!vbuf)
- return rc;
- voutp = videobuf_to_vmalloc(&vbuf->vb);
-
- if (!voutp)
- return 0;
- }
-
- for (ptr = data; ptr < endp;) {
- if (!dev->isoc_ctl.cmd) {
- /* Header */
- if (dev->isoc_ctl.tmp_buf_len > 0) {
- /* from last urb or packet */
- header = dev->isoc_ctl.tmp_buf;
- if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
- memcpy((u8 *)&header +
- dev->isoc_ctl.tmp_buf_len,
- ptr,
- 4 - dev->isoc_ctl.tmp_buf_len);
- ptr += 4 - dev->isoc_ctl.tmp_buf_len;
- }
- dev->isoc_ctl.tmp_buf_len = 0;
- } else {
- if (ptr + 3 >= endp) {
- /* have incomplete header */
- dev->isoc_ctl.tmp_buf_len = endp - ptr;
- memcpy(&dev->isoc_ctl.tmp_buf, ptr,
- dev->isoc_ctl.tmp_buf_len);
- return rc;
- }
- /* Seek for sync */
- for (; ptr < endp - 3; ptr++) {
- if (*(ptr + 3) == 0x47)
- break;
- }
- /* Get message header */
- header = *(unsigned long *)ptr;
- ptr += 4;
- }
-
- /* split the header fields */
- size = ((header & 0x7e) << 1);
- if (size > 0)
- size -= 4;
- block = (header >> 7) & 0xf;
- field = (header >> 11) & 0x1;
- line = (header >> 12) & 0x1ff;
- cmd = (header >> 21) & 0x7;
- /* Validates haeder fields */
- if (size > TM6000_URB_MSG_LEN)
- size = TM6000_URB_MSG_LEN;
- pktsize = TM6000_URB_MSG_LEN;
- /*
- * calculate position in buffer and change the buffer
- */
- switch (cmd) {
- case TM6000_URB_MSG_VIDEO:
- if (!dev->radio) {
- if ((dev->isoc_ctl.vfield != field) &&
- (field == 1)) {
- /*
- * Announces that a new buffer
- * were filled
- */
- buffer_filled(dev, dma_q, vbuf);
- dprintk(dev, V4L2_DEBUG_ISOC,
- "new buffer filled\n");
- get_next_buf(dma_q, &vbuf);
- if (!vbuf)
- return rc;
- voutp = videobuf_to_vmalloc(&vbuf->vb);
- if (!voutp)
- return rc;
- memset(voutp, 0, vbuf->vb.size);
- }
- linewidth = vbuf->vb.width << 1;
- pos = ((line << 1) - field - 1) *
- linewidth + block * TM6000_URB_MSG_LEN;
- /* Don't allow to write out of the buffer */
- if (pos + size > vbuf->vb.size)
- cmd = TM6000_URB_MSG_ERR;
- dev->isoc_ctl.vfield = field;
- }
- break;
- case TM6000_URB_MSG_VBI:
- break;
- case TM6000_URB_MSG_AUDIO:
- case TM6000_URB_MSG_PTS:
- size = pktsize; /* Size is always 180 bytes */
- break;
- }
- } else {
- /* Continue the last copy */
- cmd = dev->isoc_ctl.cmd;
- size = dev->isoc_ctl.size;
- pos = dev->isoc_ctl.pos;
- pktsize = dev->isoc_ctl.pktsize;
- field = dev->isoc_ctl.field;
- }
- cpysize = (endp - ptr > size) ? size : endp - ptr;
- if (cpysize) {
- /* copy data in different buffers */
- switch (cmd) {
- case TM6000_URB_MSG_VIDEO:
- /* Fills video buffer */
- if (vbuf)
- memcpy(&voutp[pos], ptr, cpysize);
- break;
- case TM6000_URB_MSG_AUDIO: {
- int i;
- for (i = 0; i < cpysize; i += 2)
- swab16s((u16 *)(ptr + i));
-
- tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
- break;
- }
- case TM6000_URB_MSG_VBI:
- /* Need some code to copy vbi buffer */
- break;
- case TM6000_URB_MSG_PTS: {
- /* Need some code to copy pts */
- u32 pts;
- pts = *(u32 *)ptr;
- dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
- field, pts);
- break;
- }
- }
- }
- if (ptr + pktsize > endp) {
- /*
- * End of URB packet, but cmd processing is not
- * complete. Preserve the state for a next packet
- */
- dev->isoc_ctl.pos = pos + cpysize;
- dev->isoc_ctl.size = size - cpysize;
- dev->isoc_ctl.cmd = cmd;
- dev->isoc_ctl.field = field;
- dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
- ptr += endp - ptr;
- } else {
- dev->isoc_ctl.cmd = 0;
- ptr += pktsize;
- }
- }
- return 0;
-}
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_multiplexed(u8 *ptr, unsigned long len,
- struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- unsigned int pos = dev->isoc_ctl.pos, cpysize;
- int rc = 1;
- struct tm6000_buffer *buf;
- char *outp = NULL;
-
- get_next_buf(dma_q, &buf);
- if (buf)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- if (!outp)
- return 0;
-
- while (len > 0) {
- cpysize = min(len, buf->vb.size-pos);
- memcpy(&outp[pos], ptr, cpysize);
- pos += cpysize;
- ptr += cpysize;
- len -= cpysize;
- if (pos >= buf->vb.size) {
- pos = 0;
- /* Announces that a new buffer were filled */
- buffer_filled(dev, dma_q, buf);
- dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
- get_next_buf(dma_q, &buf);
- if (!buf)
- break;
- outp = videobuf_to_vmalloc(&(buf->vb));
- if (!outp)
- return rc;
- pos = 0;
- }
- }
-
- dev->isoc_ctl.pos = pos;
- return rc;
-}
-
-static inline void print_err_status(struct tm6000_core *dev,
- int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronuously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronuously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
- status, errmsg);
- } else {
- dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int tm6000_isoc_copy(struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- int i, len = 0, rc = 1, status;
- char *p;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- return 0;
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- continue;
- }
-
- len = urb->iso_frame_desc[i].actual_length;
-
- if (len > 0) {
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- if (!urb->iso_frame_desc[i].status) {
- if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
- rc = copy_multiplexed(p, len, urb);
- if (rc <= 0)
- return rc;
- } else {
- copy_streams(p, len, urb);
- }
- }
- }
- }
- return rc;
-}
-
-/* ------------------------------------------------------------------
- * URB control
- * ------------------------------------------------------------------
- */
-
-/*
- * IRQ callback, called by URB callback
- */
-static void tm6000_irq_callback(struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- int i;
-
- switch (urb->status) {
- case 0:
- case -ETIMEDOUT:
- break;
-
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- return;
-
- default:
- tm6000_err("urb completion error %d.\n", urb->status);
- break;
- }
-
- spin_lock(&dev->slock);
- tm6000_isoc_copy(urb);
- spin_unlock(&dev->slock);
-
- /* Reset urb buffers */
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
-
- urb->status = usb_submit_urb(urb, GFP_ATOMIC);
- if (urb->status)
- tm6000_err("urb resubmit failed (error=%i)\n",
- urb->status);
-}
-
-/*
- * Stop and Deallocate URBs
- */
-static void tm6000_uninit_isoc(struct tm6000_core *dev)
-{
- struct urb *urb;
- int i;
-
- dev->isoc_ctl.buf = NULL;
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = dev->isoc_ctl.urb[i];
- if (urb) {
- usb_kill_urb(urb);
- usb_unlink_urb(urb);
- if (dev->isoc_ctl.transfer_buffer[i]) {
- usb_free_coherent(dev->udev,
- urb->transfer_buffer_length,
- dev->isoc_ctl.transfer_buffer[i],
- urb->transfer_dma);
- }
- usb_free_urb(urb);
- dev->isoc_ctl.urb[i] = NULL;
- }
- dev->isoc_ctl.transfer_buffer[i] = NULL;
- }
-
- kfree(dev->isoc_ctl.urb);
- kfree(dev->isoc_ctl.transfer_buffer);
-
- dev->isoc_ctl.urb = NULL;
- dev->isoc_ctl.transfer_buffer = NULL;
- dev->isoc_ctl.num_bufs = 0;
-}
-
-/*
- * Allocate URBs and start IRQ
- */
-static int tm6000_prepare_isoc(struct tm6000_core *dev)
-{
- struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
- struct urb *urb;
-
- /* De-allocates all pending stuff */
- tm6000_uninit_isoc(dev);
- /* Stop interrupt USB pipe */
- tm6000_ir_int_stop(dev);
-
- usb_set_interface(dev->udev,
- dev->isoc_in.bInterfaceNumber,
- dev->isoc_in.bAlternateSetting);
-
- /* Start interrupt USB pipe */
- tm6000_ir_int_start(dev);
-
- pipe = usb_rcvisocpipe(dev->udev,
- dev->isoc_in.endp->desc.bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-
- if (size > dev->isoc_in.maxsize)
- size = dev->isoc_in.maxsize;
-
- dev->isoc_ctl.max_pkt_size = size;
-
- max_packets = TM6000_MAX_ISO_PACKETS;
- sb_size = max_packets * size;
-
- dev->isoc_ctl.num_bufs = num_bufs;
-
- dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
- if (!dev->isoc_ctl.urb) {
- tm6000_err("cannot alloc memory for usb buffers\n");
- return -ENOMEM;
- }
-
- dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
- GFP_KERNEL);
- if (!dev->isoc_ctl.transfer_buffer) {
- tm6000_err("cannot allocate memory for usbtransfer\n");
- kfree(dev->isoc_ctl.urb);
- return -ENOMEM;
- }
-
- dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
- " (%d bytes) of %d bytes each to handle %u size\n",
- max_packets, num_bufs, sb_size,
- dev->isoc_in.maxsize, size);
-
- /* allocate urbs and transfer buffers */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = usb_alloc_urb(max_packets, GFP_KERNEL);
- if (!urb) {
- tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
- tm6000_uninit_isoc(dev);
- usb_free_urb(urb);
- return -ENOMEM;
- }
- dev->isoc_ctl.urb[i] = urb;
-
- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!dev->isoc_ctl.transfer_buffer[i]) {
- tm6000_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
- tm6000_uninit_isoc(dev);
- return -ENOMEM;
- }
- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
-
- usb_fill_bulk_urb(urb, dev->udev, pipe,
- dev->isoc_ctl.transfer_buffer[i], sb_size,
- tm6000_irq_callback, dma_q);
- urb->interval = dev->isoc_in.endp->desc.bInterval;
- urb->number_of_packets = max_packets;
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-
- for (j = 0; j < max_packets; j++) {
- urb->iso_frame_desc[j].offset = size * j;
- urb->iso_frame_desc[j].length = size;
- }
- }
-
- return 0;
-}
-
-static int tm6000_start_thread(struct tm6000_core *dev)
-{
- struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i;
-
- dma_q->frame = 0;
- dma_q->ini_jiffies = jiffies;
-
- init_waitqueue_head(&dma_q->wq);
-
- /* submit urbs and enables IRQ */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
- if (rc) {
- tm6000_err("submit of urb %i failed (error=%i)\n", i,
- rc);
- tm6000_uninit_isoc(dev);
- return rc;
- }
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------
- * Videobuf operations
- * ------------------------------------------------------------------
- */
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
-{
- struct tm6000_fh *fh = vq->priv_data;
-
- *size = fh->fmt->depth * fh->width * fh->height >> 3;
- if (0 == *count)
- *count = TM6000_DEF_BUF;
-
- if (*count < TM6000_MIN_BUF)
- *count = TM6000_MIN_BUF;
-
- while (*size * *count > vid_limit * 1024 * 1024)
- (*count)--;
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
-{
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_core *dev = fh->dev;
- unsigned long flags;
-
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.buf == buf)
- dev->isoc_ctl.buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
- struct tm6000_core *dev = fh->dev;
- int rc = 0;
-
- BUG_ON(NULL == fh->fmt);
-
-
- /* FIXME: It assumes depth=2 */
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc != 0)
- goto fail;
- }
-
- if (!dev->isoc_ctl.num_bufs) {
- rc = tm6000_prepare_isoc(dev);
- if (rc < 0)
- goto fail;
-
- rc = tm6000_start_thread(dev);
- if (rc < 0)
- goto fail;
-
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_core *dev = fh->dev;
- struct tm6000_dmaqueue *vidq = &dev->vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
-
- free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops tm6000_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------
- * IOCTL handling
- * ------------------------------------------------------------------
- */
-
-static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh && dev->is_res_read)
- return true;
-
- return false;
-}
-
-static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh)
- return true;
-
- return false;
-}
-
-static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
- bool is_res_read)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh && dev->is_res_read == is_res_read)
- return true;
-
- /* is it free? */
- if (dev->resources)
- return false;
-
- /* grab it */
- dev->resources = fh;
- dev->is_res_read = is_res_read;
- dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
- return true;
-}
-
-static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources != fh)
- return;
-
- dev->resources = NULL;
- dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
-}
-
-/* ------------------------------------------------------------------
- * IOCTL vidioc handling
- * ------------------------------------------------------------------
- */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
-
- strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
- strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE;
-
- if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (unlikely(f->index >= ARRAY_SIZE(format)))
- return -EINVAL;
-
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
- f->pixelformat = format[f->index].fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_fh *fh = priv;
-
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
-
- return 0;
-}
-
-static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(format); i++)
- if (format[i].fourcc == fourcc)
- return format+i;
- return NULL;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
- struct tm6000_fmt *fmt;
- enum v4l2_field field;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt) {
- dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
- " invalid.\n", f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- field = f->fmt.pix.field;
-
- if (field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_SEQ_TB;
- else if (V4L2_FIELD_INTERLACED != field) {
- dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
- return -EINVAL;
- }
-
- tm6000_get_std_res(dev);
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
-
- f->fmt.pix.width &= ~0x01;
-
- f->fmt.pix.field = field;
-
- 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;
-}
-
-/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int ret = vidioc_try_fmt_vid_cap(file, fh, f);
- if (ret < 0)
- return ret;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
-
- dev->fourcc = f->fmt.pix.pixelformat;
-
- tm6000_set_fourcc_format(dev);
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_reqbufs(&fh->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_querybuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_qbuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->vb_vidq, p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- if (!res_get(dev, fh, false))
- return -EBUSY;
- return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (i != fh->type)
- return -EINVAL;
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
-
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
- int rc = 0;
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- dev->norm = *norm;
- rc = tm6000_init_analog_mode(dev);
-
- fh->width = dev->width;
- fh->height = dev->height;
-
- if (rc < 0)
- return rc;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
-
- return 0;
-}
-
-static const char *iname[] = {
- [TM6000_INPUT_TV] = "Television",
- [TM6000_INPUT_COMPOSITE1] = "Composite 1",
- [TM6000_INPUT_COMPOSITE2] = "Composite 2",
- [TM6000_INPUT_SVIDEO] = "S-Video",
-};
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- unsigned int n;
-
- n = i->index;
- if (n >= 3)
- return -EINVAL;
-
- if (!dev->vinput[n].type)
- return -EINVAL;
-
- i->index = n;
-
- if (dev->vinput[n].type == TM6000_INPUT_TV)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- strcpy(i->name, iname[dev->vinput[n].type]);
-
- i->std = TM6000_STD;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- *i = dev->input;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int rc = 0;
-
- if (i >= 3)
- return -EINVAL;
- if (!dev->vinput[i].type)
- return -EINVAL;
-
- dev->input = i;
-
- rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
-
- return rc;
-}
-
-/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
- if (qc->id && qc->id == tm6000_qctrl[i].id) {
- memcpy(qc, &(tm6000_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int val;
-
- /* FIXME: Probably, those won't work! Maybe we need shadow regs */
- switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
- break;
- case V4L2_CID_BRIGHTNESS:
- val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
- return 0;
- case V4L2_CID_SATURATION:
- val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
- return 0;
- case V4L2_CID_HUE:
- val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
- return 0;
- case V4L2_CID_AUDIO_MUTE:
- val = dev->ctl_mute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- val = dev->ctl_volume;
- return 0;
- default:
- return -EINVAL;
- }
-
- if (val < 0)
- return val;
-
- ctrl->value = val;
-
- return 0;
-}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- u8 val = ctrl->value;
-
- switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
- return 0;
- case V4L2_CID_BRIGHTNESS:
- tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
- return 0;
- case V4L2_CID_SATURATION:
- tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
- return 0;
- case V4L2_CID_HUE:
- tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
- return 0;
- case V4L2_CID_AUDIO_MUTE:
- dev->ctl_mute = val;
- tm6000_tvaudio_set_mute(dev, val);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- dev->ctl_volume = val;
- tm6000_set_volume(dev, val);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
- t->audmode = dev->amode;
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- dev->amode = t->audmode;
- dprintk(dev, 3, "audio mode: %x\n", t->audmode);
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
-
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->freq;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
-
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
- if (unlikely(f->tuner != 0))
- return -EINVAL;
- if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
- return -EINVAL;
- if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
- return -EINVAL;
-
- dev->freq = f->frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-
- return 0;
-}
-
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- strcpy(cap->driver, "tm6000");
- strlcpy(cap->card, dev->name, sizeof(dev->name));
- sprintf(cap->bus_info, "USB%04x:%04x",
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct));
- cap->version = dev->dev_type;
- cap->capabilities = V4L2_CAP_TUNER |
- V4L2_CAP_AUDIO |
- V4L2_CAP_RADIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static int radio_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- if (0 != t->index)
- return -EINVAL;
-
- memset(t, 0, sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- if (0 != t->index)
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int radio_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (i->index != 0)
- return -EINVAL;
-
- if (!dev->rinput.type)
- return -EINVAL;
-
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (dev->input != 5)
- return -EINVAL;
-
- *i = dev->input - 5;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- memset(a, 0, sizeof(*a));
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (i)
- return -EINVAL;
-
- if (!dev->rinput.type)
- return -EINVAL;
-
- dev->input = i + 5;
-
- return 0;
-}
-
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- const struct v4l2_queryctrl *ctrl;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- ctrl = ctrl_by_id(c->id);
- *c = *ctrl;
- } else
- *c = no_ctrl;
-
- return 0;
-}
-
-/* ------------------------------------------------------------------
- File operations for the device
- ------------------------------------------------------------------*/
-
-static int tm6000_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct tm6000_core *dev = video_drvdata(file);
- struct tm6000_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int i, rc;
- int radio = 0;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
- video_device_node_name(vdev));
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- /* If more than one user, mutex should be added */
- dev->users++;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[type],
- dev->users);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- dev->users--;
- return -ENOMEM;
- }
-
- file->private_data = fh;
- fh->dev = dev;
- fh->radio = radio;
- dev->radio = radio;
- fh->type = type;
- dev->fourcc = format[0].fourcc;
-
- fh->fmt = format_by_fourcc(dev->fourcc);
-
- tm6000_get_std_res(dev);
-
- fh->width = dev->width;
- fh->height = dev->height;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
- "dev->vidq=0x%08lx\n",
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&dev->vidq);
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
- "queued=%d\n", list_empty(&dev->vidq.queued));
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
- "active=%d\n", list_empty(&dev->vidq.active));
-
- /* initialize hardware on analog mode */
- rc = tm6000_init_analog_mode(dev);
- if (rc < 0)
- return rc;
-
- if (dev->mode != TM6000_MODE_ANALOG) {
- /* Put all controls at a sane state */
- for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
- qctl_regs[i] = tm6000_qctrl[i].default_value;
-
- dev->mode = TM6000_MODE_ANALOG;
- }
-
- if (!fh->radio) {
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
- NULL, &dev->slock,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct tm6000_buffer), fh, &dev->lock);
- } else {
- dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
- dev->input = 5;
- tm6000_set_audio_rinput(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
- tm6000_prepare_isoc(dev);
- tm6000_start_thread(dev);
- }
-
- return 0;
-}
-
-static ssize_t
-tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
-{
- struct tm6000_fh *fh = file->private_data;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (!res_get(fh->dev, fh, true))
- return -EBUSY;
-
- return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
- file->f_flags & O_NONBLOCK);
- }
- return 0;
-}
-
-static unsigned int
-tm6000_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_buffer *buf;
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
-
- if (!!is_res_streaming(fh->dev, fh))
- return POLLERR;
-
- if (!is_res_read(fh->dev, fh)) {
- /* streaming capture */
- if (list_empty(&fh->vb_vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
- } else {
- /* read() capture */
- return videobuf_poll_stream(file, &fh->vb_vidq, wait);
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int tm6000_release(struct file *file)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
- struct video_device *vdev = video_devdata(file);
-
- dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
- video_device_node_name(vdev), dev->users);
-
- dev->users--;
-
- res_free(dev, fh);
-
- if (!dev->users) {
- 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);
- }
-
- kfree(fh);
-
- return 0;
-}
-
-static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct tm6000_fh *fh = file->private_data;
-
- return videobuf_mmap_mapper(&fh->vb_vidq, vma);
-}
-
-static struct v4l2_file_operations tm6000_fops = {
- .owner = THIS_MODULE,
- .open = tm6000_open,
- .release = tm6000_release,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .read = tm6000_read,
- .poll = tm6000_poll,
- .mmap = tm6000_mmap,
-};
-
-static const struct v4l2_ioctl_ops video_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_s_std = vidioc_s_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .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_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-};
-
-static struct video_device tm6000_template = {
- .name = "tm6000",
- .fops = &tm6000_fops,
- .ioctl_ops = &video_ioctl_ops,
- .release = video_device_release,
- .tvnorms = TM6000_STD,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-static const struct v4l2_file_operations radio_fops = {
- .owner = THIS_MODULE,
- .open = tm6000_open,
- .release = tm6000_release,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
- .vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
- .vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_s_std = radio_s_std,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_input = radio_g_input,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-};
-
-static struct video_device tm6000_radio_template = {
- .name = "tm6000",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
-};
-
-/* -----------------------------------------------------------------
- * Initialization and module stuff
- * ------------------------------------------------------------------
- */
-
-static struct video_device *vdev_init(struct tm6000_core *dev,
- const struct video_device
- *template, const char *type_name)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
-
- *vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
- vfd->debug = tm6000_debug;
- vfd->lock = &dev->lock;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
-
- snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
-
- video_set_drvdata(vfd, dev);
- return vfd;
-}
-
-int tm6000_v4l2_register(struct tm6000_core *dev)
-{
- int ret = -1;
-
- dev->vfd = vdev_init(dev, &tm6000_template, "video");
-
- if (!dev->vfd) {
- printk(KERN_INFO "%s: can't register video device\n",
- dev->name);
- return -ENOMEM;
- }
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
-
- ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
-
- if (ret < 0) {
- printk(KERN_INFO "%s: can't register video device\n",
- dev->name);
- return ret;
- }
-
- printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(dev->vfd));
-
- if (dev->caps.has_radio) {
- dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
- "radio");
- if (!dev->radio_dev) {
- printk(KERN_INFO "%s: can't register radio device\n",
- dev->name);
- return ret; /* FIXME release resource */
- }
-
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
- radio_nr);
- if (ret < 0) {
- printk(KERN_INFO "%s: can't register radio device\n",
- dev->name);
- return ret; /* FIXME release resource */
- }
-
- printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(dev->radio_dev));
- }
-
- printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
- return ret;
-}
-
-int tm6000_v4l2_unregister(struct tm6000_core *dev)
-{
- video_unregister_device(dev->vfd);
-
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
-
- return 0;
-}
-
-int tm6000_v4l2_exit(void)
-{
- return 0;
-}
-
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "Allow changing video device number");
-
-module_param_named(debug, tm6000_debug, int, 0444);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
deleted file mode 100644
index cd615c1d6011..000000000000
--- a/drivers/media/video/tvp514x.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
- * drivers/media/video/tvp514x.c
- *
- * TI TVP5146/47 decoder driver
- *
- * Copyright (C) 2008 Texas Instruments Inc
- * Author: Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * Contributors:
- * Sivaraj R <sivaraj@ti.com>
- * Brijesh R Jadav <brijesh.j@ti.com>
- * Hardik Shah <hardik.shah@ti.com>
- * Manjunath Hadli <mrh@ti.com>
- * Karicheri Muralidharan <m-karicheri2@ti.com>
- *
- * This package 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/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/v4l2-device.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-mediabus.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ctrls.h>
-#include <media/tvp514x.h>
-
-#include "tvp514x_regs.h"
-
-/* Module Name */
-#define TVP514X_MODULE_NAME "tvp514x"
-
-/* Private macros for TVP */
-#define I2C_RETRY_COUNT (5)
-#define LOCK_RETRY_COUNT (5)
-#define LOCK_RETRY_DELAY (200)
-
-/* Debug functions */
-static bool debug;
-module_param(debug, bool, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("TVP514X linux decoder driver");
-MODULE_LICENSE("GPL");
-
-/* enum tvp514x_std - enum for supported standards */
-enum tvp514x_std {
- STD_NTSC_MJ = 0,
- STD_PAL_BDGHIN,
- STD_INVALID
-};
-
-/**
- * struct tvp514x_std_info - Structure to store standard informations
- * @width: Line width in pixels
- * @height:Number of active lines
- * @video_std: Value to write in REG_VIDEO_STD register
- * @standard: v4l2 standard structure information
- */
-struct tvp514x_std_info {
- unsigned long width;
- unsigned long height;
- u8 video_std;
- struct v4l2_standard standard;
-};
-
-static struct tvp514x_reg tvp514x_reg_list_default[0x40];
-
-static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
-/**
- * struct tvp514x_decoder - TVP5146/47 decoder object
- * @sd: Subdevice Slave handle
- * @tvp514x_regs: copy of hw's regs with preset values.
- * @pdata: Board specific
- * @ver: Chip version
- * @streaming: TVP5146/47 decoder streaming - enabled or disabled.
- * @current_std: Current standard
- * @num_stds: Number of standards
- * @std_list: Standards list
- * @input: Input routing at chip level
- * @output: Output routing at chip level
- */
-struct tvp514x_decoder {
- struct v4l2_subdev sd;
- struct v4l2_ctrl_handler hdl;
- struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
- const struct tvp514x_platform_data *pdata;
-
- int ver;
- int streaming;
-
- enum tvp514x_std current_std;
- int num_stds;
- const struct tvp514x_std_info *std_list;
- /* Input and Output Routing parameters */
- u32 input;
- u32 output;
-};
-
-/* TVP514x default register values */
-static struct tvp514x_reg tvp514x_reg_list_default[] = {
- /* Composite selected */
- {TOK_WRITE, REG_INPUT_SEL, 0x05},
- {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
- /* Auto mode */
- {TOK_WRITE, REG_VIDEO_STD, 0x00},
- {TOK_WRITE, REG_OPERATION_MODE, 0x00},
- {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
- {TOK_WRITE, REG_COLOR_KILLER, 0x10},
- {TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
- {TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
- {TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
- {TOK_WRITE, REG_BRIGHTNESS, 0x80},
- {TOK_WRITE, REG_CONTRAST, 0x80},
- {TOK_WRITE, REG_SATURATION, 0x80},
- {TOK_WRITE, REG_HUE, 0x00},
- {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
- {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
- /* Reserved */
- {TOK_SKIP, 0x0F, 0x00},
- {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
- {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
- {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
- /* Reserved */
- {TOK_SKIP, 0x13, 0x00},
- {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
- /* Reserved */
- {TOK_SKIP, 0x15, 0x00},
- /* NTSC timing */
- {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},
- {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
- {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
- {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
- /* NTSC timing */
- {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},
- {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
- {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
- {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
- /* NTSC timing */
- {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
- {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
- {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
- {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
- /* NTSC timing */
- {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
- {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
- {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
- {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x26, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x27, 0x00},
- {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
- /* Reserved */
- {TOK_SKIP, 0x29, 0x00},
- {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x2B, 0x00},
- {TOK_SKIP, REG_SCART_DELAY, 0x00},
- {TOK_SKIP, REG_CTI_DELAY, 0x00},
- {TOK_SKIP, REG_CTI_CONTROL, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x2F, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x30, 0x00},
- /* Reserved */
- {TOK_SKIP, 0x31, 0x00},
- /* HS, VS active high */
- {TOK_WRITE, REG_SYNC_CONTROL, 0x00},
- /* 10-bit BT.656 */
- {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},
- /* Enable clk & data */
- {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
- /* Enable AVID & FLD */
- {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
- /* Enable VS & HS */
- {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
- {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
- {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
- /* Clear status */
- {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
- {TOK_TERM, 0, 0},
-};
-
-/**
- * Supported standards -
- *
- * Currently supports two standards only, need to add support for rest of the
- * modes, like SECAM, etc...
- */
-static const struct tvp514x_std_info tvp514x_std_list[] = {
- /* Standard: STD_NTSC_MJ */
- [STD_NTSC_MJ] = {
- .width = NTSC_NUM_ACTIVE_PIXELS,
- .height = NTSC_NUM_ACTIVE_LINES,
- .video_std = VIDEO_STD_NTSC_MJ_BIT,
- .standard = {
- .index = 0,
- .id = V4L2_STD_NTSC,
- .name = "NTSC",
- .frameperiod = {1001, 30000},
- .framelines = 525
- },
- /* Standard: STD_PAL_BDGHIN */
- },
- [STD_PAL_BDGHIN] = {
- .width = PAL_NUM_ACTIVE_PIXELS,
- .height = PAL_NUM_ACTIVE_LINES,
- .video_std = VIDEO_STD_PAL_BDGHIN_BIT,
- .standard = {
- .index = 1,
- .id = V4L2_STD_PAL,
- .name = "PAL",
- .frameperiod = {1, 25},
- .framelines = 625
- },
- },
- /* Standard: need to add for additional standard */
-};
-
-
-static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct tvp514x_decoder, sd);
-}
-
-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
-{
- return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd;
-}
-
-
-/**
- * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
- * @sd: ptr to v4l2_subdev struct
- * @reg: TVP5146/47 register address
- *
- * Returns value read if successful, or non-zero (-1) otherwise.
- */
-static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
-{
- int err, retry = 0;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-read_again:
-
- err = i2c_smbus_read_byte_data(client, reg);
- if (err < 0) {
- if (retry <= I2C_RETRY_COUNT) {
- v4l2_warn(sd, "Read: retry ... %d\n", retry);
- retry++;
- msleep_interruptible(10);
- goto read_again;
- }
- }
-
- return err;
-}
-
-/**
- * dump_reg() - dump the register content of TVP5146/47.
- * @sd: ptr to v4l2_subdev struct
- * @reg: TVP5146/47 register address
- */
-static void dump_reg(struct v4l2_subdev *sd, u8 reg)
-{
- u32 val;
-
- val = tvp514x_read_reg(sd, reg);
- v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
-}
-
-/**
- * tvp514x_write_reg() - Write a value to a register in TVP5146/47
- * @sd: ptr to v4l2_subdev struct
- * @reg: TVP5146/47 register address
- * @val: value to be written to the register
- *
- * Write a value to a register in an TVP5146/47 decoder device.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
- int err, retry = 0;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-write_again:
-
- err = i2c_smbus_write_byte_data(client, reg, val);
- if (err) {
- if (retry <= I2C_RETRY_COUNT) {
- v4l2_warn(sd, "Write: retry ... %d\n", retry);
- retry++;
- msleep_interruptible(10);
- goto write_again;
- }
- }
-
- return err;
-}
-
-/**
- * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
- * @sd: ptr to v4l2_subdev struct
- * @reglist: list of TVP5146/47 registers and values
- *
- * Initializes a list of TVP5146/47 registers:-
- * if token is TOK_TERM, then entire write operation terminates
- * if token is TOK_DELAY, then a delay of 'val' msec is introduced
- * if token is TOK_SKIP, then the register write is skipped
- * if token is TOK_WRITE, then the register write is performed
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tvp514x_write_regs(struct v4l2_subdev *sd,
- const struct tvp514x_reg reglist[])
-{
- int err;
- const struct tvp514x_reg *next = reglist;
-
- for (; next->token != TOK_TERM; next++) {
- if (next->token == TOK_DELAY) {
- msleep(next->val);
- continue;
- }
-
- if (next->token == TOK_SKIP)
- continue;
-
- err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
- if (err) {
- v4l2_err(sd, "Write failed. Err[%d]\n", err);
- return err;
- }
- }
- return 0;
-}
-
-/**
- * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
- * @sd: ptr to v4l2_subdev struct
- *
- * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
- * standard detected.
- */
-static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
-{
- u8 std, std_status;
-
- std = tvp514x_read_reg(sd, REG_VIDEO_STD);
- if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
- /* use the standard status register */
- std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
- else
- /* use the standard register itself */
- std_status = std;
-
- switch (std_status & VIDEO_STD_MASK) {
- case VIDEO_STD_NTSC_MJ_BIT:
- return STD_NTSC_MJ;
-
- case VIDEO_STD_PAL_BDGHIN_BIT:
- return STD_PAL_BDGHIN;
-
- default:
- return STD_INVALID;
- }
-
- return STD_INVALID;
-}
-
-/* TVP5146/47 register dump function */
-static void tvp514x_reg_dump(struct v4l2_subdev *sd)
-{
- dump_reg(sd, REG_INPUT_SEL);
- dump_reg(sd, REG_AFE_GAIN_CTRL);
- dump_reg(sd, REG_VIDEO_STD);
- dump_reg(sd, REG_OPERATION_MODE);
- dump_reg(sd, REG_COLOR_KILLER);
- dump_reg(sd, REG_LUMA_CONTROL1);
- dump_reg(sd, REG_LUMA_CONTROL2);
- dump_reg(sd, REG_LUMA_CONTROL3);
- dump_reg(sd, REG_BRIGHTNESS);
- dump_reg(sd, REG_CONTRAST);
- dump_reg(sd, REG_SATURATION);
- dump_reg(sd, REG_HUE);
- dump_reg(sd, REG_CHROMA_CONTROL1);
- dump_reg(sd, REG_CHROMA_CONTROL2);
- dump_reg(sd, REG_COMP_PR_SATURATION);
- dump_reg(sd, REG_COMP_Y_CONTRAST);
- dump_reg(sd, REG_COMP_PB_SATURATION);
- dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
- dump_reg(sd, REG_AVID_START_PIXEL_LSB);
- dump_reg(sd, REG_AVID_START_PIXEL_MSB);
- dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
- dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
- dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
- dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
- dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
- dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
- dump_reg(sd, REG_VSYNC_START_LINE_LSB);
- dump_reg(sd, REG_VSYNC_START_LINE_MSB);
- dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
- dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
- dump_reg(sd, REG_VBLK_START_LINE_LSB);
- dump_reg(sd, REG_VBLK_START_LINE_MSB);
- dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
- dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
- dump_reg(sd, REG_SYNC_CONTROL);
- dump_reg(sd, REG_OUTPUT_FORMATTER1);
- dump_reg(sd, REG_OUTPUT_FORMATTER2);
- dump_reg(sd, REG_OUTPUT_FORMATTER3);
- dump_reg(sd, REG_OUTPUT_FORMATTER4);
- dump_reg(sd, REG_OUTPUT_FORMATTER5);
- dump_reg(sd, REG_OUTPUT_FORMATTER6);
- dump_reg(sd, REG_CLEAR_LOST_LOCK);
-}
-
-/**
- * tvp514x_configure() - Configure the TVP5146/47 registers
- * @sd: ptr to v4l2_subdev struct
- * @decoder: ptr to tvp514x_decoder structure
- *
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tvp514x_configure(struct v4l2_subdev *sd,
- struct tvp514x_decoder *decoder)
-{
- int err;
-
- /* common register initialization */
- err =
- tvp514x_write_regs(sd, decoder->tvp514x_regs);
- if (err)
- return err;
-
- if (debug)
- tvp514x_reg_dump(sd);
-
- return 0;
-}
-
-/**
- * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
- * @sd: pointer to standard V4L2 sub-device structure
- * @decoder: pointer to tvp514x_decoder structure
- *
- * A device is considered to be detected if the chip ID (LSB and MSB)
- * registers match the expected values.
- * Any value of the rom version register is accepted.
- * Returns ENODEV error number if no device is detected, or zero
- * if a device is detected.
- */
-static int tvp514x_detect(struct v4l2_subdev *sd,
- struct tvp514x_decoder *decoder)
-{
- u8 chip_id_msb, chip_id_lsb, rom_ver;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
- chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
- rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
-
- v4l2_dbg(1, debug, sd,
- "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
- chip_id_msb, chip_id_lsb, rom_ver);
- if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
- || ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
- && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
- /* We didn't read the values we expected, so this must not be
- * an TVP5146/47.
- */
- v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
- chip_id_msb, chip_id_lsb);
- return -ENODEV;
- }
-
- decoder->ver = rom_ver;
-
- v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
- client->name, decoder->ver,
- client->addr << 1, client->adapter->name);
- return 0;
-}
-
-/**
- * tvp514x_querystd() - V4L2 decoder interface handler for querystd
- * @sd: pointer to standard V4L2 sub-device structure
- * @std_id: standard V4L2 std_id ioctl enum
- *
- * Returns the current standard detected by TVP5146/47. If no active input is
- * detected then *std_id is set to 0 and the function returns 0.
- */
-static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- enum tvp514x_std current_std;
- enum tvp514x_input input_sel;
- u8 sync_lock_status, lock_mask;
-
- if (std_id == NULL)
- return -EINVAL;
-
- *std_id = V4L2_STD_UNKNOWN;
-
- /* query the current standard */
- current_std = tvp514x_query_current_std(sd);
- if (current_std == STD_INVALID)
- return 0;
-
- input_sel = decoder->input;
-
- switch (input_sel) {
- case INPUT_CVBS_VI1A:
- case INPUT_CVBS_VI1B:
- case INPUT_CVBS_VI1C:
- case INPUT_CVBS_VI2A:
- case INPUT_CVBS_VI2B:
- case INPUT_CVBS_VI2C:
- case INPUT_CVBS_VI3A:
- case INPUT_CVBS_VI3B:
- case INPUT_CVBS_VI3C:
- case INPUT_CVBS_VI4A:
- lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
- STATUS_HORZ_SYNC_LOCK_BIT |
- STATUS_VIRT_SYNC_LOCK_BIT;
- break;
-
- case INPUT_SVIDEO_VI2A_VI1A:
- case INPUT_SVIDEO_VI2B_VI1B:
- case INPUT_SVIDEO_VI2C_VI1C:
- case INPUT_SVIDEO_VI2A_VI3A:
- case INPUT_SVIDEO_VI2B_VI3B:
- case INPUT_SVIDEO_VI2C_VI3C:
- case INPUT_SVIDEO_VI4A_VI1A:
- case INPUT_SVIDEO_VI4A_VI1B:
- case INPUT_SVIDEO_VI4A_VI1C:
- case INPUT_SVIDEO_VI4A_VI3A:
- case INPUT_SVIDEO_VI4A_VI3B:
- case INPUT_SVIDEO_VI4A_VI3C:
- lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
- STATUS_VIRT_SYNC_LOCK_BIT;
- break;
- /*Need to add other interfaces*/
- default:
- return -EINVAL;
- }
- /* check whether signal is locked */
- sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
- if (lock_mask != (sync_lock_status & lock_mask))
- return 0; /* No input detected */
-
- *std_id = decoder->std_list[current_std].standard.id;
-
- v4l2_dbg(1, debug, sd, "Current STD: %s\n",
- decoder->std_list[current_std].standard.name);
- return 0;
-}
-
-/**
- * tvp514x_s_std() - V4L2 decoder interface handler for s_std
- * @sd: pointer to standard V4L2 sub-device structure
- * @std_id: standard V4L2 v4l2_std_id ioctl enum
- *
- * If std_id is supported, sets the requested standard. Otherwise, returns
- * -EINVAL
- */
-static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- int err, i;
-
- for (i = 0; i < decoder->num_stds; i++)
- if (std_id & decoder->std_list[i].standard.id)
- break;
-
- if ((i == decoder->num_stds) || (i == STD_INVALID))
- return -EINVAL;
-
- err = tvp514x_write_reg(sd, REG_VIDEO_STD,
- decoder->std_list[i].video_std);
- if (err)
- return err;
-
- decoder->current_std = i;
- decoder->tvp514x_regs[REG_VIDEO_STD].val =
- decoder->std_list[i].video_std;
-
- v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
- decoder->std_list[i].standard.name);
- return 0;
-}
-
-/**
- * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
- * @sd: pointer to standard V4L2 sub-device structure
- * @input: input selector for routing the signal
- * @output: output selector for routing the signal
- * @config: config value. Not used
- *
- * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
- * the input is not supported or there is no active signal present in the
- * selected input.
- */
-static int tvp514x_s_routing(struct v4l2_subdev *sd,
- u32 input, u32 output, u32 config)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- int err;
- enum tvp514x_input input_sel;
- enum tvp514x_output output_sel;
- u8 sync_lock_status, lock_mask;
- int try_count = LOCK_RETRY_COUNT;
-
- if ((input >= INPUT_INVALID) ||
- (output >= OUTPUT_INVALID))
- /* Index out of bound */
- return -EINVAL;
-
- /*
- * For the sequence streamon -> streamoff and again s_input
- * it fails to lock the signal, since streamoff puts TVP514x
- * into power off state which leads to failure in sub-sequent s_input.
- *
- * So power up the TVP514x device here, since it is important to lock
- * the signal at this stage.
- */
- if (!decoder->streaming)
- tvp514x_s_stream(sd, 1);
-
- input_sel = input;
- output_sel = output;
-
- err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
- if (err)
- return err;
-
- output_sel |= tvp514x_read_reg(sd,
- REG_OUTPUT_FORMATTER1) & 0x7;
- err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
- output_sel);
- if (err)
- return err;
-
- decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
- decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
-
- /* Clear status */
- msleep(LOCK_RETRY_DELAY);
- err =
- tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
- if (err)
- return err;
-
- switch (input_sel) {
- case INPUT_CVBS_VI1A:
- case INPUT_CVBS_VI1B:
- case INPUT_CVBS_VI1C:
- case INPUT_CVBS_VI2A:
- case INPUT_CVBS_VI2B:
- case INPUT_CVBS_VI2C:
- case INPUT_CVBS_VI3A:
- case INPUT_CVBS_VI3B:
- case INPUT_CVBS_VI3C:
- case INPUT_CVBS_VI4A:
- lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
- STATUS_HORZ_SYNC_LOCK_BIT |
- STATUS_VIRT_SYNC_LOCK_BIT;
- break;
-
- case INPUT_SVIDEO_VI2A_VI1A:
- case INPUT_SVIDEO_VI2B_VI1B:
- case INPUT_SVIDEO_VI2C_VI1C:
- case INPUT_SVIDEO_VI2A_VI3A:
- case INPUT_SVIDEO_VI2B_VI3B:
- case INPUT_SVIDEO_VI2C_VI3C:
- case INPUT_SVIDEO_VI4A_VI1A:
- case INPUT_SVIDEO_VI4A_VI1B:
- case INPUT_SVIDEO_VI4A_VI1C:
- case INPUT_SVIDEO_VI4A_VI3A:
- case INPUT_SVIDEO_VI4A_VI3B:
- case INPUT_SVIDEO_VI4A_VI3C:
- lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
- STATUS_VIRT_SYNC_LOCK_BIT;
- break;
- /* Need to add other interfaces*/
- default:
- return -EINVAL;
- }
-
- while (try_count-- > 0) {
- /* Allow decoder to sync up with new input */
- msleep(LOCK_RETRY_DELAY);
-
- sync_lock_status = tvp514x_read_reg(sd,
- REG_STATUS1);
- if (lock_mask == (sync_lock_status & lock_mask))
- /* Input detected */
- break;
- }
-
- if (try_count < 0)
- return -EINVAL;
-
- decoder->input = input;
- decoder->output = output;
-
- v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
-
- return 0;
-}
-
-/**
- * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
- * @ctrl: pointer to v4l2_ctrl structure
- *
- * If the requested control is supported, sets the control's current
- * value in HW. Otherwise, returns -EINVAL if the control is not supported.
- */
-static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct tvp514x_decoder *decoder = to_decoder(sd);
- int err = -EINVAL, value;
-
- value = ctrl->val;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value);
- if (!err)
- decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
- break;
- case V4L2_CID_CONTRAST:
- err = tvp514x_write_reg(sd, REG_CONTRAST, value);
- if (!err)
- decoder->tvp514x_regs[REG_CONTRAST].val = value;
- break;
- case V4L2_CID_SATURATION:
- err = tvp514x_write_reg(sd, REG_SATURATION, value);
- if (!err)
- decoder->tvp514x_regs[REG_SATURATION].val = value;
- break;
- case V4L2_CID_HUE:
- if (value == 180)
- value = 0x7F;
- else if (value == -180)
- value = 0x80;
- err = tvp514x_write_reg(sd, REG_HUE, value);
- if (!err)
- decoder->tvp514x_regs[REG_HUE].val = value;
- break;
- case V4L2_CID_AUTOGAIN:
- err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c);
- if (!err)
- decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
- break;
- }
-
- v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
- ctrl->id, ctrl->val);
- return err;
-}
-
-/**
- * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @index: index of pixelcode to retrieve
- * @code: receives the pixelcode
- *
- * Enumerates supported mediabus formats
- */
-static int
-tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index)
- return -EINVAL;
-
- *code = V4L2_MBUS_FMT_YUYV10_2X10;
- return 0;
-}
-
-/**
- * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to the mediabus format structure
- *
- * Negotiates the image capture size and mediabus format.
- */
-static int
-tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- enum tvp514x_std current_std;
-
- if (f == NULL)
- return -EINVAL;
-
- /* Calculate height and width based on current standard */
- current_std = decoder->current_std;
-
- f->code = V4L2_MBUS_FMT_YUYV10_2X10;
- f->width = decoder->std_list[current_std].width;
- f->height = decoder->std_list[current_std].height;
- f->field = V4L2_FIELD_INTERLACED;
- f->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
- f->width, f->height);
- return 0;
-}
-
-/**
- * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
- * @sd: pointer to standard V4L2 sub-device structure
- * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
- *
- * Returns the decoder's video CAPTURE parameters.
- */
-static int
-tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- struct v4l2_captureparm *cparm;
- enum tvp514x_std current_std;
-
- if (a == NULL)
- return -EINVAL;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- /* get the current standard */
- current_std = decoder->current_std;
-
- cparm = &a->parm.capture;
- cparm->capability = V4L2_CAP_TIMEPERFRAME;
- cparm->timeperframe =
- decoder->std_list[current_std].standard.frameperiod;
-
- return 0;
-}
-
-/**
- * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
- * @sd: pointer to standard V4L2 sub-device structure
- * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
- *
- * Configures the decoder to use the input parameters, if possible. If
- * not possible, returns the appropriate error code.
- */
-static int
-tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- struct v4l2_fract *timeperframe;
- enum tvp514x_std current_std;
-
- if (a == NULL)
- return -EINVAL;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- timeperframe = &a->parm.capture.timeperframe;
-
- /* get the current standard */
- current_std = decoder->current_std;
-
- *timeperframe =
- decoder->std_list[current_std].standard.frameperiod;
-
- return 0;
-}
-
-/**
- * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream
- * @sd: pointer to standard V4L2 sub-device structure
- * @enable: streaming enable or disable
- *
- * Sets streaming to enable or disable, if possible.
- */
-static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
-{
- int err = 0;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tvp514x_decoder *decoder = to_decoder(sd);
-
- if (decoder->streaming == enable)
- return 0;
-
- switch (enable) {
- case 0:
- {
- /* Power Down Sequence */
- err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
- if (err) {
- v4l2_err(sd, "Unable to turn off decoder\n");
- return err;
- }
- decoder->streaming = enable;
- break;
- }
- case 1:
- {
- struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
- client->driver->id_table->driver_data;
-
- /* Power Up Sequence */
- err = tvp514x_write_regs(sd, int_seq);
- if (err) {
- v4l2_err(sd, "Unable to turn on decoder\n");
- return err;
- }
- /* Detect if not already detected */
- err = tvp514x_detect(sd, decoder);
- if (err) {
- v4l2_err(sd, "Unable to detect decoder\n");
- return err;
- }
- err = tvp514x_configure(sd, decoder);
- if (err) {
- v4l2_err(sd, "Unable to configure decoder\n");
- return err;
- }
- decoder->streaming = enable;
- break;
- }
- default:
- err = -ENODEV;
- break;
- }
-
- return err;
-}
-
-static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
- .s_ctrl = tvp514x_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
- .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
- .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
- .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
- .queryctrl = v4l2_subdev_queryctrl,
- .querymenu = v4l2_subdev_querymenu,
- .s_std = tvp514x_s_std,
-};
-
-static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
- .s_routing = tvp514x_s_routing,
- .querystd = tvp514x_querystd,
- .enum_mbus_fmt = tvp514x_enum_mbus_fmt,
- .g_mbus_fmt = tvp514x_mbus_fmt,
- .try_mbus_fmt = tvp514x_mbus_fmt,
- .s_mbus_fmt = tvp514x_mbus_fmt,
- .g_parm = tvp514x_g_parm,
- .s_parm = tvp514x_s_parm,
- .s_stream = tvp514x_s_stream,
-};
-
-static const struct v4l2_subdev_ops tvp514x_ops = {
- .core = &tvp514x_core_ops,
- .video = &tvp514x_video_ops,
-};
-
-static struct tvp514x_decoder tvp514x_dev = {
- .streaming = 0,
- .current_std = STD_NTSC_MJ,
- .std_list = tvp514x_std_list,
- .num_stds = ARRAY_SIZE(tvp514x_std_list),
-
-};
-
-/**
- * tvp514x_probe() - decoder driver i2c probe handler
- * @client: i2c driver client device structure
- * @id: i2c driver id table
- *
- * Register decoder as an i2c client device and V4L2
- * device.
- */
-static int
-tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
- struct tvp514x_decoder *decoder;
- struct v4l2_subdev *sd;
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
- if (!client->dev.platform_data) {
- v4l2_err(client, "No platform data!!\n");
- return -ENODEV;
- }
-
- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
- if (!decoder)
- return -ENOMEM;
-
- /* Initialize the tvp514x_decoder with default configuration */
- *decoder = tvp514x_dev;
- /* Copy default register configuration */
- memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
- sizeof(tvp514x_reg_list_default));
-
- /* Copy board specific information here */
- decoder->pdata = client->dev.platform_data;
-
- /**
- * Fetch platform specific data, and configure the
- * tvp514x_reg_list[] accordingly. Since this is one
- * time configuration, no need to preserve.
- */
- decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
- (decoder->pdata->clk_polarity << 1);
- decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
- ((decoder->pdata->hs_polarity << 2) |
- (decoder->pdata->vs_polarity << 3));
- /* Set default standard to auto */
- decoder->tvp514x_regs[REG_VIDEO_STD].val =
- VIDEO_STD_AUTO_SWITCH_BIT;
-
- /* Register with V4L2 layer as slave device */
- sd = &decoder->sd;
- v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
-
- v4l2_ctrl_handler_init(&decoder->hdl, 5);
- v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
- V4L2_CID_HUE, -180, 180, 180, 0);
- v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
- V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- sd->ctrl_handler = &decoder->hdl;
- if (decoder->hdl.error) {
- int err = decoder->hdl.error;
-
- v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
- return err;
- }
- v4l2_ctrl_handler_setup(&decoder->hdl);
-
- v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
-
- return 0;
-
-}
-
-/**
- * tvp514x_remove() - decoder driver i2c remove handler
- * @client: i2c driver client device structure
- *
- * Unregister decoder as an i2c client device and V4L2
- * device. Complement of tvp514x_probe().
- */
-static int tvp514x_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct tvp514x_decoder *decoder = to_decoder(sd);
-
- v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
- return 0;
-}
-/* TVP5146 Init/Power on Sequence */
-static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
- {TOK_WRITE, REG_OPERATION_MODE, 0x01},
- {TOK_WRITE, REG_OPERATION_MODE, 0x00},
- {TOK_TERM, 0, 0},
-};
-
-/* TVP5147 Init/Power on Sequence */
-static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
- {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
- {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
- {TOK_WRITE, REG_OPERATION_MODE, 0x01},
- {TOK_WRITE, REG_OPERATION_MODE, 0x00},
- {TOK_TERM, 0, 0},
-};
-
-/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
-static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
- {TOK_WRITE, REG_OPERATION_MODE, 0x01},
- {TOK_WRITE, REG_OPERATION_MODE, 0x00},
- {TOK_TERM, 0, 0},
-};
-
-/**
- * I2C Device Table -
- *
- * name - Name of the actual device/chip.
- * driver_data - Driver data
- */
-static const struct i2c_device_id tvp514x_id[] = {
- {"tvp5146", (unsigned long)tvp5146_init_reg_seq},
- {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
- {"tvp5147", (unsigned long)tvp5147_init_reg_seq},
- {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
- {},
-};
-
-MODULE_DEVICE_TABLE(i2c, tvp514x_id);
-
-static struct i2c_driver tvp514x_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = TVP514X_MODULE_NAME,
- },
- .probe = tvp514x_probe,
- .remove = tvp514x_remove,
- .id_table = tvp514x_id,
-};
-
-module_i2c_driver(tvp514x_driver);
diff --git a/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
deleted file mode 100644
index 18f29ad0dfe2..000000000000
--- a/drivers/media/video/tvp514x_regs.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * drivers/media/video/tvp514x_regs.h
- *
- * Copyright (C) 2008 Texas Instruments Inc
- * Author: Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * Contributors:
- * Sivaraj R <sivaraj@ti.com>
- * Brijesh R Jadav <brijesh.j@ti.com>
- * Hardik Shah <hardik.shah@ti.com>
- * Manjunath Hadli <mrh@ti.com>
- * Karicheri Muralidharan <m-karicheri2@ti.com>
- *
- * This package 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 _TVP514X_REGS_H
-#define _TVP514X_REGS_H
-
-/*
- * TVP5146/47 registers
- */
-#define REG_INPUT_SEL (0x00)
-#define REG_AFE_GAIN_CTRL (0x01)
-#define REG_VIDEO_STD (0x02)
-#define REG_OPERATION_MODE (0x03)
-#define REG_AUTOSWITCH_MASK (0x04)
-
-#define REG_COLOR_KILLER (0x05)
-#define REG_LUMA_CONTROL1 (0x06)
-#define REG_LUMA_CONTROL2 (0x07)
-#define REG_LUMA_CONTROL3 (0x08)
-
-#define REG_BRIGHTNESS (0x09)
-#define REG_CONTRAST (0x0A)
-#define REG_SATURATION (0x0B)
-#define REG_HUE (0x0C)
-
-#define REG_CHROMA_CONTROL1 (0x0D)
-#define REG_CHROMA_CONTROL2 (0x0E)
-
-/* 0x0F Reserved */
-
-#define REG_COMP_PR_SATURATION (0x10)
-#define REG_COMP_Y_CONTRAST (0x11)
-#define REG_COMP_PB_SATURATION (0x12)
-
-/* 0x13 Reserved */
-
-#define REG_COMP_Y_BRIGHTNESS (0x14)
-
-/* 0x15 Reserved */
-
-#define REG_AVID_START_PIXEL_LSB (0x16)
-#define REG_AVID_START_PIXEL_MSB (0x17)
-#define REG_AVID_STOP_PIXEL_LSB (0x18)
-#define REG_AVID_STOP_PIXEL_MSB (0x19)
-
-#define REG_HSYNC_START_PIXEL_LSB (0x1A)
-#define REG_HSYNC_START_PIXEL_MSB (0x1B)
-#define REG_HSYNC_STOP_PIXEL_LSB (0x1C)
-#define REG_HSYNC_STOP_PIXEL_MSB (0x1D)
-
-#define REG_VSYNC_START_LINE_LSB (0x1E)
-#define REG_VSYNC_START_LINE_MSB (0x1F)
-#define REG_VSYNC_STOP_LINE_LSB (0x20)
-#define REG_VSYNC_STOP_LINE_MSB (0x21)
-
-#define REG_VBLK_START_LINE_LSB (0x22)
-#define REG_VBLK_START_LINE_MSB (0x23)
-#define REG_VBLK_STOP_LINE_LSB (0x24)
-#define REG_VBLK_STOP_LINE_MSB (0x25)
-
-/* 0x26 - 0x27 Reserved */
-
-#define REG_FAST_SWTICH_CONTROL (0x28)
-
-/* 0x29 Reserved */
-
-#define REG_FAST_SWTICH_SCART_DELAY (0x2A)
-
-/* 0x2B Reserved */
-
-#define REG_SCART_DELAY (0x2C)
-#define REG_CTI_DELAY (0x2D)
-#define REG_CTI_CONTROL (0x2E)
-
-/* 0x2F - 0x31 Reserved */
-
-#define REG_SYNC_CONTROL (0x32)
-#define REG_OUTPUT_FORMATTER1 (0x33)
-#define REG_OUTPUT_FORMATTER2 (0x34)
-#define REG_OUTPUT_FORMATTER3 (0x35)
-#define REG_OUTPUT_FORMATTER4 (0x36)
-#define REG_OUTPUT_FORMATTER5 (0x37)
-#define REG_OUTPUT_FORMATTER6 (0x38)
-#define REG_CLEAR_LOST_LOCK (0x39)
-
-#define REG_STATUS1 (0x3A)
-#define REG_STATUS2 (0x3B)
-
-#define REG_AGC_GAIN_STATUS_LSB (0x3C)
-#define REG_AGC_GAIN_STATUS_MSB (0x3D)
-
-/* 0x3E Reserved */
-
-#define REG_VIDEO_STD_STATUS (0x3F)
-#define REG_GPIO_INPUT1 (0x40)
-#define REG_GPIO_INPUT2 (0x41)
-
-/* 0x42 - 0x45 Reserved */
-
-#define REG_AFE_COARSE_GAIN_CH1 (0x46)
-#define REG_AFE_COARSE_GAIN_CH2 (0x47)
-#define REG_AFE_COARSE_GAIN_CH3 (0x48)
-#define REG_AFE_COARSE_GAIN_CH4 (0x49)
-
-#define REG_AFE_FINE_GAIN_PB_B_LSB (0x4A)
-#define REG_AFE_FINE_GAIN_PB_B_MSB (0x4B)
-#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB (0x4C)
-#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB (0x4D)
-#define REG_AFE_FINE_GAIN_PR_R_LSB (0x4E)
-#define REG_AFE_FINE_GAIN_PR_R_MSB (0x4F)
-#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB (0x50)
-#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB (0x51)
-
-/* 0x52 - 0x68 Reserved */
-
-#define REG_FBIT_VBIT_CONTROL1 (0x69)
-
-/* 0x6A - 0x6B Reserved */
-
-#define REG_BACKEND_AGC_CONTROL (0x6C)
-
-/* 0x6D - 0x6E Reserved */
-
-#define REG_AGC_DECREMENT_SPEED_CONTROL (0x6F)
-#define REG_ROM_VERSION (0x70)
-
-/* 0x71 - 0x73 Reserved */
-
-#define REG_AGC_WHITE_PEAK_PROCESSING (0x74)
-#define REG_FBIT_VBIT_CONTROL2 (0x75)
-#define REG_VCR_TRICK_MODE_CONTROL (0x76)
-#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77)
-#define REG_AGC_INCREMENT_SPEED (0x78)
-#define REG_AGC_INCREMENT_DELAY (0x79)
-
-/* 0x7A - 0x7F Reserved */
-
-#define REG_CHIP_ID_MSB (0x80)
-#define REG_CHIP_ID_LSB (0x81)
-
-/* 0x82 Reserved */
-
-#define REG_CPLL_SPEED_CONTROL (0x83)
-
-/* 0x84 - 0x96 Reserved */
-
-#define REG_STATUS_REQUEST (0x97)
-
-/* 0x98 - 0x99 Reserved */
-
-#define REG_VERTICAL_LINE_COUNT_LSB (0x9A)
-#define REG_VERTICAL_LINE_COUNT_MSB (0x9B)
-
-/* 0x9C - 0x9D Reserved */
-
-#define REG_AGC_DECREMENT_DELAY (0x9E)
-
-/* 0x9F - 0xB0 Reserved */
-
-#define REG_VDP_TTX_FILTER_1_MASK1 (0xB1)
-#define REG_VDP_TTX_FILTER_1_MASK2 (0xB2)
-#define REG_VDP_TTX_FILTER_1_MASK3 (0xB3)
-#define REG_VDP_TTX_FILTER_1_MASK4 (0xB4)
-#define REG_VDP_TTX_FILTER_1_MASK5 (0xB5)
-#define REG_VDP_TTX_FILTER_2_MASK1 (0xB6)
-#define REG_VDP_TTX_FILTER_2_MASK2 (0xB7)
-#define REG_VDP_TTX_FILTER_2_MASK3 (0xB8)
-#define REG_VDP_TTX_FILTER_2_MASK4 (0xB9)
-#define REG_VDP_TTX_FILTER_2_MASK5 (0xBA)
-#define REG_VDP_TTX_FILTER_CONTROL (0xBB)
-#define REG_VDP_FIFO_WORD_COUNT (0xBC)
-#define REG_VDP_FIFO_INTERRUPT_THRLD (0xBD)
-
-/* 0xBE Reserved */
-
-#define REG_VDP_FIFO_RESET (0xBF)
-#define REG_VDP_FIFO_OUTPUT_CONTROL (0xC0)
-#define REG_VDP_LINE_NUMBER_INTERRUPT (0xC1)
-#define REG_VDP_PIXEL_ALIGNMENT_LSB (0xC2)
-#define REG_VDP_PIXEL_ALIGNMENT_MSB (0xC3)
-
-/* 0xC4 - 0xD5 Reserved */
-
-#define REG_VDP_LINE_START (0xD6)
-#define REG_VDP_LINE_STOP (0xD7)
-#define REG_VDP_GLOBAL_LINE_MODE (0xD8)
-#define REG_VDP_FULL_FIELD_ENABLE (0xD9)
-#define REG_VDP_FULL_FIELD_MODE (0xDA)
-
-/* 0xDB - 0xDF Reserved */
-
-#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0)
-#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR (0xE1)
-#define REG_FIFO_READ_DATA (0xE2)
-
-/* 0xE3 - 0xE7 Reserved */
-
-#define REG_VBUS_ADDRESS_ACCESS1 (0xE8)
-#define REG_VBUS_ADDRESS_ACCESS2 (0xE9)
-#define REG_VBUS_ADDRESS_ACCESS3 (0xEA)
-
-/* 0xEB - 0xEF Reserved */
-
-#define REG_INTERRUPT_RAW_STATUS0 (0xF0)
-#define REG_INTERRUPT_RAW_STATUS1 (0xF1)
-#define REG_INTERRUPT_STATUS0 (0xF2)
-#define REG_INTERRUPT_STATUS1 (0xF3)
-#define REG_INTERRUPT_MASK0 (0xF4)
-#define REG_INTERRUPT_MASK1 (0xF5)
-#define REG_INTERRUPT_CLEAR0 (0xF6)
-#define REG_INTERRUPT_CLEAR1 (0xF7)
-
-/* 0xF8 - 0xFF Reserved */
-
-/*
- * Mask and bit definitions of TVP5146/47 registers
- */
-/* The ID values we are looking for */
-#define TVP514X_CHIP_ID_MSB (0x51)
-#define TVP5146_CHIP_ID_LSB (0x46)
-#define TVP5147_CHIP_ID_LSB (0x47)
-
-#define VIDEO_STD_MASK (0x07)
-#define VIDEO_STD_AUTO_SWITCH_BIT (0x00)
-#define VIDEO_STD_NTSC_MJ_BIT (0x01)
-#define VIDEO_STD_PAL_BDGHIN_BIT (0x02)
-#define VIDEO_STD_PAL_M_BIT (0x03)
-#define VIDEO_STD_PAL_COMBINATION_N_BIT (0x04)
-#define VIDEO_STD_NTSC_4_43_BIT (0x05)
-#define VIDEO_STD_SECAM_BIT (0x06)
-#define VIDEO_STD_PAL_60_BIT (0x07)
-
-/*
- * Status bit
- */
-#define STATUS_TV_VCR_BIT (1<<0)
-#define STATUS_HORZ_SYNC_LOCK_BIT (1<<1)
-#define STATUS_VIRT_SYNC_LOCK_BIT (1<<2)
-#define STATUS_CLR_SUBCAR_LOCK_BIT (1<<3)
-#define STATUS_LOST_LOCK_DETECT_BIT (1<<4)
-#define STATUS_FEILD_RATE_BIT (1<<5)
-#define STATUS_LINE_ALTERNATING_BIT (1<<6)
-#define STATUS_PEAK_WHITE_DETECT_BIT (1<<7)
-
-/* Tokens for register write */
-#define TOK_WRITE (0) /* token for write operation */
-#define TOK_TERM (1) /* terminating token */
-#define TOK_DELAY (2) /* delay token for reg list */
-#define TOK_SKIP (3) /* token to skip a register */
-/**
- * struct tvp514x_reg - Structure for TVP5146/47 register initialization values
- * @token - Token: TOK_WRITE, TOK_TERM etc..
- * @reg - Register offset
- * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
- */
-struct tvp514x_reg {
- u8 token;
- u8 reg;
- u32 val;
-};
-
-#endif /* ifndef _TVP514X_REGS_H */
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
deleted file mode 100644
index 9f53eacb66e3..000000000000
--- a/drivers/media/video/tw9910.c
+++ /dev/null
@@ -1,956 +0,0 @@
-/*
- * tw9910 Video Driver
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov772x driver,
- *
- * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/soc_camera.h>
-#include <media/tw9910.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-subdev.h>
-
-#define GET_ID(val) ((val & 0xF8) >> 3)
-#define GET_REV(val) (val & 0x07)
-
-/*
- * register offset
- */
-#define ID 0x00 /* Product ID Code Register */
-#define STATUS1 0x01 /* Chip Status Register I */
-#define INFORM 0x02 /* Input Format */
-#define OPFORM 0x03 /* Output Format Control Register */
-#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */
-#define OUTCTR1 0x05 /* Output Control I */
-#define ACNTL1 0x06 /* Analog Control Register 1 */
-#define CROP_HI 0x07 /* Cropping Register, High */
-#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */
-#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */
-#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */
-#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */
-#define CNTRL1 0x0C /* Control Register I */
-#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */
-#define SCALE_HI 0x0E /* Scaling Register, High */
-#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */
-#define BRIGHT 0x10 /* BRIGHTNESS Control Register */
-#define CONTRAST 0x11 /* CONTRAST Control Register */
-#define SHARPNESS 0x12 /* SHARPNESS Control Register I */
-#define SAT_U 0x13 /* Chroma (U) Gain Register */
-#define SAT_V 0x14 /* Chroma (V) Gain Register */
-#define HUE 0x15 /* Hue Control Register */
-#define CORING1 0x17
-#define CORING2 0x18 /* Coring and IF compensation */
-#define VBICNTL 0x19 /* VBI Control Register */
-#define ACNTL2 0x1A /* Analog Control 2 */
-#define OUTCTR2 0x1B /* Output Control 2 */
-#define SDT 0x1C /* Standard Selection */
-#define SDTR 0x1D /* Standard Recognition */
-#define TEST 0x1F /* Test Control Register */
-#define CLMPG 0x20 /* Clamping Gain */
-#define IAGC 0x21 /* Individual AGC Gain */
-#define AGCGAIN 0x22 /* AGC Gain */
-#define PEAKWT 0x23 /* White Peak Threshold */
-#define CLMPL 0x24 /* Clamp level */
-#define SYNCT 0x25 /* Sync Amplitude */
-#define MISSCNT 0x26 /* Sync Miss Count Register */
-#define PCLAMP 0x27 /* Clamp Position Register */
-#define VCNTL1 0x28 /* Vertical Control I */
-#define VCNTL2 0x29 /* Vertical Control II */
-#define CKILL 0x2A /* Color Killer Level Control */
-#define COMB 0x2B /* Comb Filter Control */
-#define LDLY 0x2C /* Luma Delay and H Filter Control */
-#define MISC1 0x2D /* Miscellaneous Control I */
-#define LOOP 0x2E /* LOOP Control Register */
-#define MISC2 0x2F /* Miscellaneous Control II */
-#define MVSN 0x30 /* Macrovision Detection */
-#define STATUS2 0x31 /* Chip STATUS II */
-#define HFREF 0x32 /* H monitor */
-#define CLMD 0x33 /* CLAMP MODE */
-#define IDCNTL 0x34 /* ID Detection Control */
-#define CLCNTL1 0x35 /* Clamp Control I */
-#define ANAPLLCTL 0x4C
-#define VBIMIN 0x4D
-#define HSLOWCTL 0x4E
-#define WSS3 0x4F
-#define FILLDATA 0x50
-#define SDID 0x51
-#define DID 0x52
-#define WSS1 0x53
-#define WSS2 0x54
-#define VVBI 0x55
-#define LCTL6 0x56
-#define LCTL7 0x57
-#define LCTL8 0x58
-#define LCTL9 0x59
-#define LCTL10 0x5A
-#define LCTL11 0x5B
-#define LCTL12 0x5C
-#define LCTL13 0x5D
-#define LCTL14 0x5E
-#define LCTL15 0x5F
-#define LCTL16 0x60
-#define LCTL17 0x61
-#define LCTL18 0x62
-#define LCTL19 0x63
-#define LCTL20 0x64
-#define LCTL21 0x65
-#define LCTL22 0x66
-#define LCTL23 0x67
-#define LCTL24 0x68
-#define LCTL25 0x69
-#define LCTL26 0x6A
-#define HSBEGIN 0x6B
-#define HSEND 0x6C
-#define OVSDLY 0x6D
-#define OVSEND 0x6E
-#define VBIDELAY 0x6F
-
-/*
- * register detail
- */
-
-/* INFORM */
-#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */
-#define FC27_FF 0x00 /* 0 : Square pixel mode. */
- /* Must use 24.54MHz for 60Hz field rate */
- /* source or 29.5MHz for 50Hz field rate */
-#define IFSEL_S 0x10 /* 01 : S-video decoding */
-#define IFSEL_C 0x00 /* 00 : Composite video decoding */
- /* Y input video selection */
-#define YSEL_M0 0x00 /* 00 : Mux0 selected */
-#define YSEL_M1 0x04 /* 01 : Mux1 selected */
-#define YSEL_M2 0x08 /* 10 : Mux2 selected */
-#define YSEL_M3 0x10 /* 11 : Mux3 selected */
-
-/* OPFORM */
-#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
- /* 1 : ITU-R-656 compatible data sequence format */
-#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
- /* 1 : 16-bit YCrCb 4:2:2 output format.*/
-#define LLCMODE 0x20 /* 1 : LLC output mode. */
- /* 0 : free-run output mode */
-#define AINC 0x10 /* Serial interface auto-indexing control */
- /* 0 : auto-increment */
- /* 1 : non-auto */
-#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */
- /* 0 : Vertical out ctrl by HACTIVE and DVALID */
-#define OEN_TRI_SEL_MASK 0x07
-#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */
-#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */
-#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */
-
-/* OUTCTR1 */
-#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */
-#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */
- /* VS pin output control */
-#define VSSL_VSYNC 0x00 /* 0 : VSYNC */
-#define VSSL_VACT 0x10 /* 1 : VACT */
-#define VSSL_FIELD 0x20 /* 2 : FIELD */
-#define VSSL_VVALID 0x30 /* 3 : VVALID */
-#define VSSL_ZERO 0x70 /* 7 : 0 */
-#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */
-#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/
- /* HS pin output control */
-#define HSSL_HACT 0x00 /* 0 : HACT */
-#define HSSL_HSYNC 0x01 /* 1 : HSYNC */
-#define HSSL_DVALID 0x02 /* 2 : DVALID */
-#define HSSL_HLOCK 0x03 /* 3 : HLOCK */
-#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */
-#define HSSL_ZERO 0x07 /* 7 : 0 */
-
-/* ACNTL1 */
-#define SRESET 0x80 /* resets the device to its default state
- * but all register content remain unchanged.
- * This bit is self-resetting.
- */
-#define ACNTL1_PDN_MASK 0x0e
-#define CLK_PDN 0x08 /* system clock power down */
-#define Y_PDN 0x04 /* Luma ADC power down */
-#define C_PDN 0x02 /* Chroma ADC power down */
-
-/* ACNTL2 */
-#define ACNTL2_PDN_MASK 0x40
-#define PLL_PDN 0x40 /* PLL power down */
-
-/* VBICNTL */
-
-/* RTSEL : control the real time signal output from the MPOUT pin */
-#define RTSEL_MASK 0x07
-#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
-#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
-#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
-#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
-#define RTSEL_MONO 0x04 /* 0100 = MONO */
-#define RTSEL_DET50 0x05 /* 0101 = DET50 */
-#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
-#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */
-
-/* HSYNC start and end are constant for now */
-#define HSYNC_START 0x0260
-#define HSYNC_END 0x0300
-
-/*
- * structure
- */
-
-struct regval_list {
- unsigned char reg_num;
- unsigned char value;
-};
-
-struct tw9910_scale_ctrl {
- char *name;
- unsigned short width;
- unsigned short height;
- u16 hscale;
- u16 vscale;
-};
-
-struct tw9910_priv {
- struct v4l2_subdev subdev;
- struct tw9910_video_info *info;
- const struct tw9910_scale_ctrl *scale;
- v4l2_std_id norm;
- u32 revision;
-};
-
-static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
- {
- .name = "NTSC SQ",
- .width = 640,
- .height = 480,
- .hscale = 0x0100,
- .vscale = 0x0100,
- },
- {
- .name = "NTSC CCIR601",
- .width = 720,
- .height = 480,
- .hscale = 0x0100,
- .vscale = 0x0100,
- },
- {
- .name = "NTSC SQ (CIF)",
- .width = 320,
- .height = 240,
- .hscale = 0x0200,
- .vscale = 0x0200,
- },
- {
- .name = "NTSC CCIR601 (CIF)",
- .width = 360,
- .height = 240,
- .hscale = 0x0200,
- .vscale = 0x0200,
- },
- {
- .name = "NTSC SQ (QCIF)",
- .width = 160,
- .height = 120,
- .hscale = 0x0400,
- .vscale = 0x0400,
- },
- {
- .name = "NTSC CCIR601 (QCIF)",
- .width = 180,
- .height = 120,
- .hscale = 0x0400,
- .vscale = 0x0400,
- },
-};
-
-static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
- {
- .name = "PAL SQ",
- .width = 768,
- .height = 576,
- .hscale = 0x0100,
- .vscale = 0x0100,
- },
- {
- .name = "PAL CCIR601",
- .width = 720,
- .height = 576,
- .hscale = 0x0100,
- .vscale = 0x0100,
- },
- {
- .name = "PAL SQ (CIF)",
- .width = 384,
- .height = 288,
- .hscale = 0x0200,
- .vscale = 0x0200,
- },
- {
- .name = "PAL CCIR601 (CIF)",
- .width = 360,
- .height = 288,
- .hscale = 0x0200,
- .vscale = 0x0200,
- },
- {
- .name = "PAL SQ (QCIF)",
- .width = 192,
- .height = 144,
- .hscale = 0x0400,
- .vscale = 0x0400,
- },
- {
- .name = "PAL CCIR601 (QCIF)",
- .width = 180,
- .height = 144,
- .hscale = 0x0400,
- .vscale = 0x0400,
- },
-};
-
-/*
- * general function
- */
-static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
-{
- return container_of(i2c_get_clientdata(client), struct tw9910_priv,
- subdev);
-}
-
-static int tw9910_mask_set(struct i2c_client *client, u8 command,
- u8 mask, u8 set)
-{
- s32 val = i2c_smbus_read_byte_data(client, command);
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- return i2c_smbus_write_byte_data(client, command, val);
-}
-
-static int tw9910_set_scale(struct i2c_client *client,
- const struct tw9910_scale_ctrl *scale)
-{
- int ret;
-
- ret = i2c_smbus_write_byte_data(client, SCALE_HI,
- (scale->vscale & 0x0F00) >> 4 |
- (scale->hscale & 0x0F00) >> 8);
- if (ret < 0)
- return ret;
-
- ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
- scale->hscale & 0x00FF);
- if (ret < 0)
- return ret;
-
- ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
- scale->vscale & 0x00FF);
-
- return ret;
-}
-
-static int tw9910_set_hsync(struct i2c_client *client)
-{
- struct tw9910_priv *priv = to_tw9910(client);
- int ret;
-
- /* bit 10 - 3 */
- ret = i2c_smbus_write_byte_data(client, HSBEGIN,
- (HSYNC_START & 0x07F8) >> 3);
- if (ret < 0)
- return ret;
-
- /* bit 10 - 3 */
- ret = i2c_smbus_write_byte_data(client, HSEND,
- (HSYNC_END & 0x07F8) >> 3);
- if (ret < 0)
- return ret;
-
- /* So far only revisions 0 and 1 have been seen */
- /* bit 2 - 0 */
- if (1 == priv->revision)
- ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
- (HSYNC_START & 0x0007) << 4 |
- (HSYNC_END & 0x0007));
-
- return ret;
-}
-
-static void tw9910_reset(struct i2c_client *client)
-{
- tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
- msleep(1);
-}
-
-static int tw9910_power(struct i2c_client *client, int enable)
-{
- int ret;
- u8 acntl1;
- u8 acntl2;
-
- if (enable) {
- acntl1 = 0;
- acntl2 = 0;
- } else {
- acntl1 = CLK_PDN | Y_PDN | C_PDN;
- acntl2 = PLL_PDN;
- }
-
- ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
- if (ret < 0)
- return ret;
-
- return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
-}
-
-static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
- u32 width, u32 height)
-{
- const struct tw9910_scale_ctrl *scale;
- const struct tw9910_scale_ctrl *ret = NULL;
- __u32 diff = 0xffffffff, tmp;
- int size, i;
-
- if (norm & V4L2_STD_NTSC) {
- scale = tw9910_ntsc_scales;
- size = ARRAY_SIZE(tw9910_ntsc_scales);
- } else if (norm & V4L2_STD_PAL) {
- scale = tw9910_pal_scales;
- size = ARRAY_SIZE(tw9910_pal_scales);
- } else {
- return NULL;
- }
-
- for (i = 0; i < size; i++) {
- tmp = abs(width - scale[i].width) +
- abs(height - scale[i].height);
- if (tmp < diff) {
- diff = tmp;
- ret = scale + i;
- }
- }
-
- return ret;
-}
-
-/*
- * subdevice operations
- */
-static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
- u8 val;
- int ret;
-
- if (!enable) {
- switch (priv->revision) {
- case 0:
- val = OEN_TRI_SEL_ALL_OFF_r0;
- break;
- case 1:
- val = OEN_TRI_SEL_ALL_OFF_r1;
- break;
- default:
- dev_err(&client->dev, "un-supported revision\n");
- return -EINVAL;
- }
- } else {
- val = OEN_TRI_SEL_ALL_ON;
-
- if (!priv->scale) {
- dev_err(&client->dev, "norm select error\n");
- return -EPERM;
- }
-
- dev_dbg(&client->dev, "%s %dx%d\n",
- priv->scale->name,
- priv->scale->width,
- priv->scale->height);
- }
-
- ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
- if (ret < 0)
- return ret;
-
- return tw9910_power(client, enable);
-}
-
-static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- *norm = priv->norm;
-
- return 0;
-}
-
-static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
- return -EINVAL;
-
- priv->norm = norm;
-
- return 0;
-}
-
-static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- id->ident = V4L2_IDENT_TW9910;
- id->revision = priv->revision;
-
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int tw9910_g_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- if (reg->reg > 0xff)
- return -EINVAL;
-
- ret = i2c_smbus_read_byte_data(client, reg->reg);
- if (ret < 0)
- return ret;
-
- /*
- * ret = int
- * reg->val = __u64
- */
- reg->val = (__u64)ret;
-
- return 0;
-}
-
-static int tw9910_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (reg->reg > 0xff ||
- reg->val > 0xff)
- return -EINVAL;
-
- return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
-}
-#endif
-
-static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
- int ret = -EINVAL;
- u8 val;
-
- /*
- * select suitable norm
- */
- priv->scale = tw9910_select_norm(priv->norm, *width, *height);
- if (!priv->scale)
- goto tw9910_set_fmt_error;
-
- /*
- * reset hardware
- */
- tw9910_reset(client);
-
- /*
- * set bus width
- */
- val = 0x00;
- if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
- val = LEN;
-
- ret = tw9910_mask_set(client, OPFORM, LEN, val);
- if (ret < 0)
- goto tw9910_set_fmt_error;
-
- /*
- * select MPOUT behavior
- */
- switch (priv->info->mpout) {
- case TW9910_MPO_VLOSS:
- val = RTSEL_VLOSS; break;
- case TW9910_MPO_HLOCK:
- val = RTSEL_HLOCK; break;
- case TW9910_MPO_SLOCK:
- val = RTSEL_SLOCK; break;
- case TW9910_MPO_VLOCK:
- val = RTSEL_VLOCK; break;
- case TW9910_MPO_MONO:
- val = RTSEL_MONO; break;
- case TW9910_MPO_DET50:
- val = RTSEL_DET50; break;
- case TW9910_MPO_FIELD:
- val = RTSEL_FIELD; break;
- case TW9910_MPO_RTCO:
- val = RTSEL_RTCO; break;
- default:
- val = 0;
- }
-
- ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
- if (ret < 0)
- goto tw9910_set_fmt_error;
-
- /*
- * set scale
- */
- ret = tw9910_set_scale(client, priv->scale);
- if (ret < 0)
- goto tw9910_set_fmt_error;
-
- /*
- * set hsync
- */
- ret = tw9910_set_hsync(client);
- if (ret < 0)
- goto tw9910_set_fmt_error;
-
- *width = priv->scale->width;
- *height = priv->scale->height;
-
- return ret;
-
-tw9910_set_fmt_error:
-
- tw9910_reset(client);
- priv->scale = NULL;
-
- return ret;
-}
-
-static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- a->c.left = 0;
- a->c.top = 0;
- if (priv->norm & V4L2_STD_NTSC) {
- a->c.width = 640;
- a->c.height = 480;
- } else {
- a->c.width = 768;
- a->c.height = 576;
- }
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
-static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- a->bounds.left = 0;
- a->bounds.top = 0;
- if (priv->norm & V4L2_STD_NTSC) {
- a->bounds.width = 640;
- a->bounds.height = 480;
- } else {
- a->bounds.width = 768;
- a->bounds.height = 576;
- }
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int tw9910_g_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
-
- if (!priv->scale) {
- priv->scale = tw9910_select_norm(priv->norm, 640, 480);
- if (!priv->scale)
- return -EINVAL;
- }
-
- mf->width = priv->scale->width;
- mf->height = priv->scale->height;
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- mf->field = V4L2_FIELD_INTERLACED_BT;
-
- return 0;
-}
-
-static int tw9910_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- u32 width = mf->width, height = mf->height;
- int ret;
-
- WARN_ON(mf->field != V4L2_FIELD_ANY &&
- mf->field != V4L2_FIELD_INTERLACED_BT);
-
- /*
- * check color format
- */
- if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
- return -EINVAL;
-
- mf->colorspace = V4L2_COLORSPACE_JPEG;
-
- ret = tw9910_set_frame(sd, &width, &height);
- if (!ret) {
- mf->width = width;
- mf->height = height;
- }
- return ret;
-}
-
-static int tw9910_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tw9910_priv *priv = to_tw9910(client);
- const struct tw9910_scale_ctrl *scale;
-
- if (V4L2_FIELD_ANY == mf->field) {
- mf->field = V4L2_FIELD_INTERLACED_BT;
- } else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
- dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
- return -EINVAL;
- }
-
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
-
- /*
- * select suitable norm
- */
- scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
- if (!scale)
- return -EINVAL;
-
- mf->width = scale->width;
- mf->height = scale->height;
-
- return 0;
-}
-
-static int tw9910_video_probe(struct i2c_client *client)
-{
- struct tw9910_priv *priv = to_tw9910(client);
- s32 id;
-
- /*
- * tw9910 only use 8 or 16 bit bus width
- */
- if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
- SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&client->dev, "bus width error\n");
- return -ENODEV;
- }
-
- /*
- * check and show Product ID
- * So far only revisions 0 and 1 have been seen
- */
- id = i2c_smbus_read_byte_data(client, ID);
- priv->revision = GET_REV(id);
- id = GET_ID(id);
-
- if (0x0B != id ||
- 0x01 < priv->revision) {
- dev_err(&client->dev,
- "Product ID error %x:%x\n",
- id, priv->revision);
- return -ENODEV;
- }
-
- dev_info(&client->dev,
- "tw9910 Product ID %0x:%0x\n", id, priv->revision);
-
- priv->norm = V4L2_STD_NTSC;
-
- return 0;
-}
-
-static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
- .g_chip_ident = tw9910_g_chip_ident,
- .s_std = tw9910_s_std,
- .g_std = tw9910_g_std,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .g_register = tw9910_g_register,
- .s_register = tw9910_s_register,
-#endif
-};
-
-static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
-{
- if (index)
- return -EINVAL;
-
- *code = V4L2_MBUS_FMT_UYVY8_2X8;
- return 0;
-}
-
-static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
-
- cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
-
- return 0;
-}
-
-static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- u8 val = VSSL_VVALID | HSSL_DVALID;
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
-
- /*
- * set OUTCTR1
- *
- * We use VVALID and DVALID signals to control VSYNC and HSYNC
- * outputs, in this mode their polarity is inverted.
- */
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- val |= HSP_HI;
-
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- val |= VSP_HI;
-
- return i2c_smbus_write_byte_data(client, OUTCTR1, val);
-}
-
-static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
- .s_stream = tw9910_s_stream,
- .g_mbus_fmt = tw9910_g_fmt,
- .s_mbus_fmt = tw9910_s_fmt,
- .try_mbus_fmt = tw9910_try_fmt,
- .cropcap = tw9910_cropcap,
- .g_crop = tw9910_g_crop,
- .enum_mbus_fmt = tw9910_enum_fmt,
- .g_mbus_config = tw9910_g_mbus_config,
- .s_mbus_config = tw9910_s_mbus_config,
-};
-
-static struct v4l2_subdev_ops tw9910_subdev_ops = {
- .core = &tw9910_subdev_core_ops,
- .video = &tw9910_subdev_video_ops,
-};
-
-/*
- * i2c_driver function
- */
-
-static int tw9910_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-
-{
- struct tw9910_priv *priv;
- struct tw9910_video_info *info;
- struct i2c_adapter *adapter =
- to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
-
- if (!icl || !icl->priv) {
- dev_err(&client->dev, "TW9910: missing platform data!\n");
- return -EINVAL;
- }
-
- info = icl->priv;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev,
- "I2C-Adapter doesn't support "
- "I2C_FUNC_SMBUS_BYTE_DATA\n");
- return -EIO;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->info = info;
-
- v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
-
- ret = tw9910_video_probe(client);
- if (ret)
- kfree(priv);
-
- return ret;
-}
-
-static int tw9910_remove(struct i2c_client *client)
-{
- struct tw9910_priv *priv = to_tw9910(client);
-
- kfree(priv);
- return 0;
-}
-
-static const struct i2c_device_id tw9910_id[] = {
- { "tw9910", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tw9910_id);
-
-static struct i2c_driver tw9910_i2c_driver = {
- .driver = {
- .name = "tw9910",
- },
- .probe = tw9910_probe,
- .remove = tw9910_remove,
- .id_table = tw9910_id,
-};
-
-module_i2c_driver(tw9910_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for tw9910");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
deleted file mode 100644
index fc24ef05b3f3..000000000000
--- a/drivers/media/video/usbvision/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config VIDEO_USBVISION
- tristate "USB video devices based on Nogatech NT1003/1004/1005"
- depends on I2C && VIDEO_V4L2
- select VIDEO_TUNER
- select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
- ---help---
- There are more than 50 different USB video devices based on
- NT1003/1004/1005 USB Bridges. This driver enables using those
- devices.
-
- To compile this driver as a module, choose M here: the
- module will be called usbvision.
diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile
deleted file mode 100644
index aea1e3b5f06b..000000000000
--- a/drivers/media/video/usbvision/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o
-
-obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
-
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
deleted file mode 100644
index 9bd8f084f348..000000000000
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ /dev/null
@@ -1,1690 +0,0 @@
-/*
- * USB USBVISION Video device driver 0.9.10
- *
- *
- *
- * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
- *
- * This module is part of usbvision driver project.
- *
- * 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.
- *
- * Let's call the version 0.... until compression decoding is completely
- * implemented.
- *
- * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach.
- * It was based on USB CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt
- * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler &
- * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink
- * Updates to driver completed by Dwaine P. Garden
- *
- *
- * TODO:
- * - use submit_urb for all setup packets
- * - Fix memory settings for nt1004. It is 4 times as big as the
- * nt1003 memory.
- * - Add audio on endpoint 3 for nt1004 chip.
- * Seems impossible, needs a codec interface. Which one?
- * - Clean up the driver.
- * - optimization for performance.
- * - Add Videotext capability (VBI). Working on it.....
- * - Check audio for other devices
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-
-#include <media/saa7115.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/tuner.h>
-
-#include <linux/workqueue.h>
-
-#include "usbvision.h"
-#include "usbvision-cards.h"
-
-#define DRIVER_AUTHOR \
- "Joerg Heckenbach <joerg@heckenbach-aw.de>, " \
- "Dwaine Garden <DwaineGarden@rogers.com>"
-#define DRIVER_NAME "usbvision"
-#define DRIVER_ALIAS "USBVision"
-#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
-#define DRIVER_LICENSE "GPL"
-#define USBVISION_VERSION_STRING "0.9.11"
-
-#define ENABLE_HEXDUMP 0 /* Enable if you need it */
-
-
-#ifdef USBVISION_DEBUG
- #define PDEBUG(level, fmt, args...) { \
- if (video_debug & (level)) \
- printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
- __func__, __LINE__ , ## args); \
- }
-#else
- #define PDEBUG(level, fmt, args...) do {} while (0)
-#endif
-
-#define DBG_IO (1 << 1)
-#define DBG_PROBE (1 << 2)
-#define DBG_MMAP (1 << 3)
-
-/* String operations */
-#define rmspace(str) while (*str == ' ') str++;
-#define goto2next(str) while (*str != ' ') str++; while (*str == ' ') str++;
-
-
-/* sequential number of usbvision device */
-static int usbvision_nr;
-
-static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
- { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
- { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" },
- { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" },
- { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" },
- { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" },
- { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" },
- { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */
- { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
-};
-
-/* Function prototypes */
-static void usbvision_release(struct usb_usbvision *usbvision);
-
-/* Default initialization of device driver parameters */
-/* Set the default format for ISOC endpoint */
-static int isoc_mode = ISOC_MODE_COMPRESS;
-/* Set the default Debug Mode of the device driver */
-static int video_debug;
-/* Set the default device to power on at startup */
-static int power_on_at_open = 1;
-/* Sequential Number of Video Device */
-static int video_nr = -1;
-/* Sequential Number of Radio Device */
-static int radio_nr = -1;
-
-/* Grab parameters for the device driver */
-
-/* Showing parameters under SYSFS */
-module_param(isoc_mode, int, 0444);
-module_param(video_debug, int, 0444);
-module_param(power_on_at_open, int, 0444);
-module_param(video_nr, int, 0444);
-module_param(radio_nr, int, 0444);
-
-MODULE_PARM_DESC(isoc_mode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
-MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
-MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)");
-MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");
-MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
-
-
-/* Misc stuff */
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-MODULE_VERSION(USBVISION_VERSION_STRING);
-MODULE_ALIAS(DRIVER_ALIAS);
-
-
-/*****************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module. */
-/* Device information is located at /sys/class/video4linux/video0 */
-/* Device parameters information is located at /sys/module/usbvision */
-/* Device USB Information is located at */
-/* /sys/bus/usb/drivers/USBVision Video Grabber */
-/*****************************************************************************/
-
-#define YES_NO(x) ((x) ? "Yes" : "No")
-
-static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- return video_get_drvdata(vdev);
-}
-
-static ssize_t show_version(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
-}
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-
-static ssize_t show_model(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n",
- usbvision_device_data[usbvision->dev_model].model_string);
-}
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_hue(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- struct v4l2_control ctrl;
- ctrl.id = V4L2_CID_HUE;
- ctrl.value = 0;
- if (usbvision->user)
- call_all(usbvision, core, g_ctrl, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value);
-}
-static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_contrast(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- struct v4l2_control ctrl;
- ctrl.id = V4L2_CID_CONTRAST;
- ctrl.value = 0;
- if (usbvision->user)
- call_all(usbvision, core, g_ctrl, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value);
-}
-static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_brightness(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- struct v4l2_control ctrl;
- ctrl.id = V4L2_CID_BRIGHTNESS;
- ctrl.value = 0;
- if (usbvision->user)
- call_all(usbvision, core, g_ctrl, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value);
-}
-static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- struct v4l2_control ctrl;
- ctrl.id = V4L2_CID_SATURATION;
- ctrl.value = 0;
- if (usbvision->user)
- call_all(usbvision, core, g_ctrl, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value);
-}
-static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_streaming(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n",
- YES_NO(usbvision->streaming == stream_on ? 1 : 0));
-}
-static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
-
-static ssize_t show_compression(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n",
- YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS));
-}
-static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
-
-static ssize_t show_device_bridge(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev =
- container_of(cd, struct video_device, dev);
- struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%d\n", usbvision->bridge_type);
-}
-static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
-
-static void usbvision_create_sysfs(struct video_device *vdev)
-{
- int res;
-
- if (!vdev)
- return;
- do {
- res = device_create_file(&vdev->dev, &dev_attr_version);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_model);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_hue);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_contrast);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_brightness);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_saturation);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_streaming);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_compression);
- if (res < 0)
- break;
- res = device_create_file(&vdev->dev, &dev_attr_bridge);
- if (res >= 0)
- return;
- } while (0);
-
- dev_err(&vdev->dev, "%s error: %d\n", __func__, res);
-}
-
-static void usbvision_remove_sysfs(struct video_device *vdev)
-{
- if (vdev) {
- device_remove_file(&vdev->dev, &dev_attr_version);
- device_remove_file(&vdev->dev, &dev_attr_model);
- device_remove_file(&vdev->dev, &dev_attr_hue);
- device_remove_file(&vdev->dev, &dev_attr_contrast);
- device_remove_file(&vdev->dev, &dev_attr_brightness);
- device_remove_file(&vdev->dev, &dev_attr_saturation);
- device_remove_file(&vdev->dev, &dev_attr_streaming);
- device_remove_file(&vdev->dev, &dev_attr_compression);
- device_remove_file(&vdev->dev, &dev_attr_bridge);
- }
-}
-
-/*
- * usbvision_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'usbvision->user'). The procedure
- * then allocates buffers needed for video processing.
- *
- */
-static int usbvision_v4l2_open(struct file *file)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int err_code = 0;
-
- PDEBUG(DBG_IO, "open");
-
- usbvision_reset_power_off_timer(usbvision);
-
- if (usbvision->user)
- err_code = -EBUSY;
- else {
- /* Allocate memory for the scratch ring buffer */
- err_code = usbvision_scratch_alloc(usbvision);
- if (isoc_mode == ISOC_MODE_COMPRESS) {
- /* Allocate intermediate decompression buffers
- only if needed */
- err_code = usbvision_decompress_alloc(usbvision);
- }
- if (err_code) {
- /* Deallocate all buffers if trouble */
- usbvision_scratch_free(usbvision);
- usbvision_decompress_free(usbvision);
- }
- }
-
- /* If so far no errors then we shall start the camera */
- if (!err_code) {
- if (usbvision->power == 0) {
- usbvision_power_on(usbvision);
- usbvision_i2c_register(usbvision);
- }
-
- /* Send init sequence only once, it's large! */
- if (!usbvision->initialized) {
- int setup_ok = 0;
- setup_ok = usbvision_setup(usbvision, isoc_mode);
- if (setup_ok)
- usbvision->initialized = 1;
- else
- err_code = -EBUSY;
- }
-
- if (!err_code) {
- usbvision_begin_streaming(usbvision);
- err_code = usbvision_init_isoc(usbvision);
- /* device must be initialized before isoc transfer */
- usbvision_muxsel(usbvision, 0);
- usbvision->user++;
- } else {
- if (power_on_at_open) {
- usbvision_i2c_unregister(usbvision);
- usbvision_power_off(usbvision);
- usbvision->initialized = 0;
- }
- }
- }
-
- /* prepare queues */
- usbvision_empty_framequeues(usbvision);
-
- PDEBUG(DBG_IO, "success");
- return err_code;
-}
-
-/*
- * usbvision_v4l2_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in usbvision_v4l2_open().
- *
- */
-static int usbvision_v4l2_close(struct file *file)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- PDEBUG(DBG_IO, "close");
-
- usbvision_audio_off(usbvision);
- usbvision_restart_isoc(usbvision);
- usbvision_stop_isoc(usbvision);
-
- usbvision_decompress_free(usbvision);
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- usbvision_scratch_free(usbvision);
-
- usbvision->user--;
-
- if (power_on_at_open) {
- /* power off in a little while
- to avoid off/on every close/open short sequences */
- usbvision_set_power_off_timer(usbvision);
- usbvision->initialized = 0;
- }
-
- if (usbvision->remove_pending) {
- printk(KERN_INFO "%s: Final disconnect\n", __func__);
- usbvision_release(usbvision);
- }
-
- PDEBUG(DBG_IO, "success");
- return 0;
-}
-
-
-/*
- * usbvision_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
- */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int err_code;
-
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- /* NT100x has a 8-bit register space */
- err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
- if (err_code < 0) {
- dev_err(&usbvision->vdev->dev,
- "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
- __func__, err_code);
- return err_code;
- }
- reg->val = err_code;
- reg->size = 1;
- return 0;
-}
-
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int err_code;
-
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
- /* NT100x has a 8-bit register space */
- err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
- if (err_code < 0) {
- dev_err(&usbvision->vdev->dev,
- "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
- __func__, err_code);
- return err_code;
- }
- return 0;
-}
-#endif
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *vc)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card,
- usbvision_device_data[usbvision->dev_model].model_string,
- sizeof(vc->card));
- usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *vi)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int chan;
-
- if (vi->index >= usbvision->video_inputs)
- return -EINVAL;
- if (usbvision->have_tuner)
- chan = vi->index;
- else
- chan = vi->index + 1; /* skip Television string*/
-
- /* Determine the requested input characteristics
- specific for each usbvision card model */
- switch (chan) {
- case 0:
- if (usbvision_device_data[usbvision->dev_model].video_channels == 4) {
- strcpy(vi->name, "White Video Input");
- } else {
- strcpy(vi->name, "Television");
- vi->type = V4L2_INPUT_TYPE_TUNER;
- vi->audioset = 1;
- vi->tuner = chan;
- vi->std = USBVISION_NORMS;
- }
- break;
- case 1:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
- strcpy(vi->name, "Green Video Input");
- else
- strcpy(vi->name, "Composite Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- case 2:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
- strcpy(vi->name, "Yellow Video Input");
- else
- strcpy(vi->name, "S-Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- case 3:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(vi->name, "Red Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- }
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- *input = usbvision->ctl_input;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- if (input >= usbvision->video_inputs)
- return -EINVAL;
-
- usbvision_muxsel(usbvision, input);
- usbvision_set_input(usbvision);
- usbvision_set_output(usbvision,
- usbvision->curwidth,
- usbvision->curheight);
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- usbvision->tvnorm_id = *id;
-
- call_all(usbvision, core, s_std, usbvision->tvnorm_id);
- /* propagate the change to the decoder */
- usbvision_muxsel(usbvision, usbvision->ctl_input);
-
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *vt)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */
- return -EINVAL;
- if (usbvision->radio) {
- strcpy(vt->name, "Radio");
- vt->type = V4L2_TUNER_RADIO;
- } else {
- strcpy(vt->name, "Television");
- }
- /* Let clients fill in the remainder of this struct */
- call_all(usbvision, tuner, g_tuner, vt);
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *vt)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- /* Only no or one tuner for now */
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_all(usbvision, tuner, s_tuner, vt);
-
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- freq->tuner = 0; /* Only one tuner */
- if (usbvision->radio)
- freq->type = V4L2_TUNER_RADIO;
- else
- freq->type = V4L2_TUNER_ANALOG_TV;
- freq->frequency = usbvision->freq;
-
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- /* Only no or one tuner for now */
- if (!usbvision->have_tuner || freq->tuner)
- return -EINVAL;
-
- usbvision->freq = freq->frequency;
- call_all(usbvision, tuner, s_frequency, freq);
-
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- if (usbvision->radio)
- strcpy(a->name, "Radio");
- else
- strcpy(a->name, "TV");
-
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- if (a->index)
- return -EINVAL;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *ctrl)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- call_all(usbvision, core, queryctrl, ctrl);
-
- if (!ctrl->type)
- return -EINVAL;
-
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- call_all(usbvision, core, g_ctrl, ctrl);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- call_all(usbvision, core, s_ctrl, ctrl);
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file,
- void *priv, struct v4l2_requestbuffers *vr)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int ret;
-
- RESTRICT_TO_RANGE(vr->count, 1, USBVISION_NUMFRAMES);
-
- /* Check input validity:
- the user must do a VIDEO CAPTURE and MMAP method. */
- if (vr->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (usbvision->streaming == stream_on) {
- ret = usbvision_stream_interrupt(usbvision);
- if (ret)
- return ret;
- }
-
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision, vr->count);
-
- usbvision->cur_frame = NULL;
-
- return 0;
-}
-
-static int vidioc_querybuf(struct file *file,
- void *priv, struct v4l2_buffer *vb)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- struct usbvision_frame *frame;
-
- /* FIXME : must control
- that buffers are mapped (VIDIOC_REQBUFS has been called) */
- if (vb->index >= usbvision->num_frames)
- return -EINVAL;
- /* Updating the corresponding frame state */
- vb->flags = 0;
- frame = &usbvision->frame[vb->index];
- if (frame->grabstate >= frame_state_ready)
- vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if (frame->grabstate >= frame_state_done)
- vb->flags |= V4L2_BUF_FLAG_DONE;
- if (frame->grabstate == frame_state_unused)
- vb->flags |= V4L2_BUF_FLAG_MAPPED;
- vb->memory = V4L2_MEMORY_MMAP;
-
- vb->m.offset = vb->index * PAGE_ALIGN(usbvision->max_frame_size);
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth *
- usbvision->curheight *
- usbvision->palette.bytes_per_pixel;
- vb->timestamp = usbvision->frame[vb->index].timestamp;
- vb->sequence = usbvision->frame[vb->index].sequence;
- return 0;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- struct usbvision_frame *frame;
- unsigned long lock_flags;
-
- /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
- if (vb->index >= usbvision->num_frames)
- return -EINVAL;
-
- frame = &usbvision->frame[vb->index];
-
- if (frame->grabstate != frame_state_unused)
- return -EAGAIN;
-
- /* Mark it as ready and enqueue frame */
- frame->grabstate = frame_state_ready;
- frame->scanstate = scan_state_scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
-
- vb->flags &= ~V4L2_BUF_FLAG_DONE;
-
- /* set v4l2_format index */
- frame->v4l2_format = usbvision->palette;
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int ret;
- struct usbvision_frame *f;
- unsigned long lock_flags;
-
- if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == stream_idle)
- return -EINVAL;
- ret = wait_event_interruptible
- (usbvision->wait_frame,
- !list_empty(&(usbvision->outqueue)));
- if (ret)
- return ret;
- }
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- f = list_entry(usbvision->outqueue.next,
- struct usbvision_frame, frame);
- list_del(usbvision->outqueue.next);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- f->grabstate = frame_state_unused;
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->flags = V4L2_BUF_FLAG_MAPPED |
- V4L2_BUF_FLAG_QUEUED |
- V4L2_BUF_FLAG_DONE;
- vb->index = f->index;
- vb->sequence = f->sequence;
- vb->timestamp = f->timestamp;
- vb->field = V4L2_FIELD_NONE;
- vb->bytesused = f->scanlength;
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- usbvision->streaming = stream_on;
- call_all(usbvision, video, s_stream, 1);
-
- return 0;
-}
-
-static int vidioc_streamoff(struct file *file,
- void *priv, enum v4l2_buf_type type)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (usbvision->streaming == stream_on) {
- usbvision_stream_interrupt(usbvision);
- /* Stop all video streamings */
- call_all(usbvision, video, s_stream, 0);
- }
- usbvision_empty_framequeues(usbvision);
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *vfd)
-{
- if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1)
- return -EINVAL;
- strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc);
- vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *vf)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- vf->fmt.pix.width = usbvision->curwidth;
- vf->fmt.pix.height = usbvision->curheight;
- vf->fmt.pix.pixelformat = usbvision->palette.format;
- vf->fmt.pix.bytesperline =
- usbvision->curwidth * usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline * usbvision->curheight;
- vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
-
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *vf)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int format_idx;
-
- /* Find requested format in available ones */
- for (format_idx = 0; format_idx < USBVISION_SUPPORTED_PALETTES; format_idx++) {
- if (vf->fmt.pix.pixelformat ==
- usbvision_v4l2_format[format_idx].format) {
- usbvision->palette = usbvision_v4l2_format[format_idx];
- break;
- }
- }
- /* robustness */
- if (format_idx == USBVISION_SUPPORTED_PALETTES)
- return -EINVAL;
- RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
- RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
- vf->fmt.pix.bytesperline = vf->fmt.pix.width*
- usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *vf)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int ret;
-
- ret = vidioc_try_fmt_vid_cap(file, priv, vf);
- if (ret)
- return ret;
-
- /* stop io in case it is already in progress */
- if (usbvision->streaming == stream_on) {
- ret = usbvision_stream_interrupt(usbvision);
- if (ret)
- return ret;
- }
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
-
- usbvision->cur_frame = NULL;
-
- /* by now we are committed to the new data... */
- usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-
- return 0;
-}
-
-static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int noblock = file->f_flags & O_NONBLOCK;
- unsigned long lock_flags;
- int ret, i;
- struct usbvision_frame *frame;
-
- PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
- (unsigned long)count, noblock);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
- return -EFAULT;
-
- /* This entry point is compatible with the mmap routines
- so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
- to get frames or call read on the device. */
- if (!usbvision->num_frames) {
- /* First, allocate some frames to work with
- if this has not been done with VIDIOC_REQBUF */
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- usbvision_frames_alloc(usbvision, USBVISION_NUMFRAMES);
- }
-
- if (usbvision->streaming != stream_on) {
- /* no stream is running, make it running ! */
- usbvision->streaming = stream_on;
- call_all(usbvision, video, s_stream, 1);
- }
-
- /* Then, enqueue as many frames as possible
- (like a user of VIDIOC_QBUF would do) */
- for (i = 0; i < usbvision->num_frames; i++) {
- frame = &usbvision->frame[i];
- if (frame->grabstate == frame_state_unused) {
- /* Mark it as ready and enqueue frame */
- frame->grabstate = frame_state_ready;
- frame->scanstate = scan_state_scanning;
- /* Accumulated in usbvision_parse_data() */
- frame->scanlength = 0;
-
- /* set v4l2_format index */
- frame->v4l2_format = usbvision->palette;
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- list_add_tail(&frame->frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock,
- lock_flags);
- }
- }
-
- /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
- if (list_empty(&(usbvision->outqueue))) {
- if (noblock)
- return -EAGAIN;
-
- ret = wait_event_interruptible
- (usbvision->wait_frame,
- !list_empty(&(usbvision->outqueue)));
- if (ret)
- return ret;
- }
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- frame = list_entry(usbvision->outqueue.next,
- struct usbvision_frame, frame);
- list_del(usbvision->outqueue.next);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- /* An error returns an empty frame */
- if (frame->grabstate == frame_state_error) {
- frame->bytes_read = 0;
- return 0;
- }
-
- PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
- __func__,
- frame->index, frame->bytes_read, frame->scanlength);
-
- /* copy bytes to user space; we allow for partials reads */
- if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
- count = frame->scanlength - frame->bytes_read;
-
- if (copy_to_user(buf, frame->data + frame->bytes_read, count))
- return -EFAULT;
-
- frame->bytes_read += count;
- PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
- __func__,
- (unsigned long)count, frame->bytes_read);
-
- /* For now, forget the frame if it has not been read in one shot. */
-/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */
- frame->bytes_read = 0;
-
- /* Mark it as available to be used again. */
- frame->grabstate = frame_state_unused;
-/* } */
-
- return count;
-}
-
-static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
- unsigned long size = vma->vm_end - vma->vm_start,
- start = vma->vm_start;
- void *pos;
- u32 i;
- struct usb_usbvision *usbvision = video_drvdata(file);
-
- PDEBUG(DBG_MMAP, "mmap");
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EFAULT;
-
- if (!(vma->vm_flags & VM_WRITE) ||
- size != PAGE_ALIGN(usbvision->max_frame_size)) {
- return -EINVAL;
- }
-
- for (i = 0; i < usbvision->num_frames; i++) {
- if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
- vma->vm_pgoff)
- break;
- }
- if (i == usbvision->num_frames) {
- PDEBUG(DBG_MMAP,
- "mmap: user supplied mapping address is out of range");
- return -EINVAL;
- }
-
- /* VM_IO is eventually going to replace PageReserved altogether */
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
-
- pos = usbvision->frame[i].data;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return 0;
-}
-
-
-/*
- * Here comes the stuff for radio on usbvision based devices
- *
- */
-static int usbvision_radio_open(struct file *file)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int err_code = 0;
-
- PDEBUG(DBG_IO, "%s:", __func__);
-
- if (usbvision->user) {
- dev_err(&usbvision->rdev->dev,
- "%s: Someone tried to open an already opened USBVision Radio!\n",
- __func__);
- err_code = -EBUSY;
- } else {
- if (power_on_at_open) {
- usbvision_reset_power_off_timer(usbvision);
- if (usbvision->power == 0) {
- usbvision_power_on(usbvision);
- usbvision_i2c_register(usbvision);
- }
- }
-
- /* Alternate interface 1 is is the biggest frame size */
- err_code = usbvision_set_alternate(usbvision);
- if (err_code < 0) {
- usbvision->last_error = err_code;
- err_code = -EBUSY;
- goto out;
- }
-
- /* If so far no errors then we shall start the radio */
- usbvision->radio = 1;
- call_all(usbvision, tuner, s_radio);
- usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
- usbvision->user++;
- }
-
- if (err_code) {
- if (power_on_at_open) {
- usbvision_i2c_unregister(usbvision);
- usbvision_power_off(usbvision);
- usbvision->initialized = 0;
- }
- }
-out:
- return err_code;
-}
-
-
-static int usbvision_radio_close(struct file *file)
-{
- struct usb_usbvision *usbvision = video_drvdata(file);
- int err_code = 0;
-
- PDEBUG(DBG_IO, "");
-
- /* Set packet size to 0 */
- usbvision->iface_alt = 0;
- err_code = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->iface_alt);
-
- usbvision_audio_off(usbvision);
- usbvision->radio = 0;
- usbvision->user--;
-
- if (power_on_at_open) {
- usbvision_set_power_off_timer(usbvision);
- usbvision->initialized = 0;
- }
-
- if (usbvision->remove_pending) {
- printk(KERN_INFO "%s: Final disconnect\n", __func__);
- usbvision_release(usbvision);
- }
-
- PDEBUG(DBG_IO, "success");
- return err_code;
-}
-
-/* Video registration stuff */
-
-/* Video template */
-static const struct v4l2_file_operations usbvision_fops = {
- .owner = THIS_MODULE,
- .open = usbvision_v4l2_open,
- .release = usbvision_v4l2_close,
- .read = usbvision_v4l2_read,
- .mmap = usbvision_v4l2_mmap,
- .unlocked_ioctl = video_ioctl2,
-/* .poll = video_poll, */
-};
-
-static const struct v4l2_ioctl_ops usbvision_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_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
-#endif
-};
-
-static struct video_device usbvision_video_template = {
- .fops = &usbvision_fops,
- .ioctl_ops = &usbvision_ioctl_ops,
- .name = "usbvision-video",
- .release = video_device_release,
- .tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
-};
-
-
-/* Radio template */
-static const struct v4l2_file_operations usbvision_radio_fops = {
- .owner = THIS_MODULE,
- .open = usbvision_radio_open,
- .release = usbvision_radio_close,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-};
-
-static struct video_device usbvision_radio_template = {
- .fops = &usbvision_radio_fops,
- .name = "usbvision-radio",
- .release = video_device_release,
- .ioctl_ops = &usbvision_radio_ioctl_ops,
-
- .tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
-};
-
-
-static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
- struct video_device *vdev_template,
- char *name)
-{
- struct usb_device *usb_dev = usbvision->dev;
- struct video_device *vdev;
-
- if (usb_dev == NULL) {
- dev_err(&usbvision->dev->dev,
- "%s: usbvision->dev is not set\n", __func__);
- return NULL;
- }
-
- vdev = video_device_alloc();
- if (NULL == vdev)
- return NULL;
- *vdev = *vdev_template;
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
- vdev->lock = &usbvision->v4l2_lock;
- vdev->v4l2_dev = &usbvision->v4l2_dev;
- snprintf(vdev->name, sizeof(vdev->name), "%s", name);
- video_set_drvdata(vdev, usbvision);
- return vdev;
-}
-
-/* unregister video4linux devices */
-static void usbvision_unregister_video(struct usb_usbvision *usbvision)
-{
- /* Radio Device: */
- if (usbvision->rdev) {
- PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
- video_device_node_name(usbvision->rdev));
- if (video_is_registered(usbvision->rdev))
- video_unregister_device(usbvision->rdev);
- else
- video_device_release(usbvision->rdev);
- usbvision->rdev = NULL;
- }
-
- /* Video Device: */
- if (usbvision->vdev) {
- PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
- video_device_node_name(usbvision->vdev));
- if (video_is_registered(usbvision->vdev))
- video_unregister_device(usbvision->vdev);
- else
- video_device_release(usbvision->vdev);
- usbvision->vdev = NULL;
- }
-}
-
-/* register video4linux devices */
-static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
-{
- /* Video Device: */
- usbvision->vdev = usbvision_vdev_init(usbvision,
- &usbvision_video_template,
- "USBVision Video");
- if (usbvision->vdev == NULL)
- goto err_exit;
- if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
- goto err_exit;
- printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
- usbvision->nr, video_device_node_name(usbvision->vdev));
-
- /* Radio Device: */
- if (usbvision_device_data[usbvision->dev_model].radio) {
- /* usbvision has radio */
- usbvision->rdev = usbvision_vdev_init(usbvision,
- &usbvision_radio_template,
- "USBVision Radio");
- if (usbvision->rdev == NULL)
- goto err_exit;
- if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
- goto err_exit;
- printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
- usbvision->nr, video_device_node_name(usbvision->rdev));
- }
- /* all done */
- return 0;
-
- err_exit:
- dev_err(&usbvision->dev->dev,
- "USBVision[%d]: video_register_device() failed\n",
- usbvision->nr);
- usbvision_unregister_video(usbvision);
- return -1;
-}
-
-/*
- * usbvision_alloc()
- *
- * This code allocates the struct usb_usbvision.
- * It is filled with default values.
- *
- * Returns NULL on error, a pointer to usb_usbvision else.
- *
- */
-static struct usb_usbvision *usbvision_alloc(struct usb_device *dev,
- struct usb_interface *intf)
-{
- struct usb_usbvision *usbvision;
-
- usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
- if (usbvision == NULL)
- return NULL;
-
- usbvision->dev = dev;
- if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev))
- goto err_free;
-
- mutex_init(&usbvision->v4l2_lock);
-
- /* prepare control urb for control messages during interrupts */
- usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
- if (usbvision->ctrl_urb == NULL)
- goto err_unreg;
- init_waitqueue_head(&usbvision->ctrl_urb_wq);
-
- usbvision_init_power_off_timer(usbvision);
-
- return usbvision;
-
-err_unreg:
- v4l2_device_unregister(&usbvision->v4l2_dev);
-err_free:
- kfree(usbvision);
- return NULL;
-}
-
-/*
- * usbvision_release()
- *
- * This code does final release of struct usb_usbvision. This happens
- * after the device is disconnected -and- all clients closed their files.
- *
- */
-static void usbvision_release(struct usb_usbvision *usbvision)
-{
- PDEBUG(DBG_PROBE, "");
-
- usbvision_reset_power_off_timer(usbvision);
-
- usbvision->initialized = 0;
-
- usbvision_remove_sysfs(usbvision->vdev);
- usbvision_unregister_video(usbvision);
-
- usb_free_urb(usbvision->ctrl_urb);
-
- v4l2_device_unregister(&usbvision->v4l2_dev);
- kfree(usbvision);
-
- PDEBUG(DBG_PROBE, "success");
-}
-
-
-/*********************** usb interface **********************************/
-
-static void usbvision_configure_video(struct usb_usbvision *usbvision)
-{
- int model;
-
- if (usbvision == NULL)
- return;
-
- model = usbvision->dev_model;
- usbvision->palette = usbvision_v4l2_format[2]; /* V4L2_PIX_FMT_RGB24; */
-
- if (usbvision_device_data[usbvision->dev_model].vin_reg2_override) {
- usbvision->vin_reg2_preset =
- usbvision_device_data[usbvision->dev_model].vin_reg2;
- } else {
- usbvision->vin_reg2_preset = 0;
- }
-
- usbvision->tvnorm_id = usbvision_device_data[model].video_norm;
-
- usbvision->video_inputs = usbvision_device_data[model].video_channels;
- usbvision->ctl_input = 0;
-
- /* This should be here to make i2c clients to be able to register */
- /* first switch off audio */
- if (usbvision_device_data[model].audio_channels > 0)
- usbvision_audio_off(usbvision);
- if (!power_on_at_open) {
- /* and then power up the noisy tuner */
- usbvision_power_on(usbvision);
- usbvision_i2c_register(usbvision);
- }
-}
-
-/*
- * usbvision_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like USBVISION video device
- *
- */
-static int __devinit usbvision_probe(struct usb_interface *intf,
- const struct usb_device_id *devid)
-{
- struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
- struct usb_interface *uif;
- __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
- const struct usb_host_interface *interface;
- struct usb_usbvision *usbvision = NULL;
- const struct usb_endpoint_descriptor *endpoint;
- int model, i;
-
- PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
- dev->descriptor.idVendor,
- dev->descriptor.idProduct, ifnum);
-
- model = devid->driver_info;
- if (model < 0 || model >= usbvision_device_data_size) {
- PDEBUG(DBG_PROBE, "model out of bounds %d", model);
- return -ENODEV;
- }
- printk(KERN_INFO "%s: %s found\n", __func__,
- usbvision_device_data[model].model_string);
-
- if (usbvision_device_data[model].interface >= 0)
- interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
- else
- interface = &dev->actconfig->interface[ifnum]->altsetting[0];
- endpoint = &interface->endpoint[1].desc;
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
- __func__, ifnum);
- dev_err(&intf->dev, "%s: Endpoint attributes %d",
- __func__, endpoint->bmAttributes);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n",
- __func__, ifnum);
- return -ENODEV;
- }
-
- usbvision = usbvision_alloc(dev, intf);
- if (usbvision == NULL) {
- dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__);
- return -ENOMEM;
- }
-
- if (dev->descriptor.bNumConfigurations > 1)
- usbvision->bridge_type = BRIDGE_NT1004;
- else if (model == DAZZLE_DVC_90_REV_1_SECAM)
- usbvision->bridge_type = BRIDGE_NT1005;
- else
- usbvision->bridge_type = BRIDGE_NT1003;
- PDEBUG(DBG_PROBE, "bridge_type %d", usbvision->bridge_type);
-
- /* compute alternate max packet sizes */
- uif = dev->actconfig->interface[0];
-
- usbvision->num_alt = uif->num_altsetting;
- PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt);
- usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
- if (usbvision->alt_max_pkt_size == NULL) {
- dev_err(&intf->dev, "usbvision: out of memory!\n");
- return -ENOMEM;
- }
-
- for (i = 0; i < usbvision->num_alt; i++) {
- u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
- wMaxPacketSize);
- usbvision->alt_max_pkt_size[i] =
- (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i", i,
- usbvision->alt_max_pkt_size[i]);
- }
-
-
- usbvision->nr = usbvision_nr++;
-
- usbvision->have_tuner = usbvision_device_data[model].tuner;
- if (usbvision->have_tuner)
- usbvision->tuner_type = usbvision_device_data[model].tuner_type;
-
- usbvision->dev_model = model;
- usbvision->remove_pending = 0;
- usbvision->iface = ifnum;
- usbvision->iface_alt = 0;
- usbvision->video_endp = endpoint->bEndpointAddress;
- usbvision->isoc_packet_size = 0;
- usbvision->usb_bandwidth = 0;
- usbvision->user = 0;
- usbvision->streaming = stream_off;
- usbvision_configure_video(usbvision);
- usbvision_register_video(usbvision);
-
- usbvision_create_sysfs(usbvision->vdev);
-
- PDEBUG(DBG_PROBE, "success");
- return 0;
-}
-
-
-/*
- * usbvision_disconnect()
- *
- * This procedure stops all driver activity, deallocates interface-private
- * structure (pointed by 'ptr') and after that driver should be removable
- * with no ill consequences.
- *
- */
-static void __devexit usbvision_disconnect(struct usb_interface *intf)
-{
- struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
-
- PDEBUG(DBG_PROBE, "");
-
- if (usbvision == NULL) {
- pr_err("%s: usb_get_intfdata() failed\n", __func__);
- return;
- }
-
- mutex_lock(&usbvision->v4l2_lock);
-
- /* At this time we ask to cancel outstanding URBs */
- usbvision_stop_isoc(usbvision);
-
- v4l2_device_disconnect(&usbvision->v4l2_dev);
-
- if (usbvision->power) {
- usbvision_i2c_unregister(usbvision);
- usbvision_power_off(usbvision);
- }
- usbvision->remove_pending = 1; /* Now all ISO data will be ignored */
-
- usb_put_dev(usbvision->dev);
- usbvision->dev = NULL; /* USB device is no more */
-
- mutex_unlock(&usbvision->v4l2_lock);
-
- if (usbvision->user) {
- printk(KERN_INFO "%s: In use, disconnect pending\n",
- __func__);
- wake_up_interruptible(&usbvision->wait_frame);
- wake_up_interruptible(&usbvision->wait_stream);
- } else {
- usbvision_release(usbvision);
- }
-
- PDEBUG(DBG_PROBE, "success");
-}
-
-static struct usb_driver usbvision_driver = {
- .name = "usbvision",
- .id_table = usbvision_table,
- .probe = usbvision_probe,
- .disconnect = __devexit_p(usbvision_disconnect),
-};
-
-/*
- * usbvision_init()
- *
- * This code is run to initialize the driver.
- *
- */
-static int __init usbvision_init(void)
-{
- int err_code;
-
- PDEBUG(DBG_PROBE, "");
-
- PDEBUG(DBG_IO, "IO debugging is enabled [video]");
- PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
- PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
-
- /* disable planar mode support unless compression enabled */
- if (isoc_mode != ISOC_MODE_COMPRESS) {
- /* FIXME : not the right way to set supported flag */
- usbvision_v4l2_format[6].supported = 0; /* V4L2_PIX_FMT_YVU420 */
- usbvision_v4l2_format[7].supported = 0; /* V4L2_PIX_FMT_YUV422P */
- }
-
- err_code = usb_register(&usbvision_driver);
-
- if (err_code == 0) {
- printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
- PDEBUG(DBG_PROBE, "success");
- }
- return err_code;
-}
-
-static void __exit usbvision_exit(void)
-{
- PDEBUG(DBG_PROBE, "");
-
- usb_deregister(&usbvision_driver);
- PDEBUG(DBG_PROBE, "success");
-}
-
-module_init(usbvision_init);
-module_exit(usbvision_exit);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
deleted file mode 100644
index 1d131720b6d7..000000000000
--- a/drivers/media/video/uvc/uvc_driver.c
+++ /dev/null
@@ -1,2448 +0,0 @@
-/*
- * uvc_driver.c -- USB Video Class driver
- *
- * Copyright (C) 2005-2010
- * 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.
- *
- */
-
-/*
- * This driver aims to support video input and ouput devices compliant with the
- * 'USB Video Class' specification.
- *
- * The driver doesn't support the deprecated v4l1 interface. It implements the
- * mmap capture method only, and doesn't do any image format conversion in
- * software. If your user-space application doesn't support YUYV or MJPEG, fix
- * it :-). Please note that the MJPEG data have been stripped from their
- * Huffman tables (DHT marker), you will need to add it back if your JPEG
- * codec can't handle MJPEG data.
- */
-
-#include <linux/atomic.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/version.h>
-#include <asm/unaligned.h>
-
-#include <media/v4l2-common.h>
-
-#include "uvcvideo.h"
-
-#define DRIVER_AUTHOR "Laurent Pinchart " \
- "<laurent.pinchart@ideasonboard.com>"
-#define DRIVER_DESC "USB Video Class driver"
-
-unsigned int uvc_clock_param = CLOCK_MONOTONIC;
-unsigned int uvc_no_drop_param;
-static unsigned int uvc_quirks_param = -1;
-unsigned int uvc_trace_param;
-unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
-
-/* ------------------------------------------------------------------------
- * Video formats
- */
-
-static struct uvc_format_desc uvc_fmts[] = {
- {
- .name = "YUV 4:2:2 (YUYV)",
- .guid = UVC_GUID_FORMAT_YUY2,
- .fcc = V4L2_PIX_FMT_YUYV,
- },
- {
- .name = "YUV 4:2:2 (YUYV)",
- .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
- .fcc = V4L2_PIX_FMT_YUYV,
- },
- {
- .name = "YUV 4:2:0 (NV12)",
- .guid = UVC_GUID_FORMAT_NV12,
- .fcc = V4L2_PIX_FMT_NV12,
- },
- {
- .name = "MJPEG",
- .guid = UVC_GUID_FORMAT_MJPEG,
- .fcc = V4L2_PIX_FMT_MJPEG,
- },
- {
- .name = "YVU 4:2:0 (YV12)",
- .guid = UVC_GUID_FORMAT_YV12,
- .fcc = V4L2_PIX_FMT_YVU420,
- },
- {
- .name = "YUV 4:2:0 (I420)",
- .guid = UVC_GUID_FORMAT_I420,
- .fcc = V4L2_PIX_FMT_YUV420,
- },
- {
- .name = "YUV 4:2:0 (M420)",
- .guid = UVC_GUID_FORMAT_M420,
- .fcc = V4L2_PIX_FMT_M420,
- },
- {
- .name = "YUV 4:2:2 (UYVY)",
- .guid = UVC_GUID_FORMAT_UYVY,
- .fcc = V4L2_PIX_FMT_UYVY,
- },
- {
- .name = "Greyscale (8-bit)",
- .guid = UVC_GUID_FORMAT_Y800,
- .fcc = V4L2_PIX_FMT_GREY,
- },
- {
- .name = "Greyscale (16-bit)",
- .guid = UVC_GUID_FORMAT_Y16,
- .fcc = V4L2_PIX_FMT_Y16,
- },
- {
- .name = "RGB Bayer",
- .guid = UVC_GUID_FORMAT_BY8,
- .fcc = V4L2_PIX_FMT_SBGGR8,
- },
- {
- .name = "RGB565",
- .guid = UVC_GUID_FORMAT_RGBP,
- .fcc = V4L2_PIX_FMT_RGB565,
- },
- {
- .name = "H.264",
- .guid = UVC_GUID_FORMAT_H264,
- .fcc = V4L2_PIX_FMT_H264,
- },
-};
-
-/* ------------------------------------------------------------------------
- * Utility functions
- */
-
-struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
- __u8 epaddr)
-{
- struct usb_host_endpoint *ep;
- unsigned int i;
-
- for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
- ep = &alts->endpoint[i];
- if (ep->desc.bEndpointAddress == epaddr)
- return ep;
- }
-
- return NULL;
-}
-
-static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
-{
- unsigned int len = ARRAY_SIZE(uvc_fmts);
- unsigned int i;
-
- for (i = 0; i < len; ++i) {
- if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
- return &uvc_fmts[i];
- }
-
- return NULL;
-}
-
-static __u32 uvc_colorspace(const __u8 primaries)
-{
- static const __u8 colorprimaries[] = {
- 0,
- V4L2_COLORSPACE_SRGB,
- V4L2_COLORSPACE_470_SYSTEM_M,
- V4L2_COLORSPACE_470_SYSTEM_BG,
- V4L2_COLORSPACE_SMPTE170M,
- V4L2_COLORSPACE_SMPTE240M,
- };
-
- if (primaries < ARRAY_SIZE(colorprimaries))
- return colorprimaries[primaries];
-
- return 0;
-}
-
-/* Simplify a fraction using a simple continued fraction decomposition. The
- * idea here is to convert fractions such as 333333/10000000 to 1/30 using
- * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
- * arbitrary parameters to remove non-significative terms from the simple
- * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
- * respectively seems to give nice results.
- */
-void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
- unsigned int n_terms, unsigned int threshold)
-{
- uint32_t *an;
- uint32_t x, y, r;
- unsigned int i, n;
-
- an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
- if (an == NULL)
- return;
-
- /* Convert the fraction to a simple continued fraction. See
- * http://mathforum.org/dr.math/faq/faq.fractions.html
- * Stop if the current term is bigger than or equal to the given
- * threshold.
- */
- x = *numerator;
- y = *denominator;
-
- for (n = 0; n < n_terms && y != 0; ++n) {
- an[n] = x / y;
- if (an[n] >= threshold) {
- if (n < 2)
- n++;
- break;
- }
-
- r = x - an[n] * y;
- x = y;
- y = r;
- }
-
- /* Expand the simple continued fraction back to an integer fraction. */
- x = 0;
- y = 1;
-
- for (i = n; i > 0; --i) {
- r = y;
- y = an[i-1] * y + x;
- x = r;
- }
-
- *numerator = y;
- *denominator = x;
- kfree(an);
-}
-
-/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
- * to compute numerator / denominator * 10000000 using 32 bit fixed point
- * arithmetic only.
- */
-uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
-{
- uint32_t multiplier;
-
- /* Saturate the result if the operation would overflow. */
- if (denominator == 0 ||
- numerator/denominator >= ((uint32_t)-1)/10000000)
- return (uint32_t)-1;
-
- /* Divide both the denominator and the multiplier by two until
- * numerator * multiplier doesn't overflow. If anyone knows a better
- * algorithm please let me know.
- */
- multiplier = 10000000;
- while (numerator > ((uint32_t)-1)/multiplier) {
- multiplier /= 2;
- denominator /= 2;
- }
-
- return denominator ? numerator * multiplier / denominator : 0;
-}
-
-/* ------------------------------------------------------------------------
- * Terminal and unit management
- */
-
-struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
-{
- struct uvc_entity *entity;
-
- list_for_each_entry(entity, &dev->entities, list) {
- if (entity->id == id)
- return entity;
- }
-
- return NULL;
-}
-
-static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
- int id, struct uvc_entity *entity)
-{
- unsigned int i;
-
- if (entity == NULL)
- entity = list_entry(&dev->entities, struct uvc_entity, list);
-
- list_for_each_entry_continue(entity, &dev->entities, list) {
- for (i = 0; i < entity->bNrInPins; ++i)
- if (entity->baSourceID[i] == id)
- return entity;
- }
-
- return NULL;
-}
-
-static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
-{
- struct uvc_streaming *stream;
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->header.bTerminalLink == id)
- return stream;
- }
-
- return NULL;
-}
-
-/* ------------------------------------------------------------------------
- * Descriptors parsing
- */
-
-static int uvc_parse_format(struct uvc_device *dev,
- struct uvc_streaming *streaming, struct uvc_format *format,
- __u32 **intervals, unsigned char *buffer, int buflen)
-{
- struct usb_interface *intf = streaming->intf;
- struct usb_host_interface *alts = intf->cur_altsetting;
- struct uvc_format_desc *fmtdesc;
- struct uvc_frame *frame;
- const unsigned char *start = buffer;
- unsigned int interval;
- unsigned int i, n;
- __u8 ftype;
-
- format->type = buffer[2];
- format->index = buffer[3];
-
- switch (buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_FRAME_BASED:
- n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
- if (buflen < n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Find the format descriptor from its GUID. */
- fmtdesc = uvc_format_by_guid(&buffer[5]);
-
- if (fmtdesc != NULL) {
- strlcpy(format->name, fmtdesc->name,
- sizeof format->name);
- format->fcc = fmtdesc->fcc;
- } else {
- uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
- &buffer[5]);
- snprintf(format->name, sizeof(format->name), "%pUl\n",
- &buffer[5]);
- format->fcc = 0;
- }
-
- format->bpp = buffer[21];
- if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
- ftype = UVC_VS_FRAME_UNCOMPRESSED;
- } else {
- ftype = UVC_VS_FRAME_FRAME_BASED;
- if (buffer[27])
- format->flags = UVC_FMT_FLAG_COMPRESSED;
- }
- break;
-
- case UVC_VS_FORMAT_MJPEG:
- if (buflen < 11) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- strlcpy(format->name, "MJPEG", sizeof format->name);
- format->fcc = V4L2_PIX_FMT_MJPEG;
- format->flags = UVC_FMT_FLAG_COMPRESSED;
- format->bpp = 0;
- ftype = UVC_VS_FRAME_MJPEG;
- break;
-
- case UVC_VS_FORMAT_DV:
- if (buflen < 9) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- switch (buffer[8] & 0x7f) {
- case 0:
- strlcpy(format->name, "SD-DV", sizeof format->name);
- break;
- case 1:
- strlcpy(format->name, "SDL-DV", sizeof format->name);
- break;
- case 2:
- strlcpy(format->name, "HD-DV", sizeof format->name);
- break;
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d: unknown DV format %u\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber, buffer[8]);
- return -EINVAL;
- }
-
- strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
- sizeof format->name);
-
- format->fcc = V4L2_PIX_FMT_DV;
- format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
- format->bpp = 0;
- ftype = 0;
-
- /* Create a dummy frame descriptor. */
- frame = &format->frame[0];
- memset(&format->frame[0], 0, sizeof format->frame[0]);
- frame->bFrameIntervalType = 1;
- frame->dwDefaultFrameInterval = 1;
- frame->dwFrameInterval = *intervals;
- *(*intervals)++ = 1;
- format->nframes = 1;
- break;
-
- case UVC_VS_FORMAT_MPEG2TS:
- case UVC_VS_FORMAT_STREAM_BASED:
- /* Not supported yet. */
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d unsupported format %u\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber,
- buffer[2]);
- return -EINVAL;
- }
-
- uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
-
- buflen -= buffer[0];
- buffer += buffer[0];
-
- /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
- * based formats have frame descriptors.
- */
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == ftype) {
- frame = &format->frame[format->nframes];
- if (ftype != UVC_VS_FRAME_FRAME_BASED)
- n = buflen > 25 ? buffer[25] : 0;
- else
- n = buflen > 21 ? buffer[21] : 0;
-
- n = n ? n : 3;
-
- if (buflen < 26 + 4*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FRAME error\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- frame->bFrameIndex = buffer[3];
- frame->bmCapabilities = buffer[4];
- frame->wWidth = get_unaligned_le16(&buffer[5]);
- frame->wHeight = get_unaligned_le16(&buffer[7]);
- frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
- frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
- if (ftype != UVC_VS_FRAME_FRAME_BASED) {
- frame->dwMaxVideoFrameBufferSize =
- get_unaligned_le32(&buffer[17]);
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[21]);
- frame->bFrameIntervalType = buffer[25];
- } else {
- frame->dwMaxVideoFrameBufferSize = 0;
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[17]);
- frame->bFrameIntervalType = buffer[21];
- }
- frame->dwFrameInterval = *intervals;
-
- /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
- * completely. Observed behaviours range from setting the
- * value to 1.1x the actual frame size to hardwiring the
- * 16 low bits to 0. This results in a higher than necessary
- * memory usage as well as a wrong image size information. For
- * uncompressed formats this can be fixed by computing the
- * value from the frame size.
- */
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
- frame->dwMaxVideoFrameBufferSize = format->bpp
- * frame->wWidth * frame->wHeight / 8;
-
- /* Some bogus devices report dwMinFrameInterval equal to
- * dwMaxFrameInterval and have dwFrameIntervalStep set to
- * zero. Setting all null intervals to 1 fixes the problem and
- * some other divisions by zero that could happen.
- */
- for (i = 0; i < n; ++i) {
- interval = get_unaligned_le32(&buffer[26+4*i]);
- *(*intervals)++ = interval ? interval : 1;
- }
-
- /* Make sure that the default frame interval stays between
- * the boundaries.
- */
- n -= frame->bFrameIntervalType ? 1 : 2;
- frame->dwDefaultFrameInterval =
- min(frame->dwFrameInterval[n],
- max(frame->dwFrameInterval[0],
- frame->dwDefaultFrameInterval));
-
- if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
- frame->bFrameIntervalType = 1;
- frame->dwFrameInterval[0] =
- frame->dwDefaultFrameInterval;
- }
-
- uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
- frame->wWidth, frame->wHeight,
- 10000000/frame->dwDefaultFrameInterval,
- (100000000/frame->dwDefaultFrameInterval)%10);
-
- format->nframes++;
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == UVC_VS_COLORFORMAT) {
- if (buflen < 6) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d COLORFORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- format->colorspace = uvc_colorspace(buffer[3]);
-
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- return buffer - start;
-}
-
-static int uvc_parse_streaming(struct uvc_device *dev,
- struct usb_interface *intf)
-{
- struct uvc_streaming *streaming = NULL;
- struct uvc_format *format;
- struct uvc_frame *frame;
- struct usb_host_interface *alts = &intf->altsetting[0];
- unsigned char *_buffer, *buffer = alts->extra;
- int _buflen, buflen = alts->extralen;
- unsigned int nformats = 0, nframes = 0, nintervals = 0;
- unsigned int size, i, n, p;
- __u32 *interval;
- __u16 psize;
- int ret = -EINVAL;
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass
- != UVC_SC_VIDEOSTREAMING) {
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
- "video streaming interface\n", dev->udev->devnum,
- intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
- "claimed\n", dev->udev->devnum,
- intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
- if (streaming == NULL) {
- usb_driver_release_interface(&uvc_driver.driver, intf);
- return -EINVAL;
- }
-
- mutex_init(&streaming->mutex);
- streaming->dev = dev;
- streaming->intf = usb_get_intf(intf);
- streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
- /* The Pico iMage webcam has its class-specific interface descriptors
- * after the endpoint descriptors.
- */
- if (buflen == 0) {
- for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
- struct usb_host_endpoint *ep = &alts->endpoint[i];
-
- if (ep->extralen == 0)
- continue;
-
- if (ep->extralen > 2 &&
- ep->extra[1] == USB_DT_CS_INTERFACE) {
- uvc_trace(UVC_TRACE_DESCR, "trying extra data "
- "from endpoint %u.\n", i);
- buffer = alts->endpoint[i].extra;
- buflen = alts->endpoint[i].extralen;
- break;
- }
- }
- }
-
- /* Skip the standard interface descriptors. */
- while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen <= 2) {
- uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
- "interface descriptors found.\n");
- goto error;
- }
-
- /* Parse the header descriptor. */
- switch (buffer[2]) {
- case UVC_VS_OUTPUT_HEADER:
- streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- size = 9;
- break;
-
- case UVC_VS_INPUT_HEADER:
- streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- size = 13;
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d HEADER descriptor not found.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- goto error;
- }
-
- p = buflen >= 4 ? buffer[3] : 0;
- n = buflen >= size ? buffer[size-1] : 0;
-
- if (buflen < size + p*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d HEADER descriptor is invalid.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
-
- streaming->header.bNumFormats = p;
- streaming->header.bEndpointAddress = buffer[6];
- if (buffer[2] == UVC_VS_INPUT_HEADER) {
- streaming->header.bmInfo = buffer[7];
- streaming->header.bTerminalLink = buffer[8];
- streaming->header.bStillCaptureMethod = buffer[9];
- streaming->header.bTriggerSupport = buffer[10];
- streaming->header.bTriggerUsage = buffer[11];
- } else {
- streaming->header.bTerminalLink = buffer[7];
- }
- streaming->header.bControlSize = n;
-
- streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
- GFP_KERNEL);
- if (streaming->header.bmaControls == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- buflen -= buffer[0];
- buffer += buffer[0];
-
- _buffer = buffer;
- _buflen = buflen;
-
- /* Count the format and frame descriptors. */
- while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
- switch (_buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_FRAME_BASED:
- nformats++;
- break;
-
- case UVC_VS_FORMAT_DV:
- /* DV format has no frame descriptor. We will create a
- * dummy frame descriptor with a dummy frame interval.
- */
- nformats++;
- nframes++;
- nintervals++;
- break;
-
- case UVC_VS_FORMAT_MPEG2TS:
- case UVC_VS_FORMAT_STREAM_BASED:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT %u is not supported.\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber, _buffer[2]);
- break;
-
- case UVC_VS_FRAME_UNCOMPRESSED:
- case UVC_VS_FRAME_MJPEG:
- nframes++;
- if (_buflen > 25)
- nintervals += _buffer[25] ? _buffer[25] : 3;
- break;
-
- case UVC_VS_FRAME_FRAME_BASED:
- nframes++;
- if (_buflen > 21)
- nintervals += _buffer[21] ? _buffer[21] : 3;
- break;
- }
-
- _buflen -= _buffer[0];
- _buffer += _buffer[0];
- }
-
- if (nformats == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d has no supported formats defined.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
-
- size = nformats * sizeof *format + nframes * sizeof *frame
- + nintervals * sizeof *interval;
- format = kzalloc(size, GFP_KERNEL);
- if (format == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- frame = (struct uvc_frame *)&format[nformats];
- interval = (__u32 *)&frame[nframes];
-
- streaming->format = format;
- streaming->nformats = nformats;
-
- /* Parse the format descriptors. */
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
- switch (buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_DV:
- case UVC_VS_FORMAT_FRAME_BASED:
- format->frame = frame;
- ret = uvc_parse_format(dev, streaming, format,
- &interval, buffer, buflen);
- if (ret < 0)
- goto error;
-
- frame += format->nframes;
- format++;
-
- buflen -= ret;
- buffer += ret;
- continue;
-
- default:
- break;
- }
-
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen)
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d has %u bytes of trailing descriptor garbage.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);
-
- /* Parse the alternate settings to find the maximum bandwidth. */
- for (i = 0; i < intf->num_altsetting; ++i) {
- struct usb_host_endpoint *ep;
- alts = &intf->altsetting[i];
- ep = uvc_find_endpoint(alts,
- streaming->header.bEndpointAddress);
- if (ep == NULL)
- continue;
-
- psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize > streaming->maxpsize)
- streaming->maxpsize = psize;
- }
-
- list_add_tail(&streaming->list, &dev->streams);
- return 0;
-
-error:
- usb_driver_release_interface(&uvc_driver.driver, intf);
- usb_put_intf(intf);
- kfree(streaming->format);
- kfree(streaming->header.bmaControls);
- kfree(streaming);
- return ret;
-}
-
-static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
- unsigned int num_pads, unsigned int extra_size)
-{
- struct uvc_entity *entity;
- unsigned int num_inputs;
- unsigned int size;
- unsigned int i;
-
- extra_size = ALIGN(extra_size, sizeof(*entity->pads));
- num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
- size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
- + num_inputs;
- entity = kzalloc(size, GFP_KERNEL);
- if (entity == NULL)
- return NULL;
-
- entity->id = id;
- entity->type = type;
-
- entity->num_links = 0;
- entity->num_pads = num_pads;
- entity->pads = ((void *)(entity + 1)) + extra_size;
-
- for (i = 0; i < num_inputs; ++i)
- entity->pads[i].flags = MEDIA_PAD_FL_SINK;
- if (!UVC_ENTITY_IS_OTERM(entity))
- entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
-
- entity->bNrInPins = num_inputs;
- entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
-
- return entity;
-}
-
-/* Parse vendor-specific extensions. */
-static int uvc_parse_vendor_control(struct uvc_device *dev,
- const unsigned char *buffer, int buflen)
-{
- struct usb_device *udev = dev->udev;
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- struct uvc_entity *unit;
- unsigned int n, p;
- int handled = 0;
-
- switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
- case 0x046d: /* Logitech */
- if (buffer[1] != 0x41 || buffer[2] != 0x01)
- break;
-
- /* Logitech implements several vendor specific functions
- * through vendor specific extension units (LXU).
- *
- * The LXU descriptors are similar to XU descriptors
- * (see "USB Device Video Class for Video Devices", section
- * 3.7.2.6 "Extension Unit Descriptor") with the following
- * differences:
- *
- * ----------------------------------------------------------
- * 0 bLength 1 Number
- * Size of this descriptor, in bytes: 24+p+n*2
- * ----------------------------------------------------------
- * 23+p+n bmControlsType N Bitmap
- * Individual bits in the set are defined:
- * 0: Absolute
- * 1: Relative
- *
- * This bitset is mapped exactly the same as bmControls.
- * ----------------------------------------------------------
- * 23+p+n*2 bReserved 1 Boolean
- * ----------------------------------------------------------
- * 24+p+n*2 iExtension 1 Index
- * Index of a string descriptor that describes this
- * extension unit.
- * ----------------------------------------------------------
- */
- p = buflen >= 22 ? buffer[21] : 0;
- n = buflen >= 25 + p ? buffer[22+p] : 0;
-
- if (buflen < 25 + p + 2*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d EXTENSION_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- break;
- }
-
- unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
- p + 1, 2*n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
- unit->extension.bNumControls = buffer[20];
- memcpy(unit->baSourceID, &buffer[22], p);
- unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof(*unit);
- unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit)
- + n;
- memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
-
- if (buffer[24+p+2*n] != 0)
- usb_string(udev, buffer[24+p+2*n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- handled = 1;
- break;
- }
-
- return handled;
-}
-
-static int uvc_parse_standard_control(struct uvc_device *dev,
- const unsigned char *buffer, int buflen)
-{
- struct usb_device *udev = dev->udev;
- struct uvc_entity *unit, *term;
- struct usb_interface *intf;
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- unsigned int i, n, p, len;
- __u16 type;
-
- switch (buffer[2]) {
- case UVC_VC_HEADER:
- n = buflen >= 12 ? buffer[11] : 0;
-
- if (buflen < 12 || buflen < 12 + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d HEADER error\n", udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- dev->uvc_version = get_unaligned_le16(&buffer[3]);
- dev->clock_frequency = get_unaligned_le32(&buffer[7]);
-
- /* Parse all USB Video Streaming interfaces. */
- for (i = 0; i < n; ++i) {
- intf = usb_ifnum_to_if(udev, buffer[12+i]);
- if (intf == NULL) {
- uvc_trace(UVC_TRACE_DESCR, "device %d "
- "interface %d doesn't exists\n",
- udev->devnum, i);
- continue;
- }
-
- uvc_parse_streaming(dev, intf);
- }
- break;
-
- case UVC_VC_INPUT_TERMINAL:
- if (buflen < 8) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Make sure the terminal type MSB is not null, otherwise it
- * could be confused with a unit.
- */
- type = get_unaligned_le16(&buffer[4]);
- if ((type & 0xff00) == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL %d has invalid "
- "type 0x%04x, skipping\n", udev->devnum,
- alts->desc.bInterfaceNumber,
- buffer[3], type);
- return 0;
- }
-
- n = 0;
- p = 0;
- len = 8;
-
- if (type == UVC_ITT_CAMERA) {
- n = buflen >= 15 ? buffer[14] : 0;
- len = 15;
-
- } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
- n = buflen >= 9 ? buffer[8] : 0;
- p = buflen >= 10 + n ? buffer[9+n] : 0;
- len = 10;
- }
-
- if (buflen < len + n + p) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
- 1, n + p);
- if (term == NULL)
- return -ENOMEM;
-
- if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
- term->camera.bControlSize = n;
- term->camera.bmControls = (__u8 *)term + sizeof *term;
- term->camera.wObjectiveFocalLengthMin =
- get_unaligned_le16(&buffer[8]);
- term->camera.wObjectiveFocalLengthMax =
- get_unaligned_le16(&buffer[10]);
- term->camera.wOcularFocalLength =
- get_unaligned_le16(&buffer[12]);
- memcpy(term->camera.bmControls, &buffer[15], n);
- } else if (UVC_ENTITY_TYPE(term) ==
- UVC_ITT_MEDIA_TRANSPORT_INPUT) {
- term->media.bControlSize = n;
- term->media.bmControls = (__u8 *)term + sizeof *term;
- term->media.bTransportModeSize = p;
- term->media.bmTransportModes = (__u8 *)term
- + sizeof *term + n;
- memcpy(term->media.bmControls, &buffer[9], n);
- memcpy(term->media.bmTransportModes, &buffer[10+n], p);
- }
-
- if (buffer[7] != 0)
- usb_string(udev, buffer[7], term->name,
- sizeof term->name);
- else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
- sprintf(term->name, "Camera %u", buffer[3]);
- else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
- sprintf(term->name, "Media %u", buffer[3]);
- else
- sprintf(term->name, "Input %u", buffer[3]);
-
- list_add_tail(&term->list, &dev->entities);
- break;
-
- case UVC_VC_OUTPUT_TERMINAL:
- if (buflen < 9) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d OUTPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Make sure the terminal type MSB is not null, otherwise it
- * could be confused with a unit.
- */
- type = get_unaligned_le16(&buffer[4]);
- if ((type & 0xff00) == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d OUTPUT_TERMINAL %d has invalid "
- "type 0x%04x, skipping\n", udev->devnum,
- alts->desc.bInterfaceNumber, buffer[3], type);
- return 0;
- }
-
- term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
- 1, 0);
- if (term == NULL)
- return -ENOMEM;
-
- memcpy(term->baSourceID, &buffer[7], 1);
-
- if (buffer[8] != 0)
- usb_string(udev, buffer[8], term->name,
- sizeof term->name);
- else
- sprintf(term->name, "Output %u", buffer[3]);
-
- list_add_tail(&term->list, &dev->entities);
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- p = buflen >= 5 ? buffer[4] : 0;
-
- if (buflen < 5 || buflen < 6 + p) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d SELECTOR_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->baSourceID, &buffer[5], p);
-
- if (buffer[5+p] != 0)
- usb_string(udev, buffer[5+p], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Selector %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- case UVC_VC_PROCESSING_UNIT:
- n = buflen >= 8 ? buffer[7] : 0;
- p = dev->uvc_version >= 0x0110 ? 10 : 9;
-
- if (buflen < p + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d PROCESSING_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->baSourceID, &buffer[4], 1);
- unit->processing.wMaxMultiplier =
- get_unaligned_le16(&buffer[5]);
- unit->processing.bControlSize = buffer[7];
- unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
- memcpy(unit->processing.bmControls, &buffer[8], n);
- if (dev->uvc_version >= 0x0110)
- unit->processing.bmVideoStandards = buffer[9+n];
-
- if (buffer[8+n] != 0)
- usb_string(udev, buffer[8+n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Processing %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- case UVC_VC_EXTENSION_UNIT:
- p = buflen >= 22 ? buffer[21] : 0;
- n = buflen >= 24 + p ? buffer[22+p] : 0;
-
- if (buflen < 24 + p + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d EXTENSION_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
- unit->extension.bNumControls = buffer[20];
- memcpy(unit->baSourceID, &buffer[22], p);
- unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof *unit;
- memcpy(unit->extension.bmControls, &buffer[23+p], n);
-
- if (buffer[23+p+n] != 0)
- usb_string(udev, buffer[23+p+n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
- "descriptor (%u)\n", buffer[2]);
- break;
- }
-
- return 0;
-}
-
-static int uvc_parse_control(struct uvc_device *dev)
-{
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- unsigned char *buffer = alts->extra;
- int buflen = alts->extralen;
- int ret;
-
- /* Parse the default alternate setting only, as the UVC specification
- * defines a single alternate setting, the default alternate setting
- * zero.
- */
-
- while (buflen > 2) {
- if (uvc_parse_vendor_control(dev, buffer, buflen) ||
- buffer[1] != USB_DT_CS_INTERFACE)
- goto next_descriptor;
-
- if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
- return ret;
-
-next_descriptor:
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- /* Check if the optional status endpoint is present. Built-in iSight
- * webcams have an interrupt endpoint but spit proprietary data that
- * don't conform to the UVC status endpoint messages. Don't try to
- * handle the interrupt endpoint for those cameras.
- */
- if (alts->desc.bNumEndpoints == 1 &&
- !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
- struct usb_host_endpoint *ep = &alts->endpoint[0];
- struct usb_endpoint_descriptor *desc = &ep->desc;
-
- if (usb_endpoint_is_int_in(desc) &&
- le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
- desc->bInterval != 0) {
- uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
- "(addr %02x).\n", desc->bEndpointAddress);
- dev->int_ep = ep;
- }
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * UVC device scan
- */
-
-/*
- * Scan the UVC descriptors to locate a chain starting at an Output Terminal
- * and containing the following units:
- *
- * - one or more Output Terminals (USB Streaming or Display)
- * - zero or one Processing Unit
- * - zero, one or more single-input Selector Units
- * - zero or one multiple-input Selector Units, provided all inputs are
- * connected to input terminals
- * - zero, one or mode single-input Extension Units
- * - one or more Input Terminals (Camera, External or USB Streaming)
- *
- * The terminal and units must match on of the following structures:
- *
- * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
- * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
- * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
- *
- * +---------+ +---------+ -> OTT_*(0)
- * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
- * +---------+ +---------+ -> OTT_*(n)
- *
- * The Processing Unit and Extension Units can be in any order. Additional
- * Extension Units connected to the main chain as single-unit branches are
- * also supported. Single-input Selector Units are ignored.
- */
-static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
- struct uvc_entity *entity)
-{
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_VC_EXTENSION_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- XU %d", entity->id);
-
- if (entity->bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
- "than 1 input pin.\n", entity->id);
- return -1;
- }
-
- break;
-
- case UVC_VC_PROCESSING_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- PU %d", entity->id);
-
- if (chain->processing != NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found multiple "
- "Processing Units in chain.\n");
- return -1;
- }
-
- chain->processing = entity;
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- SU %d", entity->id);
-
- /* Single-input selector units are ignored. */
- if (entity->bNrInPins == 1)
- break;
-
- if (chain->selector != NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
- "Units in chain.\n");
- return -1;
- }
-
- chain->selector = entity;
- break;
-
- case UVC_ITT_VENDOR_SPECIFIC:
- case UVC_ITT_CAMERA:
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT %d\n", entity->id);
-
- break;
-
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" OT %d", entity->id);
-
- break;
-
- case UVC_TT_STREAMING:
- if (UVC_ENTITY_IS_ITERM(entity)) {
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT %d\n", entity->id);
- } else {
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" OT %d", entity->id);
- }
-
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
- "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
- return -1;
- }
-
- list_add_tail(&entity->chain, &chain->entities);
- return 0;
-}
-
-static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
- struct uvc_entity *entity, struct uvc_entity *prev)
-{
- struct uvc_entity *forward;
- int found;
-
- /* Forward scan */
- forward = NULL;
- found = 0;
-
- while (1) {
- forward = uvc_entity_by_reference(chain->dev, entity->id,
- forward);
- if (forward == NULL)
- break;
- if (forward == prev)
- continue;
-
- switch (UVC_ENTITY_TYPE(forward)) {
- case UVC_VC_EXTENSION_UNIT:
- if (forward->bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
- "has more than 1 input pin.\n",
- entity->id);
- return -EINVAL;
- }
-
- list_add_tail(&forward->chain, &chain->entities);
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- if (!found)
- printk(" (->");
-
- printk(" XU %d", forward->id);
- found = 1;
- }
- break;
-
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- case UVC_TT_STREAMING:
- if (UVC_ENTITY_IS_ITERM(forward)) {
- uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
- "terminal %u.\n", forward->id);
- return -EINVAL;
- }
-
- list_add_tail(&forward->chain, &chain->entities);
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- if (!found)
- printk(" (->");
-
- printk(" OT %d", forward->id);
- found = 1;
- }
- break;
- }
- }
- if (found)
- printk(")");
-
- return 0;
-}
-
-static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
- struct uvc_entity **_entity)
-{
- struct uvc_entity *entity = *_entity;
- struct uvc_entity *term;
- int id = -EINVAL, i;
-
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_VC_EXTENSION_UNIT:
- case UVC_VC_PROCESSING_UNIT:
- id = entity->baSourceID[0];
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- /* Single-input selector units are ignored. */
- if (entity->bNrInPins == 1) {
- id = entity->baSourceID[0];
- break;
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT");
-
- chain->selector = entity;
- for (i = 0; i < entity->bNrInPins; ++i) {
- id = entity->baSourceID[i];
- term = uvc_entity_by_id(chain->dev, id);
- if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
- uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
- "input %d isn't connected to an "
- "input terminal\n", entity->id, i);
- return -1;
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" %d", term->id);
-
- list_add_tail(&term->chain, &chain->entities);
- uvc_scan_chain_forward(chain, term, entity);
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk("\n");
-
- id = 0;
- break;
-
- case UVC_ITT_VENDOR_SPECIFIC:
- case UVC_ITT_CAMERA:
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- case UVC_TT_STREAMING:
- id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
- break;
- }
-
- if (id <= 0) {
- *_entity = NULL;
- return id;
- }
-
- entity = uvc_entity_by_id(chain->dev, id);
- if (entity == NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "unknown entity %d.\n", id);
- return -EINVAL;
- }
-
- *_entity = entity;
- return 0;
-}
-
-static int uvc_scan_chain(struct uvc_video_chain *chain,
- struct uvc_entity *term)
-{
- struct uvc_entity *entity, *prev;
-
- uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
-
- entity = term;
- prev = NULL;
-
- while (entity != NULL) {
- /* Entity must not be part of an existing chain */
- if (entity->chain.next || entity->chain.prev) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "entity %d already in chain.\n", entity->id);
- return -EINVAL;
- }
-
- /* Process entity */
- if (uvc_scan_chain_entity(chain, entity) < 0)
- return -EINVAL;
-
- /* Forward scan */
- if (uvc_scan_chain_forward(chain, entity, prev) < 0)
- return -EINVAL;
-
- /* Backward scan */
- prev = entity;
- if (uvc_scan_chain_backward(chain, &entity) < 0)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static unsigned int uvc_print_terms(struct list_head *terms, u16 dir,
- char *buffer)
-{
- struct uvc_entity *term;
- unsigned int nterms = 0;
- char *p = buffer;
-
- list_for_each_entry(term, terms, chain) {
- if (!UVC_ENTITY_IS_TERM(term) ||
- UVC_TERM_DIRECTION(term) != dir)
- continue;
-
- if (nterms)
- p += sprintf(p, ",");
- if (++nterms >= 4) {
- p += sprintf(p, "...");
- break;
- }
- p += sprintf(p, "%u", term->id);
- }
-
- return p - buffer;
-}
-
-static const char *uvc_print_chain(struct uvc_video_chain *chain)
-{
- static char buffer[43];
- char *p = buffer;
-
- p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p);
- p += sprintf(p, " -> ");
- uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p);
-
- return buffer;
-}
-
-/*
- * Scan the device for video chains and register video devices.
- *
- * Chains are scanned starting at their output terminals and walked backwards.
- */
-static int uvc_scan_device(struct uvc_device *dev)
-{
- struct uvc_video_chain *chain;
- struct uvc_entity *term;
-
- list_for_each_entry(term, &dev->entities, list) {
- if (!UVC_ENTITY_IS_OTERM(term))
- continue;
-
- /* If the terminal is already included in a chain, skip it.
- * This can happen for chains that have multiple output
- * terminals, where all output terminals beside the first one
- * will be inserted in the chain in forward scans.
- */
- if (term->chain.next || term->chain.prev)
- continue;
-
- chain = kzalloc(sizeof(*chain), GFP_KERNEL);
- if (chain == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&chain->entities);
- mutex_init(&chain->ctrl_mutex);
- chain->dev = dev;
-
- if (uvc_scan_chain(chain, term) < 0) {
- kfree(chain);
- continue;
- }
-
- uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
- uvc_print_chain(chain));
-
- list_add_tail(&chain->list, &dev->chains);
- }
-
- if (list_empty(&dev->chains)) {
- uvc_printk(KERN_INFO, "No valid video chain found.\n");
- return -1;
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * Video device registration and unregistration
- */
-
-/*
- * Delete the UVC device.
- *
- * Called by the kernel when the last reference to the uvc_device structure
- * is released.
- *
- * As this function is called after or during disconnect(), all URBs have
- * already been canceled by the USB core. There is no need to kill the
- * interrupt URB manually.
- */
-static void uvc_delete(struct uvc_device *dev)
-{
- struct list_head *p, *n;
-
- usb_put_intf(dev->intf);
- usb_put_dev(dev->udev);
-
- uvc_status_cleanup(dev);
- uvc_ctrl_cleanup_device(dev);
-
- if (dev->vdev.dev)
- v4l2_device_unregister(&dev->vdev);
-#ifdef CONFIG_MEDIA_CONTROLLER
- if (media_devnode_is_registered(&dev->mdev.devnode))
- media_device_unregister(&dev->mdev);
-#endif
-
- list_for_each_safe(p, n, &dev->chains) {
- struct uvc_video_chain *chain;
- chain = list_entry(p, struct uvc_video_chain, list);
- kfree(chain);
- }
-
- list_for_each_safe(p, n, &dev->entities) {
- struct uvc_entity *entity;
- entity = list_entry(p, struct uvc_entity, list);
-#ifdef CONFIG_MEDIA_CONTROLLER
- uvc_mc_cleanup_entity(entity);
-#endif
- if (entity->vdev) {
- video_device_release(entity->vdev);
- entity->vdev = NULL;
- }
- kfree(entity);
- }
-
- list_for_each_safe(p, n, &dev->streams) {
- struct uvc_streaming *streaming;
- streaming = list_entry(p, struct uvc_streaming, list);
- usb_driver_release_interface(&uvc_driver.driver,
- streaming->intf);
- usb_put_intf(streaming->intf);
- kfree(streaming->format);
- kfree(streaming->header.bmaControls);
- kfree(streaming);
- }
-
- kfree(dev);
-}
-
-static void uvc_release(struct video_device *vdev)
-{
- struct uvc_streaming *stream = video_get_drvdata(vdev);
- struct uvc_device *dev = stream->dev;
-
- /* Decrement the registered streams count and delete the device when it
- * reaches zero.
- */
- if (atomic_dec_and_test(&dev->nstreams))
- uvc_delete(dev);
-}
-
-/*
- * Unregister the video devices.
- */
-static void uvc_unregister_video(struct uvc_device *dev)
-{
- struct uvc_streaming *stream;
-
- /* Unregistering all video devices might result in uvc_delete() being
- * called from inside the loop if there's no open file handle. To avoid
- * that, increment the stream count before iterating over the streams
- * and decrement it when done.
- */
- atomic_inc(&dev->nstreams);
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->vdev == NULL)
- continue;
-
- video_unregister_device(stream->vdev);
- stream->vdev = NULL;
-
- uvc_debugfs_cleanup_stream(stream);
- }
-
- /* Decrement the stream count and call uvc_delete explicitly if there
- * are no stream left.
- */
- if (atomic_dec_and_test(&dev->nstreams))
- uvc_delete(dev);
-}
-
-static int uvc_register_video(struct uvc_device *dev,
- struct uvc_streaming *stream)
-{
- struct video_device *vdev;
- int ret;
-
- /* Initialize the streaming interface with default streaming
- * parameters.
- */
- ret = uvc_video_init(stream);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to initialize the device "
- "(%d).\n", ret);
- return ret;
- }
-
- uvc_debugfs_init_stream(stream);
-
- /* Register the device with V4L. */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
- ret);
- return -ENOMEM;
- }
-
- /* We already hold a reference to dev->udev. The video device will be
- * unregistered before the reference is released, so we don't need to
- * get another one.
- */
- vdev->v4l2_dev = &dev->vdev;
- vdev->fops = &uvc_fops;
- vdev->release = uvc_release;
- strlcpy(vdev->name, dev->name, sizeof vdev->name);
-
- /* Set the driver data before calling video_register_device, otherwise
- * uvc_v4l2_open might race us.
- */
- stream->vdev = vdev;
- video_set_drvdata(vdev, stream);
-
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
- ret);
- stream->vdev = NULL;
- video_device_release(vdev);
- return ret;
- }
-
- atomic_inc(&dev->nstreams);
- return 0;
-}
-
-/*
- * Register all video devices in all chains.
- */
-static int uvc_register_terms(struct uvc_device *dev,
- struct uvc_video_chain *chain)
-{
- struct uvc_streaming *stream;
- struct uvc_entity *term;
- int ret;
-
- list_for_each_entry(term, &chain->entities, chain) {
- if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
- continue;
-
- stream = uvc_stream_by_id(dev, term->id);
- if (stream == NULL) {
- uvc_printk(KERN_INFO, "No streaming interface found "
- "for terminal %u.", term->id);
- continue;
- }
-
- stream->chain = chain;
- ret = uvc_register_video(dev, stream);
- if (ret < 0)
- return ret;
-
- term->vdev = stream->vdev;
- }
-
- return 0;
-}
-
-static int uvc_register_chains(struct uvc_device *dev)
-{
- struct uvc_video_chain *chain;
- int ret;
-
- list_for_each_entry(chain, &dev->chains, list) {
- ret = uvc_register_terms(dev, chain);
- if (ret < 0)
- return ret;
-
-#ifdef CONFIG_MEDIA_CONTROLLER
- ret = uvc_mc_register_entities(chain);
- if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to register entites "
- "(%d).\n", ret);
- }
-#endif
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * USB probe, disconnect, suspend and resume
- */
-
-static int uvc_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct uvc_device *dev;
- int ret;
-
- if (id->idVendor && id->idProduct)
- uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
- "(%04x:%04x)\n", udev->devpath, id->idVendor,
- id->idProduct);
- else
- uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
- udev->devpath);
-
- /* Allocate memory for the device and initialize it. */
- if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&dev->entities);
- INIT_LIST_HEAD(&dev->chains);
- INIT_LIST_HEAD(&dev->streams);
- atomic_set(&dev->nstreams, 0);
- atomic_set(&dev->users, 0);
- atomic_set(&dev->nmappings, 0);
-
- dev->udev = usb_get_dev(udev);
- dev->intf = usb_get_intf(intf);
- dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = (uvc_quirks_param == -1)
- ? id->driver_info : uvc_quirks_param;
-
- if (udev->product != NULL)
- strlcpy(dev->name, udev->product, sizeof dev->name);
- else
- snprintf(dev->name, sizeof dev->name,
- "UVC Camera (%04x:%04x)",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- /* Parse the Video Class control descriptor. */
- if (uvc_parse_control(dev) < 0) {
- uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
- "descriptors.\n");
- goto error;
- }
-
- uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
- dev->uvc_version >> 8, dev->uvc_version & 0xff,
- udev->product ? udev->product : "<unnamed>",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- if (dev->quirks != id->driver_info) {
- uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
- "parameter for testing purpose.\n", dev->quirks);
- uvc_printk(KERN_INFO, "Please report required quirks to the "
- "linux-uvc-devel mailing list.\n");
- }
-
- /* Register the media and V4L2 devices. */
-#ifdef CONFIG_MEDIA_CONTROLLER
- dev->mdev.dev = &intf->dev;
- strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
- if (udev->serial)
- strlcpy(dev->mdev.serial, udev->serial,
- sizeof(dev->mdev.serial));
- strcpy(dev->mdev.bus_info, udev->devpath);
- dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- dev->mdev.driver_version = LINUX_VERSION_CODE;
- if (media_device_register(&dev->mdev) < 0)
- goto error;
-
- dev->vdev.mdev = &dev->mdev;
-#endif
- if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
- goto error;
-
- /* Initialize controls. */
- if (uvc_ctrl_init_device(dev) < 0)
- goto error;
-
- /* Scan the device for video chains. */
- if (uvc_scan_device(dev) < 0)
- goto error;
-
- /* Register video device nodes. */
- if (uvc_register_chains(dev) < 0)
- goto error;
-
- /* Save our data pointer in the interface data. */
- usb_set_intfdata(intf, dev);
-
- /* Initialize the interrupt URB. */
- if ((ret = uvc_status_init(dev)) < 0) {
- uvc_printk(KERN_INFO, "Unable to initialize the status "
- "endpoint (%d), status interrupt will not be "
- "supported.\n", ret);
- }
-
- uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
- usb_enable_autosuspend(udev);
- return 0;
-
-error:
- uvc_unregister_video(dev);
- return -ENODEV;
-}
-
-static void uvc_disconnect(struct usb_interface *intf)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
-
- /* Set the USB interface data to NULL. This can be done outside the
- * lock, as there's no other reader.
- */
- usb_set_intfdata(intf, NULL);
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOSTREAMING)
- return;
-
- dev->state |= UVC_DEV_DISCONNECTED;
-
- uvc_unregister_video(dev);
-}
-
-static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
- struct uvc_streaming *stream;
-
- uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- /* Controls are cached on the fly so they don't need to be saved. */
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOCONTROL)
- return uvc_status_suspend(dev);
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->intf == intf)
- return uvc_video_suspend(stream);
- }
-
- uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
- "mismatch.\n");
- return -EINVAL;
-}
-
-static int __uvc_resume(struct usb_interface *intf, int reset)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
- struct uvc_streaming *stream;
-
- uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOCONTROL) {
- if (reset) {
- int ret = uvc_ctrl_resume_device(dev);
-
- if (ret < 0)
- return ret;
- }
-
- return uvc_status_resume(dev);
- }
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->intf == intf)
- return uvc_video_resume(stream, reset);
- }
-
- uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
- "mismatch.\n");
- return -EINVAL;
-}
-
-static int uvc_resume(struct usb_interface *intf)
-{
- return __uvc_resume(intf, 0);
-}
-
-static int uvc_reset_resume(struct usb_interface *intf)
-{
- return __uvc_resume(intf, 1);
-}
-
-/* ------------------------------------------------------------------------
- * Module parameters
- */
-
-static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
-{
- if (uvc_clock_param == CLOCK_MONOTONIC)
- return sprintf(buffer, "CLOCK_MONOTONIC");
- else
- return sprintf(buffer, "CLOCK_REALTIME");
-}
-
-static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
-{
- if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
- val += strlen("clock_");
-
- if (strcasecmp(val, "monotonic") == 0)
- uvc_clock_param = CLOCK_MONOTONIC;
- else if (strcasecmp(val, "realtime") == 0)
- uvc_clock_param = CLOCK_REALTIME;
- else
- return -EINVAL;
-
- return 0;
-}
-
-module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
- &uvc_clock_param, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(trace, "Trace level bitmask");
-module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
-
-/* ------------------------------------------------------------------------
- * Driver initialization and cleanup
- */
-
-/*
- * The Logitech cameras listed below have their interface class set to
- * VENDOR_SPEC because they don't announce themselves as UVC devices, even
- * 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,
- .idVendor = 0x0458,
- .idProduct = 0x706e,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Microsoft Lifecam NX-6000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x00f8,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Microsoft Lifecam VX-7000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x0723,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Logitech Quickcam Fusion */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c1,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Orbit MP */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro for Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c3,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro 5000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c5,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Dell Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c6,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Cisco VT Camera II */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c7,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Chicony CNF7129 (Asus EEE 100HE) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb071,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE },
- /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x058f,
- .idProduct = 0x3820,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .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,
- .idVendor = 0x05ac,
- .idProduct = 0x8501,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_BUILTIN_ISIGHT },
- /* Foxlink ("HP Webcam" on HP Mini 5103) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05c8,
- .idProduct = 0x0403,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* Genesys Logic USB 2.0 PC Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05e3,
- .idProduct = 0x0505,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Hercules Classic Silver */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x06f8,
- .idProduct = 0x300c,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro Vega */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x332d,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro - Minoru3D */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x3410,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro Venus - Minoru3D */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x3420,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* MT6227 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0e8d,
- .idProduct = 0x0004,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_PROBE_DEF },
- /* IMC Networks (Medion Akoya) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x13d3,
- .idProduct = 0x5103,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* JMicron USB2.0 XGA WebCam */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x152d,
- .idProduct = 0x0310,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Syntek (HP Spartan) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5212,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Samsung Q310) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5931,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Packard Bell EasyNote MX52 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a12,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Asus F9SG) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a31,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Asus U3S) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a33,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (JAOtech Smart Terminal) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a34,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Miricle 307K */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x17dc,
- .idProduct = 0x0202,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Lenovo Thinkpad SL400/SL500 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x17ef,
- .idProduct = 0x480b,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Aveo Technology USB 2.0 Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1871,
- .idProduct = 0x0306,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_PROBE_EXTRAFIELDS },
- /* Ecamm Pico iMage */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18cd,
- .idProduct = 0xcafe,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
- /* Manta MM-353 Plako */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3188,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* FSC WebCam V30S */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3288,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Arkmicro unbranded */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3290,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_DEF },
- /* The Imaging Source USB CCD cameras */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x199e,
- .idProduct = 0x8102,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Bodelin ProScopeHR */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_DEV_HI
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x19ab,
- .idProduct = 0x1000,
- .bcdDevice_hi = 0x0126,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STATUS_INTERVAL },
- /* MSI StarCam 370i */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1b3b,
- .idProduct = 0x2951,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* SiGma Micro USB Web Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1c4f,
- .idProduct = 0x3000,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
- /* Generic USB Video Class */
- { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
- {}
-};
-
-MODULE_DEVICE_TABLE(usb, uvc_ids);
-
-struct uvc_driver uvc_driver = {
- .driver = {
- .name = "uvcvideo",
- .probe = uvc_probe,
- .disconnect = uvc_disconnect,
- .suspend = uvc_suspend,
- .resume = uvc_resume,
- .reset_resume = uvc_reset_resume,
- .id_table = uvc_ids,
- .supports_autosuspend = 1,
- },
-};
-
-static int __init uvc_init(void)
-{
- int ret;
-
- uvc_debugfs_init();
-
- 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);
-module_exit(uvc_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
deleted file mode 100644
index 7ac4347ca09e..000000000000
--- a/drivers/media/video/uvc/uvc_video.c
+++ /dev/null
@@ -1,1861 +0,0 @@
-/*
- * uvc_video.c -- USB Video Class driver - Video handling
- *
- * Copyright (C) 2005-2010
- * 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/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/atomic.h>
-#include <asm/unaligned.h>
-
-#include <media/v4l2-common.h>
-
-#include "uvcvideo.h"
-
-/* ------------------------------------------------------------------------
- * UVC Controls
- */
-
-static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size,
- int timeout)
-{
- __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- unsigned int pipe;
-
- pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
- : usb_sndctrlpipe(dev->udev, 0);
- type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
-
- return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
- unit << 8 | intfnum, data, size, timeout);
-}
-
-static const char *uvc_query_name(__u8 query)
-{
- switch (query) {
- case UVC_SET_CUR:
- return "SET_CUR";
- case UVC_GET_CUR:
- return "GET_CUR";
- case UVC_GET_MIN:
- return "GET_MIN";
- case UVC_GET_MAX:
- return "GET_MAX";
- case UVC_GET_RES:
- return "GET_RES";
- case UVC_GET_LEN:
- return "GET_LEN";
- case UVC_GET_INFO:
- return "GET_INFO";
- case UVC_GET_DEF:
- return "GET_DEF";
- default:
- return "<invalid>";
- }
-}
-
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size)
-{
- int ret;
-
- ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
- UVC_CTRL_CONTROL_TIMEOUT);
- if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
- "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
- unit, ret, size);
- return -EIO;
- }
-
- return 0;
-}
-
-static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl)
-{
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- unsigned int i;
-
- for (i = 0; i < stream->nformats; ++i) {
- if (stream->format[i].index == ctrl->bFormatIndex) {
- format = &stream->format[i];
- break;
- }
- }
-
- if (format == NULL)
- return;
-
- for (i = 0; i < format->nframes; ++i) {
- if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
- frame = &format->frame[i];
- break;
- }
- }
-
- if (frame == NULL)
- return;
-
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
- (ctrl->dwMaxVideoFrameSize == 0 &&
- stream->dev->uvc_version < 0x0110))
- ctrl->dwMaxVideoFrameSize =
- frame->dwMaxVideoFrameBufferSize;
-
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) &&
- stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
- stream->intf->num_altsetting > 1) {
- u32 interval;
- u32 bandwidth;
-
- interval = (ctrl->dwFrameInterval > 100000)
- ? ctrl->dwFrameInterval
- : frame->dwFrameInterval[0];
-
- /* Compute a bandwidth estimation by multiplying the frame
- * size by the number of video frames per second, divide the
- * result by the number of USB frames (or micro-frames for
- * high-speed devices) per second and add the UVC header size
- * (assumed to be 12 bytes long).
- */
- bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
- bandwidth *= 10000000 / interval + 1;
- bandwidth /= 1000;
- if (stream->dev->udev->speed == USB_SPEED_HIGH)
- bandwidth /= 8;
- bandwidth += 12;
-
- /* The bandwidth estimate is too low for many cameras. Don't use
- * maximum packet sizes lower than 1024 bytes to try and work
- * around the problem. According to measurements done on two
- * different camera models, the value is high enough to get most
- * resolutions working while not preventing two simultaneous
- * VGA streams at 15 fps.
- */
- bandwidth = max_t(u32, bandwidth, 1024);
-
- ctrl->dwMaxPayloadTransferSize = bandwidth;
- }
-}
-
-static int uvc_get_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl, int probe, __u8 query)
-{
- __u8 *data;
- __u16 size;
- int ret;
-
- size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
- if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) &&
- query == UVC_GET_DEF)
- return -EIO;
-
- data = kmalloc(size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
- probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
- size, uvc_timeout_param);
-
- if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
- /* Some cameras, mostly based on Bison Electronics chipsets,
- * answer a GET_MIN or GET_MAX request with the wCompQuality
- * field only.
- */
- uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
- "compliance - GET_MIN/MAX(PROBE) incorrectly "
- "supported. Enabling workaround.\n");
- memset(ctrl, 0, sizeof *ctrl);
- ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
- ret = 0;
- goto out;
- } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
- /* Many cameras don't support the GET_DEF request on their
- * video probe control. Warn once and return, the caller will
- * fall back to GET_CUR.
- */
- uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
- "compliance - GET_DEF(PROBE) not supported. "
- "Enabling workaround.\n");
- ret = -EIO;
- goto out;
- } else if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
- "%d (exp. %u).\n", query, probe ? "probe" : "commit",
- ret, size);
- ret = -EIO;
- goto out;
- }
-
- ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
- ctrl->bFormatIndex = data[2];
- ctrl->bFrameIndex = data[3];
- ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
- ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
- ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
- ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
- ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
- ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
- ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
- ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
-
- if (size == 34) {
- ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
- ctrl->bmFramingInfo = data[30];
- ctrl->bPreferedVersion = data[31];
- ctrl->bMinVersion = data[32];
- ctrl->bMaxVersion = data[33];
- } else {
- ctrl->dwClockFrequency = stream->dev->clock_frequency;
- ctrl->bmFramingInfo = 0;
- ctrl->bPreferedVersion = 0;
- ctrl->bMinVersion = 0;
- ctrl->bMaxVersion = 0;
- }
-
- /* Some broken devices return null or wrong dwMaxVideoFrameSize and
- * dwMaxPayloadTransferSize fields. Try to get the value from the
- * format and frame descriptors.
- */
- uvc_fixup_video_ctrl(stream, ctrl);
- ret = 0;
-
-out:
- kfree(data);
- return ret;
-}
-
-static int uvc_set_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl, int probe)
-{
- __u8 *data;
- __u16 size;
- int ret;
-
- size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
- data = kzalloc(size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
- data[2] = ctrl->bFormatIndex;
- data[3] = ctrl->bFrameIndex;
- *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
- *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
- *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
- *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
- *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
- *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
- put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
- put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
-
- if (size == 34) {
- put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
- data[30] = ctrl->bmFramingInfo;
- data[31] = ctrl->bPreferedVersion;
- data[32] = ctrl->bMinVersion;
- data[33] = ctrl->bMaxVersion;
- }
-
- ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
- probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
- size, uvc_timeout_param);
- if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
- "%d (exp. %u).\n", probe ? "probe" : "commit",
- ret, size);
- ret = -EIO;
- }
-
- kfree(data);
- return ret;
-}
-
-int uvc_probe_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe)
-{
- struct uvc_streaming_control probe_min, probe_max;
- __u16 bandwidth;
- unsigned int i;
- int ret;
-
- /* Perform probing. The device should adjust the requested values
- * according to its capabilities. However, some devices, namely the
- * first generation UVC Logitech webcams, don't implement the Video
- * Probe control properly, and just return the needed bandwidth. For
- * that reason, if the needed bandwidth exceeds the maximum available
- * bandwidth, try to lower the quality.
- */
- ret = uvc_set_video_ctrl(stream, probe, 1);
- if (ret < 0)
- goto done;
-
- /* Get the minimum and maximum values for compression settings. */
- if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
- ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
- if (ret < 0)
- goto done;
- ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
- if (ret < 0)
- goto done;
-
- probe->wCompQuality = probe_max.wCompQuality;
- }
-
- for (i = 0; i < 2; ++i) {
- ret = uvc_set_video_ctrl(stream, probe, 1);
- if (ret < 0)
- goto done;
- ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
- if (ret < 0)
- goto done;
-
- if (stream->intf->num_altsetting == 1)
- break;
-
- bandwidth = probe->dwMaxPayloadTransferSize;
- if (bandwidth <= stream->maxpsize)
- break;
-
- if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
- ret = -ENOSPC;
- goto done;
- }
-
- /* TODO: negotiate compression parameters */
- probe->wKeyFrameRate = probe_min.wKeyFrameRate;
- probe->wPFrameRate = probe_min.wPFrameRate;
- probe->wCompQuality = probe_max.wCompQuality;
- probe->wCompWindowSize = probe_min.wCompWindowSize;
- }
-
-done:
- return ret;
-}
-
-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);
-}
-
-/* ------------------------------------------------------------------------
- * Stream statistics
- */
-
-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().
- *
- * uvc_video_decode_start is called with URB data at the start of a bulk or
- * isochronous payload. It processes header data and returns the header size
- * in bytes if successful. If an error occurs, it returns a negative error
- * code. The following error codes have special meanings.
- *
- * - EAGAIN informs the caller that the current video buffer should be marked
- * as done, and that the function should be called again with the same data
- * and a new video buffer. This is used when end of frame conditions can be
- * reliably detected at the beginning of the next frame only.
- *
- * If an error other than -EAGAIN is returned, the caller will drop the current
- * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
- * made until the next payload. -ENODATA can be used to drop the current
- * payload if no other error code is appropriate.
- *
- * uvc_video_decode_data is called for every URB with URB data. It copies the
- * data to the video buffer.
- *
- * uvc_video_decode_end is called with header data at the end of a bulk or
- * isochronous payload. It performs any additional header data processing and
- * returns 0 or a negative error code if an error occurred. As header data have
- * already been processed by uvc_video_decode_start, this functions isn't
- * required to perform sanity checks a second time.
- *
- * For isochronous transfers where a payload is always transferred in a single
- * URB, the three functions will be called in a row.
- *
- * To let the decoder process header data and update its internal state even
- * when no video buffer is available, uvc_video_decode_start must be prepared
- * to be called with a NULL buf parameter. uvc_video_decode_data and
- * uvc_video_decode_end will never be called with a NULL buffer.
- */
-static int uvc_video_decode_start(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
-{
- __u8 fid;
-
- /* Sanity checks:
- * - packet must be at least 2 bytes long
- * - 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) {
- stream->stats.frame.nb_invalid++;
- return -EINVAL;
- }
-
- fid = data[1] & UVC_STREAM_FID;
-
- /* Increase the sequence number regardless of any buffer states, so
- * that discontinuous sequence numbers always indicate lost frames.
- */
- 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.
- */
- if (buf == NULL) {
- stream->last_fid = fid;
- 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
- * frame will always be in sync.
- *
- * If the device doesn't toggle the FID bit, invert stream->last_fid
- * when the EOF bit is set to force synchronisation on the next packet.
- */
- if (buf->state != UVC_BUF_STATE_ACTIVE) {
- struct timespec ts;
-
- if (fid == stream->last_fid) {
- uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
- "sync).\n");
- if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
- (data[1] & UVC_STREAM_EOF))
- stream->last_fid ^= UVC_STREAM_FID;
- return -ENODATA;
- }
-
- if (uvc_clock_param == CLOCK_MONOTONIC)
- ktime_get_ts(&ts);
- else
- ktime_get_real_ts(&ts);
-
- 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;
- }
-
- /* Mark the buffer as done if we're at the beginning of a new frame.
- * End of frame detection is better implemented by checking the EOF
- * bit (FID bit toggling is delayed by one frame compared to the EOF
- * bit), but some devices don't set the bit at end of frame (and the
- * last payload can be lost anyway). We thus must check if the FID has
- * been toggled.
- *
- * stream->last_fid is initialized to -1, so the first isochronous
- * frame will never trigger an end of frame detection.
- *
- * Empty buffers (bytesused == 0) don't trigger end of frame detection
- * as it doesn't make sense to return an empty buffer. This also
- * avoids detecting end of frame conditions at FID toggling if the
- * previous payload had the EOF bit set.
- */
- 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;
- return -EAGAIN;
- }
-
- stream->last_fid = fid;
-
- return data[0];
-}
-
-static void uvc_video_decode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
-{
- unsigned int maxlen, nbytes;
- void *mem;
-
- if (len <= 0)
- return;
-
- /* Copy the video data to the buffer. */
- maxlen = buf->length - buf->bytesused;
- mem = buf->mem + buf->bytesused;
- nbytes = min((unsigned int)len, maxlen);
- memcpy(mem, data, nbytes);
- buf->bytesused += nbytes;
-
- /* Complete the current frame if the buffer size was exceeded. */
- if (len > maxlen) {
- uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
- buf->state = UVC_BUF_STATE_READY;
- }
-}
-
-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->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");
- buf->state = UVC_BUF_STATE_READY;
- if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
- stream->last_fid ^= UVC_STREAM_FID;
- }
-}
-
-/* Video payload encoding is handled by uvc_video_encode_header() and
- * uvc_video_encode_data(). Only bulk transfers are currently supported.
- *
- * uvc_video_encode_header is called at the start of a payload. It adds header
- * data to the transfer buffer and returns the header size. As the only known
- * UVC output device transfers a whole frame in a single payload, the EOF bit
- * is always set in the header.
- *
- * uvc_video_encode_data is called for every URB and copies the data from the
- * video buffer to the transfer buffer.
- */
-static int uvc_video_encode_header(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
-{
- data[0] = 2; /* Header length */
- data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
- | (stream->last_fid & UVC_STREAM_FID);
- return 2;
-}
-
-static int uvc_video_encode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
-{
- struct uvc_video_queue *queue = &stream->queue;
- unsigned int nbytes;
- void *mem;
-
- /* Copy video data to the URB buffer. */
- 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);
-
- queue->buf_used += nbytes;
-
- return nbytes;
-}
-
-/* ------------------------------------------------------------------------
- * URB handling
- */
-
-/*
- * Completion handler for video URBs.
- */
-static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem;
- int ret, i;
-
- for (i = 0; i < urb->number_of_packets; ++i) {
- if (urb->iso_frame_desc[i].status < 0) {
- uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
- "lost (%d).\n", urb->iso_frame_desc[i].status);
- /* Mark the buffer as faulty. */
- if (buf != NULL)
- buf->error = 1;
- continue;
- }
-
- /* Decode the payload header. */
- mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- do {
- ret = uvc_video_decode_start(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
- if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
-
- if (ret < 0)
- continue;
-
- /* Decode the payload data. */
- uvc_video_decode_data(stream, buf, mem + ret,
- urb->iso_frame_desc[i].actual_length - ret);
-
- /* Process the header again. */
- uvc_video_decode_end(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
-
- if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->length != buf->bytesused &&
- !(stream->cur_format->flags &
- UVC_FMT_FLAG_COMPRESSED))
- buf->error = 1;
-
- buf = uvc_queue_next_buffer(&stream->queue, buf);
- }
- }
-}
-
-static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem;
- int len, ret;
-
- /*
- * Ignore ZLPs if they're not part of a frame, otherwise process them
- * to trigger the end of payload detection.
- */
- if (urb->actual_length == 0 && stream->bulk.header_size == 0)
- return;
-
- mem = urb->transfer_buffer;
- len = urb->actual_length;
- stream->bulk.payload_size += len;
-
- /* If the URB is the first of its payload, decode and save the
- * header.
- */
- if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
- do {
- ret = uvc_video_decode_start(stream, buf, mem, len);
- if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
-
- /* If an error occurred skip the rest of the payload. */
- if (ret < 0 || buf == NULL) {
- stream->bulk.skip_payload = 1;
- } else {
- memcpy(stream->bulk.header, mem, ret);
- stream->bulk.header_size = ret;
-
- mem += ret;
- len -= ret;
- }
- }
-
- /* The buffer queue might have been cancelled while a bulk transfer
- * was in progress, so we can reach here with buf equal to NULL. Make
- * sure buf is never dereferenced if NULL.
- */
-
- /* Process video data. */
- if (!stream->bulk.skip_payload && buf != NULL)
- uvc_video_decode_data(stream, buf, mem, len);
-
- /* Detect the payload end by a URB smaller than the maximum size (or
- * a payload size equal to the maximum) and process the header again.
- */
- if (urb->actual_length < urb->transfer_buffer_length ||
- stream->bulk.payload_size >= stream->bulk.max_payload_size) {
- if (!stream->bulk.skip_payload && buf != NULL) {
- uvc_video_decode_end(stream, buf, stream->bulk.header,
- stream->bulk.payload_size);
- if (buf->state == UVC_BUF_STATE_READY)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- }
-
- stream->bulk.header_size = 0;
- stream->bulk.skip_payload = 0;
- stream->bulk.payload_size = 0;
- }
-}
-
-static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem = urb->transfer_buffer;
- int len = stream->urb_size, ret;
-
- if (buf == NULL) {
- urb->transfer_buffer_length = 0;
- return;
- }
-
- /* If the URB is the first of its payload, add the header. */
- if (stream->bulk.header_size == 0) {
- ret = uvc_video_encode_header(stream, buf, mem, len);
- stream->bulk.header_size = ret;
- stream->bulk.payload_size += ret;
- mem += ret;
- len -= ret;
- }
-
- /* Process video data. */
- ret = uvc_video_encode_data(stream, buf, mem, len);
-
- stream->bulk.payload_size += ret;
- len -= ret;
-
- if (buf->bytesused == stream->queue.buf_used ||
- stream->bulk.payload_size == stream->bulk.max_payload_size) {
- if (buf->bytesused == stream->queue.buf_used) {
- stream->queue.buf_used = 0;
- buf->state = UVC_BUF_STATE_READY;
- buf->buf.v4l2_buf.sequence = ++stream->sequence;
- uvc_queue_next_buffer(&stream->queue, buf);
- stream->last_fid ^= UVC_STREAM_FID;
- }
-
- stream->bulk.header_size = 0;
- stream->bulk.payload_size = 0;
- }
-
- urb->transfer_buffer_length = stream->urb_size - len;
-}
-
-static void uvc_video_complete(struct urb *urb)
-{
- struct uvc_streaming *stream = urb->context;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *buf = NULL;
- unsigned long flags;
- int ret;
-
- switch (urb->status) {
- case 0:
- break;
-
- default:
- uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
- "completion handler.\n", urb->status);
-
- case -ENOENT: /* usb_kill_urb() called. */
- if (stream->frozen)
- return;
-
- case -ECONNRESET: /* usb_unlink_urb() called. */
- case -ESHUTDOWN: /* The endpoint is being disabled. */
- uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
- return;
- }
-
- spin_lock_irqsave(&queue->irqlock, flags);
- if (!list_empty(&queue->irqqueue))
- buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
- stream->decode(urb, stream, buf);
-
- if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
- ret);
- }
-}
-
-/*
- * Free transfer buffers.
- */
-static void uvc_free_urb_buffers(struct uvc_streaming *stream)
-{
- unsigned int i;
-
- for (i = 0; i < UVC_URBS; ++i) {
- if (stream->urb_buffer[i]) {
-#ifndef CONFIG_DMA_NONCOHERENT
- usb_free_coherent(stream->dev->udev, stream->urb_size,
- stream->urb_buffer[i], stream->urb_dma[i]);
-#else
- kfree(stream->urb_buffer[i]);
-#endif
- stream->urb_buffer[i] = NULL;
- }
- }
-
- stream->urb_size = 0;
-}
-
-/*
- * Allocate transfer buffers. This function can be called with buffers
- * already allocated when resuming from suspend, in which case it will
- * return without touching the buffers.
- *
- * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
- * system is too low on memory try successively smaller numbers of packets
- * until allocation succeeds.
- *
- * Return the number of allocated packets on success or 0 when out of memory.
- */
-static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
- unsigned int size, unsigned int psize, gfp_t gfp_flags)
-{
- unsigned int npackets;
- unsigned int i;
-
- /* Buffers are already allocated, bail out. */
- if (stream->urb_size)
- return stream->urb_size / psize;
-
- /* Compute the number of packets. Bulk endpoints might transfer UVC
- * payloads across multiple URBs.
- */
- npackets = DIV_ROUND_UP(size, psize);
- if (npackets > UVC_MAX_PACKETS)
- npackets = UVC_MAX_PACKETS;
-
- /* Retry allocations until one succeed. */
- for (; npackets > 1; npackets /= 2) {
- for (i = 0; i < UVC_URBS; ++i) {
- stream->urb_size = psize * npackets;
-#ifndef CONFIG_DMA_NONCOHERENT
- stream->urb_buffer[i] = usb_alloc_coherent(
- stream->dev->udev, stream->urb_size,
- gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
-#else
- stream->urb_buffer[i] =
- kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
-#endif
- if (!stream->urb_buffer[i]) {
- uvc_free_urb_buffers(stream);
- break;
- }
- }
-
- if (i == UVC_URBS) {
- uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
- "of %ux%u bytes each.\n", UVC_URBS, npackets,
- psize);
- return npackets;
- }
- }
-
- uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes "
- "per packet).\n", psize);
- return 0;
-}
-
-/*
- * Uninitialize isochronous/bulk URBs and free transfer buffers.
- */
-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)
- continue;
-
- usb_kill_urb(urb);
- usb_free_urb(urb);
- stream->urb[i] = NULL;
- }
-
- if (free_buffers)
- uvc_free_urb_buffers(stream);
-}
-
-/*
- * Initialize isochronous URBs and allocate transfer buffers. The packet size
- * is given by the endpoint.
- */
-static int uvc_init_video_isoc(struct uvc_streaming *stream,
- struct usb_host_endpoint *ep, gfp_t gfp_flags)
-{
- struct urb *urb;
- unsigned int npackets, i, j;
- u16 psize;
- u32 size;
-
- psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- size = stream->ctrl.dwMaxVideoFrameSize;
-
- npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
- if (npackets == 0)
- return -ENOMEM;
-
- size = npackets * psize;
-
- for (i = 0; i < UVC_URBS; ++i) {
- urb = usb_alloc_urb(npackets, gfp_flags);
- if (urb == NULL) {
- uvc_uninit_video(stream, 1);
- return -ENOMEM;
- }
-
- urb->dev = stream->dev->udev;
- urb->context = stream;
- urb->pipe = usb_rcvisocpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
-#ifndef CONFIG_DMA_NONCOHERENT
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = stream->urb_dma[i];
-#else
- urb->transfer_flags = URB_ISO_ASAP;
-#endif
- urb->interval = ep->desc.bInterval;
- urb->transfer_buffer = stream->urb_buffer[i];
- urb->complete = uvc_video_complete;
- urb->number_of_packets = npackets;
- urb->transfer_buffer_length = size;
-
- for (j = 0; j < npackets; ++j) {
- urb->iso_frame_desc[j].offset = j * psize;
- urb->iso_frame_desc[j].length = psize;
- }
-
- stream->urb[i] = urb;
- }
-
- return 0;
-}
-
-/*
- * Initialize bulk URBs and allocate transfer buffers. The packet size is
- * given by the endpoint.
- */
-static int uvc_init_video_bulk(struct uvc_streaming *stream,
- struct usb_host_endpoint *ep, gfp_t gfp_flags)
-{
- struct urb *urb;
- unsigned int npackets, pipe, i;
- u16 psize;
- u32 size;
-
- psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
- size = stream->ctrl.dwMaxPayloadTransferSize;
- stream->bulk.max_payload_size = size;
-
- npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
- if (npackets == 0)
- return -ENOMEM;
-
- size = npackets * psize;
-
- if (usb_endpoint_dir_in(&ep->desc))
- pipe = usb_rcvbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
- else
- pipe = usb_sndbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
-
- if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- size = 0;
-
- for (i = 0; i < UVC_URBS; ++i) {
- urb = usb_alloc_urb(0, gfp_flags);
- if (urb == NULL) {
- uvc_uninit_video(stream, 1);
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
- stream->urb_buffer[i], size, uvc_video_complete,
- stream);
-#ifndef CONFIG_DMA_NONCOHERENT
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = stream->urb_dma[i];
-#endif
-
- stream->urb[i] = urb;
- }
-
- return 0;
-}
-
-/*
- * Initialize isochronous/bulk URBs and allocate transfer buffers.
- */
-static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
-{
- struct usb_interface *intf = stream->intf;
- struct usb_host_endpoint *ep;
- unsigned int i;
- int ret;
-
- stream->sequence = -1;
- stream->last_fid = -1;
- stream->bulk.header_size = 0;
- 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;
- unsigned int bandwidth;
- unsigned int uninitialized_var(altsetting);
- int intfnum = stream->intfnum;
-
- /* Isochronous endpoint, select the alternate setting. */
- bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
-
- if (bandwidth == 0) {
- uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
- "bandwidth, defaulting to lowest.\n");
- bandwidth = 1;
- } else {
- uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
- "B/frame bandwidth.\n", bandwidth);
- }
-
- for (i = 0; i < intf->num_altsetting; ++i) {
- struct usb_host_interface *alts;
- unsigned int psize;
-
- alts = &intf->altsetting[i];
- ep = uvc_find_endpoint(alts,
- stream->header.bEndpointAddress);
- if (ep == NULL)
- continue;
-
- /* Check if the bandwidth is high enough. */
- psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize >= bandwidth && psize <= best_psize) {
- altsetting = alts->desc.bAlternateSetting;
- best_psize = psize;
- best_ep = ep;
- }
- }
-
- if (best_ep == NULL) {
- uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
- "for requested bandwidth.\n");
- return -EIO;
- }
-
- uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
- "(%u B/frame bandwidth).\n", altsetting, best_psize);
-
- ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
- if (ret < 0)
- return ret;
-
- ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
- } else {
- /* Bulk endpoint, proceed to URB initialization. */
- ep = uvc_find_endpoint(&intf->altsetting[0],
- stream->header.bEndpointAddress);
- if (ep == NULL)
- return -EIO;
-
- ret = uvc_init_video_bulk(stream, ep, gfp_flags);
- }
-
- if (ret < 0)
- return ret;
-
- /* Submit the URBs. */
- for (i = 0; i < UVC_URBS; ++i) {
- ret = usb_submit_urb(stream->urb[i], gfp_flags);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to submit URB %u "
- "(%d).\n", i, ret);
- uvc_uninit_video(stream, 1);
- return ret;
- }
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * Suspend/resume
- */
-
-/*
- * Stop streaming without disabling the video queue.
- *
- * To let userspace applications resume without trouble, we must not touch the
- * video buffers in any way. We mark the device as frozen to make sure the URB
- * completion handler won't try to cancel the queue when we kill the URBs.
- */
-int uvc_video_suspend(struct uvc_streaming *stream)
-{
- if (!uvc_queue_streaming(&stream->queue))
- return 0;
-
- stream->frozen = 1;
- uvc_uninit_video(stream, 0);
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
- return 0;
-}
-
-/*
- * Reconfigure the video interface and restart streaming if it was enabled
- * before suspend.
- *
- * If an error occurs, disable the video queue. This will wake all pending
- * buffers, making sure userspace applications are notified of the problem
- * instead of waiting forever.
- */
-int uvc_video_resume(struct uvc_streaming *stream, int reset)
-{
- int ret;
-
- /* If the bus has been reset on resume, set the alternate setting to 0.
- * This should be the default value, but some devices crash or otherwise
- * misbehave if they don't receive a SET_INTERFACE request before any
- * other video control request.
- */
- if (reset)
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
-
- stream->frozen = 0;
-
- uvc_video_clock_reset(stream);
-
- ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0) {
- uvc_queue_enable(&stream->queue, 0);
- return ret;
- }
-
- if (!uvc_queue_streaming(&stream->queue))
- return 0;
-
- ret = uvc_init_video(stream, GFP_NOIO);
- if (ret < 0)
- uvc_queue_enable(&stream->queue, 0);
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------
- * Video device
- */
-
-/*
- * Initialize the UVC video device by switching to alternate setting 0 and
- * retrieve the default format.
- *
- * Some cameras (namely the Fuji Finepix) set the format and frame
- * indexes to zero. The UVC standard doesn't clearly make this a spec
- * violation, so try to silently fix the values if possible.
- *
- * This function is called before registering the device with V4L.
- */
-int uvc_video_init(struct uvc_streaming *stream)
-{
- struct uvc_streaming_control *probe = &stream->ctrl;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- unsigned int i;
- int ret;
-
- if (stream->nformats == 0) {
- uvc_printk(KERN_INFO, "No supported video formats found.\n");
- return -EINVAL;
- }
-
- atomic_set(&stream->active, 0);
-
- /* Initialize the video buffers queue. */
- uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
-
- /* Alternate setting 0 should be the default, yet the XBox Live Vision
- * Cam (and possibly other devices) crash or otherwise misbehave if
- * they don't receive a SET_INTERFACE request before any other video
- * control request.
- */
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
-
- /* Set the streaming probe control with default streaming parameters
- * retrieved from the device. Webcams that don't suport GET_DEF
- * requests on the probe control will just keep their current streaming
- * parameters.
- */
- if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
- uvc_set_video_ctrl(stream, probe, 1);
-
- /* Initialize the streaming parameters with the probe control current
- * value. This makes sure SET_CUR requests on the streaming commit
- * control will always use values retrieved from a successful GET_CUR
- * request on the probe control, as required by the UVC specification.
- */
- ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
- if (ret < 0)
- return ret;
-
- /* Check if the default format descriptor exists. Use the first
- * available format otherwise.
- */
- for (i = stream->nformats; i > 0; --i) {
- format = &stream->format[i-1];
- if (format->index == probe->bFormatIndex)
- break;
- }
-
- if (format->nframes == 0) {
- uvc_printk(KERN_INFO, "No frame descriptor found for the "
- "default format.\n");
- return -EINVAL;
- }
-
- /* Zero bFrameIndex might be correct. Stream-based formats (including
- * MPEG-2 TS and DV) do not support frames but have a dummy frame
- * descriptor with bFrameIndex set to zero. If the default frame
- * descriptor is not found, use the first available frame.
- */
- for (i = format->nframes; i > 0; --i) {
- frame = &format->frame[i-1];
- if (frame->bFrameIndex == probe->bFrameIndex)
- break;
- }
-
- probe->bFormatIndex = format->index;
- probe->bFrameIndex = frame->bFrameIndex;
-
- stream->cur_format = format;
- stream->cur_frame = frame;
-
- /* Select the video decoding function */
- if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
- stream->decode = uvc_video_decode_isight;
- else if (stream->intf->num_altsetting > 1)
- stream->decode = uvc_video_decode_isoc;
- else
- stream->decode = uvc_video_decode_bulk;
- } else {
- if (stream->intf->num_altsetting == 1)
- stream->decode = uvc_video_encode_bulk;
- else {
- uvc_printk(KERN_INFO, "Isochronous endpoints are not "
- "supported for video output devices.\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/*
- * Enable or disable the video stream.
- */
-int uvc_video_enable(struct uvc_streaming *stream, int enable)
-{
- int ret;
-
- if (!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_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)
- goto error_commit;
-
- 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
deleted file mode 100644
index 7c3d082505b7..000000000000
--- a/drivers/media/video/uvc/uvcvideo.h
+++ /dev/null
@@ -1,709 +0,0 @@
-#ifndef _USB_VIDEO_H_
-#define _USB_VIDEO_H_
-
-#ifndef __KERNEL__
-#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
-#endif /* __KERNEL__ */
-
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/usb.h>
-#include <linux/usb/video.h>
-#include <linux/uvcvideo.h>
-#include <linux/videodev2.h>
-#include <media/media-device.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-fh.h>
-#include <media/videobuf2-core.h>
-
-/* --------------------------------------------------------------------------
- * UVC constants
- */
-
-#define UVC_TERM_INPUT 0x0000
-#define UVC_TERM_OUTPUT 0x8000
-#define UVC_TERM_DIRECTION(term) ((term)->type & 0x8000)
-
-#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff)
-#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
-#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
-#define UVC_ENTITY_IS_ITERM(entity) \
- (UVC_ENTITY_IS_TERM(entity) && \
- ((entity)->type & 0x8000) == UVC_TERM_INPUT)
-#define UVC_ENTITY_IS_OTERM(entity) \
- (UVC_ENTITY_IS_TERM(entity) && \
- ((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
-
-
-/* ------------------------------------------------------------------------
- * GUIDs
- */
-#define UVC_GUID_UVC_CAMERA \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
-#define UVC_GUID_UVC_OUTPUT \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
-#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
-#define UVC_GUID_UVC_PROCESSING \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
-#define UVC_GUID_UVC_SELECTOR \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-
-#define UVC_GUID_FORMAT_MJPEG \
- { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2 \
- { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2_ISIGHT \
- { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_NV12 \
- { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YV12 \
- { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_I420 \
- { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_UYVY \
- { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y800 \
- { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y16 \
- { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BY8 \
- { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGBP \
- { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_M420 \
- { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_H264 \
- { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-/* ------------------------------------------------------------------------
- * Driver specific constants.
- */
-
-#define DRIVER_VERSION "1.1.1"
-
-/* Number of isochronous URBs. */
-#define UVC_URBS 5
-/* Maximum number of packets per URB. */
-#define UVC_MAX_PACKETS 32
-/* Maximum number of video buffers. */
-#define UVC_MAX_VIDEO_BUFFERS 32
-/* Maximum status buffer size in bytes of interrupt URB. */
-#define UVC_MAX_STATUS_SIZE 16
-
-#define UVC_CTRL_CONTROL_TIMEOUT 300
-#define UVC_CTRL_STREAMING_TIMEOUT 5000
-
-/* 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
-#define UVC_QUIRK_PROBE_MINMAX 0x00000002
-#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004
-#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
-#define UVC_QUIRK_STREAM_NO_FID 0x00000010
-#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
-#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
-#define UVC_QUIRK_PROBE_DEF 0x00000100
-#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
-
-/* Format flags */
-#define UVC_FMT_FLAG_COMPRESSED 0x00000001
-#define UVC_FMT_FLAG_STREAM 0x00000002
-
-/* ------------------------------------------------------------------------
- * Structures.
- */
-
-struct uvc_device;
-
-/* TODO: Put the most frequently accessed fields at the beginning of
- * structures to maximize cache efficiency.
- */
-struct uvc_control_info {
- struct list_head mappings;
-
- __u8 entity[16];
- __u8 index; /* Bit index in bmControls */
- __u8 selector;
-
- __u16 size;
- __u32 flags;
-};
-
-struct uvc_control_mapping {
- struct list_head list;
- struct list_head ev_subs;
-
- __u32 id;
- __u8 name[32];
- __u8 entity[16];
- __u8 selector;
-
- __u8 size;
- __u8 offset;
- enum v4l2_ctrl_type v4l2_type;
- __u32 data_type;
-
- struct uvc_menu_info *menu_info;
- __u32 menu_count;
-
- __u32 master_id;
- __s32 master_manual;
- __u32 slave_ids[2];
-
- __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
- const __u8 *data);
- void (*set) (struct uvc_control_mapping *mapping, __s32 value,
- __u8 *data);
-};
-
-struct uvc_control {
- struct uvc_entity *entity;
- struct uvc_control_info info;
-
- __u8 index; /* Used to match the uvc_control entry with a
- uvc_control_info. */
- __u8 dirty:1,
- loaded:1,
- modified:1,
- cached:1,
- initialized:1;
-
- __u8 *uvc_data;
-};
-
-struct uvc_format_desc {
- char *name;
- __u8 guid[16];
- __u32 fcc;
-};
-
-/* The term 'entity' refers to both UVC units and UVC terminals.
- *
- * The type field is either the terminal type (wTerminalType in the terminal
- * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
- * As the bDescriptorSubtype field is one byte long, the type value will
- * always have a null MSB for units. All terminal types defined by the UVC
- * specification have a non-null MSB, so it is safe to use the MSB to
- * differentiate between units and terminals as long as the descriptor parsing
- * code makes sure terminal types have a non-null MSB.
- *
- * For terminals, the type's most significant bit stores the terminal
- * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
- * always be accessed with the UVC_ENTITY_* macros and never directly.
- */
-
-struct uvc_entity {
- struct list_head list; /* Entity as part of a UVC device. */
- struct list_head chain; /* Entity as part of a video device
- * chain. */
- __u8 id;
- __u16 type;
- char name[64];
-
- /* Media controller-related fields. */
- struct video_device *vdev;
- struct v4l2_subdev subdev;
- unsigned int num_pads;
- unsigned int num_links;
- struct media_pad *pads;
-
- union {
- struct {
- __u16 wObjectiveFocalLengthMin;
- __u16 wObjectiveFocalLengthMax;
- __u16 wOcularFocalLength;
- __u8 bControlSize;
- __u8 *bmControls;
- } camera;
-
- struct {
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bTransportModeSize;
- __u8 *bmTransportModes;
- } media;
-
- struct {
- } output;
-
- struct {
- __u16 wMaxMultiplier;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bmVideoStandards;
- } processing;
-
- struct {
- } selector;
-
- struct {
- __u8 guidExtensionCode[16];
- __u8 bNumControls;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 *bmControlsType;
- } extension;
- };
-
- __u8 bNrInPins;
- __u8 *baSourceID;
-
- unsigned int ncontrols;
- struct uvc_control *controls;
-};
-
-struct uvc_frame {
- __u8 bFrameIndex;
- __u8 bmCapabilities;
- __u16 wWidth;
- __u16 wHeight;
- __u32 dwMinBitRate;
- __u32 dwMaxBitRate;
- __u32 dwMaxVideoFrameBufferSize;
- __u8 bFrameIntervalType;
- __u32 dwDefaultFrameInterval;
- __u32 *dwFrameInterval;
-};
-
-struct uvc_format {
- __u8 type;
- __u8 index;
- __u8 bpp;
- __u8 colorspace;
- __u32 fcc;
- __u32 flags;
-
- char name[32];
-
- unsigned int nframes;
- struct uvc_frame *frame;
-};
-
-struct uvc_streaming_header {
- __u8 bNumFormats;
- __u8 bEndpointAddress;
- __u8 bTerminalLink;
- __u8 bControlSize;
- __u8 *bmaControls;
- /* The following fields are used by input headers only. */
- __u8 bmInfo;
- __u8 bStillCaptureMethod;
- __u8 bTriggerSupport;
- __u8 bTriggerUsage;
-};
-
-enum uvc_buffer_state {
- UVC_BUF_STATE_IDLE = 0,
- UVC_BUF_STATE_QUEUED = 1,
- UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_READY = 3,
- UVC_BUF_STATE_DONE = 4,
- UVC_BUF_STATE_ERROR = 5,
-};
-
-struct uvc_buffer {
- struct vb2_buffer buf;
- struct list_head queue;
-
- enum uvc_buffer_state state;
- unsigned int error;
-
- void *mem;
- unsigned int length;
- unsigned int bytesused;
-
- u32 pts;
-};
-
-#define UVC_QUEUE_DISCONNECTED (1 << 0)
-#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
-
-struct uvc_video_queue {
- struct vb2_queue queue;
- struct mutex mutex; /* Protects queue */
-
- unsigned int flags;
- unsigned int buf_used;
-
- spinlock_t irqlock; /* Protects irqqueue */
- struct list_head irqqueue;
-};
-
-struct uvc_video_chain {
- struct uvc_device *dev;
- struct list_head list;
-
- struct list_head entities; /* All entities */
- struct uvc_entity *processing; /* Processing unit */
- struct uvc_entity *selector; /* Selector unit */
-
- 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;
- struct video_device *vdev;
- struct uvc_video_chain *chain;
- atomic_t active;
-
- struct usb_interface *intf;
- int intfnum;
- __u16 maxpsize;
-
- struct uvc_streaming_header header;
- enum v4l2_buf_type type;
-
- unsigned int nformats;
- struct uvc_format *format;
-
- struct uvc_streaming_control ctrl;
- struct uvc_format *cur_format;
- struct uvc_frame *cur_frame;
- /* Protect access to ctrl, cur_format, cur_frame and hardware video
- * probe control.
- */
- struct mutex mutex;
-
- /* Buffers queue. */
- unsigned int frozen : 1;
- struct uvc_video_queue queue;
- void (*decode) (struct urb *urb, struct uvc_streaming *video,
- struct uvc_buffer *buf);
-
- /* Context data used by the bulk completion handler. */
- struct {
- __u8 header[256];
- unsigned int header_size;
- int skip_payload;
- __u32 payload_size;
- __u32 max_payload_size;
- } bulk;
-
- struct urb *urb[UVC_URBS];
- char *urb_buffer[UVC_URBS];
- dma_addr_t urb_dma[UVC_URBS];
- unsigned int urb_size;
-
- __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 {
- UVC_DEV_DISCONNECTED = 1,
-};
-
-struct uvc_device {
- struct usb_device *udev;
- struct usb_interface *intf;
- unsigned long warnings;
- __u32 quirks;
- int intfnum;
- char name[32];
-
- enum uvc_device_state state;
- atomic_t users;
- atomic_t nmappings;
-
- /* Video control interface */
-#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_device mdev;
-#endif
- struct v4l2_device vdev;
- __u16 uvc_version;
- __u32 clock_frequency;
-
- struct list_head entities;
- struct list_head chains;
-
- /* Video Streaming interfaces */
- struct list_head streams;
- atomic_t nstreams;
-
- /* Status Interrupt Endpoint */
- struct usb_host_endpoint *int_ep;
- struct urb *int_urb;
- __u8 *status;
- struct input_dev *input;
- char input_phys[64];
-};
-
-enum uvc_handle_state {
- UVC_HANDLE_PASSIVE = 0,
- UVC_HANDLE_ACTIVE = 1,
-};
-
-struct uvc_fh {
- struct v4l2_fh vfh;
- struct uvc_video_chain *chain;
- struct uvc_streaming *stream;
- enum uvc_handle_state state;
-};
-
-struct uvc_driver {
- struct usb_driver driver;
-};
-
-/* ------------------------------------------------------------------------
- * Debugging, printing and logging
- */
-
-#define UVC_TRACE_PROBE (1 << 0)
-#define UVC_TRACE_DESCR (1 << 1)
-#define UVC_TRACE_CONTROL (1 << 2)
-#define UVC_TRACE_FORMAT (1 << 3)
-#define UVC_TRACE_CAPTURE (1 << 4)
-#define UVC_TRACE_CALLS (1 << 5)
-#define UVC_TRACE_IOCTL (1 << 6)
-#define UVC_TRACE_FRAME (1 << 7)
-#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;
-extern unsigned int uvc_trace_param;
-extern unsigned int uvc_timeout_param;
-
-#define uvc_trace(flag, msg...) \
- do { \
- if (uvc_trace_param & flag) \
- printk(KERN_DEBUG "uvcvideo: " msg); \
- } while (0)
-
-#define uvc_warn_once(dev, warn, msg...) \
- do { \
- if (!test_and_set_bit(warn, &dev->warnings)) \
- printk(KERN_INFO "uvcvideo: " msg); \
- } while (0)
-
-#define uvc_printk(level, msg...) \
- printk(level "uvcvideo: " msg)
-
-/* --------------------------------------------------------------------------
- * Internal functions.
- */
-
-/* Core driver */
-extern struct uvc_driver uvc_driver;
-
-extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
-
-/* Video buffers queue management. */
-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,
- 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,
- struct v4l2_buffer *v4l2_buf);
-extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf, int nonblocking);
-extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
-extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
-extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
- struct uvc_buffer *buf);
-extern int uvc_queue_mmap(struct uvc_video_queue *queue,
- struct vm_area_struct *vma);
-extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
- struct file *file, poll_table *wait);
-#ifndef CONFIG_MMU
-extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
- unsigned long pgoff);
-#endif
-extern int uvc_queue_allocated(struct uvc_video_queue *queue);
-static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
-{
- return vb2_is_streaming(&queue->queue);
-}
-
-/* V4L2 interface */
-extern const struct v4l2_file_operations uvc_fops;
-
-/* Media controller */
-extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
-extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
-
-/* Video */
-extern int uvc_video_init(struct uvc_streaming *stream);
-extern int uvc_video_suspend(struct uvc_streaming *stream);
-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_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);
-extern void uvc_status_cleanup(struct uvc_device *dev);
-extern int uvc_status_start(struct uvc_device *dev);
-extern void uvc_status_stop(struct uvc_device *dev);
-extern int uvc_status_suspend(struct uvc_device *dev);
-extern int uvc_status_resume(struct uvc_device *dev);
-
-/* Controls */
-extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
-
-extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl);
-extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu);
-
-extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
- const struct uvc_control_mapping *mapping);
-extern int uvc_ctrl_init_device(struct uvc_device *dev);
-extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_resume_device(struct uvc_device *dev);
-
-extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
-extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count);
-static inline int uvc_ctrl_commit(struct uvc_fh *handle,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count)
-{
- return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
-}
-static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
-{
- return __uvc_ctrl_commit(handle, 1, NULL, 0);
-}
-
-extern int uvc_ctrl_get(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
-extern int uvc_ctrl_set(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
-
-extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control_query *xqry);
-
-/* Utility functions */
-extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
- unsigned int n_terms, unsigned int threshold);
-extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
- uint32_t denominator);
-extern struct usb_host_endpoint *uvc_find_endpoint(
- struct usb_host_interface *alts, __u8 epaddr);
-
-/* Quirks support */
-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
deleted file mode 100644
index 1baec8393306..000000000000
--- a/drivers/media/video/v4l2-common.c
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * Video for Linux Two
- *
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
- *
- * This file replaces the videodev.c file that comes with the
- * regular kernel distribution.
- *
- * 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.
- *
- * Author: Bill Dirks <bill@thedirks.org>
- * based on code by Alan Cox, <alan@cymru.net>
- *
- */
-
-/*
- * Video capture interface for Linux
- *
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
- *
- * 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.
- *
- * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk>
- *
- * Fixes:
- */
-
-/*
- * Video4linux 1/2 integration by Justin Schoeman
- * <justin@suntiger.ee.up.ac.za>
- * 2.4 PROCFS support ported from 2.4 kernels by
- * Iñaki García Etxebarria <garetxe@euskalnet.net>
- * Makefile fix by "W. Michael Petullo" <mike@flyn.org>
- * 2.4 devfs support ported from 2.4 kernels by
- * Dan Merillat <dan@merillat.org>
- * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#if defined(CONFIG_SPI)
-#include <linux/spi/spi.h>
-#endif
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/div64.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
-
-#include <linux/videodev2.h>
-
-MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr");
-MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers");
-MODULE_LICENSE("GPL");
-
-/*
- *
- * V 4 L 2 D R I V E R H E L P E R A P I
- *
- */
-
-/*
- * Video Standard Operations (contributed by Michael Schimek)
- */
-
-/* Helper functions for control handling */
-
-/* Check for correctness of the ctrl's value based on the data from
- struct v4l2_queryctrl and the available menu items. Note that
- menu_items may be NULL, in that case it is ignored. */
-int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
- const char * const *menu_items)
-{
- if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
- return -EBUSY;
- if (qctrl->type == V4L2_CTRL_TYPE_STRING)
- return 0;
- if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
- qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
- qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- return 0;
- if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
- return -ERANGE;
- if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
- if (menu_items[ctrl->value] == NULL ||
- menu_items[ctrl->value][0] == '\0')
- return -EINVAL;
- }
- if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
- (ctrl->value & ~qctrl->maximum))
- return -ERANGE;
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_check);
-
-/* Fill in a struct v4l2_queryctrl */
-int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
-{
- const char *name;
-
- v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
- &min, &max, &step, &def, &qctrl->flags);
-
- if (name == NULL)
- return -EINVAL;
-
- qctrl->minimum = min;
- qctrl->maximum = max;
- qctrl->step = step;
- qctrl->default_value = def;
- qctrl->reserved[0] = qctrl->reserved[1] = 0;
- strlcpy(qctrl->name, name, sizeof(qctrl->name));
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_fill);
-
-/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
- the menu. The qctrl pointer may be NULL, in which case it is ignored.
- If menu_items is NULL, then the menu items are retrieved using
- v4l2_ctrl_get_menu. */
-int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
- const char * const *menu_items)
-{
- int i;
-
- qmenu->reserved = 0;
- if (menu_items == NULL)
- menu_items = v4l2_ctrl_get_menu(qmenu->id);
- if (menu_items == NULL ||
- (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
- return -EINVAL;
- for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
- if (menu_items[i] == NULL || menu_items[i][0] == '\0')
- return -EINVAL;
- strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name));
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_menu);
-
-/* Fill in a struct v4l2_querymenu based on the specified array of valid
- menu items (terminated by V4L2_CTRL_MENU_IDS_END).
- Use this if there are 'holes' in the list of valid menu items. */
-int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
-{
- const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
-
- qmenu->reserved = 0;
- if (menu_items == NULL || ids == NULL)
- return -EINVAL;
- while (*ids != V4L2_CTRL_MENU_IDS_END) {
- if (*ids++ == qmenu->index) {
- strlcpy(qmenu->name, menu_items[qmenu->index],
- sizeof(qmenu->name));
- return 0;
- }
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
-
-/* ctrl_classes points to an array of u32 pointers, the last element is
- a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
- Each array must be sorted low to high and belong to the same control
- class. The array of u32 pointers must also be sorted, from low class IDs
- to high class IDs.
-
- This function returns the first ID that follows after the given ID.
- When no more controls are available 0 is returned. */
-u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
-{
- u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
- const u32 *pctrl;
-
- if (ctrl_classes == NULL)
- return 0;
-
- /* if no query is desired, then check if the ID is part of ctrl_classes */
- if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
- /* find class */
- while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
- ctrl_classes++;
- if (*ctrl_classes == NULL)
- return 0;
- pctrl = *ctrl_classes;
- /* find control ID */
- while (*pctrl && *pctrl != id) pctrl++;
- return *pctrl ? id : 0;
- }
- id &= V4L2_CTRL_ID_MASK;
- id++; /* select next control */
- /* find first class that matches (or is greater than) the class of
- the ID */
- while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
- ctrl_classes++;
- /* no more classes */
- if (*ctrl_classes == NULL)
- return 0;
- pctrl = *ctrl_classes;
- /* find first ctrl within the class that is >= ID */
- while (*pctrl && *pctrl < id) pctrl++;
- if (*pctrl)
- return *pctrl;
- /* we are at the end of the controls of the current class. */
- /* continue with next class if available */
- ctrl_classes++;
- if (*ctrl_classes == NULL)
- return 0;
- return **ctrl_classes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_next);
-
-int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
-{
- switch (match->type) {
- case V4L2_CHIP_MATCH_HOST:
- return match->addr == 0;
- default:
- return 0;
- }
-}
-EXPORT_SYMBOL(v4l2_chip_match_host);
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
-{
- int len;
-
- if (c == NULL || match == NULL)
- return 0;
-
- switch (match->type) {
- case V4L2_CHIP_MATCH_I2C_DRIVER:
- if (c->driver == NULL || c->driver->driver.name == NULL)
- return 0;
- len = strlen(c->driver->driver.name);
- /* legacy drivers have a ' suffix, don't try to match that */
- if (len && c->driver->driver.name[len - 1] == '\'')
- len--;
- return len && !strncmp(c->driver->driver.name, match->name, len);
- case V4L2_CHIP_MATCH_I2C_ADDR:
- return c->addr == match->addr;
- default:
- return 0;
- }
-}
-EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
-
-int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
- u32 ident, u32 revision)
-{
- if (!v4l2_chip_match_i2c_client(c, &chip->match))
- return 0;
- if (chip->ident == V4L2_IDENT_NONE) {
- chip->ident = ident;
- chip->revision = revision;
- }
- else {
- chip->ident = V4L2_IDENT_AMBIGUOUS;
- chip->revision = 0;
- }
- return 0;
-}
-EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
-
-/* ----------------------------------------------------------------- */
-
-/* I2C Helper functions */
-
-
-void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
- const struct v4l2_subdev_ops *ops)
-{
- v4l2_subdev_init(sd, ops);
- sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
- /* the owner is the same as the i2c_client's driver owner */
- sd->owner = client->driver->driver.owner;
- /* i2c_client and v4l2_subdev point to one another */
- v4l2_set_subdevdata(sd, client);
- i2c_set_clientdata(client, sd);
- /* initialize name */
- snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
- client->driver->driver.name, i2c_adapter_id(client->adapter),
- client->addr);
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
-
-
-
-/* Load an i2c sub-device. */
-struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, struct i2c_board_info *info,
- const unsigned short *probe_addrs)
-{
- struct v4l2_subdev *sd = NULL;
- struct i2c_client *client;
-
- BUG_ON(!v4l2_dev);
-
- request_module(I2C_MODULE_PREFIX "%s", info->type);
-
- /* Create the i2c client */
- if (info->addr == 0 && probe_addrs)
- client = i2c_new_probed_device(adapter, info, probe_addrs,
- NULL);
- else
- client = i2c_new_device(adapter, info);
-
- /* Note: by loading the module first we are certain that c->driver
- will be set if the driver was found. If the module was not loaded
- first, then the i2c core tries to delay-load the module for us,
- and then c->driver is still NULL until the module is finally
- loaded. This delay-load mechanism doesn't work if other drivers
- want to use the i2c device, so explicitly loading the module
- is the best alternative. */
- if (client == NULL || client->driver == NULL)
- goto error;
-
- /* Lock the module so we can safely get the v4l2_subdev pointer */
- if (!try_module_get(client->driver->driver.owner))
- goto error;
- sd = i2c_get_clientdata(client);
-
- /* Register with the v4l2_device which increases the module's
- use count as well. */
- if (v4l2_device_register_subdev(v4l2_dev, sd))
- sd = NULL;
- /* Decrease the module use count to match the first try_module_get. */
- module_put(client->driver->driver.owner);
-
-error:
- /* If we have a client but no subdev, then something went wrong and
- we must unregister the client. */
- if (client && sd == NULL)
- i2c_unregister_device(client);
- return sd;
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
-
-struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *client_type,
- u8 addr, const unsigned short *probe_addrs)
-{
- struct i2c_board_info info;
-
- /* Setup the i2c board info with the device type and
- the device address. */
- memset(&info, 0, sizeof(info));
- strlcpy(info.type, client_type, sizeof(info.type));
- info.addr = addr;
-
- return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
-
-/* Return i2c client address of v4l2_subdev. */
-unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- return client ? client->addr : I2C_CLIENT_END;
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
-
-/* Return a list of I2C tuner addresses to probe. Use only if the tuner
- addresses are unknown. */
-const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
-{
- static const unsigned short radio_addrs[] = {
-#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
- 0x10,
-#endif
- 0x60,
- I2C_CLIENT_END
- };
- static const unsigned short demod_addrs[] = {
- 0x42, 0x43, 0x4a, 0x4b,
- I2C_CLIENT_END
- };
- static const unsigned short tv_addrs[] = {
- 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
- 0x60, 0x61, 0x62, 0x63, 0x64,
- I2C_CLIENT_END
- };
-
- switch (type) {
- case ADDRS_RADIO:
- return radio_addrs;
- case ADDRS_DEMOD:
- return demod_addrs;
- case ADDRS_TV:
- return tv_addrs;
- case ADDRS_TV_WITH_DEMOD:
- return tv_addrs + 4;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
-
-#endif /* defined(CONFIG_I2C) */
-
-#if defined(CONFIG_SPI)
-
-/* Load a spi sub-device. */
-
-void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
- const struct v4l2_subdev_ops *ops)
-{
- v4l2_subdev_init(sd, ops);
- sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
- /* the owner is the same as the spi_device's driver owner */
- sd->owner = spi->dev.driver->owner;
- /* spi_device and v4l2_subdev point to one another */
- v4l2_set_subdevdata(sd, spi);
- spi_set_drvdata(spi, sd);
- /* initialize name */
- strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name));
-}
-EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
-
-struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
- struct spi_master *master, struct spi_board_info *info)
-{
- struct v4l2_subdev *sd = NULL;
- struct spi_device *spi = NULL;
-
- BUG_ON(!v4l2_dev);
-
- if (info->modalias)
- request_module(info->modalias);
-
- spi = spi_new_device(master, info);
-
- if (spi == NULL || spi->dev.driver == NULL)
- goto error;
-
- if (!try_module_get(spi->dev.driver->owner))
- goto error;
-
- sd = spi_get_drvdata(spi);
-
- /* Register with the v4l2_device which increases the module's
- use count as well. */
- if (v4l2_device_register_subdev(v4l2_dev, sd))
- sd = NULL;
-
- /* Decrease the module use count to match the first try_module_get. */
- module_put(spi->dev.driver->owner);
-
-error:
- /* If we have a client but no subdev, then something went wrong and
- we must unregister the client. */
- if (spi && sd == NULL)
- spi_unregister_device(spi);
-
- return sd;
-}
-EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev);
-
-#endif /* defined(CONFIG_SPI) */
-
-/* Clamp x to be between min and max, aligned to a multiple of 2^align. min
- * and max don't have to be aligned, but there must be at least one valid
- * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples
- * of 16 between 17 and 31. */
-static unsigned int clamp_align(unsigned int x, unsigned int min,
- unsigned int max, unsigned int align)
-{
- /* Bits that must be zero to be aligned */
- unsigned int mask = ~((1 << align) - 1);
-
- /* Round to nearest aligned value */
- if (align)
- x = (x + (1 << (align - 1))) & mask;
-
- /* Clamp to aligned value of min and max */
- if (x < min)
- x = (min + ~mask) & mask;
- else if (x > max)
- x = max & mask;
-
- return x;
-}
-
-/* Bound an image to have a width between wmin and wmax, and height between
- * hmin and hmax, inclusive. Additionally, the width will be a multiple of
- * 2^walign, the height will be a multiple of 2^halign, and the overall size
- * (width*height) will be a multiple of 2^salign. The image may be shrunk
- * or enlarged to fit the alignment constraints.
- *
- * The width or height maximum must not be smaller than the corresponding
- * minimum. The alignments must not be so high there are no possible image
- * sizes within the allowed bounds. wmin and hmin must be at least 1
- * (don't use 0). If you don't care about a certain alignment, specify 0,
- * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If
- * you only want to adjust downward, specify a maximum that's the same as
- * the initial value.
- */
-void v4l_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, unsigned int salign)
-{
- *w = clamp_align(*w, wmin, wmax, walign);
- *h = clamp_align(*h, hmin, hmax, halign);
-
- /* Usually we don't need to align the size and are done now. */
- if (!salign)
- return;
-
- /* How much alignment do we have? */
- walign = __ffs(*w);
- halign = __ffs(*h);
- /* Enough to satisfy the image alignment? */
- if (walign + halign < salign) {
- /* Max walign where there is still a valid width */
- unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
- /* Max halign where there is still a valid height */
- unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
-
- /* up the smaller alignment until we have enough */
- do {
- if (halign >= hmaxa ||
- (walign <= halign && walign < wmaxa)) {
- *w = clamp_align(*w, wmin, wmax, walign + 1);
- walign = __ffs(*w);
- } else {
- *h = clamp_align(*h, hmin, hmax, halign + 1);
- halign = __ffs(*h);
- }
- } while (halign + walign < salign);
- }
-}
-EXPORT_SYMBOL_GPL(v4l_bound_align_image);
-
-/**
- * v4l_fill_dv_preset_info - fill description of a digital video preset
- * @preset - preset value
- * @info - pointer to struct v4l2_dv_enum_preset
- *
- * drivers can use this helper function to fill description of dv preset
- * in info.
- */
-int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
-{
- static const struct v4l2_dv_preset_info {
- u16 width;
- u16 height;
- const char *name;
- } dv_presets[] = {
- { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */
- { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */
- { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */
- { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */
- { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */
- { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */
- { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */
- { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */
- { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */
- { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */
- { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */
- { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */
- { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */
- { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */
- { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */
- { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */
- { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */
- { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */
- { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */
- };
-
- if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
- return -EINVAL;
-
- info->preset = preset;
- info->width = dv_presets[preset].width;
- info->height = dv_presets[preset].height;
- strlcpy(info->name, dv_presets[preset].name, sizeof(info->name));
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
-
-const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
- const struct v4l2_discrete_probe *probe,
- s32 width, s32 height)
-{
- int i;
- u32 error, min_error = UINT_MAX;
- const struct v4l2_frmsize_discrete *size, *best = NULL;
-
- if (!probe)
- return best;
-
- for (i = 0, size = probe->sizes; i < probe->num_sizes; i++, size++) {
- error = abs(size->width - width) + abs(size->height - height);
- if (error < min_error) {
- min_error = error;
- best = size;
- }
- if (!error)
- break;
- }
-
- return best;
-}
-EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
deleted file mode 100644
index 07aeafca9eaa..000000000000
--- a/drivers/media/video/v4l2-dev.c
+++ /dev/null
@@ -1,1038 +0,0 @@
-/*
- * Video capture interface for Linux version 2
- *
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
- *
- * 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.
- *
- * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
- * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
- *
- * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
- * - Added procfs support
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-#define VIDEO_NUM_DEVICES 256
-#define VIDEO_NAME "video4linux"
-
-/*
- * sysfs stuff
- */
-
-static ssize_t show_index(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(cd);
-
- return sprintf(buf, "%i\n", vdev->index);
-}
-
-static ssize_t show_debug(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(cd);
-
- return sprintf(buf, "%i\n", vdev->debug);
-}
-
-static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct video_device *vdev = to_video_device(cd);
- int res = 0;
- u16 value;
-
- res = kstrtou16(buf, 0, &value);
- if (res)
- return res;
-
- vdev->debug = value;
- return len;
-}
-
-static ssize_t show_name(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(cd);
-
- return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
-}
-
-static struct device_attribute video_device_attrs[] = {
- __ATTR(name, S_IRUGO, show_name, NULL),
- __ATTR(debug, 0644, show_debug, set_debug),
- __ATTR(index, S_IRUGO, show_index, NULL),
- __ATTR_NULL
-};
-
-/*
- * Active devices
- */
-static struct video_device *video_device[VIDEO_NUM_DEVICES];
-static DEFINE_MUTEX(videodev_lock);
-static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
-
-/* Device node utility functions */
-
-/* Note: these utility functions all assume that vfl_type is in the range
- [0, VFL_TYPE_MAX-1]. */
-
-#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
-/* Return the bitmap corresponding to vfl_type. */
-static inline unsigned long *devnode_bits(int vfl_type)
-{
- /* Any types not assigned to fixed minor ranges must be mapped to
- one single bitmap for the purposes of finding a free node number
- since all those unassigned types use the same minor range. */
- int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type;
-
- return devnode_nums[idx];
-}
-#else
-/* Return the bitmap corresponding to vfl_type. */
-static inline unsigned long *devnode_bits(int vfl_type)
-{
- return devnode_nums[vfl_type];
-}
-#endif
-
-/* Mark device node number vdev->num as used */
-static inline void devnode_set(struct video_device *vdev)
-{
- set_bit(vdev->num, devnode_bits(vdev->vfl_type));
-}
-
-/* Mark device node number vdev->num as unused */
-static inline void devnode_clear(struct video_device *vdev)
-{
- clear_bit(vdev->num, devnode_bits(vdev->vfl_type));
-}
-
-/* Try to find a free device node number in the range [from, to> */
-static inline int devnode_find(struct video_device *vdev, int from, int to)
-{
- return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from);
-}
-
-struct video_device *video_device_alloc(void)
-{
- return kzalloc(sizeof(struct video_device), GFP_KERNEL);
-}
-EXPORT_SYMBOL(video_device_alloc);
-
-void video_device_release(struct video_device *vdev)
-{
- kfree(vdev);
-}
-EXPORT_SYMBOL(video_device_release);
-
-void video_device_release_empty(struct video_device *vdev)
-{
- /* Do nothing */
- /* Only valid when the video_device struct is a static. */
-}
-EXPORT_SYMBOL(video_device_release_empty);
-
-static inline void video_get(struct video_device *vdev)
-{
- get_device(&vdev->dev);
-}
-
-static inline void video_put(struct video_device *vdev)
-{
- put_device(&vdev->dev);
-}
-
-/* Called when the last user of the video device exits. */
-static void v4l2_device_release(struct device *cd)
-{
- struct video_device *vdev = to_video_device(cd);
- struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
-
- mutex_lock(&videodev_lock);
- if (WARN_ON(video_device[vdev->minor] != vdev)) {
- /* should not happen */
- mutex_unlock(&videodev_lock);
- return;
- }
-
- /* Free up this device for reuse */
- video_device[vdev->minor] = NULL;
-
- /* Delete the cdev on this minor as well */
- cdev_del(vdev->cdev);
- /* Just in case some driver tries to access this from
- the release() callback. */
- vdev->cdev = NULL;
-
- /* Mark device node number as free */
- devnode_clear(vdev);
-
- mutex_unlock(&videodev_lock);
-
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (v4l2_dev && v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV)
- media_device_unregister_entity(&vdev->entity);
-#endif
-
- /* Do not call v4l2_device_put if there is no release callback set.
- * Drivers that have no v4l2_device release callback might free the
- * v4l2_dev instance in the video_device release callback below, so we
- * must perform this check here.
- *
- * TODO: In the long run all drivers that use v4l2_device should use the
- * v4l2_device release callback. This check will then be unnecessary.
- */
- if (v4l2_dev && v4l2_dev->release == NULL)
- v4l2_dev = NULL;
-
- /* Release video_device and perform other
- cleanups as needed. */
- vdev->release(vdev);
-
- /* Decrease v4l2_device refcount */
- if (v4l2_dev)
- v4l2_device_put(v4l2_dev);
-}
-
-static struct class video_class = {
- .name = VIDEO_NAME,
- .dev_attrs = video_device_attrs,
-};
-
-struct video_device *video_devdata(struct file *file)
-{
- return video_device[iminor(file->f_path.dentry->d_inode)];
-}
-EXPORT_SYMBOL(video_devdata);
-
-
-/* Priority handling */
-
-static inline bool prio_is_valid(enum v4l2_priority prio)
-{
- return prio == V4L2_PRIORITY_BACKGROUND ||
- prio == V4L2_PRIORITY_INTERACTIVE ||
- prio == V4L2_PRIORITY_RECORD;
-}
-
-void v4l2_prio_init(struct v4l2_prio_state *global)
-{
- memset(global, 0, sizeof(*global));
-}
-EXPORT_SYMBOL(v4l2_prio_init);
-
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
- enum v4l2_priority new)
-{
- if (!prio_is_valid(new))
- return -EINVAL;
- if (*local == new)
- return 0;
-
- atomic_inc(&global->prios[new]);
- if (prio_is_valid(*local))
- atomic_dec(&global->prios[*local]);
- *local = new;
- return 0;
-}
-EXPORT_SYMBOL(v4l2_prio_change);
-
-void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
-{
- v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
-}
-EXPORT_SYMBOL(v4l2_prio_open);
-
-void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
-{
- if (prio_is_valid(local))
- atomic_dec(&global->prios[local]);
-}
-EXPORT_SYMBOL(v4l2_prio_close);
-
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
-{
- if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0)
- return V4L2_PRIORITY_RECORD;
- if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0)
- return V4L2_PRIORITY_INTERACTIVE;
- if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0)
- return V4L2_PRIORITY_BACKGROUND;
- return V4L2_PRIORITY_UNSET;
-}
-EXPORT_SYMBOL(v4l2_prio_max);
-
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
-{
- return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
-}
-EXPORT_SYMBOL(v4l2_prio_check);
-
-
-static ssize_t v4l2_read(struct file *filp, char __user *buf,
- size_t sz, loff_t *off)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = -ENODEV;
-
- if (!vdev->fops->read)
- return -EINVAL;
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
- mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->read(filp, buf, sz, off);
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- if (vdev->debug)
- printk(KERN_DEBUG "%s: read: %zd (%d)\n",
- video_device_node_name(vdev), sz, ret);
- return ret;
-}
-
-static ssize_t v4l2_write(struct file *filp, const char __user *buf,
- size_t sz, loff_t *off)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = -ENODEV;
-
- if (!vdev->fops->write)
- return -EINVAL;
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
- mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->write(filp, buf, sz, off);
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- if (vdev->debug)
- printk(KERN_DEBUG "%s: write: %zd (%d)\n",
- video_device_node_name(vdev), sz, ret);
- return ret;
-}
-
-static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = POLLERR | POLLHUP;
-
- if (!vdev->fops->poll)
- return DEFAULT_POLLMASK;
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_lock(vdev->lock);
- if (video_is_registered(vdev))
- ret = vdev->fops->poll(filp, poll);
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- if (vdev->debug)
- printk(KERN_DEBUG "%s: poll: %08x\n",
- video_device_node_name(vdev), ret);
- return ret;
-}
-
-static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = -ENODEV;
-
- if (vdev->fops->unlocked_ioctl) {
- struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd);
-
- if (lock && mutex_lock_interruptible(lock))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
- if (lock)
- mutex_unlock(lock);
- } else if (vdev->fops->ioctl) {
- /* This code path is a replacement for the BKL. It is a major
- * hack but it will have to do for those drivers that are not
- * yet converted to use unlocked_ioctl.
- *
- * There are two options: if the driver implements struct
- * v4l2_device, then the lock defined there is used to
- * serialize the ioctls. Otherwise the v4l2 core lock defined
- * below is used. This lock is really bad since it serializes
- * completely independent devices.
- *
- * Both variants suffer from the same problem: if the driver
- * sleeps, then it blocks all ioctls since the lock is still
- * held. This is very common for VIDIOC_DQBUF since that
- * normally waits for a frame to arrive. As a result any other
- * ioctl calls will proceed very, very slowly since each call
- * will have to wait for the VIDIOC_QBUF to finish. Things that
- * should take 0.01s may now take 10-20 seconds.
- *
- * The workaround is to *not* take the lock for VIDIOC_DQBUF.
- * This actually works OK for videobuf-based drivers, since
- * videobuf will take its own internal lock.
- */
- static DEFINE_MUTEX(v4l2_ioctl_mutex);
- struct mutex *m = vdev->v4l2_dev ?
- &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
-
- if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->ioctl(filp, cmd, arg);
- if (cmd != VIDIOC_DQBUF)
- mutex_unlock(m);
- } else
- ret = -ENOTTY;
-
- return ret;
-}
-
-#ifdef CONFIG_MMU
-#define v4l2_get_unmapped_area NULL
-#else
-static unsigned long v4l2_get_unmapped_area(struct file *filp,
- unsigned long addr, unsigned long len, unsigned long pgoff,
- unsigned long flags)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret;
-
- if (!vdev->fops->get_unmapped_area)
- return -ENOSYS;
- if (!video_is_registered(vdev))
- return -ENODEV;
- ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
- if (vdev->debug)
- printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n",
- video_device_node_name(vdev), ret);
- return ret;
-}
-#endif
-
-static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = -ENODEV;
-
- if (!vdev->fops->mmap)
- return ret;
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
- mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = vdev->fops->mmap(filp, vm);
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- if (vdev->debug)
- printk(KERN_DEBUG "%s: mmap (%d)\n",
- video_device_node_name(vdev), ret);
- return ret;
-}
-
-/* Override for the open function */
-static int v4l2_open(struct inode *inode, struct file *filp)
-{
- struct video_device *vdev;
- int ret = 0;
-
- /* Check if the video device is available */
- mutex_lock(&videodev_lock);
- vdev = video_devdata(filp);
- /* return ENODEV if the video device has already been removed. */
- if (vdev == NULL || !video_is_registered(vdev)) {
- mutex_unlock(&videodev_lock);
- return -ENODEV;
- }
- /* and increase the device refcount */
- video_get(vdev);
- mutex_unlock(&videodev_lock);
- if (vdev->fops->open) {
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
- mutex_lock_interruptible(vdev->lock)) {
- ret = -ERESTARTSYS;
- goto err;
- }
- if (video_is_registered(vdev))
- ret = vdev->fops->open(filp);
- else
- ret = -ENODEV;
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- }
-
-err:
- if (vdev->debug)
- printk(KERN_DEBUG "%s: open (%d)\n",
- video_device_node_name(vdev), ret);
- /* decrease the refcount in case of an error */
- if (ret)
- video_put(vdev);
- return ret;
-}
-
-/* Override for the release function */
-static int v4l2_release(struct inode *inode, struct file *filp)
-{
- struct video_device *vdev = video_devdata(filp);
- int ret = 0;
-
- if (vdev->fops->release) {
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_lock(vdev->lock);
- vdev->fops->release(filp);
- if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
- mutex_unlock(vdev->lock);
- }
- if (vdev->debug)
- printk(KERN_DEBUG "%s: release\n",
- video_device_node_name(vdev));
- /* decrease the refcount unconditionally since the release()
- return value is ignored. */
- video_put(vdev);
- return ret;
-}
-
-static const struct file_operations v4l2_fops = {
- .owner = THIS_MODULE,
- .read = v4l2_read,
- .write = v4l2_write,
- .open = v4l2_open,
- .get_unmapped_area = v4l2_get_unmapped_area,
- .mmap = v4l2_mmap,
- .unlocked_ioctl = v4l2_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l2_compat_ioctl32,
-#endif
- .release = v4l2_release,
- .poll = v4l2_poll,
- .llseek = no_llseek,
-};
-
-/**
- * get_index - assign stream index number based on parent device
- * @vdev: video_device to assign index number to, vdev->parent should be assigned
- *
- * Note that when this is called the new device has not yet been registered
- * in the video_device array, but it was able to obtain a minor number.
- *
- * This means that we can always obtain a free stream index number since
- * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
- * use of the video_device array.
- *
- * Returns a free index number.
- */
-static int get_index(struct video_device *vdev)
-{
- /* This can be static since this function is called with the global
- videodev_lock held. */
- static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
- int i;
-
- /* Some drivers do not set the parent. In that case always return 0. */
- if (vdev->parent == NULL)
- return 0;
-
- bitmap_zero(used, VIDEO_NUM_DEVICES);
-
- for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
- if (video_device[i] != NULL &&
- video_device[i]->parent == vdev->parent) {
- set_bit(video_device[i]->index, used);
- }
- }
-
- return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
-}
-
-#define SET_VALID_IOCTL(ops, cmd, op) \
- if (ops->op) \
- set_bit(_IOC_NR(cmd), valid_ioctls)
-
-/* This determines which ioctls are actually implemented in the driver.
- It's a one-time thing which simplifies video_ioctl2 as it can just do
- a bit test.
-
- Note that drivers can override this by setting bits to 1 in
- vdev->valid_ioctls. If an ioctl is marked as 1 when this function is
- called, then that ioctl will actually be marked as unimplemented.
-
- It does that by first setting up the local valid_ioctls bitmap, and
- at the end do a:
-
- vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls)
- */
-static void determine_valid_ioctls(struct video_device *vdev)
-{
- DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
- const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
-
- bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
-
- SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
- if (ops->vidioc_g_priority ||
- test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
- set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
- if (ops->vidioc_s_priority ||
- test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
- set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
- if (ops->vidioc_enum_fmt_vid_cap ||
- ops->vidioc_enum_fmt_vid_out ||
- ops->vidioc_enum_fmt_vid_cap_mplane ||
- ops->vidioc_enum_fmt_vid_out_mplane ||
- ops->vidioc_enum_fmt_vid_overlay ||
- ops->vidioc_enum_fmt_type_private)
- set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
- if (ops->vidioc_g_fmt_vid_cap ||
- ops->vidioc_g_fmt_vid_out ||
- ops->vidioc_g_fmt_vid_cap_mplane ||
- ops->vidioc_g_fmt_vid_out_mplane ||
- ops->vidioc_g_fmt_vid_overlay ||
- ops->vidioc_g_fmt_vbi_cap ||
- ops->vidioc_g_fmt_vid_out_overlay ||
- ops->vidioc_g_fmt_vbi_out ||
- ops->vidioc_g_fmt_sliced_vbi_cap ||
- ops->vidioc_g_fmt_sliced_vbi_out ||
- ops->vidioc_g_fmt_type_private)
- set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
- if (ops->vidioc_s_fmt_vid_cap ||
- ops->vidioc_s_fmt_vid_out ||
- ops->vidioc_s_fmt_vid_cap_mplane ||
- ops->vidioc_s_fmt_vid_out_mplane ||
- ops->vidioc_s_fmt_vid_overlay ||
- ops->vidioc_s_fmt_vbi_cap ||
- ops->vidioc_s_fmt_vid_out_overlay ||
- ops->vidioc_s_fmt_vbi_out ||
- ops->vidioc_s_fmt_sliced_vbi_cap ||
- ops->vidioc_s_fmt_sliced_vbi_out ||
- ops->vidioc_s_fmt_type_private)
- set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
- if (ops->vidioc_try_fmt_vid_cap ||
- ops->vidioc_try_fmt_vid_out ||
- ops->vidioc_try_fmt_vid_cap_mplane ||
- ops->vidioc_try_fmt_vid_out_mplane ||
- ops->vidioc_try_fmt_vid_overlay ||
- ops->vidioc_try_fmt_vbi_cap ||
- ops->vidioc_try_fmt_vid_out_overlay ||
- ops->vidioc_try_fmt_vbi_out ||
- ops->vidioc_try_fmt_sliced_vbi_cap ||
- ops->vidioc_try_fmt_sliced_vbi_out ||
- ops->vidioc_try_fmt_type_private)
- set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
- SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
- SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
- SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
- SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
- SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
- SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf);
- SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
- SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
- if (vdev->tvnorms)
- set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
- if (ops->vidioc_g_std || vdev->current_norm)
- set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
- SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
- SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
- SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
- SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
- SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
- SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
- SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
- /* Note: the control handler can also be passed through the filehandle,
- and that can't be tested here. If the bit for these control ioctls
- is set, then the ioctl is valid. But if it is 0, then it can still
- be valid if the filehandle passed the control handler. */
- if (vdev->ctrl_handler || ops->vidioc_queryctrl)
- set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
- set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
- set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
- set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
- set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls)
- set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
- if (vdev->ctrl_handler || ops->vidioc_querymenu)
- set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
- SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
- SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
- SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout);
- SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
- SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
- SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
- SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
- if (ops->vidioc_g_crop || ops->vidioc_g_selection)
- set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
- if (ops->vidioc_s_crop || ops->vidioc_s_selection)
- set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
- SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
- if (ops->vidioc_cropcap || ops->vidioc_g_selection)
- set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp);
- SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp);
- SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index);
- SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd);
- SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
- SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
- SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
- if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
- (ops->vidioc_g_std || vdev->tvnorms)))
- set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
- SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
- SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
- SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
- SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
- SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
- SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register);
- SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register);
-#endif
- SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
- SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
- SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
- SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
- SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets);
- SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset);
- SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset);
- SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
- SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
- SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
- SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
- SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
- SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap);
- /* yes, really vidioc_subscribe_event */
- SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
- SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
- SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
- SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
- SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
- if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
- set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
- bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
- BASE_VIDIOC_PRIVATE);
-}
-
-/**
- * __video_register_device - register video4linux devices
- * @vdev: video device structure we want to register
- * @type: type of device to register
- * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
- * -1 == first free)
- * @warn_if_nr_in_use: warn if the desired device node number
- * was already in use and another number was chosen instead.
- * @owner: module that owns the video device node
- *
- * The registration code assigns minor numbers and device node numbers
- * based on the requested type and registers the new device node with
- * the kernel.
- *
- * This function assumes that struct video_device was zeroed when it
- * was allocated and does not contain any stale date.
- *
- * An error is returned if no free minor or device node number could be
- * found, or if the registration of the device node failed.
- *
- * Zero is returned on success.
- *
- * Valid types are
- *
- * %VFL_TYPE_GRABBER - A frame grabber
- *
- * %VFL_TYPE_VBI - Vertical blank data (undecoded)
- *
- * %VFL_TYPE_RADIO - A radio card
- *
- * %VFL_TYPE_SUBDEV - A subdevice
- */
-int __video_register_device(struct video_device *vdev, int type, int nr,
- int warn_if_nr_in_use, struct module *owner)
-{
- int i = 0;
- int ret;
- int minor_offset = 0;
- int minor_cnt = VIDEO_NUM_DEVICES;
- const char *name_base;
-
- /* A minor value of -1 marks this video device as never
- having been registered */
- vdev->minor = -1;
-
- /* the release callback MUST be present */
- if (WARN_ON(!vdev->release))
- return -EINVAL;
-
- /* v4l2_fh support */
- spin_lock_init(&vdev->fh_lock);
- INIT_LIST_HEAD(&vdev->fh_list);
-
- /* Part 1: check device type */
- switch (type) {
- case VFL_TYPE_GRABBER:
- name_base = "video";
- break;
- case VFL_TYPE_VBI:
- name_base = "vbi";
- break;
- case VFL_TYPE_RADIO:
- name_base = "radio";
- break;
- case VFL_TYPE_SUBDEV:
- name_base = "v4l-subdev";
- break;
- default:
- printk(KERN_ERR "%s called with unknown type: %d\n",
- __func__, type);
- return -EINVAL;
- }
-
- vdev->vfl_type = type;
- vdev->cdev = NULL;
- if (vdev->v4l2_dev) {
- if (vdev->v4l2_dev->dev)
- vdev->parent = vdev->v4l2_dev->dev;
- if (vdev->ctrl_handler == NULL)
- vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
- /* If the prio state pointer is NULL, then use the v4l2_device
- prio state. */
- if (vdev->prio == NULL)
- vdev->prio = &vdev->v4l2_dev->prio;
- }
-
- /* Part 2: find a free minor, device node number and device index. */
-#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
- /* Keep the ranges for the first four types for historical
- * reasons.
- * Newer devices (not yet in place) should use the range
- * of 128-191 and just pick the first free minor there
- * (new style). */
- switch (type) {
- case VFL_TYPE_GRABBER:
- minor_offset = 0;
- minor_cnt = 64;
- break;
- case VFL_TYPE_RADIO:
- minor_offset = 64;
- minor_cnt = 64;
- break;
- case VFL_TYPE_VBI:
- minor_offset = 224;
- minor_cnt = 32;
- break;
- default:
- minor_offset = 128;
- minor_cnt = 64;
- break;
- }
-#endif
-
- /* Pick a device node number */
- mutex_lock(&videodev_lock);
- nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
- if (nr == minor_cnt)
- nr = devnode_find(vdev, 0, minor_cnt);
- if (nr == minor_cnt) {
- printk(KERN_ERR "could not get a free device node number\n");
- mutex_unlock(&videodev_lock);
- return -ENFILE;
- }
-#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
- /* 1-on-1 mapping of device node number to minor number */
- i = nr;
-#else
- /* The device node number and minor numbers are independent, so
- we just find the first free minor number. */
- for (i = 0; i < VIDEO_NUM_DEVICES; i++)
- if (video_device[i] == NULL)
- break;
- if (i == VIDEO_NUM_DEVICES) {
- mutex_unlock(&videodev_lock);
- printk(KERN_ERR "could not get a free minor\n");
- return -ENFILE;
- }
-#endif
- vdev->minor = i + minor_offset;
- vdev->num = nr;
- devnode_set(vdev);
-
- /* Should not happen since we thought this minor was free */
- WARN_ON(video_device[vdev->minor] != NULL);
- vdev->index = get_index(vdev);
- mutex_unlock(&videodev_lock);
- /* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
- clear and warn if it wasn't. */
- if (vdev->lock == NULL)
- WARN_ON(test_and_clear_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags));
-
- if (vdev->ioctl_ops)
- determine_valid_ioctls(vdev);
-
- /* Part 3: Initialize the character device */
- vdev->cdev = cdev_alloc();
- if (vdev->cdev == NULL) {
- ret = -ENOMEM;
- goto cleanup;
- }
- vdev->cdev->ops = &v4l2_fops;
- vdev->cdev->owner = owner;
- ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
- if (ret < 0) {
- printk(KERN_ERR "%s: cdev_add failed\n", __func__);
- kfree(vdev->cdev);
- vdev->cdev = NULL;
- goto cleanup;
- }
-
- /* Part 4: register the device with sysfs */
- vdev->dev.class = &video_class;
- vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
- if (vdev->parent)
- vdev->dev.parent = vdev->parent;
- dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
- ret = device_register(&vdev->dev);
- if (ret < 0) {
- printk(KERN_ERR "%s: device_register failed\n", __func__);
- goto cleanup;
- }
- /* Register the release callback that will be called when the last
- reference to the device goes away. */
- vdev->dev.release = v4l2_device_release;
-
- if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
- printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
- name_base, nr, video_device_node_name(vdev));
-
- /* Increase v4l2_device refcount */
- if (vdev->v4l2_dev)
- v4l2_device_get(vdev->v4l2_dev);
-
-#if defined(CONFIG_MEDIA_CONTROLLER)
- /* Part 5: Register the entity. */
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV) {
- vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
- vdev->entity.name = vdev->name;
- 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)
- printk(KERN_WARNING
- "%s: media_device_register_entity failed\n",
- __func__);
- }
-#endif
- /* Part 6: Activate this minor. The char device can now be used. */
- set_bit(V4L2_FL_REGISTERED, &vdev->flags);
- mutex_lock(&videodev_lock);
- video_device[vdev->minor] = vdev;
- mutex_unlock(&videodev_lock);
-
- return 0;
-
-cleanup:
- mutex_lock(&videodev_lock);
- if (vdev->cdev)
- cdev_del(vdev->cdev);
- devnode_clear(vdev);
- mutex_unlock(&videodev_lock);
- /* Mark this video device as never having been registered. */
- vdev->minor = -1;
- return ret;
-}
-EXPORT_SYMBOL(__video_register_device);
-
-/**
- * video_unregister_device - unregister a video4linux device
- * @vdev: the device to unregister
- *
- * This unregisters the passed device. Future open calls will
- * be met with errors.
- */
-void video_unregister_device(struct video_device *vdev)
-{
- /* Check if vdev was ever registered at all */
- if (!vdev || !video_is_registered(vdev))
- return;
-
- mutex_lock(&videodev_lock);
- /* This must be in a critical section to prevent a race with v4l2_open.
- * Once this bit has been cleared video_get may never be called again.
- */
- clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
- mutex_unlock(&videodev_lock);
- device_unregister(&vdev->dev);
-}
-EXPORT_SYMBOL(video_unregister_device);
-
-/*
- * Initialise video for linux
- */
-static int __init videodev_init(void)
-{
- dev_t dev = MKDEV(VIDEO_MAJOR, 0);
- int ret;
-
- printk(KERN_INFO "Linux video capture interface: v2.00\n");
- ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
- if (ret < 0) {
- printk(KERN_WARNING "videodev: unable to get major %d\n",
- VIDEO_MAJOR);
- return ret;
- }
-
- ret = class_register(&video_class);
- if (ret < 0) {
- unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
- printk(KERN_WARNING "video_dev: class_register failed\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static void __exit videodev_exit(void)
-{
- dev_t dev = MKDEV(VIDEO_MAJOR, 0);
-
- class_unregister(&video_class);
- unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
-}
-
-subsys_initcall(videodev_init);
-module_exit(videodev_exit)
-
-MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
deleted file mode 100644
index 94d83a41381b..000000000000
--- a/drivers/media/video/videobuf-dvb.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- *
- * some helper function for simple DVB cards which simply DMA the
- * complete transport stream and let the computer sort everything else
- * (i.e. we are using the software demux, ...). Also uses the
- * video-buf to manage DMA buffers.
- *
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
- *
- * 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/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/kthread.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-
-#include <linux/freezer.h>
-
-#include <media/videobuf-core.h>
-#include <media/videobuf-dvb.h>
-
-/* ------------------------------------------------------------------ */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
-
-#define dprintk(fmt, arg...) if (debug) \
- printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg)
-
-/* ------------------------------------------------------------------ */
-
-static int videobuf_dvb_thread(void *data)
-{
- struct videobuf_dvb *dvb = data;
- struct videobuf_buffer *buf;
- unsigned long flags;
- void *outp;
-
- dprintk("dvb thread started\n");
- set_freezable();
- videobuf_read_start(&dvb->dvbq);
-
- for (;;) {
- /* fetch next buffer */
- buf = list_entry(dvb->dvbq.stream.next,
- struct videobuf_buffer, stream);
- list_del(&buf->stream);
- videobuf_waiton(&dvb->dvbq, buf, 0, 1);
-
- /* no more feeds left or stop_feed() asked us to quit */
- if (0 == dvb->nfeeds)
- break;
- if (kthread_should_stop())
- break;
- try_to_freeze();
-
- /* feed buffer data to demux */
- outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf);
-
- if (buf->state == VIDEOBUF_DONE)
- dvb_dmx_swfilter(&dvb->demux, outp,
- buf->size);
-
- /* requeue buffer */
- list_add_tail(&buf->stream,&dvb->dvbq.stream);
- spin_lock_irqsave(dvb->dvbq.irqlock,flags);
- dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf);
- spin_unlock_irqrestore(dvb->dvbq.irqlock,flags);
- }
-
- videobuf_read_stop(&dvb->dvbq);
- dprintk("dvb thread stopped\n");
-
- /* Hmm, linux becomes *very* unhappy without this ... */
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- return 0;
-}
-
-static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct videobuf_dvb *dvb = demux->priv;
- int rc;
-
- if (!demux->dmx.frontend)
- return -EINVAL;
-
- mutex_lock(&dvb->lock);
- dvb->nfeeds++;
- rc = dvb->nfeeds;
-
- if (NULL != dvb->thread)
- goto out;
- dvb->thread = kthread_run(videobuf_dvb_thread,
- dvb, "%s dvb", dvb->name);
- if (IS_ERR(dvb->thread)) {
- rc = PTR_ERR(dvb->thread);
- dvb->thread = NULL;
- }
-
-out:
- mutex_unlock(&dvb->lock);
- return rc;
-}
-
-static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct videobuf_dvb *dvb = demux->priv;
- int err = 0;
-
- mutex_lock(&dvb->lock);
- dvb->nfeeds--;
- if (0 == dvb->nfeeds && NULL != dvb->thread) {
- err = kthread_stop(dvb->thread);
- dvb->thread = NULL;
- }
- mutex_unlock(&dvb->lock);
- return err;
-}
-
-static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
- struct module *module,
- void *adapter_priv,
- struct device *device,
- char *adapter_name,
- short *adapter_nr,
- int mfe_shared,
- int (*fe_ioctl_override)(struct dvb_frontend *,
- unsigned int, void *, unsigned int))
-{
- int result;
-
- mutex_init(&fe->lock);
-
- /* register adapter */
- result = dvb_register_adapter(&fe->adapter, adapter_name, module,
- device, adapter_nr);
- if (result < 0) {
- printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
- adapter_name, result);
- }
- fe->adapter.priv = adapter_priv;
- fe->adapter.mfe_shared = mfe_shared;
- fe->adapter.fe_ioctl_override = fe_ioctl_override;
-
- return result;
-}
-
-static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
- struct videobuf_dvb *dvb)
-{
- int result;
-
- /* register frontend */
- result = dvb_register_frontend(adapter, dvb->frontend);
- if (result < 0) {
- printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
- dvb->name, result);
- goto fail_frontend;
- }
-
- /* register demux stuff */
- dvb->demux.dmx.capabilities =
- DMX_TS_FILTERING | DMX_SECTION_FILTERING |
- DMX_MEMORY_BASED_FILTERING;
- dvb->demux.priv = dvb;
- dvb->demux.filternum = 256;
- dvb->demux.feednum = 256;
- dvb->demux.start_feed = videobuf_dvb_start_feed;
- dvb->demux.stop_feed = videobuf_dvb_stop_feed;
- result = dvb_dmx_init(&dvb->demux);
- if (result < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
- dvb->name, result);
- goto fail_dmx;
- }
-
- dvb->dmxdev.filternum = 256;
- dvb->dmxdev.demux = &dvb->demux.dmx;
- dvb->dmxdev.capabilities = 0;
- result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
-
- if (result < 0) {
- printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
- dvb->name, result);
- goto fail_dmxdev;
- }
-
- dvb->fe_hw.source = DMX_FRONTEND_0;
- result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- if (result < 0) {
- printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
- dvb->name, result);
- goto fail_fe_hw;
- }
-
- dvb->fe_mem.source = DMX_MEMORY_FE;
- result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
- if (result < 0) {
- printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
- dvb->name, result);
- goto fail_fe_mem;
- }
-
- result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
- if (result < 0) {
- printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
- dvb->name, result);
- goto fail_fe_conn;
- }
-
- /* register network adapter */
- 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;
-
-fail_fe_conn:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
-fail_fe_mem:
- dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
-fail_fe_hw:
- dvb_dmxdev_release(&dvb->dmxdev);
-fail_dmxdev:
- dvb_dmx_release(&dvb->demux);
-fail_dmx:
- dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
- dvb_frontend_detach(dvb->frontend);
- dvb->frontend = NULL;
-
- return result;
-}
-
-/* ------------------------------------------------------------------ */
-/* Register a single adapter and one or more frontends */
-int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
- struct module *module,
- void *adapter_priv,
- struct device *device,
- short *adapter_nr,
- int mfe_shared,
- int (*fe_ioctl_override)(struct dvb_frontend *,
- unsigned int, void *, unsigned int))
-{
- struct list_head *list, *q;
- struct videobuf_dvb_frontend *fe;
- int res;
-
- fe = videobuf_dvb_get_frontend(f, 1);
- if (!fe) {
- printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
- return -EINVAL;
- }
-
- /* Bring up the adapter */
- res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
- fe->dvb.name, adapter_nr, mfe_shared, fe_ioctl_override);
- if (res < 0) {
- printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
- return res;
- }
-
- /* Attach all of the frontends to the adapter */
- mutex_lock(&f->lock);
- list_for_each_safe(list, q, &f->felist) {
- fe = list_entry(list, struct videobuf_dvb_frontend, felist);
- res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb);
- if (res < 0) {
- printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
- fe->dvb.name, res);
- goto err;
- }
- }
- mutex_unlock(&f->lock);
- return 0;
-
-err:
- mutex_unlock(&f->lock);
- videobuf_dvb_unregister_bus(f);
- return res;
-}
-EXPORT_SYMBOL(videobuf_dvb_register_bus);
-
-void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
-{
- videobuf_dvb_dealloc_frontends(f);
-
- dvb_unregister_adapter(&f->adapter);
-}
-EXPORT_SYMBOL(videobuf_dvb_unregister_bus);
-
-struct videobuf_dvb_frontend *videobuf_dvb_get_frontend(
- struct videobuf_dvb_frontends *f, int id)
-{
- struct list_head *list, *q;
- struct videobuf_dvb_frontend *fe, *ret = NULL;
-
- mutex_lock(&f->lock);
-
- list_for_each_safe(list, q, &f->felist) {
- fe = list_entry(list, struct videobuf_dvb_frontend, felist);
- if (fe->id == id) {
- ret = fe;
- break;
- }
- }
-
- mutex_unlock(&f->lock);
-
- return ret;
-}
-EXPORT_SYMBOL(videobuf_dvb_get_frontend);
-
-int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f,
- struct dvb_frontend *p)
-{
- struct list_head *list, *q;
- struct videobuf_dvb_frontend *fe = NULL;
- int ret = 0;
-
- mutex_lock(&f->lock);
-
- list_for_each_safe(list, q, &f->felist) {
- fe = list_entry(list, struct videobuf_dvb_frontend, felist);
- if (fe->dvb.frontend == p) {
- ret = fe->id;
- break;
- }
- }
-
- mutex_unlock(&f->lock);
-
- return ret;
-}
-EXPORT_SYMBOL(videobuf_dvb_find_frontend);
-
-struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend(
- struct videobuf_dvb_frontends *f, int id)
-{
- struct videobuf_dvb_frontend *fe;
-
- fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL);
- if (fe == NULL)
- goto fail_alloc;
-
- fe->id = id;
- mutex_init(&fe->dvb.lock);
-
- mutex_lock(&f->lock);
- list_add_tail(&fe->felist, &f->felist);
- mutex_unlock(&f->lock);
-
-fail_alloc:
- return fe;
-}
-EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
-
-void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f)
-{
- struct list_head *list, *q;
- struct videobuf_dvb_frontend *fe;
-
- mutex_lock(&f->lock);
- list_for_each_safe(list, q, &f->felist) {
- fe = list_entry(list, struct videobuf_dvb_frontend, felist);
- if (fe->dvb.net.dvbdev) {
- dvb_net_release(&fe->dvb.net);
- fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
- &fe->dvb.fe_mem);
- fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
- &fe->dvb.fe_hw);
- dvb_dmxdev_release(&fe->dvb.dmxdev);
- dvb_dmx_release(&fe->dvb.demux);
- dvb_unregister_frontend(fe->dvb.frontend);
- }
- if (fe->dvb.frontend)
- /* always allocated, may have been reset */
- dvb_frontend_detach(fe->dvb.frontend);
- list_del(list); /* remove list entry */
- kfree(fe); /* free frontend allocation */
- }
- mutex_unlock(&f->lock);
-}
-EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends);
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
deleted file mode 100644
index 268c7dd4f823..000000000000
--- a/drivers/media/video/videobuf2-core.c
+++ /dev/null
@@ -1,2387 +0,0 @@
-/*
- * videobuf2-core.c - V4L2 driver helper framework
- *
- * Copyright (C) 2010 Samsung Electronics
- *
- * Author: Pawel Osciak <pawel@osciak.com>
- * Marek Szyprowski <m.szyprowski@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.
- */
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-#include <media/v4l2-dev.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-core.h>
-
-static int debug;
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "vb2: " fmt, ## arg); \
- } while (0)
-
-#define call_memop(q, op, args...) \
- (((q)->mem_ops->op) ? \
- ((q)->mem_ops->op(args)) : 0)
-
-#define call_qop(q, op, args...) \
- (((q)->ops->op) ? ((q)->ops->op(args)) : 0)
-
-#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
- V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
- V4L2_BUF_FLAG_PREPARED)
-
-/**
- * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
- */
-static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
-{
- struct vb2_queue *q = vb->vb2_queue;
- void *mem_priv;
- int plane;
-
- /* Allocate memory for all planes in this buffer */
- for (plane = 0; plane < vb->num_planes; ++plane) {
- mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
- q->plane_sizes[plane]);
- if (IS_ERR_OR_NULL(mem_priv))
- goto free;
-
- /* Associate allocator private data with this plane */
- vb->planes[plane].mem_priv = mem_priv;
- vb->v4l2_planes[plane].length = q->plane_sizes[plane];
- }
-
- return 0;
-free:
- /* Free already allocated memory if one of the allocations failed */
- for (; plane > 0; --plane) {
- call_memop(q, put, vb->planes[plane - 1].mem_priv);
- vb->planes[plane - 1].mem_priv = NULL;
- }
-
- return -ENOMEM;
-}
-
-/**
- * __vb2_buf_mem_free() - free memory of the given buffer
- */
-static void __vb2_buf_mem_free(struct vb2_buffer *vb)
-{
- struct vb2_queue *q = vb->vb2_queue;
- unsigned int plane;
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- 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);
- }
-}
-
-/**
- * __vb2_buf_userptr_put() - release userspace memory associated with
- * a USERPTR buffer
- */
-static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
-{
- struct vb2_queue *q = vb->vb2_queue;
- unsigned int plane;
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- if (vb->planes[plane].mem_priv)
- call_memop(q, put_userptr, vb->planes[plane].mem_priv);
- vb->planes[plane].mem_priv = NULL;
- }
-}
-
-/**
- * __setup_offsets() - setup unique offsets ("cookies") for every plane in
- * every buffer on the queue
- */
-static void __setup_offsets(struct vb2_queue *q, unsigned int n)
-{
- unsigned int buffer, plane;
- struct vb2_buffer *vb;
- unsigned long off;
-
- if (q->num_buffers) {
- struct v4l2_plane *p;
- vb = q->bufs[q->num_buffers - 1];
- p = &vb->v4l2_planes[vb->num_planes - 1];
- off = PAGE_ALIGN(p->m.mem_offset + p->length);
- } else {
- off = 0;
- }
-
- for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
- vb = q->bufs[buffer];
- if (!vb)
- continue;
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->v4l2_planes[plane].length = q->plane_sizes[plane];
- vb->v4l2_planes[plane].m.mem_offset = off;
-
- dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
- buffer, plane, off);
-
- off += vb->v4l2_planes[plane].length;
- off = PAGE_ALIGN(off);
- }
- }
-}
-
-/**
- * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
- * video buffer memory for all buffers/planes on the queue and initializes the
- * queue
- *
- * Returns the number of buffers successfully allocated.
- */
-static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
- unsigned int num_buffers, unsigned int num_planes)
-{
- unsigned int buffer;
- struct vb2_buffer *vb;
- int ret;
-
- for (buffer = 0; buffer < num_buffers; ++buffer) {
- /* Allocate videobuf buffer structures */
- vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
- if (!vb) {
- dprintk(1, "Memory alloc for buffer struct failed\n");
- break;
- }
-
- /* Length stores number of planes for multiplanar buffers */
- if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
- vb->v4l2_buf.length = num_planes;
-
- vb->state = VB2_BUF_STATE_DEQUEUED;
- vb->vb2_queue = q;
- vb->num_planes = num_planes;
- vb->v4l2_buf.index = q->num_buffers + buffer;
- vb->v4l2_buf.type = q->type;
- vb->v4l2_buf.memory = memory;
-
- /* Allocate video buffer memory for the MMAP type */
- if (memory == V4L2_MEMORY_MMAP) {
- ret = __vb2_buf_mem_alloc(vb);
- if (ret) {
- dprintk(1, "Failed allocating memory for "
- "buffer %d\n", buffer);
- kfree(vb);
- break;
- }
- /*
- * Call the driver-provided buffer initialization
- * callback, if given. An error in initialization
- * results in queue setup failure.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "Buffer %d %p initialization"
- " failed\n", buffer, vb);
- __vb2_buf_mem_free(vb);
- kfree(vb);
- break;
- }
- }
-
- q->bufs[q->num_buffers + buffer] = vb;
- }
-
- __setup_offsets(q, buffer);
-
- dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
- buffer, num_planes);
-
- return buffer;
-}
-
-/**
- * __vb2_free_mem() - release all video buffer memory for a given queue
- */
-static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
-{
- unsigned int buffer;
- struct vb2_buffer *vb;
-
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- vb = q->bufs[buffer];
- if (!vb)
- continue;
-
- /* Free MMAP buffers or release USERPTR buffers */
- if (q->memory == V4L2_MEMORY_MMAP)
- __vb2_buf_mem_free(vb);
- else
- __vb2_buf_userptr_put(vb);
- }
-}
-
-/**
- * __vb2_queue_free() - free buffers at the end of the queue - video memory and
- * related information, if no buffers are left return the queue to an
- * uninitialized state. Might be called even if the queue has already been freed.
- */
-static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
-{
- unsigned int buffer;
-
- /* Call driver-provided cleanup function for each buffer, if provided */
- if (q->ops->buf_cleanup) {
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- if (NULL == q->bufs[buffer])
- continue;
- q->ops->buf_cleanup(q->bufs[buffer]);
- }
- }
-
- /* Release video buffer memory */
- __vb2_free_mem(q, buffers);
-
- /* Free videobuf buffers */
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- kfree(q->bufs[buffer]);
- q->bufs[buffer] = NULL;
- }
-
- q->num_buffers -= buffers;
- if (!q->num_buffers)
- q->memory = 0;
- INIT_LIST_HEAD(&q->queued_list);
-}
-
-/**
- * __verify_planes_array() - verify that the planes array passed in struct
- * v4l2_buffer from userspace can be safely used
- */
-static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
- /* Is memory for copying plane information present? */
- if (NULL == b->m.planes) {
- dprintk(1, "Multi-planar buffer passed but "
- "planes array not provided\n");
- return -EINVAL;
- }
-
- if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) {
- dprintk(1, "Incorrect planes array length, "
- "expected %d, got %d\n", vb->num_planes, b->length);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * __buffer_in_use() - return true if the buffer is in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */
-static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
-{
- unsigned int plane;
- for (plane = 0; plane < vb->num_planes; ++plane) {
- void *mem_priv = vb->planes[plane].mem_priv;
- /*
- * If num_users() has not been provided, call_memop
- * will return 0, apparently nobody cares about this
- * 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, num_users, mem_priv) > 1)
- return true;
- }
- return false;
-}
-
-/**
- * __buffers_in_use() - return true if any buffers on the queue are in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */
-static bool __buffers_in_use(struct vb2_queue *q)
-{
- unsigned int buffer;
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- if (__buffer_in_use(q, q->bufs[buffer]))
- return true;
- }
- return false;
-}
-
-/**
- * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
- * returned to userspace
- */
-static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
-{
- struct vb2_queue *q = vb->vb2_queue;
- int ret;
-
- /* Copy back data such as timestamp, flags, etc. */
- memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
- b->reserved2 = vb->v4l2_buf.reserved2;
- b->reserved = vb->v4l2_buf.reserved;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
- ret = __verify_planes_array(vb, b);
- if (ret)
- return ret;
-
- /*
- * Fill in plane-related data if userspace provided an array
- * for it. The memory and size is verified above.
- */
- memcpy(b->m.planes, vb->v4l2_planes,
- b->length * sizeof(struct v4l2_plane));
- } else {
- /*
- * We use length and offset in v4l2_planes array even for
- * single-planar buffers, but userspace does not.
- */
- b->length = vb->v4l2_planes[0].length;
- b->bytesused = vb->v4l2_planes[0].bytesused;
- if (q->memory == V4L2_MEMORY_MMAP)
- b->m.offset = vb->v4l2_planes[0].m.mem_offset;
- else if (q->memory == V4L2_MEMORY_USERPTR)
- b->m.userptr = vb->v4l2_planes[0].m.userptr;
- }
-
- /*
- * Clear any buffer state related flags.
- */
- b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
-
- switch (vb->state) {
- case VB2_BUF_STATE_QUEUED:
- case VB2_BUF_STATE_ACTIVE:
- b->flags |= V4L2_BUF_FLAG_QUEUED;
- break;
- case VB2_BUF_STATE_ERROR:
- b->flags |= V4L2_BUF_FLAG_ERROR;
- /* fall through */
- case VB2_BUF_STATE_DONE:
- b->flags |= V4L2_BUF_FLAG_DONE;
- break;
- case VB2_BUF_STATE_PREPARED:
- b->flags |= V4L2_BUF_FLAG_PREPARED;
- break;
- case VB2_BUF_STATE_DEQUEUED:
- /* nothing */
- break;
- }
-
- if (__buffer_in_use(q, vb))
- b->flags |= V4L2_BUF_FLAG_MAPPED;
-
- return 0;
-}
-
-/**
- * vb2_querybuf() - query video buffer information
- * @q: videobuf queue
- * @b: buffer struct passed from userspace to vidioc_querybuf handler
- * in driver
- *
- * Should be called from vidioc_querybuf ioctl handler in driver.
- * This function will verify the passed v4l2_buffer structure and fill the
- * relevant information for the userspace.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_querybuf handler in driver.
- */
-int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
-{
- struct vb2_buffer *vb;
-
- if (b->type != q->type) {
- dprintk(1, "querybuf: wrong buffer type\n");
- return -EINVAL;
- }
-
- if (b->index >= q->num_buffers) {
- dprintk(1, "querybuf: buffer index out of range\n");
- return -EINVAL;
- }
- vb = q->bufs[b->index];
-
- return __fill_v4l2_buffer(vb, b);
-}
-EXPORT_SYMBOL(vb2_querybuf);
-
-/**
- * __verify_userptr_ops() - verify that all memory operations required for
- * USERPTR queue type have been provided
- */
-static int __verify_userptr_ops(struct vb2_queue *q)
-{
- if (!(q->io_modes & VB2_USERPTR) || !q->mem_ops->get_userptr ||
- !q->mem_ops->put_userptr)
- return -EINVAL;
-
- return 0;
-}
-
-/**
- * __verify_mmap_ops() - verify that all memory operations required for
- * MMAP queue type have been provided
- */
-static int __verify_mmap_ops(struct vb2_queue *q)
-{
- if (!(q->io_modes & VB2_MMAP) || !q->mem_ops->alloc ||
- !q->mem_ops->put || !q->mem_ops->mmap)
- return -EINVAL;
-
- return 0;
-}
-
-/**
- * __verify_memory_type() - Check whether the memory type and buffer type
- * passed to a buffer operation are compatible with the queue.
- */
-static int __verify_memory_type(struct vb2_queue *q,
- enum v4l2_memory memory, enum v4l2_buf_type type)
-{
- if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) {
- dprintk(1, "reqbufs: unsupported memory type\n");
- return -EINVAL;
- }
-
- if (type != q->type) {
- dprintk(1, "reqbufs: requested type is incorrect\n");
- return -EINVAL;
- }
-
- /*
- * Make sure all the required memory ops for given memory type
- * are available.
- */
- if (memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
- dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
- return -EINVAL;
- }
-
- if (memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
- dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
- return -EINVAL;
- }
-
- /*
- * Place the busy tests at the end: -EBUSY can be ignored when
- * create_bufs is called with count == 0, but count == 0 should still
- * do the memory and type validation.
- */
- if (q->fileio) {
- dprintk(1, "reqbufs: file io in progress\n");
- return -EBUSY;
- }
- return 0;
-}
-
-/**
- * __reqbufs() - Initiate streaming
- * @q: videobuf2 queue
- * @req: struct passed from userspace to vidioc_reqbufs handler in driver
- *
- * Should be called from vidioc_reqbufs ioctl handler of a driver.
- * This function:
- * 1) verifies streaming parameters passed from the userspace,
- * 2) sets up the queue,
- * 3) negotiates number of buffers and planes per buffer with the driver
- * to be used during streaming,
- * 4) allocates internal buffer structures (struct vb2_buffer), according to
- * the agreed parameters,
- * 5) for MMAP memory type, allocates actual video memory, using the
- * memory handling/allocation routines provided during queue initialization
- *
- * If req->count is 0, all the memory will be freed instead.
- * If the queue has been allocated previously (by a previous vb2_reqbufs) call
- * and the queue is not busy, memory will be reallocated.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_reqbufs handler in driver.
- */
-static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
-{
- unsigned int num_buffers, allocated_buffers, num_planes = 0;
- int ret;
-
- if (q->streaming) {
- dprintk(1, "reqbufs: streaming active\n");
- return -EBUSY;
- }
-
- if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
- /*
- * We already have buffers allocated, so first check if they
- * are not in use and can be freed.
- */
- if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
- dprintk(1, "reqbufs: memory in use, cannot free\n");
- return -EBUSY;
- }
-
- __vb2_queue_free(q, q->num_buffers);
-
- /*
- * In case of REQBUFS(0) return immediately without calling
- * driver's queue_setup() callback and allocating resources.
- */
- if (req->count == 0)
- return 0;
- }
-
- /*
- * Make sure the requested values and current defaults are sane.
- */
- num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
- memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
- memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
- q->memory = req->memory;
-
- /*
- * Ask the driver how many buffers and planes per buffer it requires.
- * Driver also sets the size and allocator context for each plane.
- */
- ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
- q->plane_sizes, q->alloc_ctx);
- if (ret)
- return ret;
-
- /* Finally, allocate buffers and video memory */
- ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
- if (ret == 0) {
- dprintk(1, "Memory allocation failed\n");
- return -ENOMEM;
- }
-
- allocated_buffers = ret;
-
- /*
- * Check if driver can handle the allocated number of buffers.
- */
- if (allocated_buffers < num_buffers) {
- num_buffers = allocated_buffers;
-
- ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
-
- if (!ret && allocated_buffers < num_buffers)
- ret = -ENOMEM;
-
- /*
- * Either the driver has accepted a smaller number of buffers,
- * or .queue_setup() returned an error
- */
- }
-
- q->num_buffers = allocated_buffers;
-
- if (ret < 0) {
- __vb2_queue_free(q, allocated_buffers);
- return ret;
- }
-
- /*
- * Return the number of successfully allocated buffers
- * to the userspace.
- */
- req->count = allocated_buffers;
-
- return 0;
-}
-
-/**
- * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
- * type values.
- * @q: videobuf2 queue
- * @req: struct passed from userspace to vidioc_reqbufs handler in driver
- */
-int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
-{
- int ret = __verify_memory_type(q, req->memory, req->type);
-
- return ret ? ret : __reqbufs(q, req);
-}
-EXPORT_SYMBOL_GPL(vb2_reqbufs);
-
-/**
- * __create_bufs() - Allocate buffers and any required auxiliary structs
- * @q: videobuf2 queue
- * @create: creation parameters, passed from userspace to vidioc_create_bufs
- * handler in driver
- *
- * Should be called from vidioc_create_bufs ioctl handler of a driver.
- * This function:
- * 1) verifies parameter sanity
- * 2) calls the .queue_setup() queue operation
- * 3) performs any necessary memory allocations
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_create_bufs handler in driver.
- */
-static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
-{
- unsigned int num_planes = 0, num_buffers, allocated_buffers;
- int ret;
-
- if (q->num_buffers == VIDEO_MAX_FRAME) {
- dprintk(1, "%s(): maximum number of buffers already allocated\n",
- __func__);
- return -ENOBUFS;
- }
-
- if (!q->num_buffers) {
- memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
- memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
- q->memory = create->memory;
- }
-
- num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers);
-
- /*
- * Ask the driver, whether the requested number of buffers, planes per
- * buffer and their sizes are acceptable
- */
- ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
- if (ret)
- return ret;
-
- /* Finally, allocate buffers and video memory */
- ret = __vb2_queue_alloc(q, create->memory, num_buffers,
- num_planes);
- if (ret == 0) {
- dprintk(1, "Memory allocation failed\n");
- return -ENOMEM;
- }
-
- allocated_buffers = ret;
-
- /*
- * Check if driver can handle the so far allocated number of buffers.
- */
- if (ret < num_buffers) {
- num_buffers = ret;
-
- /*
- * q->num_buffers contains the total number of buffers, that the
- * queue driver has set up
- */
- ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
-
- if (!ret && allocated_buffers < num_buffers)
- ret = -ENOMEM;
-
- /*
- * Either the driver has accepted a smaller number of buffers,
- * or .queue_setup() returned an error
- */
- }
-
- q->num_buffers += allocated_buffers;
-
- if (ret < 0) {
- __vb2_queue_free(q, allocated_buffers);
- return -ENOMEM;
- }
-
- /*
- * Return the number of successfully allocated buffers
- * to the userspace.
- */
- create->count = allocated_buffers;
-
- return 0;
-}
-
-/**
- * vb2_create_bufs() - Wrapper for __create_bufs() that also verifies the
- * memory and type values.
- * @q: videobuf2 queue
- * @create: creation parameters, passed from userspace to vidioc_create_bufs
- * handler in driver
- */
-int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
-{
- int ret = __verify_memory_type(q, create->memory, create->format.type);
-
- create->index = q->num_buffers;
- if (create->count == 0)
- return ret != -EBUSY ? ret : 0;
- return ret ? ret : __create_bufs(q, create);
-}
-EXPORT_SYMBOL_GPL(vb2_create_bufs);
-
-/**
- * vb2_plane_vaddr() - Return a kernel virtual address of a given plane
- * @vb: vb2_buffer to which the plane in question belongs to
- * @plane_no: plane number for which the address is to be returned
- *
- * This function returns a kernel virtual address of a given plane if
- * such a mapping exist, NULL otherwise.
- */
-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 || !vb->planes[plane_no].mem_priv)
- return NULL;
-
- return call_memop(q, vaddr, vb->planes[plane_no].mem_priv);
-
-}
-EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
-
-/**
- * vb2_plane_cookie() - Return allocator specific cookie for the given plane
- * @vb: vb2_buffer to which the plane in question belongs to
- * @plane_no: plane number for which the cookie is to be returned
- *
- * This function returns an allocator specific cookie for a given plane if
- * available, NULL otherwise. The allocator should provide some simple static
- * inline function, which would convert this cookie to the allocator specific
- * type that can be used directly by the driver to access the buffer. This can
- * be for example physical address, pointer to scatter list or IOMMU mapping.
- */
-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 || !vb->planes[plane_no].mem_priv)
- return NULL;
-
- return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
-}
-EXPORT_SYMBOL_GPL(vb2_plane_cookie);
-
-/**
- * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished
- * @vb: vb2_buffer returned from the driver
- * @state: either VB2_BUF_STATE_DONE if the operation finished successfully
- * or VB2_BUF_STATE_ERROR if the operation finished with an error
- *
- * This function should be called by the driver after a hardware operation on
- * a buffer is finished and the buffer may be returned to userspace. The driver
- * cannot use this buffer anymore until it is queued back to it by videobuf
- * by the means of buf_queue callback. Only buffers previously queued to the
- * driver by buf_queue can be passed to this function.
- */
-void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
-{
- struct vb2_queue *q = vb->vb2_queue;
- unsigned long flags;
-
- if (vb->state != VB2_BUF_STATE_ACTIVE)
- return;
-
- if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
- return;
-
- dprintk(4, "Done processing on buffer %d, state: %d\n",
- vb->v4l2_buf.index, vb->state);
-
- /* Add the buffer to the done buffers list */
- spin_lock_irqsave(&q->done_lock, flags);
- vb->state = state;
- list_add_tail(&vb->done_entry, &q->done_list);
- atomic_dec(&q->queued_count);
- spin_unlock_irqrestore(&q->done_lock, flags);
-
- /* Inform any processes that may be waiting for buffers */
- wake_up(&q->done_wq);
-}
-EXPORT_SYMBOL_GPL(vb2_buffer_done);
-
-/**
- * __fill_vb2_buffer() - fill a vb2_buffer with information provided in
- * a v4l2_buffer by the userspace
- */
-static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
- struct v4l2_plane *v4l2_planes)
-{
- unsigned int plane;
- int ret;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
- /*
- * Verify that the userspace gave us a valid array for
- * plane information.
- */
- ret = __verify_planes_array(vb, b);
- if (ret)
- return ret;
-
- /* Fill in driver-provided information for OUTPUT types */
- if (V4L2_TYPE_IS_OUTPUT(b->type)) {
- /*
- * Will have to go up to b->length when API starts
- * accepting variable number of planes.
- */
- for (plane = 0; plane < vb->num_planes; ++plane) {
- v4l2_planes[plane].bytesused =
- b->m.planes[plane].bytesused;
- v4l2_planes[plane].data_offset =
- b->m.planes[plane].data_offset;
- }
- }
-
- if (b->memory == V4L2_MEMORY_USERPTR) {
- for (plane = 0; plane < vb->num_planes; ++plane) {
- v4l2_planes[plane].m.userptr =
- b->m.planes[plane].m.userptr;
- v4l2_planes[plane].length =
- b->m.planes[plane].length;
- }
- }
- } else {
- /*
- * Single-planar buffers do not use planes array,
- * so fill in relevant v4l2_buffer struct fields instead.
- * In videobuf we use our internal V4l2_planes struct for
- * single-planar buffers as well, for simplicity.
- */
- if (V4L2_TYPE_IS_OUTPUT(b->type))
- v4l2_planes[0].bytesused = b->bytesused;
-
- if (b->memory == V4L2_MEMORY_USERPTR) {
- v4l2_planes[0].m.userptr = b->m.userptr;
- v4l2_planes[0].length = b->length;
- }
- }
-
- vb->v4l2_buf.field = b->field;
- vb->v4l2_buf.timestamp = b->timestamp;
- vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
-
- return 0;
-}
-
-/**
- * __qbuf_userptr() - handle qbuf of a USERPTR buffer
- */
-static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
- struct v4l2_plane planes[VIDEO_MAX_PLANES];
- struct vb2_queue *q = vb->vb2_queue;
- void *mem_priv;
- unsigned int plane;
- int ret;
- int write = !V4L2_TYPE_IS_OUTPUT(q->type);
-
- /* Verify and copy relevant information provided by the userspace */
- ret = __fill_vb2_buffer(vb, b, planes);
- if (ret)
- return ret;
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- /* Skip the plane if already verified */
- 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;
-
- dprintk(3, "qbuf: userspace address for plane %d changed, "
- "reacquiring memory\n", plane);
-
- /* Check if the provided plane buffer is large enough */
- if (planes[plane].length < q->plane_sizes[plane]) {
- ret = -EINVAL;
- goto err;
- }
-
- /* Release previously acquired memory if present */
- if (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 */
- 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 = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
- goto err;
- }
- vb->planes[plane].mem_priv = mem_priv;
- }
-
- /*
- * Call driver-specific initialization on the newly acquired buffer,
- * if provided.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- goto err;
- }
-
- /*
- * Now that everything is in order, copy relevant information
- * provided by userspace.
- */
- for (plane = 0; plane < vb->num_planes; ++plane)
- vb->v4l2_planes[plane] = planes[plane];
-
- return 0;
-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, 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;
- }
-
- return ret;
-}
-
-/**
- * __qbuf_mmap() - handle qbuf of an MMAP buffer
- */
-static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
- return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
-}
-
-/**
- * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
- */
-static void __enqueue_in_driver(struct vb2_buffer *vb)
-{
- struct vb2_queue *q = vb->vb2_queue;
-
- vb->state = VB2_BUF_STATE_ACTIVE;
- atomic_inc(&q->queued_count);
- q->ops->buf_queue(vb);
-}
-
-static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
- struct vb2_queue *q = vb->vb2_queue;
- int ret;
-
- switch (q->memory) {
- case V4L2_MEMORY_MMAP:
- ret = __qbuf_mmap(vb, b);
- break;
- case V4L2_MEMORY_USERPTR:
- ret = __qbuf_userptr(vb, b);
- break;
- default:
- WARN(1, "Invalid queue type\n");
- ret = -EINVAL;
- }
-
- if (!ret)
- ret = call_qop(q, buf_prepare, vb);
- if (ret)
- dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
- else
- vb->state = VB2_BUF_STATE_PREPARED;
-
- return ret;
-}
-
-/**
- * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel
- * @q: videobuf2 queue
- * @b: buffer structure passed from userspace to vidioc_prepare_buf
- * handler in driver
- *
- * Should be called from vidioc_prepare_buf ioctl handler of a driver.
- * This function:
- * 1) verifies the passed buffer,
- * 2) calls buf_prepare callback in the driver (if provided), in which
- * driver-specific buffer initialization can be performed,
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_prepare_buf handler in driver.
- */
-int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
-{
- struct vb2_buffer *vb;
- int ret;
-
- if (q->fileio) {
- dprintk(1, "%s(): file io in progress\n", __func__);
- return -EBUSY;
- }
-
- if (b->type != q->type) {
- dprintk(1, "%s(): invalid buffer type\n", __func__);
- return -EINVAL;
- }
-
- if (b->index >= q->num_buffers) {
- dprintk(1, "%s(): buffer index out of range\n", __func__);
- return -EINVAL;
- }
-
- vb = q->bufs[b->index];
- if (NULL == vb) {
- /* Should never happen */
- dprintk(1, "%s(): buffer is NULL\n", __func__);
- return -EINVAL;
- }
-
- if (b->memory != q->memory) {
- dprintk(1, "%s(): invalid memory type\n", __func__);
- return -EINVAL;
- }
-
- if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state);
- return -EINVAL;
- }
-
- ret = __buf_prepare(vb, b);
- if (ret < 0)
- return ret;
-
- __fill_v4l2_buffer(vb, b);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_prepare_buf);
-
-/**
- * vb2_qbuf() - Queue a buffer from userspace
- * @q: videobuf2 queue
- * @b: buffer structure passed from userspace to vidioc_qbuf handler
- * in driver
- *
- * Should be called from vidioc_qbuf ioctl handler of a driver.
- * This function:
- * 1) verifies the passed buffer,
- * 2) if necessary, calls buf_prepare callback in the driver (if provided), in
- * which driver-specific buffer initialization can be performed,
- * 3) if streaming is on, queues the buffer in driver by the means of buf_queue
- * callback for processing.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_qbuf handler in driver.
- */
-int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
-{
- struct rw_semaphore *mmap_sem = NULL;
- struct vb2_buffer *vb;
- 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");
- ret = -EBUSY;
- goto unlock;
- }
-
- if (b->type != q->type) {
- dprintk(1, "qbuf: invalid buffer type\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- if (b->index >= q->num_buffers) {
- dprintk(1, "qbuf: buffer index out of range\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- vb = q->bufs[b->index];
- if (NULL == vb) {
- /* Should never happen */
- dprintk(1, "qbuf: buffer is NULL\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- if (b->memory != q->memory) {
- dprintk(1, "qbuf: invalid memory type\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- switch (vb->state) {
- case VB2_BUF_STATE_DEQUEUED:
- ret = __buf_prepare(vb, b);
- if (ret)
- goto unlock;
- case VB2_BUF_STATE_PREPARED:
- break;
- default:
- dprintk(1, "qbuf: buffer already in use\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- /*
- * Add to the queued buffers list, a buffer will stay on it until
- * dequeued in dqbuf.
- */
- list_add_tail(&vb->queued_entry, &q->queued_list);
- vb->state = VB2_BUF_STATE_QUEUED;
-
- /*
- * If already streaming, give the buffer to driver for processing.
- * If not, the buffer will be given to driver on next streamon.
- */
- if (q->streaming)
- __enqueue_in_driver(vb);
-
- /* Fill buffer information for the userspace */
- __fill_v4l2_buffer(vb, b);
-
- dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
-unlock:
- if (mmap_sem)
- up_read(mmap_sem);
- return ret;
-}
-EXPORT_SYMBOL_GPL(vb2_qbuf);
-
-/**
- * __vb2_wait_for_done_vb() - wait for a buffer to become available
- * for dequeuing
- *
- * Will sleep if required for nonblocking == false.
- */
-static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
-{
- /*
- * All operations on vb_done_list are performed under done_lock
- * spinlock protection. However, buffers may be removed from
- * it and returned to userspace only while holding both driver's
- * lock and the done_lock spinlock. Thus we can be sure that as
- * long as we hold the driver's lock, the list will remain not
- * empty if list_empty() check succeeds.
- */
-
- for (;;) {
- int ret;
-
- if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
- return -EINVAL;
- }
-
- if (!list_empty(&q->done_list)) {
- /*
- * Found a buffer that we were waiting for.
- */
- break;
- }
-
- if (nonblocking) {
- dprintk(1, "Nonblocking and no buffers to dequeue, "
- "will not wait\n");
- return -EAGAIN;
- }
-
- /*
- * We are streaming and blocking, wait for another buffer to
- * become ready or for streamoff. Driver's lock is released to
- * allow streamoff or qbuf to be called while waiting.
- */
- call_qop(q, wait_prepare, q);
-
- /*
- * All locks have been released, it is safe to sleep now.
- */
- dprintk(3, "Will sleep waiting for buffers\n");
- ret = wait_event_interruptible(q->done_wq,
- !list_empty(&q->done_list) || !q->streaming);
-
- /*
- * We need to reevaluate both conditions again after reacquiring
- * the locks or return an error if one occurred.
- */
- call_qop(q, wait_finish, q);
- if (ret)
- return ret;
- }
- return 0;
-}
-
-/**
- * __vb2_get_done_vb() - get a buffer ready for dequeuing
- *
- * Will sleep if required for nonblocking == false.
- */
-static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
- int nonblocking)
-{
- unsigned long flags;
- int ret;
-
- /*
- * Wait for at least one buffer to become available on the done_list.
- */
- ret = __vb2_wait_for_done_vb(q, nonblocking);
- if (ret)
- return ret;
-
- /*
- * Driver's lock has been held since we last verified that done_list
- * is not empty, so no need for another list_empty(done_list) check.
- */
- spin_lock_irqsave(&q->done_lock, flags);
- *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
- list_del(&(*vb)->done_entry);
- spin_unlock_irqrestore(&q->done_lock, flags);
-
- return 0;
-}
-
-/**
- * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2
- * @q: videobuf2 queue
- *
- * This function will wait until all buffers that have been given to the driver
- * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call
- * wait_prepare, wait_finish pair. It is intended to be called with all locks
- * taken, for example from stop_streaming() callback.
- */
-int vb2_wait_for_all_buffers(struct vb2_queue *q)
-{
- if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
- return -EINVAL;
- }
-
- wait_event(q->done_wq, !atomic_read(&q->queued_count));
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
-
-/**
- * vb2_dqbuf() - Dequeue a buffer to the userspace
- * @q: videobuf2 queue
- * @b: buffer structure passed from userspace to vidioc_dqbuf handler
- * in driver
- * @nonblocking: if true, this call will not sleep waiting for a buffer if no
- * buffers ready for dequeuing are present. Normally the driver
- * would be passing (file->f_flags & O_NONBLOCK) here
- *
- * Should be called from vidioc_dqbuf ioctl handler of a driver.
- * This function:
- * 1) verifies the passed buffer,
- * 2) calls buf_finish callback in the driver (if provided), in which
- * driver can perform any additional operations that may be required before
- * returning the buffer to userspace, such as cache sync,
- * 3) the buffer struct members are filled with relevant information for
- * the userspace.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_dqbuf handler in driver.
- */
-int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
-{
- struct vb2_buffer *vb = NULL;
- int ret;
-
- if (q->fileio) {
- dprintk(1, "dqbuf: file io in progress\n");
- return -EBUSY;
- }
-
- if (b->type != q->type) {
- dprintk(1, "dqbuf: invalid buffer type\n");
- return -EINVAL;
- }
-
- ret = __vb2_get_done_vb(q, &vb, nonblocking);
- if (ret < 0) {
- dprintk(1, "dqbuf: error getting next done buffer\n");
- return ret;
- }
-
- ret = call_qop(q, buf_finish, vb);
- if (ret) {
- dprintk(1, "dqbuf: buffer finish failed\n");
- return ret;
- }
-
- switch (vb->state) {
- case VB2_BUF_STATE_DONE:
- dprintk(3, "dqbuf: Returning done buffer\n");
- break;
- case VB2_BUF_STATE_ERROR:
- dprintk(3, "dqbuf: Returning done buffer with errors\n");
- break;
- default:
- dprintk(1, "dqbuf: Invalid buffer state\n");
- return -EINVAL;
- }
-
- /* Fill buffer information for the userspace */
- __fill_v4l2_buffer(vb, b);
- /* Remove from videobuf queue */
- list_del(&vb->queued_entry);
-
- dprintk(1, "dqbuf of buffer %d, with state %d\n",
- vb->v4l2_buf.index, vb->state);
-
- vb->state = VB2_BUF_STATE_DEQUEUED;
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_dqbuf);
-
-/**
- * __vb2_queue_cancel() - cancel and stop (pause) streaming
- *
- * Removes all queued buffers from driver's queue and all buffers queued by
- * userspace from videobuf's queue. Returns to state after reqbufs.
- */
-static void __vb2_queue_cancel(struct vb2_queue *q)
-{
- unsigned int i;
-
- /*
- * Tell driver to stop all transactions and release all queued
- * buffers.
- */
- if (q->streaming)
- call_qop(q, stop_streaming, q);
- q->streaming = 0;
-
- /*
- * Remove all buffers from videobuf's list...
- */
- INIT_LIST_HEAD(&q->queued_list);
- /*
- * ...and done list; userspace will not receive any buffers it
- * has not already dequeued before initiating cancel.
- */
- INIT_LIST_HEAD(&q->done_list);
- atomic_set(&q->queued_count, 0);
- wake_up_all(&q->done_wq);
-
- /*
- * Reinitialize all buffers for next use.
- */
- for (i = 0; i < q->num_buffers; ++i)
- q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
-}
-
-/**
- * vb2_streamon - start streaming
- * @q: videobuf2 queue
- * @type: type argument passed from userspace to vidioc_streamon handler
- *
- * Should be called from vidioc_streamon handler of a driver.
- * This function:
- * 1) verifies current state
- * 2) passes any previously queued buffers to the driver and starts streaming
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_streamon handler in the driver.
- */
-int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
-{
- struct vb2_buffer *vb;
- int ret;
-
- if (q->fileio) {
- dprintk(1, "streamon: file io in progress\n");
- return -EBUSY;
- }
-
- if (type != q->type) {
- dprintk(1, "streamon: invalid stream type\n");
- return -EINVAL;
- }
-
- if (q->streaming) {
- dprintk(1, "streamon: already streaming\n");
- return -EBUSY;
- }
-
- /*
- * If any buffers were queued before streamon,
- * we can now pass them to driver for processing.
- */
- list_for_each_entry(vb, &q->queued_list, queued_entry)
- __enqueue_in_driver(vb);
-
- /*
- * Let driver notice that streaming state has been enabled.
- */
- ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
- if (ret) {
- dprintk(1, "streamon: driver refused to start streaming\n");
- __vb2_queue_cancel(q);
- return ret;
- }
-
- q->streaming = 1;
-
- dprintk(3, "Streamon successful\n");
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_streamon);
-
-
-/**
- * vb2_streamoff - stop streaming
- * @q: videobuf2 queue
- * @type: type argument passed from userspace to vidioc_streamoff handler
- *
- * Should be called from vidioc_streamoff handler of a driver.
- * This function:
- * 1) verifies current state,
- * 2) stop streaming and dequeues any queued buffers, including those previously
- * passed to the driver (after waiting for the driver to finish).
- *
- * This call can be used for pausing playback.
- * The return values from this function are intended to be directly returned
- * from vidioc_streamoff handler in the driver
- */
-int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
-{
- if (q->fileio) {
- dprintk(1, "streamoff: file io in progress\n");
- return -EBUSY;
- }
-
- if (type != q->type) {
- dprintk(1, "streamoff: invalid stream type\n");
- return -EINVAL;
- }
-
- if (!q->streaming) {
- dprintk(1, "streamoff: not streaming\n");
- return -EINVAL;
- }
-
- /*
- * Cancel will pause streaming and remove all buffers from the driver
- * and videobuf, effectively returning control over them to userspace.
- */
- __vb2_queue_cancel(q);
-
- dprintk(3, "Streamoff successful\n");
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_streamoff);
-
-/**
- * __find_plane_by_offset() - find plane associated with the given offset off
- */
-static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
- unsigned int *_buffer, unsigned int *_plane)
-{
- struct vb2_buffer *vb;
- unsigned int buffer, plane;
-
- /*
- * Go over all buffers and their planes, comparing the given offset
- * with an offset assigned to each plane. If a match is found,
- * return its buffer and plane numbers.
- */
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- vb = q->bufs[buffer];
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- if (vb->v4l2_planes[plane].m.mem_offset == off) {
- *_buffer = buffer;
- *_plane = plane;
- return 0;
- }
- }
- }
-
- return -EINVAL;
-}
-
-/**
- * vb2_mmap() - map video buffers into application address space
- * @q: videobuf2 queue
- * @vma: vma passed to the mmap file operation handler in the driver
- *
- * Should be called from mmap file operation handler of a driver.
- * This function maps one plane of one of the available video buffers to
- * userspace. To map whole video memory allocated on reqbufs, this function
- * has to be called once per each plane per each buffer previously allocated.
- *
- * When the userspace application calls mmap, it passes to it an offset returned
- * to it earlier by the means of vidioc_querybuf handler. That offset acts as
- * a "cookie", which is then used to identify the plane to be mapped.
- * This function finds a plane with a matching offset and a mapping is performed
- * by the means of a provided memory operation.
- *
- * The return values from this function are intended to be directly returned
- * from the mmap handler in driver.
- */
-int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
-{
- unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
- struct vb2_buffer *vb;
- unsigned int buffer, plane;
- int ret;
-
- if (q->memory != V4L2_MEMORY_MMAP) {
- dprintk(1, "Queue is not currently set up for mmap\n");
- return -EINVAL;
- }
-
- /*
- * Check memory area access mode.
- */
- if (!(vma->vm_flags & VM_SHARED)) {
- dprintk(1, "Invalid vma flags, VM_SHARED needed\n");
- return -EINVAL;
- }
- if (V4L2_TYPE_IS_OUTPUT(q->type)) {
- if (!(vma->vm_flags & VM_WRITE)) {
- dprintk(1, "Invalid vma flags, VM_WRITE needed\n");
- return -EINVAL;
- }
- } else {
- if (!(vma->vm_flags & VM_READ)) {
- dprintk(1, "Invalid vma flags, VM_READ needed\n");
- return -EINVAL;
- }
- }
-
- /*
- * Find the plane corresponding to the offset passed by userspace.
- */
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
- if (ret)
- return ret;
-
- vb = q->bufs[buffer];
-
- ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
- if (ret)
- return ret;
-
- dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_mmap);
-
-#ifndef CONFIG_MMU
-unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
- unsigned long addr,
- unsigned long len,
- unsigned long pgoff,
- unsigned long flags)
-{
- unsigned long off = pgoff << PAGE_SHIFT;
- struct vb2_buffer *vb;
- unsigned int buffer, plane;
- int ret;
-
- if (q->memory != V4L2_MEMORY_MMAP) {
- dprintk(1, "Queue is not currently set up for mmap\n");
- return -EINVAL;
- }
-
- /*
- * Find the plane corresponding to the offset passed by userspace.
- */
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
- if (ret)
- return ret;
-
- vb = q->bufs[buffer];
-
- return (unsigned long)vb2_plane_vaddr(vb, plane);
-}
-EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
-#endif
-
-static int __vb2_init_fileio(struct vb2_queue *q, int read);
-static int __vb2_cleanup_fileio(struct vb2_queue *q);
-
-/**
- * vb2_poll() - implements poll userspace operation
- * @q: videobuf2 queue
- * @file: file argument passed to the poll file operation handler
- * @wait: wait argument passed to the poll file operation handler
- *
- * This function implements poll file operation handler for a driver.
- * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
- * be informed that the file descriptor of a video device is available for
- * reading.
- * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
- * will be reported as available for writing.
- *
- * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any
- * pending events.
- *
- * The return values from this function are intended to be directly returned
- * from poll handler in driver.
- */
-unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
-{
- struct video_device *vfd = video_devdata(file);
- unsigned long req_events = poll_requested_events(wait);
- struct vb2_buffer *vb = NULL;
- unsigned int res = 0;
- unsigned long flags;
-
- if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
- struct v4l2_fh *fh = file->private_data;
-
- if (v4l2_event_pending(fh))
- res = POLLPRI;
- else if (req_events & POLLPRI)
- poll_wait(file, &fh->wait, wait);
- }
-
- /*
- * Start file I/O emulator only if streaming API has not been used yet.
- */
- if (q->num_buffers == 0 && q->fileio == NULL) {
- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
- (req_events & (POLLIN | POLLRDNORM))) {
- if (__vb2_init_fileio(q, 1))
- return res | POLLERR;
- }
- if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
- (req_events & (POLLOUT | POLLWRNORM))) {
- if (__vb2_init_fileio(q, 0))
- return res | POLLERR;
- /*
- * Write to OUTPUT queue can be done immediately.
- */
- return res | POLLOUT | POLLWRNORM;
- }
- }
-
- /*
- * There is nothing to wait for if no buffers have already been queued.
- */
- if (list_empty(&q->queued_list))
- return res | POLLERR;
-
- poll_wait(file, &q->done_wq, wait);
-
- /*
- * Take first buffer available for dequeuing.
- */
- spin_lock_irqsave(&q->done_lock, flags);
- if (!list_empty(&q->done_list))
- vb = list_first_entry(&q->done_list, struct vb2_buffer,
- done_entry);
- spin_unlock_irqrestore(&q->done_lock, flags);
-
- if (vb && (vb->state == VB2_BUF_STATE_DONE
- || vb->state == VB2_BUF_STATE_ERROR)) {
- return (V4L2_TYPE_IS_OUTPUT(q->type)) ?
- res | POLLOUT | POLLWRNORM :
- res | POLLIN | POLLRDNORM;
- }
- return res;
-}
-EXPORT_SYMBOL_GPL(vb2_poll);
-
-/**
- * vb2_queue_init() - initialize a videobuf2 queue
- * @q: videobuf2 queue; this structure should be allocated in driver
- *
- * The vb2_queue structure should be allocated by the driver. The driver is
- * responsible of clearing it's content and setting initial values for some
- * required entries before calling this function.
- * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
- * to the struct vb2_queue description in include/media/videobuf2-core.h
- * for more information.
- */
-int vb2_queue_init(struct vb2_queue *q)
-{
- BUG_ON(!q);
- BUG_ON(!q->ops);
- BUG_ON(!q->mem_ops);
- BUG_ON(!q->type);
- BUG_ON(!q->io_modes);
-
- BUG_ON(!q->ops->queue_setup);
- BUG_ON(!q->ops->buf_queue);
-
- INIT_LIST_HEAD(&q->queued_list);
- INIT_LIST_HEAD(&q->done_list);
- spin_lock_init(&q->done_lock);
- init_waitqueue_head(&q->done_wq);
-
- if (q->buf_struct_size == 0)
- q->buf_struct_size = sizeof(struct vb2_buffer);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_queue_init);
-
-/**
- * vb2_queue_release() - stop streaming, release the queue and free memory
- * @q: videobuf2 queue
- *
- * This function stops streaming and performs necessary clean ups, including
- * freeing video buffer memory. The driver is responsible for freeing
- * the vb2_queue structure itself.
- */
-void vb2_queue_release(struct vb2_queue *q)
-{
- __vb2_cleanup_fileio(q);
- __vb2_queue_cancel(q);
- __vb2_queue_free(q, q->num_buffers);
-}
-EXPORT_SYMBOL_GPL(vb2_queue_release);
-
-/**
- * struct vb2_fileio_buf - buffer context used by file io emulator
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. This structure is used for
- * tracking context related to the buffers.
- */
-struct vb2_fileio_buf {
- void *vaddr;
- unsigned int size;
- unsigned int pos;
- unsigned int queued:1;
-};
-
-/**
- * struct vb2_fileio_data - queue context used by file io emulator
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. For proper operation it required
- * this structure to save the driver state between each call of the read
- * or write function.
- */
-struct vb2_fileio_data {
- struct v4l2_requestbuffers req;
- struct v4l2_buffer b;
- struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
- unsigned int index;
- unsigned int q_count;
- unsigned int dq_count;
- unsigned int flags;
-};
-
-/**
- * __vb2_init_fileio() - initialize file io emulator
- * @q: videobuf2 queue
- * @read: mode selector (1 means read, 0 means write)
- */
-static int __vb2_init_fileio(struct vb2_queue *q, int read)
-{
- struct vb2_fileio_data *fileio;
- int i, ret;
- unsigned int count = 0;
-
- /*
- * Sanity check
- */
- if ((read && !(q->io_modes & VB2_READ)) ||
- (!read && !(q->io_modes & VB2_WRITE)))
- BUG();
-
- /*
- * Check if device supports mapping buffers to kernel virtual space.
- */
- if (!q->mem_ops->vaddr)
- return -EBUSY;
-
- /*
- * Check if streaming api has not been already activated.
- */
- if (q->streaming || q->num_buffers > 0)
- return -EBUSY;
-
- /*
- * Start with count 1, driver can increase it in queue_setup()
- */
- count = 1;
-
- dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n",
- (read) ? "read" : "write", count, q->io_flags);
-
- fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
- if (fileio == NULL)
- return -ENOMEM;
-
- fileio->flags = q->io_flags;
-
- /*
- * Request buffers and use MMAP type to force driver
- * to allocate buffers by itself.
- */
- fileio->req.count = count;
- fileio->req.memory = V4L2_MEMORY_MMAP;
- fileio->req.type = q->type;
- ret = vb2_reqbufs(q, &fileio->req);
- if (ret)
- goto err_kfree;
-
- /*
- * Check if plane_count is correct
- * (multiplane buffers are not supported).
- */
- if (q->bufs[0]->num_planes != 1) {
- ret = -EBUSY;
- goto err_reqbufs;
- }
-
- /*
- * Get kernel address of each buffer.
- */
- for (i = 0; i < q->num_buffers; i++) {
- fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
- if (fileio->bufs[i].vaddr == NULL)
- goto err_reqbufs;
- fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
- }
-
- /*
- * Read mode requires pre queuing of all buffers.
- */
- if (read) {
- /*
- * Queue all buffers.
- */
- for (i = 0; i < q->num_buffers; i++) {
- struct v4l2_buffer *b = &fileio->b;
- memset(b, 0, sizeof(*b));
- b->type = q->type;
- b->memory = q->memory;
- b->index = i;
- ret = vb2_qbuf(q, b);
- if (ret)
- goto err_reqbufs;
- fileio->bufs[i].queued = 1;
- }
-
- /*
- * Start streaming.
- */
- ret = vb2_streamon(q, q->type);
- if (ret)
- goto err_reqbufs;
- }
-
- q->fileio = fileio;
-
- return ret;
-
-err_reqbufs:
- fileio->req.count = 0;
- vb2_reqbufs(q, &fileio->req);
-
-err_kfree:
- kfree(fileio);
- return ret;
-}
-
-/**
- * __vb2_cleanup_fileio() - free resourced used by file io emulator
- * @q: videobuf2 queue
- */
-static int __vb2_cleanup_fileio(struct vb2_queue *q)
-{
- struct vb2_fileio_data *fileio = q->fileio;
-
- if (fileio) {
- /*
- * Hack fileio context to enable direct calls to vb2 ioctl
- * interface.
- */
- q->fileio = NULL;
-
- vb2_streamoff(q, q->type);
- fileio->req.count = 0;
- vb2_reqbufs(q, &fileio->req);
- kfree(fileio);
- dprintk(3, "file io emulator closed\n");
- }
- return 0;
-}
-
-/**
- * __vb2_perform_fileio() - perform a single file io (read or write) operation
- * @q: videobuf2 queue
- * @data: pointed to target userspace buffer
- * @count: number of bytes to read or write
- * @ppos: file handle position tracking pointer
- * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
- * @read: access mode selector (1 means read, 0 means write)
- */
-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblock, int read)
-{
- struct vb2_fileio_data *fileio;
- struct vb2_fileio_buf *buf;
- int ret, index;
-
- dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n",
- read ? "read" : "write", (long)*ppos, count,
- nonblock ? "non" : "");
-
- if (!data)
- return -EINVAL;
-
- /*
- * Initialize emulator on first call.
- */
- if (!q->fileio) {
- ret = __vb2_init_fileio(q, read);
- dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
- if (ret)
- return ret;
- }
- fileio = q->fileio;
-
- /*
- * Hack fileio context to enable direct calls to vb2 ioctl interface.
- * The pointer will be restored before returning from this function.
- */
- q->fileio = NULL;
-
- index = fileio->index;
- buf = &fileio->bufs[index];
-
- /*
- * Check if we need to dequeue the buffer.
- */
- if (buf->queued) {
- struct vb2_buffer *vb;
-
- /*
- * Call vb2_dqbuf to get buffer back.
- */
- memset(&fileio->b, 0, sizeof(fileio->b));
- fileio->b.type = q->type;
- fileio->b.memory = q->memory;
- fileio->b.index = index;
- ret = vb2_dqbuf(q, &fileio->b, nonblock);
- dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
- if (ret)
- goto end;
- fileio->dq_count += 1;
-
- /*
- * Get number of bytes filled by the driver
- */
- vb = q->bufs[index];
- buf->size = vb2_get_plane_payload(vb, 0);
- buf->queued = 0;
- }
-
- /*
- * Limit count on last few bytes of the buffer.
- */
- if (buf->pos + count > buf->size) {
- count = buf->size - buf->pos;
- dprintk(5, "reducing read count: %zd\n", count);
- }
-
- /*
- * Transfer data to userspace.
- */
- dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n",
- count, index, buf->pos);
- if (read)
- ret = copy_to_user(data, buf->vaddr + buf->pos, count);
- else
- ret = copy_from_user(buf->vaddr + buf->pos, data, count);
- if (ret) {
- dprintk(3, "file io: error copying data\n");
- ret = -EFAULT;
- goto end;
- }
-
- /*
- * Update counters.
- */
- buf->pos += count;
- *ppos += count;
-
- /*
- * Queue next buffer if required.
- */
- if (buf->pos == buf->size ||
- (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) {
- /*
- * Check if this is the last buffer to read.
- */
- if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
- fileio->dq_count == 1) {
- dprintk(3, "file io: read limit reached\n");
- /*
- * Restore fileio pointer and release the context.
- */
- q->fileio = fileio;
- return __vb2_cleanup_fileio(q);
- }
-
- /*
- * Call vb2_qbuf and give buffer to the driver.
- */
- memset(&fileio->b, 0, sizeof(fileio->b));
- fileio->b.type = q->type;
- fileio->b.memory = q->memory;
- fileio->b.index = index;
- fileio->b.bytesused = buf->pos;
- ret = vb2_qbuf(q, &fileio->b);
- dprintk(5, "file io: vb2_dbuf result: %d\n", ret);
- if (ret)
- goto end;
-
- /*
- * Buffer has been queued, update the status
- */
- buf->pos = 0;
- buf->queued = 1;
- buf->size = q->bufs[0]->v4l2_planes[0].length;
- fileio->q_count += 1;
-
- /*
- * Switch to the next buffer
- */
- fileio->index = (index + 1) % q->num_buffers;
-
- /*
- * Start streaming if required.
- */
- if (!read && !q->streaming) {
- ret = vb2_streamon(q, q->type);
- if (ret)
- goto end;
- }
- }
-
- /*
- * Return proper number of bytes processed.
- */
- if (ret == 0)
- ret = count;
-end:
- /*
- * Restore the fileio context and block vb2 ioctl interface.
- */
- q->fileio = fileio;
- return ret;
-}
-
-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblocking)
-{
- return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
-}
-EXPORT_SYMBOL_GPL(vb2_read);
-
-size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblocking)
-{
- return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0);
-}
-EXPORT_SYMBOL_GPL(vb2_write);
-
-
-/*
- * The following functions are not part of the vb2 core API, but are helper
- * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
- * and struct vb2_ops.
- * They contain boilerplate code that most if not all drivers have to do
- * and so they simplify the driver code.
- */
-
-/* The queue is busy if there is a owner and you are not that owner. */
-static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
-{
- return vdev->queue->owner && vdev->queue->owner != file->private_data;
-}
-
-/* vb2 ioctl helpers */
-
-int vb2_ioctl_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct video_device *vdev = video_devdata(file);
- int res = __verify_memory_type(vdev->queue, p->memory, p->type);
-
- if (res)
- return res;
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- res = __reqbufs(vdev->queue, p);
- /* If count == 0, then the owner has released all buffers and he
- is no longer owner of the queue. Otherwise we have a new owner. */
- if (res == 0)
- vdev->queue->owner = p->count ? file->private_data : NULL;
- return res;
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_reqbufs);
-
-int vb2_ioctl_create_bufs(struct file *file, void *priv,
- struct v4l2_create_buffers *p)
-{
- struct video_device *vdev = video_devdata(file);
- int res = __verify_memory_type(vdev->queue, p->memory, p->format.type);
-
- p->index = vdev->queue->num_buffers;
- /* If count == 0, then just check if memory and type are valid.
- Any -EBUSY result from __verify_memory_type can be mapped to 0. */
- if (p->count == 0)
- return res != -EBUSY ? res : 0;
- if (res)
- return res;
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- res = __create_bufs(vdev->queue, p);
- if (res == 0)
- vdev->queue->owner = file->private_data;
- return res;
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs);
-
-int vb2_ioctl_prepare_buf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- return vb2_prepare_buf(vdev->queue, p);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf);
-
-int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *vdev = video_devdata(file);
-
- /* No need to call vb2_queue_is_busy(), anyone can query buffers. */
- return vb2_querybuf(vdev->queue, p);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
-
-int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- return vb2_qbuf(vdev->queue, p);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
-
-int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_dqbuf);
-
-int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- return vb2_streamon(vdev->queue, i);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_streamon);
-
-int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (vb2_queue_is_busy(vdev, file))
- return -EBUSY;
- return vb2_streamoff(vdev->queue, i);
-}
-EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff);
-
-/* v4l2_file_operations helpers */
-
-int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *vdev = video_devdata(file);
-
- return vb2_mmap(vdev->queue, vma);
-}
-EXPORT_SYMBOL_GPL(vb2_fop_mmap);
-
-int vb2_fop_release(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
-
- if (file->private_data == vdev->queue->owner) {
- vb2_queue_release(vdev->queue);
- vdev->queue->owner = NULL;
- }
- return v4l2_fh_release(file);
-}
-EXPORT_SYMBOL_GPL(vb2_fop_release);
-
-ssize_t vb2_fop_write(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
- bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && lock;
- int err = -EBUSY;
-
- if (must_lock && mutex_lock_interruptible(lock))
- return -ERESTARTSYS;
- if (vb2_queue_is_busy(vdev, file))
- goto exit;
- err = vb2_write(vdev->queue, buf, count, ppos,
- file->f_flags & O_NONBLOCK);
- if (err >= 0)
- vdev->queue->owner = file->private_data;
-exit:
- if (must_lock)
- mutex_unlock(lock);
- return err;
-}
-EXPORT_SYMBOL_GPL(vb2_fop_write);
-
-ssize_t vb2_fop_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
- bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && vdev->lock;
- int err = -EBUSY;
-
- if (must_lock && mutex_lock_interruptible(lock))
- return -ERESTARTSYS;
- if (vb2_queue_is_busy(vdev, file))
- goto exit;
- err = vb2_read(vdev->queue, buf, count, ppos,
- file->f_flags & O_NONBLOCK);
- if (err >= 0)
- vdev->queue->owner = file->private_data;
-exit:
- if (must_lock)
- mutex_unlock(lock);
- return err;
-}
-EXPORT_SYMBOL_GPL(vb2_fop_read);
-
-unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
-{
- struct video_device *vdev = video_devdata(file);
- struct vb2_queue *q = vdev->queue;
- struct mutex *lock = q->lock ? q->lock : vdev->lock;
- unsigned long req_events = poll_requested_events(wait);
- unsigned res;
- void *fileio;
- /* Yuck. We really need to get rid of this flag asap. If it is
- set, then the core took the serialization lock before calling
- poll(). This is being phased out, but for now we have to handle
- this case. */
- bool locked = test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
- bool must_lock = false;
-
- /* Try to be smart: only lock if polling might start fileio,
- otherwise locking will only introduce unwanted delays. */
- if (q->num_buffers == 0 && q->fileio == NULL) {
- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
- (req_events & (POLLIN | POLLRDNORM)))
- must_lock = true;
- else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
- (req_events & (POLLOUT | POLLWRNORM)))
- must_lock = true;
- }
-
- /* If locking is needed, but this helper doesn't know how, then you
- shouldn't be using this helper but you should write your own. */
- WARN_ON(must_lock && !locked && !lock);
-
- if (must_lock && !locked && lock && mutex_lock_interruptible(lock))
- return POLLERR;
-
- fileio = q->fileio;
-
- res = vb2_poll(vdev->queue, file, wait);
-
- /* If fileio was started, then we have a new queue owner. */
- if (must_lock && !fileio && q->fileio)
- q->owner = file->private_data;
- if (must_lock && !locked && lock)
- mutex_unlock(lock);
- return res;
-}
-EXPORT_SYMBOL_GPL(vb2_fop_poll);
-
-#ifndef CONFIG_MMU
-unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
- unsigned long len, unsigned long pgoff, unsigned long flags)
-{
- struct video_device *vdev = video_devdata(file);
-
- return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
-}
-EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
-#endif
-
-/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
-
-void vb2_ops_wait_prepare(struct vb2_queue *vq)
-{
- mutex_unlock(vq->lock);
-}
-EXPORT_SYMBOL_GPL(vb2_ops_wait_prepare);
-
-void vb2_ops_wait_finish(struct vb2_queue *vq)
-{
- mutex_lock(vq->lock);
-}
-EXPORT_SYMBOL_GPL(vb2_ops_wait_finish);
-
-MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
-MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
deleted file mode 100644
index 6b5ca6c70a46..000000000000
--- a/drivers/media/video/videobuf2-vmalloc.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
- *
- * Copyright (C) 2010 Samsung Electronics
- *
- * Author: Pawel Osciak <pawel@osciak.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.
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-memops.h>
-
-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;
-};
-
-static void vb2_vmalloc_put(void *buf_priv);
-
-static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
-{
- struct vb2_vmalloc_buf *buf;
-
- buf = kzalloc(sizeof(*buf), GFP_KERNEL);
- if (!buf)
- return NULL;
-
- buf->size = size;
- buf->vaddr = vmalloc_user(buf->size);
- buf->handler.refcount = &buf->refcount;
- buf->handler.put = vb2_vmalloc_put;
- buf->handler.arg = buf;
-
- if (!buf->vaddr) {
- pr_debug("vmalloc of size %ld failed\n", buf->size);
- kfree(buf);
- return NULL;
- }
-
- atomic_inc(&buf->refcount);
- return buf;
-}
-
-static void vb2_vmalloc_put(void *buf_priv)
-{
- struct vb2_vmalloc_buf *buf = buf_priv;
-
- if (atomic_dec_and_test(&buf->refcount)) {
- vfree(buf->vaddr);
- kfree(buf);
- }
-}
-
-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);
-}
-
-static void *vb2_vmalloc_vaddr(void *buf_priv)
-{
- struct vb2_vmalloc_buf *buf = buf_priv;
-
- if (!buf->vaddr) {
- pr_err("Address of an unallocated plane requested "
- "or cannot map user pointer\n");
- return NULL;
- }
-
- return buf->vaddr;
-}
-
-static unsigned int vb2_vmalloc_num_users(void *buf_priv)
-{
- struct vb2_vmalloc_buf *buf = buf_priv;
- return atomic_read(&buf->refcount);
-}
-
-static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
-{
- struct vb2_vmalloc_buf *buf = buf_priv;
- int ret;
-
- if (!buf) {
- pr_err("No memory to map\n");
- return -EINVAL;
- }
-
- ret = remap_vmalloc_range(vma, buf->vaddr, 0);
- if (ret) {
- pr_err("Remapping vmalloc memory, error: %d\n", ret);
- return ret;
- }
-
- /*
- * Make sure that vm_areas for 2 buffers won't be merged together
- */
- vma->vm_flags |= VM_DONTEXPAND;
-
- /*
- * Use common vm_area operations to track buffer refcount.
- */
- vma->vm_private_data = &buf->handler;
- vma->vm_ops = &vb2_common_vm_ops;
-
- vma->vm_ops->open(vma);
-
- return 0;
-}
-
-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,
-};
-EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
-
-MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
-MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
deleted file mode 100644
index a05494b71b20..000000000000
--- a/drivers/media/video/vivi.c
+++ /dev/null
@@ -1,1385 +0,0 @@
-/*
- * Virtual Video driver - This code emulates a real video device with v4l2 api
- *
- * Copyright (c) 2006 by:
- * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- * Ted Walther <ted--a.t--enumera.com>
- * John Sokol <sokol--a.t--videotechnology.com>
- * http://v4l.videotechnology.com/
- *
- * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
- * Copyright (c) 2010 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD Licence, 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/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/font.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/videobuf2-vmalloc.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/v4l2-common.h>
-
-#define VIVI_MODULE_NAME "vivi"
-
-/* Wake up at about 30 fps */
-#define WAKE_NUMERATOR 30
-#define WAKE_DENOMINATOR 1001
-#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
-
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
-
-#define VIVI_VERSION "0.8.1"
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(VIVI_VERSION);
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
-
-static unsigned n_devs = 1;
-module_param(n_devs, uint, 0644);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit, uint, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-
-/* Global font descriptor */
-static const u8 *font8x16;
-
-#define dprintk(dev, level, fmt, arg...) \
- v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
-
-/* ------------------------------------------------------------------
- Basic structures
- ------------------------------------------------------------------*/
-
-struct vivi_fmt {
- char *name;
- u32 fourcc; /* v4l2 format id */
- int depth;
-};
-
-static struct vivi_fmt formats[] = {
- {
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- },
- {
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- },
- {
- .name = "4:2:2, packed, YVYU",
- .fourcc = V4L2_PIX_FMT_YVYU,
- .depth = 16,
- },
- {
- .name = "4:2:2, packed, VYUY",
- .fourcc = V4L2_PIX_FMT_VYUY,
- .depth = 16,
- },
- {
- .name = "RGB565 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .depth = 16,
- },
- {
- .name = "RGB565 (BE)",
- .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
- .depth = 16,
- },
- {
- .name = "RGB555 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
- },
- {
- .name = "RGB555 (BE)",
- .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
- .depth = 16,
- },
- {
- .name = "RGB24 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
- .depth = 24,
- },
- {
- .name = "RGB24 (BE)",
- .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
- .depth = 24,
- },
- {
- .name = "RGB32 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
- .depth = 32,
- },
- {
- .name = "RGB32 (BE)",
- .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
- .depth = 32,
- },
-};
-
-static struct vivi_fmt *get_format(struct v4l2_format *f)
-{
- struct vivi_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- fmt = &formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
- break;
- }
-
- if (k == ARRAY_SIZE(formats))
- return NULL;
-
- return &formats[k];
-}
-
-/* buffer for one video frame */
-struct vivi_buffer {
- /* common v4l buffer stuff -- must be first */
- struct vb2_buffer vb;
- struct list_head list;
- struct vivi_fmt *fmt;
-};
-
-struct vivi_dmaqueue {
- struct list_head active;
-
- /* thread for generating video stream*/
- struct task_struct *kthread;
- wait_queue_head_t wq;
- /* Counters to control fps rate */
- int frame;
- int ini_jiffies;
-};
-
-static LIST_HEAD(vivi_devlist);
-
-struct vivi_dev {
- struct list_head vivi_devlist;
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
- struct video_device vdev;
-
- /* controls */
- struct v4l2_ctrl *brightness;
- struct v4l2_ctrl *contrast;
- struct v4l2_ctrl *saturation;
- struct v4l2_ctrl *hue;
- struct {
- /* autogain/gain cluster */
- struct v4l2_ctrl *autogain;
- struct v4l2_ctrl *gain;
- };
- struct v4l2_ctrl *volume;
- struct v4l2_ctrl *alpha;
- struct v4l2_ctrl *button;
- struct v4l2_ctrl *boolean;
- struct v4l2_ctrl *int32;
- struct v4l2_ctrl *int64;
- struct v4l2_ctrl *menu;
- struct v4l2_ctrl *string;
- struct v4l2_ctrl *bitmask;
- struct v4l2_ctrl *int_menu;
-
- spinlock_t slock;
- struct mutex mutex;
-
- struct vivi_dmaqueue vidq;
-
- /* Several counters */
- unsigned ms;
- unsigned long jiffies;
- unsigned button_pressed;
-
- int mv_count; /* Controls bars movement */
-
- /* Input Number */
- int input;
-
- /* video capture */
- struct vivi_fmt *fmt;
- unsigned int width, height;
- struct vb2_queue vb_vidq;
- unsigned int field_count;
-
- u8 bars[9][3];
- u8 line[MAX_WIDTH * 8];
- unsigned int pixelsize;
- u8 alpha_component;
-};
-
-/* ------------------------------------------------------------------
- DMA and thread functions
- ------------------------------------------------------------------*/
-
-/* Bars and Colors should match positions */
-
-enum colors {
- WHITE,
- AMBER,
- CYAN,
- GREEN,
- MAGENTA,
- RED,
- BLUE,
- BLACK,
- TEXT_BLACK,
-};
-
-/* R G B */
-#define COLOR_WHITE {204, 204, 204}
-#define COLOR_AMBER {208, 208, 0}
-#define COLOR_CYAN { 0, 206, 206}
-#define COLOR_GREEN { 0, 239, 0}
-#define COLOR_MAGENTA {239, 0, 239}
-#define COLOR_RED {205, 0, 0}
-#define COLOR_BLUE { 0, 0, 255}
-#define COLOR_BLACK { 0, 0, 0}
-
-struct bar_std {
- u8 bar[9][3];
-};
-
-/* Maximum number of bars are 10 - otherwise, the input print code
- should be modified */
-static struct bar_std bars[] = {
- { /* Standard ITU-R color bar sequence */
- { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
- COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
- }, {
- { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
- COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
- }, {
- { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
- COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
- }, {
- { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
- COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
- },
-};
-
-#define NUM_INPUTS ARRAY_SIZE(bars)
-
-#define TO_Y(r, g, b) \
- (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
-/* RGB to V(Cr) Color transform */
-#define TO_V(r, g, b) \
- (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)
-/* RGB to U(Cb) Color transform */
-#define TO_U(r, g, b) \
- (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
-
-/* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_dev *dev)
-{
- u8 r, g, b;
- int k, is_yuv;
-
- for (k = 0; k < 9; k++) {
- r = bars[dev->input].bar[k][0];
- g = bars[dev->input].bar[k][1];
- b = bars[dev->input].bar[k][2];
- is_yuv = 0;
-
- switch (dev->fmt->fourcc) {
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_VYUY:
- is_yuv = 1;
- break;
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- r >>= 3;
- g >>= 2;
- b >>= 3;
- break;
- case V4L2_PIX_FMT_RGB555:
- case V4L2_PIX_FMT_RGB555X:
- r >>= 3;
- g >>= 3;
- b >>= 3;
- break;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:
- break;
- }
-
- if (is_yuv) {
- dev->bars[k][0] = TO_Y(r, g, b); /* Luma */
- dev->bars[k][1] = TO_U(r, g, b); /* Cb */
- dev->bars[k][2] = TO_V(r, g, b); /* Cr */
- } else {
- dev->bars[k][0] = r;
- dev->bars[k][1] = g;
- dev->bars[k][2] = b;
- }
- }
-}
-
-#define TSTAMP_MIN_Y 24
-#define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15)
-#define TSTAMP_INPUT_X 10
-#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
-
-/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
-{
- u8 r_y, g_u, b_v;
- u8 alpha = dev->alpha_component;
- int color;
- u8 *p;
-
- r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
- g_u = dev->bars[colorpos][1]; /* G or precalculated U */
- b_v = dev->bars[colorpos][2]; /* B or precalculated V */
-
- for (color = 0; color < dev->pixelsize; color++) {
- p = buf + color;
-
- switch (dev->fmt->fourcc) {
- case V4L2_PIX_FMT_YUYV:
- switch (color) {
- case 0:
- *p = r_y;
- break;
- case 1:
- *p = odd ? b_v : g_u;
- break;
- }
- break;
- case V4L2_PIX_FMT_UYVY:
- switch (color) {
- case 0:
- *p = odd ? b_v : g_u;
- break;
- case 1:
- *p = r_y;
- break;
- }
- break;
- case V4L2_PIX_FMT_YVYU:
- switch (color) {
- case 0:
- *p = r_y;
- break;
- case 1:
- *p = odd ? g_u : b_v;
- break;
- }
- break;
- case V4L2_PIX_FMT_VYUY:
- switch (color) {
- case 0:
- *p = odd ? g_u : b_v;
- break;
- case 1:
- *p = r_y;
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB565:
- switch (color) {
- case 0:
- *p = (g_u << 5) | b_v;
- break;
- case 1:
- *p = (r_y << 3) | (g_u >> 3);
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB565X:
- switch (color) {
- case 0:
- *p = (r_y << 3) | (g_u >> 3);
- break;
- case 1:
- *p = (g_u << 5) | b_v;
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB555:
- switch (color) {
- case 0:
- *p = (g_u << 5) | b_v;
- break;
- case 1:
- *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB555X:
- switch (color) {
- case 0:
- *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
- break;
- case 1:
- *p = (g_u << 5) | b_v;
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB24:
- switch (color) {
- case 0:
- *p = r_y;
- break;
- case 1:
- *p = g_u;
- break;
- case 2:
- *p = b_v;
- break;
- }
- break;
- case V4L2_PIX_FMT_BGR24:
- switch (color) {
- case 0:
- *p = b_v;
- break;
- case 1:
- *p = g_u;
- break;
- case 2:
- *p = r_y;
- break;
- }
- break;
- case V4L2_PIX_FMT_RGB32:
- switch (color) {
- case 0:
- *p = alpha;
- break;
- case 1:
- *p = r_y;
- break;
- case 2:
- *p = g_u;
- break;
- case 3:
- *p = b_v;
- break;
- }
- break;
- case V4L2_PIX_FMT_BGR32:
- switch (color) {
- case 0:
- *p = b_v;
- break;
- case 1:
- *p = g_u;
- break;
- case 2:
- *p = r_y;
- break;
- case 3:
- *p = alpha;
- break;
- }
- break;
- }
- }
-}
-
-static void precalculate_line(struct vivi_dev *dev)
-{
- int w;
-
- for (w = 0; w < dev->width * 2; w++) {
- int colorpos = w / (dev->width / 8) % 8;
-
- gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
- }
-}
-
-static void gen_text(struct vivi_dev *dev, char *basep,
- int y, int x, char *text)
-{
- int line;
-
- /* Checks if it is possible to show string */
- if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
- return;
-
- /* Print stream time */
- for (line = y; line < y + 16; line++) {
- int j = 0;
- char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
- char *s;
-
- for (s = text; *s; s++) {
- u8 chr = font8x16[*s * 16 + line - y];
- int i;
-
- for (i = 0; i < 7; i++, j++) {
- /* Draw white font on black background */
- if (chr & (1 << (7 - i)))
- gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
- else
- gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
- }
- }
- }
-}
-
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
-{
- int wmax = dev->width;
- int hmax = dev->height;
- struct timeval ts;
- void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
- unsigned ms;
- char str[100];
- int h, line = 1;
- s32 gain;
-
- if (!vbuf)
- return;
-
- for (h = 0; h < hmax; h++)
- memcpy(vbuf + h * wmax * dev->pixelsize,
- dev->line + (dev->mv_count % wmax) * dev->pixelsize,
- wmax * dev->pixelsize);
-
- /* Updates stream time */
-
- dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
- dev->jiffies = jiffies;
- ms = dev->ms;
- snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
- (ms / (60 * 60 * 1000)) % 24,
- (ms / (60 * 1000)) % 60,
- (ms / 1000) % 60,
- ms % 1000);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " %dx%d, input %d ",
- dev->width, dev->height, dev->input);
- gen_text(dev, vbuf, line++ * 16, 16, str);
-
- gain = v4l2_ctrl_g_ctrl(dev->gain);
- mutex_lock(dev->ctrl_handler.lock);
- snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
- dev->brightness->cur.val,
- dev->contrast->cur.val,
- dev->saturation->cur.val,
- dev->hue->cur.val);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
- dev->autogain->cur.val, gain, dev->volume->cur.val,
- dev->alpha->cur.val);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
- dev->int32->cur.val,
- dev->int64->cur.val64,
- dev->bitmask->cur.val);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
- dev->boolean->cur.val,
- dev->menu->qmenu[dev->menu->cur.val],
- dev->string->cur.string);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
- dev->int_menu->qmenu_int[dev->int_menu->cur.val],
- dev->int_menu->cur.val);
- gen_text(dev, vbuf, line++ * 16, 16, str);
- mutex_unlock(dev->ctrl_handler.lock);
- if (dev->button_pressed) {
- dev->button_pressed--;
- snprintf(str, sizeof(str), " button pressed!");
- gen_text(dev, vbuf, line++ * 16, 16, str);
- }
-
- dev->mv_count += 2;
-
- buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
- dev->field_count++;
- buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
- do_gettimeofday(&ts);
- buf->vb.v4l2_buf.timestamp = ts;
-}
-
-static void vivi_thread_tick(struct vivi_dev *dev)
-{
- struct vivi_dmaqueue *dma_q = &dev->vidq;
- struct vivi_buffer *buf;
- unsigned long flags = 0;
-
- dprintk(dev, 1, "Thread tick\n");
-
- spin_lock_irqsave(&dev->slock, flags);
- if (list_empty(&dma_q->active)) {
- dprintk(dev, 1, "No active queue to serve\n");
- spin_unlock_irqrestore(&dev->slock, flags);
- return;
- }
-
- buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
- list_del(&buf->list);
- spin_unlock_irqrestore(&dev->slock, flags);
-
- do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
-
- /* Fill buffer */
- vivi_fillbuff(dev, buf);
- dprintk(dev, 1, "filled buffer %p\n", buf);
-
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
- dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-}
-
-#define frames_to_ms(frames) \
- ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
-
-static void vivi_sleep(struct vivi_dev *dev)
-{
- struct vivi_dmaqueue *dma_q = &dev->vidq;
- int timeout;
- DECLARE_WAITQUEUE(wait, current);
-
- dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
- (unsigned long)dma_q);
-
- add_wait_queue(&dma_q->wq, &wait);
- if (kthread_should_stop())
- goto stop_task;
-
- /* Calculate time to wake up */
- timeout = msecs_to_jiffies(frames_to_ms(1));
-
- vivi_thread_tick(dev);
-
- schedule_timeout_interruptible(timeout);
-
-stop_task:
- remove_wait_queue(&dma_q->wq, &wait);
- try_to_freeze();
-}
-
-static int vivi_thread(void *data)
-{
- struct vivi_dev *dev = data;
-
- dprintk(dev, 1, "thread started\n");
-
- set_freezable();
-
- for (;;) {
- vivi_sleep(dev);
-
- if (kthread_should_stop())
- break;
- }
- dprintk(dev, 1, "thread: exit\n");
- return 0;
-}
-
-static int vivi_start_generating(struct vivi_dev *dev)
-{
- struct vivi_dmaqueue *dma_q = &dev->vidq;
-
- dprintk(dev, 1, "%s\n", __func__);
-
- /* Resets frame counters */
- dev->ms = 0;
- dev->mv_count = 0;
- dev->jiffies = jiffies;
-
- dma_q->frame = 0;
- dma_q->ini_jiffies = jiffies;
- dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
-
- if (IS_ERR(dma_q->kthread)) {
- v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
- return PTR_ERR(dma_q->kthread);
- }
- /* Wakes thread */
- wake_up_interruptible(&dma_q->wq);
-
- dprintk(dev, 1, "returning from %s\n", __func__);
- return 0;
-}
-
-static void vivi_stop_generating(struct vivi_dev *dev)
-{
- struct vivi_dmaqueue *dma_q = &dev->vidq;
-
- dprintk(dev, 1, "%s\n", __func__);
-
- /* shutdown control thread */
- if (dma_q->kthread) {
- kthread_stop(dma_q->kthread);
- dma_q->kthread = NULL;
- }
-
- /*
- * Typical driver might need to wait here until dma engine stops.
- * In this case we can abort imiedetly, so it's just a noop.
- */
-
- /* Release all active buffers */
- while (!list_empty(&dma_q->active)) {
- struct vivi_buffer *buf;
- buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
- list_del(&buf->list);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
- dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
- }
-}
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vq);
- unsigned long size;
-
- if (fmt)
- size = fmt->fmt.pix.sizeimage;
- else
- size = dev->width * dev->height * dev->pixelsize;
-
- if (size == 0)
- return -EINVAL;
-
- if (0 == *nbuffers)
- *nbuffers = 32;
-
- while (size * *nbuffers > vid_limit * 1024 * 1024)
- (*nbuffers)--;
-
- *nplanes = 1;
-
- sizes[0] = size;
-
- /*
- * videobuf2-vmalloc allocator is context-less so no need to set
- * alloc_ctxs array.
- */
-
- dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
- *nbuffers, size);
-
- return 0;
-}
-
-static int buffer_prepare(struct vb2_buffer *vb)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
- unsigned long size;
-
- dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
-
- BUG_ON(NULL == dev->fmt);
-
- /*
- * Theses properties only change when queue is idle, see s_fmt.
- * The below checks should not be performed here, on each
- * buffer_prepare (i.e. on each qbuf). Most of the code in this function
- * should thus be moved to buffer_init and s_fmt.
- */
- if (dev->width < 48 || dev->width > MAX_WIDTH ||
- dev->height < 32 || dev->height > MAX_HEIGHT)
- return -EINVAL;
-
- size = dev->width * dev->height * dev->pixelsize;
- if (vb2_plane_size(vb, 0) < size) {
- dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
- __func__, vb2_plane_size(vb, 0), size);
- return -EINVAL;
- }
-
- vb2_set_plane_payload(&buf->vb, 0, size);
-
- buf->fmt = dev->fmt;
-
- precalculate_bars(dev);
- precalculate_line(dev);
-
- return 0;
-}
-
-static void buffer_queue(struct vb2_buffer *vb)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
- struct vivi_dmaqueue *vidq = &dev->vidq;
- unsigned long flags = 0;
-
- dprintk(dev, 1, "%s\n", __func__);
-
- spin_lock_irqsave(&dev->slock, flags);
- list_add_tail(&buf->list, &vidq->active);
- spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vq);
- dprintk(dev, 1, "%s\n", __func__);
- return vivi_start_generating(dev);
-}
-
-/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vq);
- dprintk(dev, 1, "%s\n", __func__);
- vivi_stop_generating(dev);
- return 0;
-}
-
-static void vivi_lock(struct vb2_queue *vq)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vq);
- mutex_lock(&dev->mutex);
-}
-
-static void vivi_unlock(struct vb2_queue *vq)
-{
- struct vivi_dev *dev = vb2_get_drv_priv(vq);
- mutex_unlock(&dev->mutex);
-}
-
-
-static struct vb2_ops vivi_video_qops = {
- .queue_setup = queue_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .start_streaming = start_streaming,
- .stop_streaming = stop_streaming,
- .wait_prepare = vivi_unlock,
- .wait_finish = vivi_lock,
-};
-
-/* ------------------------------------------------------------------
- IOCTL vidioc handling
- ------------------------------------------------------------------*/
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- strcpy(cap->driver, "vivi");
- strcpy(cap->card, "vivi");
- strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct vivi_fmt *fmt;
-
- if (f->index >= ARRAY_SIZE(formats))
- return -EINVAL;
-
- fmt = &formats[f->index];
-
- strlcpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.pixelformat = dev->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * dev->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV ||
- dev->fmt->fourcc == V4L2_PIX_FMT_UYVY)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- else
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivi_dev *dev = video_drvdata(file);
- struct vivi_fmt *fmt;
-
- fmt = get_format(f);
- if (!fmt) {
- dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
- f->fmt.pix.pixelformat);
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- fmt = get_format(f);
- }
-
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
- &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- if (fmt->fourcc == V4L2_PIX_FMT_YUYV ||
- fmt->fourcc == V4L2_PIX_FMT_UYVY)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- else
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct vivi_dev *dev = video_drvdata(file);
- struct vb2_queue *q = &dev->vb_vidq;
-
- int ret = vidioc_try_fmt_vid_cap(file, priv, f);
- if (ret < 0)
- return ret;
-
- if (vb2_is_busy(q)) {
- dprintk(dev, 1, "%s device busy\n", __func__);
- return -EBUSY;
- }
-
- dev->fmt = get_format(f);
- dev->pixelsize = dev->fmt->depth / 8;
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
-
- return 0;
-}
-
-/* only one input in this sample driver */
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- if (inp->index >= NUM_INPUTS)
- return -EINVAL;
-
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- sprintf(inp->name, "Camera %u", inp->index);
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- *i = dev->input;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- if (i >= NUM_INPUTS)
- return -EINVAL;
-
- if (i == dev->input)
- return 0;
-
- dev->input = i;
- precalculate_bars(dev);
- precalculate_line(dev);
- return 0;
-}
-
-/* --- controls ---------------------------------------------- */
-
-static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
- if (ctrl == dev->autogain)
- dev->gain->val = jiffies & 0xff;
- return 0;
-}
-
-static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
- switch (ctrl->id) {
- case V4L2_CID_ALPHA_COMPONENT:
- dev->alpha_component = ctrl->val;
- break;
- default:
- if (ctrl == dev->button)
- dev->button_pressed = 30;
- break;
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------
- File operations for the device
- ------------------------------------------------------------------*/
-
-static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
- .g_volatile_ctrl = vivi_g_volatile_ctrl,
- .s_ctrl = vivi_s_ctrl,
-};
-
-#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
-
-static const struct v4l2_ctrl_config vivi_ctrl_button = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 0,
- .name = "Button",
- .type = V4L2_CTRL_TYPE_BUTTON,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 1,
- .name = "Boolean",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 2,
- .name = "Integer 32 Bits",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0x80000000,
- .max = 0x7fffffff,
- .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 3,
- .name = "Integer 64 Bits",
- .type = V4L2_CTRL_TYPE_INTEGER64,
-};
-
-static const char * const vivi_ctrl_menu_strings[] = {
- "Menu Item 0 (Skipped)",
- "Menu Item 1",
- "Menu Item 2 (Skipped)",
- "Menu Item 3",
- "Menu Item 4",
- "Menu Item 5 (Skipped)",
- NULL,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_menu = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 4,
- .name = "Menu",
- .type = V4L2_CTRL_TYPE_MENU,
- .min = 1,
- .max = 4,
- .def = 3,
- .menu_skip_mask = 0x04,
- .qmenu = vivi_ctrl_menu_strings,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_string = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 5,
- .name = "String",
- .type = V4L2_CTRL_TYPE_STRING,
- .min = 2,
- .max = 4,
- .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 6,
- .name = "Bitmask",
- .type = V4L2_CTRL_TYPE_BITMASK,
- .def = 0x80002000,
- .min = 0,
- .max = 0x80402010,
- .step = 0,
-};
-
-static const s64 vivi_ctrl_int_menu_values[] = {
- 1, 1, 2, 3, 5, 8, 13, 21, 42,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
- .ops = &vivi_ctrl_ops,
- .id = VIVI_CID_CUSTOM_BASE + 7,
- .name = "Integer menu",
- .type = V4L2_CTRL_TYPE_INTEGER_MENU,
- .min = 1,
- .max = 8,
- .def = 4,
- .menu_skip_mask = 0x02,
- .qmenu_int = vivi_ctrl_int_menu_values,
-};
-
-static const struct v4l2_file_operations vivi_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .read = vb2_fop_read,
- .poll = vb2_fop_poll,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops vivi_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_reqbufs = vb2_ioctl_reqbufs,
- .vidioc_create_bufs = vb2_ioctl_create_bufs,
- .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
- .vidioc_querybuf = vb2_ioctl_querybuf,
- .vidioc_qbuf = vb2_ioctl_qbuf,
- .vidioc_dqbuf = vb2_ioctl_dqbuf,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vb2_ioctl_streamon,
- .vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static struct video_device vivi_template = {
- .name = "vivi",
- .fops = &vivi_fops,
- .ioctl_ops = &vivi_ioctl_ops,
- .release = video_device_release_empty,
-};
-
-/* -----------------------------------------------------------------
- Initialization and module stuff
- ------------------------------------------------------------------*/
-
-static int vivi_release(void)
-{
- struct vivi_dev *dev;
- struct list_head *list;
-
- while (!list_empty(&vivi_devlist)) {
- list = vivi_devlist.next;
- list_del(list);
- dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
- v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
- video_device_node_name(&dev->vdev));
- video_unregister_device(&dev->vdev);
- v4l2_device_unregister(&dev->v4l2_dev);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- kfree(dev);
- }
-
- return 0;
-}
-
-static int __init vivi_create_instance(int inst)
-{
- struct vivi_dev *dev;
- struct video_device *vfd;
- struct v4l2_ctrl_handler *hdl;
- struct vb2_queue *q;
- int ret;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s-%03d", VIVI_MODULE_NAME, inst);
- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
- if (ret)
- goto free_dev;
-
- dev->fmt = &formats[0];
- dev->width = 640;
- dev->height = 480;
- dev->pixelsize = dev->fmt->depth / 8;
- hdl = &dev->ctrl_handler;
- v4l2_ctrl_handler_init(hdl, 11);
- dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
- dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
- dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 16);
- dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, 127);
- dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_HUE, -128, 127, 1, 0);
- dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_GAIN, 0, 255, 1, 100);
- dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
- dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
- dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
- dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
- dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
- dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
- dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
- dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
- dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
- if (hdl->error) {
- ret = hdl->error;
- goto unreg_dev;
- }
- v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
- dev->v4l2_dev.ctrl_handler = hdl;
-
- /* initialize locks */
- spin_lock_init(&dev->slock);
-
- /* initialize queue */
- q = &dev->vb_vidq;
- memset(q, 0, sizeof(dev->vb_vidq));
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivi_buffer);
- q->ops = &vivi_video_qops;
- q->mem_ops = &vb2_vmalloc_memops;
-
- vb2_queue_init(q);
-
- mutex_init(&dev->mutex);
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- init_waitqueue_head(&dev->vidq.wq);
-
- vfd = &dev->vdev;
- *vfd = vivi_template;
- vfd->debug = debug;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->queue = q;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
-
- /*
- * Provide a mutex to v4l2 core. It will be used to protect
- * all fops and v4l2 ioctls.
- */
- vfd->lock = &dev->mutex;
- video_set_drvdata(vfd, dev);
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
- if (ret < 0)
- goto unreg_dev;
-
- /* Now that everything is fine, let's add it to device list */
- list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
- v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(vfd));
- return 0;
-
-unreg_dev:
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
- kfree(dev);
- return ret;
-}
-
-/* This routine allocates from 1 to n_devs virtual drivers.
-
- The real maximum number of virtual drivers will depend on how many drivers
- will succeed. This is limited to the maximum number of devices that
- videodev supports, which is equal to VIDEO_NUM_DEVICES.
- */
-static int __init vivi_init(void)
-{
- const struct font_desc *font = find_font("VGA8x16");
- int ret = 0, i;
-
- if (font == NULL) {
- printk(KERN_ERR "vivi: could not find font\n");
- return -ENODEV;
- }
- font8x16 = font->data;
-
- if (n_devs <= 0)
- n_devs = 1;
-
- for (i = 0; i < n_devs; i++) {
- ret = vivi_create_instance(i);
- if (ret) {
- /* If some instantiations succeeded, keep driver */
- if (i)
- ret = 0;
- break;
- }
- }
-
- if (ret < 0) {
- printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
- return ret;
- }
-
- printk(KERN_INFO "Video Technology Magazine Virtual Video "
- "Capture Board ver %s successfully loaded.\n",
- VIVI_VERSION);
-
- /* n_devs will reflect the actual number of allocated devices */
- n_devs = i;
-
- return ret;
-}
-
-static void __exit vivi_exit(void)
-{
- vivi_release();
-}
-
-module_init(vivi_init);
-module_exit(vivi_exit);
diff --git a/drivers/media/video/zoran/Kconfig b/drivers/media/video/zoran/Kconfig
deleted file mode 100644
index fd4120e4c104..000000000000
--- a/drivers/media/video/zoran/Kconfig
+++ /dev/null
@@ -1,74 +0,0 @@
-config VIDEO_ZORAN
- tristate "Zoran ZR36057/36067 Video For Linux"
- depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
- help
- Say Y for support for MJPEG capture cards based on the Zoran
- 36057/36067 PCI controller chipset. This includes the Iomega
- Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
- a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
- more information, check <file:Documentation/video4linux/Zoran>.
-
- To compile this driver as a module, choose M here: the
- module will be called zr36067.
-
-config VIDEO_ZORAN_DC30
- tristate "Pinnacle/Miro DC30(+) support"
- depends on VIDEO_ZORAN
- select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
- card. This also supports really old DC10 cards based on the
- zr36050 MJPEG codec and zr36016 VFE.
-
-config VIDEO_ZORAN_ZR36060
- tristate "Zoran ZR36060"
- depends on VIDEO_ZORAN
- help
- Say Y to support Zoran boards based on 36060 chips.
- This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
- and 33 R10 and AverMedia 6 boards.
-
-config VIDEO_ZORAN_BUZ
- tristate "Iomega Buz support"
- depends on VIDEO_ZORAN_ZR36060
- select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the Iomega Buz MJPEG capture/playback card.
-
-config VIDEO_ZORAN_DC10
- tristate "Pinnacle/Miro DC10(+) support"
- depends on VIDEO_ZORAN_ZR36060
- select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
- card.
-
-config VIDEO_ZORAN_LML33
- tristate "Linux Media Labs LML33 support"
- depends on VIDEO_ZORAN_ZR36060
- select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the Linux Media Labs LML33 MJPEG capture/playback
- card.
-
-config VIDEO_ZORAN_LML33R10
- tristate "Linux Media Labs LML33R10 support"
- depends on VIDEO_ZORAN_ZR36060
- select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
- help
- support for the Linux Media Labs LML33R10 MJPEG capture/playback
- card.
-
-config VIDEO_ZORAN_AVS6EYES
- tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
- depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
- select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
- help
- Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 4f4b7d6281a7..427218b8b10f 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -25,8 +25,6 @@ source "drivers/staging/media/cxd2099/Kconfig"
source "drivers/staging/media/dt3155v4l/Kconfig"
-source "drivers/staging/media/easycap/Kconfig"
-
source "drivers/staging/media/go7007/Kconfig"
source "drivers/staging/media/solo6x10/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index c69124cdb0d3..aec6eb963940 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_DVB_AS102) += as102/
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
-obj-$(CONFIG_EASYCAP) += easycap/
obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_SOLO6X10) += solo6x10/
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile
index 1bca43e847c7..d8dfb757f1e2 100644
--- a/drivers/staging/media/as102/Makefile
+++ b/drivers/staging/media/as102/Makefile
@@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
obj-$(CONFIG_DVB_AS102) += dvb-as102.o
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb-core
diff --git a/drivers/staging/media/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile
index 64cfc77be357..b2905e65057c 100644
--- a/drivers/staging/media/cxd2099/Makefile
+++ b/drivers/staging/media/cxd2099/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 1c04185bcfd7..0ff19724992f 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -683,27 +683,26 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
void *priv,
struct i2c_adapter *i2c)
{
- struct cxd *ci = 0;
+ struct cxd *ci;
u8 val;
if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
- return 0;
+ return NULL;
}
- ci = kmalloc(sizeof(struct cxd), GFP_KERNEL);
+ ci = kzalloc(sizeof(struct cxd), GFP_KERNEL);
if (!ci)
- return 0;
- memset(ci, 0, sizeof(*ci));
+ return NULL;
mutex_init(&ci->lock);
- memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
+ ci->cfg = *cfg;
ci->i2c = i2c;
ci->lastaddress = 0xff;
ci->clk_reg_b = 0x4a;
ci->clk_reg_f = 0x1b;
- memcpy(&ci->en, &en_templ, sizeof(en_templ));
+ ci->en = en_templ;
ci->en.data = ci;
init(ci);
printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index ebe5a27c06f5..2e7b711c8501 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -381,6 +381,8 @@ dt3155_open(struct file *filp)
int ret = 0;
struct dt3155_priv *pd = video_drvdata(filp);
+ if (mutex_lock_interruptible(&pd->mux))
+ return -ERESTARTSYS;
if (!pd->users) {
pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL);
if (!pd->q) {
@@ -411,6 +413,7 @@ err_request_irq:
kfree(pd->q);
pd->q = NULL;
err_alloc_queue:
+ mutex_unlock(&pd->mux);
return ret;
}
@@ -419,6 +422,7 @@ dt3155_release(struct file *filp)
{
struct dt3155_priv *pd = video_drvdata(filp);
+ mutex_lock(&pd->mux);
pd->users--;
BUG_ON(pd->users < 0);
if (!pd->users) {
@@ -429,6 +433,7 @@ dt3155_release(struct file *filp)
kfree(pd->q);
pd->q = NULL;
}
+ mutex_unlock(&pd->mux);
return 0;
}
@@ -436,24 +441,38 @@ static ssize_t
dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
{
struct dt3155_priv *pd = video_drvdata(filp);
+ ssize_t res;
- return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
+ if (mutex_lock_interruptible(&pd->mux))
+ return -ERESTARTSYS;
+ res = vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
+ mutex_unlock(&pd->mux);
+ return res;
}
static unsigned int
dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
{
struct dt3155_priv *pd = video_drvdata(filp);
+ unsigned int res;
- return vb2_poll(pd->q, filp, polltbl);
+ mutex_lock(&pd->mux);
+ res = vb2_poll(pd->q, filp, polltbl);
+ mutex_unlock(&pd->mux);
+ return res;
}
static int
dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct dt3155_priv *pd = video_drvdata(filp);
+ int res;
- return vb2_mmap(pd->q, vma);
+ if (mutex_lock_interruptible(&pd->mux))
+ return -ERESTARTSYS;
+ res = vb2_mmap(pd->q, vma);
+ mutex_unlock(&pd->mux);
+ return res;
}
static const struct v4l2_file_operations dt3155_fops = {
@@ -898,10 +917,6 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&pd->dmaq);
mutex_init(&pd->mux);
pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
- /* Locking in file operations other than ioctl should be done
- by the driver, not the V4L2 core.
- This driver needs auditing so that this flag can be removed. */
- set_bit(V4L2_FL_LOCK_ALL_FOPS, &pd->vdev->flags);
spin_lock_init(&pd->lock);
pd->csr2 = csr2_init;
pd->config = config_init;
diff --git a/drivers/staging/media/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig
deleted file mode 100644
index a425a6f9cdca..000000000000
--- a/drivers/staging/media/easycap/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-config EASYCAP
- tristate "EasyCAP USB ID 05e1:0408 support"
- depends on USB && VIDEO_DEV && SND
- select SND_PCM
-
- ---help---
- This is an integrated audio/video driver for EasyCAP cards with
- USB ID 05e1:0408. It supports two hardware variants:
-
- * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
- having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
- * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
- 1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
- To compile this driver as a module, choose M here: the
- module will be called easycap
-
-config EASYCAP_DEBUG
- bool "Enable EasyCAP driver debugging"
- depends on EASYCAP
-
- ---help---
- This option enables debug printouts
-
- To enable debug, pass the debug level to the debug module
- parameter:
-
- modprobe easycap debug=[0..9]
-
diff --git a/drivers/staging/media/easycap/Makefile b/drivers/staging/media/easycap/Makefile
deleted file mode 100644
index a34e75f59c18..000000000000
--- a/drivers/staging/media/easycap/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-easycap-objs := easycap_main.o
-easycap-objs += easycap_low.o
-easycap-objs += easycap_ioctl.o
-easycap-objs += easycap_settings.o
-easycap-objs += easycap_testcard.o
-easycap-objs += easycap_sound.o
-obj-$(CONFIG_EASYCAP) += easycap.o
-
-ccflags-y := -Wall
-
diff --git a/drivers/staging/media/easycap/README b/drivers/staging/media/easycap/README
deleted file mode 100644
index 796b032384bd..000000000000
--- a/drivers/staging/media/easycap/README
+++ /dev/null
@@ -1,141 +0,0 @@
-
- ***********************************************************
- * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60 *
- * and *
- * EasyCAP002 4-Channel USB 2.0 DVR *
- ***********************************************************
- Mike Thomas <rmthomas@sciolus.org>
-
-
-
-SUPPORTED HARDWARE
-------------------
-
-This driver is intended for use with hardware having USB ID 05e1:0408.
-Two kinds of EasyCAP have this USB ID, namely:
-
- * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
- having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
- * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
- 1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
-
-BUILD OPTIONS AND DEPENDENCIES
-------------------------------
-
-Unless EASYCAP_DEBUG is defined during compilation it will not be possible
-to select a debug level at the time of module installation.
-
-
-KNOWN RUNTIME ISSUES
---------------------
-
-(1) Intentionally, this driver will not stream material which is unambiguously
-identified by the hardware as copy-protected. Normal video output will be
-present for about a minute but will then freeze when this situation arises.
-
-(2) The controls for luminance, contrast, saturation, hue and volume may not
-always work properly.
-
-(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
-
-
-INPUT NUMBERING
----------------
-
-For the EasyCAP with S-VIDEO input cable the driver regards a request for
-inputs numbered 0 or 1 as referring to CVBS and a request for input
-numbered 5 as referring to S-VIDEO.
-
-For the EasyCAP with four CVBS inputs the driver expects to be asked for
-any one of inputs numbered 1,2,3,4. If input 0 is asked for, it is
-interpreted as input 1.
-
-
-MODULE PARAMETERS
------------------
-
-Three module parameters are defined:
-
-debug the easycap module is configured at diagnostic level n (0 to 9)
-gain audio gain level n (0 to 31, default is 16)
-bars whether to display testcard bars when incoming video signal is lost
- 0 => no, 1 => yes (default)
-
-
-SUPPORTED TV STANDARDS AND RESOLUTIONS
---------------------------------------
-
-The following TV standards are natively supported by the hardware and are
-usable as (for example) the "norm=" parameter in the mplayer command:
-
- PAL_BGHIN, NTSC_N_443,
- PAL_Nc, NTSC_N,
- SECAM, NTSC_M, NTSC_M_JP,
- PAL_60, NTSC_443,
- PAL_M.
-
-In addition, the driver offers "custom" pseudo-standards with a framerate
-which is 20% of the usual framerate. These pseudo-standards are named:
-
- PAL_BGHIN_SLOW, NTSC_N_443_SLOW,
- PAL_Nc_SLOW, NTSC_N_SLOW,
- SECAM_SLOW, NTSC_M_SLOW, NTSC_M_JP_SLOW,
- PAL_60_SLOW, NTSC_443_SLOW,
- PAL_M_SLOW.
-
-
-The available picture sizes are:
-
- at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240;
- at 30 frames per second: 720x480, 640x480, 360x240, 320x240.
-
-
-WHAT'S TESTED AND WHAT'S NOT
-----------------------------
-
-This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
-xawtv, gstreamer and sufficiently recent versions of vlc. An interface
-to ffmpeg is implemented, but serious audio-video synchronization problems
-remain.
-
-The driver is designed to support all the TV standards accepted by the
-hardware, but as yet it has actually been tested on only a few of these.
-
-I have been unable to test and calibrate the S-video input myself because I
-do not possess any equipment with S-video output.
-
-
-UDEV RULES
-----------
-
-In order that the special files /dev/easycap0 and /dev/easysnd1 are created
-with conveniently relaxed permissions when the EasyCAP is plugged in, a file
-is preferably to be provided in directory /etc/udev/rules.d with content:
-
-ACTION!="add|change", GOTO="easycap_rules_end"
-ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
- MODE="0666", OWNER="root", GROUP="root"
-LABEL="easycap_rules_end"
-
-
-MODPROBE CONFIGURATION
-----------------------
-
-The easycap module is in competition with the module snd-usb-audio for the
-EasyCAP's audio channel, and its installation can be aided by providing a
-file in directory /etc/modprobe.d with content:
-
-options easycap gain=16 bars=1
-install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
-
-
-ACKNOWLEGEMENTS AND REFERENCES
-------------------------------
-This driver makes use of information contained in the Syntek Semicon DC-1125
-Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
-by Nicolas Vivien. Particularly useful has been a patch to the latter driver
-provided by Ivor Hewitt in January 2009. The NTSC implementation is taken
-from the work of Ben Trask.
-
diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h
deleted file mode 100644
index a007e7442be8..000000000000
--- a/drivers/staging/media/easycap/easycap.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/*****************************************************************************
-* *
-* easycap.h *
-* *
-*****************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * THE FOLLOWING PARAMETERS ARE UNDEFINED:
- *
- * EASYCAP_DEBUG
- *
- * IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
- * OPTIONS.
- */
-/*---------------------------------------------------------------------------*/
-
-#ifndef __EASYCAP_H__
-#define __EASYCAP_H__
-
-/*---------------------------------------------------------------------------*/
-/*
- * THESE ARE NORMALLY DEFINED
- */
-/*---------------------------------------------------------------------------*/
-#define PATIENCE 500
-#define PERSEVERE
-/*---------------------------------------------------------------------------*/
-/*
- * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
- */
-/*---------------------------------------------------------------------------*/
-#undef EASYCAP_TESTCARD
-/*---------------------------------------------------------------------------*/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/usb.h>
-#include <linux/uaccess.h>
-
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-
-#include <linux/vmalloc.h>
-#include <linux/sound.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <linux/videodev2.h>
-#include <linux/soundcard.h>
-
-/*---------------------------------------------------------------------------*/
-/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd
- *
- * EITHER EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
- * with input cabling: AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
- *
- * OR EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
- * with input cabling: MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
- */
-/*---------------------------------------------------------------------------*/
-#define USB_EASYCAP_VENDOR_ID 0x05e1
-#define USB_EASYCAP_PRODUCT_ID 0x0408
-
-#define EASYCAP_DRIVER_VERSION "0.9.01"
-#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
-
-#define DONGLE_MANY 8
-#define INPUT_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- * DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
- */
-/*---------------------------------------------------------------------------*/
-#define SAA_0A_DEFAULT 0x7F
-#define SAA_0B_DEFAULT 0x3F
-#define SAA_0C_DEFAULT 0x2F
-#define SAA_0D_DEFAULT 0x00
-/*---------------------------------------------------------------------------*/
-/*
- * VIDEO STREAMING PARAMETERS:
- * USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
- * OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
- */
-/*---------------------------------------------------------------------------*/
-#define VIDEO_ISOC_BUFFER_MANY 16
-#define VIDEO_ISOC_ORDER 3
-#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
-#define USB_2_0_MAXPACKETSIZE 3072
-#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
-#error video_isoc_buffer[.] will not be big enough
-#endif
-#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
-#define VIDEO_LOST_TOLERATE 50
-/*---------------------------------------------------------------------------*/
-/*
- * VIDEO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
-#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
-#define FIELD_BUFFER_MANY 4
-#define FRAME_BUFFER_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- * AUDIO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_ISOC_BUFFER_MANY 16
-#define AUDIO_ISOC_ORDER 1
-#define AUDIO_ISOC_FRAMESPERDESC 32
-#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
-/*---------------------------------------------------------------------------*/
-/*
- * AUDIO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_FRAGMENT_MANY 32
-#define PAGES_PER_AUDIO_FRAGMENT 4
-/*---------------------------------------------------------------------------*/
-/*
- * IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
- * ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
- * THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE. NOT
- * ONLY MUST THE PARAMETER
- * STANDARD_MANY
- * BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
- * NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE: DUMMY STANDARDS
- * MAY NEED TO BE ADDED. APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
- * ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE. BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-#define PAL_BGHIN 0
-#define PAL_Nc 2
-#define SECAM 4
-#define NTSC_N 6
-#define NTSC_N_443 8
-#define NTSC_M 1
-#define NTSC_443 3
-#define NTSC_M_JP 5
-#define PAL_60 7
-#define PAL_M 9
-#define PAL_BGHIN_SLOW 10
-#define PAL_Nc_SLOW 12
-#define SECAM_SLOW 14
-#define NTSC_N_SLOW 16
-#define NTSC_N_443_SLOW 18
-#define NTSC_M_SLOW 11
-#define NTSC_443_SLOW 13
-#define NTSC_M_JP_SLOW 15
-#define PAL_60_SLOW 17
-#define PAL_M_SLOW 19
-#define STANDARD_MANY 20
-/*---------------------------------------------------------------------------*/
-/*
- * ENUMS
- */
-/*---------------------------------------------------------------------------*/
-enum {
- AT_720x576,
- AT_704x576,
- AT_640x480,
- AT_720x480,
- AT_360x288,
- AT_320x240,
- AT_360x240,
- RESOLUTION_MANY
-};
-enum {
- FMT_UYVY,
- FMT_YUY2,
- FMT_RGB24,
- FMT_RGB32,
- FMT_BGR24,
- FMT_BGR32,
- PIXELFORMAT_MANY
-};
-enum {
- FIELD_NONE,
- FIELD_INTERLACED,
- INTERLACE_MANY
-};
-#define SETTINGS_MANY (STANDARD_MANY * \
- RESOLUTION_MANY * \
- 2 * \
- PIXELFORMAT_MANY * \
- INTERLACE_MANY)
-/*---------------------------------------------------------------------------*/
-/*
- * STRUCTURE DEFINITIONS
- */
-/*---------------------------------------------------------------------------*/
-struct easycap_dongle {
- struct easycap *peasycap;
- struct mutex mutex_video;
- struct mutex mutex_audio;
-};
-/*---------------------------------------------------------------------------*/
-struct data_buffer {
- struct list_head list_head;
- void *pgo;
- void *pto;
- u16 kount;
- u16 input;
-};
-/*---------------------------------------------------------------------------*/
-struct data_urb {
- struct list_head list_head;
- struct urb *purb;
- int isbuf;
- int length;
-};
-/*---------------------------------------------------------------------------*/
-struct easycap_standard {
- u16 mask;
-struct v4l2_standard v4l2_standard;
-};
-struct easycap_format {
- u16 mask;
- char name[128];
-struct v4l2_format v4l2_format;
-};
-struct inputset {
- int input;
- int input_ok;
- int standard_offset;
- int standard_offset_ok;
- int format_offset;
- int format_offset_ok;
- int brightness;
- int brightness_ok;
- int contrast;
- int contrast_ok;
- int saturation;
- int saturation_ok;
- int hue;
- int hue_ok;
-};
-/*---------------------------------------------------------------------------*/
-/*
- * easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
- * easycap.ilk == 2 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
- * easycap.ilk == 3 => FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
- */
-/*---------------------------------------------------------------------------*/
-struct easycap {
- int isdongle;
- int minor;
-
- struct video_device video_device;
- struct v4l2_device v4l2_device;
-
- int status;
- unsigned int audio_pages_per_fragment;
- unsigned int audio_bytes_per_fragment;
- unsigned int audio_buffer_page_many;
-
-#define UPSAMPLE
-#ifdef UPSAMPLE
- s16 oldaudio;
-#endif /*UPSAMPLE*/
-
- int ilk;
- bool microphone;
-
- struct usb_device *pusb_device;
- struct usb_interface *pusb_interface;
-
- struct kref kref;
-
- int queued[FRAME_BUFFER_MANY];
- int done[FRAME_BUFFER_MANY];
-
- wait_queue_head_t wq_video;
- wait_queue_head_t wq_audio;
- wait_queue_head_t wq_trigger;
-
- int input;
- int polled;
- int standard_offset;
- int format_offset;
- struct inputset inputset[INPUT_MANY];
-
- bool ntsc;
- int fps;
- int usec;
- int tolerate;
- int skip;
- int skipped;
- int lost[INPUT_MANY];
- int merit[180];
-
- int video_interface;
- int video_altsetting_on;
- int video_altsetting_off;
- int video_endpointnumber;
- int video_isoc_maxframesize;
- int video_isoc_buffer_size;
- int video_isoc_framesperdesc;
-
- int video_isoc_streaming;
- int video_isoc_sequence;
- int video_idle;
- int video_eof;
- int video_junk;
-
- struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
- struct data_buffer field_buffer[FIELD_BUFFER_MANY]
- [(FIELD_BUFFER_SIZE/PAGE_SIZE)];
- struct data_buffer frame_buffer[FRAME_BUFFER_MANY]
- [(FRAME_BUFFER_SIZE/PAGE_SIZE)];
-
- struct list_head urb_video_head;
- struct list_head *purb_video_head;
-
- u8 cache[8];
- u8 *pcache;
- int video_mt;
- int audio_mt;
- u32 isequence;
-
- int vma_many;
-/*---------------------------------------------------------------------------*/
-/*
- * BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
- int field_fill; /* Field buffer being filled by easycap_complete(). */
- /* Bumped only by easycap_complete(). */
- int field_page; /* Page of field buffer page being filled by */
- /* easycap_complete(). */
- int field_read; /* Field buffer to be read by field2frame(). */
- /* Bumped only by easycap_complete(). */
- int frame_fill; /* Frame buffer being filled by field2frame(). */
- /* Bumped only by easycap_dqbuf() when */
- /* field2frame() has created a complete frame. */
- int frame_read; /* Frame buffer offered to user by DQBUF. */
- /* Set only by easycap_dqbuf() to trail frame_fill.*/
- int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */
-/*---------------------------------------------------------------------------*/
-/*
- * IMAGE PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
- u32 pixelformat;
- int width;
- int height;
- int bytesperpixel;
- bool byteswaporder;
- bool decimatepixel;
- bool offerfields;
- int frame_buffer_used;
- int frame_buffer_many;
- int videofieldamount;
-
- int brightness;
- int contrast;
- int saturation;
- int hue;
-
- int allocation_video_urb;
- int allocation_video_page;
- int allocation_video_struct;
- int registered_video;
-/*---------------------------------------------------------------------------*/
-/*
- * ALSA
- */
-/*---------------------------------------------------------------------------*/
- struct snd_pcm_hardware alsa_hardware;
- struct snd_card *psnd_card;
- struct snd_pcm *psnd_pcm;
- struct snd_pcm_substream *psubstream;
- int dma_fill;
- int dma_next;
- int dma_read;
-/*---------------------------------------------------------------------------*/
-/*
- * SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
- int audio_interface;
- int audio_altsetting_on;
- int audio_altsetting_off;
- int audio_endpointnumber;
- int audio_isoc_maxframesize;
- int audio_isoc_buffer_size;
- int audio_isoc_framesperdesc;
-
- int audio_isoc_streaming;
- int audio_idle;
- int audio_eof;
- int volume;
- int mute;
- s8 gain;
-
- struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
-
- struct list_head urb_audio_head;
- struct list_head *purb_audio_head;
-/*---------------------------------------------------------------------------*/
-/*
- * BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
- int audio_fill; /* Audio buffer being filled by easycap_complete(). */
- /* Bumped only by easycap_complete(). */
- int audio_read; /* Audio buffer page being read by easycap_read(). */
- /* Set by easycap_read() to trail audio_fill by */
- /* one fragment. */
-/*---------------------------------------------------------------------------*/
-/*
- * SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
- int allocation_audio_urb;
- int allocation_audio_page;
- int allocation_audio_struct;
- int registered_audio;
-
- long long int audio_sample;
- long long int audio_niveau;
- long long int audio_square;
-
- struct data_buffer audio_buffer[];
-};
-/*---------------------------------------------------------------------------*/
-/*
- * VIDEO FUNCTION PROTOTYPES
- */
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-int easycap_newinput(struct easycap *, int);
-void easycap_testcard(struct easycap *, int);
-int easycap_isdongle(struct easycap *);
-
-long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-
-int easycap_video_dqbuf(struct easycap *, int);
-int easycap_video_submit_urbs(struct easycap *);
-int easycap_video_kill_urbs(struct easycap *);
-int easycap_video_fillin_formats(void);
-
-int adjust_standard(struct easycap *, v4l2_std_id);
-int adjust_format(struct easycap *, u32, u32, u32, int, bool);
-int adjust_brightness(struct easycap *, int);
-int adjust_contrast(struct easycap *, int);
-int adjust_saturation(struct easycap *, int);
-int adjust_hue(struct easycap *, int);
-/*---------------------------------------------------------------------------*/
-/*
- * AUDIO FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int easycap_alsa_probe(struct easycap *);
-int easycap_audio_kill_urbs(struct easycap *);
-void easycap_alsa_complete(struct urb *);
-/*---------------------------------------------------------------------------*/
-/*
- * LOW-LEVEL FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int easycap_audio_gainset(struct usb_device *, s8);
-int easycap_audio_setup(struct easycap *);
-
-int easycap_wakeup_device(struct usb_device *);
-
-int setup_stk(struct usb_device *, bool);
-int setup_saa(struct usb_device *, bool);
-int ready_saa(struct usb_device *);
-int merit_saa(struct usb_device *);
-int check_vt(struct usb_device *);
-int select_input(struct usb_device *, int, int);
-int set_resolution(struct usb_device *, u16, u16, u16, u16);
-
-int read_saa(struct usb_device *, u16);
-int write_saa(struct usb_device *, u16, u16);
-int start_100(struct usb_device *);
-int stop_100(struct usb_device *);
-/*---------------------------------------------------------------------------*/
-
-
-/*---------------------------------------------------------------------------*/
-/*
- * MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
- * THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
- * POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
- * IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE. BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-const char *strerror(int err);
-
-#define SAY(format, args...) do { \
- printk(KERN_DEBUG "easycap:: %s: " \
- format, __func__, ##args); \
-} while (0)
-#define SAM(format, args...) do { \
- printk(KERN_DEBUG "easycap::%i%s: " \
- format, peasycap->isdongle, __func__, ##args);\
-} while (0)
-
-#ifdef CONFIG_EASYCAP_DEBUG
-extern int easycap_debug;
-#define JOT(n, format, args...) do { \
- if (n <= easycap_debug) { \
- printk(KERN_DEBUG "easycap:: %s: " \
- format, __func__, ##args);\
- } \
-} while (0)
-#define JOM(n, format, args...) do { \
- if (n <= easycap_debug) { \
- printk(KERN_DEBUG "easycap::%i%s: " \
- format, peasycap->isdongle, __func__, ##args);\
- } \
-} while (0)
-
-#else
-#define JOT(n, format, args...) do {} while (0)
-#define JOM(n, format, args...) do {} while (0)
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-/*---------------------------------------------------------------------------*/
-
-/*---------------------------------------------------------------------------*/
-/* globals
- */
-/*---------------------------------------------------------------------------*/
-
-extern bool easycap_readback;
-extern const struct easycap_standard easycap_standard[];
-extern struct easycap_format easycap_format[];
-extern struct v4l2_queryctrl easycap_control[];
-extern struct easycap_dongle easycapdc60_dongle[];
-
-#endif /* !__EASYCAP_H__ */
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
deleted file mode 100644
index 3cee3cd986d2..000000000000
--- a/drivers/staging/media/easycap/easycap_ioctl.c
+++ /dev/null
@@ -1,2443 +0,0 @@
-/******************************************************************************
-* *
-* easycap_ioctl.c *
-* *
-******************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-#include <linux/version.h>
-
-/*--------------------------------------------------------------------------*/
-/*
- * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
- * FOLLOWING:
- * peasycap->standard_offset
- * peasycap->inputset[peasycap->input].standard_offset
- * peasycap->fps
- * peasycap->usec
- * peasycap->tolerate
- * peasycap->skip
- */
-/*---------------------------------------------------------------------------*/
-int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
-{
- struct easycap_standard const *peasycap_standard;
- u16 reg, set;
- int ir, rc, need, k;
- unsigned int itwas, isnow;
- bool resubmit;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- peasycap_standard = &easycap_standard[0];
- while (0xFFFF != peasycap_standard->mask) {
- if (std_id == peasycap_standard->v4l2_standard.id)
- break;
- peasycap_standard++;
- }
- if (0xFFFF == peasycap_standard->mask) {
- peasycap_standard = &easycap_standard[0];
- while (0xFFFF != peasycap_standard->mask) {
- if (std_id & peasycap_standard->v4l2_standard.id)
- break;
- peasycap_standard++;
- }
- }
- if (0xFFFF == peasycap_standard->mask) {
- SAM("ERROR: 0x%08X=std_id: standard not found\n",
- (unsigned int)std_id);
- return -EINVAL;
- }
- SAM("selected standard: %s\n",
- &(peasycap_standard->v4l2_standard.name[0]));
- if (peasycap->standard_offset == peasycap_standard - easycap_standard) {
- SAM("requested standard already in effect\n");
- return 0;
- }
- peasycap->standard_offset = peasycap_standard - easycap_standard;
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].standard_offset_ok) {
- peasycap->inputset[k].standard_offset =
- peasycap->standard_offset;
- }
- }
- if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
- peasycap->inputset[peasycap->input].standard_offset =
- peasycap->standard_offset;
- peasycap->inputset[peasycap->input].standard_offset_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
-
- peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator /
- peasycap_standard->v4l2_standard.frameperiod.numerator;
- switch (peasycap->fps) {
- case 6:
- case 30: {
- peasycap->ntsc = true;
- break;
- }
- case 5:
- case 25: {
- peasycap->ntsc = false;
- break;
- }
- default: {
- SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
- return -ENOENT;
- }
- }
- JOM(8, "%i frames-per-second\n", peasycap->fps);
- if (0x8000 & peasycap_standard->mask) {
- peasycap->skip = 5;
- peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
- peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
- } else {
- peasycap->skip = 0;
- peasycap->usec = 1000000 / (2 * peasycap->fps);
- peasycap->tolerate = 1000 * (25 / peasycap->fps);
- }
- if (peasycap->video_isoc_streaming) {
- resubmit = true;
- easycap_video_kill_urbs(peasycap);
- } else
- resubmit = false;
-/*--------------------------------------------------------------------------*/
-/*
- * SAA7113H DATASHEET PAGE 44, TABLE 42
- */
-/*--------------------------------------------------------------------------*/
- need = 0;
- itwas = 0;
- reg = 0x00;
- set = 0x00;
- switch (peasycap_standard->mask & 0x000F) {
- case NTSC_M_JP: {
- reg = 0x0A;
- set = 0x95;
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
- else
- itwas = (unsigned int)ir;
- rc = write_saa(peasycap->pusb_device, reg, set);
- if (rc)
- SAM("ERROR: failed to set SAA register "
- "0x%02X to 0x%02X for JP standard\n", reg, set);
- else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed "
- "to 0x%02X\n", reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
-
- reg = 0x0B;
- set = 0x48;
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
- else
- itwas = (unsigned int)ir;
- rc = write_saa(peasycap->pusb_device, reg, set);
- if (rc)
- SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X "
- "for JP standard\n", reg, set);
- else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed "
- "to 0x%02X\n", reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
-/*--------------------------------------------------------------------------*/
-/*
- * NOTE: NO break HERE: RUN ON TO NEXT CASE
- */
-/*--------------------------------------------------------------------------*/
- }
- case NTSC_M:
- case PAL_BGHIN: {
- reg = 0x0E;
- set = 0x01;
- need = 1;
- break;
- }
- case NTSC_N_443:
- case PAL_60: {
- reg = 0x0E;
- set = 0x11;
- need = 1;
- break;
- }
- case NTSC_443:
- case PAL_Nc: {
- reg = 0x0E;
- set = 0x21;
- need = 1;
- break;
- }
- case NTSC_N:
- case PAL_M: {
- reg = 0x0E;
- set = 0x31;
- need = 1;
- break;
- }
- case SECAM: {
- reg = 0x0E;
- set = 0x51;
- need = 1;
- break;
- }
- default:
- break;
- }
-/*--------------------------------------------------------------------------*/
- if (need) {
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
- else
- itwas = (unsigned int)ir;
- rc = write_saa(peasycap->pusb_device, reg, set);
- if (0 != write_saa(peasycap->pusb_device, reg, set)) {
- SAM("ERROR: failed to set SAA register "
- "0x%02X to 0x%02X for table 42\n", reg, set);
- } else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed "
- "to 0x%02X\n", reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
- }
-/*--------------------------------------------------------------------------*/
-/*
- * SAA7113H DATASHEET PAGE 41
- */
-/*--------------------------------------------------------------------------*/
- reg = 0x08;
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: failed to read SAA register 0x%02X "
- "so cannot reset\n", reg);
- else {
- itwas = (unsigned int)ir;
- if (peasycap_standard->mask & 0x0001)
- set = itwas | 0x40 ;
- else
- set = itwas & ~0x40 ;
- rc = write_saa(peasycap->pusb_device, reg, set);
- if (rc)
- SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
- reg, set);
- else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
- reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
- }
-/*--------------------------------------------------------------------------*/
-/*
- * SAA7113H DATASHEET PAGE 51, TABLE 57
- */
-/*---------------------------------------------------------------------------*/
- reg = 0x40;
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: failed to read SAA register 0x%02X "
- "so cannot reset\n", reg);
- else {
- itwas = (unsigned int)ir;
- if (peasycap_standard->mask & 0x0001)
- set = itwas | 0x80 ;
- else
- set = itwas & ~0x80 ;
- rc = write_saa(peasycap->pusb_device, reg, set);
- if (rc)
- SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
- reg, set);
- else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
- reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
- }
-/*--------------------------------------------------------------------------*/
-/*
- * SAA7113H DATASHEET PAGE 53, TABLE 66
- */
-/*--------------------------------------------------------------------------*/
- reg = 0x5A;
- ir = read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
- itwas = (unsigned int)ir;
- if (peasycap_standard->mask & 0x0001)
- set = 0x0A ;
- else
- set = 0x07 ;
- if (0 != write_saa(peasycap->pusb_device, reg, set))
- SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
- reg, set);
- else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOM(8, "SAA register 0x%02X changed "
- "to 0x%02X\n", reg, isnow);
- else
- JOM(8, "SAA register 0x%02X changed "
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
- }
- if (resubmit)
- easycap_video_submit_urbs(peasycap);
- return 0;
-}
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
- * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
- *
- * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
- * THIS ROUTINE UPDATES THE FOLLOWING:
- * peasycap->format_offset
- * peasycap->inputset[peasycap->input].format_offset
- * peasycap->pixelformat
- * peasycap->height
- * peasycap->width
- * peasycap->bytesperpixel
- * peasycap->byteswaporder
- * peasycap->decimatepixel
- * peasycap->frame_buffer_used
- * peasycap->videofieldamount
- * peasycap->offerfields
- *
- * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
- * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
- * ERRORS RETURN A NEGATIVE NUMBER.
- */
-/*--------------------------------------------------------------------------*/
-int adjust_format(struct easycap *peasycap,
- u32 width, u32 height, u32 pixelformat, int field, bool try)
-{
- struct easycap_format *peasycap_format, *peasycap_best_format;
- u16 mask;
- struct usb_device *p;
- int miss, multiplier, best, k;
- char bf[5], fo[32], *pc;
- u32 uc;
- bool resubmit;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (0 > peasycap->standard_offset) {
- JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
- return -EBUSY;
- }
- p = peasycap->pusb_device;
- if (!p) {
- SAM("ERROR: peaycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- pc = &bf[0];
- uc = pixelformat;
- memcpy((void *)pc, (void *)(&uc), 4);
- bf[4] = 0;
- mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
- SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n",
- width, height, pc, pixelformat, field, mask);
- switch (field) {
- case V4L2_FIELD_ANY: {
- strcpy(&fo[0], "V4L2_FIELD_ANY ");
- break;
- }
- case V4L2_FIELD_NONE: {
- strcpy(&fo[0], "V4L2_FIELD_NONE");
- break;
- }
- case V4L2_FIELD_TOP: {
- strcpy(&fo[0], "V4L2_FIELD_TOP");
- break;
- }
- case V4L2_FIELD_BOTTOM: {
- strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
- break;
- }
- case V4L2_FIELD_INTERLACED: {
- strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
- break;
- }
- case V4L2_FIELD_SEQ_TB: {
- strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
- break;
- }
- case V4L2_FIELD_SEQ_BT: {
- strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
- break;
- }
- case V4L2_FIELD_ALTERNATE: {
- strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
- break;
- }
- case V4L2_FIELD_INTERLACED_TB: {
- strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
- break;
- }
- case V4L2_FIELD_INTERLACED_BT: {
- strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
- break;
- }
- default: {
- strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN ");
- break;
- }
- }
- SAM("sought: %s\n", &fo[0]);
- if (V4L2_FIELD_ANY == field) {
- field = V4L2_FIELD_NONE;
- SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
- }
- peasycap_best_format = NULL;
- peasycap_format = &easycap_format[0];
- while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
- JOM(16, ".> %i %i 0x%08X %ix%i\n",
- peasycap_format->mask & 0x01,
- peasycap_format->v4l2_format.fmt.pix.field,
- peasycap_format->v4l2_format.fmt.pix.pixelformat,
- peasycap_format->v4l2_format.fmt.pix.width,
- peasycap_format->v4l2_format.fmt.pix.height);
-
- if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
- (peasycap_format->v4l2_format.fmt.pix.field == field) &&
- (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) &&
- (peasycap_format->v4l2_format.fmt.pix.width == width) &&
- (peasycap_format->v4l2_format.fmt.pix.height == height)) {
-
- peasycap_best_format = peasycap_format;
- break;
- }
- peasycap_format++;
- }
- if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
- SAM("cannot do: %ix%i with standard mask 0x%02X\n",
- width, height, mask);
- peasycap_format = &easycap_format[0];
- best = -1;
- while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
- if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
- (peasycap_format->v4l2_format.fmt.pix.field == field) &&
- (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) {
-
- miss = abs(peasycap_format->v4l2_format.fmt.pix.width - width);
- if ((best > miss) || (best < 0)) {
- best = miss;
- peasycap_best_format = peasycap_format;
- if (!miss)
- break;
- }
- }
- peasycap_format++;
- }
- if (-1 == best) {
- SAM("cannot do %ix... with standard mask 0x%02X\n",
- width, mask);
- SAM("cannot do ...x%i with standard mask 0x%02X\n",
- height, mask);
- SAM(" %ix%i unmatched\n", width, height);
- return peasycap->format_offset;
- }
- }
- if (!peasycap_best_format) {
- SAM("MISTAKE: peasycap_best_format is NULL");
- return -EINVAL;
- }
- peasycap_format = peasycap_best_format;
-
-/*...........................................................................*/
- if (try)
- return peasycap_best_format - easycap_format;
-/*...........................................................................*/
-
- if (false != try) {
- SAM("MISTAKE: true==try where is should be false\n");
- return -EINVAL;
- }
- SAM("actioning: %ix%i %s\n",
- peasycap_format->v4l2_format.fmt.pix.width,
- peasycap_format->v4l2_format.fmt.pix.height,
- &peasycap_format->name[0]);
- peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
- peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
- peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
- peasycap->format_offset = peasycap_format - easycap_format;
-
-
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].format_offset_ok) {
- peasycap->inputset[k].format_offset =
- peasycap->format_offset;
- }
- }
- if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
- peasycap->inputset[peasycap->input].format_offset =
- peasycap->format_offset;
- peasycap->inputset[peasycap->input].format_offset_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-
-
- peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
- if (0x0100 & peasycap_format->mask)
- peasycap->byteswaporder = true;
- else
- peasycap->byteswaporder = false;
- if (0x0200 & peasycap_format->mask)
- peasycap->skip = 5;
- else
- peasycap->skip = 0;
- if (0x0800 & peasycap_format->mask)
- peasycap->decimatepixel = true;
- else
- peasycap->decimatepixel = false;
- if (0x1000 & peasycap_format->mask)
- peasycap->offerfields = true;
- else
- peasycap->offerfields = false;
- if (peasycap->decimatepixel)
- multiplier = 2;
- else
- multiplier = 1;
- peasycap->videofieldamount =
- multiplier * peasycap->width * multiplier * peasycap->height;
- peasycap->frame_buffer_used =
- peasycap->bytesperpixel * peasycap->width * peasycap->height;
- if (peasycap->video_isoc_streaming) {
- resubmit = true;
- easycap_video_kill_urbs(peasycap);
- } else
- resubmit = false;
-/*---------------------------------------------------------------------------*/
-/*
- * PAL
- */
-/*---------------------------------------------------------------------------*/
- if (0 == (0x01 & peasycap_format->mask)) {
- if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (576 == peasycap_format->v4l2_format.fmt.pix.height)) ||
- ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (288 == peasycap_format->v4l2_format.fmt.pix.height))) {
- if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
- SAM("ERROR: set_resolution() failed\n");
- return -EINVAL;
- }
- } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
- if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
- SAM("ERROR: set_resolution() failed\n");
- return -EINVAL;
- }
- } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
- ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
- if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
- SAM("ERROR: set_resolution() failed\n");
- return -EINVAL;
- }
- } else {
- SAM("MISTAKE: bad format, cannot set resolution\n");
- return -EINVAL;
- }
-/*---------------------------------------------------------------------------*/
-/*
- * NTSC
- */
-/*---------------------------------------------------------------------------*/
- } else {
- if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
- ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
- if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
- SAM("ERROR: set_resolution() failed\n");
- return -EINVAL;
- }
- } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
- ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
- (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
- if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
- SAM("ERROR: set_resolution() failed\n");
- return -EINVAL;
- }
- } else {
- SAM("MISTAKE: bad format, cannot set resolution\n");
- return -EINVAL;
- }
- }
-/*---------------------------------------------------------------------------*/
- if (resubmit)
- easycap_video_submit_urbs(peasycap);
-
- return peasycap_best_format - easycap_format;
-}
-/*****************************************************************************/
-int adjust_brightness(struct easycap *peasycap, int value)
-{
- unsigned int mood;
- int i1, k;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
- if ((easycap_control[i1].minimum > value) ||
- (easycap_control[i1].maximum < value))
- value = easycap_control[i1].default_value;
-
- if ((easycap_control[i1].minimum <= peasycap->brightness) &&
- (easycap_control[i1].maximum >= peasycap->brightness)) {
- if (peasycap->brightness == value) {
- SAM("unchanged brightness at 0x%02X\n",
- value);
- return 0;
- }
- }
- peasycap->brightness = value;
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].brightness_ok)
- peasycap->inputset[k].brightness =
- peasycap->brightness;
- }
- if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
- peasycap->inputset[peasycap->input].brightness =
- peasycap->brightness;
- peasycap->inputset[peasycap->input].brightness_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
-
- mood = 0x00FF & (unsigned int)peasycap->brightness;
- if (write_saa(peasycap->pusb_device, 0x0A, mood)) {
- SAM("WARNING: failed to adjust brightness "
- "to 0x%02X\n", mood);
- return -ENOENT;
- }
- SAM("adjusting brightness to 0x%02X\n", mood);
- return 0;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust brightness: control not found\n");
- return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_contrast(struct easycap *peasycap, int value)
-{
- unsigned int mood;
- int i1, k;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
- if ((easycap_control[i1].minimum > value) ||
- (easycap_control[i1].maximum < value))
- value = easycap_control[i1].default_value;
-
-
- if ((easycap_control[i1].minimum <= peasycap->contrast) &&
- (easycap_control[i1].maximum >= peasycap->contrast)) {
- if (peasycap->contrast == value) {
- SAM("unchanged contrast at 0x%02X\n", value);
- return 0;
- }
- }
- peasycap->contrast = value;
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].contrast_ok)
- peasycap->inputset[k].contrast = peasycap->contrast;
- }
-
- if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
- peasycap->inputset[peasycap->input].contrast =
- peasycap->contrast;
- peasycap->inputset[peasycap->input].contrast_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
-
- mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
- if (write_saa(peasycap->pusb_device, 0x0B, mood)) {
- SAM("WARNING: failed to adjust contrast to "
- "0x%02X\n", mood);
- return -ENOENT;
- }
- SAM("adjusting contrast to 0x%02X\n", mood);
- return 0;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust contrast: control not found\n");
- return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_saturation(struct easycap *peasycap, int value)
-{
- unsigned int mood;
- int i1, k;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_SATURATION == easycap_control[i1].id) {
- if ((easycap_control[i1].minimum > value) ||
- (easycap_control[i1].maximum < value))
- value = easycap_control[i1].default_value;
-
-
- if ((easycap_control[i1].minimum <= peasycap->saturation) &&
- (easycap_control[i1].maximum >= peasycap->saturation)) {
- if (peasycap->saturation == value) {
- SAM("unchanged saturation at 0x%02X\n",
- value);
- return 0;
- }
- }
- peasycap->saturation = value;
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].saturation_ok)
- peasycap->inputset[k].saturation =
- peasycap->saturation;
- }
- if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
- peasycap->inputset[peasycap->input].saturation =
- peasycap->saturation;
- peasycap->inputset[peasycap->input].saturation_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
- mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
- if (write_saa(peasycap->pusb_device, 0x0C, mood)) {
- SAM("WARNING: failed to adjust saturation to "
- "0x%02X\n", mood);
- return -ENOENT;
- }
- SAM("adjusting saturation to 0x%02X\n", mood);
- return 0;
- break;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust saturation: control not found\n");
- return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_hue(struct easycap *peasycap, int value)
-{
- unsigned int mood;
- int i1, i2, k;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_HUE == easycap_control[i1].id) {
- if ((easycap_control[i1].minimum > value) ||
- (easycap_control[i1].maximum < value))
- value = easycap_control[i1].default_value;
-
- if ((easycap_control[i1].minimum <= peasycap->hue) &&
- (easycap_control[i1].maximum >= peasycap->hue)) {
- if (peasycap->hue == value) {
- SAM("unchanged hue at 0x%02X\n", value);
- return 0;
- }
- }
- peasycap->hue = value;
- for (k = 0; k < INPUT_MANY; k++) {
- if (!peasycap->inputset[k].hue_ok)
- peasycap->inputset[k].hue = peasycap->hue;
- }
- if (0 <= peasycap->input && INPUT_MANY > peasycap->input) {
- peasycap->inputset[peasycap->input].hue = peasycap->hue;
- peasycap->inputset[peasycap->input].hue_ok = 1;
- } else
- JOM(8, "%i=peasycap->input\n", peasycap->input);
- i2 = peasycap->hue - 128;
- mood = 0x00FF & ((int) i2);
- if (write_saa(peasycap->pusb_device, 0x0D, mood)) {
- SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
- return -ENOENT;
- }
- SAM("adjusting hue to 0x%02X\n", mood);
- return 0;
- break;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust hue: control not found\n");
- return -ENOENT;
-}
-/*****************************************************************************/
-static int adjust_volume(struct easycap *peasycap, int value)
-{
- s8 mood;
- int i1;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
- if ((easycap_control[i1].minimum > value) ||
- (easycap_control[i1].maximum < value))
- value = easycap_control[i1].default_value;
-
- if ((easycap_control[i1].minimum <= peasycap->volume) &&
- (easycap_control[i1].maximum >= peasycap->volume)) {
- if (peasycap->volume == value) {
- SAM("unchanged volume at 0x%02X\n", value);
- return 0;
- }
- }
- peasycap->volume = value;
- mood = (16 > peasycap->volume) ? 16 :
- ((31 < peasycap->volume) ? 31 :
- (s8) peasycap->volume);
- if (!easycap_audio_gainset(peasycap->pusb_device, mood)) {
- SAM("WARNING: failed to adjust volume to "
- "0x%2X\n", mood);
- return -ENOENT;
- }
- SAM("adjusting volume to 0x%02X\n", mood);
- return 0;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust volume: control not found\n");
- return -ENOENT;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
- * usb_set_interface(peasycap->pusb_device,
- * peasycap->audio_interface,
- * peasycap->audio_altsetting_off);
- * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
- * -ESHUTDOWN. THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
- * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int adjust_mute(struct easycap *peasycap, int value)
-{
- int i1;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
- peasycap->mute = value;
- switch (peasycap->mute) {
- case 1: {
- peasycap->audio_idle = 1;
- SAM("adjusting mute: %i=peasycap->audio_idle\n",
- peasycap->audio_idle);
- return 0;
- }
- default: {
- peasycap->audio_idle = 0;
- SAM("adjusting mute: %i=peasycap->audio_idle\n",
- peasycap->audio_idle);
- return 0;
- }
- }
- break;
- }
- i1++;
- }
- SAM("WARNING: failed to adjust mute: control not found\n");
- return -ENOENT;
-}
-/*---------------------------------------------------------------------------*/
-long easycap_unlocked_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct easycap *peasycap;
- struct usb_device *p;
- int kd;
-
- if (!file) {
- SAY("ERROR: file is NULL\n");
- return -ERESTARTSYS;
- }
- peasycap = file->private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -1;
- }
- p = peasycap->pusb_device;
- if (!p) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- kd = easycap_isdongle(peasycap);
- if (0 <= kd && DONGLE_MANY > kd) {
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
- SAY("ERROR: cannot lock "
- "easycapdc60_dongle[%i].mutex_video\n", kd);
- return -ERESTARTSYS;
- }
- JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
-/*---------------------------------------------------------------------------*/
-/*
- * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
- * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
- * IF NECESSARY, BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
- if (kd != easycap_isdongle(peasycap))
- return -ERESTARTSYS;
- if (!file) {
- SAY("ERROR: file is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- peasycap = file->private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- } else {
-/*---------------------------------------------------------------------------*/
-/*
- * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
- * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
- return -ERESTARTSYS;
- }
-/*---------------------------------------------------------------------------*/
- switch (cmd) {
- case VIDIOC_QUERYCAP: {
- struct v4l2_capability v4l2_capability;
- char version[16], *p1, *p2;
- int i, rc, k[3];
- long lng;
-
- JOM(8, "VIDIOC_QUERYCAP\n");
-
- if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
- SAM("ERROR: bad driver version string\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- strcpy(&version[0], EASYCAP_DRIVER_VERSION);
- for (i = 0; i < 3; i++)
- k[i] = 0;
- p2 = &version[0];
- i = 0;
- while (*p2) {
- p1 = p2;
- while (*p2 && ('.' != *p2))
- p2++;
- if (*p2)
- *p2++ = 0;
- if (3 > i) {
- rc = (int) strict_strtol(p1, 10, &lng);
- if (rc) {
- SAM("ERROR: %i=strict_strtol(%s,.,,)\n",
- rc, p1);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- k[i] = (int)lng;
- }
- i++;
- }
-
- memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
- strlcpy(&v4l2_capability.driver[0],
- "easycap", sizeof(v4l2_capability.driver));
-
- v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE;
-
- v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
- JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
-
- strlcpy(&v4l2_capability.card[0],
- "EasyCAP DC60", sizeof(v4l2_capability.card));
-
- if (usb_make_path(peasycap->pusb_device,
- &v4l2_capability.bus_info[0],
- sizeof(v4l2_capability.bus_info)) < 0) {
-
- strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info",
- sizeof(v4l2_capability.bus_info));
- JOM(8, "%s=v4l2_capability.bus_info\n",
- &v4l2_capability.bus_info[0]);
- }
- if (copy_to_user((void __user *)arg, &v4l2_capability,
- sizeof(struct v4l2_capability))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUMINPUT: {
- struct v4l2_input v4l2_input;
- u32 index;
-
- JOM(8, "VIDIOC_ENUMINPUT\n");
-
- if (copy_from_user(&v4l2_input, (void __user *)arg,
- sizeof(struct v4l2_input))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- index = v4l2_input.index;
- memset(&v4l2_input, 0, sizeof(struct v4l2_input));
-
- switch (index) {
- case 0: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "CVBS0");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL |
- V4L2_STD_SECAM |
- V4L2_STD_NTSC ;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- case 1: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "CVBS1");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
- V4L2_STD_NTSC;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- case 2: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "CVBS2");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
- V4L2_STD_NTSC ;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- case 3: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "CVBS3");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
- V4L2_STD_NTSC ;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- case 4: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "CVBS4");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
- V4L2_STD_NTSC ;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- case 5: {
- v4l2_input.index = index;
- strcpy(&v4l2_input.name[0], "S-VIDEO");
- v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
- v4l2_input.audioset = 0x01;
- v4l2_input.tuner = 0;
- v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
- V4L2_STD_NTSC ;
- v4l2_input.status = 0;
- JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
- break;
- }
- default: {
- JOM(8, "%i=index: exhausts inputs\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
-
- if (copy_to_user((void __user *)arg, &v4l2_input,
- sizeof(struct v4l2_input))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_INPUT: {
- u32 index;
-
- JOM(8, "VIDIOC_G_INPUT\n");
- index = (u32)peasycap->input;
- JOM(8, "user is told: %i\n", index);
- if (copy_to_user((void __user *)arg, &index, sizeof(u32))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_INPUT:
- {
- u32 index;
- int rc;
-
- JOM(8, "VIDIOC_S_INPUT\n");
-
- if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- JOM(8, "user requests input %i\n", index);
-
- if ((int)index == peasycap->input) {
- SAM("requested input already in effect\n");
- break;
- }
-
- if ((0 > index) || (INPUT_MANY <= index)) {
- JOM(8, "ERROR: bad requested input: %i\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-
- rc = easycap_newinput(peasycap, (int)index);
- if (0 == rc) {
- JOM(8, "newinput(.,%i) OK\n", (int)index);
- } else {
- SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUMAUDIO: {
- JOM(8, "VIDIOC_ENUMAUDIO\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUMAUDOUT: {
- struct v4l2_audioout v4l2_audioout;
-
- JOM(8, "VIDIOC_ENUMAUDOUT\n");
-
- if (copy_from_user(&v4l2_audioout, (void __user *)arg,
- sizeof(struct v4l2_audioout))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (0 != v4l2_audioout.index) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
- v4l2_audioout.index = 0;
- strcpy(&v4l2_audioout.name[0], "Soundtrack");
-
- if (copy_to_user((void __user *)arg, &v4l2_audioout,
- sizeof(struct v4l2_audioout))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_QUERYCTRL: {
- int i1;
- struct v4l2_queryctrl v4l2_queryctrl;
-
- JOM(8, "VIDIOC_QUERYCTRL\n");
-
- if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg,
- sizeof(struct v4l2_queryctrl))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- i1 = 0;
- while (0xFFFFFFFF != easycap_control[i1].id) {
- if (easycap_control[i1].id == v4l2_queryctrl.id) {
- JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]"
- ".name\n", &easycap_control[i1].name[0], i1);
- memcpy(&v4l2_queryctrl, &easycap_control[i1],
- sizeof(struct v4l2_queryctrl));
- break;
- }
- i1++;
- }
- if (0xFFFFFFFF == easycap_control[i1].id) {
- JOM(8, "%i=index: exhausts controls\n", i1);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- if (copy_to_user((void __user *)arg, &v4l2_queryctrl,
- sizeof(struct v4l2_queryctrl))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_QUERYMENU: {
- JOM(8, "VIDIOC_QUERYMENU unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_CTRL: {
- struct v4l2_control *pv4l2_control;
-
- JOM(8, "VIDIOC_G_CTRL\n");
- pv4l2_control = memdup_user((void __user *)arg,
- sizeof(struct v4l2_control));
- if (IS_ERR(pv4l2_control)) {
- SAM("ERROR: copy from user failed\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return PTR_ERR(pv4l2_control);
- }
-
- switch (pv4l2_control->id) {
- case V4L2_CID_BRIGHTNESS: {
- pv4l2_control->value = peasycap->brightness;
- JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
- break;
- }
- case V4L2_CID_CONTRAST: {
- pv4l2_control->value = peasycap->contrast;
- JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
- break;
- }
- case V4L2_CID_SATURATION: {
- pv4l2_control->value = peasycap->saturation;
- JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
- break;
- }
- case V4L2_CID_HUE: {
- pv4l2_control->value = peasycap->hue;
- JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
- break;
- }
- case V4L2_CID_AUDIO_VOLUME: {
- pv4l2_control->value = peasycap->volume;
- JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
- break;
- }
- case V4L2_CID_AUDIO_MUTE: {
- if (1 == peasycap->mute)
- pv4l2_control->value = true;
- else
- pv4l2_control->value = false;
- JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
- break;
- }
- default: {
- SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
- pv4l2_control->id);
- kfree(pv4l2_control);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- if (copy_to_user((void __user *)arg, pv4l2_control,
- sizeof(struct v4l2_control))) {
- kfree(pv4l2_control);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- kfree(pv4l2_control);
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_CTRL: {
- struct v4l2_control v4l2_control;
-
- JOM(8, "VIDIOC_S_CTRL\n");
-
- if (0 != copy_from_user(&v4l2_control, (void __user *)arg,
- sizeof(struct v4l2_control))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- switch (v4l2_control.id) {
- case V4L2_CID_BRIGHTNESS: {
- JOM(8, "user requests brightness %i\n", v4l2_control.value);
- if (0 != adjust_brightness(peasycap, v4l2_control.value))
- ;
- break;
- }
- case V4L2_CID_CONTRAST: {
- JOM(8, "user requests contrast %i\n", v4l2_control.value);
- if (0 != adjust_contrast(peasycap, v4l2_control.value))
- ;
- break;
- }
- case V4L2_CID_SATURATION: {
- JOM(8, "user requests saturation %i\n", v4l2_control.value);
- if (0 != adjust_saturation(peasycap, v4l2_control.value))
- ;
- break;
- }
- case V4L2_CID_HUE: {
- JOM(8, "user requests hue %i\n", v4l2_control.value);
- if (0 != adjust_hue(peasycap, v4l2_control.value))
- ;
- break;
- }
- case V4L2_CID_AUDIO_VOLUME: {
- JOM(8, "user requests volume %i\n", v4l2_control.value);
- if (0 != adjust_volume(peasycap, v4l2_control.value))
- ;
- break;
- }
- case V4L2_CID_AUDIO_MUTE: {
- int mute;
-
- JOM(8, "user requests mute %i\n", v4l2_control.value);
- if (v4l2_control.value)
- mute = 1;
- else
- mute = 0;
-
- if (0 != adjust_mute(peasycap, mute))
- SAM("WARNING: failed to adjust mute to %i\n", mute);
- break;
- }
- default: {
- SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
- v4l2_control.id);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_EXT_CTRLS: {
- JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUM_FMT: {
- u32 index;
- struct v4l2_fmtdesc v4l2_fmtdesc;
-
- JOM(8, "VIDIOC_ENUM_FMT\n");
-
- if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg,
- sizeof(struct v4l2_fmtdesc))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- index = v4l2_fmtdesc.index;
- memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
-
- v4l2_fmtdesc.index = index;
- v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- switch (index) {
- case 0: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "uyvy");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- case 1: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "yuy2");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- case 2: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "rgb24");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- case 3: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "rgb32");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- case 4: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "bgr24");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- case 5: {
- v4l2_fmtdesc.flags = 0;
- strcpy(&v4l2_fmtdesc.description[0], "bgr32");
- v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
- JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
- break;
- }
- default: {
- JOM(8, "%i=index: exhausts formats\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- if (copy_to_user((void __user *)arg, &v4l2_fmtdesc,
- sizeof(struct v4l2_fmtdesc))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
- * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
- */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUM_FRAMESIZES: {
- u32 index;
- struct v4l2_frmsizeenum v4l2_frmsizeenum;
-
- JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
-
- if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg,
- sizeof(struct v4l2_frmsizeenum))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- index = v4l2_frmsizeenum.index;
-
- v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE;
-
- if (peasycap->ntsc) {
- switch (index) {
- case 0: {
- v4l2_frmsizeenum.discrete.width = 640;
- v4l2_frmsizeenum.discrete.height = 480;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 1: {
- v4l2_frmsizeenum.discrete.width = 320;
- v4l2_frmsizeenum.discrete.height = 240;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 2: {
- v4l2_frmsizeenum.discrete.width = 720;
- v4l2_frmsizeenum.discrete.height = 480;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 3: {
- v4l2_frmsizeenum.discrete.width = 360;
- v4l2_frmsizeenum.discrete.height = 240;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- default: {
- JOM(8, "%i=index: exhausts framesizes\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- } else {
- switch (index) {
- case 0: {
- v4l2_frmsizeenum.discrete.width = 640;
- v4l2_frmsizeenum.discrete.height = 480;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 1: {
- v4l2_frmsizeenum.discrete.width = 320;
- v4l2_frmsizeenum.discrete.height = 240;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 2: {
- v4l2_frmsizeenum.discrete.width = 704;
- v4l2_frmsizeenum.discrete.height = 576;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 3: {
- v4l2_frmsizeenum.discrete.width = 720;
- v4l2_frmsizeenum.discrete.height = 576;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- case 4: {
- v4l2_frmsizeenum.discrete.width = 360;
- v4l2_frmsizeenum.discrete.height = 288;
- JOM(8, "%i=index: %ix%i\n", index,
- (int)(v4l2_frmsizeenum.
- discrete.width),
- (int)(v4l2_frmsizeenum.
- discrete.height));
- break;
- }
- default: {
- JOM(8, "%i=index: exhausts framesizes\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- }
- if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum,
- sizeof(struct v4l2_frmsizeenum))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
- * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
- */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_ENUM_FRAMEINTERVALS: {
- u32 index;
- int denominator;
- struct v4l2_frmivalenum v4l2_frmivalenum;
-
- JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
-
- if (peasycap->fps)
- denominator = peasycap->fps;
- else {
- if (peasycap->ntsc)
- denominator = 30;
- else
- denominator = 25;
- }
-
- if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg,
- sizeof(struct v4l2_frmivalenum))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- index = v4l2_frmivalenum.index;
-
- v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE;
-
- switch (index) {
- case 0: {
- v4l2_frmivalenum.discrete.numerator = 1;
- v4l2_frmivalenum.discrete.denominator = denominator;
- JOM(8, "%i=index: %i/%i\n", index,
- (int)(v4l2_frmivalenum.discrete.numerator),
- (int)(v4l2_frmivalenum.discrete.denominator));
- break;
- }
- case 1: {
- v4l2_frmivalenum.discrete.numerator = 1;
- v4l2_frmivalenum.discrete.denominator = denominator/5;
- JOM(8, "%i=index: %i/%i\n", index,
- (int)(v4l2_frmivalenum.discrete.numerator),
- (int)(v4l2_frmivalenum.discrete.denominator));
- break;
- }
- default: {
- JOM(8, "%i=index: exhausts frameintervals\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- }
- if (copy_to_user((void __user *)arg, &v4l2_frmivalenum,
- sizeof(struct v4l2_frmivalenum))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_FMT: {
- struct v4l2_format *pv4l2_format;
- struct v4l2_pix_format *pv4l2_pix_format;
-
- JOM(8, "VIDIOC_G_FMT\n");
- pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
- if (!pv4l2_format) {
- SAM("ERROR: out of memory\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ENOMEM;
- }
- pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
- if (!pv4l2_pix_format) {
- SAM("ERROR: out of memory\n");
- kfree(pv4l2_format);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ENOMEM;
- }
- if (0 != copy_from_user(pv4l2_format, (void __user *)arg,
- sizeof(struct v4l2_format))) {
- kfree(pv4l2_format);
- kfree(pv4l2_pix_format);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- kfree(pv4l2_format);
- kfree(pv4l2_pix_format);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-
- memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
- pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memcpy(&pv4l2_format->fmt.pix,
- &easycap_format[peasycap->format_offset]
- .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
- JOM(8, "user is told: %s\n",
- &easycap_format[peasycap->format_offset].name[0]);
-
- if (copy_to_user((void __user *)arg, pv4l2_format,
- sizeof(struct v4l2_format))) {
- kfree(pv4l2_format);
- kfree(pv4l2_pix_format);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- kfree(pv4l2_format);
- kfree(pv4l2_pix_format);
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT: {
- struct v4l2_format v4l2_format;
- struct v4l2_pix_format v4l2_pix_format;
- bool try;
- int best_format;
-
- if (VIDIOC_TRY_FMT == cmd) {
- JOM(8, "VIDIOC_TRY_FMT\n");
- try = true;
- } else {
- JOM(8, "VIDIOC_S_FMT\n");
- try = false;
- }
-
- if (0 != copy_from_user(&v4l2_format, (void __user *)arg,
- sizeof(struct v4l2_format))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- best_format = adjust_format(peasycap,
- v4l2_format.fmt.pix.width,
- v4l2_format.fmt.pix.height,
- v4l2_format.fmt.pix.pixelformat,
- v4l2_format.fmt.pix.field,
- try);
- if (0 > best_format) {
- if (-EBUSY == best_format) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EBUSY;
- }
- JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ENOENT;
- }
-/*...........................................................................*/
- memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
- v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- memcpy(&(v4l2_format.fmt.pix),
- &(easycap_format[best_format].v4l2_format.fmt.pix),
- sizeof(v4l2_pix_format));
- JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
-
- if (copy_to_user((void __user *)arg, &v4l2_format,
- sizeof(struct v4l2_format))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_CROPCAP: {
- struct v4l2_cropcap v4l2_cropcap;
-
- JOM(8, "VIDIOC_CROPCAP\n");
-
- if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg,
- sizeof(struct v4l2_cropcap))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
-
- memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
- v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- v4l2_cropcap.bounds.left = 0;
- v4l2_cropcap.bounds.top = 0;
- v4l2_cropcap.bounds.width = peasycap->width;
- v4l2_cropcap.bounds.height = peasycap->height;
- v4l2_cropcap.defrect.left = 0;
- v4l2_cropcap.defrect.top = 0;
- v4l2_cropcap.defrect.width = peasycap->width;
- v4l2_cropcap.defrect.height = peasycap->height;
- v4l2_cropcap.pixelaspect.numerator = 1;
- v4l2_cropcap.pixelaspect.denominator = 1;
-
- JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
-
- if (copy_to_user((void __user *)arg, &v4l2_cropcap,
- sizeof(struct v4l2_cropcap))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP: {
- JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_QUERYSTD: {
- JOM(8, "VIDIOC_QUERYSTD: "
- "EasyCAP is incapable of detecting standard\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- break;
- }
- /*-------------------------------------------------------------------*/
- /*
- * THE MANIPULATIONS INVOLVING last0,last1,last2,last3
- * CONSTITUTE A WORKAROUND * FOR WHAT APPEARS TO BE
- * A BUG IN 64-BIT mplayer.
- * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
- */
- /*------------------------------------------------------------------*/
- case VIDIOC_ENUMSTD: {
- int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
- struct v4l2_standard v4l2_standard;
- u32 index;
- struct easycap_standard const *peasycap_standard;
-
- JOM(8, "VIDIOC_ENUMSTD\n");
-
- if (0 != copy_from_user(&v4l2_standard, (void __user *)arg,
- sizeof(struct v4l2_standard))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- index = v4l2_standard.index;
-
- last3 = last2;
- last2 = last1;
- last1 = last0;
- last0 = index;
- if ((index == last3) && (index == last2) &&
- (index == last1) && (index == last0)) {
- index++;
- last3 = last2;
- last2 = last1;
- last1 = last0;
- last0 = index;
- }
-
- memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
-
- peasycap_standard = &easycap_standard[0];
- while (0xFFFF != peasycap_standard->mask) {
- if ((int)(peasycap_standard - &easycap_standard[0]) == index)
- break;
- peasycap_standard++;
- }
- if (0xFFFF == peasycap_standard->mask) {
- JOM(8, "%i=index: exhausts standards\n", index);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- JOM(8, "%i=index: %s\n", index,
- &(peasycap_standard->v4l2_standard.name[0]));
- memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard),
- sizeof(struct v4l2_standard));
-
- v4l2_standard.index = index;
-
- if (copy_to_user((void __user *)arg, &v4l2_standard,
- sizeof(struct v4l2_standard))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_STD: {
- v4l2_std_id std_id;
- struct easycap_standard const *peasycap_standard;
-
- JOM(8, "VIDIOC_G_STD\n");
-
- if (0 > peasycap->standard_offset) {
- JOM(8, "%i=peasycap->standard_offset\n",
- peasycap->standard_offset);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EBUSY;
- }
-
- if (0 != copy_from_user(&std_id, (void __user *)arg,
- sizeof(v4l2_std_id))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- peasycap_standard = &easycap_standard[peasycap->standard_offset];
- std_id = peasycap_standard->v4l2_standard.id;
-
- JOM(8, "user is told: %s\n",
- &peasycap_standard->v4l2_standard.name[0]);
-
- if (copy_to_user((void __user *)arg, &std_id,
- sizeof(v4l2_std_id))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_STD: {
- v4l2_std_id std_id;
- int rc;
-
- JOM(8, "VIDIOC_S_STD\n");
-
- if (0 != copy_from_user(&std_id, (void __user *)arg,
- sizeof(v4l2_std_id))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- JOM(8, "User requests standard: 0x%08X%08X\n",
- (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32),
- (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
-
- rc = adjust_standard(peasycap, std_id);
- if (0 > rc) {
- JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ENOENT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_REQBUFS: {
- int nbuffers;
- struct v4l2_requestbuffers v4l2_requestbuffers;
-
- JOM(8, "VIDIOC_REQBUFS\n");
-
- if (0 != copy_from_user(&v4l2_requestbuffers,
- (void __user *)arg,
- sizeof(struct v4l2_requestbuffers))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- nbuffers = v4l2_requestbuffers.count;
- JOM(8, " User requests %i buffers ...\n", nbuffers);
- if (nbuffers < 2)
- nbuffers = 2;
- if (nbuffers > FRAME_BUFFER_MANY)
- nbuffers = FRAME_BUFFER_MANY;
- if (v4l2_requestbuffers.count == nbuffers) {
- JOM(8, " ... agree to %i buffers\n",
- nbuffers);
- } else {
- JOM(8, " ... insist on %i buffers\n",
- nbuffers);
- v4l2_requestbuffers.count = nbuffers;
- }
- peasycap->frame_buffer_many = nbuffers;
-
- if (copy_to_user((void __user *)arg, &v4l2_requestbuffers,
- sizeof(struct v4l2_requestbuffers))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_QUERYBUF: {
- u32 index;
- struct v4l2_buffer v4l2_buffer;
-
- JOM(8, "VIDIOC_QUERYBUF\n");
-
- if (peasycap->video_eof) {
- JOM(8, "returning -EIO because %i=video_eof\n",
- peasycap->video_eof);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EIO;
- }
-
- if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- index = v4l2_buffer.index;
- if (index < 0 || index >= peasycap->frame_buffer_many)
- return -EINVAL;
- memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
- v4l2_buffer.index = index;
- v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- v4l2_buffer.bytesused = peasycap->frame_buffer_used;
- v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED |
- peasycap->done[index] |
- peasycap->queued[index];
- v4l2_buffer.field = V4L2_FIELD_NONE;
- v4l2_buffer.memory = V4L2_MEMORY_MMAP;
- v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
- v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
- JOM(16, " %10i=index\n", v4l2_buffer.index);
- JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
- JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
- JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
- JOM(16, " %10i=field\n", v4l2_buffer.field);
- JOM(16, " %10li=timestamp.tv_usec\n",
- (long)v4l2_buffer.timestamp.tv_usec);
- JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
- JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
- JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
- JOM(16, " %10i=length\n", v4l2_buffer.length);
-
- if (copy_to_user((void __user *)arg, &v4l2_buffer,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_QBUF: {
- struct v4l2_buffer v4l2_buffer;
-
- JOM(8, "VIDIOC_QBUF\n");
-
- if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- if (v4l2_buffer.index < 0 ||
- v4l2_buffer.index >= peasycap->frame_buffer_many) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
-
- peasycap->done[v4l2_buffer.index] = 0;
- peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
-
- if (copy_to_user((void __user *)arg, &v4l2_buffer,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- JOM(8, "..... user queueing frame buffer %i\n",
- (int)v4l2_buffer.index);
-
- peasycap->frame_lock = 0;
-
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_DQBUF:
- {
- struct timeval timeval, timeval2;
- int i, j;
- struct v4l2_buffer v4l2_buffer;
- int rcdq;
- u16 input;
-
- JOM(8, "VIDIOC_DQBUF\n");
-
- if ((peasycap->video_idle) || (peasycap->video_eof)) {
- JOM(8, "returning -EIO because "
- "%i=video_idle %i=video_eof\n",
- peasycap->video_idle, peasycap->video_eof);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EIO;
- }
-
- if (copy_from_user(&v4l2_buffer, (void __user *)arg,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-
- if (peasycap->offerfields) {
- /*---------------------------------------------------*/
- /*
- * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
- * V4L2_FIELD_BOTTOM
- */
- /*---------------------------------------------------*/
- if (V4L2_FIELD_TOP == v4l2_buffer.field)
- JOM(8, "user wants V4L2_FIELD_TOP\n");
- else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
- JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
- else if (V4L2_FIELD_ANY == v4l2_buffer.field)
- JOM(8, "user wants V4L2_FIELD_ANY\n");
- else
- JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n",
- v4l2_buffer.field);
- }
-
- if (!peasycap->video_isoc_streaming) {
- JOM(16, "returning -EIO because video urbs not streaming\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EIO;
- }
- /*-------------------------------------------------------------------*/
- /*
- * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(),
- * AS DETERMINED BY FINDING
- * THE FLAG peasycap->polled SET, THERE MUST BE
- * NO FURTHER WAIT HERE. IN THIS
- * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
- */
- /*-------------------------------------------------------------------*/
-
- if (!peasycap->polled) {
- do {
- rcdq = easycap_video_dqbuf(peasycap, 0);
- if (-EIO == rcdq) {
- JOM(8, "returning -EIO because "
- "dqbuf() returned -EIO\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EIO;
- }
- } while (0 != rcdq);
- } else {
- if (peasycap->video_eof) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EIO;
- }
- }
- if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
- JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n",
- peasycap->done[peasycap->frame_read]);
- }
- peasycap->polled = 0;
-
- if (!(peasycap->isequence % 10)) {
- for (i = 0; i < 179; i++)
- peasycap->merit[i] = peasycap->merit[i+1];
- peasycap->merit[179] = merit_saa(peasycap->pusb_device);
- j = 0;
- for (i = 0; i < 180; i++)
- j += peasycap->merit[i];
- if (90 < j) {
- SAM("easycap driver shutting down "
- "on condition blue\n");
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- }
- }
-
- v4l2_buffer.index = peasycap->frame_read;
- v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- v4l2_buffer.bytesused = peasycap->frame_buffer_used;
- v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
- if (peasycap->offerfields)
- v4l2_buffer.field = V4L2_FIELD_BOTTOM;
- else
- v4l2_buffer.field = V4L2_FIELD_NONE;
- do_gettimeofday(&timeval);
- timeval2 = timeval;
-
- v4l2_buffer.timestamp = timeval2;
- v4l2_buffer.sequence = peasycap->isequence++;
- v4l2_buffer.memory = V4L2_MEMORY_MMAP;
- v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
- v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
- JOM(16, " %10i=index\n", v4l2_buffer.index);
- JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
- JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
- JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
- JOM(16, " %10i=field\n", v4l2_buffer.field);
- JOM(16, " %10li=timestamp.tv_sec\n",
- (long)v4l2_buffer.timestamp.tv_sec);
- JOM(16, " %10li=timestamp.tv_usec\n",
- (long)v4l2_buffer.timestamp.tv_usec);
- JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
- JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
- JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
- JOM(16, " %10i=length\n", v4l2_buffer.length);
-
- if (copy_to_user((void __user *)arg, &v4l2_buffer,
- sizeof(struct v4l2_buffer))) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- input = peasycap->frame_buffer[peasycap->frame_read][0].input;
- if (0x08 & input) {
- JOM(8, "user is offered frame buffer %i, input %i\n",
- peasycap->frame_read, (0x07 & input));
- } else {
- JOM(8, "user is offered frame buffer %i\n",
- peasycap->frame_read);
- }
- peasycap->frame_lock = 1;
- JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
- if (peasycap->frame_read == peasycap->frame_fill) {
- if (peasycap->frame_lock) {
- JOM(8, "WORRY: filling frame buffer "
- "while offered to user\n");
- }
- }
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_STREAMON: {
- int i;
-
- JOM(8, "VIDIOC_STREAMON\n");
-
- peasycap->isequence = 0;
- for (i = 0; i < 180; i++)
- peasycap->merit[i] = 0;
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- easycap_video_submit_urbs(peasycap);
- peasycap->video_idle = 0;
- peasycap->audio_idle = 0;
- peasycap->video_eof = 0;
- peasycap->audio_eof = 0;
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_STREAMOFF: {
- JOM(8, "VIDIOC_STREAMOFF\n");
-
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
-
- peasycap->video_idle = 1;
- peasycap->audio_idle = 1;
-/*---------------------------------------------------------------------------*/
-/*
- * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
- * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
- */
-/*---------------------------------------------------------------------------*/
- JOM(8, "calling wake_up on wq_video and wq_audio\n");
- wake_up_interruptible(&(peasycap->wq_video));
- if (peasycap->psubstream)
- snd_pcm_period_elapsed(peasycap->psubstream);
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_PARM: {
- struct v4l2_streamparm *pv4l2_streamparm;
-
- JOM(8, "VIDIOC_G_PARM\n");
- pv4l2_streamparm = memdup_user((void __user *)arg,
- sizeof(struct v4l2_streamparm));
- if (IS_ERR(pv4l2_streamparm)) {
- SAM("ERROR: copy from user failed\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return PTR_ERR(pv4l2_streamparm);
- }
-
- if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- kfree(pv4l2_streamparm);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- pv4l2_streamparm->parm.capture.capability = 0;
- pv4l2_streamparm->parm.capture.capturemode = 0;
- pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
-
- if (peasycap->fps) {
- pv4l2_streamparm->parm.capture.timeperframe.
- denominator = peasycap->fps;
- } else {
- if (peasycap->ntsc) {
- pv4l2_streamparm->parm.capture.timeperframe.
- denominator = 30;
- } else {
- pv4l2_streamparm->parm.capture.timeperframe.
- denominator = 25;
- }
- }
-
- pv4l2_streamparm->parm.capture.readbuffers =
- peasycap->frame_buffer_many;
- pv4l2_streamparm->parm.capture.extendedmode = 0;
- if (copy_to_user((void __user *)arg,
- pv4l2_streamparm,
- sizeof(struct v4l2_streamparm))) {
- kfree(pv4l2_streamparm);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EFAULT;
- }
- kfree(pv4l2_streamparm);
- break;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_PARM: {
- JOM(8, "VIDIOC_S_PARM unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_AUDIO: {
- JOM(8, "VIDIOC_G_AUDIO unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_AUDIO: {
- JOM(8, "VIDIOC_S_AUDIO unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_S_TUNER: {
- JOM(8, "VIDIOC_S_TUNER unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_FBUF:
- case VIDIOC_S_FBUF:
- case VIDIOC_OVERLAY: {
- JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- case VIDIOC_G_TUNER: {
- JOM(8, "VIDIOC_G_TUNER unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY: {
- JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -EINVAL;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- default: {
- JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ENOIOCTLCMD;
- }
- }
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
- return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c
deleted file mode 100644
index 0380babed22c..000000000000
--- a/drivers/staging/media/easycap/easycap_low.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/*****************************************************************************
-* *
-* *
-* easycap_low.c *
-* *
-* *
-*****************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-/*
- * ACKNOWLEGEMENTS AND REFERENCES
- * ------------------------------
- * This driver makes use of register information contained in the Syntek
- * Semicon DC-1125 driver hosted at
- * http://sourceforge.net/projects/syntekdriver/.
- * Particularly useful has been a patch to the latter driver provided by
- * Ivor Hewitt in January 2009. The NTSC implementation is taken from the
- * work of Ben Trask.
-*/
-/****************************************************************************/
-
-#include "easycap.h"
-
-
-#define GET(X, Y, Z) do { \
- int __rc; \
- *(Z) = (u16)0; \
- __rc = regget(X, Y, Z, sizeof(u8)); \
- if (0 > __rc) { \
- JOT(8, ":-(%i\n", __LINE__); return __rc; \
- } \
-} while (0)
-
-#define SET(X, Y, Z) do { \
- int __rc; \
- __rc = regset(X, Y, Z); \
- if (0 > __rc) { \
- JOT(8, ":-(%i\n", __LINE__); return __rc; \
- } \
-} while (0)
-
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config {
- u16 reg;
- u16 set;
-} stk1160configPAL[] = {
- {0x000, 0x0098},
- {0x002, 0x0093},
-
- {0x001, 0x0003},
- {0x003, 0x0080},
- {0x00D, 0x0000},
- {0x00F, 0x0002},
- {0x018, 0x0010},
- {0x019, 0x0000},
- {0x01A, 0x0014},
- {0x01B, 0x000E},
- {0x01C, 0x0046},
-
- {0x100, 0x0033},
- {0x103, 0x0000},
- {0x104, 0x0000},
- {0x105, 0x0000},
- {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- * RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {0x110, 0x0008},
- {0x111, 0x0000},
- {0x112, 0x0020},
- {0x113, 0x0000},
- {0x114, 0x0508},
- {0x115, 0x0005},
- {0x116, 0x0110},
- {0x117, 0x0001},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- {0x202, 0x000F},
- {0x203, 0x004A},
- {0x2FF, 0x0000},
-
- {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config stk1160configNTSC[] = {
- {0x000, 0x0098},
- {0x002, 0x0093},
-
- {0x001, 0x0003},
- {0x003, 0x0080},
- {0x00D, 0x0000},
- {0x00F, 0x0002},
- {0x018, 0x0010},
- {0x019, 0x0000},
- {0x01A, 0x0014},
- {0x01B, 0x000E},
- {0x01C, 0x0046},
-
- {0x100, 0x0033},
- {0x103, 0x0000},
- {0x104, 0x0000},
- {0x105, 0x0000},
- {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- * RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {0x110, 0x0008},
- {0x111, 0x0000},
- {0x112, 0x0003},
- {0x113, 0x0000},
- {0x114, 0x0508},
- {0x115, 0x0005},
- {0x116, 0x00F3},
- {0x117, 0x0000},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- {0x202, 0x000F},
- {0x203, 0x004A},
- {0x2FF, 0x0000},
-
- {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config {
- u8 reg;
- u8 set;
-} saa7113configPAL[] = {
- {0x01, 0x08},
- {0x02, 0x80},
- {0x03, 0x33},
- {0x04, 0x00},
- {0x05, 0x00},
- {0x06, 0xE9},
- {0x07, 0x0D},
- {0x08, 0x38},
- {0x09, 0x00},
- {0x0A, SAA_0A_DEFAULT},
- {0x0B, SAA_0B_DEFAULT},
- {0x0C, SAA_0C_DEFAULT},
- {0x0D, SAA_0D_DEFAULT},
- {0x0E, 0x01},
- {0x0F, 0x36},
- {0x10, 0x00},
- {0x11, 0x0C},
- {0x12, 0xE7},
- {0x13, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x40, 0x02},
- {0x41, 0xFF},
- {0x42, 0xFF},
- {0x43, 0xFF},
- {0x44, 0xFF},
- {0x45, 0xFF},
- {0x46, 0xFF},
- {0x47, 0xFF},
- {0x48, 0xFF},
- {0x49, 0xFF},
- {0x4A, 0xFF},
- {0x4B, 0xFF},
- {0x4C, 0xFF},
- {0x4D, 0xFF},
- {0x4E, 0xFF},
- {0x4F, 0xFF},
- {0x50, 0xFF},
- {0x51, 0xFF},
- {0x52, 0xFF},
- {0x53, 0xFF},
- {0x54, 0xFF},
- {0x55, 0xFF},
- {0x56, 0xFF},
- {0x57, 0xFF},
- {0x58, 0x40},
- {0x59, 0x54},
- {0x5A, 0x07},
- {0x5B, 0x83},
-
- {0xFF, 0xFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config saa7113configNTSC[] = {
- {0x01, 0x08},
- {0x02, 0x80},
- {0x03, 0x33},
- {0x04, 0x00},
- {0x05, 0x00},
- {0x06, 0xE9},
- {0x07, 0x0D},
- {0x08, 0x78},
- {0x09, 0x00},
- {0x0A, SAA_0A_DEFAULT},
- {0x0B, SAA_0B_DEFAULT},
- {0x0C, SAA_0C_DEFAULT},
- {0x0D, SAA_0D_DEFAULT},
- {0x0E, 0x01},
- {0x0F, 0x36},
- {0x10, 0x00},
- {0x11, 0x0C},
- {0x12, 0xE7},
- {0x13, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x40, 0x82},
- {0x41, 0xFF},
- {0x42, 0xFF},
- {0x43, 0xFF},
- {0x44, 0xFF},
- {0x45, 0xFF},
- {0x46, 0xFF},
- {0x47, 0xFF},
- {0x48, 0xFF},
- {0x49, 0xFF},
- {0x4A, 0xFF},
- {0x4B, 0xFF},
- {0x4C, 0xFF},
- {0x4D, 0xFF},
- {0x4E, 0xFF},
- {0x4F, 0xFF},
- {0x50, 0xFF},
- {0x51, 0xFF},
- {0x52, 0xFF},
- {0x53, 0xFF},
- {0x54, 0xFF},
- {0x55, 0xFF},
- {0x56, 0xFF},
- {0x57, 0xFF},
- {0x58, 0x40},
- {0x59, 0x54},
- {0x5A, 0x0A},
- {0x5B, 0x83},
-
- {0xFF, 0xFF}
-};
-
-static int regget(struct usb_device *pusb_device,
- u16 index, void *reg, int reg_size)
-{
- int rc;
-
- if (!pusb_device)
- return -ENODEV;
-
- rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
- 0x00,
- (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
- 0x00,
- index, reg, reg_size, 50000);
-
- return rc;
-}
-
-static int regset(struct usb_device *pusb_device, u16 index, u16 value)
-{
- int rc;
-
- if (!pusb_device)
- return -ENODEV;
-
- rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
- 0x01,
- (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
- value, index, NULL, 0, 500);
-
- if (rc < 0)
- return rc;
-
- if (easycap_readback) {
- u16 igot = 0;
- rc = regget(pusb_device, index, &igot, sizeof(igot));
- igot = 0xFF & igot;
- switch (index) {
- case 0x000:
- case 0x500:
- case 0x502:
- case 0x503:
- case 0x504:
- case 0x506:
- case 0x507:
- break;
-
- case 0x204:
- case 0x205:
- case 0x350:
- case 0x351:
- if (igot)
- JOT(8, "unexpected 0x%02X "
- "for STK register 0x%03X\n",
- igot, index);
- break;
-
- default:
- if ((0xFF & value) != igot)
- JOT(8, "unexpected 0x%02X != 0x%02X "
- "for STK register 0x%03X\n",
- igot, value, index);
- break;
- }
- }
-
- return rc;
-}
-/*--------------------------------------------------------------------------*/
-/*
- * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
-*/
-/*--------------------------------------------------------------------------*/
-static int wait_i2c(struct usb_device *p)
-{
- u16 get0;
- u8 igot;
- const int max = 2;
- int k;
-
- if (!p)
- return -ENODEV;
-
- for (k = 0; k < max; k++) {
- GET(p, 0x0201, &igot); get0 = igot;
- switch (get0) {
- case 0x04:
- case 0x01:
- return 0;
- case 0x00:
- msleep(20);
- continue;
- default:
- return get0 - 1;
- }
- }
- return -1;
-}
-
-/****************************************************************************/
-int write_saa(struct usb_device *p, u16 reg0, u16 set0)
-{
- if (!p)
- return -ENODEV;
- SET(p, 0x200, 0x00);
- SET(p, 0x204, reg0);
- SET(p, 0x205, set0);
- SET(p, 0x200, 0x01);
- return wait_i2c(p);
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
- * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET
- * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET
- * REGISTER 504: TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-static int write_vt(struct usb_device *p, u16 reg0, u16 set0)
-{
- u8 igot;
- u16 got502, got503;
- u16 set502, set503;
-
- if (!p)
- return -ENODEV;
- SET(p, 0x0504, reg0);
- SET(p, 0x0500, 0x008B);
-
- GET(p, 0x0502, &igot); got502 = (0xFF & igot);
- GET(p, 0x0503, &igot); got503 = (0xFF & igot);
-
- JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
- reg0, set0, ((got503 << 8) | got502));
-
- set502 = (0x00FF & set0);
- set503 = ((0xFF00 & set0) >> 8);
-
- SET(p, 0x0504, reg0);
- SET(p, 0x0502, set502);
- SET(p, 0x0503, set503);
- SET(p, 0x0500, 0x008C);
-
- return 0;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
- * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET
- * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET
- * REGISTER 504: TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-static int read_vt(struct usb_device *p, u16 reg0)
-{
- u8 igot;
- u16 got502, got503;
-
- if (!p)
- return -ENODEV;
- SET(p, 0x0504, reg0);
- SET(p, 0x0500, 0x008B);
-
- GET(p, 0x0502, &igot); got502 = (0xFF & igot);
- GET(p, 0x0503, &igot); got503 = (0xFF & igot);
-
- JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
- reg0, ((got503 << 8) | got502));
-
- return (got503 << 8) | got502;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
- */
-/*--------------------------------------------------------------------------*/
-static int write_300(struct usb_device *p)
-{
- if (!p)
- return -ENODEV;
- SET(p, 0x300, 0x0012);
- SET(p, 0x350, 0x002D);
- SET(p, 0x351, 0x0001);
- SET(p, 0x352, 0x0000);
- SET(p, 0x353, 0x0000);
- SET(p, 0x300, 0x0080);
- return 0;
-}
-/****************************************************************************/
-/****************************************************************************/
-int setup_stk(struct usb_device *p, bool ntsc)
-{
- int i;
- const struct stk1160config *cfg;
- if (!p)
- return -ENODEV;
- cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
- for (i = 0; cfg[i].reg != 0xFFF; i++)
- SET(p, cfg[i].reg, cfg[i].set);
-
- write_300(p);
-
- return 0;
-}
-/****************************************************************************/
-int setup_saa(struct usb_device *p, bool ntsc)
-{
- int i, rc;
- const struct saa7113config *cfg;
- if (!p)
- return -ENODEV;
- cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
- for (i = 0; cfg[i].reg != 0xFF; i++) {
- rc = write_saa(p, cfg[i].reg, cfg[i].set);
- if (rc)
- dev_err(&p->dev,
- "Failed to set SAA register %d", cfg[i].reg);
- }
- return 0;
-}
-/****************************************************************************/
-int merit_saa(struct usb_device *p)
-{
- int rc;
-
- if (!p)
- return -ENODEV;
- rc = read_saa(p, 0x1F);
- return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
-}
-/****************************************************************************/
-int ready_saa(struct usb_device *p)
-{
- int j, rc, rate;
- const int max = 5, marktime = PATIENCE/5;
-/*--------------------------------------------------------------------------*/
-/*
- * RETURNS 0 FOR INTERLACED 50 Hz
- * 1 FOR NON-INTERLACED 50 Hz
- * 2 FOR INTERLACED 60 Hz
- * 3 FOR NON-INTERLACED 60 Hz
-*/
-/*--------------------------------------------------------------------------*/
- if (!p)
- return -ENODEV;
- j = 0;
- while (max > j) {
- rc = read_saa(p, 0x1F);
- if (0 <= rc) {
- if (0 == (0x40 & rc))
- break;
- if (1 == (0x01 & rc))
- break;
- }
- msleep(marktime);
- j++;
- }
-
- if (max == j)
- return -1;
-
- if (0x20 & rc) {
- rate = 2;
- JOT(8, "hardware detects 60 Hz\n");
- } else {
- rate = 0;
- JOT(8, "hardware detects 50 Hz\n");
- }
- if (0x80 & rc)
- JOT(8, "hardware detects interlacing\n");
- else {
- rate++;
- JOT(8, "hardware detects no interlacing\n");
- }
- return 0;
-}
-/****************************************************************************/
-int read_saa(struct usb_device *p, u16 reg0)
-{
- u8 igot;
-
- if (!p)
- return -ENODEV;
- SET(p, 0x208, reg0);
- SET(p, 0x200, 0x20);
- if (0 != wait_i2c(p))
- return -1;
- igot = 0;
- GET(p, 0x0209, &igot);
- return igot;
-}
-/****************************************************************************/
-static int read_stk(struct usb_device *p, u32 reg0)
-{
- u8 igot;
-
- if (!p)
- return -ENODEV;
- igot = 0;
- GET(p, reg0, &igot);
- return igot;
-}
-int select_input(struct usb_device *p, int input, int mode)
-{
- int ir;
-
- if (!p)
- return -ENODEV;
- stop_100(p);
- switch (input) {
- case 0:
- case 1: {
- if (0 != write_saa(p, 0x02, 0x80))
- SAY("ERROR: failed to set SAA register 0x02 "
- "for input %i\n", input);
-
- SET(p, 0x0000, 0x0098);
- SET(p, 0x0002, 0x0078);
- break;
- }
- case 2: {
- if (0 != write_saa(p, 0x02, 0x80))
- SAY("ERROR: failed to set SAA register 0x02 "
- "for input %i\n", input);
-
- SET(p, 0x0000, 0x0090);
- SET(p, 0x0002, 0x0078);
- break;
- }
- case 3: {
- if (0 != write_saa(p, 0x02, 0x80))
- SAY("ERROR: failed to set SAA register 0x02 "
- " for input %i\n", input);
-
- SET(p, 0x0000, 0x0088);
- SET(p, 0x0002, 0x0078);
- break;
- }
- case 4: {
- if (0 != write_saa(p, 0x02, 0x80)) {
- SAY("ERROR: failed to set SAA register 0x02 "
- "for input %i\n", input);
- }
- SET(p, 0x0000, 0x0080);
- SET(p, 0x0002, 0x0078);
- break;
- }
- case 5: {
- if (9 != mode)
- mode = 7;
- switch (mode) {
- case 7: {
- if (0 != write_saa(p, 0x02, 0x87))
- SAY("ERROR: failed to set SAA register 0x02 "
- "for input %i\n", input);
-
- if (0 != write_saa(p, 0x05, 0xFF))
- SAY("ERROR: failed to set SAA register 0x05 "
- "for input %i\n", input);
-
- break;
- }
- case 9: {
- if (0 != write_saa(p, 0x02, 0x89))
- SAY("ERROR: failed to set SAA register 0x02 "
- "for input %i\n", input);
-
- if (0 != write_saa(p, 0x05, 0x00))
- SAY("ERROR: failed to set SAA register 0x05 "
- "for input %i\n", input);
-
- break;
- }
- default:
- SAY("MISTAKE: bad mode: %i\n", mode);
- return -1;
- }
-
- if (0 != write_saa(p, 0x04, 0x00))
- SAY("ERROR: failed to set SAA register 0x04 "
- "for input %i\n", input);
-
- if (0 != write_saa(p, 0x09, 0x80))
- SAY("ERROR: failed to set SAA register 0x09 "
- "for input %i\n", input);
-
- SET(p, 0x0002, 0x0093);
- break;
- }
- default:
- SAY("ERROR: bad input: %i\n", input);
- return -1;
- }
-
- ir = read_stk(p, 0x00);
- JOT(8, "STK register 0x00 has 0x%02X\n", ir);
- ir = read_saa(p, 0x02);
- JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
-
- start_100(p);
-
- return 0;
-}
-/****************************************************************************/
-int set_resolution(struct usb_device *p,
- u16 set0, u16 set1, u16 set2, u16 set3)
-{
- u16 u0x0111, u0x0113, u0x0115, u0x0117;
-
- if (!p)
- return -ENODEV;
- u0x0111 = ((0xFF00 & set0) >> 8);
- u0x0113 = ((0xFF00 & set1) >> 8);
- u0x0115 = ((0xFF00 & set2) >> 8);
- u0x0117 = ((0xFF00 & set3) >> 8);
-
- SET(p, 0x0110, (0x00FF & set0));
- SET(p, 0x0111, u0x0111);
- SET(p, 0x0112, (0x00FF & set1));
- SET(p, 0x0113, u0x0113);
- SET(p, 0x0114, (0x00FF & set2));
- SET(p, 0x0115, u0x0115);
- SET(p, 0x0116, (0x00FF & set3));
- SET(p, 0x0117, u0x0117);
-
- return 0;
-}
-/****************************************************************************/
-int start_100(struct usb_device *p)
-{
- u16 get116, get117, get0;
- u8 igot116, igot117, igot;
-
- if (!p)
- return -ENODEV;
- GET(p, 0x0116, &igot116);
- get116 = igot116;
- GET(p, 0x0117, &igot117);
- get117 = igot117;
- SET(p, 0x0116, 0x0000);
- SET(p, 0x0117, 0x0000);
-
- GET(p, 0x0100, &igot);
- get0 = igot;
- SET(p, 0x0100, (0x80 | get0));
-
- SET(p, 0x0116, get116);
- SET(p, 0x0117, get117);
-
- return 0;
-}
-/****************************************************************************/
-int stop_100(struct usb_device *p)
-{
- u16 get0;
- u8 igot;
-
- if (!p)
- return -ENODEV;
- GET(p, 0x0100, &igot);
- get0 = igot;
- SET(p, 0x0100, (0x7F & get0));
- return 0;
-}
-/****************************************************************************/
-/****************************************************************************/
-/*****************************************************************************/
-int easycap_wakeup_device(struct usb_device *pusb_device)
-{
- if (!pusb_device)
- return -ENODEV;
-
- return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
- USB_REQ_SET_FEATURE,
- USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- USB_DEVICE_REMOTE_WAKEUP,
- 0, NULL, 0, 50000);
-}
-/*****************************************************************************/
-int easycap_audio_setup(struct easycap *peasycap)
-{
- struct usb_device *pusb_device;
- u8 buffer[1];
- int rc, id1, id2;
-/*---------------------------------------------------------------------------*/
-/*
- * IMPORTANT:
- * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
- * CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
- * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.
- */
-/*---------------------------------------------------------------------------*/
- const u8 request = 0x01;
- const u8 requesttype = USB_DIR_OUT |
- USB_TYPE_CLASS |
- USB_RECIP_INTERFACE;
- const u16 value_unmute = 0x0200;
- const u16 index = 0x0301;
- const u16 length = 1;
-
- if (!peasycap)
- return -EFAULT;
-
- pusb_device = peasycap->pusb_device;
- if (!pusb_device)
- return -ENODEV;
-
- JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
- requesttype, request,
- (0x00FF & value_unmute),
- (0xFF00 & value_unmute) >> 8,
- (0x00FF & index),
- (0xFF00 & index) >> 8,
- (0x00FF & length),
- (0xFF00 & length) >> 8);
-
- buffer[0] = 0x01;
-
- rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
- request, requesttype, value_unmute,
- index, &buffer[0], length, 50000);
-
- JOT(8, "0x%02X=buffer\n", buffer[0]);
- if (rc != (int)length) {
- switch (rc) {
- case -EPIPE:
- SAY("usb_control_msg returned -EPIPE\n");
- break;
- default:
- SAY("ERROR: usb_control_msg returned %i\n", rc);
- break;
- }
- }
-/*--------------------------------------------------------------------------*/
-/*
- * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
- * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ???
- * FOR THE CVBS+S-VIDEO HARDWARE:
- * SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
- * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- * FOR THE FOUR-CVBS HARDWARE:
- * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
- * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
- * FOR THE CVBS-S-VIDEO HARDWARE:
- * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
- * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- */
-/*--------------------------------------------------------------------------*/
- SET(pusb_device, 0x0500, 0x0094);
- SET(pusb_device, 0x0500, 0x008C);
- SET(pusb_device, 0x0506, 0x0001);
- SET(pusb_device, 0x0507, 0x0000);
- id1 = read_vt(pusb_device, 0x007C);
- id2 = read_vt(pusb_device, 0x007E);
- SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
-/*---------------------------------------------------------------------------*/
-/*
- * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
-*/
-/*---------------------------------------------------------------------------*/
- if (easycap_audio_gainset(pusb_device, peasycap->gain))
- SAY("ERROR: audio_gainset() failed\n");
- check_vt(pusb_device);
- return 0;
-}
-/*****************************************************************************/
-int check_vt(struct usb_device *pusb_device)
-{
- int igot;
-
- if (!pusb_device)
- return -ENODEV;
- igot = read_vt(pusb_device, 0x0002);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x02\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x02);
-
- igot = read_vt(pusb_device, 0x000E);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x0E\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x0E);
-
- igot = read_vt(pusb_device, 0x0010);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x10\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x10);
-
- igot = read_vt(pusb_device, 0x0012);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x12\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x12);
-
- igot = read_vt(pusb_device, 0x0014);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x14\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x14);
-
- igot = read_vt(pusb_device, 0x0016);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x16\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x16);
-
- igot = read_vt(pusb_device, 0x0018);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x18\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x18);
-
- igot = read_vt(pusb_device, 0x001C);
- if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x1C\n");
- if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x1C);
-
- return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
- * audio_gainset(pusb_device, 0x000F);
- *
- * loud dB register 0x10 dB register 0x1C dB total
- * 0 -34.5 0 -34.5
- * .. .... . ....
- * 15 10.5 0 10.5
- * 16 12.0 0 12.0
- * 17 12.0 1.5 13.5
- * .. .... .... ....
- * 31 12.0 22.5 34.5
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud)
-{
- int igot;
- u8 tmp;
- u16 mute;
-
- if (!pusb_device)
- return -ENODEV;
- if (0 > loud)
- loud = 0;
- if (31 < loud)
- loud = 31;
-
- write_vt(pusb_device, 0x0002, 0x8000);
-/*---------------------------------------------------------------------------*/
- igot = read_vt(pusb_device, 0x000E);
- if (0 > igot) {
- SAY("ERROR: failed to read VT1612A register 0x0E\n");
- mute = 0x0000;
- } else
- mute = 0x8000 & ((unsigned int)igot);
- mute = 0;
-
- if (16 > loud)
- tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
- else
- tmp = 0;
-
- JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
- write_vt(pusb_device, 0x000E, (mute | tmp));
-/*---------------------------------------------------------------------------*/
- igot = read_vt(pusb_device, 0x0010);
- if (0 > igot) {
- SAY("ERROR: failed to read VT1612A register 0x10\n");
- mute = 0x0000;
- } else
- mute = 0x8000 & ((unsigned int)igot);
- mute = 0;
-
- JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
- mute | tmp | (tmp << 8));
- write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
- write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
- write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
- write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
- write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
-/*---------------------------------------------------------------------------*/
- igot = read_vt(pusb_device, 0x001C);
- if (0 > igot) {
- SAY("ERROR: failed to read VT1612A register 0x1C\n");
- mute = 0x0000;
- } else
- mute = 0x8000 & ((unsigned int)igot);
- mute = 0;
-
- if (16 <= loud)
- tmp = 0x000F & (u8)(loud - 16);
- else
- tmp = 0;
-
- JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
- mute | tmp | (tmp << 8));
- write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
- write_vt(pusb_device, 0x001A, 0x0404);
- write_vt(pusb_device, 0x0002, 0x0000);
- return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
deleted file mode 100644
index 8269c77dbf7d..000000000000
--- a/drivers/staging/media/easycap/easycap_main.c
+++ /dev/null
@@ -1,4239 +0,0 @@
-/******************************************************************************
-* *
-* easycap_main.c *
-* *
-* Video driver for EasyCAP USB2.0 Video Capture Device DC60 *
-* *
-* *
-******************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-#include <linux/usb/audio.h>
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
-MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
-MODULE_VERSION(EASYCAP_DRIVER_VERSION);
-
-#ifdef CONFIG_EASYCAP_DEBUG
-int easycap_debug;
-module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-bool easycap_readback;
-module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(readback, "read back written registers: (default false)");
-
-static int easycap_bars = 1;
-module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(bars,
- "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
-
-static int easycap_gain = 16;
-module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
-
-static bool easycap_ntsc;
-module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)");
-
-
-
-struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
-static struct mutex mutex_dongle;
-static void easycap_complete(struct urb *purb);
-static int reset(struct easycap *peasycap);
-static int field2frame(struct easycap *peasycap);
-static int redaub(struct easycap *peasycap,
- void *pad, void *pex, int much, int more,
- u8 mask, u8 margin, bool isuy);
-
-const char *strerror(int err)
-{
-#define ERRNOSTR(_e) case _e: return # _e
- switch (err) {
- case 0: return "OK";
- ERRNOSTR(ENOMEM);
- ERRNOSTR(ENODEV);
- ERRNOSTR(ENXIO);
- ERRNOSTR(EINVAL);
- ERRNOSTR(EAGAIN);
- ERRNOSTR(EFBIG);
- ERRNOSTR(EPIPE);
- ERRNOSTR(EMSGSIZE);
- ERRNOSTR(ENOSPC);
- ERRNOSTR(EINPROGRESS);
- ERRNOSTR(ENOSR);
- ERRNOSTR(EOVERFLOW);
- ERRNOSTR(EPROTO);
- ERRNOSTR(EILSEQ);
- ERRNOSTR(ETIMEDOUT);
- ERRNOSTR(EOPNOTSUPP);
- ERRNOSTR(EPFNOSUPPORT);
- ERRNOSTR(EAFNOSUPPORT);
- ERRNOSTR(EADDRINUSE);
- ERRNOSTR(EADDRNOTAVAIL);
- ERRNOSTR(ENOBUFS);
- ERRNOSTR(EISCONN);
- ERRNOSTR(ENOTCONN);
- ERRNOSTR(ESHUTDOWN);
- ERRNOSTR(ENOENT);
- ERRNOSTR(ECONNRESET);
- ERRNOSTR(ETIME);
- ERRNOSTR(ECOMM);
- ERRNOSTR(EREMOTEIO);
- ERRNOSTR(EXDEV);
- ERRNOSTR(EPERM);
- default: return "unknown";
- }
-
-#undef ERRNOSTR
-}
-
-/****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_isdongle(struct easycap *peasycap)
-{
- int k;
- if (!peasycap)
- return -2;
- for (k = 0; k < DONGLE_MANY; k++) {
- if (easycapdc60_dongle[k].peasycap == peasycap) {
- peasycap->isdongle = k;
- return k;
- }
- }
- return -1;
-}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-static int easycap_open(struct inode *inode, struct file *file)
-{
- struct video_device *pvideo_device;
- struct easycap *peasycap;
- int rc;
-
- JOT(4, "\n");
- SAY("==========OPEN=========\n");
-
- pvideo_device = video_devdata(file);
- if (!pvideo_device) {
- SAY("ERROR: pvideo_device is NULL.\n");
- return -EFAULT;
- }
- peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
-
- JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
-
- file->private_data = peasycap;
- rc = easycap_wakeup_device(peasycap->pusb_device);
- if (rc) {
- SAM("ERROR: wakeup_device() rc = %i\n", rc);
- if (-ENODEV == rc)
- SAM("ERROR: wakeup_device() returned -ENODEV\n");
- else
- SAM("ERROR: wakeup_device() rc = %i\n", rc);
- return rc;
- }
- JOM(8, "wakeup_device() OK\n");
- peasycap->input = 0;
- rc = reset(peasycap);
- if (rc) {
- SAM("ERROR: reset() rc = %i\n", rc);
- return -EFAULT;
- }
- return 0;
-}
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * RESET THE HARDWARE TO ITS REFERENCE STATE.
- *
- * THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
- * A BAD VIDEO FRAME SIZE.
-*/
-/*---------------------------------------------------------------------------*/
-static int reset(struct easycap *peasycap)
-{
- struct easycap_standard const *peasycap_standard;
- int fmtidx, input, rate;
- bool ntsc, other;
- int rc;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- input = peasycap->input;
-
-/*---------------------------------------------------------------------------*/
-/*
- * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
- * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
- * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
- * A SWITCH BETWEEN PAL AND NTSC.
- *
- * FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
- * COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
-*/
-/*---------------------------------------------------------------------------*/
- other = false;
- JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc);
-
- rate = ready_saa(peasycap->pusb_device);
- if (rate < 0) {
- JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
- ntsc = !peasycap->ntsc;
- JOM(8, "... trying %s ..\n", ntsc ? "NTSC" : "PAL");
- rc = setup_stk(peasycap->pusb_device, ntsc);
- if (rc) {
- SAM("ERROR: setup_stk() rc = %i\n", rc);
- return -EFAULT;
- }
- rc = setup_saa(peasycap->pusb_device, ntsc);
- if (rc) {
- SAM("ERROR: setup_saa() rc = %i\n", rc);
- return -EFAULT;
- }
-
- rate = ready_saa(peasycap->pusb_device);
- if (rate < 0) {
- JOM(8, "not ready to capture after %i ms\n", PATIENCE);
- JOM(8, "... saa register 0x1F has 0x%02X\n",
- read_saa(peasycap->pusb_device, 0x1F));
- ntsc = peasycap->ntsc;
- } else {
- JOM(8, "... success at second try: %i=rate\n", rate);
- ntsc = (0 < (rate/2)) ? true : false ;
- other = true;
- }
- } else {
- JOM(8, "... success at first try: %i=rate\n", rate);
- ntsc = (0 < rate/2) ? true : false ;
- }
- JOM(8, "ntsc=%d\n", ntsc);
-/*---------------------------------------------------------------------------*/
-
- rc = setup_stk(peasycap->pusb_device, ntsc);
- if (rc) {
- SAM("ERROR: setup_stk() rc = %i\n", rc);
- return -EFAULT;
- }
- rc = setup_saa(peasycap->pusb_device, ntsc);
- if (rc) {
- SAM("ERROR: setup_saa() rc = %i\n", rc);
- return -EFAULT;
- }
-
- memset(peasycap->merit, 0, sizeof(peasycap->merit));
-
- peasycap->video_eof = 0;
- peasycap->audio_eof = 0;
-/*---------------------------------------------------------------------------*/
-/*
- * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
- *
- * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
-*/
-/*---------------------------------------------------------------------------*/
- peasycap->input = -8192;
- peasycap->standard_offset = -8192;
- fmtidx = ntsc ? NTSC_M : PAL_BGHIN;
- if (other) {
- peasycap_standard = &easycap_standard[0];
- while (0xFFFF != peasycap_standard->mask) {
- if (fmtidx == peasycap_standard->v4l2_standard.index) {
- peasycap->inputset[input].standard_offset =
- peasycap_standard - easycap_standard;
- break;
- }
- peasycap_standard++;
- }
- if (0xFFFF == peasycap_standard->mask) {
- SAM("ERROR: standard not found\n");
- return -EINVAL;
- }
- JOM(8, "%i=peasycap->inputset[%i].standard_offset\n",
- peasycap->inputset[input].standard_offset, input);
- }
- peasycap->format_offset = -8192;
- peasycap->brightness = -8192;
- peasycap->contrast = -8192;
- peasycap->saturation = -8192;
- peasycap->hue = -8192;
-
- rc = easycap_newinput(peasycap, input);
-
- if (rc) {
- SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
- return -EFAULT;
- }
- JOM(4, "restored input, standard and format\n");
-
- JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc);
-
- if (0 > peasycap->input) {
- SAM("MISTAKE: %i=peasycap->input\n", peasycap->input);
- return -ENOENT;
- }
- if (0 > peasycap->standard_offset) {
- SAM("MISTAKE: %i=peasycap->standard_offset\n",
- peasycap->standard_offset);
- return -ENOENT;
- }
- if (0 > peasycap->format_offset) {
- SAM("MISTAKE: %i=peasycap->format_offset\n",
- peasycap->format_offset);
- return -ENOENT;
- }
- if (0 > peasycap->brightness) {
- SAM("MISTAKE: %i=peasycap->brightness\n",
- peasycap->brightness);
- return -ENOENT;
- }
- if (0 > peasycap->contrast) {
- SAM("MISTAKE: %i=peasycap->contrast\n", peasycap->contrast);
- return -ENOENT;
- }
- if (0 > peasycap->saturation) {
- SAM("MISTAKE: %i=peasycap->saturation\n",
- peasycap->saturation);
- return -ENOENT;
- }
- if (0 > peasycap->hue) {
- SAM("MISTAKE: %i=peasycap->hue\n", peasycap->hue);
- return -ENOENT;
- }
- return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
- * OTHERWISE:
- * KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
- * _read AND _fill POINTERS.
- * SELECT THE NEW INPUT.
- * ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
- * ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
- * RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
- *
- * NOTE:
- * THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
- * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_newinput(struct easycap *peasycap, int input)
-{
- int rc, k, m, mood, off;
- int inputnow, video_idlenow, audio_idlenow;
- bool resubmit;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- JOM(8, "%i=input sought\n", input);
-
- if (0 > input && INPUT_MANY <= input)
- return -ENOENT;
- inputnow = peasycap->input;
- if (input == inputnow)
- return 0;
-/*---------------------------------------------------------------------------*/
-/*
- * IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
- * STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
- * IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
- * ROUTINE.
-*/
-/*---------------------------------------------------------------------------*/
- video_idlenow = peasycap->video_idle;
- audio_idlenow = peasycap->audio_idle;
-
- peasycap->video_idle = 1;
- peasycap->audio_idle = 1;
- if (peasycap->video_isoc_streaming) {
- resubmit = true;
- easycap_video_kill_urbs(peasycap);
- } else {
- resubmit = false;
- }
-/*---------------------------------------------------------------------------*/
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -ENODEV;
- }
- rc = usb_set_interface(peasycap->pusb_device,
- peasycap->video_interface,
- peasycap->video_altsetting_off);
- if (rc) {
- SAM("ERROR: usb_set_interface() rc = %i\n", rc);
- return -EFAULT;
- }
- rc = stop_100(peasycap->pusb_device);
- if (rc) {
- SAM("ERROR: stop_100() rc = %i\n", rc);
- return -EFAULT;
- }
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
- memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
- }
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
- memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
- }
- peasycap->field_page = 0;
- peasycap->field_read = 0;
- peasycap->field_fill = 0;
-
- peasycap->frame_read = 0;
- peasycap->frame_fill = 0;
- for (k = 0; k < peasycap->input; k++) {
- (peasycap->frame_fill)++;
- if (peasycap->frame_buffer_many <= peasycap->frame_fill)
- peasycap->frame_fill = 0;
- }
- peasycap->input = input;
- select_input(peasycap->pusb_device, peasycap->input, 9);
-/*---------------------------------------------------------------------------*/
- if (input == peasycap->inputset[input].input) {
- off = peasycap->inputset[input].standard_offset;
- if (off != peasycap->standard_offset) {
- rc = adjust_standard(peasycap,
- easycap_standard[off].v4l2_standard.id);
- if (rc) {
- SAM("ERROR: adjust_standard() rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->standard_offset\n",
- peasycap->standard_offset);
- } else {
- JOM(8, "%i=peasycap->standard_offset unchanged\n",
- peasycap->standard_offset);
- }
- off = peasycap->inputset[input].format_offset;
- if (off != peasycap->format_offset) {
- struct v4l2_pix_format *pix =
- &easycap_format[off].v4l2_format.fmt.pix;
- rc = adjust_format(peasycap,
- pix->width, pix->height,
- pix->pixelformat, pix->field, false);
- if (0 > rc) {
- SAM("ERROR: adjust_format() rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->format_offset\n",
- peasycap->format_offset);
- } else {
- JOM(8, "%i=peasycap->format_offset unchanged\n",
- peasycap->format_offset);
- }
- mood = peasycap->inputset[input].brightness;
- if (mood != peasycap->brightness) {
- rc = adjust_brightness(peasycap, mood);
- if (rc) {
- SAM("ERROR: adjust_brightness rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->brightness\n",
- peasycap->brightness);
- }
- mood = peasycap->inputset[input].contrast;
- if (mood != peasycap->contrast) {
- rc = adjust_contrast(peasycap, mood);
- if (rc) {
- SAM("ERROR: adjust_contrast rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
- }
- mood = peasycap->inputset[input].saturation;
- if (mood != peasycap->saturation) {
- rc = adjust_saturation(peasycap, mood);
- if (rc) {
- SAM("ERROR: adjust_saturation rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->saturation\n",
- peasycap->saturation);
- }
- mood = peasycap->inputset[input].hue;
- if (mood != peasycap->hue) {
- rc = adjust_hue(peasycap, mood);
- if (rc) {
- SAM("ERROR: adjust_hue rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(8, "%i=peasycap->hue\n", peasycap->hue);
- }
- } else {
- SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
- return -ENOENT;
- }
-/*---------------------------------------------------------------------------*/
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -ENODEV;
- }
- rc = usb_set_interface(peasycap->pusb_device,
- peasycap->video_interface,
- peasycap->video_altsetting_on);
- if (rc) {
- SAM("ERROR: usb_set_interface() rc = %i\n", rc);
- return -EFAULT;
- }
- rc = start_100(peasycap->pusb_device);
- if (rc) {
- SAM("ERROR: start_100() rc = %i\n", rc);
- return -EFAULT;
- }
- if (resubmit)
- easycap_video_submit_urbs(peasycap);
-
- peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
- peasycap->video_idle = video_idlenow;
- peasycap->audio_idle = audio_idlenow;
- peasycap->video_junk = 0;
-
- return 0;
-}
-/*****************************************************************************/
-int easycap_video_submit_urbs(struct easycap *peasycap)
-{
- struct data_urb *pdata_urb;
- struct urb *purb;
- struct list_head *plist_head;
- int j, isbad, nospc, m, rc;
- int isbuf;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
-
- if (!peasycap->purb_video_head) {
- SAY("ERROR: peasycap->urb_video_head uninitialized\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
- return -ENODEV;
- }
- if (!peasycap->video_isoc_streaming) {
- JOM(4, "submission of all video urbs\n");
- isbad = 0; nospc = 0; m = 0;
- list_for_each(plist_head, (peasycap->purb_video_head)) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- purb = pdata_urb->purb;
- isbuf = pdata_urb->isbuf;
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe =
- usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->video_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer =
- peasycap->video_isoc_buffer[isbuf].pgo;
- purb->transfer_buffer_length =
- peasycap->video_isoc_buffer_size;
- purb->complete = easycap_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets =
- peasycap->video_isoc_framesperdesc;
-
- for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j]. offset =
- j * peasycap->video_isoc_maxframesize;
- purb->iso_frame_desc[j]. length =
- peasycap->video_isoc_maxframesize;
- }
-
- rc = usb_submit_urb(purb, GFP_KERNEL);
- if (rc) {
- isbad++;
- SAM("ERROR: usb_submit_urb() failed "
- "for urb with rc:-%s\n",
- strerror(rc));
- if (rc == -ENOSPC)
- nospc++;
- } else {
- m++;
- }
- } else {
- isbad++;
- }
- }
- if (nospc) {
- SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
- SAM("..... possibly inadequate USB bandwidth\n");
- peasycap->video_eof = 1;
- }
-
- if (isbad)
- easycap_video_kill_urbs(peasycap);
- else
- peasycap->video_isoc_streaming = 1;
- } else {
- JOM(4, "already streaming video urbs\n");
- }
- return 0;
-}
-/*****************************************************************************/
-int easycap_audio_kill_urbs(struct easycap *peasycap)
-{
- int m;
- struct list_head *plist_head;
- struct data_urb *pdata_urb;
-
- if (!peasycap->audio_isoc_streaming)
- return 0;
-
- if (!peasycap->purb_audio_head) {
- SAM("ERROR: peasycap->purb_audio_head is NULL\n");
- return -EFAULT;
- }
-
- peasycap->audio_isoc_streaming = 0;
- m = 0;
- list_for_each(plist_head, peasycap->purb_audio_head) {
- pdata_urb = list_entry(plist_head, struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_kill_urb(pdata_urb->purb);
- m++;
- }
- }
-
- JOM(4, "%i audio urbs killed\n", m);
-
- return 0;
-}
-int easycap_video_kill_urbs(struct easycap *peasycap)
-{
- int m;
- struct list_head *plist_head;
- struct data_urb *pdata_urb;
-
- if (!peasycap->video_isoc_streaming)
- return 0;
-
- if (!peasycap->purb_video_head) {
- SAM("ERROR: peasycap->purb_video_head is NULL\n");
- return -EFAULT;
- }
-
- peasycap->video_isoc_streaming = 0;
- JOM(4, "killing video urbs\n");
- m = 0;
- list_for_each(plist_head, (peasycap->purb_video_head)) {
- pdata_urb = list_entry(plist_head, struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_kill_urb(pdata_urb->purb);
- m++;
- }
- }
- JOM(4, "%i video urbs killed\n", m);
-
- return 0;
-}
-/****************************************************************************/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*--------------------------------------------------------------------------*/
-static int easycap_open_noinode(struct file *file)
-{
- return easycap_open(NULL, file);
-}
-
-static int videodev_release(struct video_device *pvideo_device)
-{
- struct easycap *peasycap;
-
- peasycap = video_get_drvdata(pvideo_device);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- SAY("ending unsuccessfully\n");
- return -EFAULT;
- }
- if (easycap_video_kill_urbs(peasycap)) {
- SAM("ERROR: easycap_video_kill_urbs() failed\n");
- return -EFAULT;
- }
- JOM(4, "ending successfully\n");
- return 0;
-}
-
-/*****************************************************************************/
-static unsigned int easycap_poll(struct file *file, poll_table *wait)
-{
- struct easycap *peasycap;
- int rc, kd;
-
- JOT(8, "\n");
-
- if (NULL == ((poll_table *)wait))
- JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
- if (!file) {
- SAY("ERROR: file pointer is NULL\n");
- return -ERESTARTSYS;
- }
- peasycap = file->private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
-/*---------------------------------------------------------------------------*/
- kd = easycap_isdongle(peasycap);
- if (0 <= kd && DONGLE_MANY > kd) {
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
- SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd);
- return -ERESTARTSYS;
- }
- JOM(4, "locked dongle[%i].mutex_video\n", kd);
- /*
- * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
- * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
- * IF NECESSARY, BAIL OUT.
- */
- if (kd != easycap_isdongle(peasycap)) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- if (!file) {
- SAY("ERROR: file is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- peasycap = file->private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return -ERESTARTSYS;
- }
- } else
- /*
- * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
- * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
- * HAVE FAILED. BAIL OUT.
- */
- return -ERESTARTSYS;
-/*---------------------------------------------------------------------------*/
- rc = easycap_video_dqbuf(peasycap, 0);
- peasycap->polled = 1;
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- if (rc)
- return POLLERR;
-
- return POLLIN | POLLRDNORM;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
- */
-/*---------------------------------------------------------------------------*/
-int easycap_video_dqbuf(struct easycap *peasycap, int mode)
-{
- int input, ifield, miss, rc;
-
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
- ifield = 0;
- JOM(8, "%i=ifield\n", ifield);
-/*---------------------------------------------------------------------------*/
-/*
- * CHECK FOR LOST INPUT SIGNAL.
- *
- * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
- * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
- * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
- * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS:
- *
- * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
- * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
- * INPUT 0 UNPLUGGED, INPUT 4 PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
- * INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
-*/
-/*---------------------------------------------------------------------------*/
- input = peasycap->input;
- if (0 <= input && INPUT_MANY > input) {
- rc = read_saa(peasycap->pusb_device, 0x1F);
- if (0 <= rc) {
- if (rc & 0x40)
- peasycap->lost[input] += 1;
- else
- peasycap->lost[input] -= 2;
-
- if (0 > peasycap->lost[input])
- peasycap->lost[input] = 0;
- else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
- peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
- }
- }
-/*---------------------------------------------------------------------------*/
-/*
- * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM)
- */
-/*---------------------------------------------------------------------------*/
- miss = 0;
- while ((peasycap->field_read == peasycap->field_fill) ||
- (0 != (0xFF00 & peasycap->field_buffer
- [peasycap->field_read][0].kount)) ||
- (ifield != (0x00FF & peasycap->field_buffer
- [peasycap->field_read][0].kount))) {
- if (mode)
- return -EAGAIN;
-
- JOM(8, "first wait on wq_video, %i=field_read %i=field_fill\n",
- peasycap->field_read, peasycap->field_fill);
-
- if (0 != (wait_event_interruptible(peasycap->wq_video,
- (peasycap->video_idle || peasycap->video_eof ||
- ((peasycap->field_read != peasycap->field_fill) &&
- (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
- (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
- SAM("aborted by signal\n");
- return -EIO;
- }
- if (peasycap->video_idle) {
- JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
- peasycap->video_idle);
- return -EAGAIN;
- }
- if (peasycap->video_eof) {
- JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
- #if defined(PERSEVERE)
- if (1 == peasycap->status) {
- JOM(8, "persevering ...\n");
- peasycap->video_eof = 0;
- peasycap->audio_eof = 0;
- if (0 != reset(peasycap)) {
- JOM(8, " ... failed returning -EIO\n");
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- easycap_video_kill_urbs(peasycap);
- return -EIO;
- }
- peasycap->status = 0;
- JOM(8, " ... OK returning -EAGAIN\n");
- return -EAGAIN;
- }
- #endif /*PERSEVERE*/
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- easycap_video_kill_urbs(peasycap);
- JOM(8, "returning -EIO\n");
- return -EIO;
- }
- miss++;
- }
- JOM(8, "first awakening on wq_video after %i waits\n", miss);
-
- rc = field2frame(peasycap);
- if (rc)
- SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- * WAIT FOR THE OTHER FIELD
- */
-/*---------------------------------------------------------------------------*/
- if (ifield)
- ifield = 0;
- else
- ifield = 1;
- miss = 0;
- while ((peasycap->field_read == peasycap->field_fill) ||
- (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) ||
- (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) {
- if (mode)
- return -EAGAIN;
-
- JOM(8, "second wait on wq_video %i=field_read %i=field_fill\n",
- peasycap->field_read, peasycap->field_fill);
- if (0 != (wait_event_interruptible(peasycap->wq_video,
- (peasycap->video_idle || peasycap->video_eof ||
- ((peasycap->field_read != peasycap->field_fill) &&
- (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
- (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
- SAM("aborted by signal\n");
- return -EIO;
- }
- if (peasycap->video_idle) {
- JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
- peasycap->video_idle);
- return -EAGAIN;
- }
- if (peasycap->video_eof) {
- JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
-#if defined(PERSEVERE)
- if (1 == peasycap->status) {
- JOM(8, "persevering ...\n");
- peasycap->video_eof = 0;
- peasycap->audio_eof = 0;
- if (0 != reset(peasycap)) {
- JOM(8, " ... failed returning -EIO\n");
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- easycap_video_kill_urbs(peasycap);
- return -EIO;
- }
- peasycap->status = 0;
- JOM(8, " ... OK ... returning -EAGAIN\n");
- return -EAGAIN;
- }
-#endif /*PERSEVERE*/
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- easycap_video_kill_urbs(peasycap);
- JOM(8, "returning -EIO\n");
- return -EIO;
- }
- miss++;
- }
- JOM(8, "second awakening on wq_video after %i waits\n", miss);
-
- rc = field2frame(peasycap);
- if (rc)
- SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- * WASTE THIS FRAME
-*/
-/*---------------------------------------------------------------------------*/
- if (peasycap->skip) {
- peasycap->skipped++;
- if (peasycap->skip != peasycap->skipped)
- return peasycap->skip - peasycap->skipped;
- else
- peasycap->skipped = 0;
- }
-/*---------------------------------------------------------------------------*/
- peasycap->frame_read = peasycap->frame_fill;
- peasycap->queued[peasycap->frame_read] = 0;
- peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;
-
- peasycap->frame_fill++;
- if (peasycap->frame_buffer_many <= peasycap->frame_fill)
- peasycap->frame_fill = 0;
-
- if (0x01 & easycap_standard[peasycap->standard_offset].mask)
- peasycap->frame_buffer[peasycap->frame_read][0].kount =
- V4L2_FIELD_TOP;
- else
- peasycap->frame_buffer[peasycap->frame_read][0].kount =
- V4L2_FIELD_BOTTOM;
-
-
- JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
- JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
-
- return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * BY DEFINITION, odd IS true FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
- * odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
- *
- * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
- * odd==false IS TRANSFERRED TO THE FRAME BUFFER.
- *
- */
-/*---------------------------------------------------------------------------*/
-static int field2frame(struct easycap *peasycap)
-{
-
- void *pex, *pad;
- int kex, kad, mex, mad, rex, rad, rad2;
- int c2, c3, w2, w3, cz, wz;
- int rc, bytesperpixel, multiplier;
- int much, more, over, rump, caches, input;
- u8 mask, margin;
- bool odd, isuy, decimatepixel, badinput;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
-
- badinput = false;
- input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
-
- JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> "
- "frame buffer %i\n",
- peasycap->field_buffer[peasycap->field_read][0].kount,
- peasycap->field_buffer[peasycap->field_read][0].input,
- peasycap->field_read, peasycap->frame_fill);
- JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
-
-/*---------------------------------------------------------------------------*/
-/*
- * REJECT OR CLEAN BAD FIELDS
- */
-/*---------------------------------------------------------------------------*/
- if (peasycap->field_read == peasycap->field_fill) {
- SAM("ERROR: on entry, still filling field buffer %i\n",
- peasycap->field_read);
- return 0;
- }
-#ifdef EASYCAP_TESTCARD
- easycap_testcard(peasycap, peasycap->field_read);
-#else
- if (0 <= input && INPUT_MANY > input) {
- if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
- easycap_testcard(peasycap, peasycap->field_read);
- }
-#endif /*EASYCAP_TESTCARD*/
-/*---------------------------------------------------------------------------*/
-
- bytesperpixel = peasycap->bytesperpixel;
- decimatepixel = peasycap->decimatepixel;
-
- if ((2 != bytesperpixel) &&
- (3 != bytesperpixel) &&
- (4 != bytesperpixel)) {
- SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
- return -EFAULT;
- }
- if (decimatepixel)
- multiplier = 2;
- else
- multiplier = 1;
-
- w2 = 2 * multiplier * (peasycap->width);
- w3 = bytesperpixel * multiplier * (peasycap->width);
- wz = multiplier * (peasycap->height) *
- multiplier * (peasycap->width);
-
- kex = peasycap->field_read; mex = 0;
- kad = peasycap->frame_fill; mad = 0;
-
- pex = peasycap->field_buffer[kex][0].pgo; rex = PAGE_SIZE;
- pad = peasycap->frame_buffer[kad][0].pgo; rad = PAGE_SIZE;
- odd = !!(peasycap->field_buffer[kex][0].kount);
-
- if (odd && (!decimatepixel)) {
- JOM(8, "initial skipping %4i bytes p.%4i\n",
- w3/multiplier, mad);
- pad += (w3 / multiplier); rad -= (w3 / multiplier);
- }
- isuy = true;
- mask = 0; rump = 0; caches = 0;
-
- cz = 0;
- while (cz < wz) {
- /*
- * PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
- * READ w2 BYTES FROM FIELD BUFFER,
- * WRITE w3 BYTES TO FRAME BUFFER
- */
- if (!decimatepixel) {
- over = w2;
- do {
- much = over; more = 0;
- margin = 0; mask = 0x00;
- if (rex < much)
- much = rex;
- rump = 0;
-
- if (much % 2) {
- SAM("MISTAKE: much is odd\n");
- return -EFAULT;
- }
-
- more = (bytesperpixel *
- much) / 2;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- if (1 < bytesperpixel) {
- if (rad * 2 < much * bytesperpixel) {
- /*
- * INJUDICIOUS ALTERATION OF
- * THIS STATEMENT BLOCK WILL
- * CAUSE BREAKAGE. BEWARE.
- */
- rad2 = rad + bytesperpixel - 1;
- much = ((((2 * rad2)/bytesperpixel)/2) * 2);
- rump = ((bytesperpixel * much) / 2) - rad;
- more = rad;
- }
- mask = (u8)rump;
- margin = 0;
- if (much == rex) {
- mask |= 0x04;
- if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
- margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
- else
- mask |= 0x08;
- }
- } else {
- SAM("MISTAKE: %i=bytesperpixel\n",
- bytesperpixel);
- return -EFAULT;
- }
- if (rump)
- caches++;
- if (badinput) {
- JOM(8, "ERROR: 0x%02X=->field_buffer"
- "[%i][%i].input, "
- "0x%02X=(0x08|->input)\n",
- peasycap->field_buffer
- [kex][mex].input, kex, mex,
- (0x08|peasycap->input));
- }
- rc = redaub(peasycap, pad, pex, much, more,
- mask, margin, isuy);
- if (0 > rc) {
- SAM("ERROR: redaub() failed\n");
- return -EFAULT;
- }
- if (much % 4)
- isuy = !isuy;
-
- over -= much; cz += much;
- pex += much; rex -= much;
- if (!rex) {
- mex++;
- pex = peasycap->field_buffer[kex][mex].pgo;
- rex = PAGE_SIZE;
- if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input))
- badinput = true;
- }
- pad += more;
- rad -= more;
- if (!rad) {
- mad++;
- pad = peasycap->frame_buffer[kad][mad].pgo;
- rad = PAGE_SIZE;
- if (rump) {
- pad += rump;
- rad -= rump;
- }
- }
- } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- * SKIP w3 BYTES IN TARGET FRAME BUFFER,
- * UNLESS IT IS THE LAST LINE OF AN ODD FRAME
- */
-/*---------------------------------------------------------------------------*/
- if (!odd || (cz != wz)) {
- over = w3;
- do {
- if (!rad) {
- mad++;
- pad = peasycap->frame_buffer
- [kad][mad].pgo;
- rad = PAGE_SIZE;
- }
- more = over;
- if (rad < more)
- more = rad;
- over -= more;
- pad += more;
- rad -= more;
- } while (over);
- }
-/*---------------------------------------------------------------------------*/
-/*
- * PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
- * ONLY IF false==odd,
- * READ w2 BYTES FROM FIELD BUFFER,
- * WRITE w3 / 2 BYTES TO FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
- } else if (!odd) {
- over = w2;
- do {
- much = over; more = 0; margin = 0; mask = 0x00;
- if (rex < much)
- much = rex;
- rump = 0;
-
- if (much % 2) {
- SAM("MISTAKE: much is odd\n");
- return -EFAULT;
- }
-
- more = (bytesperpixel * much) / 4;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- if (1 < bytesperpixel) {
- if (rad * 4 < much * bytesperpixel) {
- /*
- * INJUDICIOUS ALTERATION OF
- * THIS STATEMENT BLOCK
- * WILL CAUSE BREAKAGE.
- * BEWARE.
- */
- rad2 = rad + bytesperpixel - 1;
- much = ((((2 * rad2) / bytesperpixel) / 2) * 4);
- rump = ((bytesperpixel * much) / 4) - rad;
- more = rad;
- }
- mask = (u8)rump;
- margin = 0;
- if (much == rex) {
- mask |= 0x04;
- if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
- margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
- else
- mask |= 0x08;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- } else {
- SAM("MISTAKE: %i=bytesperpixel\n",
- bytesperpixel);
- return -EFAULT;
- }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- if (rump)
- caches++;
-
- if (badinput) {
- JOM(8, "ERROR: 0x%02X=->field_buffer"
- "[%i][%i].input, "
- "0x%02X=(0x08|->input)\n",
- peasycap->field_buffer
- [kex][mex].input, kex, mex,
- (0x08|peasycap->input));
- }
- rc = redaub(peasycap, pad, pex, much, more,
- mask, margin, isuy);
- if (0 > rc) {
- SAM("ERROR: redaub() failed\n");
- return -EFAULT;
- }
- over -= much; cz += much;
- pex += much; rex -= much;
- if (!rex) {
- mex++;
- pex = peasycap->field_buffer[kex][mex].pgo;
- rex = PAGE_SIZE;
- if (peasycap->field_buffer[kex][mex].input !=
- (0x08|peasycap->input))
- badinput = true;
- }
- pad += more;
- rad -= more;
- if (!rad) {
- mad++;
- pad = peasycap->frame_buffer[kad][mad].pgo;
- rad = PAGE_SIZE;
- if (rump) {
- pad += rump;
- rad -= rump;
- }
- }
- } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- * OTHERWISE JUST
- * READ w2 BYTES FROM FIELD BUFFER AND DISCARD THEM
- */
-/*---------------------------------------------------------------------------*/
- } else {
- over = w2;
- do {
- if (!rex) {
- mex++;
- pex = peasycap->field_buffer[kex][mex].pgo;
- rex = PAGE_SIZE;
- if (peasycap->field_buffer[kex][mex].input !=
- (0x08|peasycap->input)) {
- JOM(8, "ERROR: 0x%02X=->field_buffer"
- "[%i][%i].input, "
- "0x%02X=(0x08|->input)\n",
- peasycap->field_buffer
- [kex][mex].input, kex, mex,
- (0x08|peasycap->input));
- badinput = true;
- }
- }
- much = over;
- if (rex < much)
- much = rex;
- over -= much;
- cz += much;
- pex += much;
- rex -= much;
- } while (over);
- }
- }
-/*---------------------------------------------------------------------------*/
-/*
- * SANITY CHECKS
- */
-/*---------------------------------------------------------------------------*/
- c2 = (mex + 1)*PAGE_SIZE - rex;
- if (cz != c2)
- SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
- c3 = (mad + 1)*PAGE_SIZE - rad;
-
- if (!decimatepixel) {
- if (bytesperpixel * cz != c3)
- SAM("ERROR: discrepancy %i in bytes written\n",
- c3 - (bytesperpixel * cz));
- } else {
- if (!odd) {
- if (bytesperpixel *
- cz != (4 * c3))
- SAM("ERROR: discrepancy %i in bytes written\n",
- (2*c3)-(bytesperpixel * cz));
- } else {
- if (0 != c3)
- SAM("ERROR: discrepancy %i "
- "in bytes written\n", c3);
- }
- }
- if (rump)
- SAM("WORRY: undischarged cache at end of line in frame buffer\n");
-
- JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
- JOM(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);
-
- if (odd)
- JOM(8, "+++++ field2frame(): frame buffer %i is full\n", kad);
-
- if (peasycap->field_read == peasycap->field_fill)
- SAM("WARNING: on exit, filling field buffer %i\n",
- peasycap->field_read);
-
- if (caches)
- JOM(8, "%i=caches\n", caches);
- return 0;
-}
-/*---------------------------------------------------------------------------*/
-/*
- * DECIMATION AND COLOURSPACE CONVERSION.
- *
- * THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
- * AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
- * THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
- * ALSO ENSURE THAT much IS EVEN.
- *
- * much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
- * IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
- *
- * mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
- * 0x03 & mask = number of bytes to be written to cache instead of to
- * frame buffer
- * 0x04 & mask => use argument margin to set the chrominance for last pixel
- * 0x08 & mask => do not set the chrominance for last pixel
- *
- * YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
- *
- * THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
- * INEFFICIENT SWITCHING INSIDE INNER LOOPS. REARRANGING THE LOGIC TO
- * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int redaub(struct easycap *peasycap,
- void *pad, void *pex, int much, int more,
- u8 mask, u8 margin, bool isuy)
-{
- static s32 ay[256], bu[256], rv[256], gu[256], gv[256];
- u8 *pcache;
- u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
- int bytesperpixel;
- bool byteswaporder, decimatepixel, last;
- int j, rump;
- s32 tmp;
-
- if (much % 2) {
- SAM("MISTAKE: much is odd\n");
- return -EFAULT;
- }
- bytesperpixel = peasycap->bytesperpixel;
- byteswaporder = peasycap->byteswaporder;
- decimatepixel = peasycap->decimatepixel;
-
-/*---------------------------------------------------------------------------*/
- if (!bu[255]) {
- for (j = 0; j < 112; j++) {
- tmp = (0xFF00 & (453 * j)) >> 8;
- bu[j + 128] = tmp; bu[127 - j] = -tmp;
- tmp = (0xFF00 & (359 * j)) >> 8;
- rv[j + 128] = tmp; rv[127 - j] = -tmp;
- tmp = (0xFF00 & (88 * j)) >> 8;
- gu[j + 128] = tmp; gu[127 - j] = -tmp;
- tmp = (0xFF00 & (183 * j)) >> 8;
- gv[j + 128] = tmp; gv[127 - j] = -tmp;
- }
- for (j = 0; j < 16; j++) {
- bu[j] = bu[16]; rv[j] = rv[16];
- gu[j] = gu[16]; gv[j] = gv[16];
- }
- for (j = 240; j < 256; j++) {
- bu[j] = bu[239]; rv[j] = rv[239];
- gu[j] = gu[239]; gv[j] = gv[239];
- }
- for (j = 16; j < 236; j++)
- ay[j] = j;
- for (j = 0; j < 16; j++)
- ay[j] = ay[16];
- for (j = 236; j < 256; j++)
- ay[j] = ay[235];
- JOM(8, "lookup tables are prepared\n");
- }
- pcache = peasycap->pcache;
- if (!pcache)
- pcache = &peasycap->cache[0];
-/*---------------------------------------------------------------------------*/
-/*
- * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
- if (!pcache) {
- SAM("MISTAKE: pcache is NULL\n");
- return -EFAULT;
- }
-
- if (pcache != &peasycap->cache[0])
- JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
- p2 = &peasycap->cache[0];
- p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]);
- while (p2 < pcache) {
- *p3++ = *p2; p2++;
- }
- pcache = &peasycap->cache[0];
- if (p3 != pad) {
- SAM("MISTAKE: pointer misalignment\n");
- return -EFAULT;
- }
-/*---------------------------------------------------------------------------*/
- rump = (int)(0x03 & mask);
- u = 0; v = 0;
- p2 = (u8 *)pex; pz = p2 + much; pr = p3 + more; last = false;
- p2++;
-
- if (isuy)
- u = *(p2 - 1);
- else
- v = *(p2 - 1);
-
- if (rump)
- JOM(16, "%4i=much %4i=more %i=rump\n", much, more, rump);
-
-/*---------------------------------------------------------------------------*/
- switch (bytesperpixel) {
- case 2: {
- if (!decimatepixel) {
- memcpy(pad, pex, (size_t)much);
- if (!byteswaporder) {
- /* UYVY */
- return 0;
- } else {
- /* YUYV */
- p3 = (u8 *)pad; pz = p3 + much;
- while (pz > p3) {
- c = *p3;
- *p3 = *(p3 + 1);
- *(p3 + 1) = c;
- p3 += 2;
- }
- return 0;
- }
- } else {
- if (!byteswaporder) {
- /* UYVY DECIMATED */
- p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much;
- while (pz > p2) {
- *p3 = *p2;
- *(p3 + 1) = *(p2 + 1);
- *(p3 + 2) = *(p2 + 2);
- *(p3 + 3) = *(p2 + 3);
- p3 += 4; p2 += 8;
- }
- return 0;
- } else {
- /* YUYV DECIMATED */
- p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much;
- while (pz > p2) {
- *p3 = *(p2 + 1);
- *(p3 + 1) = *p2;
- *(p3 + 2) = *(p2 + 3);
- *(p3 + 3) = *(p2 + 2);
- p3 += 4; p2 += 8;
- }
- return 0;
- }
- }
- break;
- }
- case 3:
- {
- if (!decimatepixel) {
- if (!byteswaporder) {
- /* RGB */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = r;
- *pcache++ = g;
- *pcache++ = b;
- break;
- }
- case 2: {
- *p3 = r;
- *(p3 + 1) = g;
- *pcache++ = b;
- break;
- }
- default: {
- SAM("MISTAKE: %i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- }
- p2 += 2;
- if (isuy)
- isuy = false;
- else
- isuy = true;
- p3 += bytesperpixel;
- }
- return 0;
- } else {
- /* BGR */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- }
- else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = b;
- *pcache++ = g;
- *pcache++ = r;
- break;
- }
- case 2: {
- *p3 = b;
- *(p3 + 1) = g;
- *pcache++ = r;
- break;
- }
- default: {
- SAM("MISTAKE: %i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- }
- p2 += 2;
- if (isuy)
- isuy = false;
- else
- isuy = true;
- p3 += bytesperpixel;
- }
- }
- return 0;
- } else {
- if (!byteswaporder) {
- /* RGB DECIMATED */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- if (isuy) {
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] -
- gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = r;
- *pcache++ = g;
- *pcache++ = b;
- break;
- }
- case 2: {
- *p3 = r;
- *(p3 + 1) = g;
- *pcache++ = b;
- break;
- }
- default: {
- SAM("MISTAKE: "
- "%i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- }
- isuy = false;
- p3 += bytesperpixel;
- } else {
- isuy = true;
- }
- p2 += 2;
- }
- return 0;
- } else {
- /* BGR DECIMATED */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- if (isuy) {
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] -
- gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = b;
- *pcache++ = g;
- *pcache++ = r;
- break;
- }
- case 2: {
- *p3 = b;
- *(p3 + 1) = g;
- *pcache++ = r;
- break;
- }
- default: {
- SAM("MISTAKE: "
- "%i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- }
- isuy = false;
- p3 += bytesperpixel;
- }
- else
- isuy = true;
- p2 += 2;
- }
- return 0;
- }
- }
- break;
- }
- case 4:
- {
- if (!decimatepixel) {
- if (!byteswaporder) {
- /* RGBA */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = r;
- *pcache++ = g;
- *pcache++ = b;
- *pcache++ = 0;
- break;
- }
- case 2: {
- *p3 = r;
- *(p3 + 1) = g;
- *pcache++ = b;
- *pcache++ = 0;
- break;
- }
- case 3: {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- *pcache++ = 0;
- break;
- }
- default: {
- SAM("MISTAKE: %i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- *(p3 + 3) = 0;
- }
- p2 += 2;
- if (isuy)
- isuy = false;
- else
- isuy = true;
- p3 += bytesperpixel;
- }
- return 0;
- } else {
- /*
- * BGRA
- */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = b;
- *pcache++ = g;
- *pcache++ = r;
- *pcache++ = 0;
- break;
- }
- case 2: {
- *p3 = b;
- *(p3 + 1) = g;
- *pcache++ = r;
- *pcache++ = 0;
- break;
- }
- case 3: {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- *pcache++ = 0;
- break;
- }
- default:
- SAM("MISTAKE: %i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- } else {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- *(p3 + 3) = 0;
- }
- p2 += 2;
- if (isuy)
- isuy = false;
- else
- isuy = true;
- p3 += bytesperpixel;
- }
- }
- return 0;
- } else {
- if (!byteswaporder) {
- /*
- * RGBA DECIMATED
- */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- if (isuy) {
-
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] -
- gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = r;
- *pcache++ = g;
- *pcache++ = b;
- *pcache++ = 0;
- break;
- }
- case 2: {
- *p3 = r;
- *(p3 + 1) = g;
- *pcache++ = b;
- *pcache++ = 0;
- break;
- }
- case 3: {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- *pcache++ = 0;
- break;
- }
- default: {
- SAM("MISTAKE: "
- "%i=rump\n",
- bytesperpixel -
- rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = r;
- *(p3 + 1) = g;
- *(p3 + 2) = b;
- *(p3 + 3) = 0;
- }
- isuy = false;
- p3 += bytesperpixel;
- } else
- isuy = true;
- p2 += 2;
- }
- return 0;
- } else {
- /*
- * BGRA DECIMATED
- */
- while (pz > p2) {
- if (pr <= (p3 + bytesperpixel))
- last = true;
- else
- last = false;
- y = *p2;
- if (last && (0x0C & mask)) {
- if (0x04 & mask) {
- if (isuy)
- v = margin;
- else
- u = margin;
- } else
- if (0x08 & mask)
- ;
- } else {
- if (isuy)
- v = *(p2 + 1);
- else
- u = *(p2 + 1);
- }
-
- if (isuy) {
- tmp = ay[(int)y] + rv[(int)v];
- r = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] - gu[(int)u] -
- gv[(int)v];
- g = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
- tmp = ay[(int)y] + bu[(int)u];
- b = (255 < tmp) ? 255 : ((0 > tmp) ?
- 0 : (u8)tmp);
-
- if (last && rump) {
- pcache = &peasycap->cache[0];
- switch (bytesperpixel - rump) {
- case 1: {
- *p3 = b;
- *pcache++ = g;
- *pcache++ = r;
- *pcache++ = 0;
- break;
- }
- case 2: {
- *p3 = b;
- *(p3 + 1) = g;
- *pcache++ = r;
- *pcache++ = 0;
- break;
- }
- case 3: {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- *pcache++ = 0;
- break;
- }
- default: {
- SAM("MISTAKE: "
- "%i=rump\n",
- bytesperpixel - rump);
- return -EFAULT;
- }
- }
- } else {
- *p3 = b;
- *(p3 + 1) = g;
- *(p3 + 2) = r;
- *(p3 + 3) = 0;
- }
- isuy = false;
- p3 += bytesperpixel;
- } else
- isuy = true;
- p2 += 2;
- }
- return 0;
- }
- }
- break;
- }
- default: {
- SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
- return -EFAULT;
- }
- }
- return 0;
-}
-/*****************************************************************************/
-/*
- * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
- */
-/*****************************************************************************/
-static void easycap_vma_open(struct vm_area_struct *pvma)
-{
- struct easycap *peasycap;
-
- peasycap = pvma->vm_private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return;
- }
- peasycap->vma_many++;
- JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
- return;
-}
-/*****************************************************************************/
-static void easycap_vma_close(struct vm_area_struct *pvma)
-{
- struct easycap *peasycap;
-
- peasycap = pvma->vm_private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return;
- }
- peasycap->vma_many--;
- JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
- return;
-}
-/*****************************************************************************/
-static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
-{
- int k, m, retcode;
- void *pbuf;
- struct page *page;
- struct easycap *peasycap;
-
- retcode = VM_FAULT_NOPAGE;
-
- if (!pvma) {
- SAY("pvma is NULL\n");
- return retcode;
- }
- if (!pvmf) {
- SAY("pvmf is NULL\n");
- return retcode;
- }
-
- k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
- m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
-
- if (!m)
- JOT(4, "%4i=k, %4i=m\n", k, m);
- else
- JOT(16, "%4i=k, %4i=m\n", k, m);
-
- if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
- SAY("ERROR: buffer index %i out of range\n", k);
- return retcode;
- }
- if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
- SAY("ERROR: page number %i out of range\n", m);
- return retcode;
- }
- peasycap = pvma->vm_private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return retcode;
- }
-/*---------------------------------------------------------------------------*/
- pbuf = peasycap->frame_buffer[k][m].pgo;
- if (!pbuf) {
- SAM("ERROR: pbuf is NULL\n");
- return retcode;
- }
- page = virt_to_page(pbuf);
- if (!page) {
- SAM("ERROR: page is NULL\n");
- return retcode;
- }
- get_page(page);
-/*---------------------------------------------------------------------------*/
- if (!page) {
- SAM("ERROR: page is NULL after get_page(page)\n");
- } else {
- pvmf->page = page;
- retcode = VM_FAULT_MINOR;
- }
- return retcode;
-}
-
-static const struct vm_operations_struct easycap_vm_ops = {
- .open = easycap_vma_open,
- .close = easycap_vma_close,
- .fault = easycap_vma_fault,
-};
-
-static int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
-{
- JOT(8, "\n");
-
- pvma->vm_ops = &easycap_vm_ops;
- pvma->vm_flags |= VM_RESERVED;
- if (file)
- pvma->vm_private_data = file->private_data;
- easycap_vma_open(pvma);
- return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
- * PROVIDED peasycap->video_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
- * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
- *
- * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
- *
- * INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
- * STORED IN THE TWO-BYTE STATUS PARAMETER
- * peasycap->field_buffer[peasycap->field_fill][0].kount
- * NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
- *
- * THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
- * CHIP.
- *
- * THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
- * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS
- * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA
- * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA
- * 0 != (kount & 0x1000) => BUFFER HAS DATA FROM DISPARATE INPUTS
- * 0 != (kount & 0x0400) => RESERVED
- * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED
- * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY?
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_complete(struct urb *purb)
-{
- struct easycap *peasycap;
- struct data_buffer *pfield_buffer;
- char errbuf[16];
- int i, more, much, leap, rc, last;
- int videofieldamount;
- unsigned int override, bad;
- int framestatus, framelength, frameactual, frameoffset;
- u8 *pu;
-
- if (!purb) {
- SAY("ERROR: easycap_complete(): purb is NULL\n");
- return;
- }
- peasycap = purb->context;
- if (!peasycap) {
- SAY("ERROR: easycap_complete(): peasycap is NULL\n");
- return;
- }
- if (peasycap->video_eof)
- return;
- for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
- if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
- break;
- JOM(16, "%2i=urb\n", i);
- last = peasycap->video_isoc_sequence;
- if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) ||
- (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) {
- JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n",
- last, i);
- }
- peasycap->video_isoc_sequence = i;
-
- if (peasycap->video_idle) {
- JOM(16, "%i=video_idle %i=video_isoc_streaming\n",
- peasycap->video_idle, peasycap->video_isoc_streaming);
- if (peasycap->video_isoc_streaming) {
- rc = usb_submit_urb(purb, GFP_ATOMIC);
- if (rc) {
- SAM("%s:%d ENOMEM\n", strerror(rc), rc);
- if (-ENODEV != rc)
- SAM("ERROR: while %i=video_idle, "
- "usb_submit_urb() "
- "failed with rc:\n",
- peasycap->video_idle);
- }
- }
- return;
- }
- override = 0;
-/*---------------------------------------------------------------------------*/
- if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAM("ERROR: bad peasycap->field_fill\n");
- return;
- }
- if (purb->status) {
- if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
- JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
- return;
- }
-
- (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
- SAM("ERROR: bad urb status -%s: %d\n",
- strerror(purb->status), purb->status);
-/*---------------------------------------------------------------------------*/
- } else {
- for (i = 0; i < purb->number_of_packets; i++) {
- if (0 != purb->iso_frame_desc[i].status) {
- (peasycap->field_buffer
- [peasycap->field_fill][0].kount) |= 0x8000 ;
- /* FIXME: 1. missing '-' check boundaries */
- strcpy(&errbuf[0],
- strerror(purb->iso_frame_desc[i].status));
- }
- framestatus = purb->iso_frame_desc[i].status;
- framelength = purb->iso_frame_desc[i].length;
- frameactual = purb->iso_frame_desc[i].actual_length;
- frameoffset = purb->iso_frame_desc[i].offset;
-
- JOM(16, "frame[%2i]:"
- "%4i=status "
- "%4i=actual "
- "%4i=length "
- "%5i=offset\n",
- i, framestatus, frameactual, framelength, frameoffset);
- if (!purb->iso_frame_desc[i].status) {
- more = purb->iso_frame_desc[i].actual_length;
- pfield_buffer = &peasycap->field_buffer
- [peasycap->field_fill][peasycap->field_page];
- videofieldamount = (peasycap->field_page *
- PAGE_SIZE) +
- (int)(pfield_buffer->pto - pfield_buffer->pgo);
- if (4 == more)
- peasycap->video_mt++;
- if (4 < more) {
- if (peasycap->video_mt) {
- JOM(8, "%4i empty video urb frames\n",
- peasycap->video_mt);
- peasycap->video_mt = 0;
- }
- if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAM("ERROR: bad peasycap->field_fill\n");
- return;
- }
- if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
- peasycap->field_page) {
- SAM("ERROR: bad peasycap->field_page\n");
- return;
- }
- pfield_buffer = &peasycap->field_buffer
- [peasycap->field_fill][peasycap->field_page];
- pu = (u8 *)(purb->transfer_buffer +
- purb->iso_frame_desc[i].offset);
- if (0x80 & *pu)
- leap = 8;
- else
- leap = 4;
-/*--------------------------------------------------------------------------*/
-/*
- * EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
- * NOTE: A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
- * CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
- *
- * PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
- * BYTE OF
- * peasycap->field_buffer[peasycap->field_fill][0].kount
- * THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
- * UPDATED AND field_fill IS BUMPED. IF THE FIELD BUFFER CONTAINS BAD DATA
- * NOTHING IS OFFERED TO dqbuf().
- *
- * THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
- * RESTS WITH dqbuf().
- */
-/*---------------------------------------------------------------------------*/
- if ((8 == more) || override) {
- if (videofieldamount >
- peasycap->videofieldamount) {
- if (2 == videofieldamount -
- peasycap->
- videofieldamount) {
- (peasycap->field_buffer
- [peasycap->field_fill]
- [0].kount) |= 0x0100;
- peasycap->video_junk += (1 +
- VIDEO_JUNK_TOLERATE);
- } else
- (peasycap->field_buffer
- [peasycap->field_fill]
- [0].kount) |= 0x4000;
- } else if (videofieldamount <
- peasycap->
- videofieldamount) {
- (peasycap->field_buffer
- [peasycap->field_fill]
- [0].kount) |= 0x2000;
- }
- bad = 0xFF00 & peasycap->field_buffer
- [peasycap->field_fill]
- [0].kount;
- if (!bad) {
- (peasycap->video_junk)--;
- if (-VIDEO_JUNK_TOLERATE >
- peasycap->video_junk)
- peasycap->video_junk =
- -VIDEO_JUNK_TOLERATE;
- peasycap->field_read =
- (peasycap->
- field_fill)++;
- if (FIELD_BUFFER_MANY <=
- peasycap->
- field_fill)
- peasycap->
- field_fill = 0;
- peasycap->field_page = 0;
- pfield_buffer = &peasycap->
- field_buffer
- [peasycap->
- field_fill]
- [peasycap->
- field_page];
- pfield_buffer->pto =
- pfield_buffer->pgo;
- JOM(8, "bumped to: %i="
- "peasycap->"
- "field_fill %i="
- "parity\n",
- peasycap->field_fill,
- 0x00FF &
- pfield_buffer->kount);
- JOM(8, "field buffer %i has "
- "%i bytes fit to be "
- "read\n",
- peasycap->field_read,
- videofieldamount);
- JOM(8, "wakeup call to "
- "wq_video, "
- "%i=field_read "
- "%i=field_fill "
- "%i=parity\n",
- peasycap->field_read,
- peasycap->field_fill,
- 0x00FF & peasycap->
- field_buffer
- [peasycap->
- field_read][0].kount);
- wake_up_interruptible
- (&(peasycap->
- wq_video));
- } else {
- peasycap->video_junk++;
- if (bad & 0x0010)
- peasycap->video_junk +=
- (1 + VIDEO_JUNK_TOLERATE/2);
- JOM(8, "field buffer %i had %i "
- "bytes, now discarded: "
- "0x%04X\n",
- peasycap->field_fill,
- videofieldamount,
- (0xFF00 &
- peasycap->field_buffer
- [peasycap->field_fill][0].
- kount));
- (peasycap->field_fill)++;
-
- if (FIELD_BUFFER_MANY <=
- peasycap->field_fill)
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- pfield_buffer =
- &peasycap->field_buffer
- [peasycap->field_fill]
- [peasycap->field_page];
- pfield_buffer->pto =
- pfield_buffer->pgo;
-
- JOM(8, "bumped to: %i=peasycap->"
- "field_fill %i=parity\n",
- peasycap->field_fill,
- 0x00FF & pfield_buffer->kount);
- }
- if (8 == more) {
- JOM(8, "end-of-field: received "
- "parity byte 0x%02X\n",
- (0xFF & *pu));
- if (0x40 & *pu)
- pfield_buffer->kount = 0x0000;
- else
- pfield_buffer->kount = 0x0001;
- pfield_buffer->input = 0x08 |
- (0x07 & peasycap->input);
- JOM(8, "end-of-field: 0x%02X=kount\n",
- 0xFF & pfield_buffer->kount);
- }
- }
-/*---------------------------------------------------------------------------*/
-/*
- * COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
- */
-/*---------------------------------------------------------------------------*/
- pu += leap;
- more -= leap;
-
- if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAM("ERROR: bad peasycap->field_fill\n");
- return;
- }
- if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) {
- SAM("ERROR: bad peasycap->field_page\n");
- return;
- }
- pfield_buffer = &peasycap->field_buffer
- [peasycap->field_fill][peasycap->field_page];
- while (more) {
- pfield_buffer = &peasycap->field_buffer
- [peasycap->field_fill]
- [peasycap->field_page];
- if (PAGE_SIZE < (pfield_buffer->pto -
- pfield_buffer->pgo)) {
- SAM("ERROR: bad pfield_buffer->pto\n");
- return;
- }
- if (PAGE_SIZE == (pfield_buffer->pto -
- pfield_buffer->pgo)) {
- (peasycap->field_page)++;
- if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
- peasycap->field_page) {
- JOM(16, "wrapping peasycap->"
- "field_page\n");
- peasycap->field_page = 0;
- }
- pfield_buffer = &peasycap->
- field_buffer
- [peasycap->field_fill]
- [peasycap->field_page];
- pfield_buffer->pto = pfield_buffer->pgo;
- pfield_buffer->input = 0x08 |
- (0x07 & peasycap->input);
- if ((peasycap->field_buffer[peasycap->
- field_fill][0]).
- input !=
- pfield_buffer->input)
- (peasycap->field_buffer
- [peasycap->field_fill]
- [0]).kount |= 0x1000;
- }
-
- much = PAGE_SIZE -
- (int)(pfield_buffer->pto -
- pfield_buffer->pgo);
-
- if (much > more)
- much = more;
- memcpy(pfield_buffer->pto, pu, much);
- pu += much;
- (pfield_buffer->pto) += much;
- more -= much;
- }
- }
- }
- }
- }
-/*---------------------------------------------------------------------------*/
-/*
- * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
- *
- * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
- * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
- */
-/*---------------------------------------------------------------------------*/
- if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
- SAM("easycap driver shutting down on condition green\n");
- peasycap->status = 1;
- peasycap->video_eof = 1;
- peasycap->video_junk = 0;
- wake_up_interruptible(&peasycap->wq_video);
-#if !defined(PERSEVERE)
- peasycap->audio_eof = 1;
- wake_up_interruptible(&peasycap->wq_audio);
-#endif /*PERSEVERE*/
- return;
- }
- if (peasycap->video_isoc_streaming) {
- rc = usb_submit_urb(purb, GFP_ATOMIC);
- if (rc) {
- SAM("%s: %d\n", strerror(rc), rc);
- if (-ENODEV != rc)
- SAM("ERROR: while %i=video_idle, "
- "usb_submit_urb() "
- "failed with rc:\n",
- peasycap->video_idle);
- }
- }
- return;
-}
-
-static struct easycap *alloc_easycap(u8 bInterfaceNumber)
-{
- struct easycap *peasycap;
- int i;
-
- peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
- if (!peasycap) {
- SAY("ERROR: Could not allocate peasycap\n");
- return NULL;
- }
-
- if (mutex_lock_interruptible(&mutex_dongle)) {
- SAY("ERROR: cannot lock mutex_dongle\n");
- kfree(peasycap);
- return NULL;
- }
-
- /* Find a free dongle in easycapdc60_dongle array */
- for (i = 0; i < DONGLE_MANY; i++) {
-
- if ((!easycapdc60_dongle[i].peasycap) &&
- (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) &&
- (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) {
-
- easycapdc60_dongle[i].peasycap = peasycap;
- peasycap->isdongle = i;
- JOM(8, "intf[%i]: peasycap-->easycap"
- "_dongle[%i].peasycap\n",
- bInterfaceNumber, i);
- break;
- }
- }
-
- mutex_unlock(&mutex_dongle);
-
- if (i >= DONGLE_MANY) {
- SAM("ERROR: too many dongles\n");
- kfree(peasycap);
- return NULL;
- }
-
- return peasycap;
-}
-
-static void free_easycap(struct easycap *peasycap)
-{
- int allocation_video_urb;
- int allocation_video_page;
- int allocation_video_struct;
- int allocation_audio_urb;
- int allocation_audio_page;
- int allocation_audio_struct;
- int registered_video, registered_audio;
- int kd;
-
- JOM(4, "freeing easycap structure.\n");
- allocation_video_urb = peasycap->allocation_video_urb;
- allocation_video_page = peasycap->allocation_video_page;
- allocation_video_struct = peasycap->allocation_video_struct;
- registered_video = peasycap->registered_video;
- allocation_audio_urb = peasycap->allocation_audio_urb;
- allocation_audio_page = peasycap->allocation_audio_page;
- allocation_audio_struct = peasycap->allocation_audio_struct;
- registered_audio = peasycap->registered_audio;
-
- kd = easycap_isdongle(peasycap);
- if (0 <= kd && DONGLE_MANY > kd) {
- if (mutex_lock_interruptible(&mutex_dongle)) {
- SAY("ERROR: cannot down mutex_dongle\n");
- } else {
- JOM(4, "locked mutex_dongle\n");
- easycapdc60_dongle[kd].peasycap = NULL;
- mutex_unlock(&mutex_dongle);
- JOM(4, "unlocked mutex_dongle\n");
- JOT(4, " null-->dongle[%i].peasycap\n", kd);
- allocation_video_struct -= sizeof(struct easycap);
- }
- } else {
- SAY("ERROR: cannot purge dongle[].peasycap");
- }
-
- /* Free device structure */
- kfree(peasycap);
-
- SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
- SAY("%8i=video pages after all deletions\n", allocation_video_page);
- SAY("%8i=video structs after all deletions\n", allocation_video_struct);
- SAY("%8i=video devices after all deletions\n", registered_video);
- SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
- SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
- SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
- SAY("%8i=audio devices after all deletions\n", registered_audio);
-}
-
-/*
- * FIXME: Identify the appropriate pointer peasycap for interfaces
- * 1 and 2. The address of peasycap->pusb_device is reluctantly used
- * for this purpose.
- */
-static struct easycap *get_easycap(struct usb_device *usbdev,
- u8 bInterfaceNumber)
-{
- int i;
- struct easycap *peasycap;
-
- for (i = 0; i < DONGLE_MANY; i++) {
- if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) {
- peasycap = easycapdc60_dongle[i].peasycap;
- JOT(8, "intf[%i]: dongle[%i].peasycap\n",
- bInterfaceNumber, i);
- break;
- }
- }
- if (i >= DONGLE_MANY) {
- SAY("ERROR: peasycap is unknown when probing interface %i\n",
- bInterfaceNumber);
- return NULL;
- }
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL when probing interface %i\n",
- bInterfaceNumber);
- return NULL;
- }
-
- return peasycap;
-}
-
-static void init_easycap(struct easycap *peasycap,
- struct usb_device *usbdev,
- struct usb_interface *intf,
- u8 bInterfaceNumber)
-{
- /* Save usb_device and usb_interface */
- peasycap->pusb_device = usbdev;
- peasycap->pusb_interface = intf;
-
- peasycap->minor = -1;
- kref_init(&peasycap->kref);
- JOM(8, "intf[%i]: after kref_init(..._video) "
- "%i=peasycap->kref.refcount.counter\n",
- bInterfaceNumber, peasycap->kref.refcount.counter);
-
- /* module params */
- peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
-
- init_waitqueue_head(&peasycap->wq_video);
- init_waitqueue_head(&peasycap->wq_audio);
- init_waitqueue_head(&peasycap->wq_trigger);
-
- peasycap->allocation_video_struct = sizeof(struct easycap);
-
- peasycap->microphone = false;
-
- peasycap->video_interface = -1;
- peasycap->video_altsetting_on = -1;
- peasycap->video_altsetting_off = -1;
- peasycap->video_endpointnumber = -1;
- peasycap->video_isoc_maxframesize = -1;
- peasycap->video_isoc_buffer_size = -1;
-
- peasycap->audio_interface = -1;
- peasycap->audio_altsetting_on = -1;
- peasycap->audio_altsetting_off = -1;
- peasycap->audio_endpointnumber = -1;
- peasycap->audio_isoc_maxframesize = -1;
- peasycap->audio_isoc_buffer_size = -1;
-
- peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
-
- peasycap->ntsc = easycap_ntsc;
- JOM(8, "defaulting initially to %s\n",
- easycap_ntsc ? "NTSC" : "PAL");
-}
-
-static int populate_inputset(struct easycap *peasycap)
-{
- struct inputset *inputset;
- struct easycap_format *peasycap_format;
- struct v4l2_pix_format *pix;
- int m, i, k, mask, fmtidx;
- s32 value;
-
- inputset = peasycap->inputset;
-
- fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
-
- m = 0;
- mask = 0;
- for (i = 0; easycap_standard[i].mask != 0xffff; i++) {
- if (fmtidx == easycap_standard[i].v4l2_standard.index) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].standard_offset = i;
- mask = easycap_standard[i].mask;
- }
- }
-
- if (m != 1) {
- SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m);
- return -ENOENT;
- }
-
- peasycap_format = &easycap_format[0];
- m = 0;
- for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
- pix = &peasycap_format->v4l2_format.fmt.pix;
- if (((peasycap_format->mask & 0x0F) == (mask & 0x0F))
- && pix->field == V4L2_FIELD_NONE
- && pix->pixelformat == V4L2_PIX_FMT_UYVY
- && pix->width == 640 && pix->height == 480) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].format_offset = i;
- break;
- }
- peasycap_format++;
- }
- if (m != 1) {
- SAM("ERROR: inputset[]->format_offset unpopulated\n");
- return -ENOENT;
- }
-
- m = 0;
- for (i = 0; easycap_control[i].id != 0xffffffff; i++) {
- value = easycap_control[i].default_value;
- if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].brightness = value;
- } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].contrast = value;
- } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].saturation = value;
- } else if (V4L2_CID_HUE == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].hue = value;
- }
- }
-
- if (m != 4) {
- SAM("ERROR: inputset[]->brightness underpopulated\n");
- return -ENOENT;
- }
-
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].input = k;
- JOM(4, "populated inputset[]\n");
-
- return 0;
-}
-
-static int alloc_framebuffers(struct easycap *peasycap)
-{
- int i, j;
- void *pbuf;
-
- JOM(4, "allocating %i frame buffers of size %li\n",
- FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FRAME_BUFFER_SIZE/PAGE_SIZE);
-
- for (i = 0; i < FRAME_BUFFER_MANY; i++) {
- for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) {
- if (peasycap->frame_buffer[i][j].pgo)
- SAM("attempting to reallocate framebuffers\n");
- else {
- pbuf = (void *)__get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate "
- "framebuffer %i page %i\n", i, j);
- return -ENOMEM;
- }
- peasycap->allocation_video_page += 1;
- peasycap->frame_buffer[i][j].pgo = pbuf;
- }
- peasycap->frame_buffer[i][j].pto =
- peasycap->frame_buffer[i][j].pgo;
- }
- }
-
- peasycap->frame_fill = 0;
- peasycap->frame_read = 0;
- JOM(4, "allocation of frame buffers done: %i pages\n", i*j);
-
- return 0;
-}
-
-static void free_framebuffers(struct easycap *peasycap)
-{
- int k, m, gone;
-
- JOM(4, "freeing video frame buffers.\n");
- gone = 0;
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->frame_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->frame_buffer[k][m].pgo);
- peasycap->frame_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video frame buffers freed: %i pages\n", gone);
-}
-
-static int alloc_fieldbuffers(struct easycap *peasycap)
-{
- int i, j;
- void *pbuf;
-
- JOM(4, "allocating %i field buffers of size %li\n",
- FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FIELD_BUFFER_SIZE/PAGE_SIZE);
-
- for (i = 0; i < FIELD_BUFFER_MANY; i++) {
- for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) {
- if (peasycap->field_buffer[i][j].pgo) {
- SAM("ERROR: attempting to reallocate "
- "fieldbuffers\n");
- } else {
- pbuf = (void *) __get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate "
- "fieldbuffer %i page %i\n", i, j);
- return -ENOMEM;
- }
- peasycap->allocation_video_page += 1;
- peasycap->field_buffer[i][j].pgo = pbuf;
- }
- peasycap->field_buffer[i][j].pto =
- peasycap->field_buffer[i][j].pgo;
- }
- /* TODO: Hardcoded 0x0200 meaning? */
- peasycap->field_buffer[i][0].kount = 0x0200;
- }
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- peasycap->field_read = 0;
- JOM(4, "allocation of field buffers done: %i pages\n", i*j);
-
- return 0;
-}
-
-static void free_fieldbuffers(struct easycap *peasycap)
-{
- int k, m, gone;
-
- JOM(4, "freeing video field buffers.\n");
- gone = 0;
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->field_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->field_buffer[k][m].pgo);
- peasycap->field_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video field buffers freed: %i pages\n", gone);
-}
-
-static int alloc_isocbuffers(struct easycap *peasycap)
-{
- int i;
- void *pbuf;
-
- JOM(4, "allocating %i isoc video buffers of size %i\n",
- VIDEO_ISOC_BUFFER_MANY,
- peasycap->video_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL,
- VIDEO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc "
- "video buffer %i\n", i);
- return -ENOMEM;
- }
- peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER);
-
- peasycap->video_isoc_buffer[i].pgo = pbuf;
- peasycap->video_isoc_buffer[i].pto =
- pbuf + peasycap->video_isoc_buffer_size;
- peasycap->video_isoc_buffer[i].kount = i;
- }
- JOM(4, "allocation of isoc video buffers done: %i pages\n",
- i * (0x01 << VIDEO_ISOC_ORDER));
- return 0;
-}
-
-static void free_isocbuffers(struct easycap *peasycap)
-{
- int k, m;
-
- JOM(4, "freeing video isoc buffers.\n");
- m = 0;
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->video_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- peasycap->video_isoc_buffer[k].pgo,
- VIDEO_ISOC_ORDER);
- peasycap->video_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_video_page -=
- BIT(VIDEO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "isoc video buffers freed: %i pages\n",
- m * (0x01 << VIDEO_ISOC_ORDER));
-}
-
-static int create_video_urbs(struct easycap *peasycap)
-{
- struct urb *purb;
- struct data_urb *pdata_urb;
- int i, j;
-
- JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
- peasycap->video_isoc_buffer_size);
-
- for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
- purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", i);
- return -ENOMEM;
- }
-
- peasycap->allocation_video_urb += 1;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- usb_free_urb(purb);
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
-
- peasycap->allocation_video_struct +=
- sizeof(struct data_urb);
-
- pdata_urb->purb = purb;
- pdata_urb->isbuf = i;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_video_head);
-
- if (!i) {
- JOM(4, "initializing video urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe"
- "(peasycap->pusb_device,%i);\n",
- peasycap->video_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = peasycap->"
- "video_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->video_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " }\n");
- }
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->video_endpointnumber);
-
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo;
- purb->transfer_buffer_length =
- peasycap->video_isoc_buffer_size;
-
- purb->complete = easycap_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->video_isoc_framesperdesc;
-
- for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset =
- j * peasycap->video_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->video_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", i);
- return 0;
-}
-
-static void free_video_urbs(struct easycap *peasycap)
-{
- struct list_head *plist_head, *plist_next;
- struct data_urb *pdata_urb;
- int m;
-
- if (peasycap->purb_video_head) {
- m = 0;
- list_for_each(plist_head, peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_video_urb--;
- m++;
- }
- }
-
- JOM(4, "%i video urbs freed\n", m);
- JOM(4, "freeing video data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_video_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i video data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_video_head=NULL\n");
- peasycap->purb_video_head = NULL;
- }
-}
-
-static int alloc_audio_buffers(struct easycap *peasycap)
-{
- void *pbuf;
- int k;
-
- JOM(4, "allocating %i isoc audio buffers of size %i\n",
- AUDIO_ISOC_BUFFER_MANY,
- peasycap->audio_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc audio buffer %i\n",
- k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER);
-
- peasycap->audio_isoc_buffer[k].pgo = pbuf;
- peasycap->audio_isoc_buffer[k].pto =
- pbuf + peasycap->audio_isoc_buffer_size;
- peasycap->audio_isoc_buffer[k].kount = k;
- }
-
- JOM(4, "allocation of isoc audio buffers done.\n");
- return 0;
-}
-
-static void free_audio_buffers(struct easycap *peasycap)
-{
- int k, m;
-
- JOM(4, "freeing audio isoc buffers.\n");
- m = 0;
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->audio_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- (peasycap->audio_isoc_buffer[k].pgo),
- AUDIO_ISOC_ORDER);
- peasycap->audio_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_audio_page -=
- BIT(AUDIO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
- m * (0x01 << AUDIO_ISOC_ORDER));
-}
-
-static int create_audio_urbs(struct easycap *peasycap)
-{
- struct urb *purb;
- struct data_urb *pdata_urb;
- int k, j;
-
- JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
- peasycap->audio_isoc_buffer_size);
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_urb += 1 ;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- usb_free_urb(purb);
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
- peasycap->allocation_audio_struct +=
- sizeof(struct data_urb);
-
- pdata_urb->purb = purb;
- pdata_urb->isbuf = k;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_audio_head);
-
- if (!k) {
- JOM(4, "initializing audio urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
- "pusb_device,%i);\n",
- peasycap->audio_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = "
- "peasycap->audio_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->audio_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_alsa_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " }\n");
- }
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->audio_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
- purb->transfer_buffer_length =
- peasycap->audio_isoc_buffer_size;
- purb->complete = easycap_alsa_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
- for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset =
- j * peasycap->audio_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->audio_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", k);
- return 0;
-}
-
-static void free_audio_urbs(struct easycap *peasycap)
-{
- struct list_head *plist_head, *plist_next;
- struct data_urb *pdata_urb;
- int m;
-
- if (peasycap->purb_audio_head) {
- JOM(4, "freeing audio urbs\n");
- m = 0;
- list_for_each(plist_head, (peasycap->purb_audio_head)) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_audio_urb--;
- m++;
- }
- }
- JOM(4, "%i audio urbs freed\n", m);
- JOM(4, "freeing audio data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_audio_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_audio_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i audio data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_audio_head=NULL\n");
- peasycap->purb_audio_head = NULL;
- }
-}
-
-static void config_easycap(struct easycap *peasycap,
- u8 bInterfaceNumber,
- u8 bInterfaceClass,
- u8 bInterfaceSubClass)
-{
- if ((USB_CLASS_VIDEO == bInterfaceClass) ||
- (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
- if (-1 == peasycap->video_interface) {
- peasycap->video_interface = bInterfaceNumber;
- JOM(4, "setting peasycap->video_interface=%i\n",
- peasycap->video_interface);
- } else {
- if (peasycap->video_interface != bInterfaceNumber) {
- SAM("ERROR: attempting to reset "
- "peasycap->video_interface\n");
- SAM("...... continuing with "
- "%i=peasycap->video_interface\n",
- peasycap->video_interface);
- }
- }
- } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
- (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
- if (-1 == peasycap->audio_interface) {
- peasycap->audio_interface = bInterfaceNumber;
- JOM(4, "setting peasycap->audio_interface=%i\n",
- peasycap->audio_interface);
- } else {
- if (peasycap->audio_interface != bInterfaceNumber) {
- SAM("ERROR: attempting to reset "
- "peasycap->audio_interface\n");
- SAM("...... continuing with "
- "%i=peasycap->audio_interface\n",
- peasycap->audio_interface);
- }
- }
- }
-}
-
-/*
- * This function is called from within easycap_usb_disconnect() and is
- * protected by semaphores set and cleared by easycap_usb_disconnect().
- * By this stage the device has already been physically unplugged,
- * so peasycap->pusb_device is no longer valid.
- */
-static void easycap_delete(struct kref *pkref)
-{
- struct easycap *peasycap;
-
- peasycap = container_of(pkref, struct easycap, kref);
- if (!peasycap) {
- SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
- return;
- }
-
- /* Free video urbs */
- free_video_urbs(peasycap);
-
- /* Free video isoc buffers */
- free_isocbuffers(peasycap);
-
- /* Free video field buffers */
- free_fieldbuffers(peasycap);
-
- /* Free video frame buffers */
- free_framebuffers(peasycap);
-
- /* Free audio urbs */
- free_audio_urbs(peasycap);
-
- /* Free audio isoc buffers */
- free_audio_buffers(peasycap);
-
- free_easycap(peasycap);
-
- JOT(4, "ending.\n");
-}
-
-static const struct v4l2_file_operations v4l2_fops = {
- .owner = THIS_MODULE,
- .open = easycap_open_noinode,
- .unlocked_ioctl = easycap_unlocked_ioctl,
- .poll = easycap_poll,
- .mmap = easycap_mmap,
-};
-
-static int easycap_register_video(struct easycap *peasycap)
-{
- /*
- * FIXME: This is believed to be harmless,
- * but may well be unnecessary or wrong.
- */
- peasycap->video_device.v4l2_dev = NULL;
-
- strcpy(&peasycap->video_device.name[0], "easycapdc60");
- peasycap->video_device.fops = &v4l2_fops;
- peasycap->video_device.minor = -1;
- peasycap->video_device.release = (void *)(&videodev_release);
-
- video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
- if (0 != (video_register_device(&(peasycap->video_device),
- VFL_TYPE_GRABBER, -1))) {
- videodev_release(&(peasycap->video_device));
- return -ENODEV;
- }
-
- peasycap->registered_video++;
-
- SAM("registered with videodev: %i=minor\n",
- peasycap->video_device.minor);
- peasycap->minor = peasycap->video_device.minor;
-
- return 0;
-}
-
-/*
- * When the device is plugged, this function is called three times,
- * one for each interface.
- */
-static int easycap_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *usbdev;
- struct usb_host_interface *alt;
- struct usb_endpoint_descriptor *ep;
- struct usb_interface_descriptor *interface;
- struct easycap *peasycap;
- int i, j, rc;
- u8 bInterfaceNumber;
- u8 bInterfaceClass;
- u8 bInterfaceSubClass;
- int okalt[8], isokalt;
- int okepn[8];
- int okmps[8];
- int maxpacketsize;
-
- usbdev = interface_to_usbdev(intf);
-
- alt = usb_altnum_to_altsetting(intf, 0);
- if (!alt) {
- SAY("ERROR: usb_host_interface not found\n");
- return -EFAULT;
- }
-
- interface = &alt->desc;
- if (!interface) {
- SAY("ERROR: intf_descriptor is NULL\n");
- return -EFAULT;
- }
-
- /* Get properties of probed interface */
- bInterfaceNumber = interface->bInterfaceNumber;
- bInterfaceClass = interface->bInterfaceClass;
- bInterfaceSubClass = interface->bInterfaceSubClass;
-
- JOT(4, "intf[%i]: num_altsetting=%i\n",
- bInterfaceNumber, intf->num_altsetting);
- JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
- bInterfaceNumber,
- (long int)(intf->cur_altsetting - intf->altsetting));
- JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
- bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
-
- /*
- * A new struct easycap is always allocated when interface 0 is probed.
- * It is not possible here to free any existing struct easycap.
- * This should have been done by easycap_delete() when the device was
- * physically unplugged.
- * The allocated struct easycap is saved for later usage when
- * interfaces 1 and 2 are probed.
- */
- if (0 == bInterfaceNumber) {
- /*
- * Alloc structure and save it in a free slot in
- * easycapdc60_dongle array
- */
- peasycap = alloc_easycap(bInterfaceNumber);
- if (!peasycap)
- return -ENOMEM;
-
- /* Perform basic struct initialization */
- init_easycap(peasycap, usbdev, intf, bInterfaceNumber);
-
- /* Dynamically fill in the available formats */
- rc = easycap_video_fillin_formats();
- if (0 > rc) {
- SAM("ERROR: fillin_formats() rc = %i\n", rc);
- return -EFAULT;
- }
- JOM(4, "%i formats available\n", rc);
-
- /* Populate easycap.inputset[] */
- rc = populate_inputset(peasycap);
- if (rc < 0)
- return rc;
- JOM(4, "finished initialization\n");
- } else {
- peasycap = get_easycap(usbdev, bInterfaceNumber);
- if (!peasycap)
- return -ENODEV;
- }
-
- config_easycap(peasycap, bInterfaceNumber,
- bInterfaceClass,
- bInterfaceSubClass);
-
- /*
- * Investigate all altsettings. This is done in detail
- * because USB device 05e1:0408 has disparate incarnations.
- */
- isokalt = 0;
- for (i = 0; i < intf->num_altsetting; i++) {
- alt = usb_altnum_to_altsetting(intf, i);
- if (!alt) {
- SAM("ERROR: alt is NULL\n");
- return -EFAULT;
- }
- interface = &alt->desc;
- if (!interface) {
- SAM("ERROR: intf_descriptor is NULL\n");
- return -EFAULT;
- }
-
- if (0 == interface->bNumEndpoints)
- JOM(4, "intf[%i]alt[%i] has no endpoints\n",
- bInterfaceNumber, i);
- for (j = 0; j < interface->bNumEndpoints; j++) {
- ep = &alt->endpoint[j].desc;
- if (!ep) {
- SAM("ERROR: ep is NULL.\n");
- SAM("...... skipping\n");
- continue;
- }
-
- if (!usb_endpoint_is_isoc_in(ep)) {
- JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n",
- bInterfaceNumber,
- i, j, ep->bmAttributes);
- if (usb_endpoint_dir_out(ep)) {
- SAM("ERROR: OUT endpoint unexpected\n");
- SAM("...... continuing\n");
- }
- continue;
- }
- switch (bInterfaceClass) {
- case USB_CLASS_VIDEO:
- case USB_CLASS_VENDOR_SPEC: {
- if (ep->wMaxPacketSize) {
- if (8 > isokalt) {
- okalt[isokalt] = i;
- JOM(4,
- "%i=okalt[%i]\n",
- okalt[isokalt],
- isokalt);
- okepn[isokalt] =
- ep->
- bEndpointAddress &
- 0x0F;
- JOM(4,
- "%i=okepn[%i]\n",
- okepn[isokalt],
- isokalt);
- okmps[isokalt] =
- le16_to_cpu(ep->
- wMaxPacketSize);
- JOM(4,
- "%i=okmps[%i]\n",
- okmps[isokalt],
- isokalt);
- isokalt++;
- }
- } else {
- if (-1 == peasycap->
- video_altsetting_off) {
- peasycap->
- video_altsetting_off =
- i;
- JOM(4, "%i=video_"
- "altsetting_off "
- "<====\n",
- peasycap->
- video_altsetting_off);
- } else {
- SAM("ERROR: peasycap"
- "->video_altsetting_"
- "off already set\n");
- SAM("...... "
- "continuing with "
- "%i=peasycap->video_"
- "altsetting_off\n",
- peasycap->
- video_altsetting_off);
- }
- }
- break;
- }
- case USB_CLASS_AUDIO: {
- if (bInterfaceSubClass !=
- USB_SUBCLASS_AUDIOSTREAMING)
- break;
- if (!peasycap) {
- SAM("MISTAKE: "
- "peasycap is NULL\n");
- return -EFAULT;
- }
- if (ep->wMaxPacketSize) {
- if (8 > isokalt) {
- okalt[isokalt] = i ;
- JOM(4,
- "%i=okalt[%i]\n",
- okalt[isokalt],
- isokalt);
- okepn[isokalt] =
- ep->
- bEndpointAddress &
- 0x0F;
- JOM(4,
- "%i=okepn[%i]\n",
- okepn[isokalt],
- isokalt);
- okmps[isokalt] =
- le16_to_cpu(ep->
- wMaxPacketSize);
- JOM(4,
- "%i=okmps[%i]\n",
- okmps[isokalt],
- isokalt);
- isokalt++;
- }
- } else {
- if (-1 == peasycap->
- audio_altsetting_off) {
- peasycap->
- audio_altsetting_off =
- i;
- JOM(4, "%i=audio_"
- "altsetting_off "
- "<====\n",
- peasycap->
- audio_altsetting_off);
- } else {
- SAM("ERROR: peasycap"
- "->audio_altsetting_"
- "off already set\n");
- SAM("...... "
- "continuing with "
- "%i=peasycap->"
- "audio_altsetting_"
- "off\n",
- peasycap->
- audio_altsetting_off);
- }
- }
- break;
- }
- default:
- break;
- }
- if (0 == ep->wMaxPacketSize) {
- JOM(4, "intf[%i]alt[%i]end[%i] "
- "has zero packet size\n",
- bInterfaceNumber, i, j);
- }
- }
- }
-
- /* Perform initialization of the probed interface */
- JOM(4, "initialization begins for interface %i\n",
- interface->bInterfaceNumber);
- switch (bInterfaceNumber) {
- /* 0: Video interface */
- case 0: {
- if (!peasycap) {
- SAM("MISTAKE: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!isokalt) {
- SAM("ERROR: no viable video_altsetting_on\n");
- return -ENOENT;
- }
- peasycap->video_altsetting_on = okalt[isokalt - 1];
- JOM(4, "%i=video_altsetting_on <====\n",
- peasycap->video_altsetting_on);
-
- /* Decide video streaming parameters */
- peasycap->video_endpointnumber = okepn[isokalt - 1];
- JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
- maxpacketsize = okmps[isokalt - 1];
-
- peasycap->video_isoc_maxframesize =
- min(maxpacketsize, USB_2_0_MAXPACKETSIZE);
- if (0 >= peasycap->video_isoc_maxframesize) {
- SAM("ERROR: bad video_isoc_maxframesize\n");
- SAM(" possibly because port is USB 1.1\n");
- return -ENOENT;
- }
- JOM(4, "%i=video_isoc_maxframesize\n",
- peasycap->video_isoc_maxframesize);
-
- peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
- JOM(4, "%i=video_isoc_framesperdesc\n",
- peasycap->video_isoc_framesperdesc);
- if (0 >= peasycap->video_isoc_framesperdesc) {
- SAM("ERROR: bad video_isoc_framesperdesc\n");
- return -ENOENT;
- }
- peasycap->video_isoc_buffer_size =
- peasycap->video_isoc_maxframesize *
- peasycap->video_isoc_framesperdesc;
- JOM(4, "%i=video_isoc_buffer_size\n",
- peasycap->video_isoc_buffer_size);
- if ((PAGE_SIZE << VIDEO_ISOC_ORDER) <
- peasycap->video_isoc_buffer_size) {
- SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_interface) {
- SAM("MISTAKE: video_interface is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_altsetting_on) {
- SAM("MISTAKE: video_altsetting_on is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_altsetting_off) {
- SAM("MISTAKE: video_interface_off is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_endpointnumber) {
- SAM("MISTAKE: video_endpointnumber is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_isoc_maxframesize) {
- SAM("MISTAKE: video_isoc_maxframesize is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->video_isoc_buffer_size) {
- SAM("MISTAKE: video_isoc_buffer_size is unset\n");
- return -EFAULT;
- }
-
- /*
- * Allocate memory for video buffers.
- * Lists must be initialized first.
- */
- INIT_LIST_HEAD(&(peasycap->urb_video_head));
- peasycap->purb_video_head = &(peasycap->urb_video_head);
-
- rc = alloc_framebuffers(peasycap);
- if (rc < 0)
- return rc;
-
- rc = alloc_fieldbuffers(peasycap);
- if (rc < 0)
- return rc;
-
- rc = alloc_isocbuffers(peasycap);
- if (rc < 0)
- return rc;
-
- /* Allocate and initialize video urbs */
- rc = create_video_urbs(peasycap);
- if (rc < 0)
- return rc;
-
- /* Save pointer peasycap in this interface */
- usb_set_intfdata(intf, peasycap);
-
- /*
- * It is essential to initialize the hardware before,
- * rather than after, the device is registered,
- * because some udev rules triggers easycap_open()
- * immediately after registration, causing a clash.
- */
- rc = reset(peasycap);
- if (rc) {
- SAM("ERROR: reset() rc = %i\n", rc);
- return -EFAULT;
- }
-
- /* The video device can now be registered */
- if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
- SAM("v4l2_device_register() failed\n");
- return -ENODEV;
- }
- JOM(4, "registered device instance: %s\n",
- peasycap->v4l2_device.name);
-
- rc = easycap_register_video(peasycap);
- if (rc < 0) {
- dev_err(&intf->dev,
- "Not able to register with videodev\n");
- return -ENODEV;
- }
- break;
- }
- /* 1: Audio control */
- case 1: {
- if (!peasycap) {
- SAM("MISTAKE: peasycap is NULL\n");
- return -EFAULT;
- }
- /* Save pointer peasycap in this interface */
- usb_set_intfdata(intf, peasycap);
- JOM(4, "no initialization required for interface %i\n",
- interface->bInterfaceNumber);
- break;
- }
- /* 2: Audio streaming */
- case 2: {
- if (!peasycap) {
- SAM("MISTAKE: peasycap is NULL\n");
- return -EFAULT;
- }
- if (!isokalt) {
- SAM("ERROR: no viable audio_altsetting_on\n");
- return -ENOENT;
- }
- peasycap->audio_altsetting_on = okalt[isokalt - 1];
- JOM(4, "%i=audio_altsetting_on <====\n",
- peasycap->audio_altsetting_on);
-
- peasycap->audio_endpointnumber = okepn[isokalt - 1];
- JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
-
- peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
- JOM(4, "%i=audio_isoc_maxframesize\n",
- peasycap->audio_isoc_maxframesize);
- if (0 >= peasycap->audio_isoc_maxframesize) {
- SAM("ERROR: bad audio_isoc_maxframesize\n");
- return -ENOENT;
- }
- if (9 == peasycap->audio_isoc_maxframesize) {
- peasycap->ilk |= 0x02;
- SAM("audio hardware is microphone\n");
- peasycap->microphone = true;
- peasycap->audio_pages_per_fragment =
- PAGES_PER_AUDIO_FRAGMENT;
- } else if (256 == peasycap->audio_isoc_maxframesize) {
- peasycap->ilk &= ~0x02;
- SAM("audio hardware is AC'97\n");
- peasycap->microphone = false;
- peasycap->audio_pages_per_fragment =
- PAGES_PER_AUDIO_FRAGMENT;
- } else {
- SAM("hardware is unidentified:\n");
- SAM("%i=audio_isoc_maxframesize\n",
- peasycap->audio_isoc_maxframesize);
- return -ENOENT;
- }
-
- peasycap->audio_bytes_per_fragment =
- peasycap->audio_pages_per_fragment * PAGE_SIZE;
- peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY *
- peasycap->audio_pages_per_fragment);
-
- JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
- JOM(4, "%6i=audio_pages_per_fragment\n",
- peasycap->audio_pages_per_fragment);
- JOM(4, "%6i=audio_bytes_per_fragment\n",
- peasycap->audio_bytes_per_fragment);
- JOM(4, "%6i=audio_buffer_page_many\n",
- peasycap->audio_buffer_page_many);
-
- peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
-
- JOM(4, "%i=audio_isoc_framesperdesc\n",
- peasycap->audio_isoc_framesperdesc);
- if (0 >= peasycap->audio_isoc_framesperdesc) {
- SAM("ERROR: bad audio_isoc_framesperdesc\n");
- return -ENOENT;
- }
-
- peasycap->audio_isoc_buffer_size =
- peasycap->audio_isoc_maxframesize *
- peasycap->audio_isoc_framesperdesc;
- JOM(4, "%i=audio_isoc_buffer_size\n",
- peasycap->audio_isoc_buffer_size);
- if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
- SAM("MISTAKE: audio_isoc_buffer_size bigger "
- "than %li=AUDIO_ISOC_BUFFER_SIZE\n",
- AUDIO_ISOC_BUFFER_SIZE);
- return -EFAULT;
- }
- if (-1 == peasycap->audio_interface) {
- SAM("MISTAKE: audio_interface is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->audio_altsetting_on) {
- SAM("MISTAKE: audio_altsetting_on is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->audio_altsetting_off) {
- SAM("MISTAKE: audio_interface_off is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->audio_endpointnumber) {
- SAM("MISTAKE: audio_endpointnumber is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->audio_isoc_maxframesize) {
- SAM("MISTAKE: audio_isoc_maxframesize is unset\n");
- return -EFAULT;
- }
- if (-1 == peasycap->audio_isoc_buffer_size) {
- SAM("MISTAKE: audio_isoc_buffer_size is unset\n");
- return -EFAULT;
- }
-
- /*
- * Allocate memory for audio buffers.
- * Lists must be initialized first.
- */
- INIT_LIST_HEAD(&(peasycap->urb_audio_head));
- peasycap->purb_audio_head = &(peasycap->urb_audio_head);
-
- alloc_audio_buffers(peasycap);
- if (rc < 0)
- return rc;
-
- /* Allocate and initialize urbs */
- rc = create_audio_urbs(peasycap);
- if (rc < 0)
- return rc;
-
- /* Save pointer peasycap in this interface */
- usb_set_intfdata(intf, peasycap);
-
- /* The audio device can now be registered */
- JOM(4, "initializing ALSA card\n");
-
- rc = easycap_alsa_probe(peasycap);
- if (rc) {
- dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
- rc);
- return -ENODEV;
- }
-
-
- JOM(8, "kref_get() with %i=kref.refcount.counter\n",
- peasycap->kref.refcount.counter);
- kref_get(&peasycap->kref);
- peasycap->registered_audio++;
- break;
- }
- /* Interfaces other than 0,1,2 are unexpected */
- default:
- JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
- return -EINVAL;
- }
- SAM("ends successfully for interface %i\n", bInterfaceNumber);
- return 0;
-}
-
-/*
- * When this function is called the device has already been
- * physically unplugged.
- * Hence, peasycap->pusb_device is no longer valid.
- * This function affects alsa.
- */
-static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
-{
- struct usb_host_interface *pusb_host_interface;
- struct usb_interface_descriptor *pusb_interface_descriptor;
- struct easycap *peasycap;
- int minor, kd;
- u8 bInterfaceNumber;
-
- JOT(4, "\n");
-
- pusb_host_interface = pusb_interface->cur_altsetting;
- if (!pusb_host_interface) {
- JOT(4, "ERROR: pusb_host_interface is NULL\n");
- return;
- }
- pusb_interface_descriptor = &(pusb_host_interface->desc);
- if (!pusb_interface_descriptor) {
- JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
- return;
- }
- bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
- minor = pusb_interface->minor;
- JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
-
- /* There is nothing to do for Interface Number 1 */
- if (1 == bInterfaceNumber)
- return;
-
- peasycap = usb_get_intfdata(pusb_interface);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return;
- }
-
- /* If the waitqueues are not cleared a deadlock is possible */
- peasycap->video_eof = 1;
- peasycap->audio_eof = 1;
- wake_up_interruptible(&(peasycap->wq_video));
- wake_up_interruptible(&(peasycap->wq_audio));
-
- switch (bInterfaceNumber) {
- case 0:
- easycap_video_kill_urbs(peasycap);
- break;
- case 2:
- easycap_audio_kill_urbs(peasycap);
- break;
- default:
- break;
- }
-
- /*
- * Deregister
- * This procedure will block until easycap_poll(),
- * video and audio ioctl are all unlocked.
- * If this is not done an oops can occur when an easycap
- * is unplugged while the urbs are running.
- */
- kd = easycap_isdongle(peasycap);
- switch (bInterfaceNumber) {
- case 0: {
- if (0 <= kd && DONGLE_MANY > kd) {
- wake_up_interruptible(&peasycap->wq_video);
- JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
- mutex_video)) {
- SAY("ERROR: "
- "cannot lock dongle[%i].mutex_video\n", kd);
- return;
- }
- JOM(4, "locked dongle[%i].mutex_video\n", kd);
- } else {
- SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
- }
- if (!peasycap->v4l2_device.name[0]) {
- SAM("ERROR: peasycap->v4l2_device.name is empty\n");
- if (0 <= kd && DONGLE_MANY > kd)
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- return;
- }
- v4l2_device_disconnect(&peasycap->v4l2_device);
- JOM(4, "v4l2_device_disconnect() OK\n");
- v4l2_device_unregister(&peasycap->v4l2_device);
- JOM(4, "v4l2_device_unregister() OK\n");
-
- video_unregister_device(&peasycap->video_device);
- JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
- bInterfaceNumber, minor);
- peasycap->registered_video--;
-
- if (0 <= kd && DONGLE_MANY > kd) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
- }
- break;
- }
- case 2: {
- if (0 <= kd && DONGLE_MANY > kd) {
- wake_up_interruptible(&peasycap->wq_audio);
- JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
- mutex_audio)) {
- SAY("ERROR: "
- "cannot lock dongle[%i].mutex_audio\n", kd);
- return;
- }
- JOM(4, "locked dongle[%i].mutex_audio\n", kd);
- } else
- SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
- if (0 != snd_card_free(peasycap->psnd_card)) {
- SAY("ERROR: snd_card_free() failed\n");
- } else {
- peasycap->psnd_card = NULL;
- (peasycap->registered_audio)--;
- }
- if (0 <= kd && DONGLE_MANY > kd) {
- mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
- JOM(4, "unlocked dongle[%i].mutex_audio\n", kd);
- }
- break;
- }
- default:
- break;
- }
-
- /*
- * If no remaining references to peasycap,
- * call easycap_delete.
- * (Also when alsa has been in use)
- */
- if (!peasycap->kref.refcount.counter) {
- SAM("ERROR: peasycap->kref.refcount.counter is zero "
- "so cannot call kref_put()\n");
- SAM("ending unsuccessfully: may cause memory leak\n");
- return;
- }
- if (0 <= kd && DONGLE_MANY > kd) {
- JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
- SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd);
- SAM("ending unsuccessfully: may cause memory leak\n");
- return;
- }
- JOM(4, "locked dongle[%i].mutex_video\n", kd);
- JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
- if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
- SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd);
- mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
- JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
- SAM("ending unsuccessfully: may cause memory leak\n");
- return;
- }
- JOM(4, "locked dongle[%i].mutex_audio\n", kd);
- }
- JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n",
- bInterfaceNumber, (int)peasycap->kref.refcount.counter);
- kref_put(&peasycap->kref, easycap_delete);
- JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
- if (0 <= kd && DONGLE_MANY > kd) {
- mutex_unlock(&(easycapdc60_dongle[kd].mutex_audio));
- JOT(4, "unlocked dongle[%i].mutex_audio\n", kd);
- mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
- JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
- }
- JOM(4, "ends\n");
- return;
-}
-
-/* Devices supported by this driver */
-static struct usb_device_id easycap_usb_device_id_table[] = {
- {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
-static struct usb_driver easycap_usb_driver = {
- .name = "easycap",
- .id_table = easycap_usb_device_id_table,
- .probe = easycap_usb_probe,
- .disconnect = easycap_usb_disconnect,
-};
-
-static int __init easycap_module_init(void)
-{
- int k, rc;
-
- printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n");
-
- JOT(4, "begins. %i=debug %i=bars %i=gain\n",
- easycap_debug, easycap_bars, easycap_gain);
-
- mutex_init(&mutex_dongle);
- for (k = 0; k < DONGLE_MANY; k++) {
- easycapdc60_dongle[k].peasycap = NULL;
- mutex_init(&easycapdc60_dongle[k].mutex_video);
- mutex_init(&easycapdc60_dongle[k].mutex_audio);
- }
- rc = usb_register(&easycap_usb_driver);
- if (rc)
- printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc);
-
- return rc;
-}
-
-static void __exit easycap_module_exit(void)
-{
- usb_deregister(&easycap_usb_driver);
-}
-
-module_init(easycap_module_init);
-module_exit(easycap_module_exit);
diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c
deleted file mode 100644
index 3f5f5b3e5a35..000000000000
--- a/drivers/staging/media/easycap/easycap_settings.c
+++ /dev/null
@@ -1,696 +0,0 @@
-/******************************************************************************
-* *
-* easycap_settings.c *
-* *
-******************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*---------------------------------------------------------------------------*/
-/*
- * THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- * 0 => 25 fps
- * 1 => 30 fps
- *
- * THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- * 0 => full framerate
- * 1 => 20% framerate
- */
-/*---------------------------------------------------------------------------*/
-const struct easycap_standard easycap_standard[] = {
- {
- .mask = 0x00FF & PAL_BGHIN ,
- .v4l2_standard = {
- .index = PAL_BGHIN,
- .id = (V4L2_STD_PAL_B |
- V4L2_STD_PAL_G | V4L2_STD_PAL_H |
- V4L2_STD_PAL_I | V4L2_STD_PAL_N),
- .name = "PAL_BGHIN",
- .frameperiod = {1, 25},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & NTSC_N_443 ,
- .v4l2_standard = {
- .index = NTSC_N_443,
- .id = V4L2_STD_UNKNOWN,
- .name = "NTSC_N_443",
- .frameperiod = {1, 25},
- .framelines = 480,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & PAL_Nc ,
- .v4l2_standard = {
- .index = PAL_Nc,
- .id = V4L2_STD_PAL_Nc,
- .name = "PAL_Nc",
- .frameperiod = {1, 25},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & NTSC_N ,
- .v4l2_standard = {
- .index = NTSC_N,
- .id = V4L2_STD_UNKNOWN,
- .name = "NTSC_N",
- .frameperiod = {1, 25},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & SECAM ,
- .v4l2_standard = {
- .index = SECAM,
- .id = V4L2_STD_SECAM,
- .name = "SECAM",
- .frameperiod = {1, 25},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & NTSC_M ,
- .v4l2_standard = {
- .index = NTSC_M,
- .id = V4L2_STD_NTSC_M,
- .name = "NTSC_M",
- .frameperiod = {1, 30},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & NTSC_M_JP ,
- .v4l2_standard = {
- .index = NTSC_M_JP,
- .id = V4L2_STD_NTSC_M_JP,
- .name = "NTSC_M_JP",
- .frameperiod = {1, 30},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & PAL_60 ,
- .v4l2_standard = {
- .index = PAL_60,
- .id = V4L2_STD_PAL_60,
- .name = "PAL_60",
- .frameperiod = {1, 30},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & NTSC_443 ,
- .v4l2_standard = {
- .index = NTSC_443,
- .id = V4L2_STD_NTSC_443,
- .name = "NTSC_443",
- .frameperiod = {1, 30},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x00FF & PAL_M ,
- .v4l2_standard = {
- .index = PAL_M,
- .id = V4L2_STD_PAL_M,
- .name = "PAL_M",
- .frameperiod = {1, 30},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
- .v4l2_standard = {
- .index = PAL_BGHIN_SLOW,
- .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G |
- V4L2_STD_PAL_H |
- V4L2_STD_PAL_I | V4L2_STD_PAL_N |
- (((v4l2_std_id)0x01) << 32)),
- .name = "PAL_BGHIN_SLOW",
- .frameperiod = {1, 5},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
- .v4l2_standard = {
- .index = NTSC_N_443_SLOW,
- .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
- .name = "NTSC_N_443_SLOW",
- .frameperiod = {1, 5},
- .framelines = 480,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
- .v4l2_standard = {
- .index = PAL_Nc_SLOW,
- .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
- .name = "PAL_Nc_SLOW",
- .frameperiod = {1, 5},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
- .v4l2_standard = {
- .index = NTSC_N_SLOW,
- .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
- .name = "NTSC_N_SLOW",
- .frameperiod = {1, 5},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & SECAM_SLOW),
- .v4l2_standard = {
- .index = SECAM_SLOW,
- .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
- .name = "SECAM_SLOW",
- .frameperiod = {1, 5},
- .framelines = 625,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
- .v4l2_standard = {
- .index = NTSC_M_SLOW,
- .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
- .name = "NTSC_M_SLOW",
- .frameperiod = {1, 6},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
- .v4l2_standard = {
- .index = NTSC_M_JP_SLOW,
- .id = (V4L2_STD_NTSC_M_JP |
- (((v4l2_std_id)0x01) << 32)),
- .name = "NTSC_M_JP_SLOW",
- .frameperiod = {1, 6},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & PAL_60_SLOW),
- .v4l2_standard = {
- .index = PAL_60_SLOW,
- .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
- .name = "PAL_60_SLOW",
- .frameperiod = {1, 6},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
- .v4l2_standard = {
- .index = NTSC_443_SLOW,
- .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
- .name = "NTSC_443_SLOW",
- .frameperiod = {1, 6},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0x8000 | (0x00FF & PAL_M_SLOW),
- .v4l2_standard = {
- .index = PAL_M_SLOW,
- .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
- .name = "PAL_M_SLOW",
- .frameperiod = {1, 6},
- .framelines = 525,
- .reserved = {0, 0, 0, 0}
- }
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .mask = 0xFFFF
- }
-};
-/*---------------------------------------------------------------------------*/
-/*
- * THE 16-BIT easycap_format.mask HAS MEANING:
- * (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
- * BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS
- * BITS 5-7: NUMBER OF BYTES PER PIXEL
- * BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED
- * BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS
- * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
- * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
- * BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED
- * (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
- * IT FOLLOWS THAT:
- * bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5)
- * byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
- *
- * decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
- *
- * offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
- */
-/*---------------------------------------------------------------------------*/
-
-struct easycap_format easycap_format[1 + SETTINGS_MANY];
-
-int easycap_video_fillin_formats(void)
-{
- const char *name1, *name2, *name3, *name4;
- struct v4l2_format *fmt;
- int i, j, k, m, n;
- u32 width, height, pixelformat, bytesperline, sizeimage;
- u16 mask1, mask2, mask3, mask4;
- enum v4l2_field field;
- enum v4l2_colorspace colorspace;
-
- for (i = 0, n = 0; i < STANDARD_MANY; i++) {
- mask1 = 0x0000;
- switch (i) {
- case PAL_BGHIN: {
- mask1 = 0x1F & PAL_BGHIN;
- name1 = "PAL_BGHIN";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case SECAM: {
- mask1 = 0x1F & SECAM;
- name1 = "SECAM";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_Nc: {
- mask1 = 0x1F & PAL_Nc;
- name1 = "PAL_Nc";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_60: {
- mask1 = 0x1F & PAL_60;
- name1 = "PAL_60";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_M: {
- mask1 = 0x1F & PAL_M;
- name1 = "PAL_M";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case NTSC_M: {
- mask1 = 0x1F & NTSC_M;
- name1 = "NTSC_M";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_443: {
- mask1 = 0x1F & NTSC_443;
- name1 = "NTSC_443";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_M_JP: {
- mask1 = 0x1F & NTSC_M_JP;
- name1 = "NTSC_M_JP";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_N: {
- mask1 = 0x1F & NTSC_M;
- name1 = "NTSC_N";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_N_443: {
- mask1 = 0x1F & NTSC_N_443;
- name1 = "NTSC_N_443";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case PAL_BGHIN_SLOW: {
- mask1 = 0x001F & PAL_BGHIN_SLOW;
- mask1 |= 0x0200;
- name1 = "PAL_BGHIN_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case SECAM_SLOW: {
- mask1 = 0x001F & SECAM_SLOW;
- mask1 |= 0x0200;
- name1 = "SECAM_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_Nc_SLOW: {
- mask1 = 0x001F & PAL_Nc_SLOW;
- mask1 |= 0x0200;
- name1 = "PAL_Nc_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_60_SLOW: {
- mask1 = 0x001F & PAL_60_SLOW;
- mask1 |= 0x0200;
- name1 = "PAL_60_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case PAL_M_SLOW: {
- mask1 = 0x001F & PAL_M_SLOW;
- mask1 |= 0x0200;
- name1 = "PAL_M_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
- break;
- }
- case NTSC_M_SLOW: {
- mask1 = 0x001F & NTSC_M_SLOW;
- mask1 |= 0x0200;
- name1 = "NTSC_M_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_443_SLOW: {
- mask1 = 0x001F & NTSC_443_SLOW;
- mask1 |= 0x0200;
- name1 = "NTSC_443_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_M_JP_SLOW: {
- mask1 = 0x001F & NTSC_M_JP_SLOW;
- mask1 |= 0x0200;
- name1 = "NTSC_M_JP_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_N_SLOW: {
- mask1 = 0x001F & NTSC_N_SLOW;
- mask1 |= 0x0200;
- name1 = "NTSC_N_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- case NTSC_N_443_SLOW: {
- mask1 = 0x001F & NTSC_N_443_SLOW;
- mask1 |= 0x0200;
- name1 = "NTSC_N_443_SLOW";
- colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
- break;
- }
- default:
- return -1;
- }
-
- for (j = 0; j < RESOLUTION_MANY; j++) {
- mask2 = 0x0000;
- switch (j) {
- case AT_720x576: {
- if (0x1 & mask1)
- continue;
- name2 = "_AT_720x576";
- width = 720;
- height = 576;
- break;
- }
- case AT_704x576: {
- if (0x1 & mask1)
- continue;
- name2 = "_AT_704x576";
- width = 704;
- height = 576;
- break;
- }
- case AT_640x480: {
- name2 = "_AT_640x480";
- width = 640;
- height = 480;
- break;
- }
- case AT_720x480: {
- if (!(0x1 & mask1))
- continue;
- name2 = "_AT_720x480";
- width = 720;
- height = 480;
- break;
- }
- case AT_360x288: {
- if (0x1 & mask1)
- continue;
- name2 = "_AT_360x288";
- width = 360;
- height = 288;
- mask2 = 0x0800;
- break;
- }
- case AT_320x240: {
- name2 = "_AT_320x240";
- width = 320;
- height = 240;
- mask2 = 0x0800;
- break;
- }
- case AT_360x240: {
- if (!(0x1 & mask1))
- continue;
- name2 = "_AT_360x240";
- width = 360;
- height = 240;
- mask2 = 0x0800;
- break;
- }
- default:
- return -2;
- }
-
- for (k = 0; k < PIXELFORMAT_MANY; k++) {
- mask3 = 0x0000;
- switch (k) {
- case FMT_UYVY: {
- name3 = __stringify(FMT_UYVY);
- pixelformat = V4L2_PIX_FMT_UYVY;
- mask3 |= (0x02 << 5);
- break;
- }
- case FMT_YUY2: {
- name3 = __stringify(FMT_YUY2);
- pixelformat = V4L2_PIX_FMT_YUYV;
- mask3 |= (0x02 << 5);
- mask3 |= 0x0100;
- break;
- }
- case FMT_RGB24: {
- name3 = __stringify(FMT_RGB24);
- pixelformat = V4L2_PIX_FMT_RGB24;
- mask3 |= (0x03 << 5);
- break;
- }
- case FMT_RGB32: {
- name3 = __stringify(FMT_RGB32);
- pixelformat = V4L2_PIX_FMT_RGB32;
- mask3 |= (0x04 << 5);
- break;
- }
- case FMT_BGR24: {
- name3 = __stringify(FMT_BGR24);
- pixelformat = V4L2_PIX_FMT_BGR24;
- mask3 |= (0x03 << 5);
- mask3 |= 0x0100;
- break;
- }
- case FMT_BGR32: {
- name3 = __stringify(FMT_BGR32);
- pixelformat = V4L2_PIX_FMT_BGR32;
- mask3 |= (0x04 << 5);
- mask3 |= 0x0100;
- break;
- }
- default:
- return -3;
- }
- bytesperline = width * ((mask3 & 0x00E0) >> 5);
- sizeimage = bytesperline * height;
-
- for (m = 0; m < INTERLACE_MANY; m++) {
- mask4 = 0x0000;
- switch (m) {
- case FIELD_NONE: {
- name4 = "-n";
- field = V4L2_FIELD_NONE;
- break;
- }
- case FIELD_INTERLACED: {
- name4 = "-i";
- mask4 |= 0x1000;
- field = V4L2_FIELD_INTERLACED;
- break;
- }
- default:
- return -4;
- }
- if (SETTINGS_MANY <= n)
- return -5;
-
- strcpy(easycap_format[n].name, name1);
- strcat(easycap_format[n].name, name2);
- strcat(easycap_format[n].name, "_");
- strcat(easycap_format[n].name, name3);
- strcat(easycap_format[n].name, name4);
- easycap_format[n].mask =
- mask1 | mask2 | mask3 | mask4;
- fmt = &easycap_format[n].v4l2_format;
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt->fmt.pix.width = width;
- fmt->fmt.pix.height = height;
- fmt->fmt.pix.pixelformat = pixelformat;
- fmt->fmt.pix.field = field;
- fmt->fmt.pix.bytesperline = bytesperline;
- fmt->fmt.pix.sizeimage = sizeimage;
- fmt->fmt.pix.colorspace = colorspace;
- fmt->fmt.pix.priv = 0;
- n++;
- }
- }
- }
- }
- if ((1 + SETTINGS_MANY) <= n)
- return -6;
- easycap_format[n].mask = 0xFFFF;
- return n;
-}
-/*---------------------------------------------------------------------------*/
-struct v4l2_queryctrl easycap_control[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = SAA_0A_DEFAULT,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = SAA_0B_DEFAULT + 128,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = SAA_0C_DEFAULT + 128,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = SAA_0D_DEFAULT + 128,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 31,
- .step = 1,
- .default_value = 16,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .default_value = true,
- .flags = 0,
- .reserved = {0, 0}
- },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- {
- .id = 0xFFFFFFFF
- }
-};
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c
deleted file mode 100644
index 8c8bcae8ded8..000000000000
--- a/drivers/staging/media/easycap/easycap_sound.c
+++ /dev/null
@@ -1,750 +0,0 @@
-/******************************************************************************
-* *
-* easycap_sound.c *
-* *
-* Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *
-* *
-* *
-******************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*--------------------------------------------------------------------------*/
-/*
- * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
- */
-/*--------------------------------------------------------------------------*/
-static const struct snd_pcm_hardware alsa_hardware = {
- .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
- .rate_min = 32000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = PAGE_SIZE *
- PAGES_PER_AUDIO_FRAGMENT *
- AUDIO_FRAGMENT_MANY,
- .period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT,
- .period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2,
- .periods_min = AUDIO_FRAGMENT_MANY,
- .periods_max = AUDIO_FRAGMENT_MANY * 2,
-};
-
-
-/*---------------------------------------------------------------------------*/
-/*
- * SUBMIT ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-static int easycap_audio_submit_urbs(struct easycap *peasycap)
-{
- struct data_urb *pdata_urb;
- struct urb *purb;
- struct list_head *plist_head;
- int j, isbad, nospc, m, rc;
- int isbuf;
-
- if (!peasycap->purb_audio_head) {
- SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
- }
-
- if (peasycap->audio_isoc_streaming) {
- JOM(4, "already streaming audio urbs\n");
- return 0;
- }
-
- JOM(4, "initial submission of all audio urbs\n");
- rc = usb_set_interface(peasycap->pusb_device,
- peasycap->audio_interface,
- peasycap->audio_altsetting_on);
- JOM(8, "usb_set_interface(.,%i,%i) returned %i\n",
- peasycap->audio_interface,
- peasycap->audio_altsetting_on, rc);
-
- isbad = 0;
- nospc = 0;
- m = 0;
- list_for_each(plist_head, peasycap->purb_audio_head) {
- pdata_urb = list_entry(plist_head, struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- purb = pdata_urb->purb;
- isbuf = pdata_urb->isbuf;
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->audio_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
- purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
- purb->complete = easycap_alsa_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
- for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
- purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
- }
-
- rc = usb_submit_urb(purb, GFP_KERNEL);
- if (rc) {
- isbad++;
- SAM("ERROR: usb_submit_urb() failed"
- " for urb with rc: -%s: %d\n",
- strerror(rc), rc);
- } else {
- m++;
- }
- } else {
- isbad++;
- }
- }
- if (nospc) {
- SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
- SAM("..... possibly inadequate USB bandwidth\n");
- peasycap->audio_eof = 1;
- }
-
- if (isbad)
- easycap_audio_kill_urbs(peasycap);
- else
- peasycap->audio_isoc_streaming = m;
-
- return 0;
-}
-/*---------------------------------------------------------------------------*/
-/*
- * COMMON AUDIO INITIALIZATION
- */
-/*---------------------------------------------------------------------------*/
-static int easycap_sound_setup(struct easycap *peasycap)
-{
- int rc;
-
- JOM(4, "starting initialization\n");
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL.\n");
- return -EFAULT;
- }
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device is NULL\n");
- return -ENODEV;
- }
- JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
-
- rc = easycap_audio_setup(peasycap);
- JOM(8, "audio_setup() returned %i\n", rc);
-
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device has become NULL\n");
- return -ENODEV;
- }
-/*---------------------------------------------------------------------------*/
- if (!peasycap->pusb_device) {
- SAM("ERROR: peasycap->pusb_device has become NULL\n");
- return -ENODEV;
- }
- rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface,
- peasycap->audio_altsetting_on);
- JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface,
- peasycap->audio_altsetting_on, rc);
-
- rc = easycap_wakeup_device(peasycap->pusb_device);
- JOM(8, "wakeup_device() returned %i\n", rc);
-
- peasycap->audio_eof = 0;
- peasycap->audio_idle = 0;
-
- easycap_audio_submit_urbs(peasycap);
-
- JOM(4, "finished initialization\n");
- return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER
- * PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
- * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
- */
-/*---------------------------------------------------------------------------*/
-void easycap_alsa_complete(struct urb *purb)
-{
- struct easycap *peasycap;
- struct snd_pcm_substream *pss;
- struct snd_pcm_runtime *prt;
- int dma_bytes, fragment_bytes;
- int isfragment;
- u8 *p1, *p2;
- s16 tmp;
- int i, j, more, much, rc;
-#ifdef UPSAMPLE
- int k;
- s16 oldaudio, newaudio, delta;
-#endif /*UPSAMPLE*/
-
- JOT(16, "\n");
-
- if (!purb) {
- SAY("ERROR: purb is NULL\n");
- return;
- }
- peasycap = purb->context;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return;
- }
- much = 0;
- if (peasycap->audio_idle) {
- JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n",
- peasycap->audio_idle, peasycap->audio_isoc_streaming);
- if (peasycap->audio_isoc_streaming)
- goto resubmit;
- }
-/*---------------------------------------------------------------------------*/
- pss = peasycap->psubstream;
- if (!pss)
- goto resubmit;
- prt = pss->runtime;
- if (!prt)
- goto resubmit;
- dma_bytes = (int)prt->dma_bytes;
- if (0 == dma_bytes)
- goto resubmit;
- fragment_bytes = 4 * ((int)prt->period_size);
- if (0 == fragment_bytes)
- goto resubmit;
-/* -------------------------------------------------------------------------*/
- if (purb->status) {
- if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
- JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
- return;
- }
- SAM("ERROR: non-zero urb status: -%s: %d\n",
- strerror(purb->status), purb->status);
- goto resubmit;
- }
-/*---------------------------------------------------------------------------*/
-/*
- * PROCEED HERE WHEN NO ERROR
- */
-/*---------------------------------------------------------------------------*/
-
-#ifdef UPSAMPLE
- oldaudio = peasycap->oldaudio;
-#endif /*UPSAMPLE*/
-
- for (i = 0; i < purb->number_of_packets; i++) {
- if (purb->iso_frame_desc[i].status < 0) {
- SAM("-%s: %d\n",
- strerror(purb->iso_frame_desc[i].status),
- purb->iso_frame_desc[i].status);
- }
- if (purb->iso_frame_desc[i].status) {
- JOM(12, "discarding audio samples because "
- "%i=purb->iso_frame_desc[i].status\n",
- purb->iso_frame_desc[i].status);
- continue;
- }
- more = purb->iso_frame_desc[i].actual_length;
- if (more == 0) {
- peasycap->audio_mt++;
- continue;
- }
- if (0 > more) {
- SAM("MISTAKE: more is negative\n");
- return;
- }
-
- if (peasycap->audio_mt) {
- JOM(12, "%4i empty audio urb frames\n",
- peasycap->audio_mt);
- peasycap->audio_mt = 0;
- }
-
- p1 = (u8 *)(purb->transfer_buffer +
- purb->iso_frame_desc[i].offset);
-
- /*
- * COPY more BYTES FROM ISOC BUFFER
- * TO THE DMA BUFFER, CONVERTING
- * 8-BIT MONO TO 16-BIT SIGNED
- * LITTLE-ENDIAN SAMPLES IF NECESSARY
- */
- while (more) {
- much = dma_bytes - peasycap->dma_fill;
- if (0 > much) {
- SAM("MISTAKE: much is negative\n");
- return;
- }
- if (0 == much) {
- peasycap->dma_fill = 0;
- peasycap->dma_next = fragment_bytes;
- JOM(8, "wrapped dma buffer\n");
- }
- if (!peasycap->microphone) {
- if (much > more)
- much = more;
- memcpy(prt->dma_area + peasycap->dma_fill,
- p1, much);
- p1 += much;
- more -= much;
- } else {
-#ifdef UPSAMPLE
- if (much % 16)
- JOM(8, "MISTAKE? much"
- " is not divisible by 16\n");
- if (much > (16 * more))
- much = 16 * more;
- p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
-
- for (j = 0; j < (much / 16); j++) {
- newaudio = ((int) *p1) - 128;
- newaudio = 128 * newaudio;
-
- delta = (newaudio - oldaudio) / 4;
- tmp = oldaudio + delta;
-
- for (k = 0; k < 4; k++) {
- *p2 = (0x00FF & tmp);
- *(p2 + 1) = (0xFF00 & tmp) >> 8;
- p2 += 2;
- *p2 = (0x00FF & tmp);
- *(p2 + 1) = (0xFF00 & tmp) >> 8;
- p2 += 2;
- tmp += delta;
- }
- p1++;
- more--;
- oldaudio = tmp;
- }
-#else /*!UPSAMPLE*/
- if (much > (2 * more))
- much = 2 * more;
- p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
-
- for (j = 0; j < (much / 2); j++) {
- tmp = ((int) *p1) - 128;
- tmp = 128 * tmp;
- *p2 = (0x00FF & tmp);
- *(p2 + 1) = (0xFF00 & tmp) >> 8;
- p1++;
- p2 += 2;
- more--;
- }
-#endif /*UPSAMPLE*/
- }
- peasycap->dma_fill += much;
- if (peasycap->dma_fill >= peasycap->dma_next) {
- isfragment = peasycap->dma_fill / fragment_bytes;
- if (0 > isfragment) {
- SAM("MISTAKE: isfragment is negative\n");
- return;
- }
- peasycap->dma_read = (isfragment - 1) * fragment_bytes;
- peasycap->dma_next = (isfragment + 1) * fragment_bytes;
- if (dma_bytes < peasycap->dma_next)
- peasycap->dma_next = fragment_bytes;
-
- if (0 <= peasycap->dma_read) {
- JOM(8, "snd_pcm_period_elapsed(), %i="
- "isfragment\n", isfragment);
- snd_pcm_period_elapsed(pss);
- }
- }
- }
-
-#ifdef UPSAMPLE
- peasycap->oldaudio = oldaudio;
-#endif /*UPSAMPLE*/
-
- }
-/*---------------------------------------------------------------------------*/
-/*
- * RESUBMIT THIS URB
- */
-/*---------------------------------------------------------------------------*/
-resubmit:
- if (peasycap->audio_isoc_streaming == 0)
- return;
-
- rc = usb_submit_urb(purb, GFP_ATOMIC);
- if (rc) {
- if ((-ENODEV != rc) && (-ENOENT != rc)) {
- SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
- "with rc: -%s :%d\n",
- peasycap->audio_idle, strerror(rc), rc);
- }
- if (0 < peasycap->audio_isoc_streaming)
- peasycap->audio_isoc_streaming--;
- }
- return;
-}
-/*****************************************************************************/
-static int easycap_alsa_open(struct snd_pcm_substream *pss)
-{
- struct snd_pcm *psnd_pcm;
- struct snd_card *psnd_card;
- struct easycap *peasycap;
-
- JOT(4, "\n");
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- psnd_pcm = pss->pcm;
- if (!psnd_pcm) {
- SAY("ERROR: psnd_pcm is NULL\n");
- return -EFAULT;
- }
- psnd_card = psnd_pcm->card;
- if (!psnd_card) {
- SAY("ERROR: psnd_card is NULL\n");
- return -EFAULT;
- }
-
- peasycap = psnd_card->private_data;
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if (peasycap->psnd_card != psnd_card) {
- SAM("ERROR: bad peasycap->psnd_card\n");
- return -EFAULT;
- }
- if (peasycap->psubstream) {
- SAM("ERROR: bad peasycap->psubstream\n");
- return -EFAULT;
- }
- pss->private_data = peasycap;
- peasycap->psubstream = pss;
- pss->runtime->hw = peasycap->alsa_hardware;
- pss->runtime->private_data = peasycap;
- pss->private_data = peasycap;
-
- if (0 != easycap_sound_setup(peasycap)) {
- JOM(4, "ending unsuccessfully\n");
- return -EFAULT;
- }
- JOM(4, "ending successfully\n");
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_close(struct snd_pcm_substream *pss)
-{
- struct easycap *peasycap;
-
- JOT(4, "\n");
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- peasycap = snd_pcm_substream_chip(pss);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- pss->private_data = NULL;
- peasycap->psubstream = NULL;
- JOT(4, "ending successfully\n");
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
-{
- struct snd_pcm_runtime *prt;
- JOT(4, "\n");
-
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- prt = pss->runtime;
- if (!prt) {
- SAY("ERROR: substream.runtime is NULL\n");
- return -EFAULT;
- }
- if (prt->dma_area) {
- if (prt->dma_bytes > sz)
- return 0;
- vfree(prt->dma_area);
- }
- prt->dma_area = vmalloc(sz);
- if (!prt->dma_area)
- return -ENOMEM;
- prt->dma_bytes = sz;
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_hw_params(struct snd_pcm_substream *pss,
- struct snd_pcm_hw_params *phw)
-{
- int rc;
-
- JOT(4, "%i\n", (params_buffer_bytes(phw)));
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
- if (rc)
- return rc;
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
-{
- struct snd_pcm_runtime *prt;
- JOT(4, "\n");
-
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- prt = pss->runtime;
- if (!prt) {
- SAY("ERROR: substream.runtime is NULL\n");
- return -EFAULT;
- }
- if (prt->dma_area) {
- JOT(8, "prt->dma_area = %p\n", prt->dma_area);
- vfree(prt->dma_area);
- prt->dma_area = NULL;
- } else
- JOT(8, "dma_area already freed\n");
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
-{
- struct easycap *peasycap;
- struct snd_pcm_runtime *prt;
-
- JOT(4, "\n");
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- prt = pss->runtime;
- peasycap = snd_pcm_substream_chip(pss);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
-
- JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
- JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
- JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
- JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
- JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
- JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
- JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
- JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
- JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
- JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
- JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
- JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
- pss->runtime->hw_ptr_interrupt);
-
- if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) {
- SAY("MISTAKE: unexpected ALSA parameters\n");
- return -ENOENT;
- }
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_ack(struct snd_pcm_substream *pss)
-{
- return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
-{
- struct easycap *peasycap;
-
- JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
- SNDRV_PCM_TRIGGER_STOP);
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- peasycap = snd_pcm_substream_chip(pss);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START: {
- peasycap->audio_idle = 0;
- break;
- }
- case SNDRV_PCM_TRIGGER_STOP: {
- peasycap->audio_idle = 1;
- break;
- }
- default:
- return -EINVAL;
- }
- return 0;
-}
-/*****************************************************************************/
-static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
-{
- struct easycap *peasycap;
- snd_pcm_uframes_t offset;
-
- JOT(16, "\n");
- if (!pss) {
- SAY("ERROR: pss is NULL\n");
- return -EFAULT;
- }
- peasycap = snd_pcm_substream_chip(pss);
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -EFAULT;
- }
- if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) {
- JOM(8, "returning -EIO because "
- "%i=audio_idle %i=audio_eof\n",
- peasycap->audio_idle, peasycap->audio_eof);
- return -EIO;
- }
-/*---------------------------------------------------------------------------*/
- if (0 > peasycap->dma_read) {
- JOM(8, "returning -EBUSY\n");
- return -EBUSY;
- }
- offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4;
- JOM(8, "ALSA decides %8i =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
- JOM(8, "ALSA decides %8i =hw_ptr_interrupt\n",
- (int)pss->runtime->hw_ptr_interrupt);
- JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n",
- (int)offset, peasycap->dma_read, peasycap->dma_next);
- return offset;
-}
-/*****************************************************************************/
-static struct page *
-easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
-{
- return vmalloc_to_page(pss->runtime->dma_area + offset);
-}
-/*****************************************************************************/
-
-static struct snd_pcm_ops easycap_alsa_pcm_ops = {
- .open = easycap_alsa_open,
- .close = easycap_alsa_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = easycap_alsa_hw_params,
- .hw_free = easycap_alsa_hw_free,
- .prepare = easycap_alsa_prepare,
- .ack = easycap_alsa_ack,
- .trigger = easycap_alsa_trigger,
- .pointer = easycap_alsa_pointer,
- .page = easycap_alsa_page,
-};
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * THE FUNCTION snd_card_create() HAS THIS_MODULE AS AN ARGUMENT. THIS
- * MEANS MODULE easycap. BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_alsa_probe(struct easycap *peasycap)
-{
- int rc;
- struct snd_card *psnd_card;
- struct snd_pcm *psnd_pcm;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return -ENODEV;
- }
- if (0 > peasycap->minor) {
- SAY("ERROR: no minor\n");
- return -ENODEV;
- }
-
- peasycap->alsa_hardware = alsa_hardware;
- if (peasycap->microphone) {
- peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000;
- peasycap->alsa_hardware.rate_min = 32000;
- peasycap->alsa_hardware.rate_max = 32000;
- } else {
- peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000;
- peasycap->alsa_hardware.rate_min = 48000;
- peasycap->alsa_hardware.rate_max = 48000;
- }
-
- if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa",
- THIS_MODULE, 0, &psnd_card)) {
- SAY("ERROR: Cannot do ALSA snd_card_create()\n");
- return -EFAULT;
- }
-
- sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor);
- strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION);
- strcpy(&psnd_card->shortname[0], "easycap_alsa");
- sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]);
-
- psnd_card->dev = &peasycap->pusb_device->dev;
- psnd_card->private_data = peasycap;
- peasycap->psnd_card = psnd_card;
-
- rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm);
- if (rc) {
- SAM("ERROR: Cannot do ALSA snd_pcm_new()\n");
- snd_card_free(psnd_card);
- return -EFAULT;
- }
-
- snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE,
- &easycap_alsa_pcm_ops);
- psnd_pcm->info_flags = 0;
- strcpy(&psnd_pcm->name[0], &psnd_card->id[0]);
- psnd_pcm->private_data = peasycap;
- peasycap->psnd_pcm = psnd_pcm;
- peasycap->psubstream = NULL;
-
- rc = snd_card_register(psnd_card);
- if (rc) {
- SAM("ERROR: Cannot do ALSA snd_card_register()\n");
- snd_card_free(psnd_card);
- return -EFAULT;
- }
-
- SAM("registered %s\n", &psnd_card->id[0]);
- return 0;
-}
-
diff --git a/drivers/staging/media/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c
deleted file mode 100644
index 0f71470ace39..000000000000
--- a/drivers/staging/media/easycap/easycap_testcard.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/******************************************************************************
-* *
-* easycap_testcard.c *
-* *
-******************************************************************************/
-/*
- *
- * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- * This 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.
- *
- * The software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*****************************************************************************/
-#define TESTCARD_BYTESPERLINE (2 * 720)
-void
-easycap_testcard(struct easycap *peasycap, int field)
-{
- int total;
- int y, u, v, r, g, b;
- unsigned char uyvy[4];
- int i1, line, k, m, n, more, much, barwidth, barheight;
- unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
- struct data_buffer *pfield_buffer;
-
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- return;
- }
- JOM(8, "%i=field\n", field);
- switch (peasycap->width) {
- case 720:
- case 360: {
- barwidth = (2 * 720) / 8;
- break;
- }
- case 704:
- case 352: {
- barwidth = (2 * 704) / 8;
- break;
- }
- case 640:
- case 320: {
- barwidth = (2 * 640) / 8;
- break;
- }
- default: {
- SAM("ERROR: cannot set barwidth\n");
- return;
- }
- }
- if (TESTCARD_BYTESPERLINE < barwidth) {
- SAM("ERROR: barwidth is too large\n");
- return;
- }
- switch (peasycap->height) {
- case 576:
- case 288: {
- barheight = 576;
- break;
- }
- case 480:
- case 240: {
- barheight = 480;
- break;
- }
- default: {
- SAM("ERROR: cannot set barheight\n");
- return;
- }
- }
- total = 0;
- k = field;
- m = 0;
- n = 0;
-
- for (line = 0; line < (barheight / 2); line++) {
- for (i1 = 0; i1 < 8; i1++) {
- r = (i1 * 256)/8;
- g = (i1 * 256)/8;
- b = (i1 * 256)/8;
-
- y = 299*r/1000 + 587*g/1000 + 114*b/1000 ;
- u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;
- u = u + 128;
- v = 615*r/1000 - 515*g/1000 - 100*b/1000 ;
- v = v + 128;
-
- uyvy[0] = 0xFF & u ;
- uyvy[1] = 0xFF & y ;
- uyvy[2] = 0xFF & v ;
- uyvy[3] = 0xFF & y ;
-
- p1 = &bfbar[0];
- while (p1 < &bfbar[barwidth]) {
- *p1++ = uyvy[0] ;
- *p1++ = uyvy[1] ;
- *p1++ = uyvy[2] ;
- *p1++ = uyvy[3] ;
- total += 4;
- }
-
- p1 = &bfbar[0];
- more = barwidth;
-
- while (more) {
- if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
- SAM("ERROR: bad m reached\n");
- return;
- }
- if (PAGE_SIZE < n) {
- SAM("ERROR: bad n reached\n");
- return;
- }
-
- if (0 > more) {
- SAM("ERROR: internal fault\n");
- return;
- }
-
- much = PAGE_SIZE - n;
- if (much > more)
- much = more;
- pfield_buffer = &peasycap->field_buffer[k][m];
- p2 = pfield_buffer->pgo + n;
- memcpy(p2, p1, much);
-
- p1 += much;
- n += much;
- more -= much;
- if (PAGE_SIZE == n) {
- m++;
- n = 0;
- }
- }
- }
- }
- return;
-}
diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile
index 6ee837c56706..3fdbef5306a0 100644
--- a/drivers/staging/media/go7007/Makefile
+++ b/drivers/staging/media/go7007/Makefile
@@ -24,7 +24,7 @@ s2250-y := s2250-board.o
#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3
# S2250 needs cypress ezusb loader from dvb-usb
-ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/dvb/dvb-usb
+ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
index 526ec0fc2f04..e60a59fc252b 100644
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -63,12 +63,6 @@ config LIRC_SIR
help
Driver for the SIR IrDA port
-config LIRC_TTUSBIR
- tristate "Technotrend USB IR Receiver"
- depends on LIRC && USB
- help
- Driver for the Technotrend USB IR Receiver
-
config LIRC_ZILOG
tristate "Zilog/Hauppauge IR Transmitter"
depends on LIRC && I2C
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
index d76b0fa2af53..b90fcabddab6 100644
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -10,5 +10,4 @@ obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
-obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o
obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o
diff --git a/drivers/staging/media/lirc/lirc_ene0100.h b/drivers/staging/media/lirc/lirc_ene0100.h
deleted file mode 100644
index 06bebd6acc46..000000000000
--- a/drivers/staging/media/lirc/lirc_ene0100.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
- *
- * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-/* hardware address */
-#define ENE_STATUS 0 /* hardware status - unused */
-#define ENE_ADDR_HI 1 /* hi byte of register address */
-#define ENE_ADDR_LO 2 /* low byte of register address */
-#define ENE_IO 3 /* read/write window */
-#define ENE_MAX_IO 4
-
-/* 8 bytes of samples, divided in 2 halfs*/
-#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */
-#define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */
-#define ENE_SAMPLE_VALUE_MASK 0x7F
-#define ENE_SAMPLE_OVERFLOW 0x7F
-#define ENE_SAMPLES_SIZE 4
-
-/* fan input sample buffer */
-#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */
- /* each sample of normal buffer */
-
-#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */
- /* if set, says that sample is pulse */
-#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */
-
-/* first firmware register */
-#define ENE_FW1 0xF8F8
-#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */
-#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */
-#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */
-#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */
-
-/* second firmware register */
-#define ENE_FW2 0xF8F9
-#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */
-#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */
-#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */
- /* learning input */
-#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
-#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */
-
-/* fan as input settings - only if learning capable */
-#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
-#define ENE_FAN_AS_IN1_EN 0xCD
-#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
-#define ENE_FAN_AS_IN2_EN 0x03
-#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
-
-/* IRQ registers block (for revision B) */
-#define ENEB_IRQ 0xFD09 /* IRQ number */
-#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */
-#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
-#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */
-
-/* IRQ registers block (for revision C,D) */
-#define ENEC_IRQ 0xFE9B /* new irq settings register */
-#define ENEC_IRQ_MASK 0x0F /* irq number mask */
-#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */
-#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */
-
-/* CIR block settings */
-#define ENE_CIR_CONF1 0xFEC0
-#define ENE_CIR_CONF1_ADC_ON 0x7 /* receiver on gpio40 enabled */
-#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */
-#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */
-#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */
-
-#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */
-#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */
-#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */
-
-#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */
-#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */
-
-
-/* transmitter - not implemented yet */
-/* KB3926C and higher */
-/* transmission is very similar to receiving, a byte is written to */
-/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
-/* sample period is fixed*/
-
-
-/* transmitter ports */
-#define ENE_TX_PORT1 0xFC01 /* this enables one or both */
-#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */
-#define ENE_TX_PORT2 0xFC08
-#define ENE_TX_PORT2_EN (1 << 1)
-
-#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */
-#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */
-#define ENE_TX_UNK1 0xFECB /* set to 0x63 */
-#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */
-
-
-#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */
-#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */
-#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */
-
-/* Hardware versions */
-#define ENE_HW_VERSION 0xFF00 /* hardware revision */
-#define ENE_HW_UNK 0xFF1D
-#define ENE_HW_UNK_CLR (1 << 2)
-#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */
-#define ENE_HW_VER_MINOR 0xFF1F
-#define ENE_HW_VER_OLD 0xFD00
-
-#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
-
-#define ENE_DRIVER_NAME "enecir"
-#define ENE_MAXGAP 250000 /* this is amount of time we wait
- before turning the sampler, chosen
- arbitry */
-
-#define space(len) (-(len)) /* add a space */
-
-/* software defines */
-#define ENE_IRQ_RX 1
-#define ENE_IRQ_TX 2
-
-#define ENE_HW_B 1 /* 3926B */
-#define ENE_HW_C 2 /* 3926C */
-#define ENE_HW_D 3 /* 3926D */
-
-#define ene_printk(level, text, ...) \
- printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
-
-struct ene_device {
- struct pnp_dev *pnp_dev;
- struct lirc_driver *lirc_driver;
-
- /* hw settings */
- unsigned long hw_io;
- int irq;
-
- int hw_revision; /* hardware revision */
- int hw_learning_and_tx_capable; /* learning capable */
- int hw_gpio40_learning; /* gpio40 is learning */
- int hw_fan_as_normal_input; /* fan input is used as regular input */
-
- /* device data */
- int idle;
- int fan_input_inuse;
-
- int sample;
- int in_use;
-
- struct timeval gap_start;
-};
diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c
index 7a2501776679..939a801c23e4 100644
--- a/drivers/staging/media/lirc/lirc_igorplugusb.c
+++ b/drivers/staging/media/lirc/lirc_igorplugusb.c
@@ -325,8 +325,8 @@ static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
if (ret < DEVICE_HEADERLEN)
return -ENODATA;
- dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
- ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
+ dprintk(DRIVER_NAME ": Got %d bytes. Header: %*ph\n",
+ ret, 3, ir->buf_in);
do_gettimeofday(&now);
timediff = now.tv_sec - ir->last_time.tv_sec;
diff --git a/drivers/staging/media/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c
deleted file mode 100644
index 3bb865c02173..000000000000
--- a/drivers/staging/media/lirc/lirc_ttusbir.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * lirc_ttusbir.c
- *
- * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
- *
- * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
- *
- * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
- * The receiver delivers the IR signal as raw sampled true/false data in
- * isochronous USB packets each of size 128 byte.
- * Currently the driver reduces the sampling rate by factor of 8 as this
- * is still more than enough to decode RC-5 - others should be analyzed.
- * But the driver does not rely on RC-5 it should be able to decode every
- * IR signal that is not too fast.
- */
-
-/*
- * 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
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
-MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
-MODULE_LICENSE("GPL");
-
-/* #define DEBUG */
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-#define DPRINTK(_x_, a...)
-#endif
-
-/* function declarations */
-static int probe(struct usb_interface *intf, const struct usb_device_id *id);
-static void disconnect(struct usb_interface *intf);
-static void urb_complete(struct urb *urb);
-static int set_use_inc(void *data);
-static void set_use_dec(void *data);
-
-static int num_urbs = 2;
-module_param(num_urbs, int, S_IRUGO);
-MODULE_PARM_DESC(num_urbs,
- "Number of URBs in queue. Try to increase to 4 in case "
- "of problems (default: 2; minimum: 2)");
-
-/* table of devices that work with this driver */
-static struct usb_device_id device_id_table[] = {
- /* TechnoTrend USB IR Receiver */
- { USB_DEVICE(0x0B48, 0x2003) },
- /* Terminating entry */
- { }
-};
-MODULE_DEVICE_TABLE(usb, device_id_table);
-
-/* USB driver definition */
-static struct usb_driver usb_driver = {
- .name = "TTUSBIR",
- .id_table = &(device_id_table[0]),
- .probe = probe,
- .disconnect = disconnect,
-};
-
-/* USB device definition */
-struct ttusbir_device {
- struct usb_driver *usb_driver;
- struct usb_device *udev;
- struct usb_interface *interf;
- struct usb_class_driver class_driver;
- unsigned int ifnum; /* Interface number to use */
- unsigned int alt_setting; /* alternate setting to use */
- unsigned int endpoint; /* Endpoint to use */
- struct urb **urb; /* num_urb URB pointers*/
- char **buffer; /* 128 byte buffer for each URB */
- struct lirc_buffer rbuf; /* Buffer towards LIRC */
- struct lirc_driver driver;
- int minor;
- int last_pulse; /* remembers if last received byte was pulse or space */
- int last_num; /* remembers how many last bytes appeared */
- int opened;
-};
-
-/*** LIRC specific functions ***/
-static int set_use_inc(void *data)
-{
- int i, retval;
- struct ttusbir_device *ttusbir = data;
-
- DPRINTK("Sending first URBs\n");
- /* @TODO Do I need to check if I am already opened */
- ttusbir->opened = 1;
-
- for (i = 0; i < num_urbs; i++) {
- retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
- if (retval) {
- dev_err(&ttusbir->interf->dev,
- "%s: usb_submit_urb failed on urb %d\n",
- __func__, i);
- return retval;
- }
- }
- return 0;
-}
-
-static void set_use_dec(void *data)
-{
- struct ttusbir_device *ttusbir = data;
-
- DPRINTK("Device closed\n");
-
- ttusbir->opened = 0;
-}
-
-/*** USB specific functions ***/
-
-/*
- * This mapping table is used to do a very simple filtering of the
- * input signal.
- * For a value with at least 4 bits set it returns 0xFF otherwise
- * 0x00. For faster IR signals this can not be used. But for RC-5 we
- * still have about 14 samples per pulse/space, i.e. we sample with 14
- * times higher frequency than the signal frequency
- */
-const unsigned char map_table[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-static void urb_complete(struct urb *urb)
-{
- struct ttusbir_device *ttusbir;
- unsigned char *buf;
- int i;
- int l;
-
- ttusbir = urb->context;
-
- if (!ttusbir->opened)
- return;
-
- buf = (unsigned char *)urb->transfer_buffer;
-
- for (i = 0; i < 128; i++) {
- /* Here we do the filtering and some kind of down sampling */
- buf[i] = ~map_table[buf[i]];
- if (ttusbir->last_pulse == buf[i]) {
- if (ttusbir->last_num < PULSE_MASK/63)
- ttusbir->last_num++;
- /*
- * else we are in a idle period and do not need to
- * increment any longer
- */
- } else {
- l = ttusbir->last_num * 62; /* about 62 = us/byte */
- if (ttusbir->last_pulse) /* pulse or space? */
- l |= PULSE_BIT;
- if (!lirc_buffer_full(&ttusbir->rbuf)) {
- lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
- wake_up_interruptible(&ttusbir->rbuf.wait_poll);
- }
- ttusbir->last_num = 0;
- ttusbir->last_pulse = buf[i];
- }
- }
- usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
-}
-
-/*
- * Called whenever the USB subsystem thinks we could be the right driver
- * to handle this device
- */
-static int probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- int alt_set, endp;
- int found = 0;
- int i, j;
- int struct_size;
- struct usb_host_interface *host_interf;
- struct usb_interface_descriptor *interf_desc;
- struct usb_host_endpoint *host_endpoint;
- struct ttusbir_device *ttusbir;
-
- DPRINTK("Module ttusbir probe\n");
-
- /* To reduce memory fragmentation we use only one allocation */
- struct_size = sizeof(struct ttusbir_device) +
- (sizeof(struct urb *) * num_urbs) +
- (sizeof(char *) * num_urbs) +
- (num_urbs * 128);
- ttusbir = kzalloc(struct_size, GFP_KERNEL);
- if (!ttusbir)
- return -ENOMEM;
-
- ttusbir->urb = (struct urb **)((char *)ttusbir +
- sizeof(struct ttusbir_device));
- ttusbir->buffer = (char **)((char *)ttusbir->urb +
- (sizeof(struct urb *) * num_urbs));
- for (i = 0; i < num_urbs; i++)
- ttusbir->buffer[i] = (char *)ttusbir->buffer +
- (sizeof(char *)*num_urbs) + (i * 128);
-
- ttusbir->usb_driver = &usb_driver;
- ttusbir->alt_setting = -1;
- /* @TODO check if error can be returned */
- ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
- ttusbir->interf = intf;
- ttusbir->last_pulse = 0x00;
- ttusbir->last_num = 0;
-
- /*
- * Now look for interface setting we can handle
- * We are searching for the alt setting where end point
- * 0x82 has max packet size 16
- */
- for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
- host_interf = &intf->altsetting[alt_set];
- interf_desc = &host_interf->desc;
- for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
- host_endpoint = &host_interf->endpoint[endp];
- if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
- (host_endpoint->desc.wMaxPacketSize == 0x10)) {
- ttusbir->alt_setting = alt_set;
- ttusbir->endpoint = endp;
- found = 1;
- break;
- }
- }
- }
- if (ttusbir->alt_setting != -1)
- DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
- else {
- dev_err(&intf->dev, "Could not find alternate setting\n");
- kfree(ttusbir);
- return -EINVAL;
- }
-
- /* OK lets setup this interface setting */
- usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
-
- /* Store device info in interface structure */
- usb_set_intfdata(intf, ttusbir);
-
- /* Register as a LIRC driver */
- if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
- dev_err(&intf->dev, "Could not get memory for LIRC data buffer\n");
- usb_set_intfdata(intf, NULL);
- kfree(ttusbir);
- return -ENOMEM;
- }
- strcpy(ttusbir->driver.name, "TTUSBIR");
- ttusbir->driver.minor = -1;
- ttusbir->driver.code_length = 1;
- ttusbir->driver.sample_rate = 0;
- ttusbir->driver.data = ttusbir;
- ttusbir->driver.add_to_buf = NULL;
- ttusbir->driver.rbuf = &ttusbir->rbuf;
- ttusbir->driver.set_use_inc = set_use_inc;
- ttusbir->driver.set_use_dec = set_use_dec;
- ttusbir->driver.dev = &intf->dev;
- ttusbir->driver.owner = THIS_MODULE;
- ttusbir->driver.features = LIRC_CAN_REC_MODE2;
- ttusbir->minor = lirc_register_driver(&ttusbir->driver);
- if (ttusbir->minor < 0) {
- dev_err(&intf->dev, "Error registering as LIRC driver\n");
- usb_set_intfdata(intf, NULL);
- lirc_buffer_free(&ttusbir->rbuf);
- kfree(ttusbir);
- return -EIO;
- }
-
- /* Allocate and setup the URB that we will use to talk to the device */
- for (i = 0; i < num_urbs; i++) {
- ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
- if (!ttusbir->urb[i]) {
- dev_err(&intf->dev, "Could not allocate memory for the URB\n");
- for (j = i - 1; j >= 0; j--)
- kfree(ttusbir->urb[j]);
- lirc_buffer_free(&ttusbir->rbuf);
- lirc_unregister_driver(ttusbir->minor);
- kfree(ttusbir);
- usb_set_intfdata(intf, NULL);
- return -ENOMEM;
- }
- ttusbir->urb[i]->dev = ttusbir->udev;
- ttusbir->urb[i]->context = ttusbir;
- ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
- ttusbir->endpoint);
- ttusbir->urb[i]->interval = 1;
- ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
- ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
- ttusbir->urb[i]->complete = urb_complete;
- ttusbir->urb[i]->number_of_packets = 8;
- ttusbir->urb[i]->transfer_buffer_length = 128;
- for (j = 0; j < 8; j++) {
- ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
- ttusbir->urb[i]->iso_frame_desc[j].length = 16;
- }
- }
- return 0;
-}
-
-/**
- * Called when the driver is unloaded or the device is unplugged
- */
-static void disconnect(struct usb_interface *intf)
-{
- int i;
- struct ttusbir_device *ttusbir;
-
- DPRINTK("Module ttusbir disconnect\n");
-
- ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
- usb_set_intfdata(intf, NULL);
- lirc_unregister_driver(ttusbir->minor);
- DPRINTK("unregistered\n");
-
- for (i = 0; i < num_urbs; i++) {
- usb_kill_urb(ttusbir->urb[i]);
- usb_free_urb(ttusbir->urb[i]);
- }
- DPRINTK("URBs killed\n");
- lirc_buffer_free(&ttusbir->rbuf);
- kfree(ttusbir);
-}
-
-module_usb_driver(usb_driver);
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
index 76ea4a8f2c75..11d5338b4f2f 100644
--- a/drivers/staging/media/lirc/lirc_zilog.c
+++ b/drivers/staging/media/lirc/lirc_zilog.c
@@ -658,8 +658,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
buf[0] = (unsigned char)(i + 1);
for (j = 0; j < tosend; ++j)
buf[1 + j] = data_block[i + j];
- dprintk("%02x %02x %02x %02x %02x",
- buf[0], buf[1], buf[2], buf[3], buf[4]);
+ dprintk("%*ph", 5, buf);
ret = i2c_master_send(tx->c, buf, tosend + 1);
if (ret != tosend + 1) {
zilog_error("i2c_master_send failed with %d\n", ret);
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index f50d4058c5fb..bb51edfc72a2 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -121,16 +121,27 @@ typedef enum fe_sec_mini_cmd {
} fe_sec_mini_cmd_t;
+/**
+ * enum fe_status - enumerates the possible frontend status
+ * @FE_HAS_SIGNAL: found something above the noise level
+ * @FE_HAS_CARRIER: found a DVB signal
+ * @FE_HAS_VITERBI: FEC is stable
+ * @FE_HAS_SYNC: found sync bytes
+ * @FE_HAS_LOCK: everything's working
+ * @FE_TIMEDOUT: no lock within the last ~2 seconds
+ * @FE_REINIT: frontend was reinitialized, application is recommended
+ * to reset DiSEqC, tone and parameters
+ */
+
typedef enum fe_status {
- FE_HAS_SIGNAL = 0x01, /* found something above the noise level */
- FE_HAS_CARRIER = 0x02, /* found a DVB signal */
- FE_HAS_VITERBI = 0x04, /* FEC is stable */
- FE_HAS_SYNC = 0x08, /* found sync bytes */
- FE_HAS_LOCK = 0x10, /* everything's working... */
- FE_TIMEDOUT = 0x20, /* no lock within the last ~2 seconds */
- FE_REINIT = 0x40 /* frontend was reinitialized, */
-} fe_status_t; /* application is recommended to reset */
- /* DiSEqC, tone and parameters */
+ FE_HAS_SIGNAL = 0x01,
+ FE_HAS_CARRIER = 0x02,
+ FE_HAS_VITERBI = 0x04,
+ FE_HAS_SYNC = 0x08,
+ FE_HAS_LOCK = 0x10,
+ FE_TIMEDOUT = 0x20,
+ FE_REINIT = 0x40,
+} fe_status_t;
typedef enum fe_spectral_inversion {
INVERSION_OFF,
@@ -152,6 +163,7 @@ typedef enum fe_code_rate {
FEC_AUTO,
FEC_3_5,
FEC_9_10,
+ FEC_2_5,
} fe_code_rate_t;
@@ -169,6 +181,7 @@ typedef enum fe_modulation {
APSK_16,
APSK_32,
DQPSK,
+ QAM_4_NR,
} fe_modulation_t;
typedef enum fe_transmit_mode {
@@ -179,6 +192,8 @@ typedef enum fe_transmit_mode {
TRANSMISSION_MODE_1K,
TRANSMISSION_MODE_16K,
TRANSMISSION_MODE_32K,
+ TRANSMISSION_MODE_C1,
+ TRANSMISSION_MODE_C3780,
} fe_transmit_mode_t;
#if defined(__DVB_CORE__) || !defined (__KERNEL__)
@@ -202,6 +217,9 @@ typedef enum fe_guard_interval {
GUARD_INTERVAL_1_128,
GUARD_INTERVAL_19_128,
GUARD_INTERVAL_19_256,
+ GUARD_INTERVAL_PN420,
+ GUARD_INTERVAL_PN595,
+ GUARD_INTERVAL_PN945,
} fe_guard_interval_t;
@@ -213,6 +231,12 @@ typedef enum fe_hierarchy {
HIERARCHY_AUTO
} fe_hierarchy_t;
+enum fe_interleaving {
+ INTERLEAVING_NONE,
+ INTERLEAVING_AUTO,
+ INTERLEAVING_240,
+ INTERLEAVING_720,
+};
#if defined(__DVB_CORE__) || !defined (__KERNEL__)
struct dvb_qpsk_parameters {
@@ -337,7 +361,9 @@ struct dvb_frontend_event {
#define DTV_ATSCMH_SCCC_CODE_MODE_C 58
#define DTV_ATSCMH_SCCC_CODE_MODE_D 59
-#define DTV_MAX_COMMAND DTV_ATSCMH_SCCC_CODE_MODE_D
+#define DTV_INTERLEAVING 60
+
+#define DTV_MAX_COMMAND DTV_INTERLEAVING
typedef enum fe_pilot {
PILOT_ON,
@@ -366,7 +392,7 @@ typedef enum fe_delivery_system {
SYS_ISDBC,
SYS_ATSC,
SYS_ATSCMH,
- SYS_DMBTH,
+ SYS_DTMB,
SYS_CMMB,
SYS_DAB,
SYS_DVBT2,
@@ -374,8 +400,9 @@ typedef enum fe_delivery_system {
SYS_DVBC_ANNEX_C,
} fe_delivery_system_t;
-
+/* backward compatibility */
#define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A
+#define SYS_DMBTH SYS_DTMB /* DMB-TH is legacy name, use DTMB instead */
/* ATSC-MH */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 43d9e8d462d4..70c2c7edcc7d 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@
#define _DVBVERSION_H_
#define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 6
+#define DVB_API_VERSION_MINOR 7
#endif /*_DVBVERSION_H_*/
diff --git a/include/linux/omap3isp.h b/include/linux/omap3isp.h
index c73a34c3434d..c090cf9249bb 100644
--- a/include/linux/omap3isp.h
+++ b/include/linux/omap3isp.h
@@ -28,6 +28,7 @@
#define OMAP3_ISP_USER_H
#include <linux/types.h>
+#include <linux/videodev2.h>
/*
* Private IOCTLs
@@ -427,7 +428,7 @@ struct omap3isp_ccdc_update_config {
#define OMAP3ISP_PREV_COLOR_CONV (1 << 8)
#define OMAP3ISP_PREV_YC_LIMIT (1 << 9)
#define OMAP3ISP_PREV_DEFECT_COR (1 << 10)
-#define OMAP3ISP_PREV_GAMMABYPASS (1 << 11)
+/* Bit 11 was OMAP3ISP_PREV_GAMMABYPASS, now merged with OMAP3ISP_PREV_GAMMA */
#define OMAP3ISP_PREV_DRK_FRM_CAPTURE (1 << 12)
#define OMAP3ISP_PREV_DRK_FRM_SUBTRACT (1 << 13)
#define OMAP3ISP_PREV_LENS_SHADING (1 << 14)
@@ -436,6 +437,7 @@ struct omap3isp_ccdc_update_config {
#define OMAP3ISP_PREV_NF_TBL_SIZE 64
#define OMAP3ISP_PREV_CFA_TBL_SIZE 576
+#define OMAP3ISP_PREV_CFA_BLK_SIZE (OMAP3ISP_PREV_CFA_TBL_SIZE / 4)
#define OMAP3ISP_PREV_GAMMA_TBL_SIZE 1024
#define OMAP3ISP_PREV_YENH_TBL_SIZE 128
@@ -477,7 +479,7 @@ struct omap3isp_prev_cfa {
enum omap3isp_cfa_fmt format;
__u8 gradthrs_vert;
__u8 gradthrs_horz;
- __u32 table[OMAP3ISP_PREV_CFA_TBL_SIZE];
+ __u32 table[4][OMAP3ISP_PREV_CFA_BLK_SIZE];
};
/**
diff --git a/include/linux/v4l2-common.h b/include/linux/v4l2-common.h
index 0fa8b64c3cdb..4f0667e010dd 100644
--- a/include/linux/v4l2-common.h
+++ b/include/linux/v4l2-common.h
@@ -53,10 +53,10 @@
/* Backward compatibility target definitions --- to be removed. */
#define V4L2_SEL_TGT_CROP_ACTIVE V4L2_SEL_TGT_CROP
#define V4L2_SEL_TGT_COMPOSE_ACTIVE V4L2_SEL_TGT_COMPOSE
-#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL \
- V4L2_SEL_TGT_CROP
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL \
- V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS V4L2_SEL_TGT_CROP_BOUNDS
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
/* Selection flags */
#define V4L2_SEL_FLAG_GE (1 << 0)
diff --git a/include/media/ir-rx51.h b/include/media/ir-rx51.h
new file mode 100644
index 000000000000..104aa892f31b
--- /dev/null
+++ b/include/media/ir-rx51.h
@@ -0,0 +1,10 @@
+#ifndef _LIRC_RX51_H
+#define _LIRC_RX51_H
+
+struct lirc_rx51_platform_data {
+ int pwm_timer;
+
+ int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
+};
+
+#endif
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index 4d94be5226af..95842696857f 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -42,12 +42,6 @@ enum isp_interface_type {
};
enum {
- ISP_BRIDGE_DISABLE = 0,
- ISP_BRIDGE_LITTLE_ENDIAN = 2,
- ISP_BRIDGE_BIG_ENDIAN = 3,
-};
-
-enum {
ISP_LANE_SHIFT_0 = 0,
ISP_LANE_SHIFT_2 = 1,
ISP_LANE_SHIFT_4 = 2,
@@ -67,17 +61,15 @@ enum {
* 0 - Active high, 1 - Active low
* @vs_pol: Vertical synchronization polarity
* 0 - Active high, 1 - Active low
- * @bridge: CCDC Bridge input control
- * ISP_BRIDGE_DISABLE - Disable
- * ISP_BRIDGE_LITTLE_ENDIAN - Little endian
- * ISP_BRIDGE_BIG_ENDIAN - Big endian
+ * @data_pol: Data polarity
+ * 0 - Normal, 1 - One's complement
*/
struct isp_parallel_platform_data {
unsigned int data_lane_shift:2;
unsigned int clk_pol:1;
unsigned int hs_pol:1;
unsigned int vs_pol:1;
- unsigned int bridge:2;
+ unsigned int data_pol:1;
};
enum {
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 773e527deabe..96058a5a4acc 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -117,8 +117,6 @@ struct saa7146_dev
{
struct module *module;
- struct list_head item;
-
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
@@ -166,8 +164,6 @@ static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
/* from saa7146_core.c */
-extern struct list_head saa7146_devices;
-extern struct mutex saa7146_devices_lock;
int saa7146_register_extension(struct saa7146_extension*);
int saa7146_unregister_extension(struct saa7146_extension*);
struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index d865dcf9879f..435e7b8ad1c3 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -86,6 +86,8 @@ struct soc_camera_host_ops {
int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *);
int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *);
int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *);
+ int (*get_selection)(struct soc_camera_device *, struct v4l2_selection *);
+ int (*set_selection)(struct soc_camera_device *, struct v4l2_selection *);
/*
* The difference to .set_crop() is, that .set_livecrop is not allowed
* to change the output sizes
@@ -254,6 +256,16 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
const struct v4l2_mbus_config *cfg);
+int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl);
+int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl);
+
+static inline int soc_camera_set_power(struct device *dev,
+ struct soc_camera_link *icl, bool on)
+{
+ return on ? soc_camera_power_on(dev, icl)
+ : soc_camera_power_off(dev, icl);
+}
+
/* This is only temporary here - until v4l2-subdev begins to link to video_device */
#include <linux/i2c.h>
static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client)
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index a298ec49ddc4..4404829d48e5 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -133,7 +133,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, struct i2c_board_info *info,
const unsigned short *probe_addrs);
-/* Initialize an v4l2_subdev with data from an i2c_client struct */
+/* Initialize a v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops);
/* Return i2c client address of v4l2_subdev. */
@@ -166,7 +166,7 @@ struct spi_device;
struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
struct spi_master *master, struct spi_board_info *info);
-/* Initialize an v4l2_subdev with data from an spi_device struct */
+/* Initialize a v4l2_subdev with data from an spi_device struct */
void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
const struct v4l2_subdev_ops *ops);
#endif
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 5c416cdc88d5..6ee8897c47e9 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -39,9 +39,6 @@ struct v4l2_ctrl_handler;
#define V4L2_FL_USES_V4L2_FH (1)
/* Use the prio field of v4l2_fh for core priority checking */
#define V4L2_FL_USE_FH_PRIO (2)
-/* If ioctl core locking is in use, then apply that also to all
- file operations. Don't use this flag in new drivers! */
-#define V4L2_FL_LOCK_ALL_FOPS (3)
/* Priority helper functions */
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c35a3545e273..4cc1652284b6 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -120,7 +120,7 @@ struct v4l2_subdev_io_pin_config {
each pin being configured. This function could be called at times
other than just subdevice initialization.
- init: initialize the sensor registors to some sort of reasonable default
+ init: initialize the sensor registers to some sort of reasonable default
values. Do not use for new drivers and should be removed in existing
drivers.
diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h
index bf365721d6b0..d63965a1faaf 100644
--- a/include/media/videobuf-dvb.h
+++ b/include/media/videobuf-dvb.h
@@ -45,9 +45,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
void *adapter_priv,
struct device *device,
short *adapter_nr,
- int mfe_shared,
- int (*fe_ioctl_override)(struct dvb_frontend *,
- unsigned int, void *, unsigned int));
+ int mfe_shared);
void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
OpenPOWER on IntegriCloud